diff --git a/packages/dashboard/app/App.tsx b/packages/dashboard/app/App.tsx
index a4cc68e2b0..0b8fc90292 100644
--- a/packages/dashboard/app/App.tsx
+++ b/packages/dashboard/app/App.tsx
@@ -123,6 +123,13 @@ const DevServerView = lazy(() => import("./components/DevServerView").then((m) =
const TodoView = lazy(() => import("./components/TodoView").then((m) => ({ default: m.TodoView })));
const GoalsView = lazy(() => import("./components/GoalsView").then((m) => ({ default: m.GoalsView })));
const PullRequestView = lazy(() => import("./components/PullRequestView").then((m) => ({ default: m.PullRequestView })));
+/*
+FNXC:Navigation 2026-06-22-00:00:
+Workflows, Import Tasks (GitHub import), and Automations render as embedded main-content views (presentation="embedded") via these lazy chunks; the same components still mount as modals in AppModals for the mobile overflow path.
+*/
+const WorkflowEditorView = lazy(() => import("./components/WorkflowNodeEditor").then((m) => ({ default: m.WorkflowNodeEditor })));
+const ImportTasksView = lazy(() => import("./components/GitHubImportModal").then((m) => ({ default: m.GitHubImportModal })));
+const AutomationsView = lazy(() => import("./components/ScheduledTasksModal").then((m) => ({ default: m.ScheduledTasksModal })));
// Warm lazy chunks during browser idle so first navigation to each view is
// instant. Each chunk is ~10–80 kB; total prefetch finishes well under a
@@ -1832,6 +1839,58 @@ function AppInner() {
);
}
+ /*
+ FNXC:Navigation 2026-06-22-00:00:
+ Workflows, Import Tasks (GitHub import), and Automations are left-sidebar destinations that render embedded in the main content area instead of as modal overlays. Closing returns to the board. The same components still mount as modals in AppModals for the mobile overflow path.
+ */
+ if (taskView === "workflows") {
+ return (
+
+
+ handleChangeTaskView("board")}
+ addToast={addToast}
+ projectId={currentProject?.id}
+ presentation="embedded"
+ />
+
+
+ );
+ }
+
+ if (taskView === "import-tasks") {
+ return (
+
+
+ handleChangeTaskView("board")}
+ onImport={handleGitHubImport}
+ tasks={tasks}
+ projectId={currentProject?.id}
+ presentation="embedded"
+ />
+
+
+ );
+ }
+
+ if (taskView === "automations") {
+ return (
+
+
+ handleChangeTaskView("board")}
+ addToast={addToast}
+ projectId={currentProject?.id}
+ presentation="embedded"
+ />
+
+
+ );
+ }
+
if (taskView === "devserver" || taskView === "dev-server") {
if (!settingsLoaded || !devServerEnabled) {
return null;
diff --git a/packages/dashboard/app/components/GitHubImportModal.css b/packages/dashboard/app/components/GitHubImportModal.css
index f7cb4da344..c2661d53c4 100644
--- a/packages/dashboard/app/components/GitHubImportModal.css
+++ b/packages/dashboard/app/components/GitHubImportModal.css
@@ -937,4 +937,29 @@
}
}
+/*
+FNXC:RightDockEmbedding 2026-06-22-00:00:
+Right-dock redesign renders the GitHub import surface inline in the main content area instead of as a fixed popup overlay.
+The embedded root is a plain flow box that fills the host; the inner shell sheds overlay-only chrome (fixed sizing, box-shadow, rounded corners, resize) and fills 100% so the main panel owns the frame. No close button is rendered in embedded mode.
+*/
+.github-import-embedded.right-dock-embedded-view {
+ display: flex;
+ width: 100%;
+ height: 100%;
+ min-height: 0;
+}
+
+.github-import-modal.github-import-modal--embedded {
+ width: 100%;
+ height: 100%;
+ max-width: none;
+ min-width: 0;
+ max-height: none;
+ min-height: 0;
+ position: static;
+ box-shadow: none;
+ border-radius: 0;
+ resize: none;
+}
+
diff --git a/packages/dashboard/app/components/GitHubImportModal.tsx b/packages/dashboard/app/components/GitHubImportModal.tsx
index 52c57f8d2d..2163fe9c85 100644
--- a/packages/dashboard/app/components/GitHubImportModal.tsx
+++ b/packages/dashboard/app/components/GitHubImportModal.tsx
@@ -24,6 +24,12 @@ interface GitHubImportModalProps {
onImport: (task: Task) => void;
tasks: Task[];
projectId?: string;
+ /*
+ FNXC:RightDockEmbedding 2026-06-22-00:00:
+ Right-dock redesign renders the GitHub import surface inline inside the main content area instead of as a fixed popup overlay.
+ "embedded" drops the modal overlay/close button and disables modal-only chrome (scroll lock, resize persistence, escape/overlay dismiss); "modal" (default) keeps the original byte-identical overlay behavior.
+ */
+ presentation?: "modal" | "embedded";
}
// Mobile and two-pane breakpoints in pixels
@@ -50,8 +56,9 @@ function formatPreviewBody(body: string | null | undefined, isMobile: boolean) {
return body.slice(0, 200) + (body.length > 200 ? "…" : "");
}
-export function GitHubImportModal({ isOpen, onClose, onImport, tasks, projectId }: GitHubImportModalProps) {
- useMobileScrollLock(isOpen);
+export function GitHubImportModal({ isOpen, onClose, onImport, tasks, projectId, presentation = "modal" }: GitHubImportModalProps) {
+ const isEmbedded = presentation === "embedded";
+ useMobileScrollLock(isOpen && !isEmbedded);
const { t } = useTranslation("app");
const [owner, setOwner] = useState("");
const [repo, setRepo] = useState("");
@@ -80,7 +87,7 @@ export function GitHubImportModal({ isOpen, onClose, onImport, tasks, projectId
const [selectedRemoteName, setSelectedRemoteName] = useState("");
const mountedRef = useRef(false);
const modalRef = useRef(null);
- useModalResizePersist(modalRef, isOpen, "fusion:github-modal-size");
+ useModalResizePersist(modalRef, isOpen && !isEmbedded, "fusion:github-modal-size");
const overlayDismissProps = useOverlayDismiss(onClose);
// Responsive view state
@@ -281,14 +288,15 @@ export function GitHubImportModal({ isOpen, onClose, onImport, tasks, projectId
}, [owner, repo, labels, activeTab, isOpen, loading, importing, handleLoad, handleLoadPulls]);
// Handle escape key
+ // FNXC:RightDockEmbedding 2026-06-22-00:00: Escape-to-close is a modal-only affordance; embedded mode has no dismiss.
useEffect(() => {
- if (!isOpen) return;
+ if (!isOpen || isEmbedded) return;
const handleKey = (e: globalThis.KeyboardEvent) => {
if (e.key === "Escape") onClose();
};
document.addEventListener("keydown", handleKey);
return () => document.removeEventListener("keydown", handleKey);
- }, [isOpen, onClose]);
+ }, [isOpen, isEmbedded, onClose]);
// Detect responsive viewport bands
useEffect(() => {
@@ -480,9 +488,18 @@ export function GitHubImportModal({ isOpen, onClose, onImport, tasks, projectId
const showPullsError = Boolean(error) && pulls.length > 0 && !isPullsEmpty;
const showInlineErrorBanner = activeTab === "issues" ? showIssuesError : showPullsError;
- return (
-
-
+ /*
+ FNXC:RightDockEmbedding 2026-06-22-00:00:
+ Embedded mode renders the import surface as a main-content-area view (no fixed .modal-overlay, no close button, no overlay-dismiss).
+ Modal mode is kept byte-identical: same overlay wrapper, header with subtitle + close button, and overlay-dismiss props.
+ */
+ const inner = (
+
);
}
diff --git a/packages/dashboard/app/components/Header.tsx b/packages/dashboard/app/components/Header.tsx
index 9a7d7e4b6d..103056365b 100644
--- a/packages/dashboard/app/components/Header.tsx
+++ b/packages/dashboard/app/components/Header.tsx
@@ -945,8 +945,11 @@ export function Header({
FN-6886 removes the header Lightbulb affordances because Planning Mode is now a primary left-sidebar destination after Command Center and a single canonical MobileNavBar More item on compact breakpoints.
*/}
- {/* Workflows - desktop only (moved to overflow on mobile/tablet) */}
- {!isCompact && onOpenWorkflowEditor && (
+ {/*
+ FNXC:Navigation 2026-06-22-00:00:
+ When the left sidebar is active it owns Workflows as a main-content destination, so the Header drops its duplicate desktop Workflow button. The flag-off desktop layout keeps the Header button; mobile/tablet keep the overflow entry.
+ */}
+ {!isCompact && !leftSidebarNavActive && onOpenWorkflowEditor && (