Fix moving of tags table

This commit is contained in:
2026-02-02 15:18:26 +01:00
parent 9121b74ade
commit 1a855b2177
3 changed files with 123 additions and 61 deletions

View File

@ -53,7 +53,7 @@ model Artwork {
albums Album[] albums Album[]
categories ArtCategory[] categories ArtCategory[]
colors ArtworkColor[] colors ArtworkColor[]
tags ArtTag[] tags Tag[] @relation("ArtworkTags")
variants FileVariant[] variants FileVariant[]
@@index([colorStatus]) @@index([colorStatus])
@ -101,43 +101,7 @@ model ArtCategory {
description String? description String?
artworks Artwork[] artworks Artwork[]
tags ArtTag[] tagLinks TagCategory[]
}
model ArtTag {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
sortIndex Int @default(0)
name String @unique
slug String @unique
isParent Boolean @default(false)
showOnAnimalPage Boolean @default(false)
description String?
aliases ArtTagAlias[]
artworks Artwork[]
categories ArtCategory[]
parentId String?
parent ArtTag? @relation("TagHierarchy", fields: [parentId], references: [id], onDelete: SetNull)
children ArtTag[] @relation("TagHierarchy")
}
model ArtTagAlias {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
alias String @unique
tagId String
tag ArtTag @relation(fields: [tagId], references: [id], onDelete: Cascade)
@@unique([tagId, alias])
@@index([alias])
} }
model Color { model Color {
@ -248,6 +212,71 @@ model FileVariant {
@@unique([artworkId, type]) @@unique([artworkId, type])
} }
model Tag {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
sortIndex Int @default(0)
name String @unique
slug String @unique
isVisible Boolean @default(true)
description String?
aliases TagAlias[]
categoryLinks TagCategory[]
categoryParents TagCategory[] @relation("TagCategoryParent")
artworks Artwork[] @relation("ArtworkTags")
commissionTypes CommissionType[] @relation("CommissionTypeTags")
miniatures Miniature[] @relation("MiniatureTags")
}
model TagAlias {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
alias String @unique
tagId String
tag Tag @relation(fields: [tagId], references: [id], onDelete: Cascade)
@@unique([tagId, alias])
@@index([alias])
}
model TagCategory {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
tagId String
categoryId String
isParent Boolean @default(false)
showOnAnimalPage Boolean @default(false)
parentTagId String?
tag Tag @relation(fields: [tagId], references: [id], onDelete: Cascade)
category ArtCategory @relation(fields: [categoryId], references: [id], onDelete: Cascade)
parentTag Tag? @relation("TagCategoryParent", fields: [parentTagId], references: [id], onDelete: SetNull)
@@unique([tagId, categoryId])
@@index([categoryId])
@@index([tagId])
@@index([parentTagId])
@@index([categoryId, parentTagId])
}
model Miniature {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
tags Tag[] @relation("MiniatureTags")
}
model Commission { model Commission {
id String @id @default(cuid()) id String @id @default(cuid())
createdAt DateTime @default(now()) createdAt DateTime @default(now())
@ -265,6 +294,8 @@ model CommissionType {
description String? description String?
tags Tag[] @relation("CommissionTypeTags")
options CommissionTypeOption[] options CommissionTypeOption[]
extras CommissionTypeExtra[] extras CommissionTypeExtra[]
customInputs CommissionTypeCustomInput[] customInputs CommissionTypeCustomInput[]

View File

@ -30,14 +30,22 @@ function sortArtworks(a: SimpleArtwork, b: SimpleArtwork) {
} }
export default async function AnimalListPage() { export default async function AnimalListPage() {
const tags = await prisma.artTag.findMany({ const tags = await prisma.tag.findMany({
where: { showOnAnimalPage: true }, where: {
isVisible: true,
categoryLinks: {
some: { category: { name: "Animal Studies" }, showOnAnimalPage: true },
},
},
select: { select: {
id: true, id: true,
name: true, name: true,
slug: true, slug: true,
sortIndex: true, sortIndex: true,
parentId: true, categoryLinks: {
where: { category: { name: "Animal Studies" } },
select: { parentTagId: true },
},
artworks: { artworks: {
where: { where: {
published: true, published: true,
@ -50,10 +58,15 @@ export default async function AnimalListPage() {
orderBy: [{ sortIndex: "asc" }, { name: "asc" }], orderBy: [{ sortIndex: "asc" }, { name: "asc" }],
}); });
const byId = new Map(tags.map((t) => [t.id, t])); const tagsWithParents = tags.map((t) => ({
const childrenByParentId = new Map<string, typeof tags>(); ...t,
parentId: t.categoryLinks[0]?.parentTagId ?? null,
}));
for (const t of tags) { const byId = new Map(tagsWithParents.map((t) => [t.id, t]));
const childrenByParentId = new Map<string, typeof tagsWithParents>();
for (const t of tagsWithParents) {
if (!t.parentId) continue; if (!t.parentId) continue;
const arr = childrenByParentId.get(t.parentId) ?? []; const arr = childrenByParentId.get(t.parentId) ?? [];
arr.push(t); arr.push(t);
@ -64,12 +77,12 @@ export default async function AnimalListPage() {
childrenByParentId.set(pid, arr.slice().sort(sortBySortIndexName)); childrenByParentId.set(pid, arr.slice().sort(sortBySortIndexName));
} }
const parents = tags const parents = tagsWithParents
.filter((t) => t.parentId === null) .filter((t) => t.parentId === null)
.slice() .slice()
.sort(sortBySortIndexName); .sort(sortBySortIndexName);
const orphans = tags const orphans = tagsWithParents
.filter((t) => t.parentId !== null && !byId.has(t.parentId)) .filter((t) => t.parentId !== null && !byId.has(t.parentId))
.slice() .slice()
.sort(sortBySortIndexName); .sort(sortBySortIndexName);

View File

@ -17,17 +17,28 @@ function parseTagsParam(tags: string | string[] | undefined): string[] {
function expandSelectedWithChildren( function expandSelectedWithChildren(
selectedSlugs: string[], selectedSlugs: string[],
tagsForFilter: Array<{ tagsForFilter: Array<{
id: string;
slug: string; slug: string;
children: Array<{ slug: string }>; parentId: string | null;
}>, }>,
) { ) {
const bySlug = new Map(tagsForFilter.map((t) => [t.slug, t])); const bySlug = new Map(tagsForFilter.map((t) => [t.slug, t]));
const childrenByParentId = new Map<string, typeof tagsForFilter>();
for (const t of tagsForFilter) {
if (!t.parentId) continue;
const arr = childrenByParentId.get(t.parentId) ?? [];
arr.push(t);
childrenByParentId.set(t.parentId, arr);
}
const out = new Set(selectedSlugs); const out = new Set(selectedSlugs);
for (const slug of selectedSlugs) { for (const slug of selectedSlugs) {
const t = bySlug.get(slug); const t = bySlug.get(slug);
if (!t) continue; if (!t) continue;
for (const c of t.children ?? []) out.add(c.slug); const children = childrenByParentId.get(t.id) ?? [];
for (const c of children) out.add(c.slug);
} }
return Array.from(out); return Array.from(out);
@ -41,24 +52,31 @@ export default async function AnimalStudiesPage({
const { tags } = await searchParams; const { tags } = await searchParams;
const selectedTagSlugs = parseTagsParam(tags); const selectedTagSlugs = parseTagsParam(tags);
const tagsForFilter = await prisma.artTag.findMany({ const tagLinks = await prisma.tagCategory.findMany({
where: { showOnAnimalPage: true }, where: {
showOnAnimalPage: true,
category: { name: "Animal Studies" },
tag: { isVisible: true },
},
select: { select: {
id: true, parentTagId: true,
name: true, tag: {
slug: true, select: { id: true, name: true, slug: true, sortIndex: true },
sortIndex: true,
parentId: true,
parent: { select: { id: true, name: true, slug: true, sortIndex: true } },
children: {
where: { showOnAnimalPage: true },
select: { id: true, name: true, slug: true, sortIndex: true, parentId: true },
orderBy: [{ sortIndex: "asc" }, { name: "asc" }],
}, },
}, },
orderBy: [{ sortIndex: "asc" }, { name: "asc" }], orderBy: [{ tag: { sortIndex: "asc" } }, { tag: { name: "asc" } }],
}); });
const tagsForFilter = tagLinks.map((link) => ({
id: link.tag.id,
name: link.tag.name,
slug: link.tag.slug,
sortIndex: link.tag.sortIndex,
parentId: link.parentTagId,
parent: null,
children: [],
}));
const expandedTagSlugs = expandSelectedWithChildren(selectedTagSlugs, tagsForFilter); const expandedTagSlugs = expandSelectedWithChildren(selectedTagSlugs, tagsForFilter);
return ( return (