FN-6038: swap workflow toolbar edit and create buttons
Swap the workflow toolbar actions so editing appears before creation. - move the workflow editor pencil button ahead of the new workflow plus button in the board toolbar - add assertions covering the full toolbar order when both actions are present - add coverage for cases where only one workflow toolbar action is available Files changed: packages/dashboard/app/components/Board.tsx | 22 +++++++-------- packages/dashboard/app/components/__tests__/Board.test.tsx | 33 ++++++++++++++++++++++ 2 files changed, 44 insertions(+), 11 deletions(-) Fusion-Task-Id: FN-6038 Fusion-Task-Lineage: 4fb28d7c-3261-4d45-9363-2b340e4aea35
This commit is contained in:
@@ -456,17 +456,6 @@ export function Board({ tasks, projectId, maxConcurrent, onMoveTask, onPauseTask
|
|||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
)}
|
)}
|
||||||
{onCreateWorkflow && (
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="btn btn-icon btn-sm board-workflow-create-btn"
|
|
||||||
onClick={onCreateWorkflow}
|
|
||||||
title="New workflow"
|
|
||||||
aria-label="New workflow"
|
|
||||||
>
|
|
||||||
<Plus size={15} />
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
{onOpenWorkflowEditor && (
|
{onOpenWorkflowEditor && (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
@@ -478,6 +467,17 @@ export function Board({ tasks, projectId, maxConcurrent, onMoveTask, onPauseTask
|
|||||||
<Pencil size={15} />
|
<Pencil size={15} />
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
|
{onCreateWorkflow && (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="btn btn-icon btn-sm board-workflow-create-btn"
|
||||||
|
onClick={onCreateWorkflow}
|
||||||
|
title="New workflow"
|
||||||
|
aria-label="New workflow"
|
||||||
|
>
|
||||||
|
<Plus size={15} />
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<main
|
<main
|
||||||
|
|||||||
@@ -921,6 +921,12 @@ describe("Board", () => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function workflowToolbarActionNames() {
|
||||||
|
const toolbar = document.querySelector(".board-workflow-toolbar");
|
||||||
|
expect(toolbar).not.toBeNull();
|
||||||
|
return Array.from(toolbar?.querySelectorAll("button") ?? []).map((button) => button.getAttribute("aria-label"));
|
||||||
|
}
|
||||||
|
|
||||||
it("flag OFF renders the legacy single-lane board byte-identically", async () => {
|
it("flag OFF renders the legacy single-lane board byte-identically", async () => {
|
||||||
fetchBoardWorkflowsMock.mockResolvedValue({
|
fetchBoardWorkflowsMock.mockResolvedValue({
|
||||||
flagEnabled: false,
|
flagEnabled: false,
|
||||||
@@ -1000,6 +1006,7 @@ describe("Board", () => {
|
|||||||
|
|
||||||
await waitFor(() => expect(screen.getByTestId("column-triage")).toBeDefined());
|
await waitFor(() => expect(screen.getByTestId("column-triage")).toBeDefined());
|
||||||
expect(screen.queryByLabelText("Select workflow")).toBeNull();
|
expect(screen.queryByLabelText("Select workflow")).toBeNull();
|
||||||
|
expect(workflowToolbarActionNames()).toEqual(["Edit workflows", "New workflow"]);
|
||||||
|
|
||||||
fireEvent.click(screen.getByRole("button", { name: "New workflow" }));
|
fireEvent.click(screen.getByRole("button", { name: "New workflow" }));
|
||||||
fireEvent.click(screen.getByRole("button", { name: "Edit workflows" }));
|
fireEvent.click(screen.getByRole("button", { name: "Edit workflows" }));
|
||||||
@@ -1007,8 +1014,30 @@ describe("Board", () => {
|
|||||||
expect(onOpenWorkflowEditor).toHaveBeenCalledTimes(1);
|
expect(onOpenWorkflowEditor).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("preserves workflow toolbar partial action visibility", async () => {
|
||||||
|
const onCreateWorkflow = vi.fn();
|
||||||
|
enableFlag({}, [DEFAULT_WORKFLOW]);
|
||||||
|
const { unmount } = renderBoard({ onCreateWorkflow });
|
||||||
|
|
||||||
|
await waitFor(() => expect(screen.getByTestId("column-triage")).toBeDefined());
|
||||||
|
expect(workflowToolbarActionNames()).toEqual(["New workflow"]);
|
||||||
|
fireEvent.click(screen.getByRole("button", { name: "New workflow" }));
|
||||||
|
expect(onCreateWorkflow).toHaveBeenCalledTimes(1);
|
||||||
|
unmount();
|
||||||
|
|
||||||
|
const onOpenWorkflowEditor = vi.fn();
|
||||||
|
enableFlag({}, [DEFAULT_WORKFLOW]);
|
||||||
|
renderBoard({ onOpenWorkflowEditor });
|
||||||
|
|
||||||
|
await waitFor(() => expect(screen.getByTestId("column-triage")).toBeDefined());
|
||||||
|
expect(workflowToolbarActionNames()).toEqual(["Edit workflows"]);
|
||||||
|
fireEvent.click(screen.getByRole("button", { name: "Edit workflows" }));
|
||||||
|
expect(onOpenWorkflowEditor).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
|
||||||
it("renders one selected workflow at a time and switches workflows from the dropdown", async () => {
|
it("renders one selected workflow at a time and switches workflows from the dropdown", async () => {
|
||||||
const onCreateWorkflow = vi.fn();
|
const onCreateWorkflow = vi.fn();
|
||||||
|
const onOpenWorkflowEditor = vi.fn();
|
||||||
enableFlag(
|
enableFlag(
|
||||||
{ "FN-1": "builtin:coding", "FN-2": "wf-custom", "FN-3": "wf-custom" },
|
{ "FN-1": "builtin:coding", "FN-2": "wf-custom", "FN-3": "wf-custom" },
|
||||||
[DEFAULT_WORKFLOW, CUSTOM_WORKFLOW],
|
[DEFAULT_WORKFLOW, CUSTOM_WORKFLOW],
|
||||||
@@ -1020,11 +1049,15 @@ describe("Board", () => {
|
|||||||
mkTask({ id: "FN-3", column: "intake" }),
|
mkTask({ id: "FN-3", column: "intake" }),
|
||||||
],
|
],
|
||||||
onCreateWorkflow,
|
onCreateWorkflow,
|
||||||
|
onOpenWorkflowEditor,
|
||||||
});
|
});
|
||||||
const selector = await screen.findByLabelText("Select workflow") as HTMLSelectElement;
|
const selector = await screen.findByLabelText("Select workflow") as HTMLSelectElement;
|
||||||
expect(selector.value).toBe("builtin:coding");
|
expect(selector.value).toBe("builtin:coding");
|
||||||
|
expect(workflowToolbarActionNames()).toEqual(["Edit workflows", "New workflow"]);
|
||||||
fireEvent.click(screen.getByRole("button", { name: "New workflow" }));
|
fireEvent.click(screen.getByRole("button", { name: "New workflow" }));
|
||||||
|
fireEvent.click(screen.getByRole("button", { name: "Edit workflows" }));
|
||||||
expect(onCreateWorkflow).toHaveBeenCalledTimes(1);
|
expect(onCreateWorkflow).toHaveBeenCalledTimes(1);
|
||||||
|
expect(onOpenWorkflowEditor).toHaveBeenCalledTimes(1);
|
||||||
expect(JSON.parse(screen.getByTestId("column-todo").getAttribute("data-tasks") || "[]").map((task: Task) => task.id)).toEqual(["FN-1"]);
|
expect(JSON.parse(screen.getByTestId("column-todo").getAttribute("data-tasks") || "[]").map((task: Task) => task.id)).toEqual(["FN-1"]);
|
||||||
expect(screen.queryByTestId("column-intake")).toBeNull();
|
expect(screen.queryByTestId("column-intake")).toBeNull();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user