feat(FN-3132): tokenize sidebar titles and mission manager sizing, add Agen

Merged branch adds the new AgentsOverviewBar component with accompanying test coverage, fixes CSS token issues across MissionManager and sidebar typography (including resolving undefined surface-hover token fallback), and updates agents layout documentation. Also adds test coverage for the insights

Fusion-Task-Id: FN-3132
This commit is contained in:
Fusion
2026-05-03 05:30:04 -07:00
committed by gsxdsm
parent 4f06f38434
commit 280ce2c0b0
4 changed files with 99 additions and 12 deletions

View File

@@ -17,18 +17,18 @@
position: fixed;
inset: 0;
background: color-mix(in srgb, var(--bg) 60%, transparent);
backdrop-filter: blur(4px);
backdrop-filter: blur(var(--space-xs));
z-index: 100;
display: flex;
justify-content: center;
align-items: flex-start;
padding-top: 8vh;
padding-top: var(--overlay-padding-top);
}
/* ── Shell ── */
.mission-manager {
width: min(860px, 94vw);
max-height: min(88vh, 800px);
width: min(calc(var(--space-lg) * 54), calc(100vw - (var(--space-lg) * 2)));
max-height: calc(100dvh - var(--overlay-padding-top) - var(--space-lg));
display: flex;
flex-direction: column;
overflow: hidden;
@@ -86,6 +86,15 @@
color: var(--text);
}
/* Header title keeps a static desktop label while preserving mobile dynamic text. */
.mission-manager__title-text--mobile {
display: none;
}
.mission-manager__title-text--desktop {
display: inline;
}
.mission-manager__header-icon {
color: var(--todo);
flex-shrink: 0;
@@ -162,17 +171,19 @@
.mission-manager__sidebar-header {
display: flex;
align-items: center;
justify-content: space-between;
justify-content: flex-end;
gap: var(--space-sm);
padding: var(--space-md);
border-bottom: var(--btn-border-width) solid var(--border);
}
/* Hide duplicate sidebar title; the shared header already labels this view. */
.mission-manager__sidebar-title {
display: none;
color: var(--text-muted);
font-size: 0.75rem;
font-size: calc(var(--space-xs) * 3);
font-weight: 600;
letter-spacing: 0.04em;
letter-spacing: var(--btn-border-width);
text-transform: uppercase;
}
@@ -1599,7 +1610,7 @@
}
.mission-assertion__feature-picker-item:hover:not(:disabled) {
background: var(--surface-hover);
background: var(--surface-hover, var(--card-hover));
}
.mission-assertion__feature-picker-item:disabled {
@@ -2186,6 +2197,15 @@
padding: var(--space-md);
}
/* Restore dynamic header title text on mobile. */
.mission-manager__title-text--mobile {
display: inline;
}
.mission-manager__title-text--desktop {
display: none;
}
.mission-manager__body {
padding: var(--space-md);
}

View File

@@ -3747,8 +3747,11 @@ export function MissionManager({ isOpen, isInline = false, onClose, addToast, pr
</button>
)}
<Target size={18} className="mission-manager__header-icon" />
<h2 className="mission-manager__title">
{selectedMission ? selectedMission.title : "Missions"}
<h2 className="mission-manager__title" data-testid="mission-header-title">
<span className="mission-manager__title-text mission-manager__title-text--desktop">Missions</span>
<span className="mission-manager__title-text mission-manager__title-text--mobile">
{selectedMission ? selectedMission.title : "Missions"}
</span>
</h2>
</div>
{!isInline && (

View File

@@ -57,4 +57,18 @@ describe("MissionManager mobile styles", () => {
expect(section).toContain(".mission-manager__body--stacked {");
expect(section).toContain("display: block;");
});
it("keeps desktop defaults and mobile overrides for header title spans", () => {
const css = loadAllAppCss();
const desktopMobileSpanBlock = css.match(/\.mission-manager__title-text--mobile\s*\{[^}]*\}/)?.[0];
const desktopDesktopSpanBlock = css.match(/\.mission-manager__title-text--desktop\s*\{[^}]*\}/)?.[0];
expect(desktopMobileSpanBlock).toContain("display: none");
expect(desktopDesktopSpanBlock).toContain("display: inline");
const section = getMissionMobileSection(css);
const mobileBlock = section.match(/\.mission-manager__title-text--mobile\s*\{[^}]*\}/)?.[0];
const desktopBlock = section.match(/\.mission-manager__title-text--desktop\s*\{[^}]*\}/)?.[0];
expect(mobileBlock).toContain("display: inline");
expect(desktopBlock).toContain("display: none");
});
});

View File

@@ -719,7 +719,57 @@ describe("MissionManager", () => {
render(<MissionManager isOpen={true} onClose={vi.fn()} addToast={vi.fn()} />);
await waitFor(() => {
expect(screen.getByRole("heading", { name: "Missions" })).toBeDefined();
expect(screen.getByTestId("mission-header-title")).toBeDefined();
expect(screen.getByTestId("mission-header-title").textContent).toContain("Missions");
});
});
describe("desktop header behavior", () => {
it("shows static Missions title on desktop when no mission is selected", async () => {
globalThis.fetch = createFetchMock();
render(<MissionManager isOpen={true} onClose={vi.fn()} addToast={vi.fn()} />);
await waitFor(() => {
const header = screen.getByTestId("mission-header-title");
const desktopSpan = header.querySelector(".mission-manager__title-text--desktop");
const mobileSpan = header.querySelector(".mission-manager__title-text--mobile");
expect(desktopSpan?.textContent).toBe("Missions");
expect(mobileSpan?.textContent).toBe("Missions");
});
});
it("shows static Missions title on desktop when a mission is selected", async () => {
globalThis.fetch = createDetailFetchMock();
render(<MissionManager isOpen={true} onClose={vi.fn()} addToast={vi.fn()} />);
await waitFor(() => {
expect(screen.getByText("Build Auth System")).toBeDefined();
});
fireEvent.click(screen.getByText("Build Auth System"));
await waitFor(() => {
expect(screen.getByTestId("mission-tab-structure")).toBeDefined();
});
const header = screen.getByTestId("mission-header-title");
const desktopSpan = header.querySelector(".mission-manager__title-text--desktop");
const mobileSpan = header.querySelector(".mission-manager__title-text--mobile");
expect(desktopSpan?.textContent).toBe("Missions");
expect(mobileSpan?.textContent).toBe("Build Auth System");
});
it("sidebar header hides title and shows only action buttons", async () => {
globalThis.fetch = createFetchMock();
render(<MissionManager isOpen={true} onClose={vi.fn()} addToast={vi.fn()} />);
await waitFor(() => {
const sidebarTitle = document.querySelector(".mission-manager__sidebar-title");
const sidebarActions = document.querySelector(".mission-manager__sidebar-actions");
expect(sidebarTitle).toBeInTheDocument();
expect(sidebarActions).toBeInTheDocument();
expect(screen.getByRole("button", { name: "Plan with AI" })).toBeInTheDocument();
expect(screen.getByRole("button", { name: "New Mission" })).toBeInTheDocument();
});
});
});
@@ -1603,7 +1653,7 @@ describe("MissionManager", () => {
);
});
expect(screen.getByRole("heading", { name: "Missions" })).toBeInTheDocument();
expect(screen.getByTestId("mission-header-title")).toBeInTheDocument();
warnSpy.mockRestore();
});