FN-7649: resolve settings landing view to board on project switch
Fixes project-switch hydration so a persisted "settings" view resolves to the Board instead of re-opening Settings. - Extend resolveLandingTaskView() in useViewState.ts to treat "settings" the same as "command-center", resolving both to "board" for the auto-restored/hydrated landing view only - Add regression tests covering the settings->board landing resolution in useViewState.test.ts - Add changeset documenting the patch-level fix Files changed: .changeset/fn-7649-project-switch-board-landing.md | 7 ++ .../app/hooks/__tests__/useViewState.test.ts | 74 ++++++++++++++++++++++ packages/dashboard/app/hooks/useViewState.ts | 5 +- 3 files changed, 85 insertions(+), 1 deletion(-) Fusion-Task-Id: FN-7649 Fusion-Task-Lineage: 7179efd6-bb1b-4ea4-a062-479b9b1fffa3 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
This commit is contained in:
7
.changeset/fn-7649-project-switch-board-landing.md
Normal file
7
.changeset/fn-7649-project-switch-board-landing.md
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
"@runfusion/fusion": patch
|
||||
---
|
||||
|
||||
summary: Switching projects now lands on the Board instead of Settings when the last-visited view was Settings.
|
||||
category: fix
|
||||
dev: Extended resolveLandingTaskView in useViewState.ts to resolve "settings" (in addition to "command-center") to "board" for the auto-restored/hydrated landing view only; deep links (?view=settings) and explicit navigation still open Settings.
|
||||
@@ -77,6 +77,55 @@ describe("useViewState", () => {
|
||||
});
|
||||
});
|
||||
|
||||
// FNXC:ViewState FN-7649: Persisted Settings must not be the auto-restored landing view either; it lands on the Board instead.
|
||||
it("lands on board when the persisted taskView is settings", async () => {
|
||||
localStorage.setItem("kb-dashboard-task-view", "settings");
|
||||
|
||||
const { result } = renderHook(() => useViewState(createOptions()));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.taskView).toBe("board");
|
||||
});
|
||||
});
|
||||
|
||||
it("?view=settings deep link still opens Settings (not routed through the landing guard)", async () => {
|
||||
const originalSearch = window.location.search;
|
||||
window.history.replaceState({}, "", "?view=settings");
|
||||
|
||||
try {
|
||||
const { result } = renderHook(() => useViewState(createOptions()));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.taskView).toBe("settings");
|
||||
});
|
||||
} finally {
|
||||
window.history.replaceState({}, "", originalSearch ? `?${originalSearch.replace(/^\?/, "")}` : "/");
|
||||
}
|
||||
});
|
||||
|
||||
it("explicit setTaskView/handleChangeTaskView to settings still opens Settings", async () => {
|
||||
const { result } = renderHook(() => useViewState(createOptions()));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.taskView).toBe("board");
|
||||
});
|
||||
|
||||
await act(async () => {
|
||||
result.current.setTaskView("settings");
|
||||
});
|
||||
|
||||
expect(result.current.taskView).toBe("settings");
|
||||
|
||||
await act(async () => {
|
||||
result.current.handleChangeTaskView("board");
|
||||
});
|
||||
await act(async () => {
|
||||
result.current.handleChangeTaskView("settings");
|
||||
});
|
||||
|
||||
expect(result.current.taskView).toBe("settings");
|
||||
});
|
||||
|
||||
it("migrates legacy reliability taskView from localStorage to Command Center", async () => {
|
||||
localStorage.setItem("kb-dashboard-task-view", "reliability");
|
||||
|
||||
@@ -578,6 +627,31 @@ describe("useViewState", () => {
|
||||
});
|
||||
});
|
||||
|
||||
// FNXC:ViewState FN-7649: Switching projects (rerender with a new currentProject) must not land on Settings when the newly selected project's scoped persisted view is settings; it resolves to board. Mirrors the existing command-center project-switch coverage above.
|
||||
it("lands on board when switching to a project whose persisted scoped taskView is settings", async () => {
|
||||
const projectA: ProjectInfo = { ...PROJECT, id: "proj_a", name: "Project A" };
|
||||
const projectB: ProjectInfo = { ...PROJECT, id: "proj_b", name: "Project B" };
|
||||
|
||||
localStorage.setItem("kb:proj_a:kb-dashboard-task-view", "list");
|
||||
localStorage.setItem("kb:proj_b:kb-dashboard-task-view", "settings");
|
||||
|
||||
const { result, rerender } = renderHook(
|
||||
({ project }) => useViewState(createOptions({ currentProject: project })),
|
||||
{ initialProps: { project: projectA } },
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.taskView).toBe("list");
|
||||
});
|
||||
|
||||
// Switch to project B, whose persisted view is settings - must land on board, not settings.
|
||||
rerender({ project: projectB });
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.taskView).toBe("board");
|
||||
});
|
||||
});
|
||||
|
||||
it("no cross-project bleed when switching projects", async () => {
|
||||
const projectA: ProjectInfo = { ...PROJECT, id: "proj_a", name: "Project A" };
|
||||
const projectB: ProjectInfo = { ...PROJECT, id: "proj_b", name: "Project B" };
|
||||
|
||||
@@ -76,9 +76,12 @@ function normalizeTaskView(value: TaskView): TaskView {
|
||||
/*
|
||||
FNXC:ViewState 2026-06-22-15:30:
|
||||
Fusion must land on the Board on load, never the Command Center "Dashboard" view. A persisted/normalized `command-center` value resolves to `board` for the auto-restored landing view only (initializer + project-hydration effect). Deep links (`?view=command-center`) and explicit user navigation still reach the Command Center — this only governs the restored landing surface.
|
||||
|
||||
FNXC:ViewState 2026-07-07-00:00:
|
||||
FN-7649: an auto-restored/hydrated landing surface must never be Settings either. Once a project's per-project persisted `kb-dashboard-task-view` becomes `settings` (a common state after configuring a project through Settings), switching projects re-hydrates that scoped value and — without this guard — restores straight to Settings instead of the Board. `settings`, like `command-center`, now resolves to `board` for the auto-restored landing view only (initializer + project-hydration effect). Deep links (`?view=settings`) and explicit header/sidebar navigation to Settings still work because the `?view=` URL effect and `setTaskView`/`handleChangeTaskView` paths use `normalizeTaskView`, not this guard.
|
||||
*/
|
||||
function resolveLandingTaskView(value: TaskView): TaskView {
|
||||
return value === "command-center" ? "board" : value;
|
||||
return value === "command-center" || value === "settings" ? "board" : value;
|
||||
}
|
||||
|
||||
function migrateLegacyRoadmapsView(value: string): TaskView {
|
||||
|
||||
Reference in New Issue
Block a user