3">
@for (tagID of tagIDs; track tagID) {
}
diff --git a/src-ui/src/app/components/document-list/document-card-small/document-card-small.component.scss b/src-ui/src/app/components/document-list/document-card-small/document-card-small.component.scss
index 508c5251a..dce77802e 100644
--- a/src-ui/src/app/components/document-list/document-card-small/document-card-small.component.scss
+++ b/src-ui/src/app/components/document-list/document-card-small/document-card-small.component.scss
@@ -72,4 +72,14 @@ a {
max-width: 80%;
row-gap: .2rem;
line-height: 1;
+
+ &.tags-no-wrap {
+ ::ng-deep .badge {
+ display: inline-block;
+ max-width: 100%;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
+ }
}
diff --git a/src-ui/src/app/components/document-list/document-card-small/document-card-small.component.spec.ts b/src-ui/src/app/components/document-list/document-card-small/document-card-small.component.spec.ts
index 63cfc5a50..982b3980b 100644
--- a/src-ui/src/app/components/document-list/document-card-small/document-card-small.component.spec.ts
+++ b/src-ui/src/app/components/document-list/document-card-small/document-card-small.component.spec.ts
@@ -82,6 +82,16 @@ describe('DocumentCardSmallComponent', () => {
).toHaveLength(6)
})
+ it('should clear hidden tag counter when tag count falls below the limit', () => {
+ expect(component.moreTags).toEqual(3)
+
+ component.document.tags = [1, 2, 3, 4, 5, 6]
+ fixture.detectChanges()
+
+ expect(component.moreTags).toBeNull()
+ expect(fixture.nativeElement.textContent).not.toContain('+ 3')
+ })
+
it('should try to close the preview on mouse leave', () => {
component.popupPreview = {
close: jest.fn(),
diff --git a/src-ui/src/app/components/document-list/document-card-small/document-card-small.component.ts b/src-ui/src/app/components/document-list/document-card-small/document-card-small.component.ts
index ad428dfab..05f84d752 100644
--- a/src-ui/src/app/components/document-list/document-card-small/document-card-small.component.ts
+++ b/src-ui/src/app/components/document-list/document-card-small/document-card-small.component.ts
@@ -126,6 +126,7 @@ export class DocumentCardSmallComponent
this.moreTags = this.document.tags.length - (limit - 1)
return this.document.tags.slice(0, limit - 1)
} else {
+ this.moreTags = null
return this.document.tags
}
}
From d919c341b12ba1fcc2a3f9bc84b4e98160582990 Mon Sep 17 00:00:00 2001
From: shamoon <4887959+shamoon@users.noreply.github.com>
Date: Thu, 12 Mar 2026 11:57:35 -0700
Subject: [PATCH 3/7] Fix: clear descendant selections in dropdown when parent
toggled (#12326)
---
.../filterable-dropdown.component.spec.ts | 53 +++++++++++++++++++
.../filterable-dropdown.component.ts | 35 ++++++++++++
2 files changed, 88 insertions(+)
diff --git a/src-ui/src/app/components/common/filterable-dropdown/filterable-dropdown.component.spec.ts b/src-ui/src/app/components/common/filterable-dropdown/filterable-dropdown.component.spec.ts
index 2ecf95f2b..1763239b1 100644
--- a/src-ui/src/app/components/common/filterable-dropdown/filterable-dropdown.component.spec.ts
+++ b/src-ui/src/app/components/common/filterable-dropdown/filterable-dropdown.component.spec.ts
@@ -631,6 +631,59 @@ describe('FilterableDropdownComponent & FilterableDropdownSelectionModel', () =>
])
})
+ it('deselecting a parent clears selected descendants', () => {
+ const root: Tag = { id: 100, name: 'Root Tag' }
+ const child: Tag = { id: 101, name: 'Child Tag', parent: root.id }
+ const grandchild: Tag = {
+ id: 102,
+ name: 'Grandchild Tag',
+ parent: child.id,
+ }
+ const other: Tag = { id: 103, name: 'Other Tag' }
+
+ selectionModel.items = [root, child, grandchild, other]
+ selectionModel.set(root.id, ToggleableItemState.Selected, false)
+ selectionModel.set(child.id, ToggleableItemState.Selected, false)
+ selectionModel.set(grandchild.id, ToggleableItemState.Selected, false)
+ selectionModel.set(other.id, ToggleableItemState.Selected, false)
+
+ selectionModel.toggle(root.id, false)
+
+ expect(selectionModel.getSelectedItems()).toEqual([other])
+ })
+
+ it('un-excluding a parent clears excluded descendants', () => {
+ const root: Tag = { id: 110, name: 'Root Tag' }
+ const child: Tag = { id: 111, name: 'Child Tag', parent: root.id }
+ const other: Tag = { id: 112, name: 'Other Tag' }
+
+ selectionModel.items = [root, child, other]
+ selectionModel.set(root.id, ToggleableItemState.Excluded, false)
+ selectionModel.set(child.id, ToggleableItemState.Excluded, false)
+ selectionModel.set(other.id, ToggleableItemState.Excluded, false)
+
+ selectionModel.exclude(root.id, false)
+
+ expect(selectionModel.getExcludedItems()).toEqual([other])
+ })
+
+ it('excluding a selected parent clears selected descendants', () => {
+ const root: Tag = { id: 120, name: 'Root Tag' }
+ const child: Tag = { id: 121, name: 'Child Tag', parent: root.id }
+ const other: Tag = { id: 122, name: 'Other Tag' }
+
+ selectionModel.manyToOne = true
+ selectionModel.items = [root, child, other]
+ selectionModel.set(root.id, ToggleableItemState.Selected, false)
+ selectionModel.set(child.id, ToggleableItemState.Selected, false)
+ selectionModel.set(other.id, ToggleableItemState.Selected, false)
+
+ selectionModel.exclude(root.id, false)
+
+ expect(selectionModel.getExcludedItems()).toEqual([root])
+ expect(selectionModel.getSelectedItems()).toEqual([other])
+ })
+
it('resorts items immediately when document count sorting enabled', () => {
const apple: Tag = { id: 55, name: 'Apple' }
const zebra: Tag = { id: 56, name: 'Zebra' }
diff --git a/src-ui/src/app/components/common/filterable-dropdown/filterable-dropdown.component.ts b/src-ui/src/app/components/common/filterable-dropdown/filterable-dropdown.component.ts
index ec5425630..bc15e3374 100644
--- a/src-ui/src/app/components/common/filterable-dropdown/filterable-dropdown.component.ts
+++ b/src-ui/src/app/components/common/filterable-dropdown/filterable-dropdown.component.ts
@@ -231,6 +231,7 @@ export class FilterableDropdownSelectionModel {
state == ToggleableItemState.Excluded
) {
this.temporarySelectionStates.delete(id)
+ this.clearDescendantSelections(id)
}
if (!id) {
@@ -257,6 +258,7 @@ export class FilterableDropdownSelectionModel {
if (this.manyToOne || this.singleSelect) {
this.temporarySelectionStates.set(id, ToggleableItemState.Excluded)
+ this.clearDescendantSelections(id)
if (this.singleSelect) {
for (let key of this.temporarySelectionStates.keys()) {
@@ -277,9 +279,15 @@ export class FilterableDropdownSelectionModel {
newState = ToggleableItemState.NotSelected
}
this.temporarySelectionStates.set(id, newState)
+ if (newState == ToggleableItemState.Excluded) {
+ this.clearDescendantSelections(id)
+ }
}
} else if (!id || state == ToggleableItemState.Excluded) {
this.temporarySelectionStates.delete(id)
+ if (id) {
+ this.clearDescendantSelections(id)
+ }
}
if (fireEvent) {
@@ -291,6 +299,33 @@ export class FilterableDropdownSelectionModel {
return this.selectionStates.get(id) || ToggleableItemState.NotSelected
}
+ private clearDescendantSelections(id: number) {
+ for (const descendantID of this.getDescendantIDs(id)) {
+ this.temporarySelectionStates.delete(descendantID)
+ }
+ }
+
+ private getDescendantIDs(id: number): number[] {
+ const descendants: number[] = []
+ const queue: number[] = [id]
+
+ while (queue.length) {
+ const parentID = queue.shift()
+ for (const item of this._items) {
+ if (
+ typeof item?.id === 'number' &&
+ typeof (item as any)['parent'] === 'number' &&
+ (item as any)['parent'] === parentID
+ ) {
+ descendants.push(item.id)
+ queue.push(item.id)
+ }
+ }
+ }
+
+ return descendants
+ }
+
get logicalOperator(): LogicalOperator {
return this.temporaryLogicalOperator
}
From 40255cfdbb8cf12c38df01a507b01e3f4991a697 Mon Sep 17 00:00:00 2001
From: shamoon <4887959+shamoon@users.noreply.github.com>
Date: Thu, 12 Mar 2026 14:06:16 -0700
Subject: [PATCH 4/7] Fix: correct dropdown list active color in dark mode
(#12328)
---
src-ui/src/theme.scss | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/src-ui/src/theme.scss b/src-ui/src/theme.scss
index eacc3b4e7..e6a4ea113 100644
--- a/src-ui/src/theme.scss
+++ b/src-ui/src/theme.scss
@@ -149,6 +149,10 @@ $form-check-radio-checked-bg-image-dark: url("data:image/svg+xml,