diff --git a/src/components/Form/IpaCheckboxes.tsx b/src/components/Form/IpaCheckboxes.tsx new file mode 100644 index 000000000..9ff8814f2 --- /dev/null +++ b/src/components/Form/IpaCheckboxes.tsx @@ -0,0 +1,78 @@ +import React from "react"; +// PatternFly +import { Checkbox } from "@patternfly/react-core"; +// Utils +import { + IPAParamDefinitionCheckboxes, + getParamPropertiesCheckBoxes, + updateIpaObject, +} from "src/utils/ipaObjectUtils"; + +export interface CheckboxOption { + value: string; + text: string; + className?: string; +} + +const IpaCheckboxes = (props: IPAParamDefinitionCheckboxes) => { + const { required, readOnly, checkedValues } = + getParamPropertiesCheckBoxes(props); + + const [checkedList, setCheckedList] = React.useState(checkedValues); + + // Updates the 'checkedList' when 'checkedValues' changes + React.useEffect(() => { + setCheckedList(checkedValues); + }, [checkedValues]); + + // Updates the list of checked values when a specific checkbox is clicked + // - This is implemented here because we need to know which specific + // value (option.value) to add/remove from the list + const updateList = (checked: boolean, elementToChange: string) => { + if ( + props.ipaObject !== undefined && + props.ipaObject[props.name] !== undefined && + props.onChange !== undefined + ) { + const updatedList = [...(props.ipaObject[props.name] as string[])]; + if (checked) { + updatedList.push(elementToChange); + } else { + const index = updatedList.indexOf(elementToChange); + if (index > -1) { + updatedList.splice(index, 1); + } + } + // Update the list of checked values + setCheckedList(updatedList); + // Update the IPA object + updateIpaObject(props.ipaObject, props.onChange, updatedList, props.name); + } + }; + + return ( + <> + {props.options.map((option) => ( + updateList(checked, option.value)} + isRequired={required} + readOnly={readOnly} + isChecked={ + checkedList.find((val) => val === option.value) !== undefined + ? true + : false + } + aria-label={props.name} + className={option.className} + isDisabled={readOnly} + /> + ))} + + ); +}; + +export default IpaCheckboxes; diff --git a/src/components/UsersSections/UsersAccountSettings.tsx b/src/components/UsersSections/UsersAccountSettings.tsx index 5f0badee6..fcf1ffad7 100644 --- a/src/components/UsersSections/UsersAccountSettings.tsx +++ b/src/components/UsersSections/UsersAccountSettings.tsx @@ -7,7 +7,6 @@ import { Form, FormGroup, TextInput, - Checkbox, DropdownItem, CalendarMonth, Button, @@ -33,6 +32,7 @@ import { asRecord } from "src/utils/userUtils"; // Form import IpaTextInput from "src/components/Form/IpaTextInput"; import IpaSelect from "../Form/IpaSelect"; +import IpaCheckboxes, { CheckboxOption } from "../Form/IpaCheckboxes"; interface PropsToUsersAccountSettings { user: Partial; @@ -74,6 +74,39 @@ const UsersAccountSettings = (props: PropsToUsersAccountSettings) => { }, ]); + // Checkboxes options + const options: CheckboxOption[] = [ + { + value: "password", + text: "Password", + className: "pf-u-mt-xs pf-u-mb-sm", + }, + { + value: "radius", + text: "RADIUS", + className: "pf-u-mt-xs pf-u-mb-sm", + }, + { + value: "otp", + text: "Two-factor authentication (password + OTP)", + className: "pf-u-mt-xs pf-u-mb-sm", + }, + { + value: "pkinit", + text: "PKINIT", + className: "pf-u-mt-xs pf-u-mb-sm", + }, + { + value: "hardened", + text: "Hardened password (by SPAKE or FAST)", + className: "pf-u-mt-xs pf-u-mb-sm", + }, + { + value: "idp", + text: "External Identity Provider", + }, + ]; + // Principal alias // - 'Add principal alias' handler const onAddPrincipalAliasFieldHandler = () => { @@ -346,14 +379,6 @@ const UsersAccountSettings = (props: PropsToUsersAccountSettings) => { , ]; - // Checkboxes - const [passwordCheckbox] = useState(false); - const [radiusCheckbox] = useState(false); - const [tpaCheckbox] = useState(false); - const [pkinitCheckbox] = useState(false); - const [hardenedPassCheckbox] = useState(false); - const [extIdentityProvCheckbox] = useState(false); - // Date and time picker (Calendar) const [isCalendarOpen, setIsCalendarOpen] = React.useState(false); const [isTimeOpen, setIsTimeOpen] = React.useState(false); @@ -626,58 +651,13 @@ const UsersAccountSettings = (props: PropsToUsersAccountSettings) => { } > - - - - - - ; + onChange?: (ipaObject: IPAObject) => void; + objectName: string; + metadata: Metadata; + propertyName?: string; + alwaysWritable?: boolean; + readOnly?: boolean; + required?: boolean; + className?: string; + options: CheckboxOption[]; } export interface ParamProperties { @@ -25,6 +45,15 @@ export interface ParamProperties { paramMetadata: ParamMetadata; } +export interface ParamPropertiesCheckboxes { + writable: boolean; + required: boolean; + readOnly: boolean; + value: BasicType; + paramMetadata: ParamMetadata; + checkedValues: string[]; +} + export function getParamMetadata( metadata: Metadata, objectName: string, @@ -147,6 +176,7 @@ export function getParamProperties( parDef.onChange({ ...parDef.ipaObject, [propName]: value }); } }; + return { writable, required, @@ -157,6 +187,49 @@ export function getParamProperties( }; } +export function getParamPropertiesCheckBoxes( + parDef: IPAParamDefinitionCheckboxes +): ParamPropertiesCheckboxes { + const propName = parDef.propertyName || parDef.name; + const paramMetadata = getParamMetadata( + parDef.metadata, + parDef.objectName, + propName + ); + if (!paramMetadata) { + return { + writable: false, + required: false, + readOnly: true, + value: "", + paramMetadata: {} as ParamMetadata, + checkedValues: [], + }; + } + const writable = isWritable( + paramMetadata, + parDef.ipaObject, + parDef.alwaysWritable + ); + const required = isRequired(parDef, paramMetadata, writable); + const readOnly = parDef.readOnly === undefined ? !writable : parDef.readOnly; + + const value = getValue(parDef.ipaObject, propName); + + const checkedValues = parDef.ipaObject !== undefined && parDef.ipaObject[propName] !== undefined + ? parDef.ipaObject[propName] as string[] + : []; + + return { + writable, + required, + readOnly, + value, + paramMetadata, + checkedValues, + }; +} + export function convertToString(value: BasicType): string { if (value === null || value === undefined) { return "";