Phase5: Automate bill creation
All checks were successful
Build and Push / build (push) Successful in 1m43s

This commit is contained in:
2026-05-25 10:41:51 +02:00
parent 6a8ad7b4be
commit 427c7c6204
16 changed files with 1343 additions and 4 deletions

View File

@@ -0,0 +1,44 @@
import { redirect } from "next/navigation";
import { getTranslations } from "next-intl/server";
import { getSessionUser } from "@/lib/session";
import {
getLastSuccessfulCronRuns,
listRecentCronRuns,
} from "@/lib/db";
import { CronControls } from "@/components/admin/cron/cron-controls";
/**
* /admin/cron — automation dashboard.
*
* Shows:
* - Last successful run of each kind, with relative time
* - Two "Run now" buttons (admin-triggered manual sweeps)
* - Recent runs table (last 30)
*
* Platform-admin gated server-side.
*/
export default async function AdminCronPage() {
const user = await getSessionUser();
if (!user || !user.isPlatform) redirect("/login");
const t = await getTranslations("adminCron");
const [recent, lastSuccess] = await Promise.all([
listRecentCronRuns(30),
getLastSuccessfulCronRuns(),
]);
return (
<main className="max-w-5xl mx-auto px-6 py-8">
<div className="mb-8 animate-in">
<h1 className="font-display text-2xl font-semibold accent-rule">
{t("title")}
</h1>
<p className="text-sm text-text-secondary mt-3">{t("subtitle")}</p>
</div>
<CronControls
initialRecent={recent}
initialLastSuccess={lastSuccess}
/>
</main>
);
}

View File

@@ -61,6 +61,12 @@ export default async function AdminPage() {
>
{t("billingTool")}
</a>
<a
href="/admin/cron"
className="text-sm px-4 py-2 rounded-lg border border-border text-text-secondary hover:text-text-primary hover:border-text-secondary transition-colors"
>
{t("cronTool")}
</a>
<a
href="/admin/openclaw"
className="text-sm px-4 py-2 rounded-lg border border-border text-text-secondary hover:text-text-primary hover:border-text-secondary transition-colors"