mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-11-15 13:58:20 +00:00
fix(studio): a reload that names no files still reloads the whole film
Eight callers bump the preview reload directly. If one lands in the same render as a scene edit, the swap would have shown the scene and missed the other change. The reload counter moves into usePreviewReloadKey, whose plain setter always means the whole film.
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { useOwnPreviewIframe, usePreviewIframeStore } from "./player/store/previewIframeStore";
|
||||
import { notePreviewReload } from "./player/sceneRemount";
|
||||
import { usePreviewReloadKey } from "./player/sceneRemount";
|
||||
import { buildProjectApiPath } from "./utils/projectRouting";
|
||||
import { useState, useCallback, useRef, useMemo, useLayoutEffect } from "react";
|
||||
import { useDismissingTabSetter, useRightPanelIntent } from "./hooks/useRightPanelIntents";
|
||||
@@ -82,7 +82,7 @@ export function StudioApp({ readOnlyPreview = false, readOnlyPreviewReason }: St
|
||||
const [compIdToSrc, setCompIdToSrc] = useState<Map<string, string>>(new Map());
|
||||
const previewIframe = useOwnPreviewIframe();
|
||||
const [compositionLoading, setCompositionLoading] = useState(true);
|
||||
const [refreshKey, setRefreshKey] = useState(0);
|
||||
const { refreshKey, setRefreshKey, reloadPreview } = usePreviewReloadKey();
|
||||
const [previewDocumentVersion, refreshPreviewDocumentVersion] = usePreviewDocumentVersion();
|
||||
const [blockPreview, setBlockPreview] = useState<BlockPreviewInfo | null>(null);
|
||||
const previewIframeRef = useRef<HTMLIFrameElement | null>(null);
|
||||
@@ -107,10 +107,6 @@ export function StudioApp({ readOnlyPreview = false, readOnlyPreviewReason }: St
|
||||
const handleDomZIndexReorderCommitRef = useRef<TimelineZIndexReorderCommit | null>(null);
|
||||
const pendingTimelineEditPathRef = useRef(new Set<string>());
|
||||
const isGestureRecordingRef = useRef(false);
|
||||
const reloadPreview = useCallback((changedPaths?: readonly string[]) => {
|
||||
notePreviewReload(Array.isArray(changedPaths) ? changedPaths : undefined);
|
||||
setRefreshKey((k) => k + 1);
|
||||
}, []);
|
||||
const fileManager = useFileManager({
|
||||
projectId,
|
||||
showToast,
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
// @vitest-environment happy-dom
|
||||
import { act, createElement } from "react";
|
||||
import { createRoot } from "react-dom/client";
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import { notePreviewReload, takePreviewReloadPaths, usePreviewReloadKey } from "./sceneRemount";
|
||||
|
||||
globalThis.IS_REACT_ACT_ENVIRONMENT = true;
|
||||
|
||||
afterEach(() => void takePreviewReloadPaths());
|
||||
|
||||
describe("preview reload paths", () => {
|
||||
it("collects the scene files named before the reload runs", () => {
|
||||
notePreviewReload(["compositions/a.html"]);
|
||||
notePreviewReload(["compositions/b.html"]);
|
||||
expect(takePreviewReloadPaths()).toEqual(["compositions/a.html", "compositions/b.html"]);
|
||||
expect(takePreviewReloadPaths()).toBeNull();
|
||||
});
|
||||
|
||||
it("reloads the whole film when any reload in the same batch names no files", () => {
|
||||
notePreviewReload(["compositions/a.html"]);
|
||||
notePreviewReload();
|
||||
notePreviewReload(["compositions/b.html"]);
|
||||
expect(takePreviewReloadPaths()).toBeNull();
|
||||
});
|
||||
|
||||
it("usePreviewReloadKey: a plain setRefreshKey bump in the same batch turns a scene swap into a film reload", () => {
|
||||
let api: ReturnType<typeof usePreviewReloadKey> | null = null;
|
||||
const Probe = () => {
|
||||
api = usePreviewReloadKey();
|
||||
return null;
|
||||
};
|
||||
const root = createRoot(document.createElement("div"));
|
||||
act(() => root.render(createElement(Probe)));
|
||||
act(() => api!.reloadPreview(["compositions/a.html"]));
|
||||
expect(api!.refreshKey).toBe(1);
|
||||
expect(takePreviewReloadPaths()).toEqual(["compositions/a.html"]);
|
||||
act(() => {
|
||||
api!.reloadPreview(["compositions/a.html"]);
|
||||
api!.setRefreshKey((key) => key + 1);
|
||||
});
|
||||
expect(api!.refreshKey).toBe(3);
|
||||
expect(takePreviewReloadPaths()).toBeNull();
|
||||
act(() => root.unmount());
|
||||
});
|
||||
});
|
||||
@@ -1,3 +1,5 @@
|
||||
import { useCallback, useState, type SetStateAction } from "react";
|
||||
|
||||
// Which files the next preview reload is for. A reload with no paths reloads the whole film.
|
||||
let pendingPaths: Set<string> | "film" | null = null;
|
||||
|
||||
@@ -48,3 +50,20 @@ function resolveUrl(path: string, base: string): string | null {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The preview reload counter. `reloadPreview(paths)` names the scene files that changed; every other
|
||||
* bump, including `setRefreshKey`, reloads the whole film.
|
||||
*/
|
||||
export function usePreviewReloadKey() {
|
||||
const [refreshKey, setKey] = useState(0);
|
||||
const setRefreshKey = useCallback((update: SetStateAction<number>) => {
|
||||
notePreviewReload();
|
||||
setKey(update);
|
||||
}, []);
|
||||
const reloadPreview = useCallback((changedPaths?: readonly string[]) => {
|
||||
notePreviewReload(Array.isArray(changedPaths) ? changedPaths : undefined);
|
||||
setKey((key) => key + 1);
|
||||
}, []);
|
||||
return { refreshKey, setRefreshKey, reloadPreview };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user