Separate dataset upload queues

This commit is contained in:
2026-07-01 16:46:55 +08:00
parent 9fa64f355d
commit be397e0557
2 changed files with 45 additions and 9 deletions

View File

@@ -637,7 +637,7 @@ function App() {
const [selectedGpuIds, setSelectedGpuIds] = useState<number[]>([]);
const [selectedCondaEnv, setSelectedCondaEnv] = useState("auto");
const [uploadKind, setUploadKind] = useState<"images" | "masks">("images");
const [uploadFiles, setUploadFiles] = useState<FileList | null>(null);
const [uploadFilesByKind, setUploadFilesByKind] = useState<Record<"images" | "masks", FileList | null>>({ images: null, masks: null });
const [agentValidation, setAgentValidation] = useState<ValidationAgentPayload | null>(null);
const [weightVerification, setWeightVerification] = useState<WeightVerifyPayload | null>(null);
const [agentBusy, setAgentBusy] = useState(false);
@@ -761,6 +761,7 @@ function App() {
const uploadAccept = uploadKind === "images"
? "image/*,video/*,.zip,.tar,.tar.gz,.tgz"
: "image/*,.txt,.json,.yaml,.yml,.zip,.tar,.tar.gz,.tgz";
const activeUploadFiles = uploadFilesByKind[uploadKind];
const inferenceOutputs = useMemo(() => {
const predictions = results.filter((item) => item.role === "segmentation" && item.previewable).slice(0, 8);
const heatmaps = results.filter((item) => item.role === "heatmap" && item.previewable).slice(0, 8);
@@ -979,12 +980,13 @@ function App() {
}
async function uploadDatasetFiles() {
if (!uploadFiles || uploadFiles.length === 0) return;
const files = uploadFilesByKind[uploadKind];
if (!files || files.length === 0) return;
setBusy(true);
try {
setActionError("");
const body = new FormData();
Array.from(uploadFiles).forEach((file) => body.append("files", file));
Array.from(files).forEach((file) => body.append("files", file));
let res: Response;
try {
res = await fetch(`${API_BASE}/api/datasets/${encodeURIComponent(datasetName)}/upload/${uploadKind}`, {
@@ -997,7 +999,7 @@ function App() {
if (!res.ok) throw new Error(await res.text());
setSelectedDatasetName(datasetName);
setUploadModalOpen(false);
setUploadFiles(null);
setUploadFilesByKind((current) => ({ ...current, [uploadKind]: null }));
await refresh();
} catch (err) {
setActionError(String(err));
@@ -1528,7 +1530,7 @@ function App() {
<span></span>
<input value={datasetDescription} onChange={(event) => setDatasetDescription(event.target.value)} />
</label>
{datasetNameExists && <small className="formWarn"></small>}
{datasetNameExists && <small className="formWarn"> {uploadKind}</small>}
<div className="segmented">
{(["images", "masks"] as const).map((kind) => (
<button key={kind} type="button" className={uploadKind === kind ? "active" : ""} onClick={() => setUploadKind(kind)}>
@@ -1536,15 +1538,25 @@ function App() {
</button>
))}
</div>
<div className="uploadKindCounts">
<span className={uploadKind === "images" ? "active" : ""}>images {uploadFilesByKind.images?.length ?? 0}</span>
<span className={uploadKind === "masks" ? "active" : ""}>masks {uploadFilesByKind.masks?.length ?? 0}</span>
</div>
<label className="drop">
{uploadFiles?.length ? <PackageOpen size={24} /> : <UploadCloud size={24} />}
<span>{uploadFiles?.length ? `${uploadFiles.length} 个文件待上传` : `选择 ${uploadKind} 图片、视频或压缩包`}</span>
{activeUploadFiles?.length ? <PackageOpen size={24} /> : <UploadCloud size={24} />}
<span>{activeUploadFiles?.length ? `${activeUploadFiles.length} ${uploadKind} 文件待上传` : `选择 ${uploadKind} 图片、视频或压缩包`}</span>
<small>.png/.jpg/.tif/.mp4/.zip/.tar.gz </small>
<input multiple type="file" accept={uploadAccept} onChange={(event) => setUploadFiles(event.target.files)} />
<input
key={uploadKind}
multiple
type="file"
accept={uploadAccept}
onChange={(event) => setUploadFilesByKind((current) => ({ ...current, [uploadKind]: event.target.files }))}
/>
</label>
<div className="modalActions">
<button className="primary" disabled={busy || datasetNameExists} onClick={createDataset}><Boxes size={17} /></button>
<button className="primary secondary" disabled={busy || !uploadFiles?.length} onClick={uploadDatasetFiles}><UploadCloud size={17} /></button>
<button className="primary secondary" disabled={busy || !activeUploadFiles?.length} onClick={uploadDatasetFiles}><UploadCloud size={17} />{datasetNameExists ? "追加文件" : "上传文件"}</button>
</div>
</div>
</div>

View File

@@ -839,6 +839,30 @@ textarea {
font-weight: 760;
}
.uploadKindCounts {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 8px;
}
.uploadKindCounts span {
min-width: 0;
padding: 7px 9px;
border: 1px solid var(--line);
border-radius: 6px;
background: rgba(8, 10, 8, 0.72);
color: var(--muted);
font-size: 12px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.uploadKindCounts span.active {
border-color: rgba(157, 226, 111, 0.58);
color: var(--ink);
}
.drop {
min-height: 128px;
display: grid;