10 lines
74 KiB
Text
10 lines
74 KiB
Text
|
|
{"parentUuid":null,"isSidechain":true,"promptId":"a1e2ae2f-8095-470a-adc9-743a67df8a3c","agentId":"a87b754c5272f9709","type":"user","message":{"role":"user","content":"Use the Forgejo MCP tool (mcp__claude_ai_mcp-server__forgejo_forgejo_get_file) to fetch these files from repo `zgaetano/wild-dragon`, branch `main`, and return their FULL content verbatim:\n\n1. services/web-ui/public/screens-library.jsx\n2. services/web-ui/public/screens-ingest.jsx\n3. services/web-ui/public/screens-jobs.jsx\n\nReturn each file's full content. I need to see every line."},"uuid":"711ce295-2e26-49d8-a344-e2034a5e7734","timestamp":"2026-05-22T13:53:27.664Z","userType":"external","entrypoint":"sdk-ts","cwd":"/home/node","sessionId":"822a2121-d8ec-424f-ace5-d65e0b717cb0","version":"2.1.129","gitBranch":"HEAD","slug":"velvet-chasing-karp"}
|
||
|
|
{"parentUuid":"711ce295-2e26-49d8-a344-e2034a5e7734","isSidechain":true,"agentId":"a87b754c5272f9709","message":{"model":"claude-haiku-4-5-20251001","id":"msg_01FMjvuAsetfL6GTjqvhiRzw","type":"message","role":"assistant","content":[{"type":"text","text":"I'll fetch those three files from the Forgejo repository for you."}],"stop_reason":null,"stop_sequence":null,"stop_details":null,"usage":{"input_tokens":3,"cache_creation_input_tokens":545,"cache_read_input_tokens":100370,"cache_creation":{"ephemeral_5m_input_tokens":545,"ephemeral_1h_input_tokens":0},"output_tokens":3,"service_tier":"standard","inference_geo":"not_available"},"diagnostics":null},"requestId":"req_011CbHifYVxxDLQzp8jATVrV","attributionAgent":"Explore","type":"assistant","uuid":"c95df8e9-3b0b-485d-bb66-7b32a8854cbc","timestamp":"2026-05-22T13:53:29.376Z","userType":"external","entrypoint":"sdk-ts","cwd":"/home/node","sessionId":"822a2121-d8ec-424f-ace5-d65e0b717cb0","version":"2.1.129","gitBranch":"HEAD","slug":"velvet-chasing-karp"}
|
||
|
|
{"parentUuid":"c95df8e9-3b0b-485d-bb66-7b32a8854cbc","isSidechain":true,"agentId":"a87b754c5272f9709","message":{"model":"claude-haiku-4-5-20251001","id":"msg_01FMjvuAsetfL6GTjqvhiRzw","type":"message","role":"assistant","content":[{"type":"tool_use","id":"toolu_01VEeFmf9hw44ed1YEHkoeAF","name":"mcp__claude_ai_mcp-server__forgejo_forgejo_get_file","input":{"owner":"zgaetano","repo":"wild-dragon","path":"services/web-ui/public/screens-library.jsx","ref":"main"},"caller":{"type":"direct"}}],"stop_reason":null,"stop_sequence":null,"stop_details":null,"usage":{"input_tokens":3,"cache_creation_input_tokens":545,"cache_read_input_tokens":100370,"cache_creation":{"ephemeral_5m_input_tokens":545,"ephemeral_1h_input_tokens":0},"output_tokens":3,"service_tier":"standard","inference_geo":"not_available"},"diagnostics":null},"requestId":"req_011CbHifYVxxDLQzp8jATVrV","attributionAgent":"Explore","type":"assistant","uuid":"60400bc7-3fbc-4da4-adad-f345bb770393","timestamp":"2026-05-22T13:53:29.760Z","userType":"external","entrypoint":"sdk-ts","cwd":"/home/node","sessionId":"822a2121-d8ec-424f-ace5-d65e0b717cb0","version":"2.1.129","gitBranch":"HEAD","slug":"velvet-chasing-karp"}
|
||
|
|
{"parentUuid":"60400bc7-3fbc-4da4-adad-f345bb770393","isSidechain":true,"agentId":"a87b754c5272f9709","message":{"model":"claude-haiku-4-5-20251001","id":"msg_01FMjvuAsetfL6GTjqvhiRzw","type":"message","role":"assistant","content":[{"type":"tool_use","id":"toolu_01EY3gPE1aYJDvqiKvYTNphp","name":"mcp__claude_ai_mcp-server__forgejo_forgejo_get_file","input":{"owner":"zgaetano","repo":"wild-dragon","path":"services/web-ui/public/screens-ingest.jsx","ref":"main"},"caller":{"type":"direct"}}],"stop_reason":null,"stop_sequence":null,"stop_details":null,"usage":{"input_tokens":3,"cache_creation_input_tokens":545,"cache_read_input_tokens":100370,"cache_creation":{"ephemeral_5m_input_tokens":545,"ephemeral_1h_input_tokens":0},"output_tokens":3,"service_tier":"standard","inference_geo":"not_available"},"diagnostics":null},"requestId":"req_011CbHifYVxxDLQzp8jATVrV","attributionAgent":"Explore","type":"assistant","uuid":"36852e55-146e-4d07-89dd-56fc1f5aee2e","timestamp":"2026-05-22T13:53:29.975Z","userType":"external","entrypoint":"sdk-ts","cwd":"/home/node","sessionId":"822a2121-d8ec-424f-ace5-d65e0b717cb0","version":"2.1.129","gitBranch":"HEAD","slug":"velvet-chasing-karp"}
|
||
|
|
{"parentUuid":"36852e55-146e-4d07-89dd-56fc1f5aee2e","isSidechain":true,"agentId":"a87b754c5272f9709","message":{"model":"claude-haiku-4-5-20251001","id":"msg_01FMjvuAsetfL6GTjqvhiRzw","type":"message","role":"assistant","content":[{"type":"tool_use","id":"toolu_016jiJucNqMjbfYBixqtjy65","name":"mcp__claude_ai_mcp-server__forgejo_forgejo_get_file","input":{"owner":"zgaetano","repo":"wild-dragon","path":"services/web-ui/public/screens-jobs.jsx","ref":"main"},"caller":{"type":"direct"}}],"stop_reason":"tool_use","stop_sequence":null,"stop_details":null,"usage":{"input_tokens":3,"cache_creation_input_tokens":545,"cache_read_input_tokens":100370,"output_tokens":400,"server_tool_use":{"web_search_requests":0,"web_fetch_requests":0},"service_tier":"standard","cache_creation":{"ephemeral_1h_input_tokens":0,"ephemeral_5m_input_tokens":545},"inference_geo":"","iterations":[{"input_tokens":3,"output_tokens":400,"cache_read_input_tokens":100370,"cache_creation_input_tokens":545,"cache_creation":{"ephemeral_5m_input_tokens":545,"ephemeral_1h_input_tokens":0},"type":"message"}],"speed":"standard"},"diagnostics":null},"requestId":"req_011CbHifYVxxDLQzp8jATVrV","attributionAgent":"Explore","type":"assistant","uuid":"a834b181-d002-41c7-b0e0-c4b93fd75d8e","timestamp":"2026-05-22T13:53:30.309Z","userType":"external","entrypoint":"sdk-ts","cwd":"/home/node","sessionId":"822a2121-d8ec-424f-ace5-d65e0b717cb0","version":"2.1.129","gitBranch":"HEAD","slug":"velvet-chasing-karp"}
|
||
|
|
{"parentUuid":"60400bc7-3fbc-4da4-adad-f345bb770393","isSidechain":true,"promptId":"a1e2ae2f-8095-470a-adc9-743a67df8a3c","agentId":"a87b754c5272f9709","type":"user","message":{"role":"user","content":[{"tool_use_id":"toolu_01VEeFmf9hw44ed1YEHkoeAF","type":"tool_result","content":"{\"result\":\"File: services/web-ui/public/screens-library.jsx\\n\\n// screens-library.jsx — library / asset grid + asset detail\\nconst { ASSETS: ALL_ASSETS, BINS, COMMENTS, PROJECTS } = window.ZAMPP_DATA;\\n\\nfunction Library({ navigate, onOpenAsset, project = \\\"Protour 2026\\\" }) {\\n const [bin, setBin] = React.useState(\\\"b1\\\");\\n const [view, setView] = React.useState(\\\"grid\\\");\\n const [filter, setFilter] = React.useState(\\\"all\\\");\\n const [search, setSearch] = React.useState(\\\"\\\");\\n\\n let assets = ALL_ASSETS;\\n if (filter !== \\\"all\\\") assets = assets.filter(a => a.status === filter);\\n if (search) assets = assets.filter(a => a.name.toLowerCase().includes(search.toLowerCase()));\\n\\n return (\\n <div className=\\\"library-layout\\\">\\n <aside className=\\\"library-rail\\\">\\n <div>\\n <h4>Projects</h4>\\n <div className=\\\"rail-list\\\">\\n {PROJECTS.slice(0, 6).map(p => (\\n <div key={p.id} className={`rail-item ${p.name === project ? \\\"active\\\" : \\\"\\\"}`}>\\n <span className=\\\"rail-color-dot\\\" style={{ background: p.color }} />\\n <span style={{ overflow: \\\"hidden\\\", textOverflow: \\\"ellipsis\\\", whiteSpace: \\\"nowrap\\\" }}>{p.name}</span>\\n <span className=\\\"rail-count\\\">{p.assets}</span>\\n </div>\\n ))}\\n </div>\\n </div>\\n <div>\\n <h4>Bins</h4>\\n <div className=\\\"rail-list\\\">\\n {BINS.map(b => (\\n <div key={b.id} className={`rail-item ${bin === b.id ? \\\"active\\\" : \\\"\\\"}`} onClick={() => setBin(b.id)}>\\n <Icon name={binIcon(b.icon)} size={13} className=\\\"rail-icon\\\" />\\n <span>{b.name}</span>\\n <span className=\\\"rail-count\\\">{b.count}</span>\\n </div>\\n ))}\\n </div>\\n </div>\\n <div>\\n <h4>Smart filters</h4>\\n <div className=\\\"rail-list\\\">\\n <div className=\\\"rail-item\\\"><Icon name=\\\"alert\\\" size={13} className=\\\"rail-icon\\\" /><span>Errors</span><span className=\\\"rail-count\\\">2</span></div>\\n <div className=\\\"rail-item\\\"><Icon name=\\\"clock\\\" size={13} className=\\\"rail-icon\\\" /><span>Last 24h</span><span className=\\\"rail-count\\\">38</span></div>\\n <div className=\\\"rail-item\\\"><Icon name=\\\"comment\\\" size={13} className=\\\"rail-icon\\\" /><span>With comments</span><span className=\\\"rail-count\\\">9</span></div>\\n <div className=\\\"rail-item\\\"><Icon name=\\\"check\\\" size={13} className=\\\"rail-icon\\\" /><span>Approved</span><span className=\\\"rail-count\\\">14</span></div>\\n </div>\\n </div>\\n </aside>\\n\\n <div className=\\\"library-main\\\">\\n <div className=\\\"library-toolbar\\\">\\n <div className=\\\"toolbar-title\\\">{project}</div>\\n <span className=\\\"count\\\">· {assets.length} assets</span>\\n <div style={{ flex: 1 }} />\\n <div className=\\\"search\\\" style={{ width: 220 }}>\\n <Icon name=\\\"search\\\" className=\\\"search-icon\\\" />\\n <input value={search} onChange={e => setSearch(e.target.value)} placeholder=\\\"Filter assets…\\\" />\\n </div>\\n <div className=\\\"tab-group\\\">\\n {[\\\"all\\\", \\\"ready\\\", \\\"processing\\\", \\\"live\\\", \\\"error\\\"].map(f => (\\n <button key={f} className={filter === f ? \\\"active\\\" : \\\"\\\"} onClick={() => setFilter(f)}>\\n {f === \\\"all\\\" ? \\\"All\\\" : f[0].toUpperCase() + f.slice(1)}\\n </button>\\n
|
||
|
|
{"parentUuid":"36852e55-146e-4d07-89dd-56fc1f5aee2e","isSidechain":true,"promptId":"a1e2ae2f-8095-470a-adc9-743a67df8a3c","agentId":"a87b754c5272f9709","type":"user","message":{"role":"user","content":[{"tool_use_id":"toolu_01EY3gPE1aYJDvqiKvYTNphp","type":"tool_result","content":"{\"result\":\"File: services/web-ui/public/screens-ingest.jsx\\n\\n// screens-ingest.jsx — Upload, Recorders, Capture (SDI), Monitors\\n\\nconst { RECORDERS, NODES, SDI_PORTS_zampp2, PROJECTS } = window.ZAMPP_DATA;\\n\\n/* ========== Upload ========== */\\nfunction Upload({ navigate }) {\\n const [files, setFiles] = React.useState([\\n { id: 1, name: \\\"Drone_Aerial_Lap_4.mov\\\", size: \\\"12.4 GB\\\", progress: 68, status: \\\"uploading\\\" },\\n { id: 2, name: \\\"Interview_Director.mxf\\\", size: \\\"2.1 GB\\\", progress: 100, status: \\\"done\\\" },\\n { id: 3, name: \\\"Sponsor_Logo_v4.mov\\\", size: \\\"120 MB\\\", progress: 100, status: \\\"done\\\" },\\n { id: 4, name: \\\"Pit_Cam_3.mp4\\\", size: \\\"4.8 GB\\\", progress: 24, status: \\\"uploading\\\" },\\n { id: 5, name: \\\"Backstage_Audio.wav\\\", size: \\\"920 MB\\\", progress: 0, status: \\\"queued\\\" },\\n ]);\\n\\n React.useEffect(() => {\\n const i = setInterval(() => {\\n setFiles(fs => fs.map(f => {\\n if (f.status !== \\\"uploading\\\") return f;\\n const next = f.progress + Math.random() * 4;\\n if (next >= 100) return { ...f, progress: 100, status: \\\"done\\\" };\\n return { ...f, progress: next };\\n }));\\n }, 600);\\n return () => clearInterval(i);\\n }, []);\\n\\n return (\\n <div className=\\\"page\\\">\\n <div className=\\\"page-header\\\">\\n <h1>Upload</h1>\\n <span className=\\\"subtitle\\\">Drop video, audio, or stills — we proxy and index automatically.</span>\\n </div>\\n <div className=\\\"page-body\\\">\\n <div style={{ display: \\\"grid\\\", gridTemplateColumns: \\\"1fr 1fr\\\", gap: 12, marginBottom: 20 }}>\\n <div>\\n <label className=\\\"field-label\\\">Project</label>\\n <div className=\\\"select-faux\\\"><span>Protour 2026</span><Icon name=\\\"chevronDown\\\" size={12} /></div>\\n </div>\\n <div>\\n <label className=\\\"field-label\\\">Bin</label>\\n <div className=\\\"select-faux\\\"><span>Master files</span><Icon name=\\\"chevronDown\\\" size={12} /></div>\\n </div>\\n </div>\\n\\n <div className=\\\"dropzone\\\">\\n <Icon name=\\\"upload\\\" size={32} style={{ color: \\\"var(--text-3)\\\" }} />\\n <div style={{ fontSize: 15, fontWeight: 500 }}>Drop files here or click to browse</div>\\n <div className=\\\"muted\\\" style={{ fontSize: 12.5 }}>Video, audio, and image files — up to 5 GB each</div>\\n <div className=\\\"dropzone-formats\\\">\\n {[\\\"MOV\\\", \\\"MP4\\\", \\\"MXF\\\", \\\"ProRes\\\", \\\"DNxHR\\\", \\\"WAV\\\", \\\"AIFF\\\"].map(f => <span key={f} className=\\\"badge outline\\\">{f}</span>)}\\n </div>\\n </div>\\n\\n <div style={{ marginTop: 24 }}>\\n <div style={{ fontSize: 13, fontWeight: 600, marginBottom: 12, display: \\\"flex\\\", alignItems: \\\"center\\\", gap: 8 }}>\\n Queue\\n <span className=\\\"badge neutral\\\">{files.length}</span>\\n <span style={{ flex: 1 }} />\\n <button className=\\\"btn ghost sm\\\">Pause all</button>\\n <button className=\\\"btn ghost sm\\\">Clear done</button>\\n </div>\\n <div className=\\\"panel\\\">\\n {files.map(f => (\\n <div key={f.id} className=\\\"upload-row\\\">\\n <Icon name={f.name.match(/\\\\.(wav|aif|mp3)$/i) ? \\\"audio\\\" : \\\"video\\\"} size={16} style={{ color: \\\"var(--text-3)\\\" }} />\\n <div style={{ flex: 1, minWidth: 0 }}>\\n <div style={{ display: \\\"flex\\\", gap: 8, alignItems: \\\"center\\\" }}>\\n <span style={{ fontWeight: 5
|
||
|
|
{"parentUuid":"a834b181-d002-41c7-b0e0-c4b93fd75d8e","isSidechain":true,"promptId":"a1e2ae2f-8095-470a-adc9-743a67df8a3c","agentId":"a87b754c5272f9709","type":"user","message":{"role":"user","content":[{"tool_use_id":"toolu_016jiJucNqMjbfYBixqtjy65","type":"tool_result","content":"{\"result\":\"File: services/web-ui/public/screens-jobs.jsx\\n\\n// screens-jobs.jsx — Jobs queue with real-time progress visualization\\n\\nconst { JOBS: ALL_JOBS } = window.ZAMPP_DATA;\\n\\nfunction Jobs({ navigate }) {\\n const [tab, setTab] = React.useState(\\\"all\\\");\\n const [jobs, setJobs] = React.useState(ALL_JOBS);\\n\\n React.useEffect(() => {\\n const i = setInterval(() => {\\n setJobs(js => js.map(j => {\\n if (j.status !== \\\"running\\\") return j;\\n const next = Math.min(100, j.progress + Math.random() * 3);\\n if (next >= 100) return { ...j, progress: 100, status: \\\"done\\\", eta: \\\"—\\\" };\\n const [m, s] = j.eta.split(\\\":\\\").map(Number);\\n const total = m * 60 + s - 1;\\n const newEta = total > 0 ? `${String(Math.floor(total / 60)).padStart(2, \\\"0\\\")}:${String(total % 60).padStart(2, \\\"0\\\")}` : \\\"00:00\\\";\\n return { ...j, progress: next, eta: newEta };\\n }));\\n }, 1200);\\n return () => clearInterval(i);\\n }, []);\\n\\n const counts = {\\n all: jobs.length,\\n running: jobs.filter(j => j.status === \\\"running\\\").length,\\n queued: jobs.filter(j => j.status === \\\"queued\\\").length,\\n done: jobs.filter(j => j.status === \\\"done\\\").length,\\n failed: jobs.filter(j => j.status === \\\"failed\\\").length,\\n };\\n const filtered = tab === \\\"all\\\" ? jobs : jobs.filter(j => j.status === tab);\\n\\n const throughput = [12, 14, 13, 16, 15, 18, 22, 24, 22, 28, 32, 38, 42, 40];\\n\\n return (\\n <div className=\\\"page\\\">\\n <div className=\\\"page-header\\\">\\n <h1>Jobs</h1>\\n <span className=\\\"subtitle\\\">Proxy generation, transcoding, AMPP sync — live across worker pool</span>\\n <div className=\\\"spacer\\\" />\\n <button className=\\\"btn ghost sm\\\"><Icon name=\\\"filter\\\" />Filter</button>\\n <button className=\\\"btn ghost sm\\\"><Icon name=\\\"refresh\\\" />Refresh</button>\\n </div>\\n\\n <div className=\\\"page-body\\\">\\n <div className=\\\"jobs-stats\\\">\\n <div className=\\\"stat-card\\\">\\n <div className=\\\"label\\\">Throughput</div>\\n <div className=\\\"value\\\">42<span style={{ fontSize: 14, color: \\\"var(--text-3)\\\", fontWeight: 400 }}> / min</span></div>\\n <div className=\\\"delta up\\\">+18% vs last hour</div>\\n <Sparkline data={throughput} color=\\\"#5B7CFA\\\" />\\n </div>\\n <div className=\\\"stat-card\\\">\\n <div className=\\\"label\\\">Avg duration</div>\\n <div className=\\\"value\\\">4.2<span style={{ fontSize: 14, color: \\\"var(--text-3)\\\", fontWeight: 400 }}> min</span></div>\\n <div className=\\\"delta\\\">Proxy: 6.1m · Transcode: 2.4m</div>\\n </div>\\n <div className=\\\"stat-card\\\">\\n <div className=\\\"label\\\">Worker pool</div>\\n <div className=\\\"value\\\">3<span style={{ fontSize: 14, color: \\\"var(--text-3)\\\", fontWeight: 400 }}> / 4 active</span></div>\\n <div className=\\\"delta\\\">GPU util: 67%</div>\\n </div>\\n <div className=\\\"stat-card\\\">\\n <div className=\\\"label\\\">Failed (24h)</div>\\n <div className=\\\"value\\\">{counts.failed}</div>\\n <div className=\\\"delta\\\" style={{ color: counts.failed > 0 ? \\\"var(--warning)\\\" : \\\"var(--text-3)\\\" }}>\\n {counts.failed > 0 ? \\\"1 needs attention\\\" : \\\"All good\\\"}\\n </div>\\n </div>\\n </div>\\n\\n <div className=\\\"tab-group\\\" style={{ marginTop: 20, width: \\\"fit-content\\\" }}>\\n {[\\n { id: \\\"all\\\", label: `A
|
||
|
|
{"parentUuid":"aa720ad4-372b-421b-987a-7d76973283e6","isSidechain":true,"agentId":"a87b754c5272f9709","message":{"model":"claude-haiku-4-5-20251001","id":"msg_016ePzNHpovTxS2TRC5cCwVB","type":"message","role":"assistant","content":[{"type":"text","text":"Here are the full contents of all three files:\n\n## 1. services/web-ui/public/screens-library.jsx\n\n```javascript\n// screens-library.jsx — library / asset grid + asset detail\nconst { ASSETS: ALL_ASSETS, BINS, COMMENTS, PROJECTS } = window.ZAMPP_DATA;\n\nfunction Library({ navigate, onOpenAsset, project = \"Protour 2026\" }) {\n const [bin, setBin] = React.useState(\"b1\");\n const [view, setView] = React.useState(\"grid\");\n const [filter, setFilter] = React.useState(\"all\");\n const [search, setSearch] = React.useState(\"\");\n\n let assets = ALL_ASSETS;\n if (filter !== \"all\") assets = assets.filter(a => a.status === filter);\n if (search) assets = assets.filter(a => a.name.toLowerCase().includes(search.toLowerCase()));\n\n return (\n <div className=\"library-layout\">\n <aside className=\"library-rail\">\n <div>\n <h4>Projects</h4>\n <div className=\"rail-list\">\n {PROJECTS.slice(0, 6).map(p => (\n <div key={p.id} className={`rail-item ${p.name === project ? \"active\" : \"\"}`}>\n <span className=\"rail-color-dot\" style={{ background: p.color }} />\n <span style={{ overflow: \"hidden\", textOverflow: \"ellipsis\", whiteSpace: \"nowrap\" }}>{p.name}</span>\n <span className=\"rail-count\">{p.assets}</span>\n </div>\n ))}\n </div>\n </div>\n <div>\n <h4>Bins</h4>\n <div className=\"rail-list\">\n {BINS.map(b => (\n <div key={b.id} className={`rail-item ${bin === b.id ? \"active\" : \"\"}`} onClick={() => setBin(b.id)}>\n <Icon name={binIcon(b.icon)} size={13} className=\"rail-icon\" />\n <span>{b.name}</span>\n <span className=\"rail-count\">{b.count}</span>\n </div>\n ))}\n </div>\n </div>\n <div>\n <h4>Smart filters</h4>\n <div className=\"rail-list\">\n <div className=\"rail-item\"><Icon name=\"alert\" size={13} className=\"rail-icon\" /><span>Errors</span><span className=\"rail-count\">2</span></div>\n <div className=\"rail-item\"><Icon name=\"clock\" size={13} className=\"rail-icon\" /><span>Last 24h</span><span className=\"rail-count\">38</span></div>\n <div className=\"rail-item\"><Icon name=\"comment\" size={13} className=\"rail-icon\" /><span>With comments</span><span className=\"rail-count\">9</span></div>\n <div className=\"rail-item\"><Icon name=\"check\" size={13} className=\"rail-icon\" /><span>Approved</span><span className=\"rail-count\">14</span></div>\n </div>\n </div>\n </aside>\n\n <div className=\"library-main\">\n <div className=\"library-toolbar\">\n <div className=\"toolbar-title\">{project}</div>\n <span className=\"count\">· {assets.length} assets</span>\n <div style={{ flex: 1 }} />\n <div className=\"search\" style={{ width: 220 }}>\n <Icon name=\"search\" className=\"search-icon\" />\n <input value={search} onChange={e => setSearch(e.target.value)} placeholder=\"Filter assets…\" />\n </div>\n <div className=\"tab-group\">\n {[\"all\", \"ready\", \"processing\", \"live\", \"error\"].map(f => (\n <button key={f} className={filter === f ? \"active\" : \"\"} onClick={() => setFilter(f)}>\n {f === \"all\" ? \"All\" : f[0].toUpperCase() + f.slice(1)}\n </button>\n ))}\n </div>\n <div className=\"tab-group\">\n <button className={view === \"grid\" ? \"active\" : \"\"} onClick={() => setView(\"grid\")} data-tip=\"Grid\"><Icon name=\"grid\" size={12} /></button>\n <button classNa
|