Fix rooms list crash and rebuild CMS settings UI.
Rooms queried the wrong Prisma model and a non-existent owner relation. Settings now use grouped managed fields plus a searchable advanced key/value panel. Co-authored-by: Cursor <[email protected]>
This commit is contained in:
1 parent
c186f51ae0
commit
e101ea474e
6 files changed
+796
-104
No files matched your search
@@ -1,11 +1,46 @@
|
|||||||
"use server";
|
"use server";
|
||||||
|
|
||||||
import { revalidatePath } from "next/cache";
|
import { revalidatePath } from "next/cache";
|
||||||
|
import { z } from "zod";
|
||||||
|
import { MANAGED_SETTING_KEYS } from "@/app/admin/settings/cms-settings-config";
|
||||||
import { requirePermissionRateLimited } from "@/lib/admin/guard";
|
import { requirePermissionRateLimited } from "@/lib/admin/guard";
|
||||||
|
import { actionOk, adminAction } from "@/lib/foundation/action";
|
||||||
import { PERMS } from "@/lib/permissions";
|
import { PERMS } from "@/lib/permissions";
|
||||||
import { prisma } from "@/lib/prisma";
|
import { prisma } from "@/lib/prisma";
|
||||||
import { siteSettings } from "@/lib/services/site-settings";
|
import { siteSettings } from "@/lib/services/site-settings";
|
||||||
|
|
||||||
|
const managedKeySet = new Set(MANAGED_SETTING_KEYS);
|
||||||
|
|
||||||
|
const saveManagedSchema = z.object({
|
||||||
|
settings: z.record(z.string(), z.string()),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const saveManagedSettings = adminAction(
|
||||||
|
{
|
||||||
|
permission: PERMS.SETTINGS_EDIT,
|
||||||
|
schema: saveManagedSchema,
|
||||||
|
rateLimitKey: "admin-settings-save",
|
||||||
|
rateLimitMax: 30,
|
||||||
|
},
|
||||||
|
async (ctx) => {
|
||||||
|
const entries = Object.entries(ctx.data.settings).filter(([key]) =>
|
||||||
|
managedKeySet.has(key),
|
||||||
|
);
|
||||||
|
await Promise.all(
|
||||||
|
entries.map(([key, value]) =>
|
||||||
|
prisma.websiteSetting.upsert({
|
||||||
|
where: { key },
|
||||||
|
update: { value },
|
||||||
|
create: { key, value },
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
siteSettings.reload();
|
||||||
|
revalidatePath("/admin/settings");
|
||||||
|
return actionOk({ saved: entries.length });
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
export async function updateSetting(formData: FormData): Promise<void> {
|
export async function updateSetting(formData: FormData): Promise<void> {
|
||||||
await requirePermissionRateLimited(PERMS.SETTINGS_EDIT);
|
await requirePermissionRateLimited(PERMS.SETTINGS_EDIT);
|
||||||
const key = String(formData.get("key") ?? "")
|
const key = String(formData.get("key") ?? "")
|
||||||
|
|||||||
@@ -6,27 +6,41 @@ export default async function RoomsPage({
|
|||||||
params: paramsPromise,
|
params: paramsPromise,
|
||||||
searchParams,
|
searchParams,
|
||||||
}: {
|
}: {
|
||||||
params: Promise<{ locale: string }>;
|
params: Promise<{ locale?: string }>;
|
||||||
searchParams: Promise<Record<string, string>>;
|
searchParams: Promise<Record<string, string>>;
|
||||||
}) {
|
}) {
|
||||||
const result = await fetchAdminList(
|
const result = await fetchAdminList(
|
||||||
{
|
{
|
||||||
permission: PERMS.ROOMS_VIEW,
|
permission: PERMS.ROOMS_VIEW,
|
||||||
model: "room",
|
// Prisma model is `Rooms` → client accessor `rooms`.
|
||||||
searchFields: ["name", "owner.username"],
|
// Owner is denormalized on the row (ownerId / ownerName), not a relation.
|
||||||
include: { owner: { select: { username: true } } },
|
model: "rooms",
|
||||||
|
searchFields: ["name", "ownerName"],
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
name: true,
|
||||||
|
ownerId: true,
|
||||||
|
ownerName: true,
|
||||||
|
state: true,
|
||||||
|
users: true,
|
||||||
|
usersMax: true,
|
||||||
|
description: true,
|
||||||
|
},
|
||||||
|
filterMap: {
|
||||||
|
filter_state: (v) => ({ state: v }),
|
||||||
|
},
|
||||||
mapRow: (r) => ({
|
mapRow: (r) => ({
|
||||||
id: r.id,
|
id: r.id as number,
|
||||||
name: r.name,
|
name: r.name as string,
|
||||||
ownerName: r.owner.username,
|
ownerName: (r.ownerName as string) || "—",
|
||||||
ownerId: r.owner?.id ?? 0,
|
ownerId: (r.ownerId as number) ?? 0,
|
||||||
state: r.state,
|
state: r.state as string,
|
||||||
users: r.users,
|
users: r.users as number,
|
||||||
usersMax: r.usersMax,
|
usersMax: r.usersMax as number,
|
||||||
description: r.description,
|
description: (r.description as string) || "",
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
paramsPromise,
|
paramsPromise as Promise<{ locale: string }>,
|
||||||
searchParams,
|
searchParams,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user