diff --git a/src/app/admin/actions/apicore-sync.ts b/src/app/admin/actions/apicore-sync.ts
index 282213e..dc378dc 100644
--- a/src/app/admin/actions/apicore-sync.ts
+++ b/src/app/admin/actions/apicore-sync.ts
@@ -370,11 +370,13 @@ async function syncBatches(sources: ApiCoreBottlingBatchWithHarvestId[]): Promis
* Formularfeld und waere sonst eine offene Weiterleitung — ein praeparierter
* Wert koennte Admins auf eine fremde Seite schicken.
*/
-const RETURN_TARGETS = ["/admin/ernten", "/admin/produkte", "/admin/chargen"] as const;
+// "/admin" ist der Normalfall (der eine Sync-Knopf sitzt auf dem Dashboard);
+// die uebrigen bleiben erlaubt, damit alte Lesezeichen/Formulare nicht ins Leere laufen.
+const RETURN_TARGETS = ["/admin", "/admin/ernten", "/admin/produkte", "/admin/chargen"] as const;
function returnTargetFrom(formData: FormData): string {
const requested = formData.get("returnTo");
- return RETURN_TARGETS.find((target) => target === requested) ?? "/admin/ernten";
+ return RETURN_TARGETS.find((target) => target === requested) ?? "/admin";
}
/**
diff --git a/src/app/admin/ernten/page.tsx b/src/app/admin/ernten/page.tsx
index 551cb8c..4effb64 100644
--- a/src/app/admin/ernten/page.tsx
+++ b/src/app/admin/ernten/page.tsx
@@ -14,13 +14,11 @@ import {
AdminRowActions,
} from "@/components/admin-list";
import { createHarvestAction, toggleHarvestPublishedAction, deleteHarvestAction } from "../actions";
-import { ApiCoreSyncPanel, ApiCoreSyncResult } from "@/components/apicore-sync-panel";
import { getLocale } from "@/i18n/locale";
import { getDictionary } from "@/i18n/get-dictionary";
-export default async function AdminHarvestsPage(props: PageProps<"/admin/ernten">) {
+export default async function AdminHarvestsPage() {
const t = getDictionary(await getLocale());
- const searchParams = await props.searchParams;
const harvests = await prisma.harvest.findMany({
orderBy: [{ year: "desc" }, { harvestDate: "desc" }],
include: { _count: { select: { batches: true, products: true } } },
@@ -31,7 +29,6 @@ export default async function AdminHarvestsPage(props: PageProps<"/admin/ernten"
-
@@ -94,7 +91,7 @@ export default async function AdminHarvestsPage(props: PageProps<"/admin/ernten"
{harvests.length === 0 ? : null}
-
+
{t.adminHarvestsPage.newHarvestHeading}
-
);
diff --git a/src/app/admin/page.tsx b/src/app/admin/page.tsx
index efa5df7..0d18dab 100644
--- a/src/app/admin/page.tsx
+++ b/src/app/admin/page.tsx
@@ -1,4 +1,5 @@
import Link from "next/link";
+import { ApiCoreSyncPanel, ApiCoreSyncResult } from "@/components/apicore-sync-panel";
import { prisma } from "@/lib/prisma";
import { formatPrice } from "@/lib/format";
import { getLocale } from "@/i18n/locale";
@@ -100,7 +101,8 @@ function daysAgo(n: number): Date {
return d;
}
-export default async function AdminDashboardPage() {
+export default async function AdminDashboardPage(props: PageProps<"/admin">) {
+ const searchParams = await props.searchParams;
const locale = await getLocale();
const t = getDictionary(locale);
const [
@@ -306,6 +308,9 @@ export default async function AdminDashboardPage() {
+ {/* Ergebnis des ApiCore-Laufs (nur direkt nach dem Klick sichtbar). */}
+
+
{/* Fehlen Dateien, zu denen die Datenbank noch Pfade haelt, ist das
fast immer ein nicht persistentes Upload-Verzeichnis (in Kubernetes
ein "emptyDir" statt eines PersistentVolumeClaim). Ohne diesen
@@ -576,6 +581,11 @@ export default async function AdminDashboardPage() {
{t.adminDashboardPage.viewAllOrders}
+
+ {/* Der eine Sync-Knopf fuer Ernten, Chargen und Produkte. */}
+
);
}
diff --git a/src/app/admin/produkte/page.tsx b/src/app/admin/produkte/page.tsx
index 6378040..8ebf54e 100644
--- a/src/app/admin/produkte/page.tsx
+++ b/src/app/admin/produkte/page.tsx
@@ -3,7 +3,6 @@ import { BackLink } from "@/components/back-link";
import { formatPrice } from "@/lib/format";
import { ConfirmForm } from "@/components/confirm-form";
import { deleteProductAction } from "../actions";
-import { ApiCoreSyncPanel, ApiCoreSyncResult } from "@/components/apicore-sync-panel";
import { getLocale } from "@/i18n/locale";
import { getDictionary } from "@/i18n/get-dictionary";
import { isArchiveView } from "@/lib/archive";
@@ -49,7 +48,6 @@ export default async function AdminProductsPage(props: PageProps<"/admin/produkt
-
-
);
}
diff --git a/src/components/apicore-sync-panel.tsx b/src/components/apicore-sync-panel.tsx
index bb58a1e..be93c7d 100644
--- a/src/components/apicore-sync-panel.tsx
+++ b/src/components/apicore-sync-panel.tsx
@@ -6,10 +6,10 @@ import { Button } from "@/components/ui";
/**
* Der eine Sync-Knopf und die Anzeige seines Ergebnisses.
*
- * Gemeinsam genutzt von /admin/ernten und /admin/produkte: es ist derselbe
- * Vorgang, egal von welcher Seite er ausgeloest wird — Ernten, Chargen und
- * Produkte laufen ohnehin immer zusammen. Zwei getrennte Bloecke in zwei
- * Seiten waeren dieselbe Anzeige zweimal gepflegt.
+ * Sitzt genau einmal: auf dem Admin-Dashboard. Ernten, Chargen und Produkte
+ * laufen ohnehin immer zusammen durch (siehe syncApiCoreAction) — derselbe
+ * Knopf zusaetzlich auf /admin/ernten und /admin/produkte sah aus wie zwei
+ * verschiedene Synchronisierungen.
*/
/** Rohwerte aus der Adresszeile — Next liefert Query-Parameter so aus. */