fix: restore Changes focus on task return (#2091)
This commit is contained in:
@@ -179,6 +179,7 @@ describe("applyChangesPanelAutoFocusState fallback session keys", () => {
|
||||
previousMarkers,
|
||||
pendingEnvKeys,
|
||||
isRestoringLayout: false,
|
||||
isMaximized: false,
|
||||
activate: () => {
|
||||
activateCalls += 1;
|
||||
return "activated";
|
||||
@@ -207,6 +208,7 @@ describe("applyChangesPanelAutoFocusState fallback session keys", () => {
|
||||
previousMarkers,
|
||||
pendingEnvKeys,
|
||||
isRestoringLayout: false,
|
||||
isMaximized: false,
|
||||
activate: () => {
|
||||
activateCalls += 1;
|
||||
return "activated";
|
||||
@@ -223,8 +225,8 @@ describe("applyChangesPanelAutoFocusState fallback session keys", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("applyChangesPanelAutoFocusState saved layouts", () => {
|
||||
it("keeps a returning environment's saved active panel over pending changes", () => {
|
||||
describe("applyChangesPanelAutoFocusState returning environments", () => {
|
||||
it("activates pending changes when returning from another environment", () => {
|
||||
const previousMarkers = {
|
||||
envB: { count: 1, fingerprint: "b1" },
|
||||
};
|
||||
@@ -240,17 +242,75 @@ describe("applyChangesPanelAutoFocusState saved layouts", () => {
|
||||
environmentIdBySessionId: {},
|
||||
previousMarkers,
|
||||
pendingEnvKeys,
|
||||
hasSavedLayout: true,
|
||||
isRestoringLayout: false,
|
||||
isMaximized: false,
|
||||
activate: () => {
|
||||
activateCalls += 1;
|
||||
return "activated";
|
||||
},
|
||||
});
|
||||
|
||||
expect(activateCalls).toBe(0);
|
||||
expect(activateCalls).toBe(1);
|
||||
expect(pendingEnvKeys.size).toBe(0);
|
||||
});
|
||||
|
||||
it("keeps pending changes while maximized and activates them after exit", () => {
|
||||
const previousMarkers = {
|
||||
envB: { count: 1, fingerprint: "b1" },
|
||||
};
|
||||
const pendingEnvKeys = new Set(["envB"]);
|
||||
let activateCalls = 0;
|
||||
const baseArgs = {
|
||||
signalsByEnv: {
|
||||
envB: signal(1, "b1"),
|
||||
},
|
||||
activeEnvKey: "envB",
|
||||
previousActiveEnvKey: "envA",
|
||||
environmentIdBySessionId: {},
|
||||
previousMarkers,
|
||||
pendingEnvKeys,
|
||||
isRestoringLayout: false,
|
||||
};
|
||||
|
||||
applyChangesPanelAutoFocusState({
|
||||
...baseArgs,
|
||||
isMaximized: true,
|
||||
activate: () => {
|
||||
activateCalls += 1;
|
||||
return "no-panel" as const;
|
||||
},
|
||||
});
|
||||
const whileMaximized = {
|
||||
activateCalls,
|
||||
pendingEnvKeys: [...pendingEnvKeys],
|
||||
};
|
||||
|
||||
applyChangesPanelAutoFocusState({
|
||||
...baseArgs,
|
||||
isMaximized: false,
|
||||
activate: () => {
|
||||
activateCalls += 1;
|
||||
return "activated" as const;
|
||||
},
|
||||
});
|
||||
|
||||
expect({
|
||||
whileMaximized,
|
||||
afterExit: {
|
||||
activateCalls,
|
||||
pendingEnvKeys: [...pendingEnvKeys],
|
||||
},
|
||||
}).toEqual({
|
||||
whileMaximized: {
|
||||
activateCalls: 1,
|
||||
pendingEnvKeys: ["envB"],
|
||||
},
|
||||
afterExit: {
|
||||
activateCalls: 2,
|
||||
pendingEnvKeys: [],
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("applyChangesPanelAutoFocusState", () => {
|
||||
@@ -270,6 +330,7 @@ describe("applyChangesPanelAutoFocusState", () => {
|
||||
previousMarkers,
|
||||
pendingEnvKeys,
|
||||
isRestoringLayout: false,
|
||||
isMaximized: false,
|
||||
activate: () => {
|
||||
activateCalls += 1;
|
||||
return "activated";
|
||||
@@ -288,6 +349,7 @@ describe("applyChangesPanelAutoFocusState", () => {
|
||||
previousMarkers,
|
||||
pendingEnvKeys,
|
||||
isRestoringLayout: false,
|
||||
isMaximized: false,
|
||||
activate: () => {
|
||||
activateCalls += 1;
|
||||
return "activated";
|
||||
@@ -309,6 +371,7 @@ describe("applyChangesPanelAutoFocusState", () => {
|
||||
previousMarkers,
|
||||
pendingEnvKeys,
|
||||
isRestoringLayout: true,
|
||||
isMaximized: false,
|
||||
activate: () => {
|
||||
activateCalls += 1;
|
||||
return "activated";
|
||||
@@ -328,6 +391,7 @@ describe("applyChangesPanelAutoFocusState", () => {
|
||||
previousMarkers,
|
||||
pendingEnvKeys,
|
||||
isRestoringLayout: false,
|
||||
isMaximized: false,
|
||||
activate: () => {
|
||||
activateCalls += 1;
|
||||
return "activated";
|
||||
@@ -480,6 +544,7 @@ describe("applyChangesPanelAutoFocusState restore races", () => {
|
||||
previousMarkers,
|
||||
pendingEnvKeys,
|
||||
isRestoringLayout: false,
|
||||
isMaximized: false,
|
||||
getIsRestoringLayout: () => restoring,
|
||||
activate: () => {
|
||||
restoring = true;
|
||||
|
||||
@@ -7,7 +7,6 @@ import { useAppStore } from "@/components/state-provider";
|
||||
import { useDockviewStore } from "@/lib/state/dockview-store";
|
||||
import type { AppState } from "@/lib/state/store";
|
||||
import type { FileInfo, GitStatusEntry } from "@/lib/state/slices/session-runtime/types";
|
||||
import { getEnvLayout } from "@/lib/local-storage";
|
||||
import { djb2Hash } from "@/lib/utils/hash";
|
||||
|
||||
type DockviewPanel = NonNullable<ReturnType<DockviewApi["getPanel"]>>;
|
||||
@@ -251,9 +250,10 @@ export function applyChangesPanelAutoFocusState(args: {
|
||||
environmentIdBySessionId: Record<string, string>;
|
||||
previousMarkers: Record<string, ChangesMarker>;
|
||||
pendingEnvKeys: Set<string>;
|
||||
hasSavedLayout?: boolean;
|
||||
isRestoringLayout: boolean;
|
||||
getIsRestoringLayout?: () => boolean;
|
||||
isMaximized: boolean;
|
||||
getIsMaximized?: () => boolean;
|
||||
activate: () => ActivateChangesPanelResult;
|
||||
}): string | null {
|
||||
const {
|
||||
@@ -263,9 +263,10 @@ export function applyChangesPanelAutoFocusState(args: {
|
||||
environmentIdBySessionId,
|
||||
previousMarkers,
|
||||
pendingEnvKeys,
|
||||
hasSavedLayout = false,
|
||||
isRestoringLayout,
|
||||
getIsRestoringLayout,
|
||||
isMaximized,
|
||||
getIsMaximized,
|
||||
activate,
|
||||
} = args;
|
||||
|
||||
@@ -288,17 +289,13 @@ export function applyChangesPanelAutoFocusState(args: {
|
||||
});
|
||||
|
||||
const isCurrentlyRestoringLayout = () => isRestoringLayout || getIsRestoringLayout?.() === true;
|
||||
const isCurrentlyMaximized = () => isMaximized || getIsMaximized?.() === true;
|
||||
|
||||
// A saved env layout records the user's active panel. Pending Changes
|
||||
// attention may choose the first panel for an unseen env, but must not
|
||||
// override that explicit focus when the user returns to a task.
|
||||
if (activeEnvKey && hasSavedLayout) {
|
||||
pendingEnvKeys.delete(activeEnvKey);
|
||||
} else if (activeEnvKey && !isCurrentlyRestoringLayout() && pendingEnvKeys.has(activeEnvKey)) {
|
||||
if (activeEnvKey && !isCurrentlyRestoringLayout() && pendingEnvKeys.has(activeEnvKey)) {
|
||||
const result = activate();
|
||||
if (
|
||||
shouldClearPendingChangesFocus(result) &&
|
||||
!(result === "no-panel" && isCurrentlyRestoringLayout())
|
||||
!(result === "no-panel" && (isCurrentlyRestoringLayout() || isCurrentlyMaximized()))
|
||||
) {
|
||||
pendingEnvKeys.delete(activeEnvKey);
|
||||
}
|
||||
@@ -310,12 +307,12 @@ export function applyChangesPanelAutoFocusState(args: {
|
||||
export function useChangesPanelAutoFocus(activeEnvKey: string | null) {
|
||||
const api = useDockviewStore((s) => s.api);
|
||||
const isRestoringLayout = useDockviewStore((s) => s.isRestoringLayout);
|
||||
const isMaximized = useDockviewStore((s) => s.preMaximizeLayout !== null);
|
||||
const signalsByEnv = useAppStore(useShallow(selectChangesSignalByEnvironment));
|
||||
const environmentIdBySessionId = useAppStore((state) => state.environmentIdBySessionId);
|
||||
const previousMarkersRef = useRef<Record<string, ChangesMarker>>({});
|
||||
const pendingEnvKeysRef = useRef<Set<string>>(new Set());
|
||||
const previousActiveEnvKeyRef = useRef<string | null>(null);
|
||||
const hasSavedLayout = activeEnvKey !== null && getEnvLayout(activeEnvKey) !== null;
|
||||
|
||||
useEffect(() => {
|
||||
previousActiveEnvKeyRef.current = applyChangesPanelAutoFocusState({
|
||||
@@ -325,17 +322,11 @@ export function useChangesPanelAutoFocus(activeEnvKey: string | null) {
|
||||
environmentIdBySessionId,
|
||||
previousMarkers: previousMarkersRef.current,
|
||||
pendingEnvKeys: pendingEnvKeysRef.current,
|
||||
hasSavedLayout,
|
||||
isRestoringLayout,
|
||||
getIsRestoringLayout: () => useDockviewStore.getState().isRestoringLayout,
|
||||
isMaximized,
|
||||
getIsMaximized: () => useDockviewStore.getState().preMaximizeLayout !== null,
|
||||
activate: () => activateChangesPanel(api),
|
||||
});
|
||||
}, [
|
||||
signalsByEnv,
|
||||
activeEnvKey,
|
||||
api,
|
||||
isRestoringLayout,
|
||||
environmentIdBySessionId,
|
||||
hasSavedLayout,
|
||||
]);
|
||||
}, [signalsByEnv, activeEnvKey, api, isRestoringLayout, isMaximized, environmentIdBySessionId]);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user