File uploads external source
This commit is contained in:
@@ -1,9 +1,10 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Wrench, Database, UploadCloud, Layers } from 'lucide-react';
|
||||
import { Wrench, Database, UploadCloud, Layers, Inbox } from 'lucide-react';
|
||||
import { api } from '../api/client';
|
||||
import { NavigationHeader } from '../components/NavigationHeader';
|
||||
import { StoreCatalogPanel } from './StoreCatalogPanel';
|
||||
import { BatchCatalogPanel } from './BatchCatalogPanel';
|
||||
import { InboxPanel } from './InboxPanel';
|
||||
|
||||
/*
|
||||
* The admin panel carries two views: the read-only project overview, and the
|
||||
@@ -20,12 +21,22 @@ const TABS = [
|
||||
{ id: 'project', label: 'Project Overview Details', icon: Database },
|
||||
{ id: 'ingest', label: 'Store Catalog Ingestion', icon: UploadCloud },
|
||||
{ id: 'batch', label: 'Batch Catalog Ingestion', icon: Layers },
|
||||
{ id: 'inbox', label: 'Review Inbox', icon: Inbox },
|
||||
];
|
||||
|
||||
// How often the pending count is refreshed. Slower than the 3s a running batch
|
||||
// polls at, because this is a "has anything arrived?" question, not progress on
|
||||
// something already in flight - and it runs on whichever tab is open, so it is
|
||||
// the one poll in the app that never stops while the page is up.
|
||||
const INBOX_POLL_MS = 15000;
|
||||
|
||||
export function AdminPage() {
|
||||
const [activeTab, setActiveTab] = useState('project');
|
||||
const [projectDetails, setProjectDetails] = useState(null);
|
||||
const [loadingProject, setLoadingProject] = useState(true);
|
||||
const [pendingUploads, setPendingUploads] = useState(0);
|
||||
// Handed to BatchCatalogPanel when a run is started from the inbox.
|
||||
const [adoptedBatch, setAdoptedBatch] = useState(null);
|
||||
|
||||
const fetchProjectDetails = async () => {
|
||||
try {
|
||||
@@ -43,6 +54,29 @@ export function AdminPage() {
|
||||
fetchProjectDetails();
|
||||
}, []);
|
||||
|
||||
// The badge. Polled here rather than inside InboxPanel so the count is live
|
||||
// whichever tab is open - the whole point is finding out that a colleague
|
||||
// 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.
|
||||
useEffect(() => {
|
||||
let alive = true;
|
||||
const check = async () => {
|
||||
try {
|
||||
const { pending_count: count } = await api.listInbox();
|
||||
if (alive) setPendingUploads(count || 0);
|
||||
} catch {
|
||||
/* next tick retries */
|
||||
}
|
||||
};
|
||||
check();
|
||||
const timer = setInterval(check, INBOX_POLL_MS);
|
||||
return () => {
|
||||
alive = false;
|
||||
clearInterval(timer);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="flex h-screen w-full flex-col overflow-y-auto bg-paper-100 text-ink-950 font-sans">
|
||||
<NavigationHeader
|
||||
@@ -64,13 +98,34 @@ export function AdminPage() {
|
||||
}`}
|
||||
>
|
||||
<Icon className="h-4 w-4" /> {label}
|
||||
{id === 'inbox' && pendingUploads > 0 && (
|
||||
<span
|
||||
className={`ml-1 min-w-5 px-1.5 py-0.5 rounded-full text-[10px] font-extrabold leading-none ${
|
||||
activeTab === id
|
||||
? 'bg-slate-950 text-amber-400'
|
||||
: 'bg-amber-500 text-slate-950'
|
||||
}`}
|
||||
>
|
||||
{pendingUploads}
|
||||
</span>
|
||||
)}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{activeTab === 'ingest' && <StoreCatalogPanel />}
|
||||
|
||||
{activeTab === 'batch' && <BatchCatalogPanel />}
|
||||
{activeTab === 'batch' && <BatchCatalogPanel adoptBatch={adoptedBatch} />}
|
||||
|
||||
{activeTab === 'inbox' && (
|
||||
<InboxPanel
|
||||
onBatchStarted={(batch) => {
|
||||
setAdoptedBatch(batch);
|
||||
setActiveTab('batch');
|
||||
setPendingUploads((n) => Math.max(0, n - batch.files_total));
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
{activeTab === 'project' && (
|
||||
<div className="space-y-6">
|
||||
|
||||
Reference in New Issue
Block a user