mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-10 22:20:14 +00:00
fix(studio): address PR #2347 review findings (rounds 1-2)
Review 1 (restore commit): - asset reveal now clears any open preview overlay (stuck-overlay repro: preview on A, click already-added B — A stayed open over the reveal) - duration readout rolls back on failed persist: captureDurationRollback snapshots store + live root data-duration before the optimistic sync and restores both in every move/resize/delete/group catch (golden's previousDuration pattern) - asset preview opened during running playback dismisses immediately (the RAF loop bypasses the store, so the subscription alone never fired) - persistTimelineBatchEdit resolves the target (findTagByTarget) before treating identical output as a no-op — a mistargeted member now throws like the single-element path instead of being silently dropped - a post-mutation history-fold failure no longer suppresses the preview sync: fold errors are surfaced separately and the rewritten script still syncs (previously the preview kept stale GSAP positions with no recovery) - timelineRevealScroll guards degenerate viewports (windowSize <= 0) - CodeQL: encodeURIComponent(projectId) at all timelineTimingSync fetches Review 2 (single-source-of-truth pass): - createTimelineElementFromManifestClip — the one manifest->element boundary — now carries authoredTrack and stackingContextId; expanded sub-comp children preserve both (authoredTrack in their OWN file's space) - authoredTrackForLane scopes occupants to the dragged clip's sourceFile (a foreign file's authored values are a different coordinate space); nearest-same-file-lane offset fallback - optimistic store updates mirror the persisted track into authoredTrack (and roll it back on failure), so consecutive drags before a reload resolve from fresh data - spill sub-lanes: documented decision — dropping onto a spill lane is a legitimate same-track join (occupants share the authored track by construction); false 'never a lane-move target' docstring rewritten - single-element fallback persists vertical-only moves (early return now requires neither start nor track changed; live DOM patch includes data-track-index) - canonical contextKey helper for stacking-context normalization - new pipeline test crosses the REAL factory boundary (sparse authored tracks -> factory -> expansion -> normalize -> drag commit -> persisted attribute), no injected fields
This commit is contained in:
@@ -13,6 +13,7 @@ import {
|
||||
type RecordEditInput,
|
||||
} from "./timelineEditingHelpers";
|
||||
import {
|
||||
captureDurationRollback,
|
||||
finishGroupTimingGsapFallback,
|
||||
readFileContent,
|
||||
scaleGsapPositions,
|
||||
@@ -223,6 +224,9 @@ export function useTimelineGroupEditing({
|
||||
}
|
||||
|
||||
const maxEnd = Math.max(...changes.map((change) => change.start + change.element.duration));
|
||||
// Snapshot the duration BEFORE the optimistic updates below so a failed
|
||||
// persist can roll the readout + live root back (see captureDurationRollback).
|
||||
const rollbackDuration = captureDurationRollback(previewIframeRef.current);
|
||||
// needsExtension gates the SDK path (setTiming can't grow the root duration),
|
||||
// so read the store BEFORE the readout sync below optimistically updates it.
|
||||
const needsExtension = extendRootDurationIfNeeded(maxEnd);
|
||||
@@ -276,6 +280,11 @@ export function useTimelineGroupEditing({
|
||||
return shiftGsapPositions(projectId, changePath, domId, delta);
|
||||
},
|
||||
});
|
||||
}).catch((error) => {
|
||||
// Failed persist: revert the optimistic duration readout + live root
|
||||
// alongside the gesture owner's store rollback.
|
||||
rollbackDuration();
|
||||
throw error;
|
||||
});
|
||||
},
|
||||
[
|
||||
@@ -308,6 +317,9 @@ export function useTimelineGroupEditing({
|
||||
}
|
||||
|
||||
const maxEnd = Math.max(...changes.map((change) => change.start + change.duration));
|
||||
// Snapshot the duration BEFORE the optimistic updates below so a failed
|
||||
// persist can roll the readout + live root back (see captureDurationRollback).
|
||||
const rollbackDuration = captureDurationRollback(previewIframeRef.current);
|
||||
// needsExtension gates the SDK path (setTiming can't grow the root duration),
|
||||
// so read the store BEFORE the readout sync below optimistically updates it.
|
||||
const needsExtension = extendRootDurationIfNeeded(maxEnd);
|
||||
@@ -371,6 +383,11 @@ export function useTimelineGroupEditing({
|
||||
);
|
||||
},
|
||||
});
|
||||
}).catch((error) => {
|
||||
// Failed persist: revert the optimistic duration readout + live root
|
||||
// alongside the gesture owner's store rollback.
|
||||
rollbackDuration();
|
||||
throw error;
|
||||
});
|
||||
},
|
||||
[
|
||||
|
||||
Reference in New Issue
Block a user