Skip to content

Commit 5d7714f

Browse files
committed
fix(editors): preserve media during external reloads
A take or rendered clip could complete after an external reload began and before its response applied, losing the new media. Re-check document dirtiness after the fetch and merge when it changed.
1 parent b0123af commit 5d7714f

2 files changed

Lines changed: 36 additions & 7 deletions

File tree

web/src/hooks/script/useScriptServerSync.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -584,7 +584,23 @@ export const useScriptServerSync = (
584584
isDirty: () =>
585585
(store.getState().scripts[scriptId] ?? null) !== syncedRef.current,
586586
reload: () => {
587-
void load("reloaded");
587+
void (async () => {
588+
try {
589+
const response = await trpcClient.scripts.get.query({ id: scriptId });
590+
if (disposed) return;
591+
// A take may complete while the clean-editor reload is in flight.
592+
// Merge that new draft with the external response instead of
593+
// applying the response over the take.
594+
if (isDirty()) {
595+
await mergeExternal({ updatedAt: response.updatedAt }, response);
596+
return;
597+
}
598+
applyResponse(response, "reloaded");
599+
} catch (error) {
600+
console.error("Failed to reload script", error);
601+
store.getState().setSaveStatus(scriptId, "error");
602+
}
603+
})();
588604
},
589605
merge: (notice) => {
590606
// A save in flight makes the notice ambiguous: it may be that save's

web/src/hooks/timeline/useTimelineExternalSync.ts

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,10 @@
1414
*/
1515
import { useEffect } from "react";
1616

17-
import { registerDocumentSync } from "../../stores/documentSync";
17+
import {
18+
handleDocumentResourceChange,
19+
registerDocumentSync
20+
} from "../../stores/documentSync";
1821
import {
1922
isOlderUpdatedAt,
2023
timelineTemporalOf,
@@ -185,11 +188,21 @@ export function useTimelineExternalSync(sequenceId: string | null): void {
185188
isDirty: () => isTimelineDocumentDirty(sequenceId),
186189
reload: () => {
187190
void (async () => {
188-
adopt(
189-
await trpcClient.timeline.get.query({
190-
id: sequenceId
191-
})
192-
);
191+
const sequence = await trpcClient.timeline.get.query({
192+
id: sequenceId
193+
});
194+
// A render may finish while this clean-editor reload is in flight.
195+
// Re-route the already-observed external change so the dirty path
196+
// merges it with the completed render rather than overwriting it.
197+
if (isTimelineDocumentDirty(sequenceId)) {
198+
handleDocumentResourceChange("timelinesequence", {
199+
event: "updated",
200+
id: sequenceId,
201+
updatedAt: sequence.updatedAt
202+
});
203+
return;
204+
}
205+
adopt(sequence);
193206
})();
194207
},
195208
merge: (notice) => {

0 commit comments

Comments
 (0)