fix: retry canvas agent view after refresh
This commit is contained in:
parent
41acb006cf
commit
dfb8971bcb
@ -129,6 +129,7 @@ import {
|
|||||||
getCanvasMediaPayloadHandledItemIds,
|
getCanvasMediaPayloadHandledItemIds,
|
||||||
getCanvasOperationHandledMediaItemIds,
|
getCanvasOperationHandledMediaItemIds,
|
||||||
type ImageGenerationStatusStreamPayload,
|
type ImageGenerationStatusStreamPayload,
|
||||||
|
shouldRetryCanvasViewOperationAfterRefresh,
|
||||||
shouldSkipCanvasMediaPayloadForHandledItems,
|
shouldSkipCanvasMediaPayloadForHandledItems,
|
||||||
} from "@/components/canvas/chat-panel/canvas-agent-stream";
|
} from "@/components/canvas/chat-panel/canvas-agent-stream";
|
||||||
import {
|
import {
|
||||||
@ -1249,6 +1250,8 @@ export function CanvasChatPanel({
|
|||||||
const autoContextRef = useRef<string | null>(null);
|
const autoContextRef = useRef<string | null>(null);
|
||||||
const contextPayloadRef = useRef<any>(null);
|
const contextPayloadRef = useRef<any>(null);
|
||||||
const handledCanvasMediaItemIdsRef = useRef<Set<string>>(new Set());
|
const handledCanvasMediaItemIdsRef = useRef<Set<string>>(new Set());
|
||||||
|
const pendingCanvasViewOperationRef =
|
||||||
|
useRef<CanvasViewOperationStreamPayload | null>(null);
|
||||||
const lastWorkflowAutofillSignatureRef = useRef<string | null>(null);
|
const lastWorkflowAutofillSignatureRef = useRef<string | null>(null);
|
||||||
const lastWorkflowAutofillUrlsRef = useRef<string[]>([]);
|
const lastWorkflowAutofillUrlsRef = useRef<string[]>([]);
|
||||||
const pendingLaunchRef = useRef<CanvasLaunchPayload | null>(null);
|
const pendingLaunchRef = useRef<CanvasLaunchPayload | null>(null);
|
||||||
@ -1826,10 +1829,10 @@ export function CanvasChatPanel({
|
|||||||
|
|
||||||
const applyCanvasViewOperation = useCallback(
|
const applyCanvasViewOperation = useCallback(
|
||||||
(payload: CanvasViewOperationStreamPayload) => {
|
(payload: CanvasViewOperationStreamPayload) => {
|
||||||
if (!payload || typeof payload !== "object") return;
|
if (!payload || typeof payload !== "object") return false;
|
||||||
const targetProjectId = String(payload.projectId || "").trim();
|
const targetProjectId = String(payload.projectId || "").trim();
|
||||||
if (targetProjectId && targetProjectId !== canvasId) return;
|
if (targetProjectId && targetProjectId !== canvasId) return false;
|
||||||
if (typeof window === "undefined") return;
|
if (typeof window === "undefined") return false;
|
||||||
|
|
||||||
const store = useCanvasStore.getState();
|
const store = useCanvasStore.getState();
|
||||||
const resolved = resolveCanvasViewOperation({
|
const resolved = resolveCanvasViewOperation({
|
||||||
@ -1842,7 +1845,7 @@ export function CanvasChatPanel({
|
|||||||
height: window.innerHeight,
|
height: window.innerHeight,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
if (!resolved) return;
|
if (!resolved) return false;
|
||||||
|
|
||||||
window.requestAnimationFrame(() => {
|
window.requestAnimationFrame(() => {
|
||||||
setTransientViewport(resolved.viewport);
|
setTransientViewport(resolved.viewport);
|
||||||
@ -1850,6 +1853,7 @@ export function CanvasChatPanel({
|
|||||||
if (resolved.targetNodeIds.length > 0) {
|
if (resolved.targetNodeIds.length > 0) {
|
||||||
store.selectNodes(resolved.targetNodeIds);
|
store.selectNodes(resolved.targetNodeIds);
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
},
|
},
|
||||||
[canvasId, setTransientViewport]
|
[canvasId, setTransientViewport]
|
||||||
);
|
);
|
||||||
@ -4062,6 +4066,16 @@ export function CanvasChatPanel({
|
|||||||
focusCanvasOnNode(focusNode);
|
focusCanvasOnNode(focusNode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const pendingViewOperation = pendingCanvasViewOperationRef.current;
|
||||||
|
if (pendingViewOperation) {
|
||||||
|
const pendingProjectId = String(pendingViewOperation.projectId || "").trim();
|
||||||
|
if (!pendingProjectId || pendingProjectId === targetProjectId) {
|
||||||
|
const applied = applyCanvasViewOperation(pendingViewOperation);
|
||||||
|
if (applied) {
|
||||||
|
pendingCanvasViewOperationRef.current = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -4071,7 +4085,7 @@ export function CanvasChatPanel({
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[canvasId, focusCanvasOnNode, mutate]
|
[applyCanvasViewOperation, canvasId, focusCanvasOnNode, mutate]
|
||||||
);
|
);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@ -4242,7 +4256,10 @@ export function CanvasChatPanel({
|
|||||||
try {
|
try {
|
||||||
const payload: CanvasViewOperationStreamPayload =
|
const payload: CanvasViewOperationStreamPayload =
|
||||||
typeof dataPart.data === "string" ? JSON.parse(dataPart.data) : dataPart.data;
|
typeof dataPart.data === "string" ? JSON.parse(dataPart.data) : dataPart.data;
|
||||||
applyCanvasViewOperation(payload);
|
const applied = applyCanvasViewOperation(payload);
|
||||||
|
if (!applied && shouldRetryCanvasViewOperationAfterRefresh(payload)) {
|
||||||
|
pendingCanvasViewOperationRef.current = payload;
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("[CanvasChat] Failed to parse data-canvasViewOperation:", e);
|
console.error("[CanvasChat] Failed to parse data-canvasViewOperation:", e);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -64,6 +64,22 @@ export function shouldSkipCanvasMediaPayloadForHandledItems(params: {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function shouldRetryCanvasViewOperationAfterRefresh(
|
||||||
|
payload: CanvasViewOperationStreamPayload
|
||||||
|
) {
|
||||||
|
const operation = String(payload?.operation || "").trim();
|
||||||
|
if (!operation) return false;
|
||||||
|
if (normalizeCanvasStreamIdList(payload.nodeIds).length > 0) return true;
|
||||||
|
if (String(payload.anchorNodeId || "").trim()) return true;
|
||||||
|
return (
|
||||||
|
operation === "focus_node" ||
|
||||||
|
operation === "focus_nodes" ||
|
||||||
|
operation === "focus_selection" ||
|
||||||
|
operation === "focus_latest_result" ||
|
||||||
|
operation === "fit_all"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export type ImageGenerationStatusStreamPayload = {
|
export type ImageGenerationStatusStreamPayload = {
|
||||||
phase?: "queued" | "processing" | "finalizing" | "failed" | "completed";
|
phase?: "queued" | "processing" | "finalizing" | "failed" | "completed";
|
||||||
providerType?: string;
|
providerType?: string;
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import {
|
|||||||
import {
|
import {
|
||||||
getCanvasMediaPayloadHandledItemIds,
|
getCanvasMediaPayloadHandledItemIds,
|
||||||
getCanvasOperationHandledMediaItemIds,
|
getCanvasOperationHandledMediaItemIds,
|
||||||
|
shouldRetryCanvasViewOperationAfterRefresh,
|
||||||
shouldSkipCanvasMediaPayloadForHandledItems,
|
shouldSkipCanvasMediaPayloadForHandledItems,
|
||||||
} from "@/components/canvas/chat-panel/canvas-agent-stream";
|
} from "@/components/canvas/chat-panel/canvas-agent-stream";
|
||||||
import {
|
import {
|
||||||
@ -1217,6 +1218,31 @@ test.describe("canvas chat pure helpers", () => {
|
|||||||
expect(useCanvasStore.getState().isAgentOperationRefreshActive()).toBe(false);
|
expect(useCanvasStore.getState().isAgentOperationRefreshActive()).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("queues target-based canvas view operations for post-refresh retry", () => {
|
||||||
|
expect(
|
||||||
|
shouldRetryCanvasViewOperationAfterRefresh({
|
||||||
|
version: 1,
|
||||||
|
viewOperationId: "view-result",
|
||||||
|
operation: "focus_latest_result",
|
||||||
|
nodeIds: ["new-image-1"],
|
||||||
|
})
|
||||||
|
).toBe(true);
|
||||||
|
expect(
|
||||||
|
shouldRetryCanvasViewOperationAfterRefresh({
|
||||||
|
version: 1,
|
||||||
|
viewOperationId: "view-fit-all",
|
||||||
|
operation: "fit_all",
|
||||||
|
})
|
||||||
|
).toBe(true);
|
||||||
|
expect(
|
||||||
|
shouldRetryCanvasViewOperationAfterRefresh({
|
||||||
|
version: 1,
|
||||||
|
viewOperationId: "view-zoom",
|
||||||
|
operation: "zoom_in",
|
||||||
|
})
|
||||||
|
).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
test("builds transient view operations for agent writeback results", () => {
|
test("builds transient view operations for agent writeback results", () => {
|
||||||
expect(
|
expect(
|
||||||
buildCanvasAgentResultViewOperation({
|
buildCanvasAgentResultViewOperation({
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user