refactor(admin): move sections to dynamic-route pattern + reduce overview

Each admin section component now accepts an optional `id` prop (was
required) so it works under the new /admin/[section] dynamic route
without scroll-anchor wrapping. Adds <IntegrationsGroupSection> as the
composite for /admin/integrations (Umami + GlitchTip + WebPush + Bug
Report). Reduces /admin to a true overview: status-card grid + welcome
card + quick-jump menu of sub-sections; the long monolithic scroll is
gone.

Bundle-size win: each section now ships under its own route bundle, so
the overview no longer drags Umami/GlitchTip/Feedback/Users/etc. trees.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Marc-André BombeckandClaude Opus 4.7 committed 2026-05-09 16:59:25 +02:00
1 parent d8b71b3848
commit 12b280bb55
14 files changed
+103 -83

No files matched your search

@@ -9,7 +9,7 @@ import { formatDate, formatDateTime } from "@/lib/format";
import { useTranslations } from "@/lib/i18n/context";
import { type ApiTokenInfo } from "./_shared";
export function ApiTokenOverviewSection({ id }: { id: string }) {
export function ApiTokenOverviewSection({ id }: { id?: string } = {}) {
const { t } = useTranslations();
const [expanded, setExpanded] = useState(false);
+1 -1
View File
@@ -10,7 +10,7 @@ import { Switch } from "@/components/ui/switch";
import { useTranslations } from "@/lib/i18n/context";
import { PasswordInput, useAdminSettings, useUpdateSettings } from "./_shared";
export function BugReportSection({ id }: { id: string }) {
export function BugReportSection({ id }: { id?: string } = {}) {
const { t } = useTranslations();
const { data: settings } = useAdminSettings();
const updateSettings = useUpdateSettings();
+1 -1
View File
@@ -17,7 +17,7 @@ import {
import { Button } from "@/components/ui/button";
import { useTranslations } from "@/lib/i18n/context";
export function DangerZoneSection({ id }: { id: string }) {
export function DangerZoneSection({ id }: { id?: string } = {}) {
const { t } = useTranslations();
const queryClient = useQueryClient();
const [wipeMsg, setWipeMsg] = useState<string | null>(null);
@@ -45,7 +45,7 @@ import {
useSystemStatus,
} from "./_shared";
export function FeedbackInboxSection({ id }: { id: string }) {
export function FeedbackInboxSection({ id }: { id?: string } = {}) {
const { t } = useTranslations();
const queryClient = useQueryClient();
const { data: status } = useSystemStatus();
@@ -4,7 +4,7 @@ import { Settings } from "lucide-react";
import { useTranslations } from "@/lib/i18n/context";
import { SettingsToggle, useAdminSettings, useUpdateSettings } from "./_shared";
export function GeneralSettingsSection({ id }: { id: string }) {
export function GeneralSettingsSection({ id }: { id?: string } = {}) {
const { t } = useTranslations();
const { data: settings } = useAdminSettings();
const updateSettings = useUpdateSettings();
+1 -1
View File
@@ -16,7 +16,7 @@ import {
useUpdateSettings,
} from "./_shared";
export function GlitchtipSection({ id }: { id: string }) {
export function GlitchtipSection({ id }: { id?: string } = {}) {
const { t } = useTranslations();
const { data: settings } = useAdminSettings();
const updateSettings = useUpdateSettings();
@@ -0,0 +1,26 @@
"use client";
/**
* `<IntegrationsGroupSection>` — composite admin route at `/admin/integrations`.
*
* Wraps the four standalone integration sub-sections (Umami, GlitchTip, Web
* Push, Bug Report) under one route so each existing component stays the
* source of truth for its own settings while admins still get a single
* landing page mirroring the v1.4 layout.
*/
import { BugReportSection } from "./bug-report-section";
import { GlitchtipSection } from "./glitchtip-section";
import { UmamiSection } from "./umami-section";
import { WebPushVapidSection } from "./web-push-vapid-section";
export function IntegrationsGroupSection() {
return (
<div className="space-y-6">
<UmamiSection />
<GlitchtipSection />
<WebPushVapidSection />
<BugReportSection />
</div>
);
}
@@ -14,7 +14,7 @@ import { formatDateTime } from "@/lib/format";
import { useTranslations } from "@/lib/i18n/context";
import { type AdminAuditEntry } from "./_shared";
export function LoginOverviewSection({ id }: { id: string }) {
export function LoginOverviewSection({ id }: { id?: string } = {}) {
const { t } = useTranslations();
const [expanded, setExpanded] = useState(false);
const [filter, setFilter] = useState<"all" | "failed">("all");
+1 -1
View File
@@ -22,7 +22,7 @@ import {
useUpdateSettings,
} from "./_shared";
export function RemindersSection({ id }: { id: string }) {
export function RemindersSection({ id }: { id?: string } = {}) {
const { t } = useTranslations();
const { data: settings } = useAdminSettings();
const updateSettings = useUpdateSettings();
+1 -1
View File
@@ -4,7 +4,7 @@ import { Bell, Globe, Key, MessageCircle } from "lucide-react";
import { useTranslations } from "@/lib/i18n/context";
import { SettingsToggle, useAdminSettings, useUpdateSettings } from "./_shared";
export function ServicesSection({ id }: { id: string }) {
export function ServicesSection({ id }: { id?: string } = {}) {
const { t } = useTranslations();
const { data: settings } = useAdminSettings();
const updateSettings = useUpdateSettings();
@@ -19,7 +19,7 @@ import { formatDateTime } from "@/lib/format";
import { useFormatters, useTranslations } from "@/lib/i18n/context";
import { StatusItem, useSystemStatus } from "./_shared";
export function SystemStatusSection({ id }: { id: string }) {
export function SystemStatusSection({ id }: { id?: string } = {}) {
const { t } = useTranslations();
const fmt = useFormatters();
const { data: status, isError } = useSystemStatus();
+1 -1
View File
@@ -16,7 +16,7 @@ import {
useUpdateSettings,
} from "./_shared";
export function UmamiSection({ id }: { id: string }) {
export function UmamiSection({ id }: { id?: string } = {}) {
const { t } = useTranslations();
const { data: settings } = useAdminSettings();
const updateSettings = useUpdateSettings();
@@ -9,7 +9,7 @@ import { Label } from "@/components/ui/label";
import { useTranslations } from "@/lib/i18n/context";
import { PasswordInput, useAdminSettings, useUpdateSettings } from "./_shared";
export function WebPushVapidSection({ id }: { id: string }) {
export function WebPushVapidSection({ id }: { id?: string } = {}) {
const { t } = useTranslations();
const { data: settings } = useAdminSettings();
const updateSettings = useUpdateSettings();