Fix Visual Manager empty categories: seed roots, harden tree API.
Local Build and Deploy / deploy (push) Successful in 56s

Seed root tabs from SSR, load the full tree without CLEAR_TREE races, coerce parent ids, and tolerate catalog_items page_id type mismatches so category pages actually appear.

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
SimoandCursor committed 2026-07-17 22:02:53 +02:00
1 parent 385cefd0fa
commit 1d8efefce4
6 files changed
+285 -187

No files matched your search

+49 -40
View File
@@ -232,49 +232,48 @@ export default async function CatalogPagesPage({
prisma.catalogPages.count({ where: { enabled: "1" } }),
]);
// ── Tree view data ──────────────────────────────────────────────
let rootPages: TreeNodeShape[] = [];
if (viewMode === "tree") {
const rootPagesRaw = await prisma.catalogPages.findMany({
where: { parentId: -1 },
orderBy: { orderNum: "asc" },
});
const rootIds = rootPagesRaw.map((p) => p.id);
const [rootChildCounts, rootItemCounts] = await Promise.all([
rootIds.length > 0
? prisma.catalogPages.groupBy({
by: ["parentId"],
where: { parentId: { in: rootIds } },
_count: true,
})
: [],
rootIds.length > 0
? prisma.catalogItems.groupBy({
// ── Root pages (tree view + Visual Manager seed) ────────────────
const rootPagesRaw = await prisma.catalogPages.findMany({
where: { OR: [{ parentId: -1 }, { parentId: 0 }] },
orderBy: { orderNum: "asc" },
});
const rootIds = rootPagesRaw.map((p) => p.id);
const [rootChildCounts, rootItemCounts] = await Promise.all([
rootIds.length > 0
? prisma.catalogPages.groupBy({
by: ["parentId"],
where: { parentId: { in: rootIds } },
_count: true,
})
: [],
rootIds.length > 0
? prisma.catalogItems
.groupBy({
by: ["pageId"],
where: { pageId: { in: rootIds } },
_count: true,
})
: [],
]);
const rootChildMap = Object.fromEntries(
rootChildCounts.map((c) => [c.parentId, c._count]),
);
const rootItemMap = Object.fromEntries(
rootItemCounts.map((c) => [c.pageId, c._count]),
);
rootPages = rootPagesRaw.map((p) => ({
id: p.id,
caption: p.caption,
parentId: p.parentId,
enabled: String(p.enabled),
visible: String(p.visible),
iconImage: p.iconImage,
iconColor: p.iconColor,
pageLayout: p.pageLayout,
childCount: rootChildMap[p.id] ?? 0,
itemCount: rootItemMap[p.id] ?? 0,
}));
}
.catch(() => [])
: [],
]);
const rootChildMap = Object.fromEntries(
rootChildCounts.map((c) => [c.parentId, c._count]),
);
const rootItemMap = Object.fromEntries(
rootItemCounts.map((c) => [c.pageId, c._count]),
);
const rootPages: TreeNodeShape[] = rootPagesRaw.map((p) => ({
id: p.id,
caption: p.caption,
parentId: p.parentId,
enabled: String(p.enabled),
visible: String(p.visible),
iconImage: p.iconImage,
iconColor: p.iconColor,
pageLayout: p.pageLayout,
childCount: rootChildMap[p.id] ?? 0,
itemCount: rootItemMap[p.id] ?? 0,
}));
// ── Table view data (skip if tree) ────────────────────────────
let rows: {
@@ -399,7 +398,17 @@ export default async function CatalogPagesPage({
</p>
<div className="flex items-center gap-2">
<CatalogViewToggle currentView={viewMode} catalogType="normal" />
{canEdit && <CatalogManagerDialog />}
{canEdit && (
<CatalogManagerDialog
initialRoots={rootPages.map((p) => ({
id: p.id,
caption: p.caption,
iconImage: p.iconImage,
enabled: p.enabled,
orderNum: 0,
}))}
/>
)}
{canEdit && <CatalogActions />}
</div>
</div>