From 26008edd51b8b22595f891b88c64228f38cd46b9 Mon Sep 17 00:00:00 2001 From: webadderall <131426131+webadderall@users.noreply.github.com> Date: Sat, 5 Sep 2026 16:47:12 +1000 Subject: [PATCH] fix: address startup review regressions --- src/components/ui/sonner.tsx | 5 ++- src/components/video-editor/SettingsPanel.tsx | 9 ++++- src/components/video-editor/VideoEditor.tsx | 3 +- .../export/useExportDialogActions.ts | 6 ++- .../video-editor/export/useExportRunner.ts | 37 ++++++++++++------- .../video-editor/export/useExportSession.ts | 2 + 6 files changed, 43 insertions(+), 19 deletions(-) diff --git a/src/components/ui/sonner.tsx b/src/components/ui/sonner.tsx index fe1e3905..42ee8ac4 100644 --- a/src/components/ui/sonner.tsx +++ b/src/components/ui/sonner.tsx @@ -1,11 +1,12 @@ import { Toaster as Sonner } from "sonner"; +import { cn } from "@/lib/utils"; type ToasterProps = React.ComponentProps; -const Toaster = ({ ...props }: ToasterProps) => { +const Toaster = ({ className, ...props }: ToasterProps) => { return ( { - if (!isBackgroundPanel && activeEffectSection !== "scene") return; + if ( + !isBackgroundPanel && + activeEffectSection !== "scene" && + activeEffectSection !== "frame" && + activeEffectSection !== "crop" + ) { + return; + } let mounted = true; (async () => { diff --git a/src/components/video-editor/VideoEditor.tsx b/src/components/video-editor/VideoEditor.tsx index 84c973b4..883e8fc9 100644 --- a/src/components/video-editor/VideoEditor.tsx +++ b/src/components/video-editor/VideoEditor.tsx @@ -103,7 +103,7 @@ export default function VideoEditor() { setExportPipelineModel, } = exportSettings; const exportSession = useExportSession(); - const { exporterRef, pendingExportSaveRef } = exportSession; + const { exporterRef, exportRunIdRef, pendingExportSaveRef } = exportSession; const enableModernExportPipeline = useCallback(() => { setExportPipelineModel("modern"); }, []); @@ -165,6 +165,7 @@ export default function VideoEditor() { useEffect(() => { return () => { + exportRunIdRef.current += 1; exporterRef.current?.cancel(); exporterRef.current = null; const pending = pendingExportSaveRef.current; diff --git a/src/components/video-editor/export/useExportDialogActions.ts b/src/components/video-editor/export/useExportDialogActions.ts index 87de829a..02cc8c25 100644 --- a/src/components/video-editor/export/useExportDialogActions.ts +++ b/src/components/video-editor/export/useExportDialogActions.ts @@ -83,8 +83,10 @@ export function useExportDialogActions({ }, [videoPath, videoPlaybackRef, hasCaptionsForSidecar, settings, session, handleExport]); const handleCancelExport = useCallback(() => { - if (!session.exporterRef.current) return; - session.exporterRef.current.cancel(); + if (!session.isExporting) return; + session.exportRunIdRef.current += 1; + session.exporterRef.current?.cancel(); + session.exporterRef.current = null; toast.info("Export canceled"); session.clearPendingExportSave(); session.setShowExportDropdown(false); diff --git a/src/components/video-editor/export/useExportRunner.ts b/src/components/video-editor/export/useExportRunner.ts index 0472f921..f36e70b5 100644 --- a/src/components/video-editor/export/useExportRunner.ts +++ b/src/components/video-editor/export/useExportRunner.ts @@ -66,6 +66,7 @@ export function useExportRunner(input: ExportRunnerInput) { pendingExportSaveRef, clearPendingExportSave, markExportAsSaving, + exportRunIdRef, } = exportSession; if (!videoPath) { toast.error("No video loaded"); @@ -78,6 +79,10 @@ export function useExportRunner(input: ExportRunnerInput) { return; } + const exportRunId = exportRunIdRef.current + 1; + exportRunIdRef.current = exportRunId; + const exportWasCancelled = () => exportRunIdRef.current !== exportRunId; + setIsExporting(true); setExportProgress(null); setExportError(null); @@ -112,6 +117,7 @@ export function useExportRunner(input: ExportRunnerInput) { if (settings.format === "gif" && settings.gifConfig) { // GIF Export const { GifExporter } = await import("@/lib/exporter/gifExporter"); + if (exportWasCancelled()) return; const gifExporter = new GifExporter({ videoUrl: videoPath, width: settings.gifConfig.width, @@ -141,6 +147,7 @@ export function useExportRunner(input: ExportRunnerInput) { exporterRef.current = gifExporter; const result = await gifExporter.export(); + if (exportWasCancelled()) return; if (result.success && result.blob) { const timestamp = Date.now(); @@ -224,6 +231,7 @@ export function useExportRunner(input: ExportRunnerInput) { }); const supportedSourceDimensions = await ensureSupportedMp4SourceDimensions(selectedMp4FrameRate); + if (exportWasCancelled()) return; const { width: exportWidth, height: exportHeight } = calculateMp4ExportDimensions( supportedSourceDimensions.width, @@ -281,20 +289,20 @@ export function useExportRunner(input: ExportRunnerInput) { sourceAudioTrackSettings: sourceAudioTrackSettingsForExport, }; + const Exporter = + pipelineModel === "modern" + ? (await import("@/lib/exporter/modernVideoExporter")) + .ModernVideoExporter + : (await import("@/lib/exporter/videoExporter")).VideoExporter; + if (exportWasCancelled()) return; const exporter = pipelineModel === "modern" - ? new ( - await import("@/lib/exporter/modernVideoExporter") - ).ModernVideoExporter({ - ...exporterConfig, - backendPreference, - }) - : new (await import("@/lib/exporter/videoExporter")).VideoExporter( - exporterConfig, - ); + ? new Exporter({ ...exporterConfig, backendPreference }) + : new Exporter(exporterConfig); exporterRef.current = exporter; const result = await exporter.export(); + if (exportWasCancelled()) return; const smokeExportElapsedMs = smokeExportStartedAt !== null ? Math.round(performance.now() - smokeExportStartedAt) @@ -466,6 +474,7 @@ export function useExportRunner(input: ExportRunnerInput) { video.currentTime = restoreTime; } } catch (error) { + if (exportWasCancelled()) return; console.error("Export error:", error); const errorMessage = error instanceof Error ? error.message : "Unknown error"; if (smokeExportConfig.enabled) { @@ -487,10 +496,12 @@ export function useExportRunner(input: ExportRunnerInput) { window.close(); } } finally { - setIsExporting(false); - exporterRef.current = null; - setShowExportDropdown(keepExportDialogOpen); - remountPreview(); + if (!exportWasCancelled()) { + setIsExporting(false); + exporterRef.current = null; + setShowExportDropdown(keepExportDialogOpen); + remountPreview(); + } } }, [showExportSuccessToast], diff --git a/src/components/video-editor/export/useExportSession.ts b/src/components/video-editor/export/useExportSession.ts index b9c92d4e..a922c049 100644 --- a/src/components/video-editor/export/useExportSession.ts +++ b/src/components/video-editor/export/useExportSession.ts @@ -13,6 +13,7 @@ export function useExportSession() { const [exportedFilePath, setExportedFilePath] = useState(); const [hasPendingExportSave, setHasPendingExportSave] = useState(false); const exporterRef = useRef(null); + const exportRunIdRef = useRef(0); const pendingExportSaveRef = useRef(null); const clearPendingExportSave = useCallback(() => { @@ -42,6 +43,7 @@ export function useExportSession() { hasPendingExportSave, setHasPendingExportSave, exporterRef, + exportRunIdRef, pendingExportSaveRef, clearPendingExportSave, markExportAsSaving,