fix(studio): address PR review — restore rollback, fix probe race, harden edit suppression

Restore rollback path: enqueueEdit now returns the queued promise so
Promise.resolve(handler(...)).catch(rollback) in useTimelineClipDrag
fires correctly on save failure. Handlers return the promise chain.

Fix lost-update race in probe enrichment: use zustand's functional
setState so concurrent probe completions each read the latest state
atomically instead of all reading the same stale snapshot.

Harden file-change suppression: pendingTimelineEditPathRef is now a
Set<string> with exact-match lookup instead of single-slot + endsWith.
Multiple concurrent edits on different files are all suppressed correctly.

Remove dead canOffsetTrimClipStart function and its tests — no longer
called after the capability gate simplification.

Document runtime sync mechanism: added comment explaining that the
runtime re-reads data attributes on each sync tick (init.ts:1324-1368).

Fix comment wording in patchIframeDomTiming catch block.
This commit is contained in:
Miguel Ángel
2026-05-19 20:59:45 -04:00
parent beb807493c
commit 366fcc2a64
6 changed files with 39 additions and 85 deletions
@@ -30,7 +30,7 @@ interface UsePreviewPersistenceParams {
domEditSaveTimestampRef: React.MutableRefObject<number>;
/** Tracks in-flight timeline edits that patch the iframe DOM directly. File-change
* events for these paths are always suppressed since the preview is already up-to-date. */
pendingTimelineEditPathRef?: React.MutableRefObject<string | null>;
pendingTimelineEditPathRef?: React.MutableRefObject<Set<string>>;
/** Called to reload the preview after undo/redo or external file changes. */
reloadPreview: () => void;
}
@@ -167,9 +167,8 @@ export function usePreviewPersistence({
const changedPath = readStudioFileChangePath(payload);
if (!changedPath) return;
const recentDomEditSave = Date.now() - domEditSaveTimestampRef.current < 4000;
const pendingPath = pendingTimelineEditPathRef?.current;
if (pendingPath && changedPath.endsWith(pendingPath)) {
pendingTimelineEditPathRef!.current = null;
if (pendingTimelineEditPathRef?.current.has(changedPath)) {
pendingTimelineEditPathRef.current.delete(changedPath);
return;
}
if (!recentDomEditSave) {