Enhancement: filterable list count sorting and opacification (#8386)

This commit is contained in:
shamoon
2024-11-29 22:36:40 -08:00
committed by GitHub
parent 548a7f05d8
commit 9614528033
6 changed files with 116 additions and 44 deletions

View File

@@ -38,7 +38,15 @@
@for (item of selectionModel.items | filter: filterText:'name'; track item; let i = $index) {
@if (allowSelectNone || item.id) {
<pngx-toggleable-dropdown-button
[item]="item" [hideCount]="hideCount(item)" [state]="selectionModel.get(item.id)" [count]="getUpdatedDocumentCount(item.id)" (toggled)="selectionModel.toggle(item.id)" (exclude)="excludeClicked(item.id)" (click)="setButtonItemIndex(i - 1)" [disabled]="disabled">
[item]="item"
[hideCount]="hideCount(item)"
[opacifyCount]="!editing"
[state]="selectionModel.get(item.id)"
[count]="getUpdatedDocumentCount(item.id)"
(toggled)="selectionModel.toggle(item.id)"
(exclude)="excludeClicked(item.id)"
(click)="setButtonItemIndex(i - 1)"
[disabled]="disabled">
</pngx-toggleable-dropdown-button>
}
}

View File

@@ -509,6 +509,37 @@ describe('FilterableDropdownComponent & FilterableDropdownSelectionModel', () =>
])
})
it('selection model should sort items by state and document counts, if set', () => {
component.items = items.concat([{ id: 4, name: 'Item D' }])
component.selectionModel = selectionModel
component.documentCounts = [
{ id: 1, document_count: 0 }, // Tag1
{ id: 2, document_count: 1 }, // Tag2
{ id: 4, document_count: 2 },
]
component.selectionModel.apply()
expect(selectionModel.items).toEqual([
nullItem,
{ id: 4, name: 'Item D' },
items[1], // Tag2
items[0], // Tag1
])
selectionModel.toggle(items[1].id)
component.documentCounts = [
{ id: 1, document_count: 0 },
{ id: 2, document_count: 1 },
{ id: 4, document_count: 0 },
]
selectionModel.apply()
expect(selectionModel.items).toEqual([
nullItem,
items[1], // Tag2
{ id: 4, name: 'Item D' },
items[0], // Tag1
])
})
it('should set support create, keep open model and call createRef method', fakeAsync(() => {
component.items = items
component.icon = 'tag-fill'

View File

@@ -43,6 +43,11 @@ export class FilterableDropdownSelectionModel {
private _intersection: Intersection = Intersection.Include
temporaryIntersection: Intersection = this._intersection
private _documentCounts: SelectionDataItem[] = []
public set documentCounts(counts: SelectionDataItem[]) {
this._documentCounts = counts
}
private _items: MatchingModel[] = []
get items(): MatchingModel[] {
return this._items
@@ -69,6 +74,16 @@ export class FilterableDropdownSelectionModel {
this.getNonTemporary(b.id) == ToggleableItemState.NotSelected
) {
return -1
} else if (
this._documentCounts.length &&
this.getDocumentCount(a.id) > this.getDocumentCount(b.id)
) {
return -1
} else if (
this._documentCounts.length &&
this.getDocumentCount(a.id) < this.getDocumentCount(b.id)
) {
return 1
} else {
return a.name.localeCompare(b.name)
}
@@ -286,6 +301,10 @@ export class FilterableDropdownSelectionModel {
)
}
getDocumentCount(id: number) {
return this._documentCounts.find((c) => c.id === id)?.document_count
}
init(map: Map<number, ToggleableItemState>) {
this.temporarySelectionStates = map
this.apply()
@@ -431,7 +450,11 @@ export class FilterableDropdownComponent implements OnDestroy, OnInit {
}
@Input()
documentCounts: SelectionDataItem[]
set documentCounts(counts: SelectionDataItem[]) {
if (counts) {
this.selectionModel.documentCounts = counts
}
}
@Input()
shortcutKey: string
@@ -544,9 +567,7 @@ export class FilterableDropdownComponent implements OnDestroy, OnInit {
}
getUpdatedDocumentCount(id: number) {
if (this.documentCounts) {
return this.documentCounts.find((c) => c.id === id)?.document_count
}
return this.selectionModel.getDocumentCount(id)
}
listKeyDown(event: KeyboardEvent) {

View File

@@ -1,4 +1,9 @@
<button class="list-group-item list-group-item-action d-flex align-items-center p-2 border-top-0 border-start-0 border-end-0 border-bottom" role="menuitem" (click)="toggleItem($event)" [disabled]="disabled">
<button
class="list-group-item list-group-item-action d-flex align-items-center p-2 border-top-0 border-start-0 border-end-0 border-bottom"
[class.opacity-50]="opacifyCount && !hideCount && currentCount === 0"
role="menuitem"
(click)="toggleItem($event)"
[disabled]="disabled">
<div class="selected-icon me-1">
@if (isChecked()) {
<i-bs width="1em" height="1em" name="check"></i-bs>
@@ -18,6 +23,6 @@
}
</div>
@if (!hideCount) {
<div class="badge bg-light text-dark rounded-pill ms-auto me-1">{{count ?? item.document_count}}</div>
<div class="badge bg-light text-dark rounded-pill ms-auto me-1">{{currentCount}}</div>
}
</button>

View File

@@ -29,6 +29,9 @@ export class ToggleableDropdownButtonComponent {
@Input()
hideCount: boolean = false
@Input()
opacifyCount: boolean = true
@Output()
toggled = new EventEmitter()
@@ -39,6 +42,10 @@ export class ToggleableDropdownButtonComponent {
return 'is_inbox_tag' in this.item
}
get currentCount(): number {
return this.count ?? this.item.document_count
}
toggleItem(event: MouseEvent): void {
if (this.state == ToggleableItemState.Selected) {
this.exclude.emit()