The `import/order` rule isn't enough to sort import within a single import group alphabetically. This adds `sort-imports` rule that handles the sorting within groups.
253 lines
7.8 KiB
TypeScript
253 lines
7.8 KiB
TypeScript
import React, { useState } from 'react';
|
|
|
|
import {
|
|
Alert,
|
|
AlertActionLink,
|
|
ExpandableSection,
|
|
List,
|
|
ListItem,
|
|
Pagination,
|
|
Title,
|
|
Toolbar,
|
|
ToolbarContent,
|
|
ToolbarItem,
|
|
} from '@patternfly/react-core';
|
|
|
|
import { useFixupBPWithNotification as useFixupBlueprintMutation } from '../../Hooks';
|
|
import {
|
|
useGetBlueprintQuery,
|
|
useGetBlueprintsQuery,
|
|
} from '../../store/backendApi';
|
|
import {
|
|
selectBlueprintSearchInput,
|
|
selectBlueprintVersionFilterAPI,
|
|
selectSelectedBlueprintId,
|
|
} from '../../store/BlueprintSlice';
|
|
import { useAppSelector } from '../../store/hooks';
|
|
import {
|
|
BlueprintItem,
|
|
Distributions,
|
|
GetBlueprintComposesApiArg,
|
|
useGetBlueprintComposesQuery,
|
|
} from '../../store/imageBuilderApi';
|
|
import { BlueprintActionsMenu } from '../Blueprints/BlueprintActionsMenu';
|
|
import BlueprintDiffModal from '../Blueprints/BlueprintDiffModal';
|
|
import BlueprintVersionFilter from '../Blueprints/BlueprintVersionFilter';
|
|
import { BuildImagesButton } from '../Blueprints/BuildImagesButton';
|
|
import { DeleteBlueprintModal } from '../Blueprints/DeleteBlueprintModal';
|
|
import { EditBlueprintButton } from '../Blueprints/EditBlueprintButton';
|
|
|
|
interface imagesTableToolbarProps {
|
|
itemCount: number;
|
|
perPage: number;
|
|
page: number;
|
|
setPage: (page: number) => void;
|
|
onPerPageSelect: (event: React.MouseEvent, perPage: number) => void;
|
|
}
|
|
|
|
const ImagesTableToolbar: React.FC<imagesTableToolbarProps> = ({
|
|
itemCount,
|
|
perPage,
|
|
page,
|
|
setPage,
|
|
onPerPageSelect,
|
|
}: imagesTableToolbarProps) => {
|
|
const [showDeleteModal, setShowDeleteModal] = useState(false);
|
|
const [showDiffModal, setShowDiffModal] = useState(false);
|
|
const selectedBlueprintId = useAppSelector(selectSelectedBlueprintId);
|
|
const blueprintSearchInput = useAppSelector(selectBlueprintSearchInput);
|
|
const blueprintVersionFilterAPI = useAppSelector(
|
|
selectBlueprintVersionFilterAPI
|
|
);
|
|
|
|
const searchParams: GetBlueprintComposesApiArg = {
|
|
id: selectedBlueprintId as string,
|
|
limit: perPage,
|
|
offset: perPage * (page - 1),
|
|
};
|
|
|
|
if (blueprintVersionFilterAPI) {
|
|
searchParams.blueprintVersion = blueprintVersionFilterAPI;
|
|
}
|
|
|
|
const {
|
|
data: blueprintsComposes,
|
|
isFetching: isFetchingBlueprintsCompose,
|
|
isSuccess: isSuccessBlueprintsCompose,
|
|
} = useGetBlueprintComposesQuery(searchParams, {
|
|
skip: !selectedBlueprintId,
|
|
});
|
|
|
|
const { selectedBlueprintName, selectedBlueprintVersion } =
|
|
useGetBlueprintsQuery(
|
|
{ search: blueprintSearchInput as string },
|
|
{
|
|
selectFromResult: ({ data }) => {
|
|
const bp = data?.data.find(
|
|
(blueprint: BlueprintItem) => blueprint.id === selectedBlueprintId
|
|
);
|
|
return {
|
|
selectedBlueprintName: bp?.name,
|
|
selectedBlueprintVersion: bp?.version,
|
|
};
|
|
},
|
|
}
|
|
);
|
|
|
|
const latestImageVersion = blueprintsComposes?.data[0]?.blueprint_version;
|
|
|
|
const isBlueprintOutSync =
|
|
selectedBlueprintId &&
|
|
!isFetchingBlueprintsCompose &&
|
|
latestImageVersion !== selectedBlueprintVersion;
|
|
|
|
const pagination = (
|
|
<Pagination
|
|
itemCount={itemCount}
|
|
perPage={perPage}
|
|
page={page}
|
|
onSetPage={(_, page) => setPage(page)}
|
|
onPerPageSelect={onPerPageSelect}
|
|
widgetId="compose-pagination-top"
|
|
data-testid="images-pagination-top"
|
|
isCompact
|
|
/>
|
|
);
|
|
|
|
const isBlueprintDistroCentos8 = () => {
|
|
if (isSuccessBlueprintsCompose) {
|
|
return (
|
|
blueprintsComposes?.data[0].request.distribution ===
|
|
('centos-8' as Distributions)
|
|
);
|
|
}
|
|
};
|
|
|
|
const { data: blueprintDetails } = useGetBlueprintQuery(
|
|
{ id: selectedBlueprintId! },
|
|
{ skip: !selectedBlueprintId }
|
|
);
|
|
|
|
const { trigger: fixupBlueprint } = useFixupBlueprintMutation();
|
|
const hasErrors =
|
|
blueprintDetails?.lint?.errors && blueprintDetails?.lint?.errors.length > 0;
|
|
const [isLintExp, setIsLintExp] = React.useState(true);
|
|
const onToggleLintExp = (_event: React.MouseEvent, isExpanded: boolean) => {
|
|
setIsLintExp(isExpanded);
|
|
};
|
|
|
|
return (
|
|
<>
|
|
<DeleteBlueprintModal
|
|
setShowDeleteModal={setShowDeleteModal}
|
|
isOpen={showDeleteModal}
|
|
/>
|
|
{itemCount > 0 && isBlueprintOutSync && (
|
|
<BlueprintDiffModal
|
|
baseVersion={latestImageVersion}
|
|
blueprintName={selectedBlueprintName}
|
|
isOpen={showDiffModal}
|
|
onClose={() => setShowDiffModal(false)}
|
|
/>
|
|
)}
|
|
<Toolbar>
|
|
<ToolbarContent>
|
|
<Title headingLevel="h2">
|
|
{selectedBlueprintName
|
|
? `${selectedBlueprintName} images`
|
|
: 'All images'}
|
|
</Title>
|
|
</ToolbarContent>
|
|
{hasErrors && (
|
|
<Alert
|
|
variant="warning"
|
|
style={{
|
|
margin:
|
|
'0 var(--pf6-c-toolbar__content--PaddingRight) 0 var(--pf-v6-c-toolbar__content--PaddingLeft)',
|
|
}}
|
|
isInline
|
|
title={`The selected blueprint has errors.`}
|
|
actionLinks={
|
|
<AlertActionLink
|
|
onClick={async () => {
|
|
await fixupBlueprint({ id: selectedBlueprintId! });
|
|
}}
|
|
id="blueprint_fix_errors_automatically"
|
|
>
|
|
Fix errors automatically (updates the blueprint)
|
|
</AlertActionLink>
|
|
}
|
|
>
|
|
<ExpandableSection
|
|
toggleText={isLintExp ? 'Show less' : 'Show more'}
|
|
onToggle={onToggleLintExp}
|
|
isExpanded={isLintExp}
|
|
>
|
|
<List isPlain>
|
|
{blueprintDetails?.lint?.errors?.map((err) => (
|
|
<ListItem key={err.description}>
|
|
{err.name}: {err.description}
|
|
</ListItem>
|
|
))}
|
|
</List>
|
|
</ExpandableSection>
|
|
</Alert>
|
|
)}
|
|
{itemCount > 0 && isBlueprintOutSync && (
|
|
<Alert
|
|
style={{
|
|
margin:
|
|
'0 var(--pf-v6-c-toolbar__content--PaddingRight) 0 var(--pf-v6-c-toolbar__content--PaddingLeft)',
|
|
}}
|
|
isInline
|
|
title={`The selected blueprint is at version ${selectedBlueprintVersion}, the latest images are at version ${latestImageVersion}. Build images to synchronize with the latest version.`}
|
|
actionLinks={
|
|
<AlertActionLink
|
|
onClick={() => setShowDiffModal(true)}
|
|
id="blueprint_view_version_difference"
|
|
>
|
|
View the difference
|
|
</AlertActionLink>
|
|
}
|
|
/>
|
|
)}{' '}
|
|
{blueprintsComposes &&
|
|
blueprintsComposes.data.length > 0 &&
|
|
isBlueprintDistroCentos8() && (
|
|
<Alert
|
|
style={{
|
|
margin:
|
|
'0 var(--pf-v6-c-toolbar__content--PaddingRight) 0 var(--pf-v6-c-toolbar__content--PaddingLeft)',
|
|
}}
|
|
isInline
|
|
variant="warning"
|
|
title="CentOS Stream 8 is no longer supported, building images from this blueprint will fail. Edit blueprint to update the release to CentOS Stream 9."
|
|
/>
|
|
)}
|
|
<ToolbarContent>
|
|
{selectedBlueprintId && (
|
|
<>
|
|
<ToolbarItem>
|
|
<BlueprintVersionFilter onFilterChange={() => setPage(1)} />
|
|
</ToolbarItem>
|
|
<ToolbarItem>
|
|
<BuildImagesButton />
|
|
</ToolbarItem>
|
|
<ToolbarItem>
|
|
<EditBlueprintButton />
|
|
</ToolbarItem>
|
|
<ToolbarItem>
|
|
<BlueprintActionsMenu setShowDeleteModal={setShowDeleteModal} />
|
|
</ToolbarItem>
|
|
</>
|
|
)}
|
|
<ToolbarItem variant="pagination" align={{ default: 'alignEnd' }}>
|
|
{pagination}
|
|
</ToolbarItem>
|
|
</ToolbarContent>
|
|
</Toolbar>
|
|
</>
|
|
);
|
|
};
|
|
|
|
export default ImagesTableToolbar;
|