feat(FN-3208): restore mobile nodes nav and improve planning mode

This merge delivers significant testing infrastructure refactoring alongside focused UI, planning, and plugin features. The largest change splits the 20K-line `routes.test.ts` monolith into 15 granular route test files (agents, auth, automation, git, github, planning, settings, system, tasks, tasks-

Fusion-Task-Id: FN-3208
This commit is contained in:
Fusion
2026-05-02 20:44:50 -07:00
committed by gsxdsm
parent 04cf5f094c
commit e5fd33f3a4
5 changed files with 69 additions and 1 deletions

View File

@@ -1046,6 +1046,7 @@ function AppInner() {
onOpenActivityLog={modalManager.openActivityLog}
onOpenSystemStats={modalManager.openSystemStats}
onOpenMailbox={() => handleTaskViewChange("mailbox")}
onOpenNodes={handleOpenNodes}
mailboxUnreadCount={mailboxUnreadCount}
onOpenGitManager={modalManager.openGitManager}
onOpenWorkflowSteps={modalManager.openWorkflowSteps}
@@ -1072,6 +1073,7 @@ function AppInner() {
devServerView: devServerEnabled,
todoView: todosEnabled,
researchView: researchEnabled,
nodesView: nodesEnabled,
}}
pluginDashboardViews={pluginDashboardViews}
/>

View File

@@ -46,6 +46,7 @@ const createDefaultMobileNavProps = () => ({
onOpenSettings: vi.fn(),
onOpenActivityLog: vi.fn(),
onOpenMailbox: vi.fn(),
onOpenNodes: vi.fn(),
mailboxUnreadCount: 0,
onOpenGitManager: vi.fn(),
onOpenWorkflowSteps: vi.fn(),
@@ -159,9 +160,22 @@ describe("Mobile Feature Access Regression Guard", () => {
expect(screen.getByTestId("mobile-more-item-github")).toBeDefined();
expect(screen.getByTestId("mobile-more-item-usage")).toBeDefined();
expect(screen.queryByTestId("mobile-more-item-chat")).toBeNull();
expect(screen.queryByTestId("mobile-more-item-nodes")).toBeNull();
expect(screen.getByTestId("mobile-more-item-settings")).toBeDefined();
});
it("nodes view is reachable from mobile More sheet when enabled", () => {
const props = createDefaultMobileNavProps();
render(<MobileNavBar {...props} experimentalFeatures={{ nodesView: true }} />);
fireEvent.click(screen.getByTestId("mobile-nav-tab-more"));
const nodesItem = screen.getByTestId("mobile-more-item-nodes");
expect(nodesItem).toBeDefined();
fireEvent.click(nodesItem);
expect(props.onOpenNodes).toHaveBeenCalledOnce();
});
it("chat is accessible via the bottom nav while remaining absent from the More sheet", () => {
const props = createDefaultMobileNavProps();
render(<MobileNavBar {...props} view="board" />);

View File

@@ -21,6 +21,7 @@ import {
Play,
Settings,
Monitor,
Network,
Search,
Sparkles,
Target,
@@ -72,7 +73,17 @@ export interface MobileNavBarProps {
/** Whether to show the skills tab */
showSkillsTab?: boolean;
/** Experimental feature flags controlling visibility of nav items. */
experimentalFeatures?: { insights?: boolean; roadmap?: boolean; memoryView?: boolean; devServer?: boolean; devServerView?: boolean; todoView?: boolean; researchView?: boolean };
experimentalFeatures?: {
insights?: boolean;
roadmap?: boolean;
memoryView?: boolean;
devServer?: boolean;
devServerView?: boolean;
todoView?: boolean;
researchView?: boolean;
nodesView?: boolean;
};
onOpenNodes?: () => void;
pluginDashboardViews?: PluginDashboardViewEntry[];
}
@@ -123,6 +134,7 @@ export function MobileNavBar({
onViewAllProjects,
showSkillsTab,
experimentalFeatures,
onOpenNodes,
pluginDashboardViews = [],
}: MobileNavBarProps) {
const mode = useViewportMode();
@@ -657,6 +669,18 @@ export function MobileNavBar({
</button>
)}
{experimentalFeatures?.nodesView && onOpenNodes && (
<button
type="button"
className="mobile-more-item"
data-testid="mobile-more-item-nodes"
onClick={() => handleMoreAction(onOpenNodes)}
>
<Network />
<span>Nodes</span>
</button>
)}
{todoViewEnabled && (
<button
type="button"

View File

@@ -34,6 +34,7 @@ const createDefaultProps = () => ({
onOpenActivityLog: vi.fn(),
onOpenSystemStats: vi.fn(),
onOpenMailbox: vi.fn(),
onOpenNodes: vi.fn(),
mailboxUnreadCount: 0,
onOpenGitManager: vi.fn(),
onOpenWorkflowSteps: vi.fn(),
@@ -334,6 +335,29 @@ describe("MobileNavBar", () => {
expect(screen.getByTestId("mobile-more-item-insights")).toBeDefined();
});
it("shows nodes in more sheet only when nodesView is enabled", () => {
const disabledProps = createDefaultProps();
const { unmount } = render(<MobileNavBar {...disabledProps} experimentalFeatures={{}} />);
fireEvent.click(screen.getByTestId("mobile-nav-tab-more"));
expect(screen.queryByTestId("mobile-more-item-nodes")).toBeNull();
unmount();
const enabledProps = createDefaultProps();
render(<MobileNavBar {...enabledProps} experimentalFeatures={{ nodesView: true }} />);
fireEvent.click(screen.getByTestId("mobile-nav-tab-more"));
expect(screen.getByTestId("mobile-more-item-nodes")).toBeDefined();
});
it("invokes onOpenNodes when nodes item is tapped", () => {
const props = createDefaultProps();
render(<MobileNavBar {...props} experimentalFeatures={{ nodesView: true }} />);
fireEvent.click(screen.getByTestId("mobile-nav-tab-more"));
fireEvent.click(screen.getByTestId("mobile-more-item-nodes"));
expect(props.onOpenNodes).toHaveBeenCalledOnce();
});
it("does not show memory in more sheet when memoryView is not enabled", () => {
render(<MobileNavBar {...createDefaultProps()} experimentalFeatures={{}} />);
fireEvent.click(screen.getByTestId("mobile-nav-tab-more"));