@@ -38,6 +38,7 @@ import RepositoryUnavailable from './RepositoryUnavailable';
3838
3939import {
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' ;
5254import { useAppDispatch , useAppSelector } from '../../../../store/hooks' ;
5355import {
@@ -61,11 +63,13 @@ import {
6163 selectPackages ,
6264 selectPayloadRepositories ,
6365 selectRecommendedRepositories ,
66+ selectSnapshotDate ,
6467 selectTemplate ,
6568 selectUseLatest ,
6669 selectWizardMode ,
6770} from '../../../../store/wizardSlice' ;
6871import { releaseToVersion } from '../../../../Utilities/releaseToVersion' ;
72+ import { convertStringToDate , timestampToDisplayStringDetailed } from '../../../../Utilities/time' ;
6973import useDebounce from '../../../../Utilities/useDebounce' ;
7074import { 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 < >
0 commit comments