fix(striker-ui): revise GateForm to use form event

main
Tsu-ba-me 2 years ago
parent 9878d03ee5
commit 95ce723b86
  1. 285
      striker-ui/components/GateForm.tsx
  2. 23
      striker-ui/components/PrepareHostForm.tsx
  3. 11
      striker-ui/types/GateForm.d.ts

@ -1,7 +1,6 @@
import { SxProps, Theme } from '@mui/material'; import { Box, BoxProps, SxProps, Theme } from '@mui/material';
import { import {
forwardRef, forwardRef,
useCallback,
useImperativeHandle, useImperativeHandle,
useMemo, useMemo,
useRef, useRef,
@ -17,26 +16,22 @@ import InputWithRef, { InputForwardedRefContent } from './InputWithRef';
import MessageGroup, { MessageGroupForwardedRefContent } from './MessageGroup'; import MessageGroup, { MessageGroupForwardedRefContent } from './MessageGroup';
import OutlinedInputWithLabel from './OutlinedInputWithLabel'; import OutlinedInputWithLabel from './OutlinedInputWithLabel';
import Spinner from './Spinner'; import Spinner from './Spinner';
import { import { buildPeacefulStringTestBatch } from '../lib/test_input';
buildPeacefulStringTestBatch, import useFormUtils from '../hooks/useFormUtils';
createTestInputFunction,
} from '../lib/test_input';
const INPUT_ROOT_SX: SxProps<Theme> = { width: '100%' }; const INPUT_ROOT_SX: SxProps<Theme> = { width: '100%' };
const IT_IDS = {
identifier: 'identifier', const INPUT_ID_PREFIX_GATE = 'gate-input';
passphrase: 'passphrase',
}; const INPUT_ID_GATE_ID = `${INPUT_ID_PREFIX_GATE}-credential-id`;
const MESSAGE_KEY: GateFormMessageKey = { const INPUT_ID_GATE_PASSPHRASE = `${INPUT_ID_PREFIX_GATE}-credential-passphrase`;
accessError: 'accessError',
identifierInputError: 'identifierInputError', const MSG_ID_GATE_ACCESS = 'access';
passphraseInputError: 'passphraseInputError',
};
const GateForm = forwardRef<GateFormForwardedRefContent, GateFormProps>( const GateForm = forwardRef<GateFormForwardedRefContent, GateFormProps>(
( (
{ {
allowSubmit: isAllowSubmit = true, formContainer: isFormContainer = true,
gridProps: { gridProps: {
columns: gridColumns = { xs: 1, sm: 2 }, columns: gridColumns = { xs: 1, sm: 2 },
layout, layout,
@ -49,7 +44,8 @@ const GateForm = forwardRef<GateFormForwardedRefContent, GateFormProps>(
inputProps: identifierInputProps, inputProps: identifierInputProps,
...restIdentifierOutlinedInputWithLabelProps ...restIdentifierOutlinedInputWithLabelProps
} = {}, } = {},
identifierInputTestBatchBuilder: overwriteIdentifierInputTestBatch, identifierInputTestBatchBuilder:
buildIdentifierInputTestBatch = buildPeacefulStringTestBatch,
onIdentifierBlurAppend, onIdentifierBlurAppend,
onSubmit, onSubmit,
onSubmitAppend, onSubmitAppend,
@ -72,151 +68,83 @@ const GateForm = forwardRef<GateFormForwardedRefContent, GateFormProps>(
const inputPassphraseRef = useRef<InputForwardedRefContent<'string'>>({}); const inputPassphraseRef = useRef<InputForwardedRefContent<'string'>>({});
const messageGroupRef = useRef<MessageGroupForwardedRefContent>({}); const messageGroupRef = useRef<MessageGroupForwardedRefContent>({});
const [isInputIdentifierValid, setIsInputIdentifierValid] =
useState<boolean>(false);
const [isInputPassphraseValid, setIsInputPassphraseValid] =
useState<boolean>(false);
const [isSubmitting, setIsSubmitting] = useState<boolean>(false); const [isSubmitting, setIsSubmitting] = useState<boolean>(false);
const setAccessErrorMessage: GateFormMessageSetter = useCallback( const formUtils = useFormUtils(
(message?) => { [INPUT_ID_GATE_ID, INPUT_ID_GATE_PASSPHRASE],
messageGroupRef.current.setMessage?.call( messageGroupRef,
null,
MESSAGE_KEY.accessError,
message,
);
},
[],
);
const setIdentifierInputErrorMessage: GateFormMessageSetter = useCallback(
(message?) => {
messageGroupRef.current.setMessage?.call(
null,
MESSAGE_KEY.identifierInputError,
message,
);
},
[],
);
const setPassphraseInputErrorMessage: GateFormMessageSetter = useCallback(
(message?) => {
messageGroupRef.current.setMessage?.call(
null,
MESSAGE_KEY.passphraseInputError,
message,
);
},
[],
); );
const {
buildFinishInputTestBatchFunction,
buildInputFirstRenderFunction,
buildInputUnmountFunction,
isFormInvalid,
setMessage,
} = formUtils;
const messagesGroupSxDisplay = useMemo( const submitHandler: DivFormEventHandler = useMemo(
() => (isAllowSubmit ? undefined : 'none'),
[isAllowSubmit],
);
const identifierInputTestBatch = useMemo(
() =>
overwriteIdentifierInputTestBatch?.call(
null,
setIdentifierInputErrorMessage,
inputIdentifierRef.current,
) ??
buildPeacefulStringTestBatch(
identifierLabel,
() => {
setIdentifierInputErrorMessage();
},
{ getValue: inputIdentifierRef.current.getValue },
(message) => {
setIdentifierInputErrorMessage({
children: message,
type: 'warning',
});
},
),
[
identifierLabel,
overwriteIdentifierInputTestBatch,
setIdentifierInputErrorMessage,
],
);
const inputTests: InputTestBatches = useMemo(
() => ({
[IT_IDS.identifier]: identifierInputTestBatch,
[IT_IDS.passphrase]: buildPeacefulStringTestBatch(
passphraseLabel,
() => {
setPassphraseInputErrorMessage();
},
{ getValue: inputPassphraseRef.current.getValue },
(message) => {
setPassphraseInputErrorMessage({
children: message,
type: 'warning',
});
},
),
}),
[
identifierInputTestBatch,
passphraseLabel,
setPassphraseInputErrorMessage,
],
);
const submitHandler: ContainedButtonProps['onClick'] = useMemo(
() => () =>
onSubmit ?? onSubmit ??
((...args) => { ((...args) => {
setAccessErrorMessage(); const { 0: event } = args;
event.preventDefault();
setMessage(MSG_ID_GATE_ACCESS);
setIsSubmitting(true); setIsSubmitting(true);
onSubmitAppend?.call( onSubmitAppend?.call(
null, null,
inputIdentifierRef.current, inputIdentifierRef.current,
inputPassphraseRef.current, inputPassphraseRef.current,
setAccessErrorMessage, (message?) => {
setMessage(MSG_ID_GATE_ACCESS, message);
},
setIsSubmitting, setIsSubmitting,
messageGroupRef.current, messageGroupRef.current,
...args, ...args,
); );
}), }),
[onSubmit, onSubmitAppend, setAccessErrorMessage], [onSubmit, onSubmitAppend, setMessage],
); );
const submitElement = useMemo( const submitElement = useMemo(
() => () =>
isSubmitting ? ( isSubmitting ? (
<Spinner mt={0} /> <Spinner mt={0} />
) : ( ) : (
<FlexBox row sx={{ justifyContent: 'flex-end' }}> <FlexBox row sx={{ justifyContent: 'flex-end' }}>
<ContainedButton <ContainedButton disabled={isFormInvalid} type="submit">
disabled={!isInputIdentifierValid || !isInputPassphraseValid}
onClick={submitHandler}
>
{submitLabel} {submitLabel}
</ContainedButton> </ContainedButton>
</FlexBox> </FlexBox>
), ),
[ [isFormInvalid, isSubmitting, submitLabel],
isInputIdentifierValid,
isInputPassphraseValid,
isSubmitting,
submitHandler,
submitLabel,
],
); );
const submitGrid = useMemo(
() => const submitAreaGridLayout = useMemo(() => {
isAllowSubmit const result: GridLayout = {};
? {
children: submitElement, if (isFormContainer) {
result['gate-cell-message-group'] = {
children: <MessageGroup count={1} ref={messageGroupRef} />,
sm: 2, sm: 2,
};
result['gate-cell-submit'] = { children: submitElement, sm: 2 };
} }
: undefined,
[isAllowSubmit, submitElement],
);
const testInput = useMemo( return result;
() => createTestInputFunction(inputTests), }, [isFormContainer, submitElement]);
[inputTests],
); const containerProps = useMemo(() => {
const result: BoxProps = {};
if (isFormContainer) {
result.component = 'form';
result.onSubmit = submitHandler;
}
return result;
}, [isFormContainer, submitHandler]);
useImperativeHandle(ref, () => ({ useImperativeHandle(ref, () => ({
get: () => ({ get: () => ({
@ -232,10 +160,11 @@ const GateForm = forwardRef<GateFormForwardedRefContent, GateFormProps>(
})); }));
return ( return (
<Box {...containerProps}>
<Grid <Grid
columns={gridColumns} columns={gridColumns}
layout={{ layout={{
'credential-identifier': { 'gate-input-cell-credential-id': {
children: ( children: (
<InputWithRef <InputWithRef
input={ input={
@ -244,34 +173,38 @@ const GateForm = forwardRef<GateFormForwardedRefContent, GateFormProps>(
...restIdentifierFormControlProps, ...restIdentifierFormControlProps,
sx: { ...INPUT_ROOT_SX, ...identifierSx }, sx: { ...INPUT_ROOT_SX, ...identifierSx },
}} }}
id="credential-identifier-input" id={INPUT_ID_GATE_ID}
inputProps={{ inputProps={identifierInputProps}
onBlur: (event) => {
const {
target: { value },
} = event;
const valid = testInput({
inputs: { [IT_IDS.identifier]: { value } },
});
setIsInputIdentifierValid(valid);
onIdentifierBlurAppend?.call(null, event);
},
onFocus: () => {
setIdentifierInputErrorMessage();
},
...identifierInputProps,
}}
label={identifierLabel} label={identifierLabel}
{...restIdentifierOutlinedInputWithLabelProps} {...restIdentifierOutlinedInputWithLabelProps}
/> />
} }
inputTestBatch={buildIdentifierInputTestBatch(
identifierLabel,
() => {
setMessage(INPUT_ID_GATE_ID);
},
{
onFinishBatch:
buildFinishInputTestBatchFunction(INPUT_ID_GATE_ID),
},
(message) => {
setMessage(INPUT_ID_GATE_ID, { children: message });
},
)}
onBlurAppend={(...args) => {
onIdentifierBlurAppend?.call(null, ...args);
}}
onFirstRender={buildInputFirstRenderFunction(
INPUT_ID_GATE_ID,
)}
onUnmount={buildInputUnmountFunction(INPUT_ID_GATE_ID)}
ref={inputIdentifierRef} ref={inputIdentifierRef}
required
/> />
), ),
}, },
'credential-passphrase': { 'gate-input-cell-credential-passphrase': {
children: ( children: (
<InputWithRef <InputWithRef
input={ input={
@ -280,42 +213,52 @@ const GateForm = forwardRef<GateFormForwardedRefContent, GateFormProps>(
...restPassphraseFormControlProps, ...restPassphraseFormControlProps,
sx: { ...INPUT_ROOT_SX, ...passphraseSx }, sx: { ...INPUT_ROOT_SX, ...passphraseSx },
}} }}
id="credential-passphrase-input" id={INPUT_ID_GATE_PASSPHRASE}
inputProps={{ inputProps={passphraseInputProps}
onBlur: ({ target: { value } }) => {
const valid = testInput({
inputs: { [IT_IDS.passphrase]: { value } },
});
setIsInputPassphraseValid(valid);
},
onFocus: () => {
setPassphraseInputErrorMessage();
},
type: INPUT_TYPES.password,
...passphraseInputProps,
}}
label={passphraseLabel} label={passphraseLabel}
type={INPUT_TYPES.password}
{...restPassphraseOutlinedInputWithLabelProps} {...restPassphraseOutlinedInputWithLabelProps}
/> />
} }
inputTestBatch={buildPeacefulStringTestBatch(
passphraseLabel,
() => {
setMessage(INPUT_ID_GATE_PASSPHRASE);
},
{
onFinishBatch: buildFinishInputTestBatchFunction(
INPUT_ID_GATE_PASSPHRASE,
),
},
(message) => {
setMessage(INPUT_ID_GATE_PASSPHRASE, {
children: message,
});
},
)}
onFirstRender={buildInputFirstRenderFunction(
INPUT_ID_GATE_PASSPHRASE,
)}
onUnmount={buildInputUnmountFunction(
INPUT_ID_GATE_PASSPHRASE,
)}
ref={inputPassphraseRef} ref={inputPassphraseRef}
required
/> />
), ),
}, },
'credential-message-group': { ...submitAreaGridLayout,
children: <MessageGroup count={1} ref={messageGroupRef} />,
sm: 2,
sx: { display: messagesGroupSxDisplay },
},
'credential-submit': submitGrid,
}} }}
spacing={gridSpacing} spacing={gridSpacing}
{...restGridProps} {...restGridProps}
/> />
</Box>
); );
}, },
); );
GateForm.displayName = 'GateForm'; GateForm.displayName = 'GateForm';
export { INPUT_ID_GATE_ID, INPUT_ID_GATE_PASSPHRASE };
export default GateForm; export default GateForm;

@ -58,7 +58,6 @@ const PrepareHostForm: FC = () => {
const { protect } = useProtect(); const { protect } = useProtect();
const confirmDialogRef = useRef<ConfirmDialogForwardedRefContent>({}); const confirmDialogRef = useRef<ConfirmDialogForwardedRefContent>({});
const gateFormRef = useRef<GateFormForwardedRefContent>({});
const inputEnterpriseKeyRef = useRef<InputForwardedRefContent<'string'>>({}); const inputEnterpriseKeyRef = useRef<InputForwardedRefContent<'string'>>({});
const inputHostNameRef = useRef<InputForwardedRefContent<'string'>>({}); const inputHostNameRef = useRef<InputForwardedRefContent<'string'>>({});
const inputRedhatPassword = useRef<InputForwardedRefContent<'string'>>({}); const inputRedhatPassword = useRef<InputForwardedRefContent<'string'>>({});
@ -199,7 +198,7 @@ const PrepareHostForm: FC = () => {
const accessSection = useMemo( const accessSection = useMemo(
() => ( () => (
<GateForm <GateForm
allowSubmit={isShowAccessSubmit} formContainer={isShowAccessSubmit}
gridProps={{ gridProps={{
wrapperBoxProps: { wrapperBoxProps: {
sx: { sx: {
@ -207,18 +206,7 @@ const PrepareHostForm: FC = () => {
}, },
}, },
}} }}
identifierInputTestBatchBuilder={(setMessage) => identifierInputTestBatchBuilder={buildIPAddressTestBatch}
buildIPAddressTestBatch(
HOST_IP_LABEL,
() => {
setMessage();
},
undefined,
(message) => {
setMessage({ children: message, type: 'warning' });
},
)
}
identifierLabel={HOST_IP_LABEL} identifierLabel={HOST_IP_LABEL}
onIdentifierBlurAppend={({ target: { value } }) => { onIdentifierBlurAppend={({ target: { value } }) => {
if (connectedHostIPAddress) { if (connectedHostIPAddress) {
@ -291,17 +279,16 @@ const PrepareHostForm: FC = () => {
} }
}, },
) )
.catch((error) => { .catch((apiError) => {
const errorMessage = handleAPIError(error); const emsg = handleAPIError(apiError);
setMessage?.call(null, errorMessage); setMessage?.call(null, emsg);
}) })
.finally(() => { .finally(() => {
setIsSubmitting(false); setIsSubmitting(false);
}); });
}} }}
passphraseLabel="Host root password" passphraseLabel="Host root password"
ref={gateFormRef}
submitLabel="Test access" submitLabel="Test access"
/> />
), ),

@ -15,21 +15,18 @@ type GateFormSubmitHandler = (
setMessage: GateFormMessageSetter, setMessage: GateFormMessageSetter,
setIsSubmitting: GateFormSubmittingSetter, setIsSubmitting: GateFormSubmittingSetter,
messageGroupContent: import('../components/MessageGroup').MessageGroupForwardedRefContent, messageGroupContent: import('../components/MessageGroup').MessageGroupForwardedRefContent,
...args: Parameters<ContainedButtonProps['onClick']> ...args: Parameters<DivFormEventHandler>
) => void; ) => void;
type GateFormOptionalProps = { type GateFormOptionalProps = {
allowSubmit?: boolean; formContainer?: boolean;
gridProps?: Partial<GridProps>; gridProps?: Partial<GridProps>;
identifierOutlinedInputWithLabelProps?: Partial< identifierOutlinedInputWithLabelProps?: Partial<
import('../components/OutlinedInputWithLabel').OutlinedInputWithLabelProps import('../components/OutlinedInputWithLabel').OutlinedInputWithLabelProps
>; >;
identifierInputTestBatchBuilder?: ( identifierInputTestBatchBuilder?: BuildInputTestBatchFunction;
setMessage: GateFormMessageSetter,
identifierContent: import('../components/InputWithRef').InputForwardedRefContent<'string'>,
) => ReturnType<BuildInputTestBatchFunction>;
onIdentifierBlurAppend?: import('../components/OutlinedInput').OutlinedInputProps['onBlur']; onIdentifierBlurAppend?: import('../components/OutlinedInput').OutlinedInputProps['onBlur'];
onSubmit?: ContainedButtonProps['onClick']; onSubmit?: DivFormEventHandler;
onSubmitAppend?: GateFormSubmitHandler; onSubmitAppend?: GateFormSubmitHandler;
passphraseOutlinedInputWithLabelProps?: Partial< passphraseOutlinedInputWithLabelProps?: Partial<
import('../components/OutlinedInputWithLabel').OutlinedInputWithLabelProps import('../components/OutlinedInputWithLabel').OutlinedInputWithLabelProps

Loading…
Cancel
Save