This commit is contained in:
2026-08-16 18:36:56 +02:00
parent d981147ff2
commit a94a5aaad7
26 changed files with 904 additions and 507 deletions
+42 -39
View File
@@ -11,7 +11,7 @@
STAFF_ROLE_OPTIONS,
assignAdminPlan,
cloneAdminCompanyCatalog,
fixAdminCompanyCatalog,
syncAdminCompanyA1,
companyPlanBadge,
isStaffRoleApiUnavailable,
listAdminCompanies,
@@ -55,7 +55,7 @@
TabsList,
TabsTrigger
} from "$lib/components/ui";
import { Building2, Copy, KeyRound, Search, Shield, UserPlus, Users, Wrench } from "@lucide/svelte";
import { Building2, Copy, KeyRound, RefreshCw, Search, Shield, UserPlus, Users } from "@lucide/svelte";
type TabKey = "users" | "companies";
@@ -94,8 +94,8 @@
let cloneOpen = $state(false);
let cloneCompany = $state<AdminOrgCompany | null>(null);
let fixOpen = $state(false);
let fixCompany = $state<AdminOrgCompany | null>(null);
let syncOpen = $state(false);
let syncCompany = $state<AdminOrgCompany | null>(null);
const usersPage = $derived(Math.floor(usersOffset / PAGE_SIZE) + 1);
const usersPages = $derived(Math.max(1, Math.ceil(usersTotal / PAGE_SIZE)));
@@ -366,28 +366,29 @@
success = "";
}
function openFixDialog(company: AdminOrgCompany) {
fixCompany = company;
fixOpen = true;
function openSyncDialog(company: AdminOrgCompany) {
syncCompany = company;
syncOpen = true;
error = "";
success = "";
}
async function confirmFixCatalog() {
if (!fixCompany) return;
async function confirmSyncA1() {
if (!syncCompany) return;
busy = true;
error = "";
success = "";
const targetName = fixCompany.name;
const targetName = syncCompany.name;
try {
const res = await fixAdminCompanyCatalog(fixCompany.id, {
const res = await syncAdminCompanyA1(syncCompany.id, {
reprocessSampleLimit: 25
});
const r = res.result;
const mappedWith = Number(r.mapped_with_category ?? 0);
const mappedWithout = Number(r.mapped_without_category ?? 0);
const mappedTotal = mappedWith + mappedWithout;
success = i18n.t("flash.admin.fixA1Success", {
const dumpStatus = String(r.dump_status ?? (r.dump_found ? "ok" : "missing"));
success = i18n.t("flash.admin.syncA1Success", {
name: targetName,
prompts: String(r.prompts ?? r.category_prompts_updated ?? 0),
hashes: String(r.hashes ?? r.weak_hashes_cleared ?? 0),
@@ -395,12 +396,14 @@
mapped_backfilled: String(r.mapped_backfilled ?? r.mapped_categories_backfilled ?? 0),
mapped_with: String(mappedWith),
mapped_total: String(mappedTotal),
taxonomy: String(r.taxonomy_categories ?? 0)
taxonomy: String(r.taxonomy_categories ?? 0),
dump_mapped: String(r.dump_mapped_updated ?? 0),
dump_status: dumpStatus
});
fixOpen = false;
fixCompany = null;
syncOpen = false;
syncCompany = null;
} catch (err) {
error = failureMessage(err, i18n.t("flash.admin.fixA1Error", { name: targetName }));
error = failureMessage(err, i18n.t("flash.admin.syncA1Error", { name: targetName }));
} finally {
busy = false;
}
@@ -827,18 +830,18 @@
<TableCell class="hidden text-muted-foreground lg:table-cell">{company.language || "—"}</TableCell>
<TableCell stickyRight>
<div class="flex flex-wrap items-center justify-end gap-1">
<Button
size="sm"
variant="outline"
onclick={() => openFixDialog(company)}
aria-label={i18n.t("admin.users.fixA1Aria", {
name: company.name
})}
data-testid="admin-fix-catalog"
>
<Wrench class="h-3.5 w-3.5 lg:mr-1" aria-hidden="true" />
<span class="hidden lg:inline">{i18n.t("admin.users.fixA1")}</span>
</Button>
<Button
size="sm"
variant="outline"
onclick={() => openSyncDialog(company)}
aria-label={i18n.t("admin.users.syncA1Aria", {
name: company.name
})}
data-testid="admin-sync-a1"
>
<RefreshCw class="h-3.5 w-3.5 lg:mr-1" aria-hidden="true" />
<span class="hidden lg:inline">{i18n.t("admin.users.syncA1")}</span>
</Button>
<Button
size="sm"
variant="outline"
@@ -1021,21 +1024,21 @@
</Dialog>
<Dialog
bind:open={fixOpen}
title={i18n.t("admin.users.fixA1Title")}
description={i18n.t("admin.users.fixA1Desc")}
bind:open={syncOpen}
title={i18n.t("admin.users.syncA1Title")}
description={i18n.t("admin.users.syncA1Desc")}
>
<div class="space-y-4">
{#if error}
<p class="text-sm text-destructive" role="alert">{error}</p>
{/if}
{#if fixCompany}
{#if syncCompany}
<p class="text-sm text-foreground">
{i18n.t("admin.users.fixA1Company", { name: fixCompany.name })}
{i18n.t("admin.users.syncA1Company", { name: syncCompany.name })}
</p>
{/if}
<p class="text-sm text-muted-foreground">
{i18n.t("admin.users.fixA1Warning")}
{i18n.t("admin.users.syncA1Warning")}
</p>
<div class="flex flex-wrap justify-end gap-2">
<Button
@@ -1043,14 +1046,14 @@
variant="outline"
disabled={busy}
onclick={() => {
fixOpen = false;
fixCompany = null;
syncOpen = false;
syncCompany = null;
}}
>
{i18n.t("admin.users.fixA1Cancel")}
{i18n.t("admin.users.syncA1Cancel")}
</Button>
<Button type="button" loading={busy} onclick={() => confirmFixCatalog()}>
{i18n.t("admin.users.fixA1Confirm")}
<Button type="button" loading={busy} onclick={() => confirmSyncA1()}>
{i18n.t("admin.users.syncA1Confirm")}
</Button>
</div>
</div>