import { Box, styled, Tooltip } from '@mui/material'; import { ReactElement, ReactNode, useMemo } from 'react'; import INPUT_TYPES from '../../lib/consts/INPUT_TYPES'; import FlexBox from '../FlexBox'; import InputWithRef from '../InputWithRef'; import OutlinedInputWithLabel from '../OutlinedInputWithLabel'; import { ExpandablePanel } from '../Panels'; import SelectWithLabel from '../SelectWithLabel'; import SwitchWithLabel from '../SwitchWithLabel'; import { buildIPAddressTestBatch, buildNumberTestBatch, buildPeacefulStringTestBatch, testNotBlank, } from '../../lib/test_input'; import { BodyText } from '../Text'; const CHECKED_STATES: Array = ['1', 'on']; const INPUT_ID_SEPARATOR = '-'; const getStringParamInputTestBatch = ({ formUtils: { buildFinishInputTestBatchFunction, setMessage }, id, label, }: { formUtils: FormUtils; id: string; label: string; }) => { const onFinishBatch = buildFinishInputTestBatchFunction(id); const onSuccess = () => { setMessage(id); }; return label.toLowerCase() === 'ip' ? buildIPAddressTestBatch( label, onSuccess, { onFinishBatch }, (message) => { setMessage(id, { children: message }); }, ) : { defaults: { onSuccess, }, onFinishBatch, tests: [{ test: testNotBlank }], }; }; const buildNumberParamInput = ( args: FenceParameterInputBuilderParameters, ): ReactElement => { const { formUtils, id, isRequired, label = '', name = id, value } = args; const { buildFinishInputTestBatchFunction, buildInputFirstRenderFunction, setMessage, } = formUtils; return ( } inputTestBatch={buildNumberTestBatch( label, () => { setMessage(id); }, { onFinishBatch: buildFinishInputTestBatchFunction(id) }, (message) => { setMessage(id, { children: message }); }, )} onFirstRender={buildInputFirstRenderFunction(id)} required={isRequired} valueType="number" /> ); }; const MAP_TO_INPUT_BUILDER: MapToInputBuilder> = { boolean: (args) => { const { id, isChecked = false, label, name = id } = args; return ( } valueType="boolean" /> ); }, integer: buildNumberParamInput, second: buildNumberParamInput, select: (args) => { const { formUtils, id, isRequired, label, name = id, selectOptions = [], value = '', } = args; const { buildFinishInputTestBatchFunction, buildInputFirstRenderFunction, setMessage, } = formUtils; return ( } inputTestBatch={{ defaults: { onSuccess: () => { setMessage(id); }, }, onFinishBatch: buildFinishInputTestBatchFunction(id), tests: [{ test: testNotBlank }], }} onFirstRender={buildInputFirstRenderFunction(id)} required={isRequired} /> ); }, string: (args) => { const { formUtils, id, isRequired, isSensitive = false, label = '', name = id, value, } = args; const { buildInputFirstRenderFunction } = formUtils; let inputType; if (isSensitive) { inputType = INPUT_TYPES.password; } return ( } inputTestBatch={getStringParamInputTestBatch({ formUtils, id, label })} onFirstRender={buildInputFirstRenderFunction(id)} required={isRequired} /> ); }, }; const combineIds = (...pieces: string[]) => pieces.join(INPUT_ID_SEPARATOR); const FenceInputWrapper = styled(FlexBox)({ margin: '.4em 0', }); const CommonFenceInputGroup = >({ fenceId, fenceParameterTooltipProps, fenceTemplate, formUtils, previousFenceName, previousFenceParameters, }: CommonFenceInputGroupProps): ReactElement => { const { buildFinishInputTestBatchFunction, buildInputFirstRenderFunction, setMessage, } = formUtils; const fenceParameterElements = useMemo(() => { let result: ReactNode; if (fenceTemplate && fenceId) { const { parameters: fenceParameters } = fenceTemplate[fenceId]; let mapToPreviousFenceParameterValues: FenceParameters = {}; if (previousFenceParameters) { mapToPreviousFenceParameterValues = Object.entries( previousFenceParameters, ).reduce((previous, [parameterId, parameterValue]) => { const newKey = combineIds(fenceId, parameterId); previous[newKey] = parameterValue; return previous; }, {}); } const { optional: optionalInputs, required: requiredInputs } = Object.entries(fenceParameters) .sort(([a], [b]) => (a > b ? 1 : -1)) .reduce<{ optional: ReactElement[]; required: ReactElement[]; }>( ( previous, [ parameterId, { content_type: parameterType, default: parameterDefault, deprecated: rawParameterDeprecated, description: parameterDescription, options: parameterSelectOptions, required: rawParameterRequired, }, ], ) => { const isParameterDeprecated = String(rawParameterDeprecated) === '1'; if (isParameterDeprecated) return previous; const { optional, required } = previous; const buildInput = MAP_TO_INPUT_BUILDER[parameterType] ?? MAP_TO_INPUT_BUILDER.string; const fenceJoinParameterId = combineIds(fenceId, parameterId); const initialValue = mapToPreviousFenceParameterValues[fenceJoinParameterId] ?? parameterDefault; const isParameterRequired = String(rawParameterRequired) === '1'; const isParameterSensitive = /passw/i.test(parameterId); const parameterInput = buildInput({ formUtils, id: fenceJoinParameterId, isChecked: CHECKED_STATES.includes(initialValue), isRequired: isParameterRequired, isSensitive: isParameterSensitive, label: parameterId, selectOptions: parameterSelectOptions, value: initialValue, }); const parameterInputWithTooltip = ( {parameterDescription}} {...fenceParameterTooltipProps} > {parameterInput} ); if (isParameterRequired) { required.push(parameterInputWithTooltip); } else { optional.push(parameterInputWithTooltip); } return previous; }, { optional: [], required: [], }, ); const inputIdFenceName = combineIds(fenceId, 'name'); const inputLabelFenceName = 'Fence device name'; result = ( div:first-child': { marginTop: 0 }, '& > div': { marginBottom: 0 }, }} > } inputTestBatch={buildPeacefulStringTestBatch( inputLabelFenceName, () => { setMessage(inputIdFenceName); }, { onFinishBatch: buildFinishInputTestBatchFunction(inputIdFenceName), }, (message) => { setMessage(inputIdFenceName, { children: message }); }, )} onFirstRender={buildInputFirstRenderFunction(inputIdFenceName)} required /> {requiredInputs} {optionalInputs} ); } return result; }, [ buildFinishInputTestBatchFunction, buildInputFirstRenderFunction, fenceId, fenceParameterTooltipProps, fenceTemplate, formUtils, previousFenceName, previousFenceParameters, setMessage, ]); return <>{fenceParameterElements}; }; export { INPUT_ID_SEPARATOR }; export default CommonFenceInputGroup;