feat(housekeeping): cut over administration to ase

This commit is contained in:
Simo committed 2026-08-30 20:35:22 +02:00
1 parent c9e35cf602
commit 2b8f73a91d
457 files changed
+589 -55936

No files matched your search

@@ -1,190 +0,0 @@
"use client";
import { Ban, Check, Loader2, ShieldCheck, X } from "lucide-react";
import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils";
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,
done,
succeeded,
failed,
cancelling,
verification,
onCancel,
onDismiss,
}: {
progress: Map<string, BatchItemStatus>;
done: boolean;
succeeded: number;
failed: number;
cancelling?: boolean;
verification?: VerificationSummary | null;
onCancel?: () => void;
onDismiss?: () => void;
}) {
const entries = [...progress.entries()];
const total = entries.length;
const completed = entries.filter(
([, s]) => s.status === "done" || s.status === "failed",
).length;
const percent = total > 0 ? Math.round((completed / total) * 100) : 0;
return (
<div className="border-t border-[var(--admin-border)] p-3">
<div className="mb-2 flex items-center justify-between gap-3">
<span className="text-xs font-bold uppercase tracking-wider text-[var(--admin-text-muted)]">
{done ? "Import finished" : "Importing…"}
</span>
{done ? (
<span
className={cn(
"text-xs font-bold",
failed > 0
? "text-[var(--admin-warning)]"
: "text-[var(--admin-success)]",
)}
>
{completed}/{total} · {succeeded} ok
{failed > 0 ? ` · ${failed} failed` : ""}
</span>
) : (
<span className="flex items-center gap-2">
<span className="text-xs font-mono text-[var(--admin-text-muted)]">
{completed}/{total}
</span>
<Loader2
size={14}
className="animate-spin text-[var(--admin-accent)]"
/>
</span>
)}
</div>
{!done && (
<div className="mb-2 h-1.5 overflow-hidden rounded-full bg-[var(--admin-accent)]/10">
<div
className="h-full rounded-full bg-[var(--admin-accent)] transition-all duration-300"
style={{ width: `${percent}%` }}
/>
</div>
)}
<div className="max-h-44 space-y-1 overflow-y-auto pr-1">
{entries.map(([classname, s]) => (
<div key={classname} className="flex items-center gap-2 text-xs">
{s.status === "done" ? (
<Check
size={12}
className="shrink-0 text-[var(--admin-success)]"
/>
) : s.status === "failed" ? (
<X size={12} className="shrink-0 text-[var(--admin-warning)]" />
) : (
<Loader2
size={12}
className="shrink-0 animate-spin text-[var(--admin-accent)]"
/>
)}
<span className="min-w-0 flex-1 truncate font-mono">
{classname}
</span>
<span className="shrink-0 capitalize text-[var(--admin-text-muted)]">
{s.status.replace(/_/g, " ")}
</span>
</div>
))}
</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}>
<Check size={14} />
Dismiss
</Button>
) : (
<Button
size="sm"
variant="outline"
onClick={onCancel}
disabled={cancelling}
>
{cancelling ? (
<Loader2 size={14} className="animate-spin" />
) : (
<Ban size={14} />
)}
Cancel
</Button>
)}
</div>
</div>
);
}