V2Wizard: Add Package recommendation to the Packages step

This adds an expandable with package recommendations to the Packages step.

The recommendations are populated when two or more packages are selected.
This commit is contained in:
regexowl 2024-04-17 11:22:00 +02:00 committed by Lucas Garfield
parent 6de7645be5
commit 648300ffb4
3 changed files with 179 additions and 0 deletions

View file

@ -68,3 +68,7 @@ ul.pf-m-plain {
.not-available {
color: #6a6e73;
}
.panel-border {
--pf-v5-c-panel--before--BorderColor: #BEE1F4;
}

View file

@ -0,0 +1,173 @@
import React, { useEffect, useState } from 'react';
import {
Alert,
Button,
ExpandableSection,
Icon,
Panel,
PanelMain,
PanelMainBody,
Spinner,
Text,
TextContent,
} from '@patternfly/react-core';
import { OptimizeIcon } from '@patternfly/react-icons';
import { Table, Tbody, Td, Th, Thead, Tr } from '@patternfly/react-table';
import { useDispatch } from 'react-redux';
import { useAppSelector } from '../../../../store/hooks';
import { useRecommendPackageMutation } from '../../../../store/imageBuilderApi';
import { addPackage, selectPackages } from '../../../../store/wizardSlice';
const PackageRecommendations = () => {
const dispatch = useDispatch();
const packages = useAppSelector(selectPackages);
const [isExpanded, setIsExpanded] = useState(false);
const onToggle = (_event: React.MouseEvent, isExpanded: boolean) => {
setIsExpanded(isExpanded);
};
const [fetchRecommendedPackages, { data, isSuccess, isLoading, isError }] =
useRecommendPackageMutation();
useEffect(() => {
const getRecommendedPackages = async () => {
await fetchRecommendedPackages({
recommendPackageRequest: {
packages: packages.map((pkg) => pkg.name),
recommendedPackages: 5,
},
});
};
if (packages.length > 0) {
getRecommendedPackages();
}
}, [fetchRecommendedPackages, packages]);
const addAllPackages = () => {
if (data) {
for (const pkg in data[0].packages) {
dispatch(
addPackage({
name: data[0].packages[pkg],
summary: 'Added from recommended packages',
repository: 'distro',
isRequiredByOpenScap: false,
})
);
}
}
};
const addRecommendedPackage = (pkg: string) => {
dispatch(
addPackage({
name: pkg,
summary: 'Added from recommended packages',
repository: 'distro',
isRequiredByOpenScap: false,
})
);
};
const isRecommendedPackageSelected = (recPkg: string) => {
const foundInPackages = packages.some((pkg) => recPkg === pkg.name);
return foundInPackages;
};
return (
<Panel variant="bordered" className="panel-border">
<PanelMain>
<PanelMainBody>
<ExpandableSection
toggleContent={
<>
<Icon>
<OptimizeIcon />
</Icon>{' '}
Recommended Red Hat packages
</>
}
onToggle={onToggle}
isExpanded={isExpanded}
>
{packages.length === 0 && (
<>Select packages to generate recommendations.</>
)}
{isLoading && <Spinner size="lg" />}
{isError && (
<Alert
title="Recommendations couldn't be fetched"
variant="danger"
isPlain
isInline
>
There was an error when fetching package recommendations. Try
again by changing your selected packages.
</Alert>
)}
{isSuccess && !data && (
<>No recommendations found for the set of selected packages</>
)}
{isSuccess && data && data[0].packages && (
<>
<TextContent>
<Text>
Other users commonly add these packages with the ones you
selected.
</Text>
</TextContent>
<Table variant="compact">
<Thead>
<Tr>
<Th width={80}>Package name</Th>
{/*<Th width={50}>Package summary</Th>*/}
<Th width={20}>
<Button
variant="link"
component="a"
onClick={() => addAllPackages()}
isInline
data-testid="add-all-recommendations-button"
>
Add all packages
</Button>
</Th>
</Tr>
</Thead>
<Tbody>
{data[0].packages.map((pkg) => (
<Tr key={pkg}>
<Td>{pkg}</Td>
{/*<Td>TODO summary</Td>*/}
<Td>
<Button
variant="link"
component="a"
onClick={() => addRecommendedPackage(pkg)}
isInline
isDisabled={isRecommendedPackageSelected(pkg)}
data-testid="add-recommendation-button"
>
Add package
</Button>
</Td>
</Tr>
))}
</Tbody>
</Table>
</>
)}
</ExpandableSection>
</PanelMainBody>
</PanelMain>
</Panel>
);
};
export default PackageRecommendations;

View file

@ -2,6 +2,7 @@ import React from 'react';
import { Text, Form, Title } from '@patternfly/react-core';
import PackageRecommendations from './PackageRecommendations';
import Packages from './Packages';
const PackagesStep = () => {
@ -12,6 +13,7 @@ const PackagesStep = () => {
</Title>
<Text>Blueprints created with Images include all required packages.</Text>
<Packages />
<PackageRecommendations />
</Form>
);
};