feat(studio): recover matching Nitro sources and persist import phases
This commit is contained in:
1 parent
00e33623f7
commit
13bd3695cb
45 files changed
+903
-28
No files matched your search
@@ -20,7 +20,7 @@ import {
|
||||
uuid as zUuid,
|
||||
} from "zod/mini";
|
||||
import { adminFetch } from "@/lib/admin-fetch";
|
||||
import type { ImportJob } from "@/lib/furni/import-job";
|
||||
import { IMPORT_PHASES, type ImportJob } from "@/lib/furni/import-job";
|
||||
|
||||
const endpoint = "/api/admin/studio/import-jobs";
|
||||
const historyTimeoutMs = 15_000;
|
||||
@@ -55,6 +55,16 @@ const jobSchema = zLooseObject({
|
||||
"cancelled",
|
||||
"interrupted",
|
||||
]),
|
||||
phase: zOptional(zEnum(IMPORT_PHASES)),
|
||||
phaseStartedAt: zOptional(zIso.datetime({ offset: true })),
|
||||
sourceAttempt: zOptional(zString()),
|
||||
recoveredSource: zOptional(
|
||||
zObject({
|
||||
sourceId: zString(),
|
||||
sourceName: zString(),
|
||||
revision: zNumber(),
|
||||
}),
|
||||
),
|
||||
error: zOptional(zString()),
|
||||
warnings: zOptional(zArray(zString())),
|
||||
itemId: zOptional(zNumber()),
|
||||
|
||||
@@ -15,6 +15,7 @@ export function FurnitureJobHistory({
|
||||
}) {
|
||||
const t = useTranslations("pages.admin.importHistory");
|
||||
const format = useFormatter();
|
||||
const progressT = useTranslations("pages.admin.importProgress");
|
||||
const [limits, setLimits] = useState<Record<string, number>>({});
|
||||
return (
|
||||
<details
|
||||
@@ -94,6 +95,29 @@ export function FurnitureJobHistory({
|
||||
<li key={item.classname}>
|
||||
<strong>{item.classname}</strong> · {t(item.state)}
|
||||
{item.itemId ? ` · ID ${item.itemId}` : ""}
|
||||
{item.phase &&
|
||||
(item.state === "running" ||
|
||||
item.state === "failed" ||
|
||||
item.state === "interrupted") && (
|
||||
<p className="text-xs text-[var(--admin-text-muted)]">
|
||||
{progressT(
|
||||
item.state === "running" ? "current" : "last",
|
||||
{ phase: progressT(item.phase) },
|
||||
)}
|
||||
{item.state === "running" &&
|
||||
item.phaseStartedAt &&
|
||||
` · ${progressT("elapsed", { seconds: Math.max(0, Math.floor((Date.now() - Date.parse(item.phaseStartedAt)) / 1000)) })}`}
|
||||
{item.sourceAttempt && ` · ${item.sourceAttempt}`}
|
||||
</p>
|
||||
)}
|
||||
{item.recoveredSource && (
|
||||
<p className="break-words text-xs text-[var(--admin-text-muted)]">
|
||||
{progressT("recovered", {
|
||||
source: item.recoveredSource.sourceName,
|
||||
revision: item.recoveredSource.revision,
|
||||
})}
|
||||
</p>
|
||||
)}
|
||||
{item.error && (
|
||||
<p className="text-[var(--admin-warning)]">
|
||||
{item.error}
|
||||
|
||||
@@ -66,6 +66,7 @@ export function ImportReview({
|
||||
setUploading(null);
|
||||
}
|
||||
}
|
||||
const progressT = useTranslations("pages.admin.importProgress");
|
||||
const inspection = useFurnitureInspection(
|
||||
items.map((item) => item.classname),
|
||||
);
|
||||
@@ -166,8 +167,7 @@ export function ImportReview({
|
||||
Source files not found by preliminary check: {check.classname}
|
||||
</p>
|
||||
<p className="text-xs text-[var(--admin-text-muted)]">
|
||||
You can continue. The importer will try the original furniture
|
||||
files and verify them before creating its SQL entry.
|
||||
{progressT("recoveryHint")}
|
||||
</p>
|
||||
</section>
|
||||
))}
|
||||
|
||||
Reference in new issue
Block a user