Files
fusion/packages/dashboard/app/components/workflowStatusCounts.ts
gsxdsm 7eceec00cc FN-6763: add themed workflow status switcher
Add a reusable dashboard workflow picker that shows inline task status counts across board and list views.

- Replace native workflow selects with a themed accessible dropdown component.
- Share workflow status count calculation between board and list views.
- Add styling, i18n labels, tests, and dashboard docs for the switcher behavior.

Files changed:
 docs/dashboard-guide.md                            |   3 +-
 packages/dashboard/app/components/Board.tsx        |  28 +--
 packages/dashboard/app/components/Lane.css         |   2 +
 .../dashboard/app/components/LeftSidebarNav.tsx    |   2 +-
 packages/dashboard/app/components/ListView.css     |  17 --
 packages/dashboard/app/components/ListView.tsx     |  31 ++-
 .../dashboard/app/components/WorkflowSwitcher.css  | 186 ++++++++++++++
 .../dashboard/app/components/WorkflowSwitcher.tsx  | 270 +++++++++++++++++++++
 .../app/components/__tests__/Board.test.tsx        |  60 +++--
 .../app/components/__tests__/ListView.test.tsx     |  79 +++++-
 .../components/__tests__/WorkflowSwitcher.test.tsx |  92 +++++++
 .../__tests__/workflowStatusCounts.test.ts         | 122 ++++++++++
 .../app/components/workflowStatusCounts.ts         |  54 +++++
 packages/i18n/locales/en/app.json                  |   9 +
 packages/i18n/locales/es/app.json                  |   9 +
 packages/i18n/locales/fr/app.json                  |   9 +
 packages/i18n/locales/ko/app.json                  |   9 +
 packages/i18n/locales/zh-CN/app.json               |   9 +
 packages/i18n/locales/zh-TW/app.json               |   9 +
 19 files changed, 930 insertions(+), 70 deletions(-)

Fusion-Task-Id: FN-6763
Fusion-Task-Lineage: 3503ea85-841a-4cd3-9960-1b22ef2cd4ea
2026-06-20 02:08:36 -07:00

55 lines
2.2 KiB
TypeScript

import type { Task } from "@fusion/core";
import type { BoardWorkflowColumn, BoardWorkflowsPayload } from "../api";
export interface WorkflowStatusCounts {
todo: number;
inProgress: number;
done: number;
}
const EMPTY_COUNTS = (): WorkflowStatusCounts => ({ todo: 0, inProgress: 0, done: 0 });
/**
* FNXC:WorkflowSwitcher 2026-06-20-00:09:
* The board/list workflow dropdown must show compact Todo, In Progress, and Done task counts for every selectable workflow without duplicating logic across render surfaces.
* Use workflow column flags as the source of truth: archived columns are excluded, complete columns count as Done, active non-intake WIP columns count as In Progress, and all remaining visible work counts as Todo/not-yet-started.
*/
export function computeWorkflowStatusCounts(
tasks: readonly Task[] | null | undefined,
boardWorkflows: BoardWorkflowsPayload | null | undefined,
): Map<string, WorkflowStatusCounts> {
const countsByWorkflow = new Map<string, WorkflowStatusCounts>();
if (!boardWorkflows) return countsByWorkflow;
const workflowsById = new Map(boardWorkflows.workflows.map((workflow) => [workflow.id, workflow]));
const columnsByWorkflowId = new Map<string, Map<string, BoardWorkflowColumn>>();
for (const workflow of boardWorkflows.workflows) {
countsByWorkflow.set(workflow.id, EMPTY_COUNTS());
columnsByWorkflowId.set(workflow.id, new Map(workflow.columns.map((column) => [column.id, column])));
}
if (!tasks?.length) return countsByWorkflow;
for (const task of tasks) {
const workflowId = boardWorkflows.taskWorkflowIds[task.id] ?? boardWorkflows.defaultWorkflowId;
const workflow = workflowsById.get(workflowId);
if (!workflow) continue;
const column = columnsByWorkflowId.get(workflow.id)?.get(task.column);
if (!column || column.flags.archived) continue;
const counts = countsByWorkflow.get(workflow.id) ?? EMPTY_COUNTS();
if (column.flags.complete) {
counts.done += 1;
} else if (column.flags.countsTowardWip && !column.flags.intake) {
counts.inProgress += 1;
} else {
counts.todo += 1;
}
countsByWorkflow.set(workflow.id, counts);
}
return countsByWorkflow;
}