feat: deep-link Inspect Pipeline button — auto-expand and scroll to video
TechniquePage's 'Inspect pipeline' button passes ?video=<id> to AdminPipeline. Previously the query param was ignored. Now AdminPipeline reads it on mount, auto-expands the matching video row, and smooth-scrolls it into view.
This commit is contained in:
parent
4b0914b12b
commit
4151e7cd25
1 changed files with 22 additions and 2 deletions
|
|
@ -3,7 +3,8 @@
|
|||
* expandable event log with token usage and collapsible JSON viewer.
|
||||
*/
|
||||
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { useSearchParams } from "react-router-dom";
|
||||
import {
|
||||
fetchPipelineVideos,
|
||||
fetchPipelineEvents,
|
||||
|
|
@ -448,6 +449,7 @@ function StatusFilter({
|
|||
// ── Main Page ────────────────────────────────────────────────────────────────
|
||||
|
||||
export default function AdminPipeline() {
|
||||
const [searchParams] = useSearchParams();
|
||||
const [videos, setVideos] = useState<PipelineVideoItem[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
|
@ -456,6 +458,8 @@ export default function AdminPipeline() {
|
|||
const [actionMessage, setActionMessage] = useState<{ id: string; text: string; ok: boolean } | null>(null);
|
||||
const [activeFilter, setActiveFilter] = useState<string | null>(null);
|
||||
const [debugMode, setDebugModeState] = useState<boolean | null>(null);
|
||||
const videoRefs = useRef<Map<string, HTMLDivElement>>(new Map());
|
||||
const deepLinked = useRef(false);
|
||||
|
||||
const load = useCallback(async () => {
|
||||
setLoading(true);
|
||||
|
|
@ -474,6 +478,22 @@ export default function AdminPipeline() {
|
|||
void load();
|
||||
}, [load]);
|
||||
|
||||
// Deep-link: auto-expand and scroll to ?video=<id> on first load
|
||||
useEffect(() => {
|
||||
if (deepLinked.current || loading || videos.length === 0) return;
|
||||
const targetVideoId = searchParams.get("video");
|
||||
if (!targetVideoId) return;
|
||||
const match = videos.find((v) => v.id === targetVideoId);
|
||||
if (!match) return;
|
||||
deepLinked.current = true;
|
||||
setExpandedId(targetVideoId);
|
||||
// Scroll after the expanded detail renders
|
||||
requestAnimationFrame(() => {
|
||||
const el = videoRefs.current.get(targetVideoId);
|
||||
if (el) el.scrollIntoView({ behavior: "smooth", block: "start" });
|
||||
});
|
||||
}, [loading, videos, searchParams]);
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false;
|
||||
fetchDebugMode()
|
||||
|
|
@ -568,7 +588,7 @@ export default function AdminPipeline() {
|
|||
{videos
|
||||
.filter((v) => activeFilter === null || v.processing_status === activeFilter)
|
||||
.map((video) => (
|
||||
<div key={video.id} className="pipeline-video">
|
||||
<div key={video.id} className="pipeline-video" ref={(el) => { if (el) videoRefs.current.set(video.id, el); }}>
|
||||
<div
|
||||
className="pipeline-video__header"
|
||||
onClick={() => toggleExpand(video.id)}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue