Release v0.1.8

This commit is contained in:
2026-07-11 16:49:03 +02:00
parent 213157aca1
commit 39c081c4fb
12 changed files with 237 additions and 46 deletions

View File

@@ -1,6 +1,6 @@
{
"name": "@govoplan/organizations-webui",
"version": "0.1.7",
"version": "0.1.8",
"private": true,
"type": "module",
"main": "src/index.ts",
@@ -14,7 +14,7 @@
"./styles/organizations.css": "./src/styles/organizations.css"
},
"peerDependencies": {
"@govoplan/core-webui": "^0.1.7",
"@govoplan/core-webui": "^0.1.8",
"@vitejs/plugin-react": "^4.3.4",
"lucide-react": "^1.23.0",
"react": "^19.0.0",

View File

@@ -13,6 +13,7 @@ import {
ModuleSubnav,
PageTitle,
StatusBadge,
ToggleSwitch,
hasScope,
useUnsavedDraftGuard,
usePlatformUiCapabilities,
@@ -324,10 +325,14 @@ function SluggedFields({
<textarea rows={3} value={draft.description} disabled={disabled} onChange={(event) => onChange({ ...draft, description: event.target.value })} />
</FormField>
</div>
<label className="organizations-inline-check wide">
<input type="checkbox" checked={draft.is_active} disabled={disabled} onChange={(event) => onChange({ ...draft, is_active: event.target.checked })} />
<span>i18n:govoplan-organizations.active.a733b809</span>
</label>
<div className="wide">
<ToggleSwitch
checked={draft.is_active}
disabled={disabled}
onChange={(checked) => onChange({ ...draft, is_active: checked })}
label="i18n:govoplan-organizations.active.a733b809"
/>
</div>
</>
);
}
@@ -982,16 +987,16 @@ export default function OrganizationsPage({
function renderModelSection() {
return (
<div className="organizations-table-stack">
<Card title="i18n:govoplan-organizations.unit_types.c7afc174" collapsible collapseKey="organizations.unit-types" actions={<AdminIconButton label="i18n:govoplan-organizations.add_unit_type.58f2c05a" icon={<Plus size={16} aria-hidden="true" />} variant="primary" disabled={!canWriteModel || busy} onClick={openUnitTypeCreate} />}>
<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} 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" collapsible collapseKey="organizations.structures" actions={<AdminIconButton label="i18n:govoplan-organizations.add_structure.b722042a" icon={<Plus size={16} aria-hidden="true" />} variant="primary" disabled={!canWriteModel || busy} onClick={openStructureCreate} />}>
<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} 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" collapsible collapseKey="organizations.relation-types" actions={<AdminIconButton label="i18n:govoplan-organizations.add_relation_type.2ad19d03" icon={<Plus size={16} aria-hidden="true" />} variant="primary" disabled={!canWriteModel || busy} onClick={openRelationTypeCreate} />}>
<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} 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" collapsible collapseKey="organizations.function-types" actions={<AdminIconButton label="i18n:govoplan-organizations.add_function_type.90d793f1" icon={<Plus size={16} aria-hidden="true" />} variant="primary" disabled={!canWriteModel || busy} onClick={openFunctionTypeCreate} />}>
<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} 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>
@@ -1026,7 +1031,7 @@ export default function OrganizationsPage({
function renderUnitsSection() {
return (
<div className="organizations-table-stack">
<Card title="i18n:govoplan-organizations.organization_tree.e5bfb195" collapsible collapseKey="organizations.tree" actions={<AdminIconButton label="i18n:govoplan-organizations.add_root_unit.1ef8a9f5" icon={<Plus size={16} aria-hidden="true" />} variant="primary" disabled={!canWriteUnits || busy} 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} onClick={() => openUnitCreate()} />}>
<div className="organizations-tree-toolbar">
{selectedUnitId && <Button type="button" variant="ghost" disabled={busy} onClick={() => setSelectedUnitId("")}>i18n:govoplan-organizations.none.334c4a4c</Button>}
</div>
@@ -1034,7 +1039,7 @@ export default function OrganizationsPage({
{model.units.length ? renderUnitTreeNodes() : <p className="muted small-note">i18n:govoplan-organizations.no_units_found.eea2dd0c</p>}
</div>
</Card>
<Card title="i18n:govoplan-organizations.units.e14d0d92" collapsible collapseKey="organizations.units" actions={<AdminIconButton label="i18n:govoplan-organizations.add_unit.8fa12fb1" icon={<Plus size={16} aria-hidden="true" />} variant="primary" disabled={!canWriteUnits || busy} onClick={() => openUnitCreate()} />}>
<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} 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>
@@ -1044,7 +1049,7 @@ export default function OrganizationsPage({
function renderRelationsSection() {
return (
<div className="organizations-table-stack">
<Card title="i18n:govoplan-organizations.relations.1c796711" collapsible collapseKey="organizations.relations" actions={<AdminIconButton label="i18n:govoplan-organizations.add_relation.6b6e67ea" icon={<Plus size={16} aria-hidden="true" />} variant="primary" disabled={!canWriteUnits || busy} onClick={openRelationCreate} />}>
<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} 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>
@@ -1054,7 +1059,7 @@ export default function OrganizationsPage({
function renderFunctionsSection() {
return (
<div className="organizations-table-stack">
<Card title="i18n:govoplan-organizations.functions.805dc49b" collapsible collapseKey="organizations.functions" actions={<AdminIconButton label="i18n:govoplan-organizations.add_function.6abafee0" icon={<Plus size={16} aria-hidden="true" />} variant="primary" disabled={!canWriteFunctions || busy} onClick={() => openFunctionCreate()} />}>
<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} 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>
@@ -1176,8 +1181,8 @@ export default function OrganizationsPage({
</select>
</FormField>
<div className="organizations-check-list">
<label><input type="checkbox" checked={relationTypeDraft.is_hierarchical} disabled={!canWriteModel || busy} onChange={(event) => setRelationTypeDraft({ ...relationTypeDraft, is_hierarchical: event.target.checked })} /> i18n:govoplan-organizations.hierarchical.8964f313</label>
<label><input type="checkbox" checked={relationTypeDraft.allow_cycles} disabled={!canWriteModel || busy} onChange={(event) => setRelationTypeDraft({ ...relationTypeDraft, allow_cycles: event.target.checked })} /> i18n:govoplan-organizations.allow_cycles.31327578</label>
<ToggleSwitch checked={relationTypeDraft.is_hierarchical} disabled={!canWriteModel || busy} onChange={(checked) => setRelationTypeDraft({ ...relationTypeDraft, is_hierarchical: checked })} label="i18n:govoplan-organizations.hierarchical.8964f313" />
<ToggleSwitch checked={relationTypeDraft.allow_cycles} disabled={!canWriteModel || busy} onChange={(checked) => setRelationTypeDraft({ ...relationTypeDraft, allow_cycles: checked })} label="i18n:govoplan-organizations.allow_cycles.31327578" />
</div>
{renderChangeRequestField()}
</>
@@ -1235,10 +1240,14 @@ export default function OrganizationsPage({
{model.units.map((item) => <option key={item.id} value={item.id}>{item.name}</option>)}
</select>
</FormField>
<label className="organizations-inline-check wide">
<input type="checkbox" checked={relationDraft.is_active} disabled={!canWriteUnits || busy} onChange={(event) => setRelationDraft({ ...relationDraft, is_active: event.target.checked })} />
<span>i18n:govoplan-organizations.active.a733b809</span>
</label>
<div className="wide">
<ToggleSwitch
checked={relationDraft.is_active}
disabled={!canWriteUnits || busy}
onChange={(checked) => setRelationDraft({ ...relationDraft, is_active: checked })}
label="i18n:govoplan-organizations.active.a733b809"
/>
</div>
{renderChangeRequestField()}
</>
);
@@ -1254,8 +1263,8 @@ export default function OrganizationsPage({
</select>
</FormField>
<div className="organizations-check-list">
<label><input type="checkbox" checked={functionTypeDraft.delegable} disabled={!canWriteModel || busy} onChange={(event) => setFunctionTypeDraft({ ...functionTypeDraft, delegable: event.target.checked })} /> i18n:govoplan-organizations.delegable.b4f0137d</label>
<label><input type="checkbox" checked={functionTypeDraft.act_in_place_allowed} disabled={!canWriteModel || busy} onChange={(event) => setFunctionTypeDraft({ ...functionTypeDraft, act_in_place_allowed: event.target.checked })} /> i18n:govoplan-organizations.act_in_place.49b942bd</label>
<ToggleSwitch checked={functionTypeDraft.delegable} disabled={!canWriteModel || busy} onChange={(checked) => setFunctionTypeDraft({ ...functionTypeDraft, delegable: checked })} label="i18n:govoplan-organizations.delegable.b4f0137d" />
<ToggleSwitch checked={functionTypeDraft.act_in_place_allowed} disabled={!canWriteModel || busy} onChange={(checked) => setFunctionTypeDraft({ ...functionTypeDraft, act_in_place_allowed: checked })} label="i18n:govoplan-organizations.act_in_place.49b942bd" />
</div>
{renderChangeRequestField()}
</>
@@ -1277,8 +1286,8 @@ export default function OrganizationsPage({
</select>
</FormField>
<div className="organizations-check-list">
<label><input type="checkbox" checked={functionDraft.delegable} disabled={!canWriteFunctions || busy} onChange={(event) => setFunctionDraft({ ...functionDraft, delegable: event.target.checked })} /> i18n:govoplan-organizations.delegable.b4f0137d</label>
<label><input type="checkbox" checked={functionDraft.act_in_place_allowed} disabled={!canWriteFunctions || busy} onChange={(event) => setFunctionDraft({ ...functionDraft, act_in_place_allowed: event.target.checked })} /> i18n:govoplan-organizations.act_in_place.49b942bd</label>
<ToggleSwitch checked={functionDraft.delegable} disabled={!canWriteFunctions || busy} onChange={(checked) => setFunctionDraft({ ...functionDraft, delegable: checked })} label="i18n:govoplan-organizations.delegable.b4f0137d" />
<ToggleSwitch checked={functionDraft.act_in_place_allowed} disabled={!canWriteFunctions || busy} onChange={(checked) => setFunctionDraft({ ...functionDraft, act_in_place_allowed: checked })} label="i18n:govoplan-organizations.act_in_place.49b942bd" />
</div>
{renderChangeRequestField()}
</>

View File

@@ -67,9 +67,9 @@ export const generatedTranslations: PlatformTranslations = {
"i18n:govoplan-organizations.none.334c4a4c": "None",
"i18n:govoplan-organizations.organization_model.4f924c0e": "Organization model",
"i18n:govoplan-organizations.organization_model_admin_description.35dc9f10": "Configure tenant-local unit types, parallel structures, relation types, and function types used by the organization module.",
"i18n:govoplan-organizations.organization_settings.c9ab9829": "Organization settings",
"i18n:govoplan-organizations.organization_settings.c9ab9829": "Organizations",
"i18n:govoplan-organizations.organization_settings_description.35dc9f10": "Configure tenant-level governance, audit, and retention behavior for organization changes.",
"i18n:govoplan-organizations.organization_settings_saved.bfbcfdfa": "Organization settings saved.",
"i18n:govoplan-organizations.organization_settings_saved.bfbcfdfa": "Organizations saved.",
"i18n:govoplan-organizations.organization_tree.e5bfb195": "Organization tree",
"i18n:govoplan-organizations.organizations.220edf64": "Organizations",
"i18n:govoplan-organizations.organizations_intro.4e67c4bb": "Model organization types, concrete units, structures, and functions.",
@@ -190,9 +190,9 @@ export const generatedTranslations: PlatformTranslations = {
"i18n:govoplan-organizations.none.334c4a4c": "Keine",
"i18n:govoplan-organizations.organization_model.4f924c0e": "Organisationsmodell",
"i18n:govoplan-organizations.organization_model_admin_description.35dc9f10": "Konfiguriere mandantenbezogene Einheitstypen, parallele Strukturen, Beziehungstypen und Funktionstypen des Organisationsmoduls.",
"i18n:govoplan-organizations.organization_settings.c9ab9829": "Organisationseinstellungen",
"i18n:govoplan-organizations.organization_settings.c9ab9829": "Organisationen",
"i18n:govoplan-organizations.organization_settings_description.35dc9f10": "Konfiguriere Governance, Audit und Aufbewahrung für Organisationsänderungen auf Mandantenebene.",
"i18n:govoplan-organizations.organization_settings_saved.bfbcfdfa": "Organisationseinstellungen gespeichert.",
"i18n:govoplan-organizations.organization_settings_saved.bfbcfdfa": "Organisationen gespeichert.",
"i18n:govoplan-organizations.organization_tree.e5bfb195": "Organisationsbaum",
"i18n:govoplan-organizations.organizations.220edf64": "Organisationen",
"i18n:govoplan-organizations.organizations_intro.4e67c4bb": "Modelliere Organisationstypen, konkrete Einheiten, Strukturen und Funktionen.",

View File

@@ -23,7 +23,7 @@ const organizationAdminSections: AdminSectionsUiCapability = {
sections: [
{
id: "tenant-organization-settings",
label: "i18n:govoplan-organizations.organization_settings.c9ab9829",
label: "i18n:govoplan-organizations.organizations.220edf64",
group: "TENANT",
order: 85,
anyOf: ["organizations:settings:read", "admin:settings:read"],
@@ -49,7 +49,7 @@ export const organizationsModule: PlatformWebModule = {
{
to: "/organizations",
label: "i18n:govoplan-organizations.organizations.220edf64",
iconName: "users",
iconName: "building-2",
anyOf: organizationReadScopes,
order: 70
}

View File

@@ -7,7 +7,6 @@
display: grid;
gap: 18px;
width: 100%;
max-width: 1480px;
}
.organizations-admin-page {
@@ -63,15 +62,6 @@
grid-column: 1 / -1;
}
.organizations-check-list label,
.organizations-inline-check {
display: inline-flex;
align-items: center;
gap: 8px;
color: var(--text);
font-weight: 600;
}
.organizations-table-stack {
display: grid;
gap: 18px;