feat(admin): Abgleich einstellbar und Schalter je Projekt
Adminbereich, Abschnitt "Automatischer Abgleich": - ein- und ausschalten - Abstand von 15 Minuten bis taeglich - Projekte je Durchlauf - fertige und archivierte auslassen - Zustand auf einen Blick: verknuepfte Projekte, letzter und naechster Durchlauf, Kurzbericht des letzten Laufs - Knopf "Jetzt abgleichen" fuer einen sofortigen Durchlauf Der Endpunkt POST /api/admin/sync/run dient zugleich als Einstieg fuer einen externen Zeitgeber, falls jemand lieber von aussen taktet als den eingebauten Automatismus zu nutzen. Im Projektdialog laesst sich ein einzelnes Projekt vom Abgleich ausnehmen - nuetzlich bei einem Repo, dessen Token staendig Fehler wirft. Manuell synchronisieren geht unabhaengig davon immer. Die Zahl der in Frage kommenden Projekte wird ueber alle Konten gezaehlt: der Abgleich ist ein Serverauftrag, keine Dateneinsicht. Ein Administrator sieht dadurch weiterhin keine fremden Projekte. Nachgewiesen: Durchlauf 1 aktualisiert das echte Repo und meldet das kaputte als Fehlschlag, Durchlauf 2 stellt das kaputte zurueck, das ausgenommene Projekt bleibt in beiden unberuehrt. Der Zeitplan loeste eigenstaendig aus. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+27
-3
@@ -1,5 +1,9 @@
|
||||
import type { Metadata } from "next";
|
||||
import { AdminManager, type AdminData } from "@/components/admin/AdminManager";
|
||||
import {
|
||||
AdminManager,
|
||||
type AdminData,
|
||||
type AutoSyncReport,
|
||||
} from "@/components/admin/AdminManager";
|
||||
import { requireAdminPage } from "@/lib/auth/guard";
|
||||
import { getAppSettings } from "@/lib/auth/settings";
|
||||
import { userSafeSelect } from "@/lib/auth/users";
|
||||
@@ -15,12 +19,23 @@ export async function generateMetadata(): Promise<Metadata> {
|
||||
export default async function AdminPage() {
|
||||
const admin = await requireAdminPage();
|
||||
|
||||
const [settings, users] = await Promise.all([
|
||||
const [settings, users, eligible] = await Promise.all([
|
||||
getAppSettings(),
|
||||
prisma.user.findMany({
|
||||
select: userSafeSelect,
|
||||
orderBy: [{ role: "asc" }, { username: "asc" }],
|
||||
}),
|
||||
// Bewusst ueber alle Konten: der Abgleich ist ein Serverauftrag, keine
|
||||
// Dateneinsicht. Gezaehlt wird nur, nicht gelesen.
|
||||
prisma.project.count({
|
||||
where: {
|
||||
autoSync: true,
|
||||
OR: [
|
||||
{ AND: [{ repoOwner: { not: null } }, { repoName: { not: null } }] },
|
||||
{ repoUrl: { not: null } },
|
||||
],
|
||||
},
|
||||
}),
|
||||
]);
|
||||
|
||||
const data: AdminData = {
|
||||
@@ -30,6 +45,15 @@ export default async function AdminPage() {
|
||||
currentUserId: admin.id,
|
||||
appUrl: APP_URL,
|
||||
passkeysAvailable: WEBAUTHN_AVAILABLE,
|
||||
autoSync: {
|
||||
enabled: settings.autoSyncEnabled,
|
||||
intervalMinutes: settings.autoSyncIntervalMinutes,
|
||||
activeOnly: settings.autoSyncActiveOnly,
|
||||
batchSize: settings.autoSyncBatchSize,
|
||||
lastRunAt: settings.lastAutoSyncAt,
|
||||
lastReport: (settings.lastAutoSyncReport as AutoSyncReport | null) ?? null,
|
||||
eligible,
|
||||
},
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -42,7 +66,7 @@ export default async function AdminPage() {
|
||||
Admin-Einstellungen
|
||||
</h1>
|
||||
<p className="mt-1 text-sm text-slate-400">
|
||||
Betriebsart, Registrierung und Benutzerkonten.
|
||||
Betriebsart, automatischer Abgleich und Benutzerkonten.
|
||||
</p>
|
||||
</header>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user