debian-image-builder-frontend/src/Components/CreateImageWizard/steps/Review/ReviewStepTables.tsx

279 lines
8 KiB
TypeScript

import React from 'react';
import {
Alert,
EmptyState,
Panel,
PanelMain,
Spinner,
} from '@patternfly/react-core';
import { Table, Tbody, Td, Th, Thead, Tr } from '@patternfly/react-table';
import { ContentOrigin } from '../../../../constants';
import {
ApiSnapshotForDate,
useGetTemplateQuery,
useListRepositoriesQuery,
} from '../../../../store/contentSourcesApi';
import { useAppSelector } from '../../../../store/hooks';
import {
selectCustomRepositories,
selectDistribution,
selectGroups,
selectPackages,
selectPartitions,
selectRecommendedRepositories,
selectTemplate,
} from '../../../../store/wizardSlice';
import { getEpelVersionForDistribution } from '../../../../Utilities/epel';
import PackageInfoNotAvailablePopover from '../Packages/components/PackageInfoNotAvailablePopover';
type repoPropType = {
repoUuid: string | undefined;
};
const RepoName = ({ repoUuid }: repoPropType) => {
const { data, isSuccess, isFetching, isError } = useListRepositoriesQuery(
{
// @ts-ignore if repoUrl is undefined the query is going to get skipped, so it's safe to ignore the linter here
uuid: repoUuid ?? '',
contentType: 'rpm',
origin: ContentOrigin.ALL,
},
{ skip: !repoUuid },
);
const errorLoading = () => {
return (
<Alert
variant="danger"
isInline
isPlain
title="Error loading repository name"
/>
);
};
return (
<>
{/*
this might be a tad bit hacky
"isSuccess" indicates only that the query fetched successfuly, but it
doesn't differentiate between a scenario when the repository was found
in the response and when it was not
for this reason I've split the "isSuccess" into two paths:
- query finished and the repo was found -> render the name of the repo
- query finished, but the repo was not found -> render an error
*/}
{isSuccess && data?.data?.[0]?.name && <p>{data.data[0].name}</p>}
{isSuccess && !data?.data?.[0]?.name && errorLoading()}
{isFetching && <Spinner size="md" />}
{isError && errorLoading()}
</>
);
};
export const FSReviewTable = () => {
const partitions = useAppSelector(selectPartitions);
return (
<Panel isScrollable>
<PanelMain maxHeight="30ch">
<Table aria-label="File system configuration table" variant="compact">
<Thead>
<Tr>
<Th>Mount point</Th>
<Th>File system type</Th>
<Th>Minimum size</Th>
</Tr>
</Thead>
<Tbody>
{partitions.map((partition, partitionIndex) => (
<Tr key={partitionIndex}>
<Td className="pf-m-width-30">{partition.mountpoint}</Td>
<Td className="pf-m-width-30">xfs</Td>
<Td className="pf-m-width-30">
{parseInt(partition.min_size).toString()} {partition.unit}
</Td>
</Tr>
))}
</Tbody>
</Table>
</PanelMain>
</Panel>
);
};
const Error = () => {
return (
<Alert title="Repositories unavailable" variant="danger" isPlain isInline>
Repositories cannot be reached, try again later.
</Alert>
);
};
const Loading = () => {
return (
<EmptyState
headingLevel="h4"
icon={Spinner}
titleText="Loading"
></EmptyState>
);
};
export const SnapshotTable = ({
snapshotForDate,
}: {
snapshotForDate: ApiSnapshotForDate[];
}) => {
const template = useAppSelector(selectTemplate);
const { data: templateData } = useGetTemplateQuery(
{
uuid: template,
},
{ refetchOnMountOrArgChange: true, skip: template === '' },
);
const { data, isSuccess, isLoading, isError } = useListRepositoriesQuery({
uuid:
snapshotForDate.length > 0
? snapshotForDate.map(({ repository_uuid }) => repository_uuid).join()
: template && templateData && templateData.repository_uuids
? templateData.repository_uuids.join(',')
: '',
origin: ContentOrigin.REDHAT + ',' + ContentOrigin.CUSTOM, // Make sure to show both redhat and external
});
const isAfterSet = new Set(
snapshotForDate
.filter(({ is_after }) => is_after)
.map(({ repository_uuid }) => repository_uuid),
);
const stringToDateToMMDDYYYY = (strDate: string) => {
const date = new Date(strDate);
return `${(date.getMonth() + 1).toString().padStart(2, '0')}/${date
.getDate()
.toString()
.padStart(2, '0')}/${date.getFullYear()}`;
};
return (
(isError && <Error />) ||
(isLoading && <Loading />) ||
(isSuccess && (
<Panel isScrollable>
<PanelMain maxHeight="30ch">
<Table aria-label="Packages table" variant="compact">
<Thead>
<Tr>
<Th>Name</Th>
<Th>Last snapshot date</Th>
</Tr>
</Thead>
<Tbody>
{data?.data?.map(({ uuid, name, last_snapshot }, pkgIndex) => (
<Tr key={pkgIndex}>
<Td>{name}</Td>
<Td>
{uuid && isAfterSet.has(uuid) ? (
<Alert
title={
last_snapshot?.created_at
? stringToDateToMMDDYYYY(last_snapshot.created_at)
: 'N/A'
}
variant="warning"
isPlain
isInline
/>
) : last_snapshot?.created_at ? (
stringToDateToMMDDYYYY(last_snapshot.created_at)
) : (
'N/A'
)}
</Td>
</Tr>
))}
</Tbody>
</Table>
</PanelMain>
</Panel>
))
);
};
export const PackagesTable = () => {
const packages = useAppSelector(selectPackages);
const groups = useAppSelector(selectGroups);
return (
<Panel isScrollable>
<PanelMain maxHeight="30ch">
<Table aria-label="Packages table" variant="compact">
<Thead>
<Tr>
<Th>Name</Th>
<Th>
Description <PackageInfoNotAvailablePopover />
</Th>
</Tr>
</Thead>
<Tbody>
{packages.map((pkg, pkgIndex) => (
<Tr key={pkgIndex}>
<Td>{pkg.name}</Td>
<Td>{pkg.summary ? pkg.summary : 'Not available'}</Td>
</Tr>
))}
{groups.map((grp, grpIndex) => (
<Tr key={grpIndex}>
<Td>@{grp.name}</Td>
<Td>{grp.description ? grp.description : 'Not available'}</Td>
</Tr>
))}
</Tbody>
</Table>
</PanelMain>
</Panel>
);
};
export const RepositoriesTable = () => {
const distribution = useAppSelector(selectDistribution);
const repositoriesList = useAppSelector(selectCustomRepositories);
const recommendedRepositoriesList = useAppSelector(
selectRecommendedRepositories,
);
return (
<Panel isScrollable>
<PanelMain maxHeight="30ch">
<Table aria-label="Custom repositories table" variant="compact">
<Thead>
<Tr>
<Th>Name</Th>
</Tr>
</Thead>
<Tbody>
{repositoriesList.map((repo, repoIndex) => (
<Tr key={repoIndex + 1}>
<Td className="pf-m-width-60">
<RepoName repoUuid={repo.id} />
</Td>
</Tr>
))}
{recommendedRepositoriesList.length > 0 && (
<Tr key={0}>
<Td className="pf-m-width-60">
EPEL {getEpelVersionForDistribution(distribution)} Everything
x86_64
</Td>
</Tr>
)}
</Tbody>
</Table>
</PanelMain>
</Panel>
);
};