fix(catalog): keep Nitro editor stable during background polling
CI / check (push) Successful in 1m32s
CI / deploy (push) Successful in 1m23s
CI / e2e (push) Successful in 21s

This commit is contained in:
Simo committed 2026-09-05 18:00:39 +02:00
1 parent dcb5f46eed
commit 3c24df9b1d
1 file changed
+35 -32
@@ -16,7 +16,7 @@ import {
Save,
Sparkles,
} from "lucide-react";
import { useCallback, useEffect, useState } from "react";
import { useEffect, useEffectEvent, useState } from "react";
import { toast } from "sonner";
import { NitroQualityPanel } from "@/components/admin/studio/nitro-quality-panel";
import { NitroScale32Generator } from "@/components/admin/studio/nitro-scale32-generator";
@@ -188,40 +188,43 @@ export function NitroEditorDialog({
);
};
const fetchMetadata = useCallback(async () => {
if (!classname) return;
const closeAfterLoadError = useEffectEvent(() => onOpenChange(false));
useEffect(() => {
if (!open || !classname) return;
const controller = new AbortController();
setActiveTab("visual");
setLoading(true);
setJsonError(null);
try {
const res = await adminFetch(
`/api/admin/import/furni/nitro-editor?classname=${encodeURIComponent(classname)}`,
);
if (!res.ok) {
const err = await res.json().catch(() => ({}));
toast.error(err.error || "Failed to load .nitro metadata");
onOpenChange(false);
return;
setAutoDetectResult(null);
void (async () => {
try {
const res = await adminFetch(
`/api/admin/import/furni/nitro-editor?classname=${encodeURIComponent(classname)}`,
{ signal: controller.signal },
);
const data = await res.json();
if (controller.signal.aborted) return;
if (!res.ok) {
toast.error(data.error || "Failed to load .nitro metadata");
closeAfterLoadError();
return;
}
setMetadata(data.metadata);
setOriginalMetadata(structuredClone(data.metadata));
setJsonText(JSON.stringify(data.metadata, null, 2));
setFlags(data.flags);
setOriginalFlags({ ...data.flags });
} catch {
if (!controller.signal.aborted) {
toast.error("Network error loading .nitro metadata");
closeAfterLoadError();
}
} finally {
if (!controller.signal.aborted) setLoading(false);
}
const data = await res.json();
setMetadata(data.metadata);
setOriginalMetadata(JSON.parse(JSON.stringify(data.metadata)));
setJsonText(JSON.stringify(data.metadata, null, 2));
setFlags(data.flags);
setOriginalFlags({ ...data.flags });
} catch {
toast.error("Network error loading .nitro metadata");
onOpenChange(false);
} finally {
setLoading(false);
}
}, [classname, onOpenChange]);
useEffect(() => {
if (open && classname) {
setActiveTab("visual");
fetchMetadata();
}
}, [open, classname, fetchMetadata]);
})();
return () => controller.abort();
}, [open, classname]);
const handleTabChange = (newTab: string) => {
if (activeTab === "json" && newTab !== "json") {