feat(hk): explain background updates with protected content links and retry details
This commit is contained in:
1 parent
dd7613850e
commit
c5c9941768
42 files changed
+1542
-145
No files matched your search
@@ -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>
|
||||
|
||||
Reference in new issue
Block a user