diff --git a/src/pages/AdminPage.jsx b/src/pages/AdminPage.jsx index c3e5c1a..babe249 100644 --- a/src/pages/AdminPage.jsx +++ b/src/pages/AdminPage.jsx @@ -61,6 +61,12 @@ export function AdminPage() { // sent something while you were looking at a different screen. A failed poll // is swallowed: a transient network blip must not replace the panel with an // error, and the next tick retries. + // + // Expect a steady zero on a deployment running UPLOAD_AUTORUN=true: uploads + // go straight into the pipeline and never wait for review, so there is + // nothing to be notified about. The badge renders only above zero, so that + // reads as "nothing to do" rather than as a broken counter, and the poll + // stays because the setting can be turned off without a redeploy. useEffect(() => { let alive = true; const check = async () => { diff --git a/src/pages/OrchestrationPanel.jsx b/src/pages/OrchestrationPanel.jsx index 9417600..5c04ea1 100644 --- a/src/pages/OrchestrationPanel.jsx +++ b/src/pages/OrchestrationPanel.jsx @@ -81,6 +81,7 @@ function fmtSecs(from, to) { export function OrchestrationPanel() { const [inbox, setInbox] = useState(null); + const [recent, setRecent] = useState([]); const [selected, setSelected] = useState(() => new Set()); const [batch, setBatch] = useState(null); const [busy, setBusy] = useState(''); @@ -104,9 +105,34 @@ export function OrchestrationPanel() { } }; + // Runs that started without anyone here pressing anything. + // + // UPLOAD_AUTORUN sends a colleague's upload straight into the pipeline, so + // the inbox it used to wait in is empty and the run has an id this screen was + // never told. Without this list an auto-started batch is invisible: its + // eleven stages are recorded and served, and nothing renders them. Slim + // responses, so twenty of these do not carry twenty product manifests. + const loadRecent = async () => { + try { + const { batches } = await api.listCatalogBatches(20); + setRecent(batches || []); + } catch { + /* the inbox call surfaces auth/network trouble; one banner is enough */ + } + }; + + const watch = (run) => { + setBatch(run); + batchIdRef.current = TERMINAL.has(run.status) ? null : run.batch_id; + }; + useEffect(() => { loadInbox(); - const timer = setInterval(loadInbox, INBOX_POLL_MS); + loadRecent(); + const timer = setInterval(() => { + loadInbox(); + loadRecent(); + }, INBOX_POLL_MS); return () => clearInterval(timer); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); @@ -210,10 +236,12 @@ export function OrchestrationPanel() { Dagster Orchestration

- Spreadsheets sent in by a colleague through the upload API. Tick the files you - want and press Start selected to send them through the 11-stage - pipeline as one batch, run by Dagster instead of this server's own worker. - Every stage each file passes through is recorded below and kept after the run + Spreadsheets sent in by a colleague through the upload API. Those uploads now + start on their own — pick one under Recent runs to follow + its stages. Anything still waiting for a decision appears below, where you can + tick files and press Start selected to send them through the + 11-stage pipeline as one batch, run by Dagster instead of this server's own + worker. Every stage each file passes through is recorded and kept after the run finishes.

@@ -286,13 +314,71 @@ export function OrchestrationPanel() { )} + {/* ---- runs that started without anyone pressing anything -------- */} + {recent.length > 0 && ( +
+

Recent runs

+

+ Uploads start on arrival, so this is where a colleague's files show up. + Pick one to see its eleven stages. +

+ +
+ )} + {/* ---- the drops waiting to be started --------------------------- */} {inbox && submissions.length === 0 && !batch && (

- Nothing waiting. Files sent to /api/uploads/catalog{' '} - appear here to be orchestrated. + Nothing waiting for review — files sent to{' '} + /api/uploads/catalog start on their own and + appear under Recent runs. +

+

+ Set UPLOAD_AUTORUN=false to hold them here for + a decision instead.

)}