V2Wizard: Create a folder for Registration step and copy needed components

This created a new folder for the Registration step and copies components that will be needed:
- ActivationKeyInformation.tsx
- ActivationKeys.tsx
- Registration.tsx
- RegistrationKeyInformation.tsx
This commit is contained in:
regexowl 2024-01-10 10:16:16 +01:00 committed by Klara Simickova
parent 1706448670
commit 9ce438295d
4 changed files with 654 additions and 0 deletions

View file

@ -0,0 +1,174 @@
import React, { useContext } from 'react';
import { useFormApi } from '@data-driven-forms/react-form-renderer';
import WizardContext from '@data-driven-forms/react-form-renderer/wizard-context';
import {
Alert,
Spinner,
Text,
TextContent,
TextList,
TextListItem,
TextListItemVariants,
TextListVariants,
TextVariants,
} from '@patternfly/react-core';
import { Button, Popover } from '@patternfly/react-core';
import { HelpIcon } from '@patternfly/react-icons';
import { Table, Tbody, Td, Th, Thead, Tr } from '@patternfly/react-table';
import { useShowActivationKeyQuery } from '../../../store/rhsmApi';
const ActivationKeyInformation = (): JSX.Element => {
const { getState } = useFormApi();
const { currentStep } = useContext(WizardContext);
const activationKey = getState()?.values?.['subscription-activation-key'];
const {
data: activationKeyInfo,
isFetching: isFetchingActivationKeyInfo,
isSuccess: isSuccessActivationKeyInfo,
isError: isErrorActivationKeyInfo,
} = useShowActivationKeyQuery(
{ name: activationKey },
{
skip: !activationKey,
}
);
return (
<>
{isFetchingActivationKeyInfo && <Spinner size="lg" />}
{isSuccessActivationKeyInfo && (
<TextContent>
<TextList component={TextListVariants.dl}>
<TextListItem component={TextListItemVariants.dt}>
Name:
</TextListItem>
<TextListItem component={TextListItemVariants.dd}>
{activationKey}
</TextListItem>
<TextListItem component={TextListItemVariants.dt}>
Role:
</TextListItem>
<TextListItem component={TextListItemVariants.dd}>
{activationKeyInfo.body?.role || 'Not defined'}
</TextListItem>
<TextListItem component={TextListItemVariants.dt}>
SLA:
</TextListItem>
<TextListItem component={TextListItemVariants.dd}>
{activationKeyInfo.body?.serviceLevel || 'Not defined'}
</TextListItem>
<TextListItem component={TextListItemVariants.dt}>
Usage:
</TextListItem>
<TextListItem component={TextListItemVariants.dd}>
{activationKeyInfo.body?.usage || 'Not defined'}
</TextListItem>
<TextListItem component={TextListItemVariants.dt}>
Additional repositories:
<Popover
bodyContent={
<TextContent>
<Text>
The core repositories for your operating system version
are always enabled and do not need to be explicitly added
to the activation key.
</Text>
</TextContent>
}
>
<Button
variant="plain"
aria-label="About additional repositories"
className="pf-u-pl-sm pf-u-pt-0 pf-u-pb-0"
size="sm"
>
<HelpIcon />
</Button>
</Popover>
</TextListItem>
<TextListItem
component={TextListItemVariants.dd}
className="pf-u-display-flex pf-u-align-items-flex-end"
>
{activationKeyInfo.body?.additionalRepositories &&
activationKeyInfo.body?.additionalRepositories?.length > 0 ? (
<Popover
bodyContent={
<TextContent>
<Text component={TextVariants.h3}>
Additional repositories
</Text>
<Table
aria-label="Additional repositories table"
variant="compact"
>
<Thead>
<Tr>
<Th>Name</Th>
</Tr>
</Thead>
<Tbody data-testid="additional-repositories-table">
{activationKeyInfo.body?.additionalRepositories?.map(
(repo, index) => (
<Tr key={index}>
<Td>{repo.repositoryLabel}</Td>
</Tr>
)
)}
</Tbody>
</Table>
</TextContent>
}
>
<Button
data-testid="repositories-popover-button"
variant="link"
aria-label="Show additional repositories"
className="pf-u-pl-0 pf-u-pt-0 pf-u-pb-0"
>
{activationKeyInfo.body?.additionalRepositories?.length}{' '}
repositories
</Button>
</Popover>
) : (
'None'
)}
</TextListItem>
</TextList>
</TextContent>
)}
{isErrorActivationKeyInfo && (
<TextContent>
<TextList component={TextListVariants.dl}>
<TextListItem component={TextListItemVariants.dt}>
Name:
</TextListItem>
<TextListItem component={TextListItemVariants.dd}>
{activationKey}
</TextListItem>
</TextList>
</TextContent>
)}
{isErrorActivationKeyInfo && currentStep.name === 'registration' && (
<>
<br />
<Alert
title="Information about the activation key unavailable"
variant="danger"
isPlain
isInline
>
Information about the activation key cannot be loaded. Please check
the key was not removed and try again later.
</Alert>
</>
)}
</>
);
};
export default ActivationKeyInformation;

View file

@ -0,0 +1,199 @@
import React, { useEffect, useState } from 'react';
import useFieldApi from '@data-driven-forms/react-form-renderer/use-field-api';
import useFormApi from '@data-driven-forms/react-form-renderer/use-form-api';
import {
Alert,
FormGroup,
Spinner,
EmptyState,
Button,
EmptyStateIcon,
EmptyStateBody,
EmptyStateHeader,
EmptyStateFooter,
EmptyStateActions,
} from '@patternfly/react-core';
import {
Select,
SelectOption,
SelectVariant,
} from '@patternfly/react-core/deprecated';
import { WrenchIcon, AddCircleOIcon } from '@patternfly/react-icons';
import { addNotification } from '@redhat-cloud-services/frontend-components-notifications/redux';
import PropTypes from 'prop-types';
import { useDispatch } from 'react-redux';
import {
useListActivationKeysQuery,
useCreateActivationKeysMutation,
} from '../../../store/rhsmApi';
import { useGetEnvironment } from '../../../Utilities/useGetEnvironment';
const EmptyActivationsKeyState = ({ handleActivationKeyFn, isLoading }) => (
<EmptyState variant="xs">
<EmptyStateHeader
titleText="No activation keys found"
headingLevel="h4"
icon={<EmptyStateIcon icon={WrenchIcon} />}
/>
<EmptyStateBody>
Get started by building a default key, which will be generated and present
for you.
</EmptyStateBody>
<EmptyStateFooter>
<EmptyStateActions>
<Button
onClick={handleActivationKeyFn}
icon={<AddCircleOIcon />}
isLoading={isLoading}
iconPosition="left"
variant="link"
>
Create activation key
</Button>
</EmptyStateActions>
</EmptyStateFooter>
</EmptyState>
);
EmptyActivationsKeyState.propTypes = {
handleActivationKeyFn: PropTypes.func.isRequired,
isLoading: PropTypes.bool,
};
const ActivationKeys = ({ label, isRequired, ...props }) => {
const { isProd } = useGetEnvironment();
const { change, getState } = useFormApi();
const { input } = useFieldApi(props);
const [isOpen, setIsOpen] = useState(false);
const [activationKeySelected, selectActivationKey] = useState(
getState()?.values?.['subscription-activation-key']
);
const dispatch = useDispatch();
const {
data: activationKeys,
isFetching: isFetchingActivationKeys,
isSuccess: isSuccessActivationKeys,
isError: isErrorActivationKeys,
refetch,
} = useListActivationKeysQuery();
const [createActivationKey, { isLoading: isLoadingActivationKey }] =
useCreateActivationKeysMutation();
useEffect(() => {
if (isProd()) {
change('subscription-server-url', 'subscription.rhsm.redhat.com');
change('subscription-base-url', 'https://cdn.redhat.com/');
} else {
change('subscription-server-url', 'subscription.rhsm.stage.redhat.com');
change('subscription-base-url', 'https://cdn.stage.redhat.com/');
}
}, [isProd, change]);
const setActivationKey = (_, selection) => {
selectActivationKey(selection);
setIsOpen(false);
change(input.name, selection);
};
const handleClear = () => {
selectActivationKey();
change(input.name, undefined);
};
const handleToggle = () => {
if (!isOpen) {
refetch();
}
setIsOpen(!isOpen);
};
const handleCreateActivationKey = async () => {
const res = await createActivationKey({
body: {
name: 'activation-key-default',
serviceLevel: 'Self-Support',
},
});
refetch();
if (res.error) {
dispatch(
addNotification({
variant: 'danger',
title: 'Error creating activation key',
description: res.error?.data?.error?.message,
})
);
}
};
const isActivationKeysEmpty =
isSuccessActivationKeys && activationKeys.body.length === 0;
return (
<>
<FormGroup
isRequired={isRequired}
label={label}
data-testid="subscription-activation-key"
>
<Select
ouiaId="activation_key_select"
variant={SelectVariant.typeahead}
onToggle={handleToggle}
onSelect={setActivationKey}
onClear={handleClear}
selections={activationKeySelected}
isOpen={isOpen}
placeholderText="Select activation key"
typeAheadAriaLabel="Select activation key"
isDisabled={!isSuccessActivationKeys}
>
{isActivationKeysEmpty && (
<EmptyActivationsKeyState
handleActivationKeyFn={handleCreateActivationKey}
isLoading={isLoadingActivationKey}
/>
)}
{isSuccessActivationKeys &&
activationKeys.body.map((key, index) => (
<SelectOption key={index} value={key.name} />
))}
{!isSuccessActivationKeys && isFetchingActivationKeys && (
<SelectOption
isNoResultsOption={true}
data-testid="activation-keys-loading"
>
<Spinner size="md" />
</SelectOption>
)}
</Select>
</FormGroup>
{isErrorActivationKeys && (
<Alert
title="Activation keys unavailable"
variant="danger"
isPlain
isInline
>
Activation keys cannot be reached, try again later.
</Alert>
)}
</>
);
};
ActivationKeys.propTypes = {
label: PropTypes.node,
isRequired: PropTypes.bool,
};
ActivationKeys.defaultProps = {
label: '',
isRequired: false,
};
export default ActivationKeys;

View file

@ -0,0 +1,252 @@
import React, { useState } from 'react';
import { FormSpy } from '@data-driven-forms/react-form-renderer';
import useFieldApi from '@data-driven-forms/react-form-renderer/use-field-api';
import useFormApi from '@data-driven-forms/react-form-renderer/use-form-api';
import {
Button,
Checkbox,
FormGroup,
Popover,
Radio,
Text,
TextContent,
} from '@patternfly/react-core';
import { HelpIcon, ExternalLinkAltIcon } from '@patternfly/react-icons';
import PropTypes from 'prop-types';
const RHSMPopover = () => {
return (
<Popover
headerContent="About Red Hat Subscription Management"
position="right"
minWidth="30rem"
bodyContent={
<TextContent>
<Text>
Registered systems are entitled to support services, errata,
patches, and upgrades.
</Text>
<Button
component="a"
target="_blank"
variant="link"
icon={<ExternalLinkAltIcon />}
iconPosition="right"
isInline
href="https://access.redhat.com/products/red-hat-subscription-management"
>
Learn more about Red Hat Subscription Management
</Button>
</TextContent>
}
>
<Button
variant="plain"
className="pf-c-form__group-label-help"
aria-label="About remote host configuration (rhc)"
isInline
>
<HelpIcon />
</Button>
</Popover>
);
};
const InsightsPopover = () => {
return (
<Popover
headerContent="About Red Hat Insights"
position="right"
minWidth="30rem"
bodyContent={
<TextContent>
<Text>
Red Hat Insights client provides actionable intelligence about your
Red Hat Enterprise Linux environments, helping to identify and
address operational and vulnerability risks before an issue results
in downtime.
</Text>
<Button
component="a"
target="_blank"
variant="link"
icon={<ExternalLinkAltIcon />}
iconPosition="right"
isInline
href="https://access.redhat.com/products/red-hat-insights"
>
Learn more about Red Hat Insights
</Button>
</TextContent>
}
>
<Button
variant="plain"
className="pf-c-form__group-label-help"
aria-label="About remote host configuration (rhc)"
isInline
>
<HelpIcon />
</Button>
</Popover>
);
};
const RhcPopover = () => {
return (
<Popover
headerContent="About remote host configuration (rhc)"
position="right"
minWidth="30rem"
bodyContent={
<TextContent>
<Text>
Remote host configuration allows Red Hat Enterprise Linux hosts to
connect to Red Hat Insights. Remote host configuration is required
to use the Red Hat Insights Remediations service.
</Text>
<Button
component="a"
target="_blank"
variant="link"
icon={<ExternalLinkAltIcon />}
iconPosition="right"
isInline
href="https://access.redhat.com/articles/rhc"
>
Learn more about remote host configuration
</Button>
</TextContent>
}
>
<Button
variant="plain"
className="pf-c-form__group-label-help"
aria-label="About remote host configuration (rhc)"
isInline
>
<HelpIcon />
</Button>
</Popover>
);
};
const Registration = ({ label, ...props }) => {
const { change, getState } = useFormApi();
const { input } = useFieldApi(props);
const registerSystem = getState()?.values?.['register-system'];
const [showOptions, setShowOptions] = useState(
registerSystem === 'register-now-insights' ||
registerSystem === 'register-now'
);
return (
<FormSpy>
{() => (
<FormGroup label={label}>
<Radio
autoFocus
label={
(!showOptions &&
'Automatically register and enable advanced capabilities') || (
<>
Monitor & manage subscriptions and access to Red Hat content
<RHSMPopover />
</>
)
}
data-testid="registration-radio-now"
name="register-system"
id="register-system-now"
isChecked={registerSystem.startsWith('register-now')}
onChange={() => {
change(input.name, 'register-now-rhc');
}}
description={
!showOptions && (
<Button
component="a"
data-testid="registration-additional-options"
variant="link"
isDisabled={!registerSystem.startsWith('register-now')}
isInline
onClick={() => setShowOptions(!showOptions)}
>
Show additional connection options
</Button>
)
}
body={
showOptions && (
<Checkbox
className="pf-u-ml-lg"
label={
<>
Enable predictive analytics and management capabilities
<InsightsPopover />
</>
}
data-testid="registration-checkbox-insights"
isChecked={
registerSystem === 'register-now-insights' ||
registerSystem === 'register-now-rhc'
}
onChange={(_event, checked) => {
if (checked) {
change(input.name, 'register-now-insights');
} else {
change(input.name, 'register-now');
}
}}
id="register-system-now-insights"
name="register-system-insights"
body={
<Checkbox
label={
<>
Enable remote remediations and system management with
automation
<RhcPopover />
</>
}
data-testid="registration-checkbox-rhc"
isChecked={registerSystem === 'register-now-rhc'}
onChange={(_event, checked) => {
if (checked) {
change(input.name, 'register-now-rhc');
} else {
change(input.name, 'register-now-insights');
}
}}
id="register-system-now-rhc"
name="register-system-rhc"
/>
}
/>
)
}
/>
<Radio
name="register-system"
className="pf-u-mt-md"
data-testid="registration-radio-later"
id="register-system-later"
label="Register later"
isChecked={registerSystem === 'register-later'}
onChange={() => {
setShowOptions(false);
change(input.name, 'register-later');
}}
/>
</FormGroup>
)}
</FormSpy>
);
};
Registration.propTypes = {
label: PropTypes.node,
};
export default Registration;

View file

@ -0,0 +1,29 @@
import React from 'react';
import { FormSpy } from '@data-driven-forms/react-form-renderer';
import { FormGroup } from '@patternfly/react-core';
import { isEmpty } from 'lodash';
import PropTypes from 'prop-types';
import ActivationKeyInformation from './ActivationKeyInformation';
const RegistrationKeyInformation = ({ label, valueReference }) => {
return (
<FormSpy>
{({ values }) =>
isEmpty(values[valueReference]) ? null : (
<FormGroup label={label}>
<ActivationKeyInformation />
</FormGroup>
)
}
</FormSpy>
);
};
RegistrationKeyInformation.propTypes = {
label: PropTypes.node,
valueReference: PropTypes.node,
};
export default RegistrationKeyInformation;