feat(themen): key reader tag visibility on the subtree rollup (#698)
Regenerate the TagTreeNodeDTO type with subtreeDocumentCount and switch hasAnyDocuments to read it directly — the backend rollup already includes all descendants, so the recursive children walk is no longer needed. Reader surfaces now hide a topic only when its whole subtree is empty. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -2230,6 +2230,11 @@ export interface components {
|
|||||||
color?: string;
|
color?: string;
|
||||||
/** Format: int32 */
|
/** Format: int32 */
|
||||||
documentCount: number;
|
documentCount: number;
|
||||||
|
/**
|
||||||
|
* Format: int32
|
||||||
|
* @description Distinct documents tagged with this tag or any descendant tag (subtree rollup)
|
||||||
|
*/
|
||||||
|
subtreeDocumentCount: number;
|
||||||
children?: components["schemas"]["TagTreeNodeDTO"][];
|
children?: components["schemas"]["TagTreeNodeDTO"][];
|
||||||
/**
|
/**
|
||||||
* Format: uuid
|
* Format: uuid
|
||||||
|
|||||||
@@ -4,26 +4,29 @@ import type { components } from '$lib/generated/api';
|
|||||||
|
|
||||||
type TagTreeNodeDTO = components['schemas']['TagTreeNodeDTO'];
|
type TagTreeNodeDTO = components['schemas']['TagTreeNodeDTO'];
|
||||||
|
|
||||||
function makeNode(documentCount: number, children: TagTreeNodeDTO[] = []): TagTreeNodeDTO {
|
function makeNode(
|
||||||
return { id: 'id', name: 'name', documentCount, children };
|
documentCount: number,
|
||||||
|
subtreeDocumentCount: number,
|
||||||
|
children: TagTreeNodeDTO[] = []
|
||||||
|
): TagTreeNodeDTO {
|
||||||
|
return { id: 'id', name: 'name', documentCount, subtreeDocumentCount, children };
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('hasAnyDocuments', () => {
|
describe('hasAnyDocuments', () => {
|
||||||
it('returns false for a leaf node with documentCount=0', () => {
|
it('returns false for a node whose subtree holds no documents', () => {
|
||||||
expect(hasAnyDocuments(makeNode(0))).toBe(false);
|
expect(hasAnyDocuments(makeNode(0, 0))).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns true for a leaf node with documentCount=3', () => {
|
it('returns true for a node whose subtree holds documents', () => {
|
||||||
expect(hasAnyDocuments(makeNode(3))).toBe(true);
|
expect(hasAnyDocuments(makeNode(3, 3))).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns true for a root with documentCount=0 but a child with documentCount=5', () => {
|
it('keys on the subtree rollup, not direct documentCount: 0 direct but rollup 5 → true', () => {
|
||||||
const node = makeNode(0, [makeNode(5)]);
|
// The rollup already includes descendants — a single field read, no recursion over children.
|
||||||
expect(hasAnyDocuments(node)).toBe(true);
|
expect(hasAnyDocuments(makeNode(0, 5))).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns false for a root with documentCount=0 and all children also 0', () => {
|
it('keys on the subtree rollup, not direct documentCount: 5 direct but rollup 0 → false', () => {
|
||||||
const node = makeNode(0, [makeNode(0), makeNode(0)]);
|
expect(hasAnyDocuments(makeNode(5, 0))).toBe(false);
|
||||||
expect(hasAnyDocuments(node)).toBe(false);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -2,6 +2,12 @@ import type { components } from '$lib/generated/api';
|
|||||||
|
|
||||||
type TagTreeNodeDTO = components['schemas']['TagTreeNodeDTO'];
|
type TagTreeNodeDTO = components['schemas']['TagTreeNodeDTO'];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether a tag's whole subtree holds any documents — keyed on the subtree rollup
|
||||||
|
* (`subtreeDocumentCount`), which the backend already computes across all descendants.
|
||||||
|
* Used by the reader surfaces (/themen page, dashboard ThemenWidget) to hide empty topics.
|
||||||
|
* A single field read: no recursion needed, the rollup is authoritative.
|
||||||
|
*/
|
||||||
export function hasAnyDocuments(node: TagTreeNodeDTO): boolean {
|
export function hasAnyDocuments(node: TagTreeNodeDTO): boolean {
|
||||||
return (node.documentCount ?? 0) > 0 || (node.children ?? []).some(hasAnyDocuments);
|
return (node.subtreeDocumentCount ?? 0) > 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user