App mode - discard slow preview messages to prevent overwriting output image#9261
App mode - discard slow preview messages to prevent overwriting output image#9261pythongosssss merged 2 commits intomainfrom
Conversation
…hed processing, stopping it to overwriting the actual output display
🎭 Playwright: ✅ 555 passed, 0 failed · 1 flaky📊 Browser Reports
|
📝 WalkthroughWalkthroughPreviews now carry optional nodeId metadata; jobPreviewStore stores NodePromptPreview objects and exposes URL-only computed mapping. linearOutputStore tracks executed node IDs, skips latent previews for executed nodes, cancels RAF appropriately, and onLatentPreview/onNodeExecuted signatures accept/record nodeId. Event handler forwards displayNodeId when setting previews. Changes
Sequence Diagram(s)sequenceDiagram
participant App as App Event Handler
participant Store as Job Preview Store
participant Linear as Linear Output Store
participant Cache as Preview Cache
App->>Store: setPreviewUrl(promptId, blobUrl, displayNodeId)
Store->>Cache: store preview {url, nodeId?}
Store-->>Linear: notify via nodePreviewsByPromptId
Linear->>Linear: if nodeId present, check executedNodeIds
alt already executed
Linear->>Linear: discard latent preview
else new node
Linear->>Linear: schedule RAF to show latent preview
Linear-->>Cache: display latent preview
end
App->>Linear: onNodeExecuted(nodeId)
Linear->>Linear: add nodeId to executedNodeIds
Linear->>Linear: cancel pending RAF / update rendering
App->>Linear: onJobComplete(jobId)
Linear->>Linear: cancel pending RAF and clear trackedJobId
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
🎨 Storybook: ✅ Built — View Storybook |
📦 Bundle: 4.46 MB gzip 🟢 -42 BDetailsSummary
Category Glance App Entry Points — 17.9 kB (baseline 17.9 kB) • ⚪ 0 BMain entry bundles and manifests
Status: 1 added / 1 removed Graph Workspace — 1.02 MB (baseline 1.02 MB) • 🔴 +446 BGraph editor runtime, canvas, workflow orchestration
Status: 1 added / 1 removed Views & Navigation — 72.1 kB (baseline 72.1 kB) • ⚪ 0 BTop-level views, pages, and routed surfaces
Status: 9 added / 9 removed Panels & Settings — 435 kB (baseline 435 kB) • ⚪ 0 BConfiguration panels, inspectors, and settings screens
Status: 10 added / 10 removed User & Accounts — 16 kB (baseline 16 kB) • ⚪ 0 BAuthentication, profile, and account management bundles
Status: 5 added / 5 removed Editors & Dialogs — 736 B (baseline 736 B) • ⚪ 0 BModals, dialogs, drawers, and in-app editors
Status: 1 added / 1 removed UI Components — 47 kB (baseline 47 kB) • ⚪ 0 BReusable component library chunks
Status: 5 added / 5 removed Data & Services — 2.55 MB (baseline 2.55 MB) • 🔴 +232 BStores, services, APIs, and repositories
Status: 13 added / 13 removed Utilities & Hooks — 55.5 kB (baseline 55.5 kB) • ⚪ 0 BHelpers, composables, and utility bundles
Status: 11 added / 11 removed Vendor & Third-Party — 8.84 MB (baseline 8.84 MB) • ⚪ 0 BExternal libraries and shared vendor chunks
Other — 7.86 MB (baseline 7.86 MB) • ⚪ 0 BBundles that do not match a named category
Status: 52 added / 52 removed |
⚡ Performance Report
Raw data{
"timestamp": "2026-02-27T14:36:54.455Z",
"gitSha": "94f181431fc108fd1d858dd54a8cc96598d166bb",
"branch": "pysssss/discard-delayed-previews",
"measurements": [
{
"name": "canvas-idle",
"durationMs": 2044.5430000000329,
"styleRecalcs": 124,
"styleRecalcDurationMs": 28.559,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 450.69599999999997,
"heapDeltaBytes": -2062412
},
{
"name": "canvas-mouse-sweep",
"durationMs": 2062.0059999999967,
"styleRecalcs": 184,
"styleRecalcDurationMs": 59.265,
"layouts": 12,
"layoutDurationMs": 3.5900000000000003,
"taskDurationMs": 1083.4,
"heapDeltaBytes": -2363972
},
{
"name": "dom-widget-clipping",
"durationMs": 620.1519999999618,
"styleRecalcs": 45,
"styleRecalcDurationMs": 16.898000000000003,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 412.31300000000005,
"heapDeltaBytes": 7831548
}
]
} |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/stores/jobPreviewStore.test.ts (1)
94-101: Consider adding a test for thewatchthat clears previews when disabled.The production code has a
watch(isPreviewEnabled, ...)that callsclearAllPreviews()when previews become disabled. This behavior isn't explicitly tested. Adding a test would improve coverage of this reactive side effect.🧪 Suggested test case
+ it('clears all previews when preview method changes to none', async () => { + const { nextTick } = await import('vue') + const store = useJobPreviewStore() + store.setPreviewUrl('p1', 'blob:a', 'node-1') + store.setPreviewUrl('p2', 'blob:b', 'node-2') + + expect(Object.keys(store.nodePreviewsByPromptId)).toHaveLength(2) + + previewMethodRef.value = 'none' + await nextTick() + + expect(store.nodePreviewsByPromptId).toEqual({}) + })🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/stores/jobPreviewStore.test.ts` around lines 94 - 101, Add a test that verifies the reactive watcher clears previews when previews become disabled: create a store via useJobPreviewStore(), enable previews by setting previewMethodRef.value to a non-'none' value, call store.setPreviewUrl(...) to populate nodePreviewsByPromptId, then change previewMethodRef.value to 'none' and assert that store.nodePreviewsByPromptId is cleared (or that clearAllPreviews was invoked); reference useJobPreviewStore(), previewMethodRef, setPreviewUrl and clearAllPreviews/watch behavior in the test.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@src/stores/jobPreviewStore.test.ts`:
- Around line 94-101: Add a test that verifies the reactive watcher clears
previews when previews become disabled: create a store via useJobPreviewStore(),
enable previews by setting previewMethodRef.value to a non-'none' value, call
store.setPreviewUrl(...) to populate nodePreviewsByPromptId, then change
previewMethodRef.value to 'none' and assert that store.nodePreviewsByPromptId is
cleared (or that clearAllPreviews was invoked); reference useJobPreviewStore(),
previewMethodRef, setPreviewUrl and clearAllPreviews/watch behavior in the test.
ℹ️ Review info
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
src/renderer/extensions/linearMode/linearOutputStore.test.tssrc/renderer/extensions/linearMode/linearOutputStore.tssrc/scripts/app.tssrc/stores/jobPreviewStore.test.tssrc/stores/jobPreviewStore.ts
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/renderer/extensions/linearMode/linearOutputStore.ts (1)
250-259: Watch only the active job preview instead of deep-watching the full mapThe deep watch triggers for unrelated job preview mutations. Watching the active job entry directly reduces unnecessary callback work.
Refactor sketch
-watch( - () => jobPreviewStore.nodePreviewsByPromptId, - (previews) => { - if (!appModeStore.isAppMode) return - const jobId = executionStore.activeJobId - if (!jobId) return - const preview = previews[jobId] - if (preview) onLatentPreview(jobId, preview.url, preview.nodeId) - }, - { deep: true } -) +watch( + () => { + const jobId = executionStore.activeJobId + return jobId ? jobPreviewStore.nodePreviewsByPromptId[jobId] : undefined + }, + (preview) => { + if (!appModeStore.isAppMode) return + const jobId = executionStore.activeJobId + if (!jobId || !preview) return + onLatentPreview(jobId, preview.url, preview.nodeId) + } +)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/renderer/extensions/linearMode/linearOutputStore.ts` around lines 250 - 259, Replace the deep watch over jobPreviewStore.nodePreviewsByPromptId with a focused watch that only observes the currently active job's preview: create the watch source as a getter that reads executionStore.activeJobId and returns the single preview entry for that id (or null/undefined when no active id), then in the watch callback call onLatentPreview(jobId, preview.url, preview.nodeId) when a preview exists; remove the { deep: true } option. Use the existing symbols: watch, executionStore.activeJobId, jobPreviewStore.nodePreviewsByPromptId, appModeStore.isAppMode, and onLatentPreview to locate and implement the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/renderer/extensions/linearMode/linearOutputStore.ts`:
- Around line 58-61: In onLatentPreview, check whether nodeId is in
executedNodeIds and return early before touching raf; move the executed-node
filtering (the nodeId && executedNodeIds.has(nodeId) check) to the top of the
function so you don't cancelAnimationFrame(raf) or schedule a new RAF for a node
that's already executed; update references to raf and any subsequent scheduling
so they only run when the node is not executed.
---
Nitpick comments:
In `@src/renderer/extensions/linearMode/linearOutputStore.ts`:
- Around line 250-259: Replace the deep watch over
jobPreviewStore.nodePreviewsByPromptId with a focused watch that only observes
the currently active job's preview: create the watch source as a getter that
reads executionStore.activeJobId and returns the single preview entry for that
id (or null/undefined when no active id), then in the watch callback call
onLatentPreview(jobId, preview.url, preview.nodeId) when a preview exists;
remove the { deep: true } option. Use the existing symbols: watch,
executionStore.activeJobId, jobPreviewStore.nodePreviewsByPromptId,
appModeStore.isAppMode, and onLatentPreview to locate and implement the change.
8b38c41 to
c797e1b
Compare
…t image (#9261) ## Summary Prevent latent previews received after the job/node has already finished processing overwriting the actual output display ## Changes - **What**: - updates job preview store to also track which node the preview was for - updates linear progress tracking to store executed nodes enabling skipping previews of these ## Review Focus <!-- Critical design decisions or edge cases that need attention --> <!-- If this PR fixes an issue, uncomment and update the line below --> <!-- Fixes #ISSUE_NUMBER --> ## Screenshots (if applicable) <!-- Add screenshots or video recording to help explain your changes --> ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-9261-App-mode-discard-slow-preview-messages-to-prevent-overwriting-output-image-3136d73d3650817884c2ce2ff5993b9e) by [Unito](https://www.unito.io)
Summary
Prevent latent previews received after the job/node has already finished processing overwriting the actual output display
Changes
Review Focus
Screenshots (if applicable)
┆Issue is synchronized with this Notion page by Unito