revert fb8e77bb68
Local Build and Deploy / deploy (push) Successful in 1m11s
Local Build and Deploy / deploy (push) Successful in 1m11s
revert style: clean up code with prettier and eslint
This commit is contained in:
1 parent
27de078f54
commit
e85e4d74ea
378 files changed
+20710
-22428
No files matched your search
@@ -1,8 +1,8 @@
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import { prisma } from '@/lib/prisma'
|
||||
|
||||
export type { NestedTreeNode, TreeNode } from "@/types/catalog";
|
||||
export type { NestedTreeNode, TreeNode } from '@/types/catalog'
|
||||
|
||||
import type { TreeNode } from "@/types/catalog";
|
||||
import type { TreeNode } from '@/types/catalog'
|
||||
|
||||
/**
|
||||
* Get the full catalog tree recursively using iterative Prisma queries.
|
||||
@@ -12,36 +12,36 @@ import type { TreeNode } from "@/types/catalog";
|
||||
export async function getTreeFlat(): Promise<TreeNode[]> {
|
||||
const [allPages, itemCounts] = await Promise.all([
|
||||
prisma.catalogPages.findMany({
|
||||
orderBy: { orderNum: "asc" },
|
||||
orderBy: { orderNum: 'asc' },
|
||||
}),
|
||||
prisma.catalogItems.groupBy({
|
||||
by: ["pageId"],
|
||||
by: ['pageId'],
|
||||
_count: true,
|
||||
}),
|
||||
]);
|
||||
])
|
||||
|
||||
const itemCountMap = new Map(itemCounts.map((c) => [c.pageId, c._count]));
|
||||
const itemCountMap = new Map(itemCounts.map((c) => [c.pageId, c._count]))
|
||||
|
||||
// Count children per page
|
||||
const childCountMap = new Map<number, number>();
|
||||
const childCountMap = new Map<number, number>()
|
||||
for (const p of allPages) {
|
||||
childCountMap.set(p.parentId, (childCountMap.get(p.parentId) ?? 0) + 1);
|
||||
childCountMap.set(p.parentId, (childCountMap.get(p.parentId) ?? 0) + 1)
|
||||
}
|
||||
|
||||
// Compute depth from parent hierarchy
|
||||
const pageMap = new Map(allPages.map((p) => [p.id, p]));
|
||||
const depthCache = new Map<number, number>();
|
||||
const pageMap = new Map(allPages.map((p) => [p.id, p]))
|
||||
const depthCache = new Map<number, number>()
|
||||
|
||||
function computeDepth(pageId: number): number {
|
||||
if (depthCache.has(pageId)) return depthCache.get(pageId)!;
|
||||
const page = pageMap.get(pageId);
|
||||
if (depthCache.has(pageId)) return depthCache.get(pageId)!
|
||||
const page = pageMap.get(pageId)
|
||||
if (!page || page.parentId <= 0) {
|
||||
depthCache.set(pageId, 0);
|
||||
return 0;
|
||||
depthCache.set(pageId, 0)
|
||||
return 0
|
||||
}
|
||||
const d = computeDepth(page.parentId) + 1;
|
||||
depthCache.set(pageId, d);
|
||||
return d;
|
||||
const d = computeDepth(page.parentId) + 1
|
||||
depthCache.set(pageId, d)
|
||||
return d
|
||||
}
|
||||
|
||||
return allPages.map((p) => ({
|
||||
@@ -57,65 +57,65 @@ export async function getTreeFlat(): Promise<TreeNode[]> {
|
||||
pageLayout: p.pageLayout,
|
||||
childCount: childCountMap.get(p.id) ?? 0,
|
||||
itemCount: itemCountMap.get(p.id) ?? 0,
|
||||
}));
|
||||
}))
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a nested tree structure from flat nodes.
|
||||
*/
|
||||
import type { NestedTreeNode } from "@/types/catalog";
|
||||
import type { NestedTreeNode } from '@/types/catalog'
|
||||
|
||||
export function buildNestedTree(flat: TreeNode[], rootParentId = -1): NestedTreeNode[] {
|
||||
const childrenMap = new Map<number, NestedTreeNode[]>();
|
||||
const nodeMap = new Map<number, NestedTreeNode>();
|
||||
const childrenMap = new Map<number, NestedTreeNode[]>()
|
||||
const nodeMap = new Map<number, NestedTreeNode>()
|
||||
|
||||
for (const node of flat) {
|
||||
const nested: NestedTreeNode = { ...node, children: [] };
|
||||
nodeMap.set(node.id, nested);
|
||||
if (!childrenMap.has(node.parentId)) childrenMap.set(node.parentId, []);
|
||||
childrenMap.get(node.parentId)!.push(nested);
|
||||
const nested: NestedTreeNode = { ...node, children: [] }
|
||||
nodeMap.set(node.id, nested)
|
||||
if (!childrenMap.has(node.parentId)) childrenMap.set(node.parentId, [])
|
||||
childrenMap.get(node.parentId)!.push(nested)
|
||||
}
|
||||
|
||||
// Attach children
|
||||
for (const node of nodeMap.values()) {
|
||||
node.children = childrenMap.get(node.id) ?? [];
|
||||
node.children = childrenMap.get(node.id) ?? []
|
||||
}
|
||||
|
||||
return childrenMap.get(rootParentId) ?? [];
|
||||
return childrenMap.get(rootParentId) ?? []
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new catalog page.
|
||||
*/
|
||||
export async function createPage(data: {
|
||||
parentId: number;
|
||||
caption: string;
|
||||
captionSave?: string;
|
||||
pageLayout?: string;
|
||||
iconImage?: number;
|
||||
iconColor?: number;
|
||||
minRank?: number;
|
||||
orderNum?: number;
|
||||
visible?: boolean;
|
||||
enabled?: boolean;
|
||||
parentId: number
|
||||
caption: string
|
||||
captionSave?: string
|
||||
pageLayout?: string
|
||||
iconImage?: number
|
||||
iconColor?: number
|
||||
minRank?: number
|
||||
orderNum?: number
|
||||
visible?: boolean
|
||||
enabled?: boolean
|
||||
}): Promise<{ id: number }> {
|
||||
// Auto-generate captionSave if not provided
|
||||
const captionSave =
|
||||
data.captionSave ||
|
||||
data.caption
|
||||
.toLowerCase()
|
||||
.replace(/[^a-z0-9_]/g, "_")
|
||||
.substring(0, 25);
|
||||
.replace(/[^a-z0-9_]/g, '_')
|
||||
.substring(0, 25)
|
||||
|
||||
// Get next orderNum if not provided
|
||||
let orderNum = data.orderNum;
|
||||
let orderNum = data.orderNum
|
||||
if (orderNum === undefined) {
|
||||
const lastSibling = await prisma.catalogPages.findFirst({
|
||||
where: { parentId: data.parentId },
|
||||
orderBy: { orderNum: "desc" },
|
||||
orderBy: { orderNum: 'desc' },
|
||||
select: { orderNum: true },
|
||||
});
|
||||
orderNum = (lastSibling?.orderNum ?? 0) + 1;
|
||||
})
|
||||
orderNum = (lastSibling?.orderNum ?? 0) + 1
|
||||
}
|
||||
|
||||
const created = await prisma.catalogPages.create({
|
||||
@@ -123,26 +123,26 @@ export async function createPage(data: {
|
||||
parentId: data.parentId,
|
||||
caption: data.caption,
|
||||
captionSave,
|
||||
pageLayout: data.pageLayout ?? "default_3x3",
|
||||
pageLayout: data.pageLayout ?? 'default_3x3',
|
||||
iconImage: data.iconImage ?? 1,
|
||||
iconColor: data.iconColor ?? 1,
|
||||
minRank: data.minRank ?? 1,
|
||||
orderNum,
|
||||
visible: (data.visible ?? true) ? "1" : "0",
|
||||
enabled: (data.enabled ?? true) ? "1" : "0",
|
||||
pageHeadline: "",
|
||||
pageTeaser: "",
|
||||
pageSpecial: "",
|
||||
pageText1: "",
|
||||
pageText2: "",
|
||||
pageTextDetails: "",
|
||||
pageTextTeaser: "",
|
||||
includes: "",
|
||||
visible: (data.visible ?? true) ? '1' : '0',
|
||||
enabled: (data.enabled ?? true) ? '1' : '0',
|
||||
pageHeadline: '',
|
||||
pageTeaser: '',
|
||||
pageSpecial: '',
|
||||
pageText1: '',
|
||||
pageText2: '',
|
||||
pageTextDetails: '',
|
||||
pageTextTeaser: '',
|
||||
includes: '',
|
||||
},
|
||||
select: { id: true },
|
||||
});
|
||||
})
|
||||
|
||||
return created;
|
||||
return created
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -152,24 +152,24 @@ export async function createPage(data: {
|
||||
export async function movePage(pageId: number, newParentId: number): Promise<void> {
|
||||
// Walk up from newParentId to root — if we hit pageId, it's circular
|
||||
if (newParentId > 0) {
|
||||
let currentId = newParentId;
|
||||
let currentId = newParentId
|
||||
for (let i = 0; i < 50; i++) {
|
||||
if (currentId === pageId) {
|
||||
throw new Error("Cannot move page: would create a circular hierarchy");
|
||||
throw new Error('Cannot move page: would create a circular hierarchy')
|
||||
}
|
||||
const parent = await prisma.catalogPages.findUnique({
|
||||
where: { id: currentId },
|
||||
select: { parentId: true },
|
||||
});
|
||||
if (!parent || parent.parentId <= 0) break;
|
||||
currentId = parent.parentId;
|
||||
})
|
||||
if (!parent || parent.parentId <= 0) break
|
||||
currentId = parent.parentId
|
||||
}
|
||||
}
|
||||
|
||||
await prisma.catalogPages.update({
|
||||
where: { id: pageId },
|
||||
data: { parentId: newParentId },
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -179,79 +179,81 @@ export async function movePage(pageId: number, newParentId: number): Promise<voi
|
||||
*/
|
||||
export async function deletePage(
|
||||
pageId: number,
|
||||
mode: "cascade" | "reparent" = "reparent",
|
||||
mode: 'cascade' | 'reparent' = 'reparent',
|
||||
): Promise<{ deletedPages: number; movedChildren: number }> {
|
||||
const page = await prisma.catalogPages.findUnique({
|
||||
where: { id: pageId },
|
||||
select: { parentId: true },
|
||||
});
|
||||
if (!page) return { deletedPages: 0, movedChildren: 0 };
|
||||
})
|
||||
if (!page) return { deletedPages: 0, movedChildren: 0 }
|
||||
|
||||
if (mode === "reparent") {
|
||||
if (mode === 'reparent') {
|
||||
// Move children to page's parent
|
||||
const result = await prisma.catalogPages.updateMany({
|
||||
where: { parentId: pageId },
|
||||
data: { parentId: page.parentId },
|
||||
});
|
||||
})
|
||||
|
||||
// Delete items in this page
|
||||
await prisma.catalogItems.deleteMany({ where: { pageId } });
|
||||
await prisma.catalogItems.deleteMany({ where: { pageId } })
|
||||
// Delete the page
|
||||
await prisma.catalogPages.delete({ where: { id: pageId } });
|
||||
await prisma.catalogPages.delete({ where: { id: pageId } })
|
||||
|
||||
return { deletedPages: 1, movedChildren: result.count };
|
||||
return { deletedPages: 1, movedChildren: result.count }
|
||||
}
|
||||
|
||||
// Cascade: delete all descendants
|
||||
const deleted = await cascadeDelete(pageId);
|
||||
return { deletedPages: deleted, movedChildren: 0 };
|
||||
const deleted = await cascadeDelete(pageId)
|
||||
return { deletedPages: deleted, movedChildren: 0 }
|
||||
}
|
||||
|
||||
async function cascadeDelete(pageId: number): Promise<number> {
|
||||
// Collect all descendant IDs iteratively to avoid N+1 recursive queries
|
||||
const toDelete: number[] = [pageId];
|
||||
const queue: number[] = [pageId];
|
||||
const toDelete: number[] = [pageId]
|
||||
const queue: number[] = [pageId]
|
||||
|
||||
while (queue.length > 0) {
|
||||
const children = await prisma.catalogPages.findMany({
|
||||
where: { parentId: { in: queue } },
|
||||
select: { id: true },
|
||||
});
|
||||
queue.length = 0;
|
||||
})
|
||||
queue.length = 0
|
||||
for (const child of children) {
|
||||
toDelete.push(child.id);
|
||||
queue.push(child.id);
|
||||
toDelete.push(child.id)
|
||||
queue.push(child.id)
|
||||
}
|
||||
}
|
||||
|
||||
// Delete all items and pages in bulk (children first, then parents)
|
||||
await prisma.catalogItems.deleteMany({ where: { pageId: { in: toDelete } } });
|
||||
await prisma.catalogItems.deleteMany({ where: { pageId: { in: toDelete } } })
|
||||
// Delete in reverse order (deepest first) to avoid FK issues
|
||||
for (let i = toDelete.length - 1; i >= 0; i--) {
|
||||
await prisma.catalogPages.delete({ where: { id: toDelete[i] } });
|
||||
await prisma.catalogPages.delete({ where: { id: toDelete[i] } })
|
||||
}
|
||||
|
||||
return toDelete.length;
|
||||
return toDelete.length
|
||||
}
|
||||
|
||||
/**
|
||||
* Get ancestors (breadcrumb) from root to the given page.
|
||||
*/
|
||||
export async function getAncestors(pageId: number): Promise<Array<{ id: number; caption: string }>> {
|
||||
const ancestors: Array<{ id: number; caption: string }> = [];
|
||||
let currentId = pageId;
|
||||
export async function getAncestors(
|
||||
pageId: number,
|
||||
): Promise<Array<{ id: number; caption: string }>> {
|
||||
const ancestors: Array<{ id: number; caption: string }> = []
|
||||
let currentId = pageId
|
||||
|
||||
// Safety limit to prevent infinite loops
|
||||
for (let i = 0; i < 20; i++) {
|
||||
const page = await prisma.catalogPages.findUnique({
|
||||
where: { id: currentId },
|
||||
select: { id: true, caption: true, parentId: true },
|
||||
});
|
||||
if (!page) break;
|
||||
ancestors.unshift({ id: page.id, caption: page.caption });
|
||||
if (page.parentId <= 0) break;
|
||||
currentId = page.parentId;
|
||||
})
|
||||
if (!page) break
|
||||
ancestors.unshift({ id: page.id, caption: page.caption })
|
||||
if (page.parentId <= 0) break
|
||||
currentId = page.parentId
|
||||
}
|
||||
|
||||
return ancestors;
|
||||
return ancestors
|
||||
}
|
||||
Reference in new issue
Block a user