fix(FN-0000): show auto-merge on workflow review columns
This commit is contained in:
3
.changeset/review-column-auto-merge.md
Normal file
3
.changeset/review-column-auto-merge.md
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
"@runfusion/fusion": patch
|
||||||
|
|
||||||
|
Allow built-in workflow review columns to surface the auto-merge toggle.
|
||||||
@@ -44,7 +44,7 @@ describe("builtin coding workflow ir", () => {
|
|||||||
expect(traitsFor("triage")).toEqual(["intake"]);
|
expect(traitsFor("triage")).toEqual(["intake"]);
|
||||||
expect(traitsFor("todo")).toEqual(["hold", "reset-on-entry"]);
|
expect(traitsFor("todo")).toEqual(["hold", "reset-on-entry"]);
|
||||||
expect(traitsFor("in-progress")).toEqual(["wip", "abort-on-exit", "timing"]);
|
expect(traitsFor("in-progress")).toEqual(["wip", "abort-on-exit", "timing"]);
|
||||||
expect(traitsFor("in-review")).toEqual(["merge-blocker", "stall-detection", "merge"]);
|
expect(traitsFor("in-review")).toEqual(["merge-blocker", "human-review", "stall-detection", "merge"]);
|
||||||
expect(traitsFor("done")).toEqual(["complete"]);
|
expect(traitsFor("done")).toEqual(["complete"]);
|
||||||
expect(traitsFor("archived")).toEqual(["archived"]);
|
expect(traitsFor("archived")).toEqual(["archived"]);
|
||||||
// todo's hold is capacity-released (legacy "pull from todo when a slot frees").
|
// todo's hold is capacity-released (legacy "pull from todo when a slot frees").
|
||||||
|
|||||||
@@ -107,4 +107,14 @@ describe("default workflow columns validate cleanly", () => {
|
|||||||
expect(flags.abortOnExit).toBe(true);
|
expect(flags.abortOnExit).toBe(true);
|
||||||
expect(flags.timing).toBe(true);
|
expect(flags.timing).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("the default workflow's in-review column resolves review and merge flags", () => {
|
||||||
|
const r = freshRegistry();
|
||||||
|
const ir = BUILTIN_CODING_WORKFLOW_IR as WorkflowIrV2;
|
||||||
|
const inReview = ir.columns.find((c) => c.id === "in-review")!;
|
||||||
|
const flags = r.resolveColumnFlags(inReview);
|
||||||
|
expect(flags.mergeBlocker).toBe(true);
|
||||||
|
expect(flags.humanReview).toBe(true);
|
||||||
|
expect(flags.mergeOrchestration).toBe(true);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import { BUILTIN_WORKFLOW_SETTINGS } from "./builtin-workflow-settings.js";
|
|||||||
* triage = intake
|
* triage = intake
|
||||||
* todo = hold(capacity) + reset-on-entry
|
* todo = hold(capacity) + reset-on-entry
|
||||||
* in-progress = wip + abort-on-exit + timing
|
* in-progress = wip + abort-on-exit + timing
|
||||||
* in-review = merge-blocker + stall-detection + merge
|
* in-review = merge-blocker + human-review + stall-detection + merge
|
||||||
* done = complete
|
* done = complete
|
||||||
* archived = archived
|
* archived = archived
|
||||||
*
|
*
|
||||||
@@ -39,7 +39,7 @@ const RAW_BUILTIN_CODING_WORKFLOW_IR: WorkflowIr = {
|
|||||||
{
|
{
|
||||||
id: "in-review",
|
id: "in-review",
|
||||||
name: "In review",
|
name: "In review",
|
||||||
traits: [{ trait: "merge-blocker" }, { trait: "stall-detection" }, { trait: "merge" }],
|
traits: [{ trait: "merge-blocker" }, { trait: "human-review" }, { trait: "stall-detection" }, { trait: "merge" }],
|
||||||
},
|
},
|
||||||
{ id: "done", name: "Done", traits: [{ trait: "complete" }] },
|
{ id: "done", name: "Done", traits: [{ trait: "complete" }] },
|
||||||
{ id: "archived", name: "Archived", traits: [{ trait: "archived" }] },
|
{ id: "archived", name: "Archived", traits: [{ trait: "archived" }] },
|
||||||
|
|||||||
@@ -26,8 +26,9 @@ import { BUILTIN_WORKFLOW_SETTINGS } from "./builtin-workflow-settings.js";
|
|||||||
* → merge seam
|
* → merge seam
|
||||||
*
|
*
|
||||||
* The columns/traits are identical to the default builtin so the full lifecycle
|
* The columns/traits are identical to the default builtin so the full lifecycle
|
||||||
* (merge-blocker, capacity, hold, complete, archived) behaves exactly as it does
|
* (merge-blocker, human review, capacity, hold, complete, archived) behaves
|
||||||
* for the default workflow — only the in-progress step modeling differs.
|
* exactly as it does for the default workflow — only the in-progress step
|
||||||
|
* modeling differs.
|
||||||
*
|
*
|
||||||
* It declares its step-source artifact (KTD-12): PROMPT.md produced by the
|
* It declares its step-source artifact (KTD-12): PROMPT.md produced by the
|
||||||
* planning seam. The IR is v2-only (foreach/step-review/parse-steps are v2 node
|
* planning seam. The IR is v2-only (foreach/step-review/parse-steps are v2 node
|
||||||
@@ -52,7 +53,7 @@ const RAW_BUILTIN_STEPWISE_CODING_WORKFLOW_IR: WorkflowIr = {
|
|||||||
{
|
{
|
||||||
id: "in-review",
|
id: "in-review",
|
||||||
name: "In review",
|
name: "In review",
|
||||||
traits: [{ trait: "merge-blocker" }, { trait: "stall-detection" }, { trait: "merge" }],
|
traits: [{ trait: "merge-blocker" }, { trait: "human-review" }, { trait: "stall-detection" }, { trait: "merge" }],
|
||||||
},
|
},
|
||||||
{ id: "done", name: "Done", traits: [{ trait: "complete" }] },
|
{ id: "done", name: "Done", traits: [{ trait: "complete" }] },
|
||||||
{ id: "archived", name: "Archived", traits: [{ trait: "archived" }] },
|
{ id: "archived", name: "Archived", traits: [{ trait: "archived" }] },
|
||||||
|
|||||||
@@ -205,7 +205,7 @@ function LaneComponent(props: LaneProps) {
|
|||||||
prAuthAvailable={props.prAuthAvailable}
|
prAuthAvailable={props.prAuthAvailable}
|
||||||
autoMerge={props.autoMerge}
|
autoMerge={props.autoMerge}
|
||||||
{...(isCreateColumn ? { onQuickCreate: props.onQuickCreate, onNewTask: props.onNewTask, onPlanningMode: props.onPlanningMode, onSubtaskBreakdown: props.onSubtaskBreakdown } : {})}
|
{...(isCreateColumn ? { onQuickCreate: props.onQuickCreate, onNewTask: props.onNewTask, onPlanningMode: props.onPlanningMode, onSubtaskBreakdown: props.onSubtaskBreakdown } : {})}
|
||||||
{...(col.flags.mergeBlocker ? { onToggleAutoMerge: props.onToggleAutoMerge } : {})}
|
{...((col.flags.mergeBlocker || col.flags.humanReview) && props.onToggleAutoMerge ? { onToggleAutoMerge: props.onToggleAutoMerge } : {})}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ const WORKFLOW: BoardWorkflowDefinition = {
|
|||||||
{ id: "triage", name: "Triage", flags: { intake: true } },
|
{ id: "triage", name: "Triage", flags: { intake: true } },
|
||||||
{ id: "todo", name: "Todo", flags: { hold: true } },
|
{ id: "todo", name: "Todo", flags: { hold: true } },
|
||||||
{ id: "in-progress", name: "In progress", flags: { countsTowardWip: true } },
|
{ id: "in-progress", name: "In progress", flags: { countsTowardWip: true } },
|
||||||
|
{ id: "in-review", name: "In review", flags: { humanReview: true } },
|
||||||
{ id: "done", name: "Done", flags: { complete: true } },
|
{ id: "done", name: "Done", flags: { complete: true } },
|
||||||
{ id: "archived", name: "Archived", flags: { archived: true } },
|
{ id: "archived", name: "Archived", flags: { archived: true } },
|
||||||
],
|
],
|
||||||
@@ -86,6 +87,7 @@ describe("Lane", () => {
|
|||||||
expect(headings).toContain("Triage");
|
expect(headings).toContain("Triage");
|
||||||
expect(headings).toContain("Todo");
|
expect(headings).toContain("Todo");
|
||||||
expect(headings).toContain("In progress");
|
expect(headings).toContain("In progress");
|
||||||
|
expect(headings).toContain("In review");
|
||||||
expect(headings).toContain("Done");
|
expect(headings).toContain("Done");
|
||||||
// Archived column is hidden.
|
// Archived column is hidden.
|
||||||
expect(headings).not.toContain("Archived");
|
expect(headings).not.toContain("Archived");
|
||||||
@@ -112,6 +114,11 @@ describe("Lane", () => {
|
|||||||
expect(props.onToggleCollapse).toHaveBeenCalledWith("builtin:coding");
|
expect(props.onToggleCollapse).toHaveBeenCalledWith("builtin:coding");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("shows the auto-merge toggle for human-review workflow columns", () => {
|
||||||
|
render(<Lane {...baseProps()} autoMerge={false} onToggleAutoMerge={vi.fn()} />);
|
||||||
|
expect(screen.getByText("Auto-merge")).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
it("shows a Promote button on hold-column cards and calls onPromote", async () => {
|
it("shows a Promote button on hold-column cards and calls onPromote", async () => {
|
||||||
const props = baseProps();
|
const props = baseProps();
|
||||||
render(<Lane {...props} tasks={[mkTask({ id: "FN-7", column: "todo" })]} />);
|
render(<Lane {...props} tasks={[mkTask({ id: "FN-7", column: "todo" })]} />);
|
||||||
|
|||||||
Reference in New Issue
Block a user