Surface post-import verification results in the Studio
After a batch import the progress panel now shows a verification summary (offer_id fixed, furnidata ids fixed / missing / conflicts, nitros and icons synced, folders chowned). Single imports include the key counts in the success toast.
This commit is contained in:
1 parent
b4968a9967
commit
635abfbc9f
3 files changed
+105
-3
No files matched your search
@@ -1,10 +1,36 @@
|
||||
"use client";
|
||||
|
||||
import { Ban, Check, Loader2, X } from "lucide-react";
|
||||
import { Ban, Check, Loader2, ShieldCheck, X } from "lucide-react";
|
||||
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { cn } from "@/lib/utils";
|
||||
import type { BatchItemStatus } from "./studio-types";
|
||||
import type { BatchItemStatus, VerificationSummary } from "./studio-types";
|
||||
|
||||
function SummaryRow({
|
||||
label,
|
||||
value,
|
||||
tone,
|
||||
}: {
|
||||
label: string;
|
||||
value: string | number;
|
||||
tone?: "ok" | "warn";
|
||||
}) {
|
||||
return (
|
||||
<div className="flex items-center justify-between gap-2 text-xs">
|
||||
<span className="text-[var(--admin-text-muted)]">{label}</span>
|
||||
<span
|
||||
className={cn(
|
||||
"font-mono font-semibold",
|
||||
tone === "warn"
|
||||
? "text-[var(--admin-warning)]"
|
||||
: "text-[var(--admin-success)]",
|
||||
)}
|
||||
>
|
||||
{value}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function BatchProgress({
|
||||
progress,
|
||||
@@ -12,6 +38,7 @@ export function BatchProgress({
|
||||
succeeded,
|
||||
failed,
|
||||
cancelling,
|
||||
verification,
|
||||
onCancel,
|
||||
onDismiss,
|
||||
}: {
|
||||
@@ -20,6 +47,7 @@ export function BatchProgress({
|
||||
succeeded: number;
|
||||
failed: number;
|
||||
cancelling?: boolean;
|
||||
verification?: VerificationSummary | null;
|
||||
onCancel?: () => void;
|
||||
onDismiss?: () => void;
|
||||
}) {
|
||||
@@ -96,6 +124,45 @@ export function BatchProgress({
|
||||
))}
|
||||
</div>
|
||||
|
||||
{done && verification && (
|
||||
<div className="mt-2 space-y-1.5 rounded-lg border border-[var(--admin-border)] bg-[var(--admin-canvas)] p-2.5">
|
||||
<div className="flex items-center gap-1.5 text-xs font-bold uppercase tracking-wider text-[var(--admin-text-muted)]">
|
||||
<ShieldCheck size={13} className="text-[var(--admin-success)]" />
|
||||
Post-import verification
|
||||
</div>
|
||||
<SummaryRow
|
||||
label="Catalog offer_id fixed"
|
||||
value={verification.offerIdsFixed}
|
||||
/>
|
||||
<SummaryRow
|
||||
label="Furnidata ids fixed"
|
||||
value={verification.furniDataFixedIds}
|
||||
/>
|
||||
<SummaryRow
|
||||
label="Furnidata entries missing"
|
||||
value={verification.furniDataMissing}
|
||||
tone={verification.furniDataMissing > 0 ? "warn" : "ok"}
|
||||
/>
|
||||
<SummaryRow
|
||||
label="Furnidata id conflicts"
|
||||
value={verification.furniDataConflicts}
|
||||
tone={verification.furniDataConflicts > 0 ? "warn" : "ok"}
|
||||
/>
|
||||
<SummaryRow
|
||||
label="Nitros synced"
|
||||
value={verification.nitrosSynced.length}
|
||||
/>
|
||||
<SummaryRow
|
||||
label="Icons synced"
|
||||
value={verification.iconsSynced.length}
|
||||
/>
|
||||
<SummaryRow
|
||||
label="Folders chowned"
|
||||
value={verification.ownershipFixed.length}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="mt-2 flex justify-end gap-2">
|
||||
{done ? (
|
||||
<Button size="sm" variant="secondary" onClick={onDismiss}>
|
||||
|
||||
@@ -64,6 +64,7 @@ import type {
|
||||
FurniItem,
|
||||
FurniStats,
|
||||
Meta,
|
||||
VerificationSummary,
|
||||
} from "./studio-types";
|
||||
|
||||
export function StudioClient({
|
||||
@@ -119,6 +120,9 @@ export function StudioClient({
|
||||
const [batchSucceeded, setBatchSucceeded] = useState(0);
|
||||
const [batchFailed, setBatchFailed] = useState(0);
|
||||
const [batchCancelling, setBatchCancelling] = useState(false);
|
||||
const [verification, setVerification] = useState<VerificationSummary | null>(
|
||||
null,
|
||||
);
|
||||
const batchAbortRef = useRef<AbortController | null>(null);
|
||||
|
||||
// Nitro editor
|
||||
@@ -363,7 +367,16 @@ export function StudioClient({
|
||||
setDetail({ ...item, alreadyImported: true, nitroExists: true });
|
||||
}
|
||||
fetchStats();
|
||||
toast.success(`${item.classname} imported into the catalog`);
|
||||
const parts = [`${item.classname} imported into the catalog`];
|
||||
if (typeof data.furniDataFixedIds === "number") {
|
||||
parts.push(
|
||||
`verified: ${data.offerIdsFixed} offer_id, ${data.furniDataFixedIds} furnidata id`,
|
||||
);
|
||||
}
|
||||
if (data.furniDataMissing > 0) {
|
||||
parts.push(`${data.furniDataMissing} furnidata missing`);
|
||||
}
|
||||
toast.success(parts.join(" · "));
|
||||
} else {
|
||||
toast.error(data.error || `Import failed for ${item.classname}`);
|
||||
}
|
||||
@@ -462,6 +475,15 @@ export function StudioClient({
|
||||
} else if (event.type === "batch_complete") {
|
||||
setBatchSucceeded(event.succeeded);
|
||||
setBatchFailed(event.failed);
|
||||
setVerification({
|
||||
offerIdsFixed: event.offerIdsFixed ?? 0,
|
||||
furniDataFixedIds: event.furniDataFixedIds ?? 0,
|
||||
furniDataMissing: event.furniDataMissing ?? 0,
|
||||
furniDataConflicts: event.furniDataConflicts ?? 0,
|
||||
nitrosSynced: event.nitrosSynced ?? [],
|
||||
iconsSynced: event.iconsSynced ?? [],
|
||||
ownershipFixed: event.ownershipFixed ?? [],
|
||||
});
|
||||
setBatchDone(true);
|
||||
}
|
||||
} catch {
|
||||
@@ -1173,10 +1195,12 @@ export function StudioClient({
|
||||
succeeded={batchSucceeded}
|
||||
failed={batchFailed}
|
||||
cancelling={batchCancelling}
|
||||
verification={verification}
|
||||
onCancel={cancelBatch}
|
||||
onDismiss={() => {
|
||||
setBatchProgress(null);
|
||||
setBatchDone(false);
|
||||
setVerification(null);
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
@@ -40,3 +40,14 @@ export interface BatchItemStatus {
|
||||
warnings?: string[];
|
||||
itemId?: number;
|
||||
}
|
||||
|
||||
/** Post-import verification results reported by the import API. */
|
||||
export interface VerificationSummary {
|
||||
offerIdsFixed: number;
|
||||
furniDataFixedIds: number;
|
||||
furniDataMissing: number;
|
||||
furniDataConflicts: number;
|
||||
nitrosSynced: string[];
|
||||
iconsSynced: string[];
|
||||
ownershipFixed: string[];
|
||||
}
|
||||
Reference in new issue
Block a user