Skip to content

Commit 1c026d5

Browse files
committed
fix(files): address review — reserve on stale memo, clear dims on content swap
- onLoad guards on the memoized storedDimensions the render uses (not a fresh cache read), so a sibling's non-reactive backfill can't leave a view unreserved. - updateWorkspaceFileContent clears width/height when it swaps bytes, so stale dimensions can't be reserved for new content (and the null re-enables backfill). - Keep optimistically-cached dimensions when the PATCH fails (correct measurement; a 403/transient error shouldn't wipe sibling reservations). - Test imports the sibling via the absolute @/ path.
1 parent ba2bf7a commit 1c026d5

4 files changed

Lines changed: 20 additions & 13 deletions

File tree

apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/rich-markdown-editor/image.tsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -134,10 +134,11 @@ function ResizableImageView({ node, updateAttributes, selected, editor }: ReactN
134134
setFailed(false)
135135
const { naturalWidth, naturalHeight } = event.currentTarget
136136
if (naturalWidth <= 0 || naturalHeight <= 0) return
137-
// Already reserved from stored metadata (possibly just backfilled by a sibling view) — done.
138-
if (source.getImageDimensions?.(attrs.src)) return
139-
// Hold the box for this first-ever view, and persist so later views reserve before load. The
140-
// report is idempotent and de-duped downstream (stored-check + server `width IS NULL`).
137+
// Guard on the memoized `storedDimensions` the render actually uses — NOT a fresh cache read: the
138+
// memo is non-reactive, so a fresh read could see a sibling's backfill the render hasn't picked up
139+
// and skip measuring, leaving THIS view unreserved. When the render isn't reserving yet, hold the
140+
// box locally and persist (the report is idempotent, de-duped downstream).
141+
if (storedDimensions) return
141142
setMeasuredDimensions({ width: naturalWidth, height: naturalHeight })
142143
source.reportImageDimensions?.(attrs.src, { width: naturalWidth, height: naturalHeight })
143144
}}

apps/sim/hooks/queries/utils/find-workspace-file-by-src.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*/
44
import { describe, expect, it } from 'vitest'
55
import type { WorkspaceFileRecord } from '@/lib/uploads/contexts/workspace'
6-
import { findWorkspaceFileBySrc } from './find-workspace-file-by-src'
6+
import { findWorkspaceFileBySrc } from '@/hooks/queries/utils/find-workspace-file-by-src'
77

88
function record(over: Partial<WorkspaceFileRecord>): WorkspaceFileRecord {
99
return { id: 'wf_x', key: 'workspace/ws1/x.png', ...over } as WorkspaceFileRecord

apps/sim/hooks/queries/workspace-files.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -151,17 +151,18 @@ export function useWorkspaceImageDimensionsAdapter(workspaceId: string): ImageDi
151151
const record = findRecord(src)
152152
// Skip when the file isn't ours to key (external/unlisted) or its dimensions are already stored.
153153
if (!record || (record.width != null && record.height != null)) return
154-
const patch = (width: number | null, height: number | null) =>
155-
queryClient.setQueryData<WorkspaceFileRecord[]>(listKey, (previous) =>
156-
previous?.map((entry) => (entry.id === record.id ? { ...entry, width, height } : entry))
157-
)
158-
// Optimistically populate the cache so this and sibling views reserve space immediately and a
159-
// concurrent measurement of the same file short-circuits above.
160-
patch(dimensions.width, dimensions.height)
154+
// Populate the cache so this and sibling views reserve space immediately and a concurrent
155+
// measurement of the same file short-circuits above. Kept even if the PATCH fails (a 403 for a
156+
// read-only member, or a transient error): the measurement is the real image size, correct
157+
// regardless of whether the write landed, so siblings should still reserve from it — a later list
158+
// refetch reconciles with the server.
159+
queryClient.setQueryData<WorkspaceFileRecord[]>(listKey, (previous) =>
160+
previous?.map((entry) => (entry.id === record.id ? { ...entry, ...dimensions } : entry))
161+
)
161162
void requestJson(updateWorkspaceFileDimensionsContract, {
162163
params: { id: workspaceId, fileId: record.id },
163164
body: dimensions,
164-
}).catch(() => patch(null, null))
165+
}).catch(() => {})
165166
},
166167
}
167168
}, [queryClient, workspaceId])

apps/sim/lib/uploads/contexts/workspace/workspace-file-manager.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1312,6 +1312,11 @@ export async function updateWorkspaceFileContent(
13121312
key: uploadResult.key,
13131313
size: content.length,
13141314
contentType: nextContentType,
1315+
// Content is being replaced, so any stored intrinsic dimensions no longer describe it. Clear
1316+
// them (they re-backfill on next view via the `width IS NULL` path) so the editor never
1317+
// reserves a stale aspect ratio for the new bytes.
1318+
width: null,
1319+
height: null,
13151320
updatedAt: now,
13161321
contentUpdatedAt,
13171322
})

0 commit comments

Comments
 (0)