diff --git a/packages/dashboard/app/components/RightDock.css b/packages/dashboard/app/components/RightDock.css
index 38309ebd0c..c84145f4c3 100644
--- a/packages/dashboard/app/components/RightDock.css
+++ b/packages/dashboard/app/components/RightDock.css
@@ -15,7 +15,11 @@ The right dock OVERLAYS the page content (floats over the right edge) instead of
display: flex;
flex-direction: column;
min-width: min(100%, var(--right-dock-min-width, calc(var(--space-2xl) * 8)));
- max-width: min(100%, var(--right-dock-max-width, calc(var(--space-2xl) * 22)));
+ /*
+ FNXC:RightDock 2026-06-23-00:50:
+ Raised the right-dock max-width default from calc(var(--space-2xl) * 22) (~704px) to calc(var(--space-2xl) * 40) (~1280px) so the dock can be dragged MUCH wider (matching the raised RIGHT_DOCK_MAX_WIDTH JS clamp) and the Files view has room for its tree|viewer two-pane split. The min(100%, ...) wrapper is kept so the dock can never exceed the viewport regardless of the larger cap.
+ */
+ max-width: min(100%, var(--right-dock-max-width, calc(var(--space-2xl) * 40)));
min-height: 0;
background: var(--surface);
border-left: thin solid var(--border);
diff --git a/packages/dashboard/app/components/RightDock.tsx b/packages/dashboard/app/components/RightDock.tsx
index 76788a53dc..5a076639b6 100644
--- a/packages/dashboard/app/components/RightDock.tsx
+++ b/packages/dashboard/app/components/RightDock.tsx
@@ -12,7 +12,11 @@ import "./RightDock.css";
export const RIGHT_DOCK_DEFAULT_WIDTH = 360;
export const RIGHT_DOCK_MIN_WIDTH = 280;
-export const RIGHT_DOCK_MAX_WIDTH = 720;
+/*
+FNXC:RightDock 2026-06-23-00:50:
+The right-dock resize cap was raised 720 -> 1280 so the user can drag the dock MUCH wider (e.g. to run the Files view as a true two-pane tree|viewer split). The clamp and the persisted-width read both funnel through clampRightDockWidth/RIGHT_DOCK_MAX_WIDTH, so a single constant governs the drag clamp, the keyboard-step clamp, the stored-width read, and the resize-handle aria-valuemax. The CSS still wraps the rendered width in min(100%, ...), so the dock can never exceed the viewport even at the larger cap.
+*/
+export const RIGHT_DOCK_MAX_WIDTH = 1280;
export const RIGHT_DOCK_WIDTH_STORAGE_KEY = "fusion:right-dock-width";
export const RIGHT_DOCK_VIEW_STORAGE_KEY = "fusion:right-dock-view";
export const RIGHT_DOCK_OPEN_STORAGE_KEY = "fusion:right-dock-open";
@@ -261,7 +265,11 @@ export function RightDock({
{selectedEntry.label}
- {selectedEntry.render?.(renderProps)}
+ {/*
+ FNXC:RightDockFiles 2026-06-23-00:50:
+ Thread the live dock width down to registry render functions as `dockWidth` (alongside surface="dock") so a view can deterministically choose its wide layout from the actual dock size. The Files entry uses this to force two-pane when the dock is wide enough, sidestepping the @container query that never reliably fired in the narrow-vs-wide dock body.
+ */}
+ {selectedEntry.render?.({ ...renderProps, surface: "dock", dockWidth: width })}
>
) : null}
diff --git a/packages/dashboard/app/components/__tests__/RightDock.test.tsx b/packages/dashboard/app/components/__tests__/RightDock.test.tsx
index 2c5bbca504..2d7bfb98a3 100644
--- a/packages/dashboard/app/components/__tests__/RightDock.test.tsx
+++ b/packages/dashboard/app/components/__tests__/RightDock.test.tsx
@@ -74,6 +74,22 @@ describe("RightDock", () => {
expect(screen.getByTestId("right-dock-tab-git-manager")).toHaveAttribute("aria-selected", "true");
});
+ /*
+ FNXC:RightDockFiles 2026-06-23-00:50:
+ Deterministic dock two-pane decision: the dock threads its measured width to the Files registry render as `dockWidth`, and the Files entry forces DockFilesView layout="two-pane" once that width crosses 640px (no @container gate). A narrow dock (default 360px) stays layout="auto" (stacked single-panel). Assert both via the data-layout attribute the view exposes.
+ */
+ it("forces the Files two-pane layout when the dock is dragged wide, and stays stacked when narrow", () => {
+ // Narrow default width (360px) -> stacked single-panel.
+ const { unmount } = render();
+ expect(screen.getByTestId("right-dock-files-view")).toHaveAttribute("data-layout", "auto");
+ unmount();
+
+ // Wide persisted width (>= 640px) -> deterministic LEFT|RIGHT two-pane.
+ window.localStorage.setItem(RIGHT_DOCK_WIDTH_STORAGE_KEY, "900");
+ render();
+ expect(screen.getByTestId("right-dock-files-view")).toHaveAttribute("data-layout", "two-pane");
+ });
+
it("falls back to Files when storage points at a removed right-dock view", () => {
window.localStorage.setItem(RIGHT_DOCK_VIEW_STORAGE_KEY, "documents");
render();
@@ -160,17 +176,21 @@ describe("RightDock", () => {
expect(screen.getByTestId("right-dock-files-view")).toBeInTheDocument();
});
+ /*
+ FNXC:RightDock 2026-06-23-00:50:
+ The resize clamp + persisted-width read both funnel through RIGHT_DOCK_MAX_WIDTH, raised to 1280 so the dock drags MUCH wider. Drag far past the cap (startWidth 360 + 2000 px of leftward travel) and assert it clamps to the new 1280 max, then a keyboard step down lands one shift-step (48px) below the cap. This proves the new cap governs both the pointer drag and the keyboard path.
+ */
it("clamps then persists resize width while open", () => {
render();
const handle = screen.getByTestId("right-dock-resize-handle");
- fireEvent.pointerDown(handle, { pointerId: 1, clientX: 900 });
+ fireEvent.pointerDown(handle, { pointerId: 1, clientX: 2000 });
fireEvent.pointerMove(document, { pointerId: 1, clientX: 0 });
fireEvent.pointerUp(document, { pointerId: 1, clientX: 0 });
- expect(window.localStorage.getItem(RIGHT_DOCK_WIDTH_STORAGE_KEY)).toBe("720");
+ expect(window.localStorage.getItem(RIGHT_DOCK_WIDTH_STORAGE_KEY)).toBe("1280");
fireEvent.keyDown(handle, { key: "ArrowRight", shiftKey: true });
- expect(window.localStorage.getItem(RIGHT_DOCK_WIDTH_STORAGE_KEY)).toBe("672");
+ expect(window.localStorage.getItem(RIGHT_DOCK_WIDTH_STORAGE_KEY)).toBe("1232");
});
it("restores persisted width on mount", () => {
diff --git a/packages/dashboard/app/components/overflowViewRegistry.tsx b/packages/dashboard/app/components/overflowViewRegistry.tsx
index fead4b2a0c..3e0ed7f406 100644
--- a/packages/dashboard/app/components/overflowViewRegistry.tsx
+++ b/packages/dashboard/app/components/overflowViewRegistry.tsx
@@ -58,6 +58,11 @@ export interface OverflowViewRenderProps {
The compact right-dock body leaves this undefined ("dock"); the RightDockExpandModal sets `surface="expand"` so DockFilesView forces its LEFT|RIGHT two-pane layout regardless of measured container width.
*/
surface?: "dock" | "expand";
+ /*
+ FNXC:RightDockFiles 2026-06-23-00:50:
+ Measured outer width (px) of the compact right dock body host, threaded from RightDock so a registry render function can deterministically pick a wide layout from the actual dock size. Only set on the "dock" surface; the expand pop-out leaves it undefined (it already forces its wide layout via surface="expand").
+ */
+ dockWidth?: number;
addToast: (message: string, type?: ToastType) => void;
settingsLoaded?: boolean;
readinessVersion?: number;
@@ -100,6 +105,12 @@ export interface OverflowViewVisibilityOptions {
pluginDashboardViews?: PluginDashboardViewEntry[];
}
+/*
+FNXC:RightDockFiles 2026-06-23-00:50:
+When the dock body is at least this wide there is clearly room for the Files tree|viewer two-pane split, so the dock forces DockFilesView layout="two-pane" deterministically instead of relying on the unreliable @container dock-files query (its root content-box often measured under the breakpoint and kept the view stacked). Matched to the CSS @container dock-files (min-width: 640px) breakpoint; compared against the threaded outer dock width (the dock chrome padding is small relative to 640px of content, so 640 outer width safely implies enough body width for two panes).
+*/
+const RIGHT_DOCK_FILES_TWO_PANE_MIN_WIDTH = 640;
+
function wrapOverflowView(node: ReactNode): ReactNode {
return (
@@ -129,12 +140,20 @@ export const STATIC_OVERFLOW_VIEW_ENTRIES: readonly OverflowViewEntry[] = [
/*
FNXC:RightDockFiles 2026-06-22-15:00:
Map the host surface to a deterministic DockFilesView layout. The expand pop-out gets `layout="two-pane"` so the tree+viewer render LEFT|RIGHT without depending on the @container query matching inside the modal body. The compact dock keeps `layout="auto"` (the container-query single-panel stack).
+
+ FNXC:RightDockFiles 2026-06-23-00:50:
+ Extend the deterministic approach to the DOCK itself: when the dock body is dragged wide (threaded `dockWidth` >= 640px) force the same LEFT|RIGHT two-pane split deterministically, NOT via the unreliable @container dock-files query (which kept the wide dock stacked because the root content-box measured under the breakpoint). Below the threshold the narrow dock keeps the single-panel stacked nav. The expand pop-out is always two-pane.
*/
render: (props) => wrapOverflowView(
= RIGHT_DOCK_FILES_TWO_PANE_MIN_WIDTH)
+ ? "two-pane"
+ : "auto"
+ }
/>,
),
},