FN-7365: allow task popups on every viewport
Broaden board task popup routing so the existing popup setting works outside mobile. - Route ordinary board-card opens to the task popup on desktop, tablet, and mobile when the popup setting is enabled. - Rename the Appearance setting copy while preserving the stored openMobileTasksInPopup key for compatibility. - Update tests, documentation, settings schema comments, and the published package changeset for the all-viewport behavior. Files changed: .changeset/fn-7365-task-popups-all-viewports.md | 7 ++++ docs/dashboard-guide.md | 6 ++-- docs/settings-reference.md | 2 +- packages/core/src/settings-schema.ts | 4 +-- packages/core/src/types.ts | 6 ++-- packages/dashboard/app/App.tsx | 6 ++-- .../__tests__/App.openTasksInRightSidebar.test.ts | 42 +++++++++++++++++----- .../settings/sections/AppearanceSection.tsx | 5 +-- .../sections/__tests__/AppearanceSection.test.tsx | 10 +++--- 9 files changed, 62 insertions(+), 26 deletions(-) Fusion-Task-Id: FN-7365 Fusion-Task-Lineage: 58713922-3ff8-4cc9-8f81-26c1e982819e Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
This commit is contained in:
7
.changeset/fn-7365-task-popups-all-viewports.md
Normal file
7
.changeset/fn-7365-task-popups-all-viewports.md
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
"@runfusion/fusion": patch
|
||||
---
|
||||
|
||||
summary: Let the task popup setting open board tasks as popups on desktop too.
|
||||
category: fix
|
||||
dev: Keeps the existing `openMobileTasksInPopup` setting key while broadening ordinary board-card routing across viewports.
|
||||
@@ -54,10 +54,10 @@ The **Right Dock Panel** experiment is enabled by default. To disable it, open *
|
||||
|
||||
When enabled on desktop or tablet project screens, the right dock is a persistent far-right tools sidebar in the project content row. By default it opens as an overlay so the main content does not reflow. Use the dock toolbar pin action to switch into push mode, where the dock becomes an in-flow pane that shrinks the main content beside it; unpinning returns to overlay mode. The selected tool, open/closed state, pinned push-mode state, width, and expanded modal size persist across reloads.
|
||||
|
||||
If **Settings → Appearance → Open tasks in the right sidebar** is enabled, board task-card clicks open task detail inside this right dock and keep the board visible. The setting is default off; mobile or hidden/inactive dock states automatically fall back to the existing full-panel task detail unless the separate mobile popup setting below is enabled, and non-board task-open paths keep their existing behavior.
|
||||
If **Settings → Appearance → Open tasks in the right sidebar** is enabled, board task-card clicks open task detail inside this right dock and keep the board visible. The setting is default off; mobile or hidden/inactive dock states automatically fall back to the existing full-panel task detail unless the task-popup setting below is enabled, and non-board task-open paths keep their existing behavior.
|
||||
|
||||
<!-- FNXC:MobileTaskPopups 2026-06-29-00:00: Mobile board-card task opens have a separate default-off popup setting so phone users can opt into the existing FloatingWindow task popup without changing desktop/tablet right-dock behavior or deep-tab task opens. -->
|
||||
On mobile, **Settings → Appearance → Open mobile tasks as popups** changes only ordinary board task-card clicks. When enabled, those clicks use the existing task popup/FloatingWindow surface instead of the full-panel task detail; deep `changes`/`retries`/`workflow` opens, list/task-detail links, plugin/graph opens, and desktop/tablet routing keep their existing paths.
|
||||
<!-- FNXC:MobileTaskPopups 2026-07-01-12:00: Board-card task opens have a separate default-off popup setting so operators on desktop, tablet, and mobile can opt into the existing FloatingWindow task popup when they want the board visible; ordinary popup routing takes precedence over the right dock, while deep-tab and non-board opens keep their existing paths. -->
|
||||
**Settings → Appearance → Open tasks as popups** changes only ordinary board task-card clicks across desktop, tablet, and mobile viewports. When enabled, those clicks use the existing task popup/FloatingWindow surface instead of the full-panel task detail or right-dock task detail, keeping the board visible in the background. Deep `changes`/`retries`/`workflow` opens, list/task-detail links, plugin/graph opens, and explicit pop-out actions keep their existing paths.
|
||||
|
||||
<!-- FNXC:DashboardNavigationDocs 2026-06-27-00:00: The right dock now hosts Chat as an inline tool panel; keep this user-facing roster aligned with STATIC_OVERFLOW_VIEW_ENTRIES so users know Chat can also pop out from the dock. -->
|
||||
<!-- FNXC:RightDockTasks 2026-06-28-19:55: The dock task-detail overlay is now anchored to the first-class Tasks tool tab. Document that Tasks is a dock-only auxiliary surface with a last-viewed detail/list fallback, not a new primary navigation destination. -->
|
||||
|
||||
@@ -471,7 +471,7 @@ Sandbox backend precedence is:
|
||||
| `recycleWorktrees` | `boolean` | `false` | Default: off (opt-in). Reuse worktrees from a pool for faster startup. |
|
||||
| `showWorktreeGrouping` | `boolean` | `false` | Default: off. When off, WIP/processing columns render plain task cards without worktree group shells or worktree-name labels in both legacy and workflow-mode boards. When on, every WIP/processing column groups tasks by worktree and shows worktree names, including workflow-mode columns flagged as counting toward WIP. |
|
||||
| `openTasksInRightSidebar` | `boolean` | `false` | Default: off. When off, board task-card clicks keep the existing full-panel task detail that replaces the board. When on and the right dock is active on desktop/tablet, board task-card clicks open the task detail in the right sidebar so the board stays visible; mobile or hidden/inactive right-dock states automatically fall back to the full-panel behavior. Non-board task-open paths, including list split detail, right-dock task cards, floating pop-outs, graph/plugin opens, and deep `changes`/`retries`/`workflow` opens, keep their existing behavior. |
|
||||
| `openMobileTasksInPopup` | `boolean` | `false` | Default: off. When off, mobile board task-card clicks keep the existing full-panel task detail. When on and the dashboard is in mobile viewport mode, ordinary board task-card clicks open the task in the existing task popup/FloatingWindow surface instead. This is mobile-only and board-only: desktop/tablet routing, `openTasksInRightSidebar`, right-dock task cards, list/detail opens, graph/plugin opens, nested task-detail opens, explicit pop-out actions, and deep `changes`/`retries`/`workflow` opens keep their existing behavior. |
|
||||
| `openMobileTasksInPopup` | `boolean` | `false` | Default: off. When off, ordinary board task-card clicks keep the existing fallback behavior: the full-panel task detail, or the right dock when `openTasksInRightSidebar` is on and the dock is active. When on, ordinary board task-card clicks open the task in the existing task popup/FloatingWindow surface on desktop, tablet, and mobile so the board remains visible; this popup route takes precedence over right-dock routing for those ordinary clicks. This setting remains board-only: right-dock task cards, list/detail opens, graph/plugin opens, nested task-detail opens, explicit pop-out actions, and deep `changes`/`retries`/`workflow` opens keep their existing behavior. |
|
||||
| `executorAllowSiblingBranchRename` | `boolean` | `false` | Opt back into the legacy executor behavior that silently allocates sibling branches (`fusion/<task-id>-2`, `-2-2`, …) when the canonical task branch is already checked out elsewhere. When disabled (default), branch conflicts fail loudly and leave the task in `todo` with `status: "failed"` so operators can resolve conflicting branches/worktrees with git tooling before retrying. See [Task Management → Branch conflict handling](./task-management.md#branch-conflict-handling). The dashboard Settings modal exposes the same toggle with warning copy because this legacy mode is discouraged. |
|
||||
| `worktreeNaming` | `"random" \| "task-id" \| "task-title"` | `"random"` | Naming mode for new worktree directories. |
|
||||
|
||||
|
||||
@@ -328,8 +328,8 @@ export const DEFAULT_PROJECT_SETTINGS = {
|
||||
showWorktreeGrouping: false,
|
||||
openTasksInRightSidebar: false,
|
||||
/*
|
||||
FNXC:MobileTaskPopups 2026-06-29-00:00:
|
||||
Default off preserves current mobile board-card task detail behavior. The dashboard only consults this project setting for mobile board-card clicks without a deep tab, and reuses the existing task pop-out surface without changing desktop/right-dock routing.
|
||||
FNXC:MobileTaskPopups 2026-07-01-12:00:
|
||||
Default off preserves current board-card task detail behavior. The dashboard only consults this project setting for ordinary board-card clicks without a deep tab across mobile, tablet, and desktop viewports, and reuses the existing task pop-out surface before falling back to right-dock or main-panel routing.
|
||||
*/
|
||||
openMobileTasksInPopup: false,
|
||||
/*
|
||||
|
||||
@@ -3730,10 +3730,10 @@ export interface ProjectSettings {
|
||||
*/
|
||||
openTasksInRightSidebar?: boolean;
|
||||
/**
|
||||
* When true, mobile board task-card clicks open task detail in the existing popped-out FloatingWindow task surface instead of the full main-panel task detail. Default: false.
|
||||
* When true, ordinary board task-card clicks open task detail in the existing popped-out FloatingWindow task surface instead of the full main-panel task detail. Default: false.
|
||||
*
|
||||
* FNXC:MobileTaskPopups 2026-06-29-00:00:
|
||||
* This project-scoped setting is default-off so mobile board navigation is unchanged until operators opt in. When enabled, it applies only to mobile viewport board-card clicks with no deep initial tab and reuses the existing task pop-out/FloatingWindow path; desktop/tablet right-dock routing and all non-board task-open paths remain governed by their existing settings and handlers.
|
||||
* FNXC:MobileTaskPopups 2026-07-01-12:00:
|
||||
* This project-scoped setting is default-off so board navigation is unchanged until operators opt in. When enabled, it applies to board-card clicks on every viewport with no deep initial tab and reuses the existing task pop-out/FloatingWindow path; the popup route takes precedence over right-dock routing for those ordinary clicks while all non-board task-open paths remain governed by their existing settings and handlers.
|
||||
*/
|
||||
openMobileTasksInPopup?: boolean;
|
||||
/**
|
||||
|
||||
@@ -195,7 +195,7 @@ export function getBoardTaskOpenRoute(options: {
|
||||
rightDockActive: boolean;
|
||||
initialTab?: DetailTaskTab;
|
||||
}): BoardTaskOpenRoute {
|
||||
if (!options.initialTab && options.isMobile && options.openMobileTasksInPopup) {
|
||||
if (!options.initialTab && options.openMobileTasksInPopup) {
|
||||
return "popup";
|
||||
}
|
||||
if (shouldOpenBoardTaskInDock(options.openTasksInRightSidebar, options.rightDockActive, options.initialTab)) {
|
||||
@@ -1142,8 +1142,8 @@ function AppInner() {
|
||||
FNXC:OpenTasksInRightSidebar 2026-06-28-00:00:
|
||||
Board card clicks are the only task-open path governed by openTasksInRightSidebar. When the project setting is enabled and the tablet/desktop right dock is active, the board keeps its current view and asks the dock controller to render task detail; otherwise the existing full main-panel replacement remains the fallback, including mobile and hidden-footer states.
|
||||
|
||||
FNXC:MobileTaskPopups 2026-06-29-00:00:
|
||||
Mobile board-card clicks may opt into the existing task pop-out path, but only for ordinary task opens with no deep initial tab. The route is intentionally ordered as mobile popup, then desktop/tablet right dock, then main-panel fallback so the new setting cannot override deep-tab opens, non-board handlers, or desktop right-dock behavior.
|
||||
FNXC:MobileTaskPopups 2026-07-01-12:00:
|
||||
Board-card clicks on every viewport may opt into the existing task pop-out path, but only for ordinary task opens with no deep initial tab. The route is intentionally ordered as all-viewport popup, then tablet/desktop right dock, then main-panel fallback so the popup setting keeps the board visible when requested while deep-tab opens and non-board handlers keep their existing behavior.
|
||||
*/
|
||||
const openBoardTaskDetail = useCallback((task: Task | TaskDetail, initialTab?: DetailTaskTab) => {
|
||||
const route = getBoardTaskOpenRoute({
|
||||
|
||||
@@ -14,28 +14,46 @@ describe("board task detail routing", () => {
|
||||
expect(shouldOpenBoardTaskInDock(true, true, "workflow")).toBe(false);
|
||||
});
|
||||
|
||||
it("routes mobile board card clicks to the popup only when the mobile popup setting is enabled", () => {
|
||||
expect(getBoardTaskOpenRoute({
|
||||
isMobile: true,
|
||||
openMobileTasksInPopup: true,
|
||||
openTasksInRightSidebar: false,
|
||||
rightDockActive: false,
|
||||
})).toBe("popup");
|
||||
it("routes ordinary board card clicks to the popup on mobile, tablet, and desktop when enabled", () => {
|
||||
for (const isMobile of [true, false]) {
|
||||
expect(getBoardTaskOpenRoute({
|
||||
isMobile,
|
||||
openMobileTasksInPopup: true,
|
||||
openTasksInRightSidebar: false,
|
||||
rightDockActive: false,
|
||||
})).toBe("popup");
|
||||
}
|
||||
});
|
||||
|
||||
it("keeps setting-off and undefined values on the existing fallback route", () => {
|
||||
expect(getBoardTaskOpenRoute({
|
||||
isMobile: true,
|
||||
openMobileTasksInPopup: false,
|
||||
openTasksInRightSidebar: false,
|
||||
rightDockActive: false,
|
||||
})).toBe("main-panel");
|
||||
|
||||
expect(getBoardTaskOpenRoute({
|
||||
isMobile: false,
|
||||
openMobileTasksInPopup: undefined as unknown as boolean,
|
||||
openTasksInRightSidebar: false,
|
||||
rightDockActive: false,
|
||||
})).toBe("main-panel");
|
||||
});
|
||||
|
||||
it("preserves desktop and tablet right-dock routing precedence", () => {
|
||||
it("gives the popup setting deterministic precedence over desktop and tablet right-dock routing", () => {
|
||||
expect(getBoardTaskOpenRoute({
|
||||
isMobile: false,
|
||||
openMobileTasksInPopup: true,
|
||||
openTasksInRightSidebar: true,
|
||||
rightDockActive: true,
|
||||
})).toBe("popup");
|
||||
|
||||
expect(getBoardTaskOpenRoute({
|
||||
isMobile: false,
|
||||
openMobileTasksInPopup: false,
|
||||
openTasksInRightSidebar: true,
|
||||
rightDockActive: true,
|
||||
})).toBe("dock");
|
||||
|
||||
expect(getBoardTaskOpenRoute({
|
||||
@@ -43,10 +61,10 @@ describe("board task detail routing", () => {
|
||||
openMobileTasksInPopup: true,
|
||||
openTasksInRightSidebar: false,
|
||||
rightDockActive: true,
|
||||
})).toBe("main-panel");
|
||||
})).toBe("popup");
|
||||
});
|
||||
|
||||
it("keeps deep-tab opens off the mobile popup path", () => {
|
||||
it("keeps deep-tab opens off the all-viewport popup path", () => {
|
||||
for (const initialTab of ["changes", "retries", "workflow"] as const) {
|
||||
expect(getBoardTaskOpenRoute({
|
||||
isMobile: true,
|
||||
@@ -55,6 +73,14 @@ describe("board task detail routing", () => {
|
||||
rightDockActive: true,
|
||||
initialTab,
|
||||
})).toBe("main-panel");
|
||||
|
||||
expect(getBoardTaskOpenRoute({
|
||||
isMobile: false,
|
||||
openMobileTasksInPopup: true,
|
||||
openTasksInRightSidebar: true,
|
||||
rightDockActive: true,
|
||||
initialTab,
|
||||
})).toBe("main-panel");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -45,11 +45,12 @@ export function AppearanceSection({ scopeBanner, form, setForm, themeMode, color
|
||||
<small className="form-text text-muted">{t("settings.appearance.openTasksInRightSidebarHelp", "When enabled, board task cards open detail in the right sidebar when it is available; mobile and hidden-sidebar states keep the full task panel.")}</small>
|
||||
</div>
|
||||
<div className="form-group">
|
||||
{/* FNXC:MobileTaskPopups 2026-07-01-12:00: Keep the stored openMobileTasksInPopup key for compatibility, but present the setting as all-viewport board-card popup routing because desktop operators also need the board visible behind task detail. */}
|
||||
<label className="checkbox-label">
|
||||
<input type="checkbox" checked={form.openMobileTasksInPopup === true} onChange={(e) => setForm((f) => ({ ...f, openMobileTasksInPopup: e.target.checked }))}/>
|
||||
<span>{t("settings.appearance.openMobileTasksInPopup", "Open mobile tasks as popups")}</span>
|
||||
<span>{t("settings.appearance.openMobileTasksInPopup", "Open tasks as popups")}</span>
|
||||
</label>
|
||||
<small className="form-text text-muted">{t("settings.appearance.openMobileTasksInPopupHelp", "When enabled, mobile board task-card clicks use the existing task popup instead of the full-screen task panel. Desktop, right-sidebar, and non-board task opens keep their current behavior.")}</small>
|
||||
<small className="form-text text-muted">{t("settings.appearance.openMobileTasksInPopupHelp", "When enabled, ordinary board task-card clicks open the existing task popup so the board remains visible. Deep-tab and non-board task opens keep their current behavior.")}</small>
|
||||
</div>
|
||||
<div className="form-group">
|
||||
{/* FNXC:TaskDetailActivityFirst 2026-06-30-23:59: The project setting is opt-in because task details now default to Activity-first; explicit Activity/Chat/Logs links keep their destination regardless of this checkbox. */}
|
||||
|
||||
@@ -63,11 +63,13 @@ describe("AppearanceSection", () => {
|
||||
expect(screen.getByLabelText("Open tasks in the right sidebar")).toBeChecked();
|
||||
});
|
||||
|
||||
it("renders and updates the mobile task popup checkbox", () => {
|
||||
it("renders and updates the task popup checkbox", () => {
|
||||
const { setForm, getForm } = renderAppearanceSection();
|
||||
|
||||
const checkbox = screen.getByLabelText("Open mobile tasks as popups");
|
||||
const checkbox = screen.getByLabelText("Open tasks as popups");
|
||||
expect(checkbox).not.toBeChecked();
|
||||
expect(screen.getByText(/ordinary board task-card clicks open the existing task popup/)).toBeInTheDocument();
|
||||
expect(screen.getByText(/Deep-tab and non-board task opens keep their current behavior/)).toBeInTheDocument();
|
||||
|
||||
fireEvent.click(checkbox);
|
||||
|
||||
@@ -75,10 +77,10 @@ describe("AppearanceSection", () => {
|
||||
expect(getForm().openMobileTasksInPopup).toBe(true);
|
||||
});
|
||||
|
||||
it("reflects a persisted enabled mobile task popup value", () => {
|
||||
it("reflects a persisted enabled task popup value", () => {
|
||||
renderAppearanceSection({ openMobileTasksInPopup: true });
|
||||
|
||||
expect(screen.getByLabelText("Open mobile tasks as popups")).toBeChecked();
|
||||
expect(screen.getByLabelText("Open tasks as popups")).toBeChecked();
|
||||
});
|
||||
|
||||
it("renders task detail Chat-first as unchecked by default and updates it", () => {
|
||||
|
||||
Reference in New Issue
Block a user