import { Visibility as MUIVisibilityIcon, VisibilityOff as MUIVisibilityOffIcon, } from '@mui/icons-material'; import { IconButton as MUIIconButton } from '@mui/material'; import { FC, useCallback, useMemo, useRef, useState } from 'react'; import { GREY } from '../lib/consts/DEFAULT_THEME'; import INPUT_TYPES from '../lib/consts/INPUT_TYPES'; import handleAPIError from '../lib/handleAPIError'; import mainAxiosInstance from '../lib/singletons/mainAxiosInstance'; import { buildDomainTestBatch, buildIPAddressTestBatch, buildPeacefulStringTestBatch, buildUUIDTestBatch, createTestInputFunction, } from '../lib/test_input'; import ConfirmDialog from './ConfirmDialog'; import ContainedButton from './ContainedButton'; import FlexBox from './FlexBox'; import GateForm from './GateForm'; import Grid from './Grid'; import InputWithRef, { InputForwardedRefContent } from './InputWithRef'; import MessageGroup, { MessageGroupForwardedRefContent } from './MessageGroup'; import OutlinedInputWithLabel from './OutlinedInputWithLabel'; import { Panel, PanelHeader } from './Panels'; import RadioGroupWithLabel from './RadioGroupWithLabel'; import { BodyText, HeaderText, MonoText } from './Text'; const ENTERPRISE_KEY_LABEL = 'Alteeve enterprise key'; const HOST_IP_LABEL = 'Host IP address'; const HOST_NAME_LABEL = 'Host name'; const REDHAT_PASSWORD_LABEL = 'RedHat password'; const REDHAT_USER_LABEL = 'RedHat user'; const IT_IDS = { enterpriseKey: 'enterpriseKey', hostName: 'hostName', redhatPassword: 'redhatPassword', redhatUser: 'redhatUser', }; const GRID_COLUMNS: Exclude = { xs: 1, sm: 2, }; const GRID_SPACING: Exclude = '1em'; const PrepareHostForm: FC = () => { const confirmDialogRef = useRef({}); const gateFormRef = useRef({}); const inputEnterpriseKeyRef = useRef>({}); const inputHostNameRef = useRef>({}); const inputRedhatPassword = useRef>({}); const inputRedhatUser = useRef>({}); const messageGroupRef = useRef({}); const [confirmValues, setConfirmValues] = useState< | { enterpriseKey: string; hostName: string; redhatPassword: string; redhatPasswordHidden: string; redhatUser: string; } | undefined >(); const [connectedHostIPAddress, setConnectedHostIPAddress] = useState< string | undefined >(); const [inputHostType, setInputHostType] = useState(''); const [isInputEnterpriseKeyValid, setIsInputEnterpriseKeyValid] = useState(true); const [isInputHostNameValid, setIsInputHostNameValid] = useState(false); const [isInputRedhatPasswordValid, setIsInputRedhatPasswordValid] = useState(true); const [isInputRedhatUserValid, setIsInputRedhatUserValid] = useState(true); const [isShowAccessSection, setIsShowAccessSection] = useState(false); const [isShowAccessSubmit, setIsShowAccessSubmit] = useState(true); const [isShowOptionalSection, setIsShowOptionalSection] = useState(false); const [isShowRedhatPassword, setIsShowRedhatPassword] = useState(false); const [isShowRedhatSection, setIsShowRedhatSection] = useState(false); const setHostNameInputMessage = useCallback((message?) => { messageGroupRef.current.setMessage?.call(null, IT_IDS.hostName, message); }, []); const setEnterpriseKeyInputMessage = useCallback((message?) => { messageGroupRef.current.setMessage?.call( null, IT_IDS.enterpriseKey, message, ); }, []); const setRedhatPasswordInputMessage = useCallback((message?) => { messageGroupRef.current.setMessage?.call( null, IT_IDS.redhatPassword, message, ); }, []); const setRedhatUserInputMessage = useCallback((message?) => { messageGroupRef.current.setMessage?.call(null, IT_IDS.redhatUser, message); }, []); const inputTests = useMemo( () => ({ [IT_IDS.enterpriseKey]: buildUUIDTestBatch( ENTERPRISE_KEY_LABEL, () => { setEnterpriseKeyInputMessage(); }, undefined, (message) => { setEnterpriseKeyInputMessage({ children: message, type: 'warning' }); }, ), [IT_IDS.hostName]: buildDomainTestBatch( HOST_NAME_LABEL, () => { setHostNameInputMessage(); }, undefined, (message) => { setHostNameInputMessage({ children: message, type: 'warning' }); }, ), [IT_IDS.redhatPassword]: buildPeacefulStringTestBatch( REDHAT_PASSWORD_LABEL, () => { setRedhatPasswordInputMessage(); }, undefined, (message) => { setRedhatPasswordInputMessage({ children: message, type: 'warning' }); }, ), [IT_IDS.redhatUser]: buildPeacefulStringTestBatch( REDHAT_USER_LABEL, () => { setRedhatUserInputMessage(); }, undefined, (message) => { setRedhatUserInputMessage({ children: message, type: 'warning' }); }, ), }), [ setEnterpriseKeyInputMessage, setHostNameInputMessage, setRedhatPasswordInputMessage, setRedhatUserInputMessage, ], ); const testInput = useMemo( () => createTestInputFunction(inputTests), [inputTests], ); const redhatElementSxDisplay = useMemo( () => (isShowRedhatSection ? undefined : 'none'), [isShowRedhatSection], ); const accessSection = useMemo( () => ( buildIPAddressTestBatch( HOST_IP_LABEL, () => { setMessage(); }, undefined, (message) => { setMessage({ children: message, type: 'warning' }); }, ) } identifierLabel={HOST_IP_LABEL} onIdentifierBlurAppend={({ target: { value } }) => { if (connectedHostIPAddress) { const isIdentifierChanged = value !== connectedHostIPAddress; setIsShowAccessSubmit(isIdentifierChanged); setIsShowOptionalSection(!isIdentifierChanged); } }} onSubmitAppend={( { getValue: getIdentifier }, { getValue: getPassphrase }, setMessage, setIsSubmitting, ) => { mainAxiosInstance .put<{ hostName: string; hostOS: string; hostUUID: string; isConnected: boolean; isInetConnected: boolean; isOSRegistered: boolean; }>( '/command/inquire-host', { ipAddress: getIdentifier?.call(null), password: getPassphrase?.call(null), }, { transformRequest: (data, headers = {}) => { headers['Content-Type'] = 'application/json'; return JSON.stringify(data); }, transformResponse: (data) => JSON.parse(data), }, ) .then( ({ data: { hostName, hostOS, isConnected, isInetConnected, isOSRegistered, }, }) => { if (isConnected) { inputHostNameRef.current.setValue?.call(null, hostName); const valid = testInput({ inputs: { [IT_IDS.hostName]: { value: hostName } }, }); setIsInputHostNameValid(valid); if ( isInetConnected && /rhel/i.test(hostOS) && !isOSRegistered ) { setIsShowRedhatSection(true); } setConnectedHostIPAddress(getIdentifier?.call(null)); setIsShowAccessSubmit(false); setIsShowOptionalSection(true); } else { setMessage?.call(null, { children: `Failed to establish a connection with the given host credentials.`, type: 'error', }); } }, ) .catch((error) => { const errorMessage = handleAPIError(error); setMessage?.call(null, errorMessage); }) .finally(() => { setIsSubmitting(false); }); }} passphraseLabel="Host root password" ref={gateFormRef} submitLabel="Test access" /> ), [ isShowAccessSection, isShowAccessSubmit, connectedHostIPAddress, testInput, ], ); const optionalSection = useMemo( () => ( { const valid = testInput({ inputs: { [IT_IDS.hostName]: { value } }, }); setIsInputHostNameValid(valid); }, onFocus: () => { setHostNameInputMessage(); }, }} label={HOST_NAME_LABEL} /> } ref={inputHostNameRef} /> ), }, 'preparehost-enterprise-key': { children: ( { if (value) { const valid = testInput({ inputs: { [IT_IDS.enterpriseKey]: { value } }, }); setIsInputEnterpriseKeyValid(valid); } }, onFocus: () => { setEnterpriseKeyInputMessage(); }, }} label={ENTERPRISE_KEY_LABEL} /> } ref={inputEnterpriseKeyRef} /> ), }, }} spacing={GRID_SPACING} wrapperBoxProps={{ sx: { display: isShowOptionalSection ? undefined : 'none' }, }} /> ), [ isShowOptionalSection, setEnterpriseKeyInputMessage, setHostNameInputMessage, testInput, ], ); const redhatSection = useMemo( () => ( { if (value) { const valid = testInput({ inputs: { [IT_IDS.redhatUser]: { value } }, }); setIsInputRedhatUserValid(valid); } }, onFocus: () => { setRedhatUserInputMessage(); }, }} label={REDHAT_USER_LABEL} /> } ref={inputRedhatUser} /> ), }, 'preparehost-redhat-password': { children: ( { if (value) { const valid = testInput({ inputs: { [IT_IDS.redhatPassword]: { value } }, }); setIsInputRedhatPasswordValid(valid); } }, onFocus: () => { setRedhatPasswordInputMessage(); }, onPasswordVisibilityAppend: (type) => { setIsShowRedhatPassword(type !== INPUT_TYPES.password); }, type: INPUT_TYPES.password, }} label={REDHAT_PASSWORD_LABEL} /> } ref={inputRedhatPassword} /> ), }, }} spacing={GRID_SPACING} wrapperBoxProps={{ sx: { display: redhatElementSxDisplay }, }} /> ), [ redhatElementSxDisplay, setRedhatPasswordInputMessage, setRedhatUserInputMessage, testInput, ], ); const submitSection = useMemo( () => ( { const redhatPasswordInputValue = inputRedhatPassword.current.getValue?.call(null); setConfirmValues({ enterpriseKey: inputEnterpriseKeyRef.current.getValue?.call(null) || 'none; using community version', hostName: inputHostNameRef.current.getValue?.call(null) || '', redhatPassword: redhatPasswordInputValue || 'none', redhatPasswordHidden: redhatPasswordInputValue?.replace(/./g, '*') || 'none', redhatUser: inputRedhatUser.current.getValue?.call(null) || 'none', }); confirmDialogRef.current.setOpen?.call(null, true); }} > Prepare host ), [ isInputEnterpriseKeyValid, isInputHostNameValid, isInputRedhatPasswordValid, isInputRedhatUserValid, isShowOptionalSection, ], ); return ( <> Prepare a host to include in Anvil! { setInputHostType(value); setIsShowAccessSection(true); }} radioItems={{ node: { label: 'Node', value: 'node' }, dr: { label: 'Disaster Recovery (DR) host', value: 'dr' }, }} /> {accessSection} {optionalSection} {redhatSection} {submitSection} ({ xs: index % 2 === 0 ? 1 : 2, })} columns={3} layout={{ 'preparehost-confirm-host-type-label': { children: Host type, }, 'preparehost-confirm-host-type-value': { children: ( {inputHostType === 'dr' ? 'Disaster Recovery (DR)' : 'Node'} ), }, 'preparehost-confirm-host-name-label': { children: Host name, }, 'preparehost-confirm-host-name-value': { children: {confirmValues?.hostName}, }, 'preparehost-confirm-enterprise-key-label': { children: Alteeve enterprise key, }, 'preparehost-confirm-enterprise-key-value': { children: {confirmValues?.enterpriseKey}, }, 'preparehost-confirm-redhat-user-label': { children: RedHat user, sx: { display: redhatElementSxDisplay }, }, 'preparehost-confirm-redhat-user-value': { children: {confirmValues?.redhatUser}, sx: { display: redhatElementSxDisplay }, }, 'preparehost-confirm-redhat-password-label': { children: RedHat password, sx: { display: redhatElementSxDisplay }, }, 'preparehost-confirm-redhat-password-value': { children: ( {isShowRedhatPassword ? confirmValues?.redhatPassword : confirmValues?.redhatPasswordHidden} { setIsShowRedhatPassword((previous) => !previous); }} sx={{ color: GREY, padding: 0 }} > {isShowRedhatPassword ? ( ) : ( )} ), sx: { display: redhatElementSxDisplay }, }, }} spacing=".6em" /> } onCancelAppend={() => { setIsShowRedhatPassword(false); }} onProceedAppend={() => { // }} ref={confirmDialogRef} titleText="Confirm host preparation" /> ); }; export default PrepareHostForm;