103 lines
2.8 KiB
TypeScript
103 lines
2.8 KiB
TypeScript
"use client";
|
|
|
|
import { useCallback, useEffect, useState } from "react";
|
|
import { adminFetch } from "@/lib/admin-fetch";
|
|
|
|
type ExportStatus = {
|
|
enabled: boolean;
|
|
pending: number;
|
|
active: number;
|
|
running?: boolean;
|
|
commit?: string;
|
|
finishedAt?: string;
|
|
error?: string;
|
|
};
|
|
|
|
export function CatalogExportClient() {
|
|
const [status, setStatus] = useState<ExportStatus | null>(null);
|
|
const [error, setError] = useState("");
|
|
const [busy, setBusy] = useState(false);
|
|
const refresh = useCallback(async () => {
|
|
try {
|
|
const response = await adminFetch("/api/admin/catalog-export", {
|
|
cache: "no-store",
|
|
});
|
|
if (!response.ok) throw new Error("Unable to load export status");
|
|
setStatus(await response.json());
|
|
setError("");
|
|
} catch {
|
|
setError("Unable to load export status");
|
|
}
|
|
}, []);
|
|
useEffect(() => {
|
|
void refresh();
|
|
const timer = setInterval(() => {
|
|
void refresh();
|
|
}, 15_000);
|
|
return () => clearInterval(timer);
|
|
}, [refresh]);
|
|
async function retry() {
|
|
setBusy(true);
|
|
try {
|
|
const response = await adminFetch("/api/admin/catalog-export", {
|
|
method: "POST",
|
|
});
|
|
if (!response.ok) throw new Error("Unable to queue export");
|
|
await refresh();
|
|
} catch {
|
|
setError("Unable to queue export");
|
|
} finally {
|
|
setBusy(false);
|
|
}
|
|
}
|
|
return (
|
|
<section className="space-y-3 rounded-lg border border-[var(--admin-border)] p-4">
|
|
<h2 className="text-lg font-semibold">Catalog repository export</h2>
|
|
<p className="text-sm text-muted-foreground">
|
|
Automatically publishes bundles, icons, gamedata, translations and
|
|
catalog SQL to Epicnabbo-Catalogus-Updated-Daily (Beta-3).
|
|
</p>
|
|
<div role="status" className="text-sm" aria-live="polite">
|
|
{!status
|
|
? "Loading…"
|
|
: !status.enabled
|
|
? "Not configured on this server."
|
|
: status.active
|
|
? `Waiting for ${status.active} operation(s) to finish.`
|
|
: status.running
|
|
? "Export in progress…"
|
|
: status.pending
|
|
? `${status.pending} update(s) queued for the worker.`
|
|
: "No pending updates."}
|
|
{status?.commit && (
|
|
<p>
|
|
Last published commit:{" "}
|
|
<a
|
|
className="underline"
|
|
href={`https://gitlab.epicnabbo.nl/remco/Epicnabbo-Catalogus-Updated-Daily/commit/${status.commit}`}
|
|
target="_blank"
|
|
rel="noreferrer"
|
|
>
|
|
{status.commit.slice(0, 12)}
|
|
</a>
|
|
</p>
|
|
)}
|
|
{status?.finishedAt && <p>Last attempt: {status.finishedAt}</p>}
|
|
</div>
|
|
{(error || status?.error) && (
|
|
<p role="alert" className="text-sm">
|
|
{error || status?.error}
|
|
</p>
|
|
)}
|
|
<button
|
|
type="button"
|
|
disabled={!status?.enabled || busy}
|
|
onClick={retry}
|
|
className="rounded-md border border-[var(--admin-border)] px-3 py-2 text-sm disabled:opacity-50"
|
|
>
|
|
{busy ? "Queuing…" : "Export now / retry"}
|
|
</button>
|
|
</section>
|
|
);
|
|
}
|