diff --git a/services/web-ui/public/screens-asset.jsx b/services/web-ui/public/screens-asset.jsx index 833dfd7..c963341 100644 --- a/services/web-ui/public/screens-asset.jsx +++ b/services/web-ui/public/screens-asset.jsx @@ -37,6 +37,7 @@ function AssetDetail({ asset, onClose }) { const [reprocessing, setReprocessing] = React.useState(null); // 'proxy' | 'thumbnail' | null const [filmFrames, setFilmFrames] = React.useState([]); const [filmstripLoading, setFilmstripLoading] = React.useState(false); + const [filmstripKey, setFilmstripKey] = React.useState(0); const videoRef = React.useRef(null); const assetId = asset && asset.id; @@ -164,7 +165,7 @@ function AssetDetail({ asset, onClose }) { }; build(); return function() { cancelled = true; }; - }, [streamUrl, streamType, totalMs]); + }, [streamUrl, streamType, totalMs, filmstripKey]); // Fake playback timer — only used when no real video stream React.useEffect(() => { @@ -491,7 +492,18 @@ function AssetDetail({ asset, onClose }) { )} {totalMs > 0 && ( - + )} @@ -499,8 +511,8 @@ function AssetDetail({ asset, onClose }) { - + + + )} ); } @@ -696,10 +751,122 @@ function CommentComposer({ asset, currentMs, value, onChange, onSubmit }) { ); } -function VersionsTab() { +function FilesTab({ asset, filmFrames, filmstripLoading, streamUrl, reprocessing, onRegenProxy, onRegenThumbnail, onRegenFilmstrip }) { + const hasProxy = !!asset.proxy_s3_key; + const hasHires = !!asset.original_s3_key; + const hasThumb = !!asset.thumbnail_s3_key; + const hasFilmstrip = Array.isArray(filmFrames) && filmFrames.length > 0; + + // Rows: label | status badge | path | action button + const FileRow = function({ label, present, path, icon, actionLabel, onAction, disabled, children }) { + return ( +
+
+ +
+
+ {label} + {present + ? ready + : missing} +
+ {path && ( +
+ {path} +
+ )} +
+ {actionLabel && onAction && ( + + )} +
+ {children &&
{children}
} +
+ ); + }; + return ( -
- Version history not yet available. +
+ + {/* Proxy */} + + {streamUrl && ( + + + {/* Hi-res */} + + + {/* Thumbnail */} + + {hasThumb && ( + Thumbnail + )} + + + {/* Filmstrip */} + + {hasFilmstrip && ( +
+ {filmFrames.filter(Boolean).slice(0, 14).map(function(src, i) { + return ( + + ); + })} +
+ )} + {filmstripLoading && ( +
Building filmstrip from proxy…
+ )} +
+
); }