Adopt shared WebUI layout primitives
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import { MetricGrid } from "@govoplan/core-webui";
|
||||
import { useEffect, useState } from "react";
|
||||
import type { ApiSettings } from "@govoplan/core-webui";
|
||||
import { fetchAdminOverview, type AdminOverview } from "../../api/admin";
|
||||
@@ -33,12 +34,12 @@ export default function AdminOverviewPanel({ settings, onSelect, availableSectio
|
||||
{overview && <>
|
||||
{hasSystemMetrics && <>
|
||||
<div className="admin-overview-section-label">i18n:govoplan-admin.system.bc0792d8</div>
|
||||
<div className="metric-grid">
|
||||
<MetricGrid>
|
||||
<Metric title="i18n:govoplan-admin.tenants.1f7ae776" value={overview.tenant_count ?? "—"} text="i18n:govoplan-admin.registered_tenant_spaces.61e17d70" />
|
||||
<Metric title="i18n:govoplan-admin.users.57f2b181" value={overview.system_account_count ?? "—"} text="i18n:govoplan-admin.global_login_accounts_across_all_tenants.2aab129d" />
|
||||
<Metric title="i18n:govoplan-admin.central_groups.5c9b5b66" value={overview.system_group_template_count ?? "—"} text="i18n:govoplan-admin.system_governed_group_definitions.de8e5dc9" />
|
||||
<Metric title="i18n:govoplan-admin.tenant_roles.51aca82d" value={overview.system_role_template_count ?? "—"} text="i18n:govoplan-admin.centrally_governed_tenant_roles.797c689b" />
|
||||
</div>
|
||||
</MetricGrid>
|
||||
</>}
|
||||
|
||||
{hasAnySection(availableSections, platformSectionIds) && <Card title={ADMIN_INTERFACE_I18N.administrationHeading}>
|
||||
@@ -67,12 +68,12 @@ export default function AdminOverviewPanel({ settings, onSelect, availableSectio
|
||||
</Card>}
|
||||
|
||||
<div className="admin-overview-section-label">i18n:govoplan-admin.active_tenant.dfadf0aa {overview.active_tenant_name}</div>
|
||||
<div className="metric-grid">
|
||||
<MetricGrid>
|
||||
<Metric title="i18n:govoplan-admin.tenant_users.cb800b38" value={`${overview.active_user_count}/${overview.user_count}`} text="i18n:govoplan-admin.active_and_total_memberships.c0c20f10" />
|
||||
<Metric title="i18n:govoplan-admin.groups.ae9629f4" value={overview.group_count} text="i18n:govoplan-admin.tenant_local_and_centrally_managed_groups.4a6296b5" />
|
||||
<Metric title="i18n:govoplan-admin.roles.47dcc27d" value={overview.role_count} text="i18n:govoplan-admin.tenant_local_and_centrally_managed_roles.4995a7b2" />
|
||||
<Metric title="i18n:govoplan-admin.api_keys.94fcf3c2" value={overview.active_api_key_count} text="i18n:govoplan-admin.active_tenant_automation_credentials.240c659e" />
|
||||
</div>
|
||||
</MetricGrid>
|
||||
|
||||
{hasAnySection(availableSections, tenantSectionIds) && <Card title={ADMIN_INTERFACE_I18N.tenantHeading}>
|
||||
<div className="admin-overview-grid">
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { DescriptionItem, DescriptionList } from "@govoplan/core-webui";
|
||||
import { MetricGrid } from "@govoplan/core-webui";
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import { Download, Eye, Play, Plus, RefreshCw, Search, ShieldCheck } from "lucide-react";
|
||||
import type { FormGrid, ApiSettings, DataGridColumn } from "@govoplan/core-webui";
|
||||
@@ -343,21 +345,21 @@ export default function DataSubjectRequestsPanel({
|
||||
</div>
|
||||
|
||||
{selected ? <>
|
||||
<div className="metric-grid">
|
||||
<MetricGrid>
|
||||
<MetricCard label={I18N.records} value={selected.request.record_count} tone="info" />
|
||||
<MetricCard label={I18N.executable} value={selected.request.executable_action_count} tone={selected.request.executable_action_count ? "warning" : "neutral"} />
|
||||
<MetricCard label={I18N.uncovered} value={coverageGaps.length} tone={coverageGaps.length ? "warning" : "good"} />
|
||||
</div>
|
||||
</MetricGrid>
|
||||
|
||||
<Card title={selected.request.reference}>
|
||||
<dl className="admin-details-grid">
|
||||
<div><dt>{I18N.subject}</dt><dd>{subjectLabel(selected.request)}</dd></div>
|
||||
<div><dt>{I18N.kindLabel}</dt><dd>{selected.request.request_kind}</dd></div>
|
||||
<div><dt>{I18N.statusLabel}</dt><dd><StatusBadge status={statusTone(selected.request.status)} label={selected.request.status} /></dd></div>
|
||||
<div><dt>{I18N.due}</dt><dd>{selected.request.due_at ? formatDateTime(selected.request.due_at) : "-"}</dd></div>
|
||||
<div><dt>{I18N.purpose}</dt><dd>{selected.request.purpose}</dd></div>
|
||||
<div><dt>{I18N.legalBasis}</dt><dd>{selected.request.legal_basis || "-"}</dd></div>
|
||||
</dl>
|
||||
<DescriptionList>
|
||||
<DescriptionItem term={<>{I18N.subject}</>}>{subjectLabel(selected.request)}</DescriptionItem>
|
||||
<DescriptionItem term={<>{I18N.kindLabel}</>}>{selected.request.request_kind}</DescriptionItem>
|
||||
<DescriptionItem term={<>{I18N.statusLabel}</>}><StatusBadge status={statusTone(selected.request.status)} label={selected.request.status} /></DescriptionItem>
|
||||
<DescriptionItem term={<>{I18N.due}</>}>{selected.request.due_at ? formatDateTime(selected.request.due_at) : "-"}</DescriptionItem>
|
||||
<DescriptionItem term={<>{I18N.purpose}</>}>{selected.request.purpose}</DescriptionItem>
|
||||
<DescriptionItem term={<>{I18N.legalBasis}</>}>{selected.request.legal_basis || "-"}</DescriptionItem>
|
||||
</DescriptionList>
|
||||
<div className="button-row">
|
||||
<Button onClick={() => void mutate((request) => searchDataSubjectRequest(settings, request), I18N.searchComplete)} disabled={!canManage || busy}><Search size={16} /> {I18N.runSearch}</Button>
|
||||
{selected.request.request_kind !== "access" && <Button onClick={() => void mutate((request) => planDataSubjectErasure(settings, request), I18N.planComplete)} disabled={!canManage || busy || !selected.search.searched_at}><ShieldCheck size={16} /> {I18N.plan}</Button>}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { DescriptionItem, DescriptionList } from "@govoplan/core-webui";
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import { Search, Pencil, Plus, Trash2 } from "lucide-react";
|
||||
import type { FormGrid, ApiSettings } from "@govoplan/core-webui";
|
||||
@@ -240,7 +241,7 @@ export default function GovernanceTemplatesPanel({
|
||||
</Dialog>
|
||||
|
||||
<Dialog variant="administration" size="wide" open={Boolean(viewing)} title={viewing?.name || "i18n:govoplan-admin.template_details.d5d75e4d"} onClose={() => setViewing(null)} className="" footer={<Button onClick={() => setViewing(null)}>i18n:govoplan-admin.close.bbfa773e</Button>}>
|
||||
{viewing && <dl className="admin-details-grid"><div><dt>i18n:govoplan-admin.kind.e00ac23f</dt><dd>{viewing.kind}</dd></div><div><dt>i18n:govoplan-admin.slug.094da9b9</dt><dd>{viewing.slug}</dd></div><div><dt>i18n:govoplan-admin.status.bae7d5be</dt><dd>{viewing.is_active ? "i18n:govoplan-admin.active.a733b809" : "i18n:govoplan-admin.inactive.09af574c"}</dd></div><div><dt>i18n:govoplan-admin.tenants.1f7ae776</dt><dd>{viewing.assignments.length || "i18n:govoplan-admin.none.6eef6648"}</dd></div><div><dt>i18n:govoplan-admin.description.55f8ebc8</dt><dd>{viewing.description || "—"}</dd></div><div><dt>i18n:govoplan-admin.permissions.d06d5557</dt><dd>{viewing.permissions.length ? <PermissionDetails scopes={viewing.permissions} permissionsByScope={permissionsByScope} /> : "—"}</dd></div></dl>}
|
||||
{viewing && <DescriptionList><DescriptionItem term={<>i18n:govoplan-admin.kind.e00ac23f</>}>{viewing.kind}</DescriptionItem><DescriptionItem term={<>i18n:govoplan-admin.slug.094da9b9</>}>{viewing.slug}</DescriptionItem><DescriptionItem term={<>i18n:govoplan-admin.status.bae7d5be</>}>{viewing.is_active ? "i18n:govoplan-admin.active.a733b809" : "i18n:govoplan-admin.inactive.09af574c"}</DescriptionItem><DescriptionItem term={<>i18n:govoplan-admin.tenants.1f7ae776</>}>{viewing.assignments.length || "i18n:govoplan-admin.none.6eef6648"}</DescriptionItem><DescriptionItem term={<>i18n:govoplan-admin.description.55f8ebc8</>}>{viewing.description || "—"}</DescriptionItem><DescriptionItem term={<>i18n:govoplan-admin.permissions.d06d5557</>}>{viewing.permissions.length ? <PermissionDetails scopes={viewing.permissions} permissionsByScope={permissionsByScope} /> : "—"}</DescriptionItem></DescriptionList>}
|
||||
</Dialog>
|
||||
|
||||
<ConfirmDialog open={Boolean(deleting)} title={kind === "group" ? "i18n:govoplan-admin.delete_group_template.8745d842" : "i18n:govoplan-admin.delete_tenant_role.4efa0813"} message={i18nMessage("i18n:govoplan-admin.delete_value_removal_is_blocked_while_a_material.d4eba73d", { value0: deleting?.name })} confirmLabel={kind === "group" ? "i18n:govoplan-admin.delete_template.399bf72a" : "i18n:govoplan-admin.delete_tenant_role.4efa0813"} tone="danger" busy={busy} onCancel={() => setDeleting(null)} onConfirm={() => void remove()} />
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { MetricGrid } from "@govoplan/core-webui";
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import type { ActionToolbar, ApiSettings } from "@govoplan/core-webui";
|
||||
import { ActionBlockerHint, AdminPageLayout, adminErrorMessage, Button, ConfirmDialog, dispatchPlatformModulesChanged, DocumentationHelpLink, formatDateTime, MetricCard, SegmentedControl, StageRail, StatusBadge, ToggleSwitch, i18nMessage, useUnsavedDraftGuard, type FormatDateTimeOptions } from "@govoplan/core-webui";
|
||||
@@ -407,13 +408,13 @@ export default function ModuleManagementPanel({ settings, canWrite, canAccessMai
|
||||
actions={<><DocumentationHelpLink reference={MODULE_LIFECYCLE_DOCUMENTATION} /><Button onClick={() => void load()} disabled={loading || busy} disabledReason={loading ? ADMIN_INTERFACE_I18N.loading : busy ? ADMIN_INTERFACE_I18N.busy : undefined}>i18n:govoplan-admin.reload.cce71553</Button><Button variant="primary" onClick={() => void save()} disabled={saveDisabled} disabledReason={saveDisabledReason}>{busy ? "i18n:govoplan-admin.working.049ac820" : saveLabel}</Button></>}>
|
||||
|
||||
{catalog && <>
|
||||
<div className="metric-grid module-management-metrics">
|
||||
<MetricGrid columns={5} minimum="compact">
|
||||
<MetricCard label="i18n:govoplan-admin.installed.7bb4405c" value={catalog.modules.length} detail="i18n:govoplan-admin.discovered_packages.660902de" tone="info" />
|
||||
<MetricCard label="i18n:govoplan-admin.active.a733b809" value={activeCount} detail="i18n:govoplan-admin.running_registry.5274b24b" tone="info" />
|
||||
<MetricCard label="i18n:govoplan-admin.saved.c0ae8f6e" value={desiredCount} detail="i18n:govoplan-admin.startup_state.d1300be6" tone="info" />
|
||||
<MetricCard label="i18n:govoplan-admin.drift.4876f7b9" value={pendingCount} detail={pendingCount ? "i18n:govoplan-admin.runtime_differs.43d1fd78" : "i18n:govoplan-admin.runtime_matches.a84afa48"} tone={pendingCount ? "warning" : "good"} />
|
||||
<MetricCard label="i18n:govoplan-admin.maintenance.94de303b" value={maintenanceEnabled ? "i18n:govoplan-admin.on.e0049a66" : "i18n:govoplan-admin.off.e3de5ab0"} detail={canAccessMaintenance ? "i18n:govoplan-admin.bypass_allowed.4e347c27" : "i18n:govoplan-admin.bypass_denied.ab987400"} tone={maintenanceEnabled ? "warning" : "info"} />
|
||||
</div>
|
||||
</MetricGrid>
|
||||
|
||||
<StageRail
|
||||
className="module-installer-stage-rail"
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { MetricGrid } from "@govoplan/core-webui";
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import {
|
||||
AdminPageLayout,
|
||||
@@ -249,12 +250,12 @@ export default function TenantModuleManagementPanel({ settings, scope, canWrite
|
||||
|
||||
{state && draft && (
|
||||
<>
|
||||
<div className="metric-grid module-management-metrics">
|
||||
<MetricGrid columns={5} minimum="compact">
|
||||
<MetricCard label="Available" value={draft.available.size} tone="info" />
|
||||
<MetricCard label="Forced" value={draft.forced.size} tone="warning" />
|
||||
<MetricCard label="Selected" value={draft.enabled.size} />
|
||||
<MetricCard label="Effective now" value={state.effective_modules.length} tone="good" />
|
||||
</div>
|
||||
</MetricGrid>
|
||||
|
||||
{state.diagnostics.map((diagnostic) => (
|
||||
<DismissibleAlert key={`${diagnostic.code}:${diagnostic.message}`} tone="warning" compact>
|
||||
|
||||
Reference in New Issue
Block a user