[GH-1368] Add empty / not empty table aggregations (#1557)

This adds new aggregations for counting empty / not empty cards as well
as computing the respective percentage.

Fixes: #1368
This commit is contained in:
Johannes Marbach 2021-10-15 23:25:38 +02:00 committed by GitHub
parent 40b9e3341f
commit 5204e2d080
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 197 additions and 4 deletions

View file

@ -151,6 +151,8 @@ describe('components/calculations/calculation logic', () => {
updatedBy: {id: 'property_lastUpdatedBy', type: 'updatedBy', name: '', options: []},
}
const autofilledProperties = new Set([properties.createdBy, properties.createdTime, properties.updatedBy, properties.updatedTime])
const intl = createIntl({locale: 'en-us'})
// testing count
@ -160,6 +162,34 @@ describe('components/calculations/calculation logic', () => {
})
})
// testing count empty
Object.values(properties).filter((p) => !autofilledProperties.has(p)).forEach((property) => {
it(`should correctly count empty for property type "${property.type}"`, function() {
expect(Calculations.countEmpty(cards, property, intl)).toBe('1')
})
})
// testing percent empty
Object.values(properties).filter((p) => !autofilledProperties.has(p)).forEach((property) => {
it(`should correctly compute empty percent for property type "${property.type}"`, function() {
expect(Calculations.percentEmpty(cards, property, intl)).toBe('25%')
})
})
// testing count not empty
Object.values(properties).filter((p) => !autofilledProperties.has(p)).forEach((property) => {
it(`should correctly count not empty for property type "${property.type}"`, function() {
expect(Calculations.countNotEmpty(cards, property, intl)).toBe('3')
})
})
// testing percent not empty
Object.values(properties).filter((p) => !autofilledProperties.has(p)).forEach((property) => {
it(`should correctly compute not empty percent for property type "${property.type}"`, function() {
expect(Calculations.percentNotEmpty(cards, property, intl)).toBe('75%')
})
})
// testing countValues
const countValueTests: Record<string, string> = {
text: '3',

View file

@ -53,6 +53,28 @@ function count(cards: readonly Card[], property: IPropertyTemplate): string {
return String(cards.length)
}
function countEmpty(cards: readonly Card[], property: IPropertyTemplate): string {
return String(cards.length - cardsWithValue(cards, property).length)
}
function countNotEmpty(cards: readonly Card[], property: IPropertyTemplate): string {
return String(cardsWithValue(cards, property).length)
}
function percentEmpty(cards: readonly Card[], property: IPropertyTemplate): string {
if (cards.length === 0) {
return ''
}
return String((((cards.length - cardsWithValue(cards, property).length) / cards.length) * 100).toFixed(0)) + '%'
}
function percentNotEmpty(cards: readonly Card[], property: IPropertyTemplate): string {
if (cards.length === 0) {
return ''
}
return String(((cardsWithValue(cards, property).length / cards.length) * 100).toFixed(0)) + '%'
}
function countValueHelper(cards: readonly Card[], property: IPropertyTemplate): number {
let values = 0
@ -274,6 +296,10 @@ function dateRange(cards: readonly Card[], property: IPropertyTemplate): string
const Calculations: Record<string, (cards: readonly Card[], property: IPropertyTemplate, intl: IntlShape) => string> = {
count,
countEmpty,
countNotEmpty,
percentEmpty,
percentNotEmpty,
countValue,
countUniqueValue,
countChecked,

View file

@ -19,6 +19,10 @@ type Option = {
export const Options:Record<string, Option> = {
none: {value: 'none', label: 'None', displayName: 'Calculate'},
count: {value: 'count', label: 'Count', displayName: 'Count'},
countEmpty: {value: 'countEmpty', label: 'Count Empty', displayName: 'Empty'},
countNotEmpty: {value: 'countNotEmpty', label: 'Count Not Empty', displayName: 'Not Empty'},
percentEmpty: {value: 'percentEmpty', label: 'Percent Empty', displayName: 'Empty'},
percentNotEmpty: {value: 'percentNotEmpty', label: 'Percent Not Empty', displayName: 'Not Empty'},
countValue: {value: 'countValue', label: 'Count Value', displayName: 'Values'},
countChecked: {value: 'countChecked', label: 'Count Checked', displayName: 'Checked'},
percentChecked: {value: 'percentChecked', label: 'Percent Checked', displayName: 'Checked'},
@ -37,7 +41,8 @@ export const Options:Record<string, Option> = {
}
export const optionsByType: Map<string, Option[]> = new Map([
['common', [Options.none, Options.count, Options.countValue, Options.countUniqueValue]],
['common', [Options.none, Options.count, Options.countEmpty, Options.countNotEmpty, Options.percentEmpty,
Options.percentNotEmpty, Options.countValue, Options.countUniqueValue]],
['checkbox', [Options.countChecked, Options.countUnchecked, Options.percentChecked, Options.percentUnchecked]],
['number', [Options.sum, Options.average, Options.median, Options.min, Options.max, Options.range]],
['date', [Options.earliest, Options.latest, Options.dateRange]],

View file

@ -45,7 +45,7 @@ exports[`components/kanban/calculation/KanbanCalculation calculations menu open
<span
id="aria-context"
>
3 results available. Use Up and Down to choose options, press Enter to select the currently focused option, press Escape to exit the menu, press Tab to select the option and exit the menu.
7 results available. Use Up and Down to choose options, press Enter to select the currently focused option, press Escape to exit the menu, press Tab to select the option and exit the menu.
</span>
</span>
<div
@ -115,6 +115,50 @@ exports[`components/kanban/calculation/KanbanCalculation calculations menu open
</span>
</div>
<div
class="KanbanCalculationOptions_CustomOption "
>
<span>
Count Empty
<i
class="CompassIcon icon-chevron-right ChevronRightIcon"
/>
</span>
</div>
<div
class="KanbanCalculationOptions_CustomOption "
>
<span>
Count Not Empty
<i
class="CompassIcon icon-chevron-right ChevronRightIcon"
/>
</span>
</div>
<div
class="KanbanCalculationOptions_CustomOption "
>
<span>
Percent Empty
<i
class="CompassIcon icon-chevron-right ChevronRightIcon"
/>
</span>
</div>
<div
class="KanbanCalculationOptions_CustomOption "
>
<span>
Percent Not Empty
<i
class="CompassIcon icon-chevron-right ChevronRightIcon"
/>
</span>
</div>
<div
class="KanbanCalculationOptions_CustomOption "
>

View file

@ -99,7 +99,7 @@ exports[`components/kanban/calculations/KanbanCalculationOptions with menu open
<span
id="aria-context"
>
3 results available. Use Up and Down to choose options, press Enter to select the currently focused option, press Escape to exit the menu, press Tab to select the option and exit the menu.
7 results available. Use Up and Down to choose options, press Enter to select the currently focused option, press Escape to exit the menu, press Tab to select the option and exit the menu.
</span>
</span>
<div
@ -169,6 +169,50 @@ exports[`components/kanban/calculations/KanbanCalculationOptions with menu open
</span>
</div>
<div
class="KanbanCalculationOptions_CustomOption "
>
<span>
Count Empty
<i
class="CompassIcon icon-chevron-right ChevronRightIcon"
/>
</span>
</div>
<div
class="KanbanCalculationOptions_CustomOption "
>
<span>
Count Not Empty
<i
class="CompassIcon icon-chevron-right ChevronRightIcon"
/>
</span>
</div>
<div
class="KanbanCalculationOptions_CustomOption "
>
<span>
Percent Empty
<i
class="CompassIcon icon-chevron-right ChevronRightIcon"
/>
</span>
</div>
<div
class="KanbanCalculationOptions_CustomOption "
>
<span>
Percent Not Empty
<i
class="CompassIcon icon-chevron-right ChevronRightIcon"
/>
</span>
</div>
<div
class="KanbanCalculationOptions_CustomOption "
>
@ -219,7 +263,7 @@ exports[`components/kanban/calculations/KanbanCalculationOptions with submenu op
<span
id="aria-context"
>
3 results available. Use Up and Down to choose options, press Enter to select the currently focused option, press Escape to exit the menu, press Tab to select the option and exit the menu.
7 results available. Use Up and Down to choose options, press Enter to select the currently focused option, press Escape to exit the menu, press Tab to select the option and exit the menu.
</span>
</span>
<div
@ -289,6 +333,50 @@ exports[`components/kanban/calculations/KanbanCalculationOptions with submenu op
</span>
</div>
<div
class="KanbanCalculationOptions_CustomOption "
>
<span>
Count Empty
<i
class="CompassIcon icon-chevron-right ChevronRightIcon"
/>
</span>
</div>
<div
class="KanbanCalculationOptions_CustomOption "
>
<span>
Count Not Empty
<i
class="CompassIcon icon-chevron-right ChevronRightIcon"
/>
</span>
</div>
<div
class="KanbanCalculationOptions_CustomOption "
>
<span>
Percent Empty
<i
class="CompassIcon icon-chevron-right ChevronRightIcon"
/>
</span>
</div>
<div
class="KanbanCalculationOptions_CustomOption "
>
<span>
Percent Not Empty
<i
class="CompassIcon icon-chevron-right ChevronRightIcon"
/>
</span>
</div>
<div
class="KanbanCalculationOptions_CustomOption "
>