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:
parent
1706448670
commit
9ce438295d
4 changed files with 654 additions and 0 deletions
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
Loading…
Add table
Add a link
Reference in a new issue