Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions examples/app-showcase/src/ui/pages/command-center.page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,16 @@ function chart(id: string, chartType: string, dataset: string, dimensions: strin

const CHART_H = '376px';

/**
* The review set — tasks whose `status` is `in_review`. ONE value read by two
* blocks: the KPI tile `cc_k3` counts it, and the work queue `cc_queue_g`
* under its 待审核列表 / 审批中 heading lists it, so the panel shows exactly
* the rows the tile counts. `object-grid` reads `filter` (singular, the
* `ViewFilterRule` array — `ComponentPropsMap['object-grid']`) and lowers it
* to `$filter`.
*/
const IN_REVIEW = [{ field: 'status', operator: 'equals', value: 'in_review' }];

export const CommandCenterPage = definePage({
name: 'showcase_command_center',
label: 'Command Center (大屏)',
Expand Down Expand Up @@ -146,7 +156,7 @@ export const CommandCenterPage = definePage({
child: band('cc_kpi_grid', 6, [
kpi('cc_k1', 'showcase_project', '活跃项目 Active', 'blue', { field: 'id', function: 'count' }, [{ field: 'status', operator: 'equals', value: 'active' }]),
kpi('cc_k2', 'showcase_task', '待办任务 Open', 'teal', { field: 'id', function: 'count' }, [{ field: 'status', operator: 'not_equals', value: 'done' }]),
kpi('cc_k3', 'showcase_task', '待复审 Review', 'purple', { field: 'id', function: 'count' }, [{ field: 'status', operator: 'equals', value: 'in_review' }]),
kpi('cc_k3', 'showcase_task', '待复审 Review', 'purple', { field: 'id', function: 'count' }, IN_REVIEW),
kpi('cc_k4', 'showcase_project', '风险项目 At-Risk', 'danger', { field: 'id', function: 'count' }, [{ field: 'health', operator: 'equals', value: 'red' }]),
kpi('cc_k5', 'showcase_account', '客户 Accounts', 'orange', { field: 'id', function: 'count' }),
kpi('cc_k6', 'showcase_project', '总预算 Budget', 'success', { field: 'budget', function: 'sum' }, undefined, '0.0a'),
Expand All @@ -169,7 +179,7 @@ export const CommandCenterPage = definePage({
// ── Work queue — its own full-width row at the bottom ────────
panel({
id: 'cc_queue', title: '待审核列表 · Work Queue', accent: A.c1, badge: '审批中', minHeight: '0px',
child: { id: 'cc_queue_g', type: 'object-grid', responsiveStyles: { large: { minWidth: '0', display: 'block' } }, properties: { objectName: 'showcase_task', columns: ['title', 'project', 'status', 'priority', 'due_date'] } },
child: { id: 'cc_queue_g', type: 'object-grid', responsiveStyles: { large: { minWidth: '0', display: 'block' } }, properties: { objectName: 'showcase_task', columns: ['title', 'project', 'status', 'priority', 'due_date'], filter: IN_REVIEW } },
}),
],
},
Expand Down
62 changes: 62 additions & 0 deletions examples/app-showcase/test/command-center-metric-filter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,65 @@ describe('Command Center — object-metric properties parse against their Compon
}
});
});

/**
* The work queue lists the set the KPI tile above it counts.
*
* `cc_queue_g` sits under the heading 待审核列表 · Work Queue with the badge
* 审批中, and the tile `cc_k3` (待复审 Review) counts tasks whose `status` is
* `in_review`. The grid carried no filter, so it listed every task, done ones
* included, while the tile beside it counted two.
*
* `filter` is the key `object-grid` declares (`ComponentPropsMap['object-grid']`,
* the `ViewFilterRule` array) and the one the committed `sdui.manifest.json`
* lists among the grid's inputs; the renderer lowers it to `$filter`. The pin
* asserts that key, parses the whole bag against the grid's row, and holds the
* queue's rules equal to the tile's so the two cannot drift apart.
*/
function nodeById(root: unknown, id: string): AnyRec | undefined {
let found: AnyRec | undefined;
const visit = (v: unknown): void => {
if (found) return;
if (Array.isArray(v)) {
for (const item of v) visit(item);
return;
}
if (!isRec(v)) return;
if (v.id === id) {
found = v;
return;
}
for (const child of Object.values(v)) visit(child);
};
visit(root);
return found;
}

describe('Command Center — the work queue lists the review set its KPI counts', () => {
const queue = nodeById(CommandCenterPage.regions, 'cc_queue_g');
const tile = nodeById(CommandCenterPage.regions, 'cc_k3');
const queueProps = isRec(queue?.properties) ? queue.properties : {};
const tileProps = isRec(tile?.properties) ? tile.properties : {};

it('finds the queue grid and the Review tile', () => {
expect(queue?.type).toBe('object-grid');
expect(tile?.type).toBe('object-metric');
expect(queueProps.objectName).toBe(tileProps.objectName);
});

it('scopes the queue to in_review tasks through `filter`', () => {
expect(queueProps.filter).toEqual([{ field: 'status', operator: 'equals', value: 'in_review' }]);
});

it("carries the same rules as the tile `cc_k3`", () => {
expect(queueProps.filter).toEqual(tileProps.filter);
});

it('the queue properties bag parses clean against its ComponentPropsMap row', () => {
const result = ComponentPropsMap['object-grid'].safeParse(queueProps);
const failures = result.success
? []
: result.error.issues.map((issue) => `properties.${issue.path.join('.')}: ${issue.code}`);
expect(failures).toEqual([]);
});
});
Loading