Adopt shared WebUI layout primitives
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
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 {
|
import { ActionToolbar,
|
||||||
Button,
|
Button,
|
||||||
Card,
|
Card,
|
||||||
ConfirmDialog,
|
ConfirmDialog,
|
||||||
@@ -186,10 +186,10 @@ export default function OrganizationTemplateUpgradePanel({ settings, auth }: { s
|
|||||||
<MetricCard label="Copy semantics" value="Tenant-owned" tone="good" />
|
<MetricCard label="Copy semantics" value="Tenant-owned" tone="good" />
|
||||||
</div>
|
</div>
|
||||||
<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>
|
||||||
<div 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>
|
||||||
<Button variant="primary" onClick={() => void createPreview()} disabled={!canWrite || busy || !targetVersionId}><GitCompareArrows aria-hidden="true" /> Create preview</Button>
|
<Button variant="primary" onClick={() => void createPreview()} disabled={!canWrite || busy || !targetVersionId}><GitCompareArrows aria-hidden="true" /> Create preview</Button>
|
||||||
</div>
|
</ActionToolbar>
|
||||||
<div className="organization-upgrade-table"><DataGrid id="organization-model-upgrades" rows={upgrades} columns={upgradeColumns} initialFit="container" getRowKey={(row) => row.id} emptyText={current ? "No organization template upgrades have been previewed." : "This tenant model was not instantiated from a system template."} /></div>
|
<div className="organization-upgrade-table"><DataGrid id="organization-model-upgrades" rows={upgrades} columns={upgradeColumns} initialFit="container" getRowKey={(row) => row.id} emptyText={current ? "No organization template upgrades have been previewed." : "This tenant model was not instantiated from a system template."} /></div>
|
||||||
</LoadingFrame>
|
</LoadingFrame>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import {
|
import { ContentGrid, FormGrid,
|
||||||
ActionBlockerHint,
|
ActionBlockerHint,
|
||||||
AdminPageLayout,
|
AdminPageLayout,
|
||||||
Button,
|
Button,
|
||||||
@@ -154,7 +154,7 @@ export default function OrganizationsAdminPanel({ settings, auth }: { settings:
|
|||||||
documentation={ORGANIZATIONS_DOCUMENTATION}
|
documentation={ORGANIZATIONS_DOCUMENTATION}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<div className="organizations-settings-grid">
|
<ContentGrid columns={1}>
|
||||||
<Card title="i18n:govoplan-organizations.model_governance.6aa18fd0">
|
<Card title="i18n:govoplan-organizations.model_governance.6aa18fd0">
|
||||||
<div className="settings-list">
|
<div className="settings-list">
|
||||||
<ToggleSwitch
|
<ToggleSwitch
|
||||||
@@ -176,7 +176,7 @@ export default function OrganizationsAdminPanel({ settings, auth }: { settings:
|
|||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
<Card title="i18n:govoplan-organizations.audit_and_retention.3ba1d2fc">
|
<Card title="i18n:govoplan-organizations.audit_and_retention.3ba1d2fc">
|
||||||
<div className="admin-form-grid two-columns">
|
<FormGrid columns={2} gap="small" collapseAt="workspace" className="">
|
||||||
<FormField
|
<FormField
|
||||||
label="i18n:govoplan-organizations.audit_detail_level.7397355d"
|
label="i18n:govoplan-organizations.audit_detail_level.7397355d"
|
||||||
help={organizationWriteReason(canWrite, busy, "settings")}
|
help={organizationWriteReason(canWrite, busy, "settings")}
|
||||||
@@ -200,10 +200,10 @@ export default function OrganizationsAdminPanel({ settings, auth }: { settings:
|
|||||||
onChange={(event) => setDraft({ ...draft, change_retention_days: event.target.value === "" ? null : Math.max(0, Number(event.target.value)) })}
|
onChange={(event) => setDraft({ ...draft, change_retention_days: event.target.value === "" ? null : Math.max(0, Number(event.target.value)) })}
|
||||||
/>
|
/>
|
||||||
</FormField>
|
</FormField>
|
||||||
</div>
|
</FormGrid>
|
||||||
<p className="muted small-note">i18n:govoplan-organizations.audit_retention_help.42dec57d</p>
|
<p className="muted small-note">i18n:govoplan-organizations.audit_retention_help.42dec57d</p>
|
||||||
</Card>
|
</Card>
|
||||||
</div>
|
</ContentGrid>
|
||||||
<OrganizationTemplateUpgradePanel settings={settings} auth={auth} />
|
<OrganizationTemplateUpgradePanel settings={settings} auth={auth} />
|
||||||
</AdminPageLayout>
|
</AdminPageLayout>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useCallback, useEffect, useMemo, useRef, useState, type FormEvent } from "react";
|
import { useCallback, useEffect, useMemo, useRef, useState, type FormEvent } from "react";
|
||||||
import { Edit3, Plus, RefreshCw } from "lucide-react";
|
import { Edit3, Plus, RefreshCw } from "lucide-react";
|
||||||
import {
|
import { FormLayout, ActionToolbar,
|
||||||
ActionBlockerHint,
|
ActionBlockerHint,
|
||||||
AdminIconButton,
|
AdminIconButton,
|
||||||
ApiError,
|
ApiError,
|
||||||
@@ -1004,7 +1004,7 @@ export default function OrganizationsPage({
|
|||||||
<PageTitle loading={loading}>{title}</PageTitle>
|
<PageTitle loading={loading}>{title}</PageTitle>
|
||||||
<p>{description}</p>
|
<p>{description}</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="organizations-toolbar">
|
<ActionToolbar className="organizations-toolbar">
|
||||||
<DocumentationHelpLink reference={ORGANIZATIONS_DOCUMENTATION} />
|
<DocumentationHelpLink reference={ORGANIZATIONS_DOCUMENTATION} />
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
@@ -1015,7 +1015,7 @@ export default function OrganizationsPage({
|
|||||||
>
|
>
|
||||||
<RefreshCw size={16} aria-hidden="true" /> i18n:govoplan-organizations.reload.cce71553
|
<RefreshCw size={16} aria-hidden="true" /> i18n:govoplan-organizations.reload.cce71553
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</ActionToolbar>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{error && <DismissibleAlert tone="danger" resetKey={error} floating>{error}</DismissibleAlert>}
|
{error && <DismissibleAlert tone="danger" resetKey={error} floating>{error}</DismissibleAlert>}
|
||||||
@@ -1086,9 +1086,9 @@ export default function OrganizationsPage({
|
|||||||
return (
|
return (
|
||||||
<div className="organizations-table-stack">
|
<div className="organizations-table-stack">
|
||||||
<Card title="i18n:govoplan-organizations.organization_tree.e5bfb195" actions={<AdminIconButton label="i18n:govoplan-organizations.add_root_unit.1ef8a9f5" icon={<Plus size={16} aria-hidden="true" />} variant="primary" disabled={!canWriteUnits || busy} disabledReason={organizationWriteReason(canWriteUnits, busy, "unit")} onClick={() => openUnitCreate()} />}>
|
<Card title="i18n:govoplan-organizations.organization_tree.e5bfb195" actions={<AdminIconButton label="i18n:govoplan-organizations.add_root_unit.1ef8a9f5" icon={<Plus size={16} aria-hidden="true" />} variant="primary" disabled={!canWriteUnits || busy} disabledReason={organizationWriteReason(canWriteUnits, busy, "unit")} onClick={() => openUnitCreate()} />}>
|
||||||
<div className="explorer-tree-toolbar">
|
<ActionToolbar className="explorer-tree-toolbar">
|
||||||
{selectedUnitId && <Button type="button" variant="ghost" disabled={busy} disabledReason={busy ? ORGANIZATIONS_INTERFACE_I18N.busy : undefined} onClick={() => setSelectedUnitId("")}>i18n:govoplan-organizations.none.334c4a4c</Button>}
|
{selectedUnitId && <Button type="button" variant="ghost" disabled={busy} disabledReason={busy ? ORGANIZATIONS_INTERFACE_I18N.busy : undefined} onClick={() => setSelectedUnitId("")}>i18n:govoplan-organizations.none.334c4a4c</Button>}
|
||||||
</div>
|
</ActionToolbar>
|
||||||
{model.units.length ? (
|
{model.units.length ? (
|
||||||
<ExplorerTree
|
<ExplorerTree
|
||||||
nodes={unitsByParentId.get("") ?? []}
|
nodes={unitsByParentId.get("") ?? []}
|
||||||
@@ -1215,7 +1215,7 @@ export default function OrganizationsPage({
|
|||||||
activeEditor === "functionType" ? submitFunctionType :
|
activeEditor === "functionType" ? submitFunctionType :
|
||||||
submitFunction;
|
submitFunction;
|
||||||
return (
|
return (
|
||||||
<Dialog
|
<Dialog variant="administration" size="wide"
|
||||||
open={Boolean(activeEditor)}
|
open={Boolean(activeEditor)}
|
||||||
title={editorTitle()}
|
title={editorTitle()}
|
||||||
onClose={() => {
|
onClose={() => {
|
||||||
@@ -1224,7 +1224,7 @@ export default function OrganizationsPage({
|
|||||||
else discardDrafts();
|
else discardDrafts();
|
||||||
}}
|
}}
|
||||||
closeDisabled={busy}
|
closeDisabled={busy}
|
||||||
className="admin-dialog admin-dialog-wide organizations-editor-dialog"
|
className="organizations-editor-dialog"
|
||||||
footer={(
|
footer={(
|
||||||
<>
|
<>
|
||||||
<Button
|
<Button
|
||||||
@@ -1250,9 +1250,9 @@ export default function OrganizationsPage({
|
|||||||
<div className="button-row organizations-dialog-help">
|
<div className="button-row organizations-dialog-help">
|
||||||
<DocumentationHelpLink reference={ORGANIZATIONS_FIELD_DOCUMENTATION} />
|
<DocumentationHelpLink reference={ORGANIZATIONS_FIELD_DOCUMENTATION} />
|
||||||
</div>
|
</div>
|
||||||
<form id={formId} className="admin-form-grid two-columns" onSubmit={(event) => void submit(event)}>
|
<FormLayout columns={2} gap="small" collapseAt="workspace" id={formId} className="" onSubmit={(event) => void submit(event)}>
|
||||||
{renderEditorFields()}
|
{renderEditorFields()}
|
||||||
</form>
|
</FormLayout>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,11 +13,6 @@
|
|||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.organizations-settings-grid {
|
|
||||||
display: grid;
|
|
||||||
gap: 18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.organizations-heading {
|
.organizations-heading {
|
||||||
margin-bottom: 4px;
|
margin-bottom: 4px;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user