Add organization change-control workflow
This commit is contained in:
@@ -36,9 +36,11 @@ import {
|
||||
patchStructure,
|
||||
patchUnit,
|
||||
patchUnitType,
|
||||
searchIdentityOptions,
|
||||
type FunctionAssignmentCreatePayload,
|
||||
type FunctionCreatePayload,
|
||||
type FunctionTypeCreatePayload,
|
||||
type IdentityOption,
|
||||
type OrganizationFunctionAssignmentItem,
|
||||
type OrganizationFunctionItem,
|
||||
type OrganizationFunctionTypeItem,
|
||||
@@ -293,7 +295,16 @@ function sectionGroupsFor(sections: ReadonlySet<OrganizationSection>): ModuleSub
|
||||
}
|
||||
|
||||
function apiErrorMessage(error: unknown): string {
|
||||
if (error instanceof ApiError) return error.message;
|
||||
if (error instanceof ApiError) {
|
||||
try {
|
||||
const parsed = JSON.parse(error.body) as { detail?: string | { message?: string } };
|
||||
if (typeof parsed.detail === "string") return parsed.detail;
|
||||
if (parsed.detail && typeof parsed.detail.message === "string") return parsed.detail.message;
|
||||
} catch {
|
||||
// Fall back to the transport message below.
|
||||
}
|
||||
return error.message;
|
||||
}
|
||||
if (error instanceof Error) return error.message;
|
||||
return String(error);
|
||||
}
|
||||
@@ -306,6 +317,21 @@ 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 identityOptionLabel(identity: IdentityOption): string {
|
||||
return identity.display_name || identity.external_subject || identity.primary_account_id || identity.id;
|
||||
}
|
||||
|
||||
function identityDisplay(identityId: string, identities: Map<string, IdentityOption>): JSX.Element {
|
||||
const identity = identities.get(identityId);
|
||||
if (!identity) return <span className="organizations-id">{identityId}</span>;
|
||||
return (
|
||||
<span className="organizations-identity">
|
||||
<span>{identityOptionLabel(identity)}</span>
|
||||
<span className="organizations-id">{identity.id}</span>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
function ActiveToggleButton({ item, disabled, onToggle }: { item: ActiveItem; disabled: boolean; onToggle: () => void }) {
|
||||
const label = item.is_active ? "i18n:govoplan-organizations.deactivate.46ab070d" : "i18n:govoplan-organizations.reactivate.58f2855d";
|
||||
return (
|
||||
@@ -392,6 +418,11 @@ export default function OrganizationsPage({
|
||||
const [editingFunctionId, setEditingFunctionId] = useState<string | null>(null);
|
||||
const [editingAssignmentId, setEditingAssignmentId] = useState<string | null>(null);
|
||||
const [selectedUnitId, setSelectedUnitId] = useState("");
|
||||
const [changeRequestId, setChangeRequestId] = useState("");
|
||||
const [identitySearch, setIdentitySearch] = useState("");
|
||||
const [identityOptions, setIdentityOptions] = useState<IdentityOption[]>([]);
|
||||
const [identityLoading, setIdentityLoading] = useState(false);
|
||||
const [identityLookupAvailable, setIdentityLookupAvailable] = useState(true);
|
||||
|
||||
const canWriteModel = hasScope(auth, "organizations:model:write");
|
||||
const canWriteUnits = hasScope(auth, "organizations:unit:write");
|
||||
@@ -404,6 +435,7 @@ export default function OrganizationsPage({
|
||||
const unitById = useMemo(() => mapById(model.units), [model.units]);
|
||||
const functionTypeById = useMemo(() => mapById(model.function_types), [model.function_types]);
|
||||
const functionById = useMemo(() => mapById(model.functions), [model.functions]);
|
||||
const identityOptionById = useMemo(() => mapById(identityOptions), [identityOptions]);
|
||||
const unitsByParentId = useMemo(() => {
|
||||
const mapped = new Map<string, OrganizationUnitItem[]>();
|
||||
for (const unit of model.units) {
|
||||
@@ -435,6 +467,11 @@ export default function OrganizationsPage({
|
||||
}
|
||||
}, [settings]);
|
||||
|
||||
const withChangeRequest = useCallback(<T extends object,>(payload: T): T & { change_request_id?: string | null } => {
|
||||
const requestId = textOrNull(changeRequestId);
|
||||
return requestId ? { ...payload, change_request_id: requestId } : payload;
|
||||
}, [changeRequestId]);
|
||||
|
||||
useEffect(() => {
|
||||
void loadModel();
|
||||
}, [loadModel]);
|
||||
@@ -447,6 +484,36 @@ export default function OrganizationsPage({
|
||||
if (selectedUnitId && !unitById.has(selectedUnitId)) setSelectedUnitId("");
|
||||
}, [selectedUnitId, unitById]);
|
||||
|
||||
useEffect(() => {
|
||||
if (active !== "assignments" || !identityLookupAvailable) return undefined;
|
||||
let cancelled = false;
|
||||
const timeout = window.setTimeout(() => {
|
||||
setIdentityLoading(true);
|
||||
searchIdentityOptions(settings, identitySearch, 50).
|
||||
then((items) => {
|
||||
if (cancelled) return;
|
||||
setIdentityOptions(items);
|
||||
setIdentityLookupAvailable(true);
|
||||
}).
|
||||
catch((caught) => {
|
||||
if (cancelled) return;
|
||||
if (caught instanceof ApiError && (caught.status === 403 || caught.status === 404)) {
|
||||
setIdentityLookupAvailable(false);
|
||||
setIdentityOptions([]);
|
||||
return;
|
||||
}
|
||||
setError(apiErrorMessage(caught));
|
||||
}).
|
||||
finally(() => {
|
||||
if (!cancelled) setIdentityLoading(false);
|
||||
});
|
||||
}, 250);
|
||||
return () => {
|
||||
cancelled = true;
|
||||
window.clearTimeout(timeout);
|
||||
};
|
||||
}, [active, identityLookupAvailable, identitySearch, settings]);
|
||||
|
||||
const runAction = useCallback(async (action: () => Promise<unknown>, successMessage = ""): Promise<boolean> => {
|
||||
setBusy(true);
|
||||
setError("");
|
||||
@@ -498,7 +565,7 @@ export default function OrganizationsPage({
|
||||
if (!canWriteModel) return rejectMissingWritePermission();
|
||||
if (!unitTypeDraft.name.trim()) return rejectMissingName();
|
||||
const ok = await runAction(
|
||||
() => editingUnitTypeId ? patchUnitType(settings, editingUnitTypeId, sluggedPatchPayload(unitTypeDraft)) : createUnitType(settings, sluggedPayload(unitTypeDraft)),
|
||||
() => editingUnitTypeId ? patchUnitType(settings, editingUnitTypeId, withChangeRequest(sluggedPatchPayload(unitTypeDraft))) : createUnitType(settings, withChangeRequest(sluggedPayload(unitTypeDraft))),
|
||||
editingUnitTypeId ? "i18n:govoplan-organizations.unit_type_updated.6d8f2a16" : "i18n:govoplan-organizations.unit_type_added.e017dc8c"
|
||||
);
|
||||
if (ok) {
|
||||
@@ -506,7 +573,7 @@ export default function OrganizationsPage({
|
||||
setEditingUnitTypeId(null);
|
||||
}
|
||||
return ok;
|
||||
}, [canWriteModel, editingUnitTypeId, runAction, settings, unitTypeDraft]);
|
||||
}, [canWriteModel, editingUnitTypeId, runAction, settings, unitTypeDraft, withChangeRequest]);
|
||||
|
||||
const submitStructure = useCallback(async (event?: FormEvent): Promise<boolean> => {
|
||||
event?.preventDefault();
|
||||
@@ -515,7 +582,7 @@ export default function OrganizationsPage({
|
||||
const payload: StructureCreatePayload = { ...sluggedPayload(structureDraft), structure_kind: structureDraft.structure_kind };
|
||||
const patchPayload: Partial<StructureCreatePayload> = { ...sluggedPatchPayload(structureDraft), structure_kind: structureDraft.structure_kind };
|
||||
const ok = await runAction(
|
||||
() => editingStructureId ? patchStructure(settings, editingStructureId, patchPayload) : createStructure(settings, payload),
|
||||
() => editingStructureId ? patchStructure(settings, editingStructureId, withChangeRequest(patchPayload)) : createStructure(settings, withChangeRequest(payload)),
|
||||
editingStructureId ? "i18n:govoplan-organizations.structure_updated.2591e75f" : "i18n:govoplan-organizations.structure_added.f6cf8e74"
|
||||
);
|
||||
if (ok) {
|
||||
@@ -523,7 +590,7 @@ export default function OrganizationsPage({
|
||||
setEditingStructureId(null);
|
||||
}
|
||||
return ok;
|
||||
}, [canWriteModel, editingStructureId, runAction, settings, structureDraft]);
|
||||
}, [canWriteModel, editingStructureId, runAction, settings, structureDraft, withChangeRequest]);
|
||||
|
||||
const submitRelationType = useCallback(async (event?: FormEvent): Promise<boolean> => {
|
||||
event?.preventDefault();
|
||||
@@ -546,7 +613,7 @@ export default function OrganizationsPage({
|
||||
allow_cycles: relationTypeDraft.allow_cycles
|
||||
};
|
||||
const ok = await runAction(
|
||||
() => editingRelationTypeId ? patchRelationType(settings, editingRelationTypeId, patchPayload) : createRelationType(settings, payload),
|
||||
() => editingRelationTypeId ? patchRelationType(settings, editingRelationTypeId, withChangeRequest(patchPayload)) : createRelationType(settings, withChangeRequest(payload)),
|
||||
editingRelationTypeId ? "i18n:govoplan-organizations.relation_type_updated.5ac57ec7" : "i18n:govoplan-organizations.relation_type_added.6f1edff1"
|
||||
);
|
||||
if (ok) {
|
||||
@@ -554,7 +621,7 @@ export default function OrganizationsPage({
|
||||
setEditingRelationTypeId(null);
|
||||
}
|
||||
return ok;
|
||||
}, [canWriteModel, editingRelationTypeId, relationTypeDraft, runAction, settings]);
|
||||
}, [canWriteModel, editingRelationTypeId, relationTypeDraft, runAction, settings, withChangeRequest]);
|
||||
|
||||
const submitUnit = useCallback(async (event?: FormEvent): Promise<boolean> => {
|
||||
event?.preventDefault();
|
||||
@@ -571,7 +638,7 @@ export default function OrganizationsPage({
|
||||
parent_id: textOrNull(unitDraft.parent_id)
|
||||
};
|
||||
const ok = await runAction(
|
||||
() => editingUnitId ? patchUnit(settings, editingUnitId, patchPayload) : createUnit(settings, payload),
|
||||
() => editingUnitId ? patchUnit(settings, editingUnitId, withChangeRequest(patchPayload)) : createUnit(settings, withChangeRequest(payload)),
|
||||
editingUnitId ? "i18n:govoplan-organizations.unit_updated.15f02216" : "i18n:govoplan-organizations.unit_added.760a8512"
|
||||
);
|
||||
if (ok) {
|
||||
@@ -579,7 +646,7 @@ export default function OrganizationsPage({
|
||||
setEditingUnitId(null);
|
||||
}
|
||||
return ok;
|
||||
}, [canWriteUnits, editingUnitId, runAction, settings, unitDraft]);
|
||||
}, [canWriteUnits, editingUnitId, runAction, settings, unitDraft, withChangeRequest]);
|
||||
|
||||
const submitRelation = useCallback(async (event?: FormEvent): Promise<boolean> => {
|
||||
event?.preventDefault();
|
||||
@@ -591,7 +658,7 @@ export default function OrganizationsPage({
|
||||
const payload: RelationCreatePayload = { ...relationDraft, settings: {} };
|
||||
const patchPayload: Partial<RelationCreatePayload> = { ...relationDraft };
|
||||
const ok = await runAction(
|
||||
() => editingRelationId ? patchRelation(settings, editingRelationId, patchPayload) : createRelation(settings, payload),
|
||||
() => editingRelationId ? patchRelation(settings, editingRelationId, withChangeRequest(patchPayload)) : createRelation(settings, withChangeRequest(payload)),
|
||||
editingRelationId ? "i18n:govoplan-organizations.relation_updated.c6212776" : "i18n:govoplan-organizations.relation_added.ca90461a"
|
||||
);
|
||||
if (ok) {
|
||||
@@ -599,7 +666,7 @@ export default function OrganizationsPage({
|
||||
setEditingRelationId(null);
|
||||
}
|
||||
return ok;
|
||||
}, [canWriteUnits, editingRelationId, relationDraft, runAction, settings]);
|
||||
}, [canWriteUnits, editingRelationId, relationDraft, runAction, settings, withChangeRequest]);
|
||||
|
||||
const submitFunctionType = useCallback(async (event?: FormEvent): Promise<boolean> => {
|
||||
event?.preventDefault();
|
||||
@@ -618,7 +685,7 @@ export default function OrganizationsPage({
|
||||
act_in_place_allowed: functionTypeDraft.act_in_place_allowed
|
||||
};
|
||||
const ok = await runAction(
|
||||
() => editingFunctionTypeId ? patchFunctionType(settings, editingFunctionTypeId, patchPayload) : createFunctionType(settings, payload),
|
||||
() => editingFunctionTypeId ? patchFunctionType(settings, editingFunctionTypeId, withChangeRequest(patchPayload)) : createFunctionType(settings, withChangeRequest(payload)),
|
||||
editingFunctionTypeId ? "i18n:govoplan-organizations.function_type_updated.1a4f29f6" : "i18n:govoplan-organizations.function_type_added.2cd9e899"
|
||||
);
|
||||
if (ok) {
|
||||
@@ -626,7 +693,7 @@ export default function OrganizationsPage({
|
||||
setEditingFunctionTypeId(null);
|
||||
}
|
||||
return ok;
|
||||
}, [canWriteModel, editingFunctionTypeId, functionTypeDraft, runAction, settings]);
|
||||
}, [canWriteModel, editingFunctionTypeId, functionTypeDraft, runAction, settings, withChangeRequest]);
|
||||
|
||||
const submitFunction = useCallback(async (event?: FormEvent): Promise<boolean> => {
|
||||
event?.preventDefault();
|
||||
@@ -651,7 +718,7 @@ export default function OrganizationsPage({
|
||||
act_in_place_allowed: functionDraft.act_in_place_allowed
|
||||
};
|
||||
const ok = await runAction(
|
||||
() => editingFunctionId ? patchFunction(settings, editingFunctionId, patchPayload) : createFunction(settings, payload),
|
||||
() => editingFunctionId ? patchFunction(settings, editingFunctionId, withChangeRequest(patchPayload)) : createFunction(settings, withChangeRequest(payload)),
|
||||
editingFunctionId ? "i18n:govoplan-organizations.function_updated.65016009" : "i18n:govoplan-organizations.function_added.e2266702"
|
||||
);
|
||||
if (ok) {
|
||||
@@ -659,7 +726,7 @@ export default function OrganizationsPage({
|
||||
setEditingFunctionId(null);
|
||||
}
|
||||
return ok;
|
||||
}, [canWriteFunctions, editingFunctionId, functionDraft, runAction, settings]);
|
||||
}, [canWriteFunctions, editingFunctionId, functionDraft, runAction, settings, withChangeRequest]);
|
||||
|
||||
const submitAssignment = useCallback(async (event?: FormEvent): Promise<boolean> => {
|
||||
event?.preventDefault();
|
||||
@@ -680,7 +747,7 @@ export default function OrganizationsPage({
|
||||
settings: {}
|
||||
};
|
||||
const ok = await runAction(
|
||||
() => editingAssignmentId ? patchFunctionAssignment(settings, editingAssignmentId, payload) : createFunctionAssignment(settings, payload),
|
||||
() => editingAssignmentId ? patchFunctionAssignment(settings, editingAssignmentId, withChangeRequest(payload)) : createFunctionAssignment(settings, withChangeRequest(payload)),
|
||||
editingAssignmentId ? "i18n:govoplan-organizations.assignment_updated.680b6e33" : "i18n:govoplan-organizations.assignment_added.94263d1b"
|
||||
);
|
||||
if (ok) {
|
||||
@@ -688,7 +755,7 @@ export default function OrganizationsPage({
|
||||
setEditingAssignmentId(null);
|
||||
}
|
||||
return ok;
|
||||
}, [assignmentDraft, canAssignFunctions, editingAssignmentId, runAction, settings]);
|
||||
}, [assignmentDraft, canAssignFunctions, editingAssignmentId, runAction, settings, withChangeRequest]);
|
||||
|
||||
const saveDrafts = useCallback(async (): Promise<boolean> => {
|
||||
if (isSluggedDirty(unitTypeDraft) && !(await submitUnitType())) return false;
|
||||
@@ -728,36 +795,36 @@ export default function OrganizationsPage({
|
||||
});
|
||||
|
||||
const toggleUnitType = useCallback((item: OrganizationUnitTypeItem) => {
|
||||
void runAction(() => patchUnitType(settings, item.id, { is_active: !item.is_active }));
|
||||
}, [runAction, settings]);
|
||||
void runAction(() => patchUnitType(settings, item.id, withChangeRequest({ is_active: !item.is_active })));
|
||||
}, [runAction, settings, withChangeRequest]);
|
||||
|
||||
const toggleStructure = useCallback((item: OrganizationStructureItem) => {
|
||||
void runAction(() => patchStructure(settings, item.id, { is_active: !item.is_active }));
|
||||
}, [runAction, settings]);
|
||||
void runAction(() => patchStructure(settings, item.id, withChangeRequest({ is_active: !item.is_active })));
|
||||
}, [runAction, settings, withChangeRequest]);
|
||||
|
||||
const toggleRelationType = useCallback((item: OrganizationRelationTypeItem) => {
|
||||
void runAction(() => patchRelationType(settings, item.id, { is_active: !item.is_active }));
|
||||
}, [runAction, settings]);
|
||||
void runAction(() => patchRelationType(settings, item.id, withChangeRequest({ is_active: !item.is_active })));
|
||||
}, [runAction, settings, withChangeRequest]);
|
||||
|
||||
const toggleUnit = useCallback((item: OrganizationUnitItem) => {
|
||||
void runAction(() => patchUnit(settings, item.id, { is_active: !item.is_active }));
|
||||
}, [runAction, settings]);
|
||||
void runAction(() => patchUnit(settings, item.id, withChangeRequest({ is_active: !item.is_active })));
|
||||
}, [runAction, settings, withChangeRequest]);
|
||||
|
||||
const toggleRelation = useCallback((item: OrganizationRelationItem) => {
|
||||
void runAction(() => patchRelation(settings, item.id, { is_active: !item.is_active }));
|
||||
}, [runAction, settings]);
|
||||
void runAction(() => patchRelation(settings, item.id, withChangeRequest({ is_active: !item.is_active })));
|
||||
}, [runAction, settings, withChangeRequest]);
|
||||
|
||||
const toggleFunctionType = useCallback((item: OrganizationFunctionTypeItem) => {
|
||||
void runAction(() => patchFunctionType(settings, item.id, { is_active: !item.is_active }));
|
||||
}, [runAction, settings]);
|
||||
void runAction(() => patchFunctionType(settings, item.id, withChangeRequest({ is_active: !item.is_active })));
|
||||
}, [runAction, settings, withChangeRequest]);
|
||||
|
||||
const toggleFunction = useCallback((item: OrganizationFunctionItem) => {
|
||||
void runAction(() => patchFunction(settings, item.id, { is_active: !item.is_active }));
|
||||
}, [runAction, settings]);
|
||||
void runAction(() => patchFunction(settings, item.id, withChangeRequest({ is_active: !item.is_active })));
|
||||
}, [runAction, settings, withChangeRequest]);
|
||||
|
||||
const toggleAssignment = useCallback((item: OrganizationFunctionAssignmentItem) => {
|
||||
void runAction(() => patchFunctionAssignment(settings, item.id, { is_active: !item.is_active }));
|
||||
}, [runAction, settings]);
|
||||
void runAction(() => patchFunctionAssignment(settings, item.id, withChangeRequest({ is_active: !item.is_active })));
|
||||
}, [runAction, settings, withChangeRequest]);
|
||||
|
||||
const editUnitType = useCallback((item: OrganizationUnitTypeItem) => {
|
||||
setEditingUnitTypeId(item.id);
|
||||
@@ -913,7 +980,7 @@ export default function OrganizationsPage({
|
||||
];
|
||||
|
||||
const assignmentColumns: DataGridColumn<OrganizationFunctionAssignmentItem>[] = [
|
||||
{ id: "identity", header: "i18n:govoplan-organizations.identity_id.b6ef5010", minWidth: 220, render: (row) => <span className="organizations-id">{row.identity_id}</span> },
|
||||
{ id: "identity", header: "i18n:govoplan-organizations.identity.3252f35f", minWidth: 220, render: (row) => identityDisplay(row.identity_id, identityOptionById) },
|
||||
{ id: "function", header: "i18n:govoplan-organizations.function.28822f3a", minWidth: 190, render: (row) => optionalLabel(functionById.get(row.function_id)?.name) },
|
||||
{ id: "unit", header: "i18n:govoplan-organizations.unit.8fe4d595", minWidth: 180, render: (row) => optionalLabel(unitById.get(row.organization_unit_id)?.name) },
|
||||
{ id: "subunits", header: "i18n:govoplan-organizations.applies_to_subunits.7a15f741", width: 150, render: (row) => activeStatus(row.applies_to_subunits) },
|
||||
@@ -936,6 +1003,10 @@ export default function OrganizationsPage({
|
||||
<p>{description}</p>
|
||||
</div>
|
||||
<div className="organizations-toolbar">
|
||||
<label className="organizations-change-request">
|
||||
<span>i18n:govoplan-organizations.change_request_id.a6e7fd6b</span>
|
||||
<input value={changeRequestId} onChange={(event) => setChangeRequestId(event.target.value)} placeholder="cfgreq-..." disabled={busy} />
|
||||
</label>
|
||||
<Button type="button" onClick={() => void loadModel()} disabled={loading || busy} title="i18n:govoplan-organizations.reload.cce71553">
|
||||
<RefreshCw size={16} aria-hidden="true" /> i18n:govoplan-organizations.reload.cce71553
|
||||
</Button>
|
||||
@@ -1232,15 +1303,52 @@ export default function OrganizationsPage({
|
||||
}
|
||||
|
||||
function renderAssignmentsSection() {
|
||||
const selectedIdentity = identityOptionById.get(assignmentDraft.identity_id);
|
||||
return (
|
||||
<div className="organizations-section-grid">
|
||||
<Card title="i18n:govoplan-organizations.add_assignment.6682f5f5">
|
||||
<form className="organizations-form-grid" onSubmit={(event) => void submitAssignment(event)}>
|
||||
<FormField label="i18n:govoplan-organizations.identity_id.b6ef5010">
|
||||
<input value={assignmentDraft.identity_id} placeholder="i18n:govoplan-organizations.identity_id_placeholder.298cbd85" disabled={!canAssignFunctions || busy} onChange={(event) => setAssignmentDraft({ ...assignmentDraft, identity_id: event.target.value })} />
|
||||
</FormField>
|
||||
{identityLookupAvailable ? (
|
||||
<div className="organizations-identity-picker wide">
|
||||
<FormField label="i18n:govoplan-organizations.identity_search.eff6eb16">
|
||||
<input value={identitySearch} placeholder="i18n:govoplan-organizations.search_identities.004afdfd" disabled={!canAssignFunctions || busy} onChange={(event) => setIdentitySearch(event.target.value)} />
|
||||
</FormField>
|
||||
<FormField label="i18n:govoplan-organizations.identity.3252f35f">
|
||||
<select
|
||||
value={assignmentDraft.identity_id}
|
||||
disabled={!canAssignFunctions || busy || identityLoading}
|
||||
onChange={(event) => {
|
||||
const identity = identityOptionById.get(event.target.value);
|
||||
setAssignmentDraft({
|
||||
...assignmentDraft,
|
||||
identity_id: event.target.value,
|
||||
account_id: identity?.primary_account_id ?? identity?.account_ids[0] ?? ""
|
||||
});
|
||||
}}
|
||||
>
|
||||
<option value="">{identityLoading ? "i18n:govoplan-organizations.loading_identities.9c31d2b5" : "i18n:govoplan-organizations.select_identity.510f1134"}</option>
|
||||
{assignmentDraft.identity_id && !identityOptionById.has(assignmentDraft.identity_id) && <option value={assignmentDraft.identity_id}>{assignmentDraft.identity_id}</option>}
|
||||
{identityOptions.map((identity) => <option key={identity.id} value={identity.id}>{identityOptionLabel(identity)}</option>)}
|
||||
</select>
|
||||
</FormField>
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<p className="organizations-muted wide">i18n:govoplan-organizations.identity_lookup_unavailable.5a3e77b2</p>
|
||||
<FormField label="i18n:govoplan-organizations.identity_id.b6ef5010">
|
||||
<input value={assignmentDraft.identity_id} placeholder="i18n:govoplan-organizations.identity_id_placeholder.298cbd85" disabled={!canAssignFunctions || busy} onChange={(event) => setAssignmentDraft({ ...assignmentDraft, identity_id: event.target.value })} />
|
||||
</FormField>
|
||||
</>
|
||||
)}
|
||||
<FormField label="i18n:govoplan-organizations.optional_account_id.5fcf495c">
|
||||
<input value={assignmentDraft.account_id} disabled={!canAssignFunctions || busy} onChange={(event) => setAssignmentDraft({ ...assignmentDraft, account_id: event.target.value })} />
|
||||
{selectedIdentity && selectedIdentity.account_ids.length > 0 ? (
|
||||
<select value={assignmentDraft.account_id} disabled={!canAssignFunctions || busy} onChange={(event) => setAssignmentDraft({ ...assignmentDraft, account_id: event.target.value })}>
|
||||
<option value="">i18n:govoplan-organizations.none.334c4a4c</option>
|
||||
{selectedIdentity.account_ids.map((accountId) => <option key={accountId} value={accountId}>{accountId}</option>)}
|
||||
</select>
|
||||
) : (
|
||||
<input value={assignmentDraft.account_id} disabled={!canAssignFunctions || busy} onChange={(event) => setAssignmentDraft({ ...assignmentDraft, account_id: event.target.value })} />
|
||||
)}
|
||||
</FormField>
|
||||
<FormField label="i18n:govoplan-organizations.function.28822f3a">
|
||||
<select value={assignmentDraft.function_id} disabled={!canAssignFunctions || busy} onChange={(event) => setAssignmentDraft({ ...assignmentDraft, function_id: event.target.value })}>
|
||||
|
||||
Reference in New Issue
Block a user