FN-6781: keep Command Center inline in the header
Keep Command Center anchored as an inline header destination while preserving changed-test coverage selection. - Render Command Center immediately after Agents on tablet and desktop instead of moving it into the More views overflow. - Update header and tablet tests plus docs to lock the stable inline navigation contract. - Treat the quarantine data file as test-irrelevant so edits do not force gate mode and drop affected-package tests. Files changed: .changeset/fix-quarantine-json-gate-mode.md | 5 ++ .changeset/fn-6781-command-center-header.md | 5 ++ CONCEPTS.md | 3 + docs/dashboard-guide.md | 4 +- ...data-file-forces-gate-mode-dropping-coverage.md | 74 ++++++++++++++++++++++ .../app/__tests__/tablet-header-controls.test.tsx | 7 +- packages/dashboard/app/components/Header.tsx | 51 +++++---------- .../app/components/__tests__/Header.test.tsx | 8 ++- scripts/__tests__/test-changed.test.mjs | 20 ++++++ scripts/test-changed.mjs | 8 +++ 10 files changed, 142 insertions(+), 43 deletions(-) Fusion-Task-Id: FN-6781 Fusion-Task-Lineage: d328501d-7ec4-40ac-a140-6a491ea560e2
This commit is contained in:
5
.changeset/fn-6781-command-center-header.md
Normal file
5
.changeset/fn-6781-command-center-header.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"@runfusion/fusion": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Keep Command Center inline next to Agents across desktop and tablet header widths instead of moving it into the More views overflow menu.
|
||||||
@@ -658,8 +658,8 @@ Features:
|
|||||||
Command Center is the combined analytics and live-operations surface for a project: it pairs historical usage, cost, throughput analytics, live system telemetry, and a live Mission Control panel.
|
Command Center is the combined analytics and live-operations surface for a project: it pairs historical usage, cost, throughput analytics, live system telemetry, and a live Mission Control panel.
|
||||||
|
|
||||||
Navigation:
|
Navigation:
|
||||||
- Desktop: **Header → More views → Command Center**
|
- Desktop/tablet: primary header view toggle, immediately after **Agents**
|
||||||
- Mobile: **More** sheet → **Command Center**
|
- Mobile: bottom nav tab, immediately after **Mailbox**
|
||||||
- Deep link: `?view=command-center`
|
- Deep link: `?view=command-center`
|
||||||
|
|
||||||
Features:
|
Features:
|
||||||
|
|||||||
@@ -113,14 +113,15 @@ describe("tablet header controls", () => {
|
|||||||
expect(screen.queryByTestId("view-overflow-command-center")).toBeNull();
|
expect(screen.queryByTestId("view-overflow-command-center")).toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("keeps desktop Documents inline and Command Center in overflow", () => {
|
it("keeps desktop Documents and Command Center inline without Command Center overflow", () => {
|
||||||
renderDesktopHeader({ onChangeView: noop, showAgentsTab: true });
|
renderDesktopHeader({ onChangeView: noop, showAgentsTab: true });
|
||||||
|
|
||||||
expect(screen.getByTitle("Documents view")).toBeDefined();
|
expect(screen.getByTitle("Documents view")).toBeDefined();
|
||||||
expect(screen.queryByTestId("view-toggle-command-center")).toBeNull();
|
expect(screen.getByTestId("view-toggle-command-center")).toBeDefined();
|
||||||
|
expect(screen.getByTestId("view-toggle-command-center").previousElementSibling).toBe(screen.getByTitle("Agents view"));
|
||||||
|
|
||||||
fireEvent.click(screen.getByTestId("view-toggle-overflow-trigger"));
|
fireEvent.click(screen.getByTestId("view-toggle-overflow-trigger"));
|
||||||
expect(screen.getByTestId("view-overflow-command-center")).toBeDefined();
|
expect(screen.queryByTestId("view-overflow-command-center")).toBeNull();
|
||||||
expect(screen.queryByTestId("view-overflow-documents")).toBeNull();
|
expect(screen.queryByTestId("view-overflow-documents")).toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1019,26 +1019,21 @@ export function Header({
|
|||||||
<Bot size={16} />
|
<Bot size={16} />
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
{isTablet && (
|
{/*
|
||||||
/*
|
FNXC:Navigation 2026-06-19-12:00:
|
||||||
FNXC:Navigation 2026-06-19-12:00:
|
FN-6781 supersedes the prior tablet-only inline / desktop-overflow split: Command Center must remain a stable inline destination immediately after Agents on tablet and desktop so the affordance does not relocate while resizing.
|
||||||
Tablet navigation promotes Command Center immediately after Agents while desktop keeps Command Center in the More-views overflow.
|
Documents still moves to the tablet More-views overflow to conserve horizontal space without changing desktop ordering.
|
||||||
Documents moves to the tablet More-views overflow below to conserve horizontal space without changing desktop ordering.
|
*/}
|
||||||
|
<button
|
||||||
FNXC:Navigation 2026-06-19-08:24:
|
className={`view-toggle-btn${view === "command-center" ? " active" : ""}`}
|
||||||
FN-6725 re-verified this tablet contract after a suspected revert: Command Center remains a single inline tablet destination after Agents, Documents remains overflow-only on tablet, and desktop ordering stays unchanged.
|
onClick={() => onChangeView("command-center")}
|
||||||
*/
|
title={t("header.commandCenterView", "Command Center")}
|
||||||
<button
|
aria-label={t("header.commandCenterView", "Command Center")}
|
||||||
className={`view-toggle-btn${view === "command-center" ? " active" : ""}`}
|
aria-pressed={view === "command-center"}
|
||||||
onClick={() => onChangeView("command-center")}
|
data-testid="view-toggle-command-center"
|
||||||
title={t("header.commandCenterView", "Command Center")}
|
>
|
||||||
aria-label={t("header.commandCenterView", "Command Center")}
|
<Gauge size={16} />
|
||||||
aria-pressed={view === "command-center"}
|
</button>
|
||||||
data-testid="view-toggle-command-center"
|
|
||||||
>
|
|
||||||
<Gauge size={16} />
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
<button
|
<button
|
||||||
className={`view-toggle-btn${view === "missions" ? " active" : ""}`}
|
className={`view-toggle-btn${view === "missions" ? " active" : ""}`}
|
||||||
onClick={() => onChangeView("missions")}
|
onClick={() => onChangeView("missions")}
|
||||||
@@ -1113,7 +1108,7 @@ export function Header({
|
|||||||
<>
|
<>
|
||||||
<button
|
<button
|
||||||
ref={viewOverflowTriggerRef}
|
ref={viewOverflowTriggerRef}
|
||||||
className={`view-toggle-btn${["research", "skills", "insights", "memory", "secrets", "dev-server", "devserver", "graph", "stash-recovery"].includes(view) || (!isTablet && view === "command-center") || (isTablet && view === "documents") || (experimentalFeatures?.evalsView && view === "evals") || (experimentalFeatures?.goalsView && view === "goalsView") || (todosEnabled && todosOpen) || isPluginViewId(view) ? " active" : ""}`}
|
className={`view-toggle-btn${["research", "skills", "insights", "memory", "secrets", "dev-server", "devserver", "graph", "stash-recovery"].includes(view) || (isTablet && view === "documents") || (experimentalFeatures?.evalsView && view === "evals") || (experimentalFeatures?.goalsView && view === "goalsView") || (todosEnabled && todosOpen) || isPluginViewId(view) ? " active" : ""}`}
|
||||||
onClick={() => setIsViewOverflowOpen((prev) => !prev)}
|
onClick={() => setIsViewOverflowOpen((prev) => !prev)}
|
||||||
title={t("header.moreViews", "More views")}
|
title={t("header.moreViews", "More views")}
|
||||||
aria-label={t("header.moreViews", "More views")}
|
aria-label={t("header.moreViews", "More views")}
|
||||||
@@ -1255,20 +1250,6 @@ export function Header({
|
|||||||
<span>{t("header.documentsView", "Documents view")}</span>
|
<span>{t("header.documentsView", "Documents view")}</span>
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
{!isTablet && (
|
|
||||||
<button
|
|
||||||
className={`view-toggle-overflow-item${view === "command-center" ? " active" : ""}`}
|
|
||||||
onClick={() => {
|
|
||||||
onChangeView("command-center");
|
|
||||||
setIsViewOverflowOpen(false);
|
|
||||||
}}
|
|
||||||
role="menuitem"
|
|
||||||
data-testid="view-overflow-command-center"
|
|
||||||
>
|
|
||||||
<Gauge size={14} />
|
|
||||||
<span>{t("header.commandCenterView", "Command Center")}</span>
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
{experimentalFeatures?.devServerView && (
|
{experimentalFeatures?.devServerView && (
|
||||||
<button
|
<button
|
||||||
className={`view-toggle-overflow-item${view === "dev-server" || view === "devserver" ? " active" : ""}`}
|
className={`view-toggle-overflow-item${view === "dev-server" || view === "devserver" ? " active" : ""}`}
|
||||||
|
|||||||
@@ -299,14 +299,16 @@ describe("Header", () => {
|
|||||||
expect(screen.getByTestId("view-toggle-overflow-trigger")).toBeDefined();
|
expect(screen.getByTestId("view-toggle-overflow-trigger")).toBeDefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("keeps desktop Documents inline and Command Center only in overflow", () => {
|
it("keeps desktop Documents and Command Center inline without Command Center overflow", () => {
|
||||||
renderHeader({ onChangeView: noop, showAgentsTab: true }, "desktop");
|
renderHeader({ onChangeView: noop, showAgentsTab: true }, "desktop");
|
||||||
|
|
||||||
expect(screen.getByTitle("Documents view")).toBeInTheDocument();
|
expect(screen.getByTitle("Documents view")).toBeInTheDocument();
|
||||||
expect(screen.queryByTestId("view-toggle-command-center")).toBeNull();
|
const agentsButton = screen.getByTitle("Agents view");
|
||||||
|
const commandCenterButton = screen.getByTestId("view-toggle-command-center");
|
||||||
|
expect(commandCenterButton.previousElementSibling).toBe(agentsButton);
|
||||||
|
|
||||||
fireEvent.click(screen.getByTestId("view-toggle-overflow-trigger"));
|
fireEvent.click(screen.getByTestId("view-toggle-overflow-trigger"));
|
||||||
expect(screen.getByTestId("view-overflow-command-center")).toBeInTheDocument();
|
expect(screen.queryByTestId("view-overflow-command-center")).toBeNull();
|
||||||
expect(screen.queryByTestId("view-overflow-documents")).toBeNull();
|
expect(screen.queryByTestId("view-overflow-documents")).toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user