Skip to content

Commit 6c458ff

Browse files
committed
fix: correct repeatable build repositories view
This adds a different view for the 'Repositories' step that reflects if repeatable build with a set snapshot date was chosen. It hides information about repositories that might be incorrect at the chosen date and present a snapshot date and displays correct package count with a link to the snapshot detail.
1 parent c1c051b commit 6c458ff

File tree

2 files changed

+247
-4
lines changed

2 files changed

+247
-4
lines changed

src/Components/CreateImageWizard/steps/Repositories/Repositories.tsx

Lines changed: 245 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import RepositoryUnavailable from './RepositoryUnavailable';
3838

3939
import {
4040
AMPLITUDE_MODULE_NAME,
41+
CONTENT_URL,
4142
ContentOrigin,
4243
PAGINATION_COUNT,
4344
TEMPLATES_URL,
@@ -48,6 +49,7 @@ import {
4849
useGetTemplateQuery,
4950
useListRepositoriesQuery,
5051
useListRepositoryParametersQuery,
52+
useListSnapshotsByDateMutation,
5153
} from '../../../../store/contentSourcesApi';
5254
import { useAppDispatch, useAppSelector } from '../../../../store/hooks';
5355
import {
@@ -61,11 +63,13 @@ import {
6163
selectPackages,
6264
selectPayloadRepositories,
6365
selectRecommendedRepositories,
66+
selectSnapshotDate,
6467
selectTemplate,
6568
selectUseLatest,
6669
selectWizardMode,
6770
} from '../../../../store/wizardSlice';
6871
import { releaseToVersion } from '../../../../Utilities/releaseToVersion';
72+
import { convertStringToDate, timestampToDisplayStringDetailed } from '../../../../Utilities/time';
6973
import useDebounce from '../../../../Utilities/useDebounce';
7074
import { useFlag } from '../../../../Utilities/useGetEnvironment';
7175

@@ -81,6 +85,7 @@ const Repositories = () => {
8185
const packages = useAppSelector(selectPackages);
8286
const groups = useAppSelector(selectGroups);
8387
const useLatestContent = useAppSelector(selectUseLatest);
88+
const snapshotDate = useAppSelector(selectSnapshotDate);
8489

8590
const payloadRepositories = useAppSelector(selectPayloadRepositories);
8691
const recommendedRepos = useAppSelector(selectRecommendedRepositories);
@@ -495,6 +500,41 @@ const Repositories = () => {
495500
{ refetchOnMountOrArgChange: true, skip: !isTemplateSelected },
496501
);
497502

503+
const [
504+
listSnapshotsByDate,
505+
{
506+
data: snapshotsByDate,
507+
isError: isSnapshotsError,
508+
isLoading: isSnapshotsLoading,
509+
},
510+
] = useListSnapshotsByDateMutation();
511+
512+
useEffect(() => {
513+
if (
514+
!snapshotDate ||
515+
useLatestContent ||
516+
isTemplateSelected ||
517+
!contentList.length
518+
) {
519+
return;
520+
}
521+
522+
listSnapshotsByDate({
523+
apiListSnapshotByDateRequest: {
524+
repository_uuids: contentList
525+
.filter((c) => !!c.uuid)
526+
.map((c) => c.uuid!),
527+
date: new Date(convertStringToDate(snapshotDate)).toISOString(),
528+
},
529+
});
530+
}, [
531+
contentList,
532+
listSnapshotsByDate,
533+
snapshotDate,
534+
useLatestContent,
535+
isTemplateSelected,
536+
]);
537+
498538
useEffect(() => {
499539
if (isTemplateSelected && reposInTemplate.length > 0) {
500540
const customReposInTemplate = reposInTemplate.filter(
@@ -530,10 +570,24 @@ const Repositories = () => {
530570
}
531571
}, [templateUuid, reposInTemplate]);
532572

533-
if (isError || isTemplateError || isReposInTemplateError) return <Error />;
534-
if (isLoading || isTemplateLoading || isReposInTemplateLoading)
573+
if (
574+
isError ||
575+
isTemplateError ||
576+
isReposInTemplateError ||
577+
isSnapshotsError
578+
) {
579+
return <Error />;
580+
}
581+
if (
582+
isLoading ||
583+
isTemplateLoading ||
584+
isReposInTemplateLoading ||
585+
isSnapshotsLoading
586+
) {
535587
return <Loading />;
536-
if (!isTemplateSelected) {
588+
}
589+
590+
if (!isTemplateSelected && !snapshotDate) {
537591
return (
538592
<Grid>
539593
<Modal isOpen={modalOpen} onClose={onClose} variant='small'>
@@ -760,6 +814,194 @@ const Repositories = () => {
760814
/>
761815
</Grid>
762816
);
817+
} else if (!isTemplateSelected && snapshotDate) {
818+
return (
819+
<Grid>
820+
<Modal isOpen={modalOpen} onClose={onClose} variant='small'>
821+
<ModalHeader title='Are you sure?' titleIconVariant='warning' />
822+
<ModalBody>
823+
You are removing a previously added repository.
824+
<br />
825+
We do not recommend removing repositories if you have added packages
826+
from them.
827+
</ModalBody>
828+
<ModalFooter>
829+
<Button key='remove' variant='primary' onClick={handleRemoveAnyway}>
830+
Remove anyway
831+
</Button>
832+
<Button key='back' variant='link' onClick={onClose}>
833+
Back
834+
</Button>
835+
</ModalFooter>
836+
</Modal>
837+
{wizardMode === 'edit' && (
838+
<Alert
839+
title='Removing previously added repositories may lead to issues with selected packages'
840+
variant='warning'
841+
isPlain
842+
isInline
843+
/>
844+
)}
845+
<Toolbar>
846+
<ToolbarContent>
847+
<ToolbarItem>
848+
<BulkSelect
849+
selected={selected}
850+
contentList={contentList}
851+
deselectAll={clearSelected}
852+
perPage={perPage}
853+
handleAddRemove={handleAddRemove}
854+
isDisabled={
855+
isFetching ||
856+
(!selected.size && !contentList.length) ||
857+
contentList.every(
858+
(repo) =>
859+
repo.uuid &&
860+
isRepoDisabled(repo, selected.has(repo.uuid))[0],
861+
)
862+
}
863+
/>
864+
</ToolbarItem>
865+
<ToolbarItem>
866+
<SearchInput
867+
placeholder='Filter repositories'
868+
aria-label='Filter repositories'
869+
onChange={handleFilterRepositories}
870+
value={filterValue}
871+
onClear={() => setFilterValue('')}
872+
/>
873+
</ToolbarItem>
874+
<ToolbarItem>
875+
<Button
876+
variant='primary'
877+
isInline
878+
onClick={() => refresh()}
879+
isLoading={isFetching}
880+
>
881+
{isFetching ? 'Refreshing' : 'Refresh'}
882+
</Button>
883+
</ToolbarItem>
884+
<ToolbarItem>
885+
<ToggleGroup aria-label='Filter repositories list'>
886+
<ToggleGroupItem
887+
text='All'
888+
aria-label='All repositories'
889+
buttonId='toggle-group-all'
890+
isSelected={toggleSelected === 'toggle-group-all'}
891+
onChange={() => handleToggleClick('toggle-group-all')}
892+
/>
893+
<ToggleGroupItem
894+
text='Selected'
895+
isDisabled={!selected.size}
896+
aria-label='Selected repositories'
897+
buttonId='toggle-group-selected'
898+
isSelected={toggleSelected === 'toggle-group-selected'}
899+
onChange={() => handleToggleClick('toggle-group-selected')}
900+
/>
901+
</ToggleGroup>
902+
</ToolbarItem>
903+
</ToolbarContent>
904+
</Toolbar>
905+
<Panel>
906+
<PanelMain>
907+
{previousReposNowUnavailable ? (
908+
<RepositoryUnavailable quantity={previousReposNowUnavailable} />
909+
) : (
910+
''
911+
)}
912+
{contentList.length === 0 ? (
913+
<Empty
914+
hasFilterValue={!!debouncedFilterValue}
915+
refetch={refresh}
916+
/>
917+
) : (
918+
<Table variant='compact'>
919+
<Thead>
920+
<Tr>
921+
<Th aria-label='Selected' />
922+
<Th width={45}>Name</Th>
923+
<Th width={30}>Snapshot date</Th>
924+
<Th>Packages</Th>
925+
</Tr>
926+
</Thead>
927+
<Tbody>
928+
{contentList.map((repo, rowIndex) => {
929+
const { uuid = '', origin = '', name } = repo;
930+
931+
const [isDisabled, disabledReason] = isRepoDisabled(
932+
repo,
933+
selected.has(uuid),
934+
);
935+
936+
const snapshot = snapshotsByDate?.data?.find(
937+
(s) => s.repository_uuid === uuid,
938+
);
939+
const packages =
940+
snapshot?.match?.content_counts?.['rpm.package'];
941+
942+
return (
943+
<Tr key={`${uuid}-${rowIndex}`}>
944+
<Td
945+
select={{
946+
isSelected: selected.has(uuid),
947+
rowIndex: rowIndex,
948+
onSelect: (_, isSelecting) =>
949+
handleAddRemove(repo, isSelecting),
950+
isDisabled: isDisabled,
951+
}}
952+
title={disabledReason}
953+
/>
954+
<Td dataLabel={'Name'}>
955+
{name}
956+
{origin === ContentOrigin.UPLOAD ? (
957+
<UploadRepositoryLabel />
958+
) : origin === ContentOrigin.COMMUNITY ? (
959+
<CommunityRepositoryLabel />
960+
) : (
961+
<></>
962+
)}
963+
</Td>
964+
<Td dataLabel={'Snapshot date'}>
965+
{timestampToDisplayStringDetailed(
966+
snapshot?.match?.created_at ?? '',
967+
'UTC',
968+
) || '-'}
969+
</Td>
970+
<Td dataLabel={'Packages'}>
971+
{packages && snapshot.match?.uuid ? (
972+
<Button
973+
component='a'
974+
target='_blank'
975+
variant='link'
976+
icon={<ExternalLinkAltIcon />}
977+
iconPosition='right'
978+
isInline
979+
href={`${CONTENT_URL}/${uuid}/snapshots/${snapshot.match.uuid}`}
980+
>
981+
{packages}
982+
</Button>
983+
) : (
984+
'-'
985+
)}
986+
</Td>
987+
</Tr>
988+
);
989+
})}
990+
</Tbody>
991+
</Table>
992+
)}
993+
</PanelMain>
994+
</Panel>
995+
<Pagination
996+
itemCount={count ?? PAGINATION_COUNT}
997+
perPage={perPage}
998+
page={page}
999+
onSetPage={(_, newPage) => setPage(newPage)}
1000+
onPerPageSelect={handlePerPageSelect}
1001+
variant={PaginationVariant.bottom}
1002+
/>
1003+
</Grid>
1004+
);
7631005
} else {
7641006
return (
7651007
<>

src/Utilities/time.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ export const timestampToDisplayString = (ts?: string) => {
3333
return tsDisplay;
3434
};
3535

36-
export const timestampToDisplayStringDetailed = (ts?: string) => {
36+
export const timestampToDisplayStringDetailed = (ts?: string, tz?: string) => {
3737
// Detailed representation including time and time zone
3838
if (!ts) {
3939
return '';
@@ -49,6 +49,7 @@ export const timestampToDisplayStringDetailed = (ts?: string) => {
4949
second: 'numeric',
5050
hour12: false,
5151
timeZoneName: 'short',
52+
timeZone: tz,
5253
};
5354

5455
const tsDisplay = new Intl.DateTimeFormat('en-US', options).format(ms);

0 commit comments

Comments
 (0)