Studio: add clone-all-per-hotel, per-item status detail, retry, ETA, and auto-translate
- Add 'Clone all missing' button for clone sources with confirmation dialog - Show per-item status badges: nitro, furnidata, catalog entry - Add status filters: missing furnidata, missing catalog entry - Add ETA and percentage to batch progress bar - Add retry button for failed items after batch import - Auto-translate all languages after clone-all completes - Fix statusFilter 'all' bug that incorrectly filtered imported items - Bulk-load FurnitureData + catalog references for O(1) per-item checks
This commit is contained in:
1 parent
1610aa1008
commit
1374bd332f
4 files changed
+580
-47
No files matched your search
@@ -11,6 +11,7 @@ import { getSource } from "@/lib/services/clone-sources";
|
||||
import { getFurniAssetDirs } from "@/lib/services/furni-asset-dirs";
|
||||
import {
|
||||
appendFurniEntriesBulk,
|
||||
readFurniData,
|
||||
rebuildCatalogOfferIds,
|
||||
reconcileFurniDataWithItemsBase,
|
||||
verifyAndFixSpriteIds,
|
||||
@@ -311,6 +312,38 @@ export const GET = withAdmin(
|
||||
});
|
||||
|
||||
const sourceIconBase = source.iconBaseUrl?.trim().replace(/\/+$/, "");
|
||||
|
||||
// Bulk-load FurnitureData and catalog references for status checks
|
||||
const furniDataSet = new Set<string>();
|
||||
const catalogIdSet = new Set<number>();
|
||||
try {
|
||||
const fd = (await readFurniData()) as {
|
||||
roomitemtypes?: { furnitype?: Array<{ classname?: string }> };
|
||||
wallitemtypes?: { furnitype?: Array<{ classname?: string }> };
|
||||
};
|
||||
for (const e of [
|
||||
...(fd.roomitemtypes?.furnitype ?? []),
|
||||
...(fd.wallitemtypes?.furnitype ?? []),
|
||||
]) {
|
||||
if (e.classname) furniDataSet.add(e.classname);
|
||||
}
|
||||
} catch {
|
||||
/* best effort */
|
||||
}
|
||||
try {
|
||||
const rows = await db.execute(sql`SELECT item_ids FROM catalog_items`);
|
||||
for (const row of (
|
||||
rows as unknown as [Array<{ item_ids: string | null }>, unknown]
|
||||
)[0]) {
|
||||
for (const part of String(row.item_ids ?? "").split(/[;,]/)) {
|
||||
const n = Number(part.trim());
|
||||
if (Number.isFinite(n) && n > 0) catalogIdSet.add(n);
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
/* best effort */
|
||||
}
|
||||
|
||||
const enriched = items.map((item) => {
|
||||
const imported = item.present;
|
||||
let nitroExists = false;
|
||||
@@ -336,6 +369,8 @@ export const GET = withAdmin(
|
||||
category: String(item.category ?? ""),
|
||||
alreadyImported: imported,
|
||||
nitroExists,
|
||||
hasFurnidata: imported ? furniDataSet.has(item.classname) : undefined,
|
||||
hasCatalogEntry: imported ? catalogIdSet.has(item.id) : undefined,
|
||||
iconUrl: sourceIconBase
|
||||
? `${sourceIconBase}/${encodeURIComponent(item.classname)}_icon.png`
|
||||
: undefined,
|
||||
@@ -364,6 +399,37 @@ export const GET = withAdmin(
|
||||
allImported.map((e) => e.itemName).filter((n): n is string => !!n),
|
||||
);
|
||||
|
||||
// Bulk-load FurnitureData and catalog references for status checks
|
||||
const furniDataSet = new Set<string>();
|
||||
const catalogIdSet = new Set<number>();
|
||||
try {
|
||||
const fd = (await readFurniData()) as {
|
||||
roomitemtypes?: { furnitype?: Array<{ classname?: string }> };
|
||||
wallitemtypes?: { furnitype?: Array<{ classname?: string }> };
|
||||
};
|
||||
for (const e of [
|
||||
...(fd.roomitemtypes?.furnitype ?? []),
|
||||
...(fd.wallitemtypes?.furnitype ?? []),
|
||||
]) {
|
||||
if (e.classname) furniDataSet.add(e.classname);
|
||||
}
|
||||
} catch {
|
||||
/* best effort */
|
||||
}
|
||||
try {
|
||||
const rows = await db.execute(sql`SELECT item_ids FROM catalog_items`);
|
||||
for (const row of (
|
||||
rows as unknown as [Array<{ item_ids: string | null }>, unknown]
|
||||
)[0]) {
|
||||
for (const part of String(row.item_ids ?? "").split(/[;,]/)) {
|
||||
const n = Number(part.trim());
|
||||
if (Number.isFinite(n) && n > 0) catalogIdSet.add(n);
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
/* best effort */
|
||||
}
|
||||
|
||||
const result = await listFurniture({
|
||||
search: search || undefined,
|
||||
page,
|
||||
@@ -386,7 +452,13 @@ export const GET = withAdmin(
|
||||
);
|
||||
nitroExists = existsSync(/*turbopackIgnore: true*/ p);
|
||||
}
|
||||
return { ...item, alreadyImported: imported, nitroExists };
|
||||
return {
|
||||
...item,
|
||||
alreadyImported: imported,
|
||||
nitroExists,
|
||||
hasFurnidata: imported ? furniDataSet.has(item.classname) : undefined,
|
||||
hasCatalogEntry: imported ? catalogIdSet.has(item.id) : undefined,
|
||||
};
|
||||
});
|
||||
|
||||
return apiOk({ items: enriched, meta: result.meta });
|
||||
|
||||
Reference in new issue
Block a user