doxa-maps-cdn/server/api/admin/pages/index.get.ts
corsacca 6f918a9d85
Let categories have child categories for nested pages. (#6)
* Let categories have child categories for nested pages.

* fixes
2026-05-21 06:00:54 -05:00

54 lines
1.9 KiB
TypeScript

// Admin: list all CMS pages with counts of published/draft translations,
// the page's category (if any), and the computed full URL path.
import { defineEventHandler } from 'h3'
import { requirePermission } from '../../../utils/rbac'
import { db } from '../../../utils/database'
import { sql } from 'kysely'
import { loadCategoryTree, pageUrlPath } from '../../../database/categoryTree'
export default defineEventHandler(async (event) => {
await requirePermission(event, 'pages.view')
const rows = await db
.selectFrom('pages')
.leftJoin('page_translations', 'page_translations.page_id', 'pages.id')
.leftJoin('categories', 'categories.id', 'pages.category_id')
.leftJoin('category_translations', join =>
join
.onRef('category_translations.category_id', '=', 'categories.id')
.on('category_translations.locale', '=', 'en')
)
.select([
'pages.id',
'pages.slug',
'pages.category_id',
'pages.menu_order',
'pages.updated',
'categories.slug as category_slug',
sql<string | null>`MAX(category_translations.name)`.as('category_name_en'),
sql<string | null>`MAX(CASE WHEN page_translations.locale = 'en' THEN page_translations.title END)`.as('title_en'),
sql<number>`COUNT(page_translations.id)::int`.as('translation_count'),
sql<number>`COUNT(CASE WHEN page_translations.status = 'published' THEN 1 END)::int`.as('published_count')
])
.groupBy([
'pages.id',
'pages.slug',
'pages.category_id',
'pages.menu_order',
'pages.updated',
'categories.slug'
])
.orderBy('categories.slug', 'asc')
.orderBy('pages.menu_order', 'asc')
.orderBy('pages.slug', 'asc')
.execute()
const tree = await loadCategoryTree()
const decorated = rows.map(r => ({
...r,
url: pageUrlPath(tree, { slug: r.slug, category_id: r.category_id })
}))
return { rows: decorated }
})