FN-6707: move throughput card atop overview

Place the Command Center throughput section first across overview states.

- Render the throughput funnel before loading, error, empty, and populated overview content.
- Preserve throughput test anchors while documenting the top-of-page ordering requirement.
- Add regression coverage for throughput ordering in loading, empty, populated, and error overview branches.

Files changed:
 .../app/components/command-center/CommandCenter.tsx | 11 +++++++----
 .../command-center/__tests__/CommandCenter.test.tsx | 21 +++++++++++++++++++++
 2 files changed, 28 insertions(+), 4 deletions(-)

Fusion-Task-Id: FN-6707

Fusion-Task-Lineage: 9b004ab4-e36b-4d83-804a-32503a7d8d72
This commit is contained in:
gsxdsm
2026-06-19 06:59:02 -07:00
parent 47e7b4a150
commit 44a7c83b23
2 changed files with 28 additions and 4 deletions

View File

@@ -217,6 +217,9 @@ function OverviewTab({ range }: { range: DateRange }) {
},
];
// FNXC:CommandCenter 2026-06-19-00:00:
// Throughput funnel now renders first in every overview branch (loading/error/empty/populated)
// so the SDLC throughput card is top-of-page; mobile scroll owner and data-testid anchors unchanged.
// The throughput funnel reads its own data (activityLog transitions) and shows
// its own empty state, so it renders even when the stat-card aggregates have no
// data yet.
@@ -229,11 +232,11 @@ function OverviewTab({ range }: { range: DateRange }) {
if (isInitialLoading) {
return (
<div className="cc-overview">
{throughputSection}
<div className="cc-loading" data-testid="command-center-overview-loading">
<div className="cc-chart-skeleton" />
<p>{t("commandCenter.loading", "Loading command center...")}</p>
</div>
{throughputSection}
</div>
);
}
@@ -241,11 +244,11 @@ function OverviewTab({ range }: { range: DateRange }) {
if (coreError !== null && !hasData) {
return (
<div className="cc-overview">
{throughputSection}
<div className="cc-error" data-testid="command-center-overview-error" role="alert">
<AlertCircle size={24} />
<p>{coreError}</p>
</div>
{throughputSection}
</div>
);
}
@@ -253,17 +256,18 @@ function OverviewTab({ range }: { range: DateRange }) {
if (!hasData) {
return (
<div className="cc-overview">
{throughputSection}
<div className="cc-empty" data-testid="command-center-empty">
<Gauge size={28} />
<p>{t("commandCenter.empty", "No usage data yet. Run some agents to populate the Command Center.")}</p>
</div>
{throughputSection}
</div>
);
}
return (
<div className="cc-overview">
{throughputSection}
<div className="cc-stat-grid">
{cards.map((card) => (
<div key={card.id} className="card cc-stat-card" data-testid={`command-center-stat-${card.id}`}>
@@ -370,7 +374,6 @@ function OverviewTab({ range }: { range: DateRange }) {
) : null}
</section>
) : null}
{throughputSection}
</div>
);
}

View File

@@ -291,6 +291,17 @@ function liveMetricValue(testId = "command-center-live-tasks-in-progress") {
return screen.getByTestId(testId).querySelector(".cc-live-metric-value")?.textContent ?? null;
}
function expectThroughputFirstBefore(...followingTestIds: string[]) {
const throughput = screen.getByTestId("command-center-throughput");
expect(throughput.parentElement?.classList.contains("cc-overview")).toBe(true);
expect(throughput.parentElement?.firstElementChild).toBe(throughput);
for (const testId of followingTestIds) {
const followingNode = screen.getByTestId(testId);
expect(Boolean(throughput.compareDocumentPosition(followingNode) & Node.DOCUMENT_POSITION_FOLLOWING)).toBe(true);
}
}
beforeEach(() => {
apiMock.mockReset();
mockEmptyOverviewApi();
@@ -308,6 +319,13 @@ describe("CommandCenter shell", () => {
expect(screen.getByTestId("command-center-panel-overview")).toBeTruthy();
});
it("renders throughput first while the Overview branch is loading", () => {
mockEmptyOverviewApi();
render(<CommandCenter />);
expect(screen.getByTestId("command-center-overview-loading")).toBeTruthy();
expectThroughputFirstBefore("command-center-overview-loading");
});
it("renders the documented empty state when there is no data (no crash)", async () => {
mockEmptyOverviewApi();
render(<CommandCenter />);
@@ -317,6 +335,7 @@ describe("CommandCenter shell", () => {
expect(screen.queryByTestId("cc-overview-pie")).toBeNull();
expect(screen.queryByTestId("cc-overview-line")).toBeNull();
await screen.findByTestId("command-center-empty");
expectThroughputFirstBefore("command-center-empty");
expect(screen.queryByTestId("command-center-overview-charts")).toBeNull();
expect(screen.queryByTestId("cc-overview-pie")).toBeNull();
expect(screen.queryByTestId("cc-overview-line")).toBeNull();
@@ -352,6 +371,7 @@ describe("CommandCenter shell", () => {
expect(statValue("command-center-stat-models")).toBe("2");
expect(statValue("command-center-stat-signals")).toBe("2");
expect(screen.getByTestId("command-center-live-strip")).toBeTruthy();
expectThroughputFirstBefore("command-center-stat-tokens", "command-center-live-strip");
expect(screen.getByTestId("command-center-live-snapshot")).toBeTruthy();
await waitFor(() => expect(liveMetricValue()).toBe("3"));
expect(screen.getByTestId("command-center-live-agents-working").textContent).toContain("2");
@@ -561,6 +581,7 @@ describe("CommandCenter shell", () => {
render(<CommandCenter />);
await screen.findByTestId("command-center-overview-error");
expectThroughputFirstBefore("command-center-overview-error");
expect(screen.getByTestId("command-center-overview-error").textContent).toContain("tokens failed");
expect(screen.queryByTestId("command-center-overview-loading")).toBeNull();
expect(screen.queryByTestId("command-center-empty")).toBeNull();