fix(striker-ui): relocate input help messages, reorder inputs

main
Tsu-ba-me 2 years ago
parent c981c286b1
commit 7abca9b508
  1. 478
      striker-ui/components/GeneralInitForm.tsx

@ -1,9 +1,17 @@
import { Box as MUIBox } from '@mui/material'; import { Grid as MUIGrid } from '@mui/material';
import { forwardRef, useImperativeHandle, useRef, useState } from 'react'; import {
forwardRef,
ReactNode,
useCallback,
useImperativeHandle,
useRef,
useState,
} from 'react';
import FlexBox from './FlexBox'; import FlexBox from './FlexBox';
import InputWithRef, { InputForwardedRefContent } from './InputWithRef'; import InputWithRef, { InputForwardedRefContent } from './InputWithRef';
import isEmpty from '../lib/isEmpty'; import isEmpty from '../lib/isEmpty';
import MessageBox from './MessageBox';
import OutlinedInputWithLabel, { import OutlinedInputWithLabel, {
OutlinedInputWithLabelProps, OutlinedInputWithLabelProps,
} from './OutlinedInputWithLabel'; } from './OutlinedInputWithLabel';
@ -12,6 +20,7 @@ import SuggestButton from './SuggestButton';
type GeneralInitFormForwardRefContent = { type GeneralInitFormForwardRefContent = {
get?: () => { get?: () => {
adminPassword?: string;
organizationName?: string; organizationName?: string;
organizationPrefix?: string; organizationPrefix?: string;
domainName?: string; domainName?: string;
@ -66,6 +75,7 @@ const buildHostName = ({
const GeneralInitForm = forwardRef<GeneralInitFormForwardRefContent>( const GeneralInitForm = forwardRef<GeneralInitFormForwardRefContent>(
(generalInitFormProps, ref) => { (generalInitFormProps, ref) => {
const [helpMessage, setHelpText] = useState<ReactNode | undefined>();
const [ const [
isShowOrganizationPrefixSuggest, isShowOrganizationPrefixSuggest,
setIsShowOrganizationPrefixSuggest, setIsShowOrganizationPrefixSuggest,
@ -73,6 +83,12 @@ const GeneralInitForm = forwardRef<GeneralInitFormForwardRefContent>(
const [isShowHostNameSuggest, setIsShowHostNameSuggest] = const [isShowHostNameSuggest, setIsShowHostNameSuggest] =
useState<boolean>(false); useState<boolean>(false);
const adminPasswordInputRef = useRef<InputForwardedRefContent<'string'>>(
{},
);
const confirmAdminPasswordInputRef = useRef<
InputForwardedRefContent<'string'>
>({});
const organizationNameInputRef = useRef<InputForwardedRefContent<'string'>>( const organizationNameInputRef = useRef<InputForwardedRefContent<'string'>>(
{}, {},
); );
@ -83,52 +99,66 @@ const GeneralInitForm = forwardRef<GeneralInitFormForwardRefContent>(
const hostNumberInputRef = useRef<InputForwardedRefContent<'number'>>({}); const hostNumberInputRef = useRef<InputForwardedRefContent<'number'>>({});
const hostNameInputRef = useRef<InputForwardedRefContent<'string'>>({}); const hostNameInputRef = useRef<InputForwardedRefContent<'string'>>({});
const populateOrganizationPrefixInput = ({ const populateOrganizationPrefixInput = useCallback(
organizationName = organizationNameInputRef.current.getValue?.call(null), ({
} = {}) => { organizationName = organizationNameInputRef.current.getValue?.call(
const organizationPrefix = buildOrganizationPrefix(organizationName); null,
),
} = {}) => {
const organizationPrefix = buildOrganizationPrefix(organizationName);
organizationPrefixInputRef.current.setValue?.call( organizationPrefixInputRef.current.setValue?.call(
null, null,
organizationPrefix, organizationPrefix,
); );
return organizationPrefix; return organizationPrefix;
}; },
const populateHostNameInput = ({ [],
organizationPrefix = organizationPrefixInputRef.current.getValue?.call( );
null, const populateHostNameInput = useCallback(
), ({
hostNumber = hostNumberInputRef.current.getValue?.call(null), organizationPrefix = organizationPrefixInputRef.current.getValue?.call(
domainName = domainNameInputRef.current.getValue?.call(null), null,
} = {}) => { ),
const hostName = buildHostName({ hostNumber = hostNumberInputRef.current.getValue?.call(null),
organizationPrefix, domainName = domainNameInputRef.current.getValue?.call(null),
hostNumber, } = {}) => {
domainName, const hostName = buildHostName({
}); organizationPrefix,
hostNumber,
domainName,
});
hostNameInputRef.current.setValue?.call(null, hostName); hostNameInputRef.current.setValue?.call(null, hostName);
return hostName; return hostName;
}; },
const isOrganizationPrefixPrereqFilled = () => [],
isEmpty([organizationNameInputRef.current.getValue?.call(null)], { );
not: true, const isOrganizationPrefixPrereqFilled = useCallback(
}); () =>
const isHostNamePrereqFilled = () => isEmpty([organizationNameInputRef.current.getValue?.call(null)], {
isEmpty(
[
organizationPrefixInputRef.current.getValue?.call(null),
hostNumberInputRef.current.getValue?.call(null),
domainNameInputRef.current.getValue?.call(null),
],
{
not: true, not: true,
}, }),
); [],
);
const isHostNamePrereqFilled = useCallback(
() =>
isEmpty(
[
organizationPrefixInputRef.current.getValue?.call(null),
hostNumberInputRef.current.getValue?.call(null),
domainNameInputRef.current.getValue?.call(null),
],
{
not: true,
},
),
[],
);
const populateOrganizationPrefixInputOnBlur: OutlinedInputWithLabelOnBlur = const populateOrganizationPrefixInputOnBlur: OutlinedInputWithLabelOnBlur =
() => { useCallback(() => {
if (organizationPrefixInputRef.current.getIsChangedByUser?.call(null)) { if (organizationPrefixInputRef.current.getIsChangedByUser?.call(null)) {
setIsShowOrganizationPrefixSuggest( setIsShowOrganizationPrefixSuggest(
isOrganizationPrefixPrereqFilled(), isOrganizationPrefixPrereqFilled(),
@ -136,27 +166,34 @@ const GeneralInitForm = forwardRef<GeneralInitFormForwardRefContent>(
} else { } else {
populateOrganizationPrefixInput(); populateOrganizationPrefixInput();
} }
}; }, [isOrganizationPrefixPrereqFilled, populateOrganizationPrefixInput]);
const populateHostNameInputOnBlur: OutlinedInputWithLabelOnBlur = () => { const populateHostNameInputOnBlur: OutlinedInputWithLabelOnBlur =
if (hostNameInputRef.current.getIsChangedByUser?.call(null)) { useCallback(() => {
setIsShowHostNameSuggest(isHostNamePrereqFilled()); if (hostNameInputRef.current.getIsChangedByUser?.call(null)) {
} else { setIsShowHostNameSuggest(isHostNamePrereqFilled());
populateHostNameInput(); } else {
} populateHostNameInput();
}; }
const handleOrganizationPrefixSuggest = () => { }, [isHostNamePrereqFilled, populateHostNameInput]);
const handleOrganizationPrefixSuggest = useCallback(() => {
const organizationPrefix = populateOrganizationPrefixInput(); const organizationPrefix = populateOrganizationPrefixInput();
if (!hostNameInputRef.current.getIsChangedByUser?.call(null)) { if (!hostNameInputRef.current.getIsChangedByUser?.call(null)) {
populateHostNameInput({ organizationPrefix }); populateHostNameInput({ organizationPrefix });
} }
}; }, [populateHostNameInput, populateOrganizationPrefixInput]);
const handlerHostNameSuggest = () => { const handlerHostNameSuggest = useCallback(() => {
populateHostNameInput(); populateHostNameInput();
}; }, [populateHostNameInput]);
const buildHelpMessage = useCallback(
(text: string) => (previous?: string) =>
previous === text ? undefined : text,
[],
);
useImperativeHandle(ref, () => ({ useImperativeHandle(ref, () => ({
get: () => ({ get: () => ({
adminPassword: adminPasswordInputRef.current.getValue?.call(null),
organizationName: organizationNameInputRef.current.getValue?.call(null), organizationName: organizationNameInputRef.current.getValue?.call(null),
organizationPrefix: organizationPrefix:
organizationPrefixInputRef.current.getValue?.call(null), organizationPrefixInputRef.current.getValue?.call(null),
@ -167,147 +204,210 @@ const GeneralInitForm = forwardRef<GeneralInitFormForwardRefContent>(
})); }));
return ( return (
<MUIBox <FlexBox>
sx={{ <MUIGrid columns={{ xs: 1, sm: 2, md: 3 }} container spacing="1em">
display: 'flex', <MUIGrid item xs={1}>
flexDirection: { xs: 'column', sm: 'row' }, <FlexBox>
<InputWithRef
'& > *': { input={
flexBasis: '50%', <OutlinedInputWithLabel
}, id="striker-init-general-organization-name"
inputProps={{
'& > :not(:first-child)': { onBlur: populateOrganizationPrefixInputOnBlur,
marginLeft: { xs: 0, sm: '1em' }, }}
marginTop: { xs: '1em', sm: 0 }, label="Organization name"
}, onHelp={() => {
}} setHelpText(
> buildHelpMessage(
<FlexBox> 'Name of the organization that maintains this Anvil! system. You can enter anything that makes sense to you.',
<InputWithRef ),
input={ );
<OutlinedInputWithLabel }}
helpMessageBoxProps={{ />
text: 'Name of the organization that maintains this Anvil! system. You can enter anything that makes sense to you.', }
}} ref={organizationNameInputRef}
id="striker-init-general-organization-name"
inputProps={{
onBlur: populateOrganizationPrefixInputOnBlur,
}}
label="Organization name"
/> />
} <FlexBox
ref={organizationNameInputRef} row
/> sx={{
<FlexBox row> '& > *': {
<InputWithRef flexBasis: '50%',
input={
<OutlinedInputWithLabel
helpMessageBoxProps={{
text: "Alphanumberic short-form of the organization name. It's used as the prefix for host names.",
}}
id="striker-init-general-organization-prefix"
inputProps={{
endAdornment: (
<SuggestButton
show={isShowOrganizationPrefixSuggest}
onClick={handleOrganizationPrefixSuggest}
/>
),
inputProps: {
maxLength: MAX_ORGANIZATION_PREFIX_LENGTH,
style: { width: '2.5em' },
},
onBlur: populateHostNameInputOnBlur,
sx: {
minWidth: 'min-content',
width: 'fit-content',
},
}}
label="Prefix"
onChange={() => {
setIsShowOrganizationPrefixSuggest(
isOrganizationPrefixPrereqFilled(),
);
}}
/>
}
ref={organizationPrefixInputRef}
/>
<InputWithRef
input={
<OutlinedInputWithLabel
helpMessageBoxProps={{
text: "Number or count of this striker; this should be '1' for the first striker, '2' for the second striker, and such.",
}}
id="striker-init-general-host-number"
inputProps={{
inputProps: { maxLength: MAX_HOST_NUMBER_LENGTH },
onBlur: populateHostNameInputOnBlur,
sx: {
width: '6em',
},
}}
label="Host #"
/>
}
ref={hostNumberInputRef}
valueType="number"
/>
</FlexBox>
</FlexBox>
<FlexBox>
<InputWithRef
input={
<OutlinedInputWithLabel
helpMessageBoxProps={{
text: "Domain name for this striker. It's also the default domain used when creating new install manifests.",
}}
id="striker-init-general-domain-name"
inputProps={{
onBlur: populateHostNameInputOnBlur,
sx: {
minWidth: { sm: '16em' },
}, },
}} }}
label="Domain name" >
<InputWithRef
input={
<OutlinedInputWithLabel
id="striker-init-general-organization-prefix"
inputProps={{
endAdornment: (
<SuggestButton
show={isShowOrganizationPrefixSuggest}
onClick={handleOrganizationPrefixSuggest}
/>
),
inputProps: {
maxLength: MAX_ORGANIZATION_PREFIX_LENGTH,
},
onBlur: populateHostNameInputOnBlur,
}}
label="Prefix"
onChange={() => {
setIsShowOrganizationPrefixSuggest(
isOrganizationPrefixPrereqFilled(),
);
}}
onHelp={() => {
setHelpText(
buildHelpMessage(
"Alphanumberic short-form of the organization name. It's used as the prefix for host names.",
),
);
}}
/>
}
ref={organizationPrefixInputRef}
/>
<InputWithRef
input={
<OutlinedInputWithLabel
id="striker-init-general-host-number"
inputProps={{
inputProps: {
maxLength: MAX_HOST_NUMBER_LENGTH,
},
onBlur: populateHostNameInputOnBlur,
}}
label="Host #"
onHelp={() => {
setHelpText(
buildHelpMessage(
"Number or count of this striker; this should be '1' for the first striker, '2' for the second striker, and such.",
),
);
}}
/>
}
ref={hostNumberInputRef}
valueType="number"
/>
</FlexBox>
</FlexBox>
</MUIGrid>
<MUIGrid item xs={1}>
<FlexBox>
<InputWithRef
input={
<OutlinedInputWithLabel
id="striker-init-general-domain-name"
inputProps={{
onBlur: populateHostNameInputOnBlur,
}}
label="Domain name"
onHelp={() => {
setHelpText(
buildHelpMessage(
"Domain name for this striker. It's also the default domain used when creating new install manifests.",
),
);
}}
/>
}
ref={domainNameInputRef}
/> />
}
ref={domainNameInputRef}
/>
<InputWithRef <InputWithRef
input={ input={
<OutlinedInputWithLabel <OutlinedInputWithLabel
helpMessageBoxProps={{ id="striker-init-general-host-name"
text: "Host name for this striker. It's usually a good idea to use the auto-generated value.", inputProps={{
}} endAdornment: (
id="striker-init-general-host-name" <SuggestButton
inputProps={{ show={isShowHostNameSuggest}
endAdornment: ( onClick={handlerHostNameSuggest}
<SuggestButton />
show={isShowHostNameSuggest} ),
onClick={handlerHostNameSuggest} }}
/> label="Host name"
), onChange={() => {
inputProps: { setIsShowHostNameSuggest(isHostNamePrereqFilled());
style: { }}
minWidth: '4em', onHelp={() => {
}, setHelpText(
}, buildHelpMessage(
sx: { "Host name for this striker. It's usually a good idea to use the auto-generated value.",
minWidth: 'min-content', ),
}, );
}} }}
label="Host name" />
onChange={() => { }
setIsShowHostNameSuggest(isHostNamePrereqFilled()); ref={hostNameInputRef}
}}
/> />
} </FlexBox>
ref={hostNameInputRef} </MUIGrid>
/> <MUIGrid item xs={1} sm={2} md={1}>
</FlexBox> <MUIGrid
</MUIBox> columns={{ xs: 1, sm: 2, md: 1 }}
container
spacing="1em"
sx={{
'& > * > *': {
width: '100%',
},
}}
>
<MUIGrid item xs={1}>
<InputWithRef
input={
<OutlinedInputWithLabel
id="striker-init-general-admin-password"
inputProps={{
inputProps: {
type: 'password',
},
}}
label="Admin password"
onHelp={() => {
setHelpText(
buildHelpMessage(
"Password use to login to this Striker and connect to its database. Don't reuse an existing password here because it'll be stored as plaintext.",
),
);
}}
/>
}
ref={adminPasswordInputRef}
/>
</MUIGrid>
<MUIGrid item xs={1}>
<InputWithRef
input={
<OutlinedInputWithLabel
id="striker-init-general-confirm-admin-password"
inputProps={{
inputProps: {
type: 'password',
},
}}
label="Confirm password"
/>
}
ref={confirmAdminPasswordInputRef}
/>
</MUIGrid>
</MUIGrid>
</MUIGrid>
</MUIGrid>
{helpMessage && (
<MessageBox
onClose={() => {
setHelpText(undefined);
}}
>
{helpMessage}
</MessageBox>
)}
</FlexBox>
); );
}, },
); );

Loading…
Cancel
Save