diff --git a/src/Pages/ContentListTable/ContentListTable.tsx b/src/Pages/ContentListTable/ContentListTable.tsx index 6a81280f..d1a36d56 100644 --- a/src/Pages/ContentListTable/ContentListTable.tsx +++ b/src/Pages/ContentListTable/ContentListTable.tsx @@ -177,7 +177,7 @@ const ContentListTable = () => { // Other update actions will be added to this later. const actionTakingPlace = - isFetching || repositoryParamsLoading || isIntrospecting || isDeletingItems; + isFetching || repositoryParamsLoading || isIntrospecting || isDeletingItems; const onSetPage = (_, newPage) => setPage(newPage); @@ -283,7 +283,7 @@ const ContentListTable = () => { { isSeparator: true }, { title: 'Delete', - onClick: () => navigate(`delete-repository?repoUUIDS=${rowData.uuid}?page=${page}?perPage=${perPage}?filterData=${filterData}`), + onClick: () => navigate(`delete-repository?repoUUIDS=${rowData.uuid}`), }, ], [actionTakingPlace, checkedRepositories, isRedHatRepository], @@ -362,7 +362,12 @@ const ContentListTable = () => { return ( <> - + { }; export const useContentListOutletContext = () => - useOutletContext<{ clearCheckedRepositories: () => void }>(); + useOutletContext<{ + clearCheckedRepositories: () => void; + deletionContext: { + page: number; + perPage: number; + filterData: FilterData; + contentOrigin: ContentOrigin; + sortString: string; + }; + }>(); export default ContentListTable; diff --git a/src/Pages/ContentListTable/components/DeleteContentModal/DeleteContent.test.tsx b/src/Pages/ContentListTable/components/DeleteContentModal/DeleteContent.test.tsx new file mode 100644 index 00000000..8d7b9af4 --- /dev/null +++ b/src/Pages/ContentListTable/components/DeleteContentModal/DeleteContent.test.tsx @@ -0,0 +1,80 @@ +import { render } from '@testing-library/react'; +import { ReactQueryTestWrapper, defaultContentItem } from '../../../../testingHelpers'; +import { useFetchContent } from '../../../../services/Content/ContentQueries'; +import DeleteContentModal from './DeleteContentModal'; +import { ContentOrigin } from '../../../../services/Content/ContentApi'; + +jest.mock('react-query', () => ({ + ...jest.requireActual('react-query'), + useQueryClient: jest.fn(), +})); + +jest.mock('react-router-dom', () => ({ + useNavigate: jest.fn(), + useLocation: () => ({ + search: `delete-repository?${defaultContentItem.uuid}`, + }), +})); + +jest.mock('../../ContentListTable', () => ({ + useContentListOutletContext: () => ({ + clearCheckedRepositories: () => undefined, + deletionContext: { + page: 1, + perPage: 21, + filterData: undefined, + contentOrigin: ContentOrigin.EXTERNAL, + sortString: '', + }, + }), +})); + +jest.mock('../../../../Hooks/useRootPath', () => () => 'someUrl'); + +jest.mock('../../../../services/Content/ContentQueries', () => ({ + useDeleteContentItemMutate: () => ({ mutate: () => undefined, isLoading: false }), + useFetchContent: jest.fn(), +})); + +jest.mock('../../../../middleware/AppContext', () => ({ useAppContext: () => ({}) })); + +it('Render Delete Modal', () => { + const data = defaultContentItem; + (useFetchContent as jest.Mock).mockImplementation(() => ({ + isLoading: false, + data: data, + })); + + const { queryByText } = render( + + + , + ); + + expect(queryByText(defaultContentItem.name)).toBeInTheDocument(); + expect(queryByText(defaultContentItem.url)).toBeInTheDocument(); + expect(queryByText(defaultContentItem.distribution_arch)).toBeInTheDocument(); + expect(queryByText(defaultContentItem.distribution_versions[0])).toBeInTheDocument(); + expect(queryByText('None')).not.toBeInTheDocument(); +}); + +it('Render Delete Modal with no gpg key', () => { + const data = defaultContentItem; + data.gpg_key = ''; + (useFetchContent as jest.Mock).mockImplementation(() => ({ + isLoading: false, + data: data, + })); + + const { queryByText } = render( + + + , + ); + + expect(queryByText(defaultContentItem.name)).toBeInTheDocument(); + expect(queryByText(defaultContentItem.url)).toBeInTheDocument(); + expect(queryByText(defaultContentItem.distribution_arch)).toBeInTheDocument(); + expect(queryByText(defaultContentItem.distribution_versions[0])).toBeInTheDocument(); + expect(queryByText('None')).toBeInTheDocument(); +}); diff --git a/src/Pages/ContentListTable/components/DeleteContentModal/DeleteContent.tsx b/src/Pages/ContentListTable/components/DeleteContentModal/DeleteContent.tsx deleted file mode 100644 index de4fe0a7..00000000 --- a/src/Pages/ContentListTable/components/DeleteContentModal/DeleteContent.tsx +++ /dev/null @@ -1,166 +0,0 @@ -import { - Bullseye, - Button, - Modal, - ModalVariant, - Popover, - Spinner, - Stack, - StackItem, - Text, - } from '@patternfly/react-core'; - import { OutlinedQuestionCircleIcon } from '@patternfly/react-icons'; - import { global_Color_200, global_Color_100 } from '@patternfly/react-tokens'; - import { useEffect, useState } from 'react'; - import { createUseStyles } from 'react-jss'; - import Hide from '../../../../components/Hide/Hide'; - import { - CONTENT_ITEM_KEY, - useFetchContent, - useDeleteContentItemMutate - } from '../../../../services/Content/ContentQueries'; - import { useQueryClient } from 'react-query'; - import { useLocation, useNavigate } from 'react-router-dom'; - import { FilterData } from '../../../../services/Content/ContentApi'; - import { useContentListOutletContext } from '../../ContentListTable'; - import useRootPath from '../../../../Hooks/useRootPath'; - - const useStyles = createUseStyles({ - description: { - paddingTop: '12px', // 4px on the title bottom padding makes this the "standard" 16 total padding - color: global_Color_200.value, - }, - removeButton: { - marginRight: '36px', - transition: 'unset!important', - }, - title:{ - paddingTop: '24px', - color: global_Color_100.value, - fontWeight: 'bold', - fontSize: '14px', - }, - textContent:{ - color: global_Color_200.value, - fontWeight: 400, - fontSize: '16px', - }, - }); - - -const DeleteContent = () => { - const classes = useStyles(); - const navigate = useNavigate(); - const rootPath = useRootPath(); - const queryClient = useQueryClient(); - const { search } = useLocation(); - const [initialLoad, setInitialLoad] = useState(true); - const [isLoading, setIsLoading] = useState(false); - const { clearCheckedRepositories } = useContentListOutletContext(); - - const uuids = new URLSearchParams(search).get('repoUUIDS')?.split(',') || []; - const page = Number(new URLSearchParams(search).get('page')) || 1; - const perPage = Number(new URLSearchParams(search).get('perPage')) || 20; - const filterData:FilterData = { - searchQuery: '', - versions: [], - arches: [], - statuses: [], - }; - const { mutateAsync: deleteItem, isLoading: isDeleting } = useDeleteContentItemMutate( - queryClient, - page, - perPage, - filterData, - '', - ); - - - const onClose = () => navigate(rootPath); - const onSave = async () => - deleteItem(data?.uuid || '').then(() => { - onClose(); - clearCheckedRepositories(); - queryClient.invalidateQueries(CONTENT_ITEM_KEY); - }); - - const { data, isError } = useFetchContent(uuids); - const values = data ? [data] : []; - - - useEffect(() => { - if (values.length) { - setInitialLoad(false); - setIsLoading(false); - } - }, [values]); - - const actionTakingPlace = isDeleting || isLoading || initialLoad || isError; - - return ( - Remove custom repository} - bodyContent={
Use this form to remove the values of an existing repository.
} - > - - - } - description={ -

- Are you sure you want to remove this repository? -

- } - isOpen - onClose={onClose} - footer={ - - - - - - - } - > - - - - - - - Name - {data?.name} - URL - {data?.url} - Archicture - {data?.distribution_arch ?? 'Any'} - Versions - {data?.distribution_versions ?? 'Any'} - GPG Key - { data?.gpg_key === undefined || data?.gpg_key === '' ? 'None' : data?.gpg_key } - -
- ); -}; - -export default DeleteContent; diff --git a/src/Pages/ContentListTable/components/DeleteContentModal/DeleteContentModal.tsx b/src/Pages/ContentListTable/components/DeleteContentModal/DeleteContentModal.tsx new file mode 100644 index 00000000..8d2c9ccc --- /dev/null +++ b/src/Pages/ContentListTable/components/DeleteContentModal/DeleteContentModal.tsx @@ -0,0 +1,166 @@ +import { + Bullseye, + Button, + Grid, + GridItem, + Modal, + ModalVariant, + Spinner, + Stack, + StackItem, + Text, + TextArea, + Title, +} from '@patternfly/react-core'; + +import { global_Color_100 } from '@patternfly/react-tokens'; +import { useEffect, useState } from 'react'; +import { createUseStyles } from 'react-jss'; +import Hide from '../../../../components/Hide/Hide'; +import { + CONTENT_ITEM_KEY, + useFetchContent, + useDeleteContentItemMutate, +} from '../../../../services/Content/ContentQueries'; +import { useQueryClient } from 'react-query'; +import { useLocation, useNavigate } from 'react-router-dom'; +import { useContentListOutletContext } from '../../ContentListTable'; +import useRootPath from '../../../../Hooks/useRootPath'; + +const useStyles = createUseStyles({ + description: { + paddingTop: '12px', // 4px on the title bottom padding makes this the "standard" 16 total padding + color: global_Color_100.value, + }, + removeButton: { + marginRight: '36px', + transition: 'unset!important', + }, + textAreaContent: { + marginTop: '8px', + color: global_Color_100.value, + height: '200px', + }, +}); + +export default function DeleteContentModal() { + const classes = useStyles(); + const navigate = useNavigate(); + const rootPath = useRootPath(); + const queryClient = useQueryClient(); + const { search } = useLocation(); + const [isLoading, setIsLoading] = useState(true); + const { + clearCheckedRepositories, + deletionContext: { page, perPage, filterData, contentOrigin, sortString }, + } = useContentListOutletContext(); + + const uuids = new URLSearchParams(search).get('repoUUIDS')?.split(',') || []; + + const { mutate: deleteItem, isLoading: isDeleting } = useDeleteContentItemMutate( + queryClient, + page, + perPage, + filterData, + contentOrigin, + sortString, + ); + + const onClose = () => navigate(rootPath); + const onSave = async () => { + deleteItem(data?.uuid || ''); + onClose(); + clearCheckedRepositories(); + queryClient.invalidateQueries(CONTENT_ITEM_KEY); + }; + + const { data, isError } = useFetchContent(uuids); + const values = data ? [data] : []; + + useEffect(() => { + if (data) { + setIsLoading(false); + } + if (isError) { + onClose(); + } + }, [values, isError]); + + const actionTakingPlace = isDeleting || isLoading; + + return ( + + Are you sure you want to remove this repository? + + } + isOpen + onClose={onClose} + footer={ + + + + + + + } + > + + + + + + + + + Name + {data?.name} + + + URL + {data?.url} + + + Archicture + {data?.distribution_arch ?? 'Any'} + + + Versions + {data?.distribution_versions ?? 'Any'} + + + GPG Key + {!data?.gpg_key ? ( + None + ) : ( +