Release govoplan-organizations v0.1.21: unify interface contracts and documentation
Module Package Release / publish-packages (push) Successful in 12s

This commit is contained in:
2026-09-08 01:32:48 +02:00
parent b23e6e4eee
commit 58ebf2c7e6
8 changed files with 42 additions and 24 deletions
@@ -178,8 +178,9 @@ export default function OrganizationTemplateUpgradePanel({ settings, auth }: { s
return <>
{error && <DismissibleAlert tone="danger" resetKey={error}>{error}</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 bodyLayout="table" 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">
<div className="content-pad">
<MetricGrid density="compact">
<MetricCard label="Applied version" value={currentVersion?.version ?? "Custom model"} tone="info" />
<MetricCard label="Available upgrades" value={targets.length} tone={targets.length ? "info" : "good"} />
@@ -191,6 +192,7 @@ export default function OrganizationTemplateUpgradePanel({ settings, auth }: { s
<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>
</ActionToolbar>
</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>
</Card>
@@ -1,5 +1,5 @@
import { useCallback, useEffect, useMemo, useRef, useState, type FormEvent } from "react";
import { Edit3, Plus, RefreshCw } from "lucide-react";
import { useCallback, useEffect, useMemo, useRef, useState, type FormEvent, type JSX } from "react";
import { Edit3, Plus } from "lucide-react";
import { FormLayout, ActionToolbar,
ActionBlockerHint,
AdminIconButton,
@@ -282,7 +282,7 @@ function mapById<T extends { id: string }>(items: T[]): Map<string, T> {
function sectionGroupsFor(sections: ReadonlySet<OrganizationSection>): ModuleSubnavGroup<OrganizationSection>[] {
return SECTION_GROUPS.map((group) => ({
...group,
items: group.items.filter((item) => sections.has(item.id))
items: group.items.filter((item) => "id" in item && sections.has(item.id))
})).filter((group) => group.items.length > 0);
}
@@ -309,14 +309,14 @@ function activeStatus(active: boolean): JSX.Element {
return <StatusBadge status={active ? "success" : "inactive"} label={active ? "i18n:govoplan-organizations.active.a733b809" : "i18n:govoplan-organizations.inactive.09af574c"} />;
}
function SluggedFields({
function SluggedFields<T extends SluggedDraft>({
draft,
onChange,
disabled,
disabledReason
}: {
draft: SluggedDraft;
onChange: (next: SluggedDraft) => void;
draft: T;
onChange: (next: T) => void;
disabled: boolean;
disabledReason?: string;
}) {
@@ -1066,7 +1066,7 @@ export default function OrganizationsPage({
)}
primaryLabel="i18n:govoplan-organizations.organization_model.5945c48a"
contentLabel={title}
documentationType={mode === "admin" ? "admin" : "user"}
documentationType="user"
>
{content}
</WorkspaceLayout>
@@ -1075,16 +1075,16 @@ export default function OrganizationsPage({
function renderModelSection() {
return (
<div className="organizations-table-stack">
<Card title="i18n:govoplan-organizations.unit_types.c7afc174" actions={<AdminIconButton label="i18n:govoplan-organizations.add_unit_type.58f2c05a" icon={<Plus size={16} aria-hidden="true" />} variant="primary" disabled={!canWriteModel || busy} disabledReason={organizationWriteReason(canWriteModel, busy, "model")} onClick={openUnitTypeCreate} />}>
<Card bodyLayout="table" title="i18n:govoplan-organizations.unit_types.c7afc174" actions={<AdminIconButton label="i18n:govoplan-organizations.add_unit_type.58f2c05a" icon={<Plus size={16} aria-hidden="true" />} variant="primary" disabled={!canWriteModel || busy} disabledReason={organizationWriteReason(canWriteModel, busy, "model")} onClick={openUnitTypeCreate} />}>
<DataGrid id="organizations-unit-types" rows={model.unit_types} columns={unitTypeColumns} getRowKey={(row) => row.id} emptyText="i18n:govoplan-organizations.no_unit_types_found.c81fb2a7" initialFit="container" />
</Card>
<Card title="i18n:govoplan-organizations.structures.f9b7f3b4" actions={<AdminIconButton label="i18n:govoplan-organizations.add_structure.b722042a" icon={<Plus size={16} aria-hidden="true" />} variant="primary" disabled={!canWriteModel || busy} disabledReason={organizationWriteReason(canWriteModel, busy, "model")} onClick={openStructureCreate} />}>
<Card bodyLayout="table" title="i18n:govoplan-organizations.structures.f9b7f3b4" actions={<AdminIconButton label="i18n:govoplan-organizations.add_structure.b722042a" icon={<Plus size={16} aria-hidden="true" />} variant="primary" disabled={!canWriteModel || busy} disabledReason={organizationWriteReason(canWriteModel, busy, "model")} onClick={openStructureCreate} />}>
<DataGrid id="organizations-structures" rows={model.structures} columns={structureColumns} getRowKey={(row) => row.id} emptyText="i18n:govoplan-organizations.no_structures_found.20b382d0" initialFit="container" />
</Card>
<Card title="i18n:govoplan-organizations.relation_types.e5890528" actions={<AdminIconButton label="i18n:govoplan-organizations.add_relation_type.2ad19d03" icon={<Plus size={16} aria-hidden="true" />} variant="primary" disabled={!canWriteModel || busy} disabledReason={organizationWriteReason(canWriteModel, busy, "model")} onClick={openRelationTypeCreate} />}>
<Card bodyLayout="table" title="i18n:govoplan-organizations.relation_types.e5890528" actions={<AdminIconButton label="i18n:govoplan-organizations.add_relation_type.2ad19d03" icon={<Plus size={16} aria-hidden="true" />} variant="primary" disabled={!canWriteModel || busy} disabledReason={organizationWriteReason(canWriteModel, busy, "model")} onClick={openRelationTypeCreate} />}>
<DataGrid id="organizations-relation-types" rows={model.relation_types} columns={relationTypeColumns} getRowKey={(row) => row.id} emptyText="i18n:govoplan-organizations.no_relation_types_found.6f90bb81" initialFit="container" />
</Card>
<Card title="i18n:govoplan-organizations.function_types.172c01fe" actions={<AdminIconButton label="i18n:govoplan-organizations.add_function_type.90d793f1" icon={<Plus size={16} aria-hidden="true" />} variant="primary" disabled={!canWriteModel || busy} disabledReason={organizationWriteReason(canWriteModel, busy, "model")} onClick={openFunctionTypeCreate} />}>
<Card bodyLayout="table" title="i18n:govoplan-organizations.function_types.172c01fe" actions={<AdminIconButton label="i18n:govoplan-organizations.add_function_type.90d793f1" icon={<Plus size={16} aria-hidden="true" />} variant="primary" disabled={!canWriteModel || busy} disabledReason={organizationWriteReason(canWriteModel, busy, "model")} onClick={openFunctionTypeCreate} />}>
<DataGrid id="organizations-function-types" rows={model.function_types} columns={functionTypeColumns} getRowKey={(row) => row.id} emptyText="i18n:govoplan-organizations.no_function_types_found.5eef31b1" initialFit="container" />
</Card>
</div>
@@ -1129,7 +1129,7 @@ export default function OrganizationsPage({
/>
) : <p className="muted small-note">i18n:govoplan-organizations.no_units_found.eea2dd0c</p>}
</Card>
<Card title="i18n:govoplan-organizations.units.e14d0d92" actions={<AdminIconButton label="i18n:govoplan-organizations.add_unit.8fa12fb1" icon={<Plus size={16} aria-hidden="true" />} variant="primary" disabled={!canWriteUnits || busy} disabledReason={organizationWriteReason(canWriteUnits, busy, "unit")} onClick={() => openUnitCreate()} />}>
<Card bodyLayout="table" title="i18n:govoplan-organizations.units.e14d0d92" actions={<AdminIconButton label="i18n:govoplan-organizations.add_unit.8fa12fb1" icon={<Plus size={16} aria-hidden="true" />} variant="primary" disabled={!canWriteUnits || busy} disabledReason={organizationWriteReason(canWriteUnits, busy, "unit")} onClick={() => openUnitCreate()} />}>
<DataGrid id="organizations-units" rows={model.units} columns={unitColumns} getRowKey={(row) => row.id} emptyText="i18n:govoplan-organizations.no_units_found.eea2dd0c" initialFit="container" />
</Card>
</div>
@@ -1139,7 +1139,7 @@ export default function OrganizationsPage({
function renderRelationsSection() {
return (
<div className="organizations-table-stack">
<Card title="i18n:govoplan-organizations.relations.1c796711" actions={<AdminIconButton label="i18n:govoplan-organizations.add_relation.6b6e67ea" icon={<Plus size={16} aria-hidden="true" />} variant="primary" disabled={!canWriteUnits || busy} disabledReason={organizationWriteReason(canWriteUnits, busy, "unit")} onClick={openRelationCreate} />}>
<Card bodyLayout="table" title="i18n:govoplan-organizations.relations.1c796711" actions={<AdminIconButton label="i18n:govoplan-organizations.add_relation.6b6e67ea" icon={<Plus size={16} aria-hidden="true" />} variant="primary" disabled={!canWriteUnits || busy} disabledReason={organizationWriteReason(canWriteUnits, busy, "unit")} onClick={openRelationCreate} />}>
<DataGrid id="organizations-relations" rows={model.relations} columns={relationColumns} getRowKey={(row) => row.id} emptyText="i18n:govoplan-organizations.no_relations_found.4e75b11d" initialFit="container" />
</Card>
</div>
@@ -1149,7 +1149,7 @@ export default function OrganizationsPage({
function renderFunctionsSection() {
return (
<div className="organizations-table-stack">
<Card title="i18n:govoplan-organizations.functions.805dc49b" actions={<AdminIconButton label="i18n:govoplan-organizations.add_function.6abafee0" icon={<Plus size={16} aria-hidden="true" />} variant="primary" disabled={!canWriteFunctions || busy} disabledReason={organizationWriteReason(canWriteFunctions, busy, "function")} onClick={() => openFunctionCreate()} />}>
<Card bodyLayout="table" title="i18n:govoplan-organizations.functions.805dc49b" actions={<AdminIconButton label="i18n:govoplan-organizations.add_function.6abafee0" icon={<Plus size={16} aria-hidden="true" />} variant="primary" disabled={!canWriteFunctions || busy} disabledReason={organizationWriteReason(canWriteFunctions, busy, "function")} onClick={() => openFunctionCreate()} />}>
<DataGrid id="organizations-functions" rows={model.functions} columns={functionColumns} getRowKey={(row) => row.id} emptyText="i18n:govoplan-organizations.no_functions_found.54e759a0" initialFit="container" />
</Card>
</div>