Fix Visual Manager opacity and load categories like CatalogTree.
Local Build and Deploy / deploy (push) Successful in 55s
Local Build and Deploy / deploy (push) Successful in 55s
Use an opaque admin-canvas portal and lazy parentId fetches instead of mode=full, which fails on large catalogs. Search no longer loads the entire tree. Co-authored-by: Cursor <[email protected]>
This commit is contained in:
1 parent
1d8efefce4
commit
33a8a19820
4 files changed
+187
-42
No files matched your search
@@ -184,15 +184,81 @@ async function getChildren(
|
||||
}
|
||||
|
||||
async function searchPages(q: string, isBc: boolean): Promise<TreeNode[]> {
|
||||
const flat = isBc ? await getBcTreeFlat() : await getTreeFlat();
|
||||
const needle = q.toLowerCase();
|
||||
return flat.filter(
|
||||
(p) =>
|
||||
p.caption.toLowerCase().includes(needle) ||
|
||||
String(p.id) === needle,
|
||||
const needle = q.trim();
|
||||
const idExact = Number.parseInt(needle, 10);
|
||||
const idFilter =
|
||||
Number.isFinite(idExact) && String(idExact) === needle
|
||||
? [{ id: idExact }]
|
||||
: [];
|
||||
|
||||
if (isBc) {
|
||||
const pages = await prisma.catalogPagesBc.findMany({
|
||||
where: {
|
||||
OR: [{ caption: { contains: needle } }, ...idFilter],
|
||||
},
|
||||
orderBy: { orderNum: "asc" },
|
||||
take: 50,
|
||||
});
|
||||
return pages.map((p) =>
|
||||
toTreeNode(
|
||||
{
|
||||
id: toInt(p.id),
|
||||
caption: p.caption,
|
||||
parentId: toInt(p.parentId, -1),
|
||||
orderNum: toInt(p.orderNum),
|
||||
enabled: String(p.enabled ?? "0"),
|
||||
visible: String(p.visible ?? "0"),
|
||||
iconImage: toInt(p.iconImage),
|
||||
iconColor: toInt(p.iconColor),
|
||||
pageLayout: p.pageLayout,
|
||||
},
|
||||
0,
|
||||
0,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
const pages = await prisma.catalogPages.findMany({
|
||||
where: {
|
||||
OR: [{ caption: { contains: needle } }, ...idFilter],
|
||||
},
|
||||
orderBy: { orderNum: "asc" },
|
||||
take: 50,
|
||||
});
|
||||
const ids = pages.map((p) => toInt(p.id));
|
||||
const [childCounts, itemMap] = await Promise.all([
|
||||
ids.length
|
||||
? prisma.catalogPages.groupBy({
|
||||
by: ["parentId"],
|
||||
where: { parentId: { in: ids } },
|
||||
_count: true,
|
||||
})
|
||||
: Promise.resolve([]),
|
||||
safeItemCounts(ids),
|
||||
]);
|
||||
const childMap = Object.fromEntries(
|
||||
childCounts.map((c) => [toInt(c.parentId), c._count]),
|
||||
);
|
||||
return pages.map((p) => {
|
||||
const id = toInt(p.id);
|
||||
return toTreeNode(
|
||||
{
|
||||
id,
|
||||
caption: p.caption,
|
||||
parentId: toInt(p.parentId, -1),
|
||||
orderNum: toInt(p.orderNum),
|
||||
enabled: String(p.enabled ?? "0"),
|
||||
visible: String(p.visible ?? "0"),
|
||||
iconImage: toInt(p.iconImage),
|
||||
iconColor: toInt(p.iconColor),
|
||||
pageLayout: p.pageLayout,
|
||||
},
|
||||
childMap[id] ?? 0,
|
||||
itemMap.get(id) ?? 0,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export const GET = withAdmin(
|
||||
{ permission: PERMS.CATALOG_VIEW },
|
||||
async (request) => {
|
||||
|
||||
@@ -59,13 +59,14 @@ export function CatalogManagerDialog({
|
||||
</Button>
|
||||
{mounted && open
|
||||
? createPortal(
|
||||
<div className="fixed inset-0 z-50">
|
||||
<div className="absolute inset-0 bg-black/50" />
|
||||
<div className="fixed inset-0 z-[200]">
|
||||
<div className="absolute inset-0 bg-black/70" />
|
||||
<div
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
aria-labelledby="visual-catalog-manager-title"
|
||||
className="fixed top-1/2 left-1/2 z-50 flex h-[95vh] max-h-[95vh] w-[98vw] max-w-[98vw] -translate-x-1/2 -translate-y-1/2 flex-col overflow-hidden rounded-lg border bg-card text-card-foreground shadow-lg"
|
||||
className="fixed top-[2.5vh] left-[1vw] z-[201] flex h-[95vh] max-h-[95vh] w-[98vw] max-w-[98vw] flex-col overflow-hidden rounded-lg border border-[var(--admin-border)] bg-[var(--admin-canvas)] text-[var(--admin-text)] shadow-2xl"
|
||||
style={{ backgroundColor: "var(--admin-canvas)" }}
|
||||
>
|
||||
<CatalogManagerProvider>
|
||||
<CatalogManagerInner
|
||||
@@ -212,7 +213,10 @@ function CatalogManagerInner({
|
||||
|
||||
return (
|
||||
<TooltipProvider delayDuration={300}>
|
||||
<div className="flex shrink-0 items-center justify-between gap-2 border-b px-4 py-2.5">
|
||||
<div
|
||||
className="flex shrink-0 items-center justify-between gap-2 border-b border-[var(--admin-border)] px-4 py-2.5"
|
||||
style={{ backgroundColor: "var(--admin-surface)" }}
|
||||
>
|
||||
<h2
|
||||
id="visual-catalog-manager-title"
|
||||
className="flex items-center gap-2 text-base font-semibold leading-none"
|
||||
@@ -243,7 +247,10 @@ function CatalogManagerInner({
|
||||
loading={state.loadingRoot}
|
||||
/>
|
||||
|
||||
<div className="flex min-h-0 flex-1 overflow-hidden">
|
||||
<div
|
||||
className="flex min-h-0 flex-1 overflow-hidden"
|
||||
style={{ backgroundColor: "var(--admin-canvas)" }}
|
||||
>
|
||||
<SortableTree
|
||||
activeTabId={state.activeTabId}
|
||||
selectedPageId={state.selectedPageId}
|
||||
@@ -251,11 +258,16 @@ function CatalogManagerInner({
|
||||
onTreeMutation={loadRootPages}
|
||||
nodeUpdate={null}
|
||||
/>
|
||||
<div
|
||||
className="flex min-h-0 min-w-0 flex-1 flex-col"
|
||||
style={{ backgroundColor: "var(--admin-canvas)" }}
|
||||
>
|
||||
<InlineEditor
|
||||
pageId={state.selectedPageId}
|
||||
onSaved={handleEditorSaved}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<StatsBar />
|
||||
</TooltipProvider>
|
||||
|
||||
@@ -128,7 +128,10 @@ export function RootTabs({
|
||||
: null;
|
||||
|
||||
return (
|
||||
<div className="flex items-center gap-1 border-b bg-muted/30 px-2 py-1.5 overflow-x-auto shrink-0">
|
||||
<div
|
||||
className="flex shrink-0 items-center gap-1 overflow-x-auto border-b border-[var(--admin-border)] px-2 py-1.5"
|
||||
style={{ backgroundColor: "var(--admin-surface)" }}
|
||||
>
|
||||
{confirmDialog}
|
||||
{loading && (
|
||||
<Loader2 className="h-4 w-4 animate-spin text-muted-foreground mx-2" />
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user