feat(admin): server-safe StatusCard and Import hub polish
CI / check (push) Failing after 8s
CI / release (push) Skipped
CI / deploy (push) Skipped

Split OnlineUsersWidget from StatusCard, decouple ad delete button, sync badge import to ExternalTexts+WebsiteBadges, add Import section hub with cancelable SSE jobs and upload SQL option.

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
SimoandCursor committed 2026-08-01 15:48:21 +02:00
1 parent db957d7fb1
commit 9c4949186c
21 files changed
+576 -249

No files matched your search

+9 -25
View File
@@ -5,6 +5,7 @@ import { apiError, apiOk } from "@/lib/api-response";
import { PERMS } from "@/lib/permissions";
import { logAudit } from "@/lib/services/audit";
import { searchBadges } from "@/lib/services/habboassets";
import { importBadgeSynced } from "@/lib/services/import-badge";
const EXTERNAL_TEXTS_PATH = path.join(
process.cwd(),
@@ -52,7 +53,7 @@ export const GET = withAdmin(
},
);
// ── Import a single badge ───────────────────────────────────────────
// ── Import a single badge (ExternalTexts + WebsiteBadges) ───────────
export const POST = withAdmin(
{ permission: PERMS.ASSETS_IMPORT },
async (request, ctx) => {
@@ -61,31 +62,14 @@ export const POST = withAdmin(
if (!code || !name) return apiError("Missing code or name", 400);
try {
const raw = await fs.readFile(EXTERNAL_TEXTS_PATH, "utf-8");
const texts = JSON.parse(raw);
const result = await importBadgeSynced({
code,
name,
description: description || "",
});
const nameKey = `badge_name_${code}`;
const descKey = `badge_desc_${code}`;
if (texts[nameKey] !== undefined) {
return apiError("Badge already exists in ExternalTexts.json", 409);
}
texts[nameKey] = name;
texts[descKey] = description || "";
await fs.writeFile(
EXTERNAL_TEXTS_PATH,
JSON.stringify(texts, null, 4),
"utf-8",
);
} catch (err) {
console.warn(
"[import-badges] Failed to update ExternalTexts.json:",
(err as Error).message,
);
return apiError("Failed to update ExternalTexts.json", 500);
if (!result.ok) {
return apiError(result.error, result.status);
}
logAudit({