Commit 1: Create individual form components per route, remove generic AdminForm dependency

- Add per-route form components: UserRoleForm, UserForm,
  ProclamationForm (with category cascade), CategoryForm,
  FreqForm, LevelForm
- Update all admin +page.svelte files to use AdminTable + AdminModal
  + their specific form component instead of AdminPage
- Update profiles page to inline fields instead of using AdminForm
- Add custom Proclamation server action with category fallback logic
  (categoryId falls back to parentCategoryId when no sub-category)
- Remove cascade/were/fieldLabels logic from generic crud.ts
- Remove outdated cascade/where tests from crud.spec.ts
- Remove fieldLabels from AdminModelConfig type
This commit is contained in:
NeilClack
2026-07-07 21:01:02 -05:00
parent 2073248576
commit 22b6adee3f
17 changed files with 1440 additions and 90 deletions
@@ -1,16 +1,73 @@
import type { PageServerLoad } from './$types';
import { getModelConfig } from '$lib/svelte-admin/registry';
import { loadRecords, upsertRecord, deleteRecord } from '$lib/svelte-admin/crud';
import { loadRecords, deleteRecord, superFormErrorsToFieldErrors } from '$lib/svelte-admin/crud';
import { prisma } from '$lib/db';
import { superValidate } from 'sveltekit-superforms/server';
import { zod4 } from 'sveltekit-superforms/adapters';
import * as Schemas from '$lib/svelte-admin/schemas';
const config = getModelConfig('proclamations')!;
export const load: PageServerLoad = async ({ locals }) => {
return loadRecords(locals, config);
const base = await loadRecords(locals, config);
const categories = await prisma.proclamationCategory.findMany({
select: { id: true, name: true, parentId: true },
orderBy: { name: 'asc' }
});
return { ...base, categories };
};
export const actions = {
upsert: async ({ request, locals }) => {
return upsertRecord(request, config, locals);
if (!locals.user) {
return { success: false, error: 'Unauthorized' };
}
const formData = await request.formData();
const form = await superValidate(formData, zod4(Schemas.Proclamation));
if (!form.valid) {
const { error, fieldErrors } = superFormErrorsToFieldErrors(
form.errors as Record<string, unknown>
);
return { success: false, error, fieldErrors };
}
const rawId = formData.get('id')?.toString();
const { parentCategoryId, ...rest } = form.data;
const data: Record<string, unknown> = {
...rest,
categoryId: rest.categoryId ?? parentCategoryId
};
try {
if (rawId) {
const existing = await prisma.proclamation.findUnique({
where: { id: rawId }
});
if (!existing) {
return { success: false, error: 'Record not found' };
}
await prisma.proclamation.update({
where: { id: rawId },
data: data as any
});
} else {
await prisma.proclamation.create({ data: data as any });
}
} catch (e: unknown) {
if (e && typeof e === 'object' && 'code' in e && (e as { code: string }).code === 'P2002') {
return {
success: false,
error: 'A record with this name already exists.'
};
}
throw e;
}
return { success: true };
},
delete: async ({ request, locals }) => {
return deleteRecord(request, config, locals);