debian-image-builder-frontend/src/Components/CreateImageWizard/utilities/PasswordValidatedInput.tsx
Michal Gold 265ba2ac78 Wizard: Add password validation in User step
This commit adds password validation to the User step:
- Moved password validation logic to a separate `checkPasswordValidity` function, returning detailed results (strength and validation state).
- Simplified validation in `PasswordValidatedInput` by using `checkPasswordValidity` results directly.
- Added dynamic password strength indicator showing success or error based on requirements.
- Integrated environment-specific validation messages (e.g., for Azure).
- Improved code separation between presentation and validation for better maintainability.
- Unit tests: Adds tests for invalid passwords, covering both default and Azure cases.
2025-03-20 13:28:46 +01:00

95 lines
2.7 KiB
TypeScript

import React, { useState } from 'react';
import {
FormGroup,
FormHelperText,
HelperText,
HelperTextItem,
InputGroup,
InputGroupItem,
TextInput,
Button,
TextInputProps,
} from '@patternfly/react-core';
import { EyeIcon, EyeSlashIcon } from '@patternfly/react-icons';
import { checkPasswordValidity } from './useValidation';
import { useAppSelector } from '../../../store/hooks';
import { selectImageTypes } from '../../../store/wizardSlice';
type ValidatedPasswordInput = TextInputProps & {
value: string;
placeholder: string;
ariaLabel: string;
onChange: (event: React.FormEvent<HTMLInputElement>, value: string) => void;
};
export const PasswordValidatedInput = ({
value,
placeholder,
ariaLabel,
onChange,
}: ValidatedPasswordInput) => {
const environments = useAppSelector(selectImageTypes);
const [isPasswordVisible, setIsPasswordVisible] = useState(false);
const { validationState, strength } = checkPasswordValidity(
value,
environments.includes('azure')
);
const { ruleLength, ruleCharacters } = validationState;
const togglePasswordVisibility = () => {
setIsPasswordVisible(!isPasswordVisible);
};
const passStrLabel = (
<HelperText>
<HelperTextItem variant={strength.variant} icon={strength.icon}>
{strength.text}
</HelperTextItem>
</HelperText>
);
return (
<FormGroup label="Password" isRequired labelInfo={passStrLabel}>
<>
<InputGroup>
<InputGroupItem isFill>
<TextInput
isRequired
type={isPasswordVisible ? 'text' : 'password'}
value={value}
onChange={onChange}
aria-label={ariaLabel}
placeholder={placeholder}
/>
</InputGroupItem>
<InputGroupItem>
<Button
variant="control"
onClick={togglePasswordVisibility}
aria-label={isPasswordVisible ? 'Hide password' : 'Show password'}
>
{isPasswordVisible ? <EyeSlashIcon /> : <EyeIcon />}
</Button>
</InputGroupItem>
</InputGroup>
</>
<FormHelperText>
<HelperText component="ul">
<HelperTextItem variant={ruleLength} component="li" hasIcon>
Password must be at least 6 characters long.
</HelperTextItem>
{environments.includes('azure') && (
<HelperTextItem variant={ruleCharacters} component="li" hasIcon>
Must include at least 3 of the following: lowercase letters,
uppercase letters, numbers, symbols.
</HelperTextItem>
)}
</HelperText>
</FormHelperText>
</FormGroup>
);
};