From b1fe53386c31b573a5dbd3d038360af435969681 Mon Sep 17 00:00:00 2001 From: inman Date: Wed, 2 Sep 2026 13:12:00 +0800 Subject: [PATCH] fix: make dashboard metrics display-only --- .../20260902-dashboard-metrics-static-a91c.md | 58 +++++++++++++++++++ .../app-operations-dashboard.test.mjs | 15 ++++- LianSyn-platform/app.js | 26 ++------- LianSyn-platform/index.html | 4 +- LianSyn-platform/styles.css | 17 ------ .../test/account-authorization.test.ts | 3 +- control-plane/test/control-plane.test.ts | 4 +- 7 files changed, 82 insertions(+), 45 deletions(-) create mode 100644 .project-docs/30-worklog/tasks/20260902-dashboard-metrics-static-a91c.md diff --git a/.project-docs/30-worklog/tasks/20260902-dashboard-metrics-static-a91c.md b/.project-docs/30-worklog/tasks/20260902-dashboard-metrics-static-a91c.md new file mode 100644 index 0000000..34ee4d9 --- /dev/null +++ b/.project-docs/30-worklog/tasks/20260902-dashboard-metrics-static-a91c.md @@ -0,0 +1,58 @@ +# Task: Make dashboard metrics display-only + +## Identity + +- Task ID: 20260902-dashboard-metrics-static-a91c +- Mode: Feature +- Branch: codex/20260902-dashboard-metrics-static-a91c-dashboard-metrics-static-a91c +- Worktree: /Users/inmanx/Documents/lwltAPI-dashboard-metrics-static-a91c +- Base commit: d034f649c4e7c5d0856f22053b92d2e5a63be5eb +- Owner: codex +- Status: Ready for integration + +## Scope + +- Make every leadership-dashboard metric card display-only and remove card-driven status filtering/selection state. +- Keep the task-result filter as the explicit status control, defaulting to `all` so the task list initially shows all matching data. +- Remove obsolete interactive/selected metric-card styles and add focused regression coverage. +- Bump the platform asset cache token so the JavaScript and CSS behavior is not masked by a previously cached dashboard build. + +## Intent And Constraints + +- Preserve the accepted read-only leadership-dashboard authorization, business-facing projection, mobile layout, and ranking drill-through behavior. +- Preserve the existing presentation rule that internal attention/waiting states are exposed as “进行中”; do not change task lifecycle storage or server classification. +- Do not change dashboard APIs, permissions, task data, ERP behavior, runtime services, deployment, or canonical project memory in this Feature task. +- Work in the isolated task worktree and reconcile the concurrent main-worktree kanban-filter task before integration; do not adopt or modify its uncommitted files. + +## Outcome + +- `renderOperationsDashboardSummary()` now emits five uniform, non-interactive `article` cards with no status metadata, selected-state computation, `aria-pressed`, or card-driven filter mutation. +- Removed the summary-container click handler and the obsolete metric-card pointer, hover, and `.is-active` styles. +- Preserved the explicit task-result filter and its `all` initialization, so the dashboard task list opens on all matching results while status changes remain opt-in through the filter form. +- Updated focused platform and authorization regressions, and advanced the dashboard asset cache token to `20260902-dashboard-metrics-static-1`. + +## Verification + +- Passed: bundled Node `--check LianSyn-platform/app.js`. +- Passed: focused dashboard regression, 4/4 tests. +- Passed: focused account-authorization regression, 8/8 tests. +- Passed: repository hygiene, 10/10 tests. +- Passed: TypeScript no-emit check. +- Passed: control-plane regression, 156/156 tests. +- Passed: legacy/platform/tool regression, 267/267 tests. +- Passed: TypeScript build. +- Passed: `git diff --check`. +- Note: the initial `node --run ...` wrappers did not enter the checks because this host has no `node` on the child-shell `PATH`; the same scripts were rerun successfully with the bundled Node executable and direct equivalent commands. + +## Follow-ups + +- Reconcile this focused change with the concurrently active main-worktree kanban-filter task before integrating; do not overwrite its unknown changes. + +## Promotion Candidates + +- Target canonical document: `.project-docs/40-domain/business-rules.md` during Integration Gate review. +- Proposal: leadership-dashboard metric cards are display-only summaries and do not carry selection/filter behavior; task results initialize to all data, while explicit status filtering remains in the filter section. +- Evidence: the user's explicit correction plus focused and full repository verification recorded above. +- Future impact: dashboard metric-card rendering and mobile presentation should not reintroduce button semantics, selected-state styles, or implicit status filtering unless a later product decision explicitly restores them. +- Semantic conflicts: none with AUTH-001 or the existing business-facing merge of internal attention states into “进行中”. The concurrent kanban-filter task may overlap code paths but its scope was still undefined when this task planned. +- Human confirmation: provided directly by the user in this task request. diff --git a/LianSyn-platform/app-operations-dashboard.test.mjs b/LianSyn-platform/app-operations-dashboard.test.mjs index 3896a23..03c793c 100644 --- a/LianSyn-platform/app-operations-dashboard.test.mjs +++ b/LianSyn-platform/app-operations-dashboard.test.mjs @@ -9,12 +9,21 @@ const [app, index, styles, taskService] = await Promise.all([ readFile(new URL('../control-plane/src/task-service.ts', import.meta.url), 'utf8') ]); -test('dashboard summary cards share one visual treatment and expose an accessible selected state', () => { +test('dashboard summary cards are uniform display-only totals and leave filtering to the explicit controls', () => { + const summaryRenderer = app.slice( + app.indexOf('function renderOperationsDashboardSummary()'), + app.indexOf('function operationsDashboardRankScale') + ); assert.match(app, /label: '操作次数'[^\n]+tone: 'total'/); assert.doesNotMatch(app, /tone: 'primary'/); - assert.match(app, /card\.setAttribute\('aria-pressed', String\(isSelected\)\)/); + assert.match(summaryRenderer, /const card = el\('article', `operations-dashboard-stat operations-dashboard-stat-\$\{item\.tone\}`\)/); + assert.doesNotMatch(summaryRenderer, /selectedStatus|isSelected|operationsStatus|aria-pressed/); + assert.doesNotMatch(app, /\$\('#operationsDashboardSummary'\)\?\.addEventListener\('click'/); + assert.match(index, /