Update: admin panel fixes, badge icons, studio improvements, gitea runner v5
Gitea Actions Runner Test / test-job (push) Successful in 2s
CI / check (push) Failing after 21s
CI / tests-unit (push) Skipped
CI / tests-integration (push) Skipped
CI / tests-ui (push) Skipped
CI / preflight (push) Skipped
CI / deploy (push) Skipped
Gitea Actions Runner Test / test-job (push) Successful in 2s
CI / check (push) Failing after 21s
CI / tests-unit (push) Skipped
CI / tests-integration (push) Skipped
CI / tests-ui (push) Skipped
CI / preflight (push) Skipped
CI / deploy (push) Skipped
This commit is contained in:
1 parent
afc8909d3f
commit
a06db72c65
7 files changed
+185
-47
No files matched your search
@@ -116,6 +116,7 @@ export default async function AdminBadges({
|
||||
<th>{t("colCode")}</th>
|
||||
<th>{t("colName")}</th>
|
||||
<th>{t("colDescription")}</th>
|
||||
<th>{t("colIcon")}</th>
|
||||
<th />
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -129,6 +130,13 @@ export default async function AdminBadges({
|
||||
<td className="text-sm theme-text-muted dark:theme-text-muted">
|
||||
{b.badgeDescription}
|
||||
</td>
|
||||
<td>
|
||||
<img
|
||||
src={`/assets/images/badges/${b.badgeKey}.gif`}
|
||||
alt={b.badgeName}
|
||||
className="h-6 w-6 object-contain"
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<form
|
||||
action={giveBadge}
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
"use client";
|
||||
|
||||
import { LayoutDashboard, RefreshCw } from "lucide-react";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { useEffect, useState } from "react";
|
||||
import Link from "@/components/link";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { reportBrowserError } from "@/lib/browser-errors";
|
||||
|
||||
/**
|
||||
* Studio error boundary. Renders inside the admin Studio layout shell.
|
||||
* Catches runtime errors in furniture rendering, icon loading, etc.
|
||||
*/
|
||||
export default function StudioErrorPage({
|
||||
error,
|
||||
reset,
|
||||
}: {
|
||||
error: Error & { digest?: string };
|
||||
reset: () => void;
|
||||
}) {
|
||||
const t = useTranslations("pages.error");
|
||||
const tNav = useTranslations("pages.admin.nav");
|
||||
|
||||
const [reference, setReference] = useState(error.digest);
|
||||
useEffect(() => {
|
||||
setReference(error.digest ?? reportBrowserError(error, "studio.boundary"));
|
||||
if (error.digest) reportBrowserError(error, "studio.boundary");
|
||||
}, [error]);
|
||||
|
||||
return (
|
||||
<div
|
||||
className="rounded-xl border p-8 max-w-lg mx-auto mt-8 text-center"
|
||||
style={{
|
||||
borderColor: "var(--admin-border, rgba(0,0,0,0.08))",
|
||||
background: "var(--admin-surface, #fff)",
|
||||
}}
|
||||
role="alert"
|
||||
>
|
||||
<p
|
||||
className="text-sm font-bold uppercase tracking-wider mb-2"
|
||||
style={{ color: "var(--admin-muted, #6b7280)" }}
|
||||
>
|
||||
{t("code")}
|
||||
</p>
|
||||
<h1 className="text-xl font-extrabold mb-2">{t("title")}</h1>
|
||||
<p
|
||||
className="text-sm mb-1"
|
||||
style={{ color: "var(--admin-muted, #6b7280)" }}
|
||||
>
|
||||
{t("subtitle")}
|
||||
</p>
|
||||
<p
|
||||
className="text-sm mb-6"
|
||||
style={{ color: "var(--admin-muted, #6b7280)" }}
|
||||
>
|
||||
{t("body")}
|
||||
</p>
|
||||
<div className="flex flex-wrap gap-3 justify-center">
|
||||
<Button type="button" variant="default" onClick={() => reset()}>
|
||||
<RefreshCw className="size-4" aria-hidden />
|
||||
{t("tryAgain")}
|
||||
</Button>
|
||||
<Button variant="outline" asChild>
|
||||
<Link href="/admin/studio/furni">
|
||||
<LayoutDashboard className="size-4" aria-hidden />
|
||||
{tNav("dashboard")}
|
||||
</Link>
|
||||
</Button>
|
||||
</div>
|
||||
{reference ? (
|
||||
<p
|
||||
className="mt-6 text-xs font-mono"
|
||||
style={{ color: "var(--admin-muted, #9ca3af)" }}
|
||||
>
|
||||
{t("reference", { digest: reference })}
|
||||
</p>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
import { withAdmin } from "@/lib/api-handler";
|
||||
import { purgeEdgeCache } from "@/lib/edge-cache";
|
||||
import { PERMS } from "@/lib/permissions";
|
||||
import { repairMissingIcons } from "@/lib/services/repair-icons";
|
||||
|
||||
@@ -21,6 +22,18 @@ export const POST = withAdmin({ permission: PERMS.ASSETS_IMPORT }, async () => {
|
||||
|
||||
try {
|
||||
await repairMissingIcons(send);
|
||||
// After icon repair, purge the Cloudflare edge cache so updated
|
||||
// icons are immediately visible instead of waiting for the 1-year
|
||||
// s-maxage to expire.
|
||||
try {
|
||||
await purgeEdgeCache(["cms-furni-icons"], "repair-missing-icons");
|
||||
send({ type: "purge", tag: "cms-furni-icons" });
|
||||
} catch (purgeError) {
|
||||
send({
|
||||
type: "error",
|
||||
message: `repairMissingIcons completed but purge failed: ${(purgeError as Error).message}`,
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
send({
|
||||
type: "error",
|
||||
|
||||
Reference in new issue
Block a user