Release v0.1.7
This commit is contained in:
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@govoplan/idm-webui",
|
"name": "@govoplan/idm-webui",
|
||||||
"version": "0.1.6",
|
"version": "0.1.7",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "webui/src/index.ts",
|
"main": "webui/src/index.ts",
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
"LICENSE"
|
"LICENSE"
|
||||||
],
|
],
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@govoplan/core-webui": "^0.1.6",
|
"@govoplan/core-webui": "^0.1.7",
|
||||||
"@vitejs/plugin-react": "^4.3.4",
|
"@vitejs/plugin-react": "^4.3.4",
|
||||||
"lucide-react": "^1.23.0",
|
"lucide-react": "^1.23.0",
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
|
|||||||
+4
-4
@@ -4,15 +4,15 @@ build-backend = "setuptools.build_meta"
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "govoplan-idm"
|
name = "govoplan-idm"
|
||||||
version = "0.1.6"
|
version = "0.1.7"
|
||||||
description = "GovOPlaN identity management bridge module."
|
description = "GovOPlaN identity management bridge module."
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.12"
|
requires-python = ">=3.12"
|
||||||
authors = [{ name = "GovOPlaN" }]
|
authors = [{ name = "GovOPlaN" }]
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"govoplan-core>=0.1.6",
|
"govoplan-core>=0.1.7",
|
||||||
"govoplan-identity>=0.1.6",
|
"govoplan-identity>=0.1.7",
|
||||||
"govoplan-organizations>=0.1.6",
|
"govoplan-organizations>=0.1.7",
|
||||||
]
|
]
|
||||||
|
|
||||||
[tool.setuptools.packages.find]
|
[tool.setuptools.packages.find]
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ def _idm_directory(context: ModuleContext) -> object:
|
|||||||
manifest = ModuleManifest(
|
manifest = ModuleManifest(
|
||||||
id="idm",
|
id="idm",
|
||||||
name="IDM",
|
name="IDM",
|
||||||
version="0.1.6",
|
version="0.1.7",
|
||||||
dependencies=("identity", "organizations"),
|
dependencies=("identity", "organizations"),
|
||||||
optional_dependencies=("access", "audit"),
|
optional_dependencies=("access", "audit"),
|
||||||
required_capabilities=(CAPABILITY_AUTH_PRINCIPAL_RESOLVER, CAPABILITY_AUTH_PERMISSION_EVALUATOR),
|
required_capabilities=(CAPABILITY_AUTH_PRINCIPAL_RESOLVER, CAPABILITY_AUTH_PERMISSION_EVALUATOR),
|
||||||
|
|||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@govoplan/idm-webui",
|
"name": "@govoplan/idm-webui",
|
||||||
"version": "0.1.6",
|
"version": "0.1.7",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "src/index.ts",
|
"main": "src/index.ts",
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
"./styles/idm.css": "./src/styles/idm.css"
|
"./styles/idm.css": "./src/styles/idm.css"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@govoplan/core-webui": "^0.1.6",
|
"@govoplan/core-webui": "^0.1.7",
|
||||||
"@vitejs/plugin-react": "^4.3.4",
|
"@vitejs/plugin-react": "^4.3.4",
|
||||||
"lucide-react": "^1.23.0",
|
"lucide-react": "^1.23.0",
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
|
|||||||
+133
-123
@@ -1,10 +1,12 @@
|
|||||||
import { useCallback, useEffect, useMemo, useRef, useState, type FormEvent } from "react";
|
import { useCallback, useEffect, useMemo, useRef, useState, type FormEvent } from "react";
|
||||||
import { Edit3, RefreshCw, Save, XCircle } from "lucide-react";
|
import { Edit3, Plus, RefreshCw } from "lucide-react";
|
||||||
import {
|
import {
|
||||||
|
AdminIconButton,
|
||||||
ApiError,
|
ApiError,
|
||||||
Button,
|
Button,
|
||||||
Card,
|
Card,
|
||||||
DataGrid,
|
DataGrid,
|
||||||
|
Dialog,
|
||||||
DismissibleAlert,
|
DismissibleAlert,
|
||||||
FormField,
|
FormField,
|
||||||
LoadingFrame,
|
LoadingFrame,
|
||||||
@@ -242,6 +244,8 @@ export default function IdmPage({ settings, auth }: IdmPageProps) {
|
|||||||
const [assignmentDraft, setAssignmentDraft] = useState<AssignmentDraft>(() => emptyAssignmentDraft());
|
const [assignmentDraft, setAssignmentDraft] = useState<AssignmentDraft>(() => emptyAssignmentDraft());
|
||||||
const [settingsDraft, setSettingsDraft] = useState<SettingsDraft>(() => settingsDraftFrom(null));
|
const [settingsDraft, setSettingsDraft] = useState<SettingsDraft>(() => settingsDraftFrom(null));
|
||||||
const [editingAssignmentId, setEditingAssignmentId] = useState<string | null>(null);
|
const [editingAssignmentId, setEditingAssignmentId] = useState<string | null>(null);
|
||||||
|
const [assignmentEditorOpen, setAssignmentEditorOpen] = useState(false);
|
||||||
|
const [assignmentChangeRequestId, setAssignmentChangeRequestId] = useState("");
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [busy, setBusy] = useState(false);
|
const [busy, setBusy] = useState(false);
|
||||||
const [error, setError] = useState("");
|
const [error, setError] = useState("");
|
||||||
@@ -298,7 +302,7 @@ export default function IdmPage({ settings, auth }: IdmPageProps) {
|
|||||||
return Array.from(values).sort((left, right) => left.localeCompare(right));
|
return Array.from(values).sort((left, right) => left.localeCompare(right));
|
||||||
}, [actingForOptionById, actingForOptions, assignmentDraft.acting_for_account_id, identityOptionById, sourceAssignment]);
|
}, [actingForOptionById, actingForOptions, assignmentDraft.acting_for_account_id, identityOptionById, sourceAssignment]);
|
||||||
const initialFunctionFilter = initialQuery.functionId;
|
const initialFunctionFilter = initialQuery.functionId;
|
||||||
const hasDirtyAssignmentDraft = isAssignmentDirty(assignmentDraft);
|
const hasDirtyAssignmentDraft = assignmentEditorOpen && isAssignmentDirty(assignmentDraft);
|
||||||
const hasDirtySettingsDraft = canReadSettings && isSettingsDirty(settingsDraft, idmSettings);
|
const hasDirtySettingsDraft = canReadSettings && isSettingsDirty(settingsDraft, idmSettings);
|
||||||
const hasDirtyDraft = hasDirtyAssignmentDraft || hasDirtySettingsDraft;
|
const hasDirtyDraft = hasDirtyAssignmentDraft || hasDirtySettingsDraft;
|
||||||
|
|
||||||
@@ -321,12 +325,9 @@ export default function IdmPage({ settings, auth }: IdmPageProps) {
|
|||||||
appliedInitialQueryRef.current = true;
|
appliedInitialQueryRef.current = true;
|
||||||
setEditingAssignmentId(initialAssignment.id);
|
setEditingAssignmentId(initialAssignment.id);
|
||||||
setAssignmentDraft(assignmentDraftFrom(initialAssignment));
|
setAssignmentDraft(assignmentDraftFrom(initialAssignment));
|
||||||
|
setAssignmentEditorOpen(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!appliedInitialQueryRef.current && initialFunctionFilter && nextModel.functions.some((item) => item.id === initialFunctionFilter)) {
|
|
||||||
appliedInitialQueryRef.current = true;
|
|
||||||
setAssignmentDraft((draft) => draft.function_id ? draft : { ...draft, function_id: initialFunctionFilter });
|
|
||||||
}
|
|
||||||
if (canSearchIdentities) {
|
if (canSearchIdentities) {
|
||||||
try {
|
try {
|
||||||
const identities = await searchOrganizationIdentityOptions(settings, "", 100);
|
const identities = await searchOrganizationIdentityOptions(settings, "", 100);
|
||||||
@@ -410,6 +411,8 @@ export default function IdmPage({ settings, auth }: IdmPageProps) {
|
|||||||
const discardAssignmentDraft = useCallback(() => {
|
const discardAssignmentDraft = useCallback(() => {
|
||||||
setAssignmentDraft(emptyAssignmentDraft());
|
setAssignmentDraft(emptyAssignmentDraft());
|
||||||
setEditingAssignmentId(null);
|
setEditingAssignmentId(null);
|
||||||
|
setAssignmentEditorOpen(false);
|
||||||
|
setAssignmentChangeRequestId("");
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const discardDrafts = useCallback(() => {
|
const discardDrafts = useCallback(() => {
|
||||||
@@ -444,14 +447,15 @@ export default function IdmPage({ settings, auth }: IdmPageProps) {
|
|||||||
setError("i18n:govoplan-idm.function_is_required.5cce5b41");
|
setError("i18n:govoplan-idm.function_is_required.5cce5b41");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const payload = assignmentPayload(assignmentDraft);
|
const requestId = textOrNull(assignmentChangeRequestId);
|
||||||
|
const payload = requestId ? { ...assignmentPayload(assignmentDraft), change_request_id: requestId } : assignmentPayload(assignmentDraft);
|
||||||
const ok = await runAction(
|
const ok = await runAction(
|
||||||
() => editingAssignmentId ? patchOrganizationFunctionAssignment(settings, editingAssignmentId, payload) : createOrganizationFunctionAssignment(settings, payload),
|
() => editingAssignmentId ? patchOrganizationFunctionAssignment(settings, editingAssignmentId, payload) : createOrganizationFunctionAssignment(settings, payload),
|
||||||
editingAssignmentId ? "i18n:govoplan-idm.assignment_updated.fbbf9bd6" : "i18n:govoplan-idm.assignment_added.91f1ee42"
|
editingAssignmentId ? "i18n:govoplan-idm.assignment_updated.fbbf9bd6" : "i18n:govoplan-idm.assignment_added.91f1ee42"
|
||||||
);
|
);
|
||||||
if (ok) discardAssignmentDraft();
|
if (ok) discardAssignmentDraft();
|
||||||
return ok;
|
return ok;
|
||||||
}, [assignmentDraft, canManage, discardAssignmentDraft, editingAssignmentId, runAction, settings]);
|
}, [assignmentChangeRequestId, assignmentDraft, canManage, discardAssignmentDraft, editingAssignmentId, runAction, settings]);
|
||||||
|
|
||||||
const saveDrafts = useCallback(async (): Promise<boolean> => {
|
const saveDrafts = useCallback(async (): Promise<boolean> => {
|
||||||
if (hasDirtyAssignmentDraft && !(await submitAssignment())) return false;
|
if (hasDirtyAssignmentDraft && !(await submitAssignment())) return false;
|
||||||
@@ -467,15 +471,20 @@ export default function IdmPage({ settings, auth }: IdmPageProps) {
|
|||||||
message: "i18n:govoplan-core.this_page_has_unsaved_changes_save_them_before_l.419a9d8b"
|
message: "i18n:govoplan-core.this_page_has_unsaved_changes_save_them_before_l.419a9d8b"
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const openCreateAssignment = useCallback(() => {
|
||||||
|
setEditingAssignmentId(null);
|
||||||
|
setAssignmentDraft({ ...emptyAssignmentDraft(), function_id: initialFunctionFilter && functionById.has(initialFunctionFilter) ? initialFunctionFilter : "" });
|
||||||
|
setAssignmentChangeRequestId("");
|
||||||
|
setAssignmentEditorOpen(true);
|
||||||
|
}, [functionById, initialFunctionFilter]);
|
||||||
|
|
||||||
const editAssignment = useCallback((item: OrganizationFunctionAssignmentItem) => {
|
const editAssignment = useCallback((item: OrganizationFunctionAssignmentItem) => {
|
||||||
setEditingAssignmentId(item.id);
|
setEditingAssignmentId(item.id);
|
||||||
setAssignmentDraft(assignmentDraftFrom(item));
|
setAssignmentDraft(assignmentDraftFrom(item));
|
||||||
|
setAssignmentChangeRequestId("");
|
||||||
|
setAssignmentEditorOpen(true);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const toggleAssignment = useCallback((item: OrganizationFunctionAssignmentItem) => {
|
|
||||||
void runAction(() => patchOrganizationFunctionAssignment(settings, item.id, { is_active: !item.is_active }));
|
|
||||||
}, [runAction, settings]);
|
|
||||||
|
|
||||||
function onIdentityChange(identityId: string) {
|
function onIdentityChange(identityId: string) {
|
||||||
const identity = identityOptionById.get(identityId);
|
const identity = identityOptionById.get(identityId);
|
||||||
setAssignmentDraft({
|
setAssignmentDraft({
|
||||||
@@ -551,16 +560,11 @@ export default function IdmPage({ settings, auth }: IdmPageProps) {
|
|||||||
{
|
{
|
||||||
id: "actions",
|
id: "actions",
|
||||||
header: "",
|
header: "",
|
||||||
width: 220,
|
width: 88,
|
||||||
sticky: "end",
|
sticky: "end",
|
||||||
render: (row) => (
|
render: (row) => (
|
||||||
<div className="idm-row-actions">
|
<div className="idm-row-actions">
|
||||||
<Button type="button" variant="ghost" disabled={!canManage || busy} onClick={() => editAssignment(row)} title="i18n:govoplan-idm.edit.a5a0f3cc">
|
<AdminIconButton label="i18n:govoplan-idm.edit.a5a0f3cc" icon={<Edit3 size={16} aria-hidden="true" />} disabled={!canManage || busy} onClick={() => editAssignment(row)} />
|
||||||
<Edit3 size={16} aria-hidden="true" /> i18n:govoplan-idm.edit.a5a0f3cc
|
|
||||||
</Button>
|
|
||||||
<Button type="button" variant={row.is_active ? "secondary" : "primary"} disabled={!canManage || busy} onClick={() => toggleAssignment(row)}>
|
|
||||||
{row.is_active ? "i18n:govoplan-idm.deactivate.585777c8" : "i18n:govoplan-idm.reactivate.e4871a43"}
|
|
||||||
</Button>
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -577,16 +581,6 @@ export default function IdmPage({ settings, auth }: IdmPageProps) {
|
|||||||
<Button type="button" onClick={() => void loadData()} disabled={loading || busy} title="i18n:govoplan-idm.reload.870ca3ec">
|
<Button type="button" onClick={() => void loadData()} disabled={loading || busy} title="i18n:govoplan-idm.reload.870ca3ec">
|
||||||
<RefreshCw size={16} aria-hidden="true" /> i18n:govoplan-idm.reload.870ca3ec
|
<RefreshCw size={16} aria-hidden="true" /> i18n:govoplan-idm.reload.870ca3ec
|
||||||
</Button>
|
</Button>
|
||||||
{hasDirtyDraft && (
|
|
||||||
<>
|
|
||||||
<Button type="button" onClick={() => void saveDrafts()} disabled={busy} title="i18n:govoplan-idm.save_drafts.32a0d60a">
|
|
||||||
<Save size={16} aria-hidden="true" /> i18n:govoplan-idm.save_drafts.32a0d60a
|
|
||||||
</Button>
|
|
||||||
<Button type="button" variant="ghost" onClick={discardDrafts} disabled={busy} title="i18n:govoplan-idm.discard_drafts.c0a86816">
|
|
||||||
<XCircle size={16} aria-hidden="true" /> i18n:govoplan-idm.discard_drafts.c0a86816
|
|
||||||
</Button>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -595,98 +589,9 @@ export default function IdmPage({ settings, auth }: IdmPageProps) {
|
|||||||
{!canManage && <DismissibleAlert tone="warning" dismissible={false}>i18n:govoplan-idm.write_permission_required.c7dde7c6</DismissibleAlert>}
|
{!canManage && <DismissibleAlert tone="warning" dismissible={false}>i18n:govoplan-idm.write_permission_required.c7dde7c6</DismissibleAlert>}
|
||||||
|
|
||||||
<LoadingFrame loading={loading || busy} label="i18n:govoplan-idm.loading_idm_assignments.0b1501bd">
|
<LoadingFrame loading={loading || busy} label="i18n:govoplan-idm.loading_idm_assignments.0b1501bd">
|
||||||
<div className="idm-layout">
|
<div className="idm-table-stack">
|
||||||
<div className="idm-editor-stack">
|
{canReadSettings && (
|
||||||
<Card title="i18n:govoplan-idm.assignment_editor.e20598e7">
|
<Card title="i18n:govoplan-idm.idm_governance.6e4f3251" collapsible collapseKey="idm.governance">
|
||||||
<form className="idm-form-grid" onSubmit={(event) => void submitAssignment(event)}>
|
|
||||||
<FormField label="i18n:govoplan-idm.identity_search.d3460fcf">
|
|
||||||
<input
|
|
||||||
value={identitySearch}
|
|
||||||
placeholder="i18n:govoplan-idm.search_identities.88a9ef15"
|
|
||||||
disabled={!canSearchIdentities || busy}
|
|
||||||
onChange={(event) => setIdentitySearch(event.target.value)}
|
|
||||||
/>
|
|
||||||
</FormField>
|
|
||||||
<FormField label="i18n:govoplan-idm.select_identity.91d31615">
|
|
||||||
<select value={assignmentDraft.identity_id} disabled={!canManage || busy} onChange={(event) => onIdentityChange(event.target.value)}>
|
|
||||||
<option value="">i18n:govoplan-idm.select_identity.91d31615</option>
|
|
||||||
{identitySelectOptions.map((item) => (
|
|
||||||
<option key={item.id} value={item.id}>{item.display_name || item.external_subject || item.id}</option>
|
|
||||||
))}
|
|
||||||
</select>
|
|
||||||
</FormField>
|
|
||||||
<FormField label="i18n:govoplan-idm.account.2b2936f8">
|
|
||||||
<select value={assignmentDraft.account_id} disabled={!canManage || busy} onChange={(event) => setAssignmentDraft({ ...assignmentDraft, account_id: event.target.value })}>
|
|
||||||
<option value="">i18n:govoplan-idm.none.2baf5c66</option>
|
|
||||||
{accountIds.map((accountId) => <option key={accountId} value={accountId}>{accountId}</option>)}
|
|
||||||
</select>
|
|
||||||
</FormField>
|
|
||||||
<FormField label="i18n:govoplan-idm.select_function.2bec86e0">
|
|
||||||
<select value={assignmentDraft.function_id} disabled={!canManage || busy} onChange={(event) => setAssignmentDraft({ ...assignmentDraft, function_id: event.target.value })}>
|
|
||||||
<option value="">i18n:govoplan-idm.select_function.2bec86e0</option>
|
|
||||||
{model.functions.map((item) => <option key={item.id} value={item.id}>{functionLabel(item, unitById)}</option>)}
|
|
||||||
</select>
|
|
||||||
</FormField>
|
|
||||||
<FormField label="i18n:govoplan-idm.source.d15b50c9">
|
|
||||||
<select value={assignmentDraft.source} disabled={!canManage || busy} onChange={(event) => onSourceChange(event.target.value)}>
|
|
||||||
{SOURCE_OPTIONS.map((item) => <option key={item.value} value={item.value}>{item.label}</option>)}
|
|
||||||
</select>
|
|
||||||
</FormField>
|
|
||||||
{(assignmentDraft.source === "delegated" || assignmentDraft.source === "acting_for") && (
|
|
||||||
<FormField label="i18n:govoplan-idm.delegated_from_assignment_id.20d4a548">
|
|
||||||
<select value={assignmentDraft.delegated_from_assignment_id} disabled={!canManage || busy} onChange={(event) => setAssignmentDraft({ ...assignmentDraft, delegated_from_assignment_id: event.target.value, acting_for_account_id: "" })}>
|
|
||||||
<option value="">i18n:govoplan-idm.none.2baf5c66</option>
|
|
||||||
{assignmentOptions.map((item) => (
|
|
||||||
<option key={item.id} value={item.id}>{assignmentOptionLabel(item, identityOptionById, functionById, unitById)}</option>
|
|
||||||
))}
|
|
||||||
</select>
|
|
||||||
</FormField>
|
|
||||||
)}
|
|
||||||
{assignmentDraft.source === "acting_for" && (
|
|
||||||
<>
|
|
||||||
<FormField label="i18n:govoplan-idm.acting_for_search.b7c526c7">
|
|
||||||
<input
|
|
||||||
value={actingForSearch}
|
|
||||||
placeholder="i18n:govoplan-idm.search_identities.88a9ef15"
|
|
||||||
disabled={!canSearchIdentities || busy}
|
|
||||||
onChange={(event) => setActingForSearch(event.target.value)}
|
|
||||||
/>
|
|
||||||
</FormField>
|
|
||||||
<FormField label="i18n:govoplan-idm.acting_for_account_id.5d7ade5b">
|
|
||||||
<select value={assignmentDraft.acting_for_account_id} disabled={!canManage || busy} onChange={(event) => setAssignmentDraft({ ...assignmentDraft, acting_for_account_id: event.target.value })}>
|
|
||||||
<option value="">i18n:govoplan-idm.select_account.982ee1ad</option>
|
|
||||||
{actingForAccountIds.map((accountId) => <option key={accountId} value={accountId}>{accountId}</option>)}
|
|
||||||
</select>
|
|
||||||
</FormField>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
<div className="idm-check-list">
|
|
||||||
<label>
|
|
||||||
<input type="checkbox" checked={assignmentDraft.applies_to_subunits} disabled={!canManage || busy} onChange={(event) => setAssignmentDraft({ ...assignmentDraft, applies_to_subunits: event.target.checked })} />
|
|
||||||
<span>i18n:govoplan-idm.applies_to_subunits.2e31b50b</span>
|
|
||||||
</label>
|
|
||||||
<label>
|
|
||||||
<input type="checkbox" checked={assignmentDraft.is_active} disabled={!canManage || busy} onChange={(event) => setAssignmentDraft({ ...assignmentDraft, is_active: event.target.checked })} />
|
|
||||||
<span>i18n:govoplan-idm.active.7bd0e9f8</span>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
{!identityLookupAvailable && <p className="idm-muted wide">i18n:govoplan-idm.identity_lookup_unavailable.b76f7714</p>}
|
|
||||||
{identityLoading && <p className="idm-muted wide">i18n:govoplan-idm.loading_identities.f3b84693</p>}
|
|
||||||
{actingForLoading && <p className="idm-muted wide">i18n:govoplan-idm.loading_acting_for_accounts.c9894b1e</p>}
|
|
||||||
{!model.functions.length && <p className="idm-muted wide">i18n:govoplan-idm.no_functions_available.51ba08eb</p>}
|
|
||||||
<div className="idm-form-actions wide">
|
|
||||||
<Button type="submit" variant="primary" disabled={!canManage || busy}>
|
|
||||||
{editingAssignmentId ? "i18n:govoplan-idm.update_assignment.e20f52aa" : "i18n:govoplan-idm.add_assignment.08f2a0d5"}
|
|
||||||
</Button>
|
|
||||||
{editingAssignmentId && (
|
|
||||||
<Button type="button" variant="ghost" onClick={discardAssignmentDraft} disabled={busy}>i18n:govoplan-idm.cancel_edit.ea4781e0</Button>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</Card>
|
|
||||||
|
|
||||||
{canReadSettings && (
|
|
||||||
<Card title="i18n:govoplan-idm.idm_governance.6e4f3251">
|
|
||||||
<form className="idm-form-grid" onSubmit={(event) => { event.preventDefault(); void submitSettings(); }}>
|
<form className="idm-form-grid" onSubmit={(event) => { event.preventDefault(); void submitSettings(); }}>
|
||||||
<div className="idm-check-list wide">
|
<div className="idm-check-list wide">
|
||||||
<label>
|
<label>
|
||||||
@@ -727,9 +632,8 @@ export default function IdmPage({ settings, auth }: IdmPageProps) {
|
|||||||
</form>
|
</form>
|
||||||
</Card>
|
</Card>
|
||||||
)}
|
)}
|
||||||
</div>
|
|
||||||
|
|
||||||
<Card title="i18n:govoplan-idm.assignments.a0d19ec5">
|
<Card title="i18n:govoplan-idm.assignments.a0d19ec5" collapsible collapseKey="idm.assignments" actions={<AdminIconButton label="i18n:govoplan-idm.add_assignment.08f2a0d5" icon={<Plus size={16} aria-hidden="true" />} variant="primary" disabled={!canManage || busy} onClick={openCreateAssignment} />}>
|
||||||
<DataGrid
|
<DataGrid
|
||||||
id="idm-organization-function-assignments"
|
id="idm-organization-function-assignments"
|
||||||
rows={assignments}
|
rows={assignments}
|
||||||
@@ -742,6 +646,112 @@ export default function IdmPage({ settings, auth }: IdmPageProps) {
|
|||||||
</Card>
|
</Card>
|
||||||
</div>
|
</div>
|
||||||
</LoadingFrame>
|
</LoadingFrame>
|
||||||
|
{renderAssignmentDialog()}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
function renderAssignmentDialog() {
|
||||||
|
const formId = "idm-assignment-editor";
|
||||||
|
return (
|
||||||
|
<Dialog
|
||||||
|
open={assignmentEditorOpen}
|
||||||
|
title={editingAssignmentId ? "i18n:govoplan-idm.update_assignment.e20f52aa" : "i18n:govoplan-idm.add_assignment.08f2a0d5"}
|
||||||
|
onClose={() => !busy && discardAssignmentDraft()}
|
||||||
|
closeDisabled={busy}
|
||||||
|
className="admin-dialog admin-dialog-wide idm-editor-dialog"
|
||||||
|
footer={(
|
||||||
|
<>
|
||||||
|
<Button type="button" onClick={discardAssignmentDraft} disabled={busy}>i18n:govoplan-idm.cancel_edit.ea4781e0</Button>
|
||||||
|
<Button type="submit" form={formId} variant="primary" disabled={!canManage || busy || !assignmentDraft.identity_id || !assignmentDraft.function_id}>
|
||||||
|
{editingAssignmentId ? "i18n:govoplan-idm.update_assignment.e20f52aa" : "i18n:govoplan-idm.add_assignment.08f2a0d5"}
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<form id={formId} className="idm-form-grid" onSubmit={(event) => void submitAssignment(event)}>
|
||||||
|
<FormField label="i18n:govoplan-idm.identity_search.d3460fcf">
|
||||||
|
<input
|
||||||
|
value={identitySearch}
|
||||||
|
placeholder="i18n:govoplan-idm.search_identities.88a9ef15"
|
||||||
|
disabled={!canSearchIdentities || busy}
|
||||||
|
onChange={(event) => setIdentitySearch(event.target.value)}
|
||||||
|
/>
|
||||||
|
</FormField>
|
||||||
|
<FormField label="i18n:govoplan-idm.select_identity.91d31615">
|
||||||
|
<select value={assignmentDraft.identity_id} disabled={!canManage || busy} onChange={(event) => onIdentityChange(event.target.value)}>
|
||||||
|
<option value="">i18n:govoplan-idm.select_identity.91d31615</option>
|
||||||
|
{identitySelectOptions.map((item) => (
|
||||||
|
<option key={item.id} value={item.id}>{item.display_name || item.external_subject || item.id}</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</FormField>
|
||||||
|
<FormField label="i18n:govoplan-idm.account.2b2936f8">
|
||||||
|
<select value={assignmentDraft.account_id} disabled={!canManage || busy} onChange={(event) => setAssignmentDraft({ ...assignmentDraft, account_id: event.target.value })}>
|
||||||
|
<option value="">i18n:govoplan-idm.none.2baf5c66</option>
|
||||||
|
{accountIds.map((accountId) => <option key={accountId} value={accountId}>{accountId}</option>)}
|
||||||
|
</select>
|
||||||
|
</FormField>
|
||||||
|
<FormField label="i18n:govoplan-idm.select_function.2bec86e0">
|
||||||
|
<select value={assignmentDraft.function_id} disabled={!canManage || busy} onChange={(event) => setAssignmentDraft({ ...assignmentDraft, function_id: event.target.value })}>
|
||||||
|
<option value="">i18n:govoplan-idm.select_function.2bec86e0</option>
|
||||||
|
{model.functions.map((item) => <option key={item.id} value={item.id}>{functionLabel(item, unitById)}</option>)}
|
||||||
|
</select>
|
||||||
|
</FormField>
|
||||||
|
<FormField label="i18n:govoplan-idm.source.d15b50c9">
|
||||||
|
<select value={assignmentDraft.source} disabled={!canManage || busy} onChange={(event) => onSourceChange(event.target.value)}>
|
||||||
|
{SOURCE_OPTIONS.map((item) => <option key={item.value} value={item.value}>{item.label}</option>)}
|
||||||
|
</select>
|
||||||
|
</FormField>
|
||||||
|
{(assignmentDraft.source === "delegated" || assignmentDraft.source === "acting_for") && (
|
||||||
|
<FormField label="i18n:govoplan-idm.delegated_from_assignment_id.20d4a548">
|
||||||
|
<select value={assignmentDraft.delegated_from_assignment_id} disabled={!canManage || busy} onChange={(event) => setAssignmentDraft({ ...assignmentDraft, delegated_from_assignment_id: event.target.value, acting_for_account_id: "" })}>
|
||||||
|
<option value="">i18n:govoplan-idm.none.2baf5c66</option>
|
||||||
|
{assignmentOptions.map((item) => (
|
||||||
|
<option key={item.id} value={item.id}>{assignmentOptionLabel(item, identityOptionById, functionById, unitById)}</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</FormField>
|
||||||
|
)}
|
||||||
|
{assignmentDraft.source === "acting_for" && (
|
||||||
|
<>
|
||||||
|
<FormField label="i18n:govoplan-idm.acting_for_search.b7c526c7">
|
||||||
|
<input
|
||||||
|
value={actingForSearch}
|
||||||
|
placeholder="i18n:govoplan-idm.search_identities.88a9ef15"
|
||||||
|
disabled={!canSearchIdentities || busy}
|
||||||
|
onChange={(event) => setActingForSearch(event.target.value)}
|
||||||
|
/>
|
||||||
|
</FormField>
|
||||||
|
<FormField label="i18n:govoplan-idm.acting_for_account_id.5d7ade5b">
|
||||||
|
<select value={assignmentDraft.acting_for_account_id} disabled={!canManage || busy} onChange={(event) => setAssignmentDraft({ ...assignmentDraft, acting_for_account_id: event.target.value })}>
|
||||||
|
<option value="">i18n:govoplan-idm.select_account.982ee1ad</option>
|
||||||
|
{actingForAccountIds.map((accountId) => <option key={accountId} value={accountId}>{accountId}</option>)}
|
||||||
|
</select>
|
||||||
|
</FormField>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
<div className="idm-check-list">
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" checked={assignmentDraft.applies_to_subunits} disabled={!canManage || busy} onChange={(event) => setAssignmentDraft({ ...assignmentDraft, applies_to_subunits: event.target.checked })} />
|
||||||
|
<span>i18n:govoplan-idm.applies_to_subunits.2e31b50b</span>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" checked={assignmentDraft.is_active} disabled={!canManage || busy} onChange={(event) => setAssignmentDraft({ ...assignmentDraft, is_active: event.target.checked })} />
|
||||||
|
<span>i18n:govoplan-idm.active.7bd0e9f8</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div className="wide idm-dialog-change-request">
|
||||||
|
<FormField label="i18n:govoplan-idm.change_request_id.b7d816db">
|
||||||
|
<input value={assignmentChangeRequestId} onChange={(event) => setAssignmentChangeRequestId(event.target.value)} placeholder="cfgreq-..." disabled={busy} />
|
||||||
|
</FormField>
|
||||||
|
<p className="idm-muted">i18n:govoplan-idm.change_request_id_help.cc7de508</p>
|
||||||
|
</div>
|
||||||
|
{!identityLookupAvailable && <p className="idm-muted wide">i18n:govoplan-idm.identity_lookup_unavailable.b76f7714</p>}
|
||||||
|
{identityLoading && <p className="idm-muted wide">i18n:govoplan-idm.loading_identities.f3b84693</p>}
|
||||||
|
{actingForLoading && <p className="idm-muted wide">i18n:govoplan-idm.loading_acting_for_accounts.c9894b1e</p>}
|
||||||
|
{!model.functions.length && <p className="idm-muted wide">i18n:govoplan-idm.no_functions_available.51ba08eb</p>}
|
||||||
|
</form>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user