style: format code with prettier
Local Build and Deploy / deploy (push) Successful in 49s

This commit is contained in:
openhands committed 2026-07-12 21:07:34 +02:00
1 parent e85e4d74ea
commit 2e4ed76121
378 files changed
+22404 -20686

No files matched your search

+52 -57
View File
@@ -1,28 +1,28 @@
import { redirect } from 'next/navigation'
import { calcPagination, parseListParams } from './admin-helpers'
import { canAccess, getAdminContext, type PermissionSet } from './permissions'
import { prisma } from './prisma'
import { redirect } from "next/navigation";
import { calcPagination, parseListParams } from "./admin-helpers";
import { canAccess, getAdminContext, type PermissionSet } from "./permissions";
import { prisma } from "./prisma";
// biome-ignore lint/suspicious/noExplicitAny: explicitly chosen here, see surrounding code
type PrismaModel = any
type PrismaModel = any;
interface AdminListConfig<TRow> {
/** Permission slug required to view this page */
permission: string
permission: string;
/** Prisma model name (e.g. 'user', 'ban', 'room') */
model: string
model: string;
/** Search field paths for OR filter. Use dot notation for nested relations (e.g. 'owner.username') */
searchFields: string[]
searchFields: string[];
/** Default sort when no sort param provided. Default: { id: 'desc' } */
defaultSort?: Record<string, 'asc' | 'desc'>
defaultSort?: Record<string, "asc" | "desc">;
/** Default items per page. Default: 20 */
defaultPerPage?: number
defaultPerPage?: number;
/** Prisma include clause for relations */
include?: Record<string, unknown>
include?: Record<string, unknown>;
/** Prisma select clause (mutually exclusive with include) */
select?: Record<string, unknown>
select?: Record<string, unknown>;
/** Fixed WHERE conditions merged with search (e.g. { online: '1' }) */
baseWhere?: Record<string, unknown>
baseWhere?: Record<string, unknown>;
/**
* Map URL ?filter_* params to Prisma WHERE conditions. Each entry receives
* the raw string value from the URL and returns the WHERE fragment to merge.
@@ -34,20 +34,20 @@ interface AdminListConfig<TRow> {
* filter_online: (v) => ({ online: v }),
* }
*/
filterMap?: Record<string, (value: string) => Record<string, unknown> | null | undefined>
filterMap?: Record<string, (value: string) => Record<string, unknown> | null | undefined>;
/** Transform raw Prisma row to the shape needed by the table component */
mapRow?: (row: PrismaModel) => TRow
mapRow?: (row: PrismaModel) => TRow;
}
interface AdminListResult<TRow> {
rows: TRow[]
total: number
page: number
perPage: number
lastPage: number
locale: string
permissions: PermissionSet
rank: number
rows: TRow[];
total: number;
page: number;
perPage: number;
lastPage: number;
locale: string;
permissions: PermissionSet;
rank: number;
}
/**
@@ -56,16 +56,16 @@ interface AdminListResult<TRow> {
* e.g. 'username' => { username: { contains: search } }
*/
function buildFieldCondition(fieldPath: string, search: string): Record<string, unknown> {
const parts = fieldPath.split('.')
const parts = fieldPath.split(".");
if (parts.length === 1) {
return { [parts[0]]: { contains: search } }
return { [parts[0]]: { contains: search } };
}
// Build nested object from right to left
let result: Record<string, unknown> = { [parts[parts.length - 1]]: { contains: search } }
let result: Record<string, unknown> = { [parts[parts.length - 1]]: { contains: search } };
for (let i = parts.length - 2; i >= 0; i--) {
result = { [parts[i]]: result }
result = { [parts[i]]: result };
}
return result
return result;
}
/**
@@ -78,35 +78,33 @@ export async function fetchAdminList<TRow = PrismaModel>(
paramsPromise: Promise<{ locale: string }>,
searchParamsPromise: Promise<Record<string, string>>,
): Promise<AdminListResult<TRow>> {
const { locale } = await paramsPromise
const { session, permissions } = await getAdminContext()
const { locale } = await paramsPromise;
const { session, permissions } = await getAdminContext();
if (!canAccess(permissions, config.permission, session.user.rank)) {
redirect('/admin')
redirect("/admin");
}
const rawParams = await searchParamsPromise
const sp = new URLSearchParams(rawParams)
const parsed = parseListParams(sp)
const perPage = config.defaultPerPage
? Number(rawParams.perPage) || config.defaultPerPage
: parsed.perPage
const { search, page, sort, order } = parsed
const rawParams = await searchParamsPromise;
const sp = new URLSearchParams(rawParams);
const parsed = parseListParams(sp);
const perPage = config.defaultPerPage ? Number(rawParams.perPage) || config.defaultPerPage : parsed.perPage;
const { search, page, sort, order } = parsed;
// Build WHERE clause
const searchWhere =
search && config.searchFields.length > 0
? { OR: config.searchFields.map((field) => buildFieldCondition(field, search)) }
: {}
: {};
// Apply URL filter_* params via filterMap
const filterWhere: Record<string, unknown> = {}
const filterWhere: Record<string, unknown> = {};
if (config.filterMap) {
for (const [paramKey, build] of Object.entries(config.filterMap)) {
const value = rawParams[paramKey]
if (!value) continue
const fragment = build(value)
if (fragment) Object.assign(filterWhere, fragment)
const value = rawParams[paramKey];
if (!value) continue;
const fragment = build(value);
if (fragment) Object.assign(filterWhere, fragment);
}
}
@@ -114,31 +112,28 @@ export async function fetchAdminList<TRow = PrismaModel>(
...(config.baseWhere ?? {}),
...filterWhere,
...searchWhere,
}
};
// Build orderBy
const orderBy = sort ? { [sort]: order } : (config.defaultSort ?? { id: 'desc' as const })
const orderBy = sort ? { [sort]: order } : (config.defaultSort ?? { id: "desc" as const });
// Access Prisma model dynamically
const delegate = (prisma as PrismaModel)[config.model]
const delegate = (prisma as PrismaModel)[config.model];
const queryArgs: PrismaModel = {
where,
orderBy,
skip: (page - 1) * perPage,
take: perPage,
}
};
if (config.include) queryArgs.include = config.include
if (config.select) queryArgs.select = config.select
if (config.include) queryArgs.include = config.include;
if (config.select) queryArgs.select = config.select;
const [rawRows, total] = await Promise.all([
delegate.findMany(queryArgs),
delegate.count({ where }),
])
const [rawRows, total] = await Promise.all([delegate.findMany(queryArgs), delegate.count({ where })]);
const pagination = calcPagination(total, page, perPage)
const rows = config.mapRow ? rawRows.map(config.mapRow) : rawRows
const pagination = calcPagination(total, page, perPage);
const rows = config.mapRow ? rawRows.map(config.mapRow) : rawRows;
return {
rows,
@@ -146,5 +141,5 @@ export async function fetchAdminList<TRow = PrismaModel>(
locale,
permissions,
rank: session.user.rank,
}
};
}