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

This commit is contained in:
openhands committed 2026-10-11 18:44:02 +02:00
1 parent afc8909d3f
commit a06db72c65
7 files changed
+185 -47

No files matched your search

+8
View File
@@ -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}
+80
View File
@@ -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",