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

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

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

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

Loading…
Cancel
Save