feat: comprehensive CMS improvements
CI / runtime-diagnostics (push) Skipped
CI / release (push) Skipped
CI / check (push) Failing after 0s
CI / deploy (push) Skipped

- Fix DOMPurify SSR crash (use isomorphic-dompurify)
- Fix SanitizedHtml to sanitize by default
- Add auth guards to studio/catalog maintenance pages
- Add update/edit to vouchers CRUD
- Add update/edit to rare-values CRUD
- Add approve workflow to applications page
- Add edit form to guilds detail page
- Add SEO metadata to all public pages (21 pages)
- Fix mobile nav accessibility (focus trap, aria attributes)
- Fix missing labels and table accessibility
- Add dynamic imports for heavy client components (6 components)
- Fix silent error swallowing (40+ locations)
- Add content scheduling for articles (publishAt, status)
- Wire up 12 missing webhook notification triggers
- Add global search to admin panel
- Add bulk actions to admin users table
- Fix JSON formatting and a11y issues
This commit is contained in:
openhands committed 2026-09-03 16:00:32 +02:00
1 parent b810b16672
commit 30c95b1a5c
78 files changed
+2252 -134

No files matched your search

+8 -11
View File
@@ -1,13 +1,14 @@
import { desc, inArray } from "drizzle-orm";
import { redirect } from "next/navigation";
import { getTranslations } from "next-intl/server";
import { dismissApplication } from "@/actions/admin-applications";
import { ApplicationActions } from "@/components/admin/application-actions";
import { StatusCard } from "@/components/admin/dashboard";
import Link from "@/components/link";
import { Button } from "@/components/ui/button";
import { db, User, WebsiteStaffApplications } from "@/lib/db";
import { formatDate } from "@/lib/format-date";
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
import { logServerError } from "@/lib/server-log";
type ApplicationRow = {
id: bigint;
@@ -31,7 +32,8 @@ export default async function AdminApplications() {
.from(WebsiteStaffApplications)
.orderBy(desc(WebsiteStaffApplications.createdAt))
.limit(100);
} catch {
} catch (error) {
logServerError("applications.query_failed", error);
applications = [];
}
@@ -45,8 +47,8 @@ export default async function AdminApplications() {
.from(User)
.where(inArray(User.id, ids));
for (const u of users) userMap.set(u.id, u.username);
} catch {
// no DB — fall back to raw ids
} catch (error) {
logServerError("applications.user_lookup_failed", error);
}
}
@@ -93,12 +95,7 @@ export default async function AdminApplications() {
<p className="text-sm text-[var(--admin-text)] whitespace-pre-wrap m-0 mb-3">
{a.content}
</p>
<form action={dismissApplication}>
<input type="hidden" name="id" value={String(a.id)} />
<Button type="submit" variant="destructive">
{t("dismiss")}
</Button>
</form>
<ApplicationActions id={String(a.id)} />
</article>
);
})}