Files
fusion/packages/dashboard/app/utils/__tests__/quickAddStart.test.ts
Fusion Agent 612195fde6 FN-022: add workflow selection and start action
Add workflow-aware task creation controls and a guarded Start action for quick task intake.

- Add workflow selection and resolved board metadata loading to New Task modal.
- Support starting eligible tasks in their workflow destination with clear success or partial-failure feedback.
- Wire move-task handling through modal callers and cover workflow/start behavior with tests and documentation.

Files changed:
 .changeset/fn-022-new-task-workflow-start.md       |   7 +
 docs/dashboard-guide.md                            |   4 +-
 packages/dashboard/app/components/AppModals.tsx    |   1 +
 packages/dashboard/app/components/NewTaskModal.tsx | 158 +++++++++++++++--
 .../dashboard/app/components/QuickEntryBox.tsx     |   5 +-
 packages/dashboard/app/components/TaskForm.tsx     |  28 ++-
 .../app/components/__tests__/AppModals.test.tsx    |  33 +++-
 .../app/components/__tests__/NewTaskModal.test.tsx | 192 ++++++++++++++++++++-
 .../app/utils/__tests__/quickAddStart.test.ts      |  16 +-
 packages/dashboard/app/utils/quickAddStart.ts      |  15 ++
 10 files changed, 441 insertions(+), 18 deletions(-)

Fusion-Task-Id: FN-022

Fusion-Task-Lineage: ce794b44-3c31-4bfc-a259-ecfd78531be1

Co-authored-by: Fusion <noreply@runfusion.ai>
2026-08-20 03:55:38 +00:00

108 lines
5.6 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { resolveQuickAddStartInitialColumn, resolveQuickAddStartTargetColumn, resolveQuickAddStartWorkflowTarget, validateQuickAddStartWorkflow, workflowSupportsQuickAddStart } from "../quickAddStart";
const workflow = (overrides: Record<string, unknown> = {}) => ({
id: "custom",
name: "Custom",
columns: [
{ id: "ideas", name: "Ideas", flags: { hold: true } },
{ id: "todo", name: "Todo", flags: {} },
{ id: "done", name: "Done", flags: { complete: true } },
],
...overrides,
});
describe("quick add Start workflow guards", () => {
it("limits resolved built-ins to Coding Ideas", () => {
const resolvedBuiltinFirstColumns = [
["builtin:coding-ideas", { intake: true, hold: true, manualIntake: true }, true],
["builtin:coding", { intake: true, hold: true }, false],
["builtin:quick-fix", { intake: true, hold: true }, false],
["builtin:stepwise-coding", { intake: true, hold: true }, false],
["builtin:review-heavy", { intake: true, hold: true }, false],
["builtin:design", { intake: true, hold: true }, false],
["builtin:compound-engineering", { intake: true, hold: true }, false],
["builtin:marketing", { intake: true, hold: true }, false],
["builtin:pr-workflow", { intake: true, hold: true }, false],
] as const;
for (const [id, flags, expected] of resolvedBuiltinFirstColumns) {
expect(workflowSupportsQuickAddStart(validateQuickAddStartWorkflow(workflow({
id,
columns: [{ id: "planning", flags }, { id: "done", flags: { complete: true } }],
})))).toBe(expected);
}
});
it("requires a first visible manual intake and complete runtime metadata", () => {
expect(workflowSupportsQuickAddStart(validateQuickAddStartWorkflow(workflow()))).toBe(false);
expect(workflowSupportsQuickAddStart(validateQuickAddStartWorkflow(workflow({ columns: [
{ id: "waiting", flags: { intake: true, hold: true, manualIntake: true } },
{ id: "todo", flags: {} },
] })))).toBe(true);
expect(workflowSupportsQuickAddStart(validateQuickAddStartWorkflow(workflow({ columns: [
{ id: "archived", flags: { archived: true, manualIntake: true } },
{ id: "waiting", flags: { manualIntake: true } },
] })))).toBe(true);
expect(workflowSupportsQuickAddStart(validateQuickAddStartWorkflow(workflow({ columns: [
{ id: "hidden", flags: { hiddenFromBoard: true, manualIntake: true } },
{ id: "planning", flags: { intake: true, hold: true } },
] })))).toBe(false);
expect(validateQuickAddStartWorkflow(workflow({ id: "__all_workflows__" }))).toBeNull();
expect(validateQuickAddStartWorkflow(workflow({ columns: [] }))).toBeNull();
expect(validateQuickAddStartWorkflow(workflow({ columns: [{ id: "", flags: {} }] }))).toBeNull();
expect(validateQuickAddStartWorkflow(workflow({ columns: [{ id: "a", flags: {} }, { id: "a", flags: {} }] }))).toBeNull();
expect(validateQuickAddStartWorkflow(workflow({ columns: [{ id: "a", flags: null }] }))).toBeNull();
});
it("derives Todo only from a captured, visible Coding Ideas definition", () => {
const canonical = validateQuickAddStartWorkflow(workflow({ id: "builtin:coding-ideas" }));
expect(canonical).not.toBeNull();
expect(resolveQuickAddStartInitialColumn(canonical!)).toBe("todo");
for (const columns of [
[{ id: "ideas", flags: { hold: true } }, { id: "todo", flags: { hiddenFromBoard: true } }],
[{ id: "todo", flags: {} }, { id: "ideas", flags: { hold: true } }],
[{ id: "ideas", flags: { hold: true } }, { id: "todo", flags: { intake: true } }],
[{ id: "ideas", flags: { hold: true } }, { id: "todo", flags: { complete: true } }],
]) {
const invalidTarget = validateQuickAddStartWorkflow(workflow({ id: "builtin:coding-ideas", columns }));
expect(invalidTarget).not.toBeNull();
expect(resolveQuickAddStartInitialColumn(invalidTarget!)).toBeNull();
}
expect(resolveQuickAddStartInitialColumn(validateQuickAddStartWorkflow(workflow())!)).toBeNull();
expect(validateQuickAddStartWorkflow(workflow({
id: "builtin:coding-ideas",
columns: [{ id: "ideas", flags: {} }, { id: "todo", flags: {} }, { id: "todo", flags: {} }],
}))).toBeNull();
});
it("proves a Start target from the manual intake lane", () => {
const valid = validateQuickAddStartWorkflow(workflow({ columns: [
{ id: "waiting", name: "Waiting", flags: { intake: true, manualIntake: true } },
{ id: "building", name: "Building", flags: {} },
{ id: "done", name: "Done", flags: { complete: true } },
] }));
expect(resolveQuickAddStartWorkflowTarget(valid)).toBe("building");
const noTarget = validateQuickAddStartWorkflow(workflow({ columns: [
{ id: "waiting", name: "Waiting", flags: { intake: true, manualIntake: true } },
{ id: "done", name: "Done", flags: { complete: true } },
] }));
expect(resolveQuickAddStartWorkflowTarget(noTarget)).toBeNull();
});
it("only chooses a later visible working destination", () => {
const valid = validateQuickAddStartWorkflow(workflow({ columns: [
{ id: "ideas", name: "Ideas", flags: { hold: true } },
{ id: "review", name: "Review", flags: { hold: true } },
{ id: "done", name: "Done", flags: { complete: true } },
{ id: "todo", name: "Todo", flags: {} },
] }));
expect(valid).not.toBeNull();
expect(resolveQuickAddStartTargetColumn(valid!, "ideas")).toBe("todo");
expect(resolveQuickAddStartTargetColumn(valid!, "todo")).toBeNull();
expect(resolveQuickAddStartTargetColumn(valid!, "unknown")).toBeNull();
});
});