feat(hk): explain background updates with protected content links and retry details
CI / check (push) Failing after 1m34s
CI / deploy (push) Skipped
CI / publish-container (push) Skipped

This commit is contained in:
Simo committed 2026-09-13 19:41:25 +02:00
1 parent dd7613850e
commit c5c9941768
42 files changed
+1542 -145

No files matched your search

+49 -26
View File
@@ -1,6 +1,8 @@
import { redirect } from "next/navigation";
import { getTranslations } from "next-intl/server";
import Link from "@/components/link";
import { DeliveryCard } from "@/features/operations/delivery-card";
import { deliveryContext } from "@/features/operations/delivery-context";
import { DeliveryRetry } from "@/features/operations/retry-button";
import { listEffects } from "@/features/operations/server";
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
@@ -9,41 +11,62 @@ export default async function DeliveryPage() {
if (!canAccess(permissions, PERMS.DEVOPS_VIEW, session.user.rank))
redirect("/admin");
const editable = canAccess(permissions, PERMS.DEVOPS_EDIT, session.user.rank);
const access = {
news: canAccess(permissions, PERMS.NEWS_VIEW, session.user.rank),
catalog: canAccess(permissions, PERMS.CATALOG_VIEW, session.user.rank),
};
const t = await getTranslations("pages.admin.deliveries");
const items = await listEffects();
let items: Awaited<ReturnType<typeof listEffects>> | null = null;
try {
items = await listEffects();
} catch {
/* Preserve the distinction between unavailable and empty history. */
}
const timestamp = (value: Date | string) =>
value instanceof Date ? value.toISOString() : value;
return (
<section className="min-w-0 space-y-4">
<h1 className="text-2xl font-semibold">{t("title")}</h1>
<p className="text-muted-foreground">{t("scope")}</p>
<Link href="/admin/devops/deliveries" className="btn btn-outline">
{t("refresh")}
</Link>
{!items.length ? (
<div className="flex flex-wrap gap-3">
<Link href="/admin/devops/deliveries" className="btn btn-outline">
{t("refresh")}
</Link>
{canAccess(permissions, PERMS.ASSETS_IMPORT, session.user.rank) && (
<Link href="/admin/operations" className="btn btn-outline">
{t("openImports")}
</Link>
)}
</div>
{items === null ? (
<p role="alert" className="admin-card">
{t("unavailable")}
</p>
) : !items.length ? (
<p className="admin-card">{t("empty")}</p>
) : (
<ul className="space-y-3">
{items.map((item) => (
<li key={item.id} className="admin-card min-w-0 space-y-2">
<div className="flex flex-wrap justify-between gap-3">
<strong>
{t(
item.topic === "catalog.refresh"
? "hotel"
: item.topic === "news.refresh"
? "news"
: "export",
)}
</strong>
<span>{t(`states.${item.status}`)}</span>
</div>
<p className="break-all text-sm">
{item.operationId} · {t("actor", { id: item.actorId })} ·{" "}
{t("attempts", { count: item.attempts })}
</p>
{item.status === "failed" && <p>{t("retryError")}</p>}
{editable && item.status === "failed" && (
<DeliveryRetry id={item.id} />
)}
<li key={item.id}>
<DeliveryCard
item={{
id: item.id,
operationId: item.operationId,
topic: item.topic,
status: item.status,
attempts: item.attempts,
actorId: item.actorId,
createdAt: timestamp(item.createdAt),
availableAt: timestamp(item.availableAt),
hasError: !!item.lastError,
context: deliveryContext(item.kind, item.resultJson, access),
}}
retry={
editable && item.status === "failed" ? (
<DeliveryRetry id={item.id} />
) : undefined
}
/>
</li>
))}
</ul>