buildImageButton: add support of building image with mulitple targets <HMS-4066>

this commit add support of building an image with mulitple targets,
when user build an image, he can choose which targets he wants to build.
This commit is contained in:
Michal Gold 2024-05-23 12:57:25 +03:00 committed by Klara Simickova
parent 67ec26bead
commit 39b29e303c
2 changed files with 174 additions and 10 deletions

View file

@ -1,20 +1,183 @@
import React from 'react';
import React, { useState } from 'react';
import { Button, ButtonProps } from '@patternfly/react-core';
import {
Dropdown,
MenuToggle,
MenuToggleElement,
Menu,
MenuContent,
MenuList,
MenuItem,
Flex,
FlexItem,
Spinner,
MenuToggleAction,
ButtonProps,
Button,
} from '@patternfly/react-core';
import { skipToken } from '@reduxjs/toolkit/query';
import { selectSelectedBlueprintId } from '../../store/BlueprintSlice';
import { useAppSelector } from '../../store/hooks';
import { useComposeBlueprintMutation } from '../../store/imageBuilderApi';
import {useAppDispatch, useAppSelector} from '../../store/hooks';
import {
ImageTypes,
useComposeBlueprintMutation,
useGetBlueprintQuery,
} from '../../store/imageBuilderApi';
import {addNotification} from "@redhat-cloud-services/frontend-components-notifications/redux";
type BuildImagesButtonPropTypes = {
export const BuildImagesButton = () => {
const selectedBlueprintId = useAppSelector(selectSelectedBlueprintId);
const [deselectedTargets, setDeselectedTargets] = useState<ImageTypes[]>([]);
const [buildBlueprint, { isLoading: imageBuildLoading, isError: imageBuildError }] =
useComposeBlueprintMutation();
const dispatch = useAppDispatch();
const onBuildHandler = async () => {
if (selectedBlueprintId) {
try{
await buildBlueprint({
id: selectedBlueprintId,
body: {
image_types: blueprintImageType?.filter(
(target) => !deselectedTargets?.includes(target)
),
},
})}
catch(imageBuildError) {
dispatch(
addNotification({
variant: 'warning',
title: 'No blueprint was build',
})
);
}
}
};
const [isOpen, setIsOpen] = useState(false);
const onToggleClick = () => {
setIsOpen(!isOpen);
};
const { data: blueprintDetails } = useGetBlueprintQuery(
selectedBlueprintId ? { id: selectedBlueprintId } : skipToken
);
const blueprintImageType = blueprintDetails?.image_requests.map(
(image) => image.image_type
);
const onSelect = (
_event: React.MouseEvent<Element, MouseEvent>,
itemId: number
) => {
const imageType = blueprintImageType?.[itemId];
if (imageType && deselectedTargets?.includes(imageType)) {
setDeselectedTargets(
deselectedTargets.filter((target) => target !== imageType)
);
} else if (imageType) {
setDeselectedTargets([...deselectedTargets, imageType]);
}
};
const handleToggleEnvironment = (target: ImageTypes) => {
switch (target) {
case 'aws':
return 'Amazon Web Services (AWS)';
case 'gcp':
return 'Google Cloud Platform (GCP)';
case 'azure':
return 'Microsoft Azure';
case 'oci':
return 'Oracle Cloud Infrastructure';
case 'vsphere-ova':
return 'VMware vSphere';
case 'guest-image':
return 'Virtualization - Guest image (.qcow2)';
case 'image-installer':
return 'Bare metal - Installer';
}
};
return (
<Dropdown
isOpen={isOpen}
onOpenChange={(isOpen: boolean) => setIsOpen(isOpen)}
toggle={(toggleRef: React.Ref<MenuToggleElement>) => (
<MenuToggle
variant="primary"
ref={toggleRef}
isFullWidth
onClick={onToggleClick}
isExpanded={isOpen}
splitButtonOptions={{
variant: 'action',
items: [
<MenuToggleAction
key="split-action"
onClick={onBuildHandler}
id="wizard-build-image-btn"
isDisabled={
!selectedBlueprintId ||
deselectedTargets.length === blueprintImageType?.length
}
>
<Flex display={{ default: 'inlineFlex' }}>
{imageBuildLoading && (
<FlexItem>
<Spinner
style={
{
'--pf-v5-c-spinner--Color': '#fff',
} as React.CSSProperties
}
isInline
size="md"
/>
</FlexItem>
)}
<FlexItem>
{deselectedTargets.length !== 0
? 'Build selected'
: 'Build image'}
</FlexItem>
</Flex>
</MenuToggleAction>,
],
}}
></MenuToggle>
)}
>
<Menu onSelect={onSelect} selected={blueprintImageType}>
<MenuContent>
<MenuList>
{blueprintImageType?.map((imageType, index) => (
<MenuItem
key={imageType}
hasCheckbox
itemId={index}
isSelected={
!deselectedTargets || !deselectedTargets.includes(imageType)
}
>
{handleToggleEnvironment(imageType)}
</MenuItem>
))}
</MenuList>
</MenuContent>
</Menu>
</Dropdown>
);
};
type BuildImagesButtonEmptyStatePropTypes = {
variant?: ButtonProps['variant'];
children?: React.ReactNode;
};
export const BuildImagesButton = ({
export const BuildImagesButtonEmptyState = ({
variant,
children,
}: BuildImagesButtonPropTypes) => {
}: BuildImagesButtonEmptyStatePropTypes) => {
const selectedBlueprintId = useAppSelector(selectSelectedBlueprintId);
const [buildBlueprint, { isLoading: imageBuildLoading }] =
useComposeBlueprintMutation();

View file

@ -22,7 +22,8 @@ import {
CREATING_IMAGES_WITH_IB_SERVICE_URL,
MANAGING_WITH_DNF_URL,
} from '../../constants';
import { BuildImagesButton } from '../Blueprints/BuildImagesButton';
import { BuildImagesButtonEmptyState } from '../Blueprints/BuildImagesButton';
type ImagesEmptyStateProps = {
selectedBlueprint?: string;
@ -44,9 +45,9 @@ const EmptyBlueprintsImagesTable = () => (
</EmptyStateBody>
<EmptyStateFooter>
<EmptyStateActions>
<BuildImagesButton variant="link">
<BuildImagesButtonEmptyState variant="link">
Build latest images
</BuildImagesButton>
</BuildImagesButtonEmptyState>
</EmptyStateActions>
</EmptyStateFooter>
</EmptyState>