Wizard: edit compliance according to updated mockups

Changes the compliance step based on most recent mockups
This commit is contained in:
Katarina Sieklova 2025-04-16 17:01:25 +02:00 committed by Klara Simickova
parent ad6b38a115
commit cfa437a34b
5 changed files with 103 additions and 179 deletions

View file

@ -1,33 +0,0 @@
import React from 'react';
import { Popover, TextContent, Text, Button } from '@patternfly/react-core';
import { HelpIcon } from '@patternfly/react-icons';
const OpenSCAPFGLabel = () => {
return (
<>
OpenSCAP profile
<Popover
maxWidth="30rem"
bodyContent={
<TextContent>
<Text>
To run a manual compliance scan in OpenSCAP, download this image.
</Text>
</TextContent>
}
>
<Button
variant="plain"
aria-label="About OpenSCAP"
isInline
className="pf-v5-u-pl-sm pf-v5-u-pt-0 pf-v5-u-pb-0 pf-v5-u-pr-0"
>
<HelpIcon />
</Button>
</Popover>
</>
);
};
export default OpenSCAPFGLabel;

View file

@ -1,8 +1,6 @@
import React, { useEffect } from 'react'; import React, { useEffect } from 'react';
import { import {
CodeBlock,
CodeBlockCode,
Spinner, Spinner,
TextContent, TextContent,
TextList, TextList,
@ -11,7 +9,6 @@ import {
TextListVariants, TextListVariants,
} from '@patternfly/react-core'; } from '@patternfly/react-core';
import { RELEASES } from '../../../../../constants';
import { useGetOscapCustomizationsQuery } from '../../../../../store/backendApi'; import { useGetOscapCustomizationsQuery } from '../../../../../store/backendApi';
import { PolicyRead, usePolicyQuery } from '../../../../../store/complianceApi'; import { PolicyRead, usePolicyQuery } from '../../../../../store/complianceApi';
import { useAppDispatch, useAppSelector } from '../../../../../store/hooks'; import { useAppDispatch, useAppSelector } from '../../../../../store/hooks';
@ -22,7 +19,6 @@ import {
selectComplianceProfileID, selectComplianceProfileID,
selectDistribution, selectDistribution,
} from '../../../../../store/wizardSlice'; } from '../../../../../store/wizardSlice';
import { useFlag } from '../../../../../Utilities/useGetEnvironment';
type OscapProfileInformationOptionPropType = { type OscapProfileInformationOptionPropType = {
allowChangingCompliancePolicy?: boolean; allowChangingCompliancePolicy?: boolean;
@ -36,9 +32,6 @@ export const OscapProfileInformation = ({
const compliancePolicyID = useAppSelector(selectCompliancePolicyID); const compliancePolicyID = useAppSelector(selectCompliancePolicyID);
const complianceProfileID = useAppSelector(selectComplianceProfileID); const complianceProfileID = useAppSelector(selectComplianceProfileID);
const isKernelEnabled = useFlag('image-builder.kernel.enabled');
const isServicesStepEnabled = useFlag('image-builder.services.enabled');
const { const {
data: oscapProfileInfo, data: oscapProfileInfo,
isFetching: isFetchingOscapProfileInfo, isFetching: isFetchingOscapProfileInfo,
@ -82,15 +75,6 @@ export const OscapProfileInformation = ({
); );
}, [isSuccessPolicyInfo]); }, [isSuccessPolicyInfo]);
const enabledServicesDisplayString =
oscapProfileInfo?.services?.enabled?.join(' ');
const disabledAndMaskedServices = [
...(oscapProfileInfo?.services?.disabled ?? []),
...(oscapProfileInfo?.services?.masked ?? []),
];
const disabledAndMaskedServicesDisplayString =
disabledAndMaskedServices.join(' ');
const oscapProfile = oscapProfileInfo?.openscap as OpenScapProfile; const oscapProfile = oscapProfileInfo?.openscap as OpenScapProfile;
return ( return (
@ -111,15 +95,6 @@ export const OscapProfileInformation = ({
<TextListItem component={TextListItemVariants.dd}> <TextListItem component={TextListItemVariants.dd}>
{oscapProfile?.profile_description} {oscapProfile?.profile_description}
</TextListItem> </TextListItem>
<TextListItem
component={TextListItemVariants.dt}
className="pf-v5-u-min-width"
>
Operating system:
</TextListItem>
<TextListItem component={TextListItemVariants.dd}>
{RELEASES.get(release)}
</TextListItem>
<TextListItem <TextListItem
component={TextListItemVariants.dt} component={TextListItemVariants.dt}
className="pf-v5-u-min-width" className="pf-v5-u-min-width"
@ -132,53 +107,50 @@ export const OscapProfileInformation = ({
> >
{oscapProfile?.profile_id} {oscapProfile?.profile_id}
</TextListItem> </TextListItem>
{!isKernelEnabled && ( </TextList>
<> </TextContent>
<TextListItem </>
component={TextListItemVariants.dt} )}
className="pf-v5-u-min-width" {isSuccessPolicyInfo && (
> <>
Kernel arguments: <TextContent>
</TextListItem> <TextList component={TextListVariants.dl}>
<TextListItem component={TextListItemVariants.dd}> <TextListItem
<CodeBlock> component={TextListItemVariants.dt}
<CodeBlockCode> className="pf-v5-u-min-width"
{oscapProfileInfo?.kernel?.append} >
</CodeBlockCode> Policy description:
</CodeBlock> </TextListItem>
</TextListItem> <TextListItem component={TextListItemVariants.dd}>
</> {policyInfo?.data?.schema?.description}
)} </TextListItem>
{!isServicesStepEnabled && ( <TextListItem
<> component={TextListItemVariants.dt}
<TextListItem className="pf-v5-u-min-width"
component={TextListItemVariants.dt} >
className="pf-v5-u-min-width" Business objective:
> </TextListItem>
Disabled services: <TextListItem component={TextListItemVariants.dd}>
</TextListItem> {policyInfo?.data?.schema?.business_objective}
<TextListItem component={TextListItemVariants.dd}> </TextListItem>
<CodeBlock> <TextListItem
<CodeBlockCode> component={TextListItemVariants.dt}
{disabledAndMaskedServicesDisplayString} className="pf-v5-u-min-width"
</CodeBlockCode> >
</CodeBlock> Policy type:
</TextListItem> </TextListItem>
<TextListItem <TextListItem component={TextListItemVariants.dd}>
component={TextListItemVariants.dt} {policyInfo?.data?.schema?.type}
className="pf-v5-u-min-width" </TextListItem>
> <TextListItem
Enabled services: component={TextListItemVariants.dt}
</TextListItem> className="pf-v5-u-min-width"
<TextListItem component={TextListItemVariants.dd}> >
<CodeBlock> Reference ID:
<CodeBlockCode> </TextListItem>
{enabledServicesDisplayString} <TextListItem component={TextListItemVariants.dd}>
</CodeBlockCode> {policyInfo?.data?.schema?.id}
</CodeBlock> </TextListItem>
</TextListItem>
</>
)}
</TextList> </TextList>
</TextContent> </TextContent>
</> </>

View file

@ -17,8 +17,6 @@ import {
import { TimesIcon } from '@patternfly/react-icons'; import { TimesIcon } from '@patternfly/react-icons';
import { v4 as uuidv4 } from 'uuid'; import { v4 as uuidv4 } from 'uuid';
import OpenSCAPFGLabel from './OpenSCAPFGLabel';
import { import {
useGetOscapProfilesQuery, useGetOscapProfilesQuery,
useGetOscapCustomizationsQuery, useGetOscapCustomizationsQuery,
@ -323,6 +321,11 @@ const ProfileSelector = () => {
onClick={() => setIsOpen(!isOpen)} onClick={() => setIsOpen(!isOpen)}
isExpanded={isOpen} isExpanded={isOpen}
isDisabled={!isSuccess || hasWslTargetOnly} isDisabled={!isSuccess || hasWslTargetOnly}
style={
{
width: '100%',
} as React.CSSProperties
}
> >
<TextInputGroup isPlain> <TextInputGroup isPlain>
<TextInputGroupMain <TextInputGroupMain
@ -350,7 +353,7 @@ const ProfileSelector = () => {
); );
return ( return (
<FormGroup data-testid="profiles-form-group" label={<OpenSCAPFGLabel />}> <FormGroup data-testid="profiles-form-group" label="Profile">
<Select <Select
isScrollable isScrollable
isOpen={isOpen} isOpen={isOpen}

View file

@ -1,14 +1,14 @@
import React, { useEffect } from 'react'; import React, { useEffect } from 'react';
import { import {
Button, Alert,
AlertActionLink,
Form, Form,
FormGroup,
Radio,
Text, Text,
Title, Title,
ToggleGroup,
ToggleGroupItem,
} from '@patternfly/react-core'; } from '@patternfly/react-core';
import { ExternalLinkAltIcon } from '@patternfly/react-icons';
import useChrome from '@redhat-cloud-services/frontend-components/useChrome'; import useChrome from '@redhat-cloud-services/frontend-components/useChrome';
import OscapOnPremSpinner from './components/OnPremSpinner'; import OscapOnPremSpinner from './components/OnPremSpinner';
@ -16,14 +16,12 @@ import OscapOnPremWarning from './components/OnPremWarning';
import Oscap from './Oscap'; import Oscap from './Oscap';
import { removeBetaFromRelease } from './removeBetaFromRelease'; import { removeBetaFromRelease } from './removeBetaFromRelease';
import { import { COMPLIANCE_URL } from '../../../../constants';
COMPLIANCE_AND_VULN_SCANNING_URL,
COMPLIANCE_URL,
} from '../../../../constants';
import { import {
useBackendPrefetch, useBackendPrefetch,
useGetOscapCustomizationsQuery, useGetOscapCustomizationsQuery,
} from '../../../../store/backendApi'; } from '../../../../store/backendApi';
import { usePoliciesQuery } from '../../../../store/complianceApi';
import { useAppDispatch, useAppSelector } from '../../../../store/hooks'; import { useAppDispatch, useAppSelector } from '../../../../store/hooks';
import { import {
ComplianceType, ComplianceType,
@ -54,6 +52,7 @@ const OscapContent = () => {
const profileID = useAppSelector(selectComplianceProfileID); const profileID = useAppSelector(selectComplianceProfileID);
const prefetchOscapProfile = useBackendPrefetch('getOscapProfiles', {}); const prefetchOscapProfile = useBackendPrefetch('getOscapProfiles', {});
const release = removeBetaFromRelease(useAppSelector(selectDistribution)); const release = removeBetaFromRelease(useAppSelector(selectDistribution));
const majorVersion = release.split('-')[1];
const { data: currentProfileData } = useGetOscapCustomizationsQuery( const { data: currentProfileData } = useGetOscapCustomizationsQuery(
{ {
@ -101,78 +100,59 @@ const OscapContent = () => {
analytics.screen('ib-createimagewizard-step-security-openscap'); analytics.screen('ib-createimagewizard-step-security-openscap');
} }
} }
const { data: policies } = usePoliciesQuery(
{
filter: `os_major_version=${majorVersion}`,
},
{
skip: complianceType === 'openscap',
}
);
return ( return (
<Form> <Form>
<Title headingLevel="h1" size="xl"> <Title headingLevel="h1" size="xl">
{complianceEnabled ? 'Compliance' : 'OpenSCAP profile'} {complianceEnabled ? 'Compliance' : 'OpenSCAP profile'}
</Title> </Title>
<Text>
Below you can select which Insights compliance policy or OpenSCAP
profile your image will be compliant to. Insights compliance allows the
use of tailored policies, whereas OpenSCAP gives you the default
versions. This will automatically help monitor the adherence of your
registered RHEL systems to a selected policy or profile.
</Text>
{complianceEnabled && ( {complianceEnabled && (
<FormGroup> <ToggleGroup aria-label="Default with single selectable">
<Radio <ToggleGroupItem
id="openscap radio openscap type" text="Compliance policies"
label="OpenSCAP" buttonId="toggle-group-compliance"
name="oscap-radio-openscap" isSelected={complianceType === 'compliance'}
isChecked={complianceType === 'openscap'}
onChange={() => handleTypeChange('openscap')}
/>
<Radio
id="openscap radio compliance type"
label="Insights compliance"
name="oscap-radio-compliance"
isChecked={complianceType === 'compliance'}
onChange={() => handleTypeChange('compliance')} onChange={() => handleTypeChange('compliance')}
/> />
</FormGroup> <ToggleGroupItem
)} text="OpenSCAP profiles"
{(!complianceEnabled || complianceType === 'openscap') && ( buttonId="toggle-group-openscap"
<Text> isSelected={complianceType === 'openscap'}
OpenSCAP enables you to automatically monitor the adherence of your onChange={() => handleTypeChange('openscap')}
registered RHEL systems to a selected regulatory compliance profile. />
<br /> </ToggleGroup>
<Button
component="a"
target="_blank"
variant="link"
icon={<ExternalLinkAltIcon />}
iconPosition="right"
isInline
href={COMPLIANCE_AND_VULN_SCANNING_URL}
>
Documentation
</Button>
</Text>
)}
{complianceType === 'compliance' && (
<Text>
Insights compliance enables you to monitor the adherence of your
registered RHEL systems to a selected compliance policy.
<br />
<Button
component="a"
target="_blank"
variant="link"
icon={<ExternalLinkAltIcon />}
iconPosition="right"
isInline
href={COMPLIANCE_URL}
>
Define new policies in Insights Compliance
</Button>
<br />
<Button
component="a"
target="_blank"
variant="link"
icon={<ExternalLinkAltIcon />}
iconPosition="right"
isInline
href={COMPLIANCE_AND_VULN_SCANNING_URL}
>
Documentation
</Button>
</Text>
)} )}
{Array.isArray(policies?.data) &&
policies.data.length === 0 &&
complianceType === 'compliance' && (
<Alert variant="info" isInline title="No compliance policies created">
<p>
Currently there are no compliance policies in your environment. To
help you get started, select one of the default policies below and
we will create the policy for you. However, in order to modify the
policy or to create a new one, you must go through Insights
Compliance.
</p>
<AlertActionLink component="a" href={COMPLIANCE_URL}>
Save blueprint and navigate to Insights Compliance
</AlertActionLink>
</Alert>
)}
<Oscap /> <Oscap />
</Form> </Form>
); );

View file

@ -39,7 +39,9 @@ const goToComplianceStep = async () => {
await clickRegisterLater(); await clickRegisterLater();
await clickNext(); // Compliance await clickNext(); // Compliance
await screen.findByRole('heading', { name: /Compliance/ }); await screen.findByRole('heading', { name: /Compliance/ });
const button = await screen.findByLabelText('Insights compliance'); const button = await screen.findByRole('button', {
name: /Compliance policies/,
});
await waitFor(() => user.click(button)); await waitFor(() => user.click(button));
// wait until all policies are loaded // wait until all policies are loaded
await screen.findByText('Select a policy'); await screen.findByText('Select a policy');