Wizard: add satellite registration, add jwt-decode

The jwt decode dependency helps us to keep track of the token that is
present in the Satellite command. jwt-decode is the most popular
dependency for the job, and very easy to use.
This commit is contained in:
Anna Vítová 2025-03-05 09:55:17 +01:00 committed by Klara Simickova
parent 739c0538fe
commit a4034e8787
21 changed files with 20892 additions and 6818 deletions

View file

@ -5,10 +5,12 @@ import {
Checkbox,
FormGroup,
Popover,
Radio,
Text,
TextContent,
} from '@patternfly/react-core';
import { ExternalLinkAltIcon, HelpIcon } from '@patternfly/react-icons';
import { useFlag } from '@unleash/proxy-client-react';
import { INSIGHTS_URL, RHC_URL, RHEL_10_BETA } from '../../../../constants';
import { useAppDispatch, useAppSelector } from '../../../../store/hooks';
@ -106,6 +108,10 @@ const Registration = () => {
registrationType === 'register-later'
);
const isSatelliteRegistrationEnabled = useFlag(
'image-builder.satellite.enabled'
);
// TO DO: Remove when rhc starts working for RHEL 10 Beta
useEffect(() => {
if (distribution === RHEL_10_BETA) {
@ -115,9 +121,9 @@ const Registration = () => {
return (
<FormGroup label="Registration method">
<Checkbox
<Radio
label="Automatically register and enable advanced capabilities"
data-testid="automatically-register-checkbox"
data-testid="automatically-register-radio"
isChecked={
registrationType === 'register-now' ||
registrationType === 'register-now-insights' ||
@ -129,9 +135,6 @@ const Registration = () => {
dispatch(changeRegistrationType('register-now-rhc'));
} else if (checked && distribution === RHEL_10_BETA) {
dispatch(changeRegistrationType('register-now-insights'));
} else {
dispatch(changeRegistrationType('register-later'));
setShowOptions(false);
}
}}
id="register-system-now"
@ -201,6 +204,30 @@ const Registration = () => {
)
}
/>
<Radio
label="Register later"
data-testid="register-later-radio"
isChecked={registrationType === 'register-later'}
onChange={() => {
dispatch(changeRegistrationType('register-later'));
setShowOptions(false);
}}
id="register-later"
name="register-later"
/>
{isSatelliteRegistrationEnabled && (
<Radio
label="Register with Satellite"
data-testid="register-satellite-radio"
isChecked={registrationType === 'register-satellite'}
onChange={() => {
dispatch(changeRegistrationType('register-satellite'));
setShowOptions(false);
}}
id="register-satellite"
name="register-satellite"
/>
)}
</FormGroup>
);
};

View file

@ -0,0 +1,100 @@
import React from 'react';
import {
DropEvent,
FileUpload,
Form,
FormGroup,
FormHelperText,
HelperText,
HelperTextItem,
} from '@patternfly/react-core';
import SatelliteRegistrationCommand from './components/SatelliteRegistrationCommand';
import { useAppDispatch, useAppSelector } from '../../../../store/hooks';
import {
changeSatelliteCaCertificate,
selectSatelliteCaCertificate,
} from '../../../../store/wizardSlice';
import { useRegistrationValidation } from '../../utilities/useValidation';
const SatelliteRegistration = () => {
const dispatch = useAppDispatch();
const caCertificate = useAppSelector(selectSatelliteCaCertificate);
const [isRejected, setIsRejected] = React.useState(false);
const stepValidation = useRegistrationValidation();
const validated =
stepValidation.errors['certificate'] === 'default'
? 'default'
: stepValidation.errors['certificate']
? 'error'
: 'success';
const handleClear = () => {
dispatch(changeSatelliteCaCertificate(''));
};
const handleTextChange = (
_event: React.ChangeEvent<HTMLTextAreaElement>,
value: string
) => {
dispatch(changeSatelliteCaCertificate(value));
};
const handleDataChange = (_: DropEvent, value: string) => {
dispatch(changeSatelliteCaCertificate(value));
};
const handleFileRejected = () => {
dispatch(changeSatelliteCaCertificate(''));
setIsRejected(true);
};
return (
<Form>
<SatelliteRegistrationCommand />
<FormGroup label="Certificate authority (CA)" isRequired>
<FileUpload
id="text-file-with-restrictions-example"
type="text"
value={caCertificate || ''}
filename={caCertificate ? 'CA detected' : ''}
onDataChange={handleDataChange}
onTextChange={handleTextChange}
onClearClick={handleClear}
isRequired={true}
dropzoneProps={{
accept: {
'application/x-pem-file': ['.pem'],
'application/x-x509-ca-cert': ['.cer', '.crt'],
'application/pkix-cert': ['.der'],
},
maxSize: 512000,
onDropRejected: handleFileRejected,
}}
validated={isRejected ? 'error' : 'default'}
browseButtonText="Upload"
allowEditingUploadedText={true}
/>
<FormHelperText>
<HelperText>
<HelperTextItem
variant={
isRejected || validated === 'error' ? 'error' : 'default'
}
hasIcon
>
{isRejected
? 'Must be a .PEM/.CER/.CRT file no larger than 512 KB'
: validated === 'error'
? stepValidation.errors['certificate']
: 'Drag and drop a file or upload one'}
</HelperTextItem>
</HelperText>
</FormHelperText>
</FormGroup>
</Form>
);
};
export default SatelliteRegistration;

View file

@ -0,0 +1,57 @@
import React from 'react';
import {
FormGroup,
FormHelperText,
HelperText,
HelperTextItem,
} from '@patternfly/react-core';
import { useAppDispatch, useAppSelector } from '../../../../../store/hooks';
import {
changeSatelliteRegistrationCommand,
selectSatelliteRegistrationCommand,
} from '../../../../../store/wizardSlice';
import { useRegistrationValidation } from '../../../utilities/useValidation';
import { ValidatedInputAndTextArea } from '../../../ValidatedInput';
const SatelliteRegistrationCommand = () => {
const dispatch = useAppDispatch();
const registrationCommand = useAppSelector(
selectSatelliteRegistrationCommand
);
const stepValidation = useRegistrationValidation();
const registrationDocs =
'https://docs.redhat.com/en/documentation/red_hat_satellite/6.16/html-single/managing_hosts/index#Customizing_the_Registration_Templates_managing-hosts';
const handleChange = (e: React.FormEvent, value: string) => {
dispatch(changeSatelliteRegistrationCommand(value));
};
return (
<FormGroup label="Registration command from Satellite" isRequired>
<ValidatedInputAndTextArea
inputType={'textArea'}
ariaLabel="registration command"
value={registrationCommand || ''}
onChange={handleChange}
placeholder="Registration command"
stepValidation={stepValidation}
fieldName="command"
/>
<FormHelperText>
<HelperText>
<HelperTextItem>
To generate command from Satellite, follow the{' '}
<a href={registrationDocs} target="_blank" rel="noreferrer">
documentation
</a>
.
</HelperTextItem>
</HelperText>
</FormHelperText>
</FormGroup>
);
};
export default SatelliteRegistrationCommand;

View file

@ -5,6 +5,7 @@ import { Text, Form, Title, FormGroup } from '@patternfly/react-core';
import ActivationKeyInformation from './ActivationKeyInformation';
import ActivationKeysList from './ActivationKeysList';
import Registration from './Registration';
import SatelliteRegistration from './SatelliteRegistration';
import { useAppSelector } from '../../../../store/hooks';
import {
@ -26,10 +27,13 @@ const RegistrationStep = () => {
system during initial boot.
</Text>
<Registration />
{!process.env.IS_ON_PREMISE && <ActivationKeysList />}
{registrationType === 'register-satellite' && <SatelliteRegistration />}
{!process.env.IS_ON_PREMISE &&
registrationType !== 'register-satellite' && <ActivationKeysList />}
{!process.env.IS_ON_PREMISE &&
activationKey &&
registrationType !== 'register-later' && (
registrationType !== 'register-later' &&
registrationType !== 'register-satellite' && (
<FormGroup
label={'Selected activation key'}
data-testid="selected-activation-key"