fix(FN-2061): remove agents tab from mobile nav

- Remove the agents tab button and showAgentsTab prop from MobileNavBar.
- Stop passing showAgentsTab from App to keep mobile navigation aligned with current feature exposure.
- Update MobileNavBar and mobile regression tests to remove agents-tab assertions and verify agents access via header fallback when mobile nav is disabled.
This commit is contained in:
Fusion
2026-04-18 16:04:54 -07:00
committed by gsxdsm
parent 60877e2991
commit 5f04cf05b2
5 changed files with 22 additions and 81 deletions

View File

@@ -683,7 +683,6 @@ function AppInner() {
onOpenQuickChat={() => setQuickChatOpen(true)}
projectId={currentProject?.id}
showSkillsTab={skillsEnabled}
showAgentsTab={agentsEnabled}
experimentalFeatures={{ insights: insightsEnabled, roadmap: roadmapEnabled, memoryView: memoryEnabled }}
/>
{viewMode === "project" && currentProject && taskView !== "chat" && taskView !== "mailbox" && taskView !== "insights" && (

View File

@@ -11,7 +11,7 @@
* Protected features:
* - List view toggle
* - Board view toggle
* - Agents view toggle
* - Agents view toggle (via header fallback on mobile when mobile nav is disabled)
* - Project overview / "All Projects" navigation
* - Secondary features via "More" sheet (settings, git, terminal, etc.)
*/
@@ -111,15 +111,10 @@ describe("Mobile Feature Access Regression Guard", () => {
expect(props.onChangeView).toHaveBeenCalledWith("list");
});
it("agents view is accessible via mobile nav bar", () => {
const props = createDefaultMobileNavProps();
render(<MobileNavBar {...props} showAgentsTab={true} />);
it("agents tab is not rendered in the mobile nav bar", () => {
render(<MobileNavBar {...createDefaultMobileNavProps()} />);
const agentsTab = screen.getByTestId("mobile-nav-tab-agents");
expect(agentsTab).toBeDefined();
fireEvent.click(agentsTab);
expect(props.onChangeView).toHaveBeenCalledWith("agents");
expect(screen.queryByTestId("mobile-nav-tab-agents")).toBeNull();
});
it("project list is accessible via header overflow menu on mobile", () => {
@@ -206,21 +201,20 @@ describe("Mobile Feature Access Regression Guard", () => {
expect(screen.getByTitle("Agents view")).toBeDefined();
});
it("all three task views remain reachable from mobile navigation surfaces", () => {
it("all three task views remain reachable across mobile navigation surfaces", () => {
const mobileNavOnChangeView = vi.fn();
const mobileNav = render(
<MobileNavBar
{...createDefaultMobileNavProps()}
view="missions"
onChangeView={mobileNavOnChangeView}
showAgentsTab={true}
/>,
);
fireEvent.click(screen.getByTestId("mobile-nav-tab-tasks"));
fireEvent.click(screen.getByTestId("mobile-nav-tab-agents"));
expect(mobileNavOnChangeView).toHaveBeenCalledWith("board");
expect(mobileNavOnChangeView).toHaveBeenCalledWith("agents");
expect(screen.queryByTestId("mobile-nav-tab-agents")).toBeNull();
mobileNav.unmount();
@@ -230,10 +224,13 @@ describe("Mobile Feature Access Regression Guard", () => {
view="board"
onChangeView={headerOnChangeView}
mobileNavEnabled={false}
showAgentsTab={true}
/>,
);
fireEvent.click(screen.getByTitle("List view"));
fireEvent.click(screen.getByTitle("Agents view"));
expect(headerOnChangeView).toHaveBeenCalledWith("list");
expect(headerOnChangeView).toHaveBeenCalledWith("agents");
});
});

View File

@@ -1,7 +1,6 @@
import { useCallback, useEffect, useMemo, useState } from "react";
import {
Activity,
Bot,
Brain,
ChevronRight,
Clock,
@@ -59,8 +58,6 @@ export interface MobileNavBarProps {
onViewAllProjects?: () => void;
/** Whether to show the skills tab */
showSkillsTab?: boolean;
/** When true, shows the Agents mobile tab. Hidden by default (experimental feature). */
showAgentsTab?: boolean;
/** Experimental feature flags controlling visibility of nav items. */
experimentalFeatures?: { insights?: boolean; roadmap?: boolean; memoryView?: boolean };
}
@@ -108,7 +105,6 @@ export function MobileNavBar({
projectId,
onViewAllProjects,
showSkillsTab,
showAgentsTab,
experimentalFeatures,
}: MobileNavBarProps) {
const mode = useViewportMode();
@@ -200,20 +196,6 @@ export function MobileNavBar({
<span className="mobile-nav-tab-label">Tasks</span>
</button>
{showAgentsTab && (
<button
type="button"
className={`mobile-nav-tab${view === "agents" ? " mobile-nav-tab--active" : ""}`}
data-testid="mobile-nav-tab-agents"
role="tab"
aria-selected={view === "agents"}
onClick={() => onChangeView("agents")}
>
<Bot />
<span className="mobile-nav-tab-label">Agents</span>
</button>
)}
<button
type="button"
className={`mobile-nav-tab${view === "missions" ? " mobile-nav-tab--active" : ""}`}

View File

@@ -97,9 +97,19 @@ export function SkillsView({ projectId, addToast, onClose }: SkillsViewProps) {
debounceRef.current = setTimeout(() => {
setDebouncedQuery(value);
debounceRef.current = null;
}, 300);
}, []);
useEffect(() => {
return () => {
if (debounceRef.current) {
clearTimeout(debounceRef.current);
debounceRef.current = null;
}
};
}, []);
// Fetch catalog when debounced query changes
useEffect(() => {
void loadCatalog(debouncedQuery);

View File

@@ -56,7 +56,7 @@ describe("MobileNavBar", () => {
mockViewport("mobile");
});
it("renders six tab buttons (tasks + missions + chat + mailbox + skills + more) when showSkillsTab is true and agents is hidden by default", () => {
it("renders six tab buttons (tasks + missions + chat + mailbox + skills + more) when showSkillsTab is true", () => {
render(<MobileNavBar {...createDefaultProps()} showSkillsTab={true} />);
expect(screen.getByTestId("mobile-nav-tab-tasks")).toBeDefined();
@@ -69,19 +69,6 @@ describe("MobileNavBar", () => {
expect(screen.getByTestId("mobile-nav-tab-more")).toBeDefined();
});
it("renders seven tab buttons when showSkillsTab and showAgentsTab are both true", () => {
render(<MobileNavBar {...createDefaultProps()} showSkillsTab={true} showAgentsTab={true} />);
expect(screen.getByTestId("mobile-nav-tab-tasks")).toBeDefined();
expect(screen.getByTestId("mobile-nav-tab-agents")).toBeDefined();
expect(screen.getByTestId("mobile-nav-tab-missions")).toBeDefined();
expect(screen.getByTestId("mobile-nav-tab-chat")).toBeDefined();
expect(screen.getByTestId("mobile-nav-tab-mailbox")).toBeDefined();
expect(screen.getByTestId("mobile-nav-tab-skills")).toBeDefined();
expect(screen.queryByTestId("mobile-nav-tab-roadmaps")).toBeNull();
expect(screen.getByTestId("mobile-nav-tab-more")).toBeDefined();
});
it("renders roadmaps tab when experimentalFeatures.roadmap is true", () => {
render(<MobileNavBar {...createDefaultProps()} experimentalFeatures={{ roadmap: true }} />);
expect(screen.getByTestId("mobile-nav-tab-roadmaps")).toBeDefined();
@@ -116,15 +103,9 @@ describe("MobileNavBar", () => {
expect(badge?.textContent).toBe("5");
});
it("active tab is highlighted for agents", () => {
render(<MobileNavBar {...createDefaultProps()} view="agents" showAgentsTab={true} />);
expect(screen.getByTestId("mobile-nav-tab-agents").className).toContain("mobile-nav-tab--active");
});
it("tasks tab calls onChangeView with 'board' when coming from a non-tasks view", () => {
const props = createDefaultProps();
render(<MobileNavBar {...props} view="agents" showAgentsTab={true} />);
render(<MobileNavBar {...props} view="missions" />);
fireEvent.click(screen.getByTestId("mobile-nav-tab-tasks"));
expect(props.onChangeView).toHaveBeenCalledWith("board");
@@ -156,11 +137,6 @@ describe("MobileNavBar", () => {
expect(screen.getByTestId("mobile-nav-tab-tasks").className).toContain("mobile-nav-tab--active");
});
it("tasks tab is not active when view is 'agents'", () => {
render(<MobileNavBar {...createDefaultProps()} view="agents" showAgentsTab={true} />);
expect(screen.getByTestId("mobile-nav-tab-tasks").className).not.toContain("mobile-nav-tab--active");
});
it("missions tab calls onChangeView with 'missions'", () => {
const props = createDefaultProps();
render(<MobileNavBar {...props} view="board" />);
@@ -335,34 +311,11 @@ describe("MobileNavBar", () => {
expect(container.querySelector(".mobile-nav-bar")).toBeNull();
});
it("tab click calls onChangeView", () => {
const props = createDefaultProps();
render(<MobileNavBar {...props} showAgentsTab={true} />);
fireEvent.click(screen.getByTestId("mobile-nav-tab-agents"));
expect(props.onChangeView).toHaveBeenCalledWith("agents");
});
it("applies footer-visible class when footer is shown", () => {
const { container } = render(<MobileNavBar {...createDefaultProps()} footerVisible={true} />);
expect(container.querySelector(".mobile-nav-bar--with-footer")).not.toBeNull();
});
it("hides agents tab when showAgentsTab is false", () => {
render(<MobileNavBar {...createDefaultProps()} showAgentsTab={false} />);
expect(screen.queryByTestId("mobile-nav-tab-agents")).toBeNull();
});
it("hides agents tab by default when showAgentsTab is not provided", () => {
render(<MobileNavBar {...createDefaultProps()} />);
expect(screen.queryByTestId("mobile-nav-tab-agents")).toBeNull();
});
it("shows agents tab when showAgentsTab is true", () => {
render(<MobileNavBar {...createDefaultProps()} showAgentsTab={true} />);
expect(screen.getByTestId("mobile-nav-tab-agents")).toBeDefined();
});
it("returns null on desktop viewport", () => {
mockViewport("desktop");
const { container } = render(<MobileNavBar {...createDefaultProps()} />);