Adopt shared WebUI layout primitives
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
|
import { MetricGrid } from "@govoplan/core-webui";
|
||||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||||
import { Eye, GitCompareArrows, Play, RefreshCw, X } from "lucide-react";
|
import { Eye, GitCompareArrows, Play, RefreshCw, X } from "lucide-react";
|
||||||
import { ActionToolbar,
|
import { ActionToolbar,
|
||||||
@@ -179,12 +180,12 @@ export default function OrganizationTemplateUpgradePanel({ settings, auth }: { s
|
|||||||
{success && <DismissibleAlert tone="success" resetKey={success}>{success}</DismissibleAlert>}
|
{success && <DismissibleAlert tone="success" resetKey={success}>{success}</DismissibleAlert>}
|
||||||
<Card title="Organization template upgrades" actions={<Button onClick={() => void load()} disabled={loading || busy}><RefreshCw aria-hidden="true" /> Reload</Button>}>
|
<Card title="Organization template upgrades" actions={<Button onClick={() => void load()} disabled={loading || busy}><RefreshCw aria-hidden="true" /> Reload</Button>}>
|
||||||
<LoadingFrame loading={loading} label="Loading organization template upgrade state">
|
<LoadingFrame loading={loading} label="Loading organization template upgrade state">
|
||||||
<div className="metric-grid compact">
|
<MetricGrid density="compact">
|
||||||
<MetricCard label="Applied version" value={currentVersion?.version ?? "Custom model"} tone="info" />
|
<MetricCard label="Applied version" value={currentVersion?.version ?? "Custom model"} tone="info" />
|
||||||
<MetricCard label="Available upgrades" value={targets.length} tone={targets.length ? "info" : "good"} />
|
<MetricCard label="Available upgrades" value={targets.length} tone={targets.length ? "info" : "good"} />
|
||||||
<MetricCard label="Open previews" value={pending.length} tone={pending.length ? "warning" : "good"} />
|
<MetricCard label="Open previews" value={pending.length} tone={pending.length ? "warning" : "good"} />
|
||||||
<MetricCard label="Copy semantics" value="Tenant-owned" tone="good" />
|
<MetricCard label="Copy semantics" value="Tenant-owned" tone="good" />
|
||||||
</div>
|
</MetricGrid>
|
||||||
<p className="muted small-note">Template versions are immutable sources. A tenant model never live-inherits changes: every upgrade is a recorded three-way comparison, explicit decision set, and confirmed new instantiation.</p>
|
<p className="muted small-note">Template versions are immutable sources. A tenant model never live-inherits changes: every upgrade is a recorded three-way comparison, explicit decision set, and confirmed new instantiation.</p>
|
||||||
<ActionToolbar className="organization-upgrade-toolbar">
|
<ActionToolbar className="organization-upgrade-toolbar">
|
||||||
<FormField label="Published target version"><select value={targetVersionId} disabled={!canWrite || busy || !targets.length} onChange={(event) => setTargetVersionId(event.target.value)}>{targets.length ? targets.map((version) => <option key={version.id} value={version.id}>{templateVersionLabel(templates, version)}</option>) : <option value="">No newer published version</option>}</select></FormField>
|
<FormField label="Published target version"><select value={targetVersionId} disabled={!canWrite || busy || !targets.length} onChange={(event) => setTargetVersionId(event.target.value)}>{targets.length ? targets.map((version) => <option key={version.id} value={version.id}>{templateVersionLabel(templates, version)}</option>) : <option value="">No newer published version</option>}</select></FormField>
|
||||||
@@ -196,12 +197,12 @@ export default function OrganizationTemplateUpgradePanel({ settings, auth }: { s
|
|||||||
|
|
||||||
<Dialog open={Boolean(selected)} title="Organization model upgrade preview" className="organization-upgrade-dialog" onClose={() => !busy && setSelected(null)} closeDisabled={busy} footer={<><Button onClick={() => setSelected(null)} disabled={busy}>Close</Button>{selected?.status === "previewed" && <><Button variant="danger" onClick={() => setCancelTarget(selected)} disabled={!canWrite || busy}>Cancel preview</Button><Button variant="primary" onClick={() => setApplyConfirmation(true)} disabled={applyDisabled}><Play aria-hidden="true" /> Review and apply</Button></>}</>}>
|
<Dialog open={Boolean(selected)} title="Organization model upgrade preview" className="organization-upgrade-dialog" onClose={() => !busy && setSelected(null)} closeDisabled={busy} footer={<><Button onClick={() => setSelected(null)} disabled={busy}>Close</Button>{selected?.status === "previewed" && <><Button variant="danger" onClick={() => setCancelTarget(selected)} disabled={!canWrite || busy}>Cancel preview</Button><Button variant="primary" onClick={() => setApplyConfirmation(true)} disabled={applyDisabled}><Play aria-hidden="true" /> Review and apply</Button></>}</>}>
|
||||||
{selected && <>
|
{selected && <>
|
||||||
<div className="metric-grid compact">
|
<MetricGrid density="compact">
|
||||||
<MetricCard label="Changes" value={selected.preview.entries.length} tone="info" />
|
<MetricCard label="Changes" value={selected.preview.entries.length} tone="info" />
|
||||||
<MetricCard label="Required decisions" value={selected.preview.requires_decisions} tone={selected.preview.requires_decisions ? "warning" : "good"} />
|
<MetricCard label="Required decisions" value={selected.preview.requires_decisions} tone={selected.preview.requires_decisions ? "warning" : "good"} />
|
||||||
<MetricCard label="Invalid references" value={selected.preview.blocking_invalid_references} tone={selected.preview.blocking_invalid_references ? "danger" : "good"} />
|
<MetricCard label="Invalid references" value={selected.preview.blocking_invalid_references} tone={selected.preview.blocking_invalid_references ? "danger" : "good"} />
|
||||||
<MetricCard label="Status" value={humanize(selected.status)} tone="info" />
|
<MetricCard label="Status" value={humanize(selected.status)} tone="info" />
|
||||||
</div>
|
</MetricGrid>
|
||||||
<p className="muted small-note">Compatible additions and non-conflicting changes apply automatically. Local-only divergence is preserved. Destructive remapping and competing edits require an explicit bounded decision.</p>
|
<p className="muted small-note">Compatible additions and non-conflicting changes apply automatically. Local-only divergence is preserved. Destructive remapping and competing edits require an explicit bounded decision.</p>
|
||||||
<div className="organization-upgrade-diff"><DataGrid id={`organization-model-upgrade-diff-${selected.id}`} rows={selected.preview.entries} columns={diffColumns} initialFit="container" getRowKey={(row) => row.id} emptyText="The versions and tenant model are equivalent." /></div>
|
<div className="organization-upgrade-diff"><DataGrid id={`organization-model-upgrade-diff-${selected.id}`} rows={selected.preview.entries} columns={diffColumns} initialFit="container" getRowKey={(row) => row.id} emptyText="The versions and tenant model are equivalent." /></div>
|
||||||
<FormField label="Approved change request (when required by tenant policy)"><input value={changeRequestId} disabled={!canWrite || busy || selected.status !== "previewed"} onChange={(event) => setChangeRequestId(event.target.value)} /></FormField>
|
<FormField label="Approved change request (when required by tenant policy)"><input value={changeRequestId} disabled={!canWrite || busy || selected.status !== "previewed"} onChange={(event) => setChangeRequestId(event.target.value)} /></FormField>
|
||||||
|
|||||||
Reference in New Issue
Block a user