From 0fe5d92decbeccf6010e555aea98590b8f2cbd6a Mon Sep 17 00:00:00 2001 From: Dominik Vagner Date: Wed, 21 Jan 2026 13:45:55 +0100 Subject: [PATCH 1/6] chore: update react-query to v4 --- package.json | 3 ++- yarn.lock | 15 ++++++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 6aa38e0a8..f312b7c6f 100644 --- a/package.json +++ b/package.json @@ -34,15 +34,16 @@ "dependencies": { "@patternfly/react-core": "^6.3.1", "@patternfly/react-data-view": "^6.3.0", + "@patternfly/react-drag-drop": "^6.3.1", "@patternfly/react-icons": "^6.3.1", "@patternfly/react-styles": "^6.3.1", "@patternfly/react-table": "^6.3.1", "@patternfly/react-templates": "^6.4.1", - "@patternfly/react-drag-drop": "^6.4.1", "@redhat-cloud-services/frontend-components": "^7.0.40", "@redhat-cloud-services/frontend-components-config": "^6.7.51", "@redhat-cloud-services/frontend-components-notifications": "^6.1.41", "@redhat-cloud-services/frontend-components-utilities": "^7.0.36", + "@tanstack/react-query": "^4.42.2", "@testing-library/dom": "^10.4.1", "@types/dockerode": "^4.0.1", "@unleash/proxy-client-react": "^5.0.1", diff --git a/yarn.lock b/yarn.lock index 2e03f3144..c654020d2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2871,6 +2871,19 @@ dependencies: "@swc/counter" "^0.1.3" +"@tanstack/query-core@4.41.1": + version "4.41.1" + resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-4.41.1.tgz#1872f912609b7ca9d24f6b5f56ab3aedb216580d" + integrity sha512-XZvEw2OT+Nmi+ByQjURv3ckxRfzbYXSL6Hb60lgEn4GqUXz8HQTFdySvcSuCdxashqkBLrDvn9NwOhAbMTe9ow== + +"@tanstack/react-query@^4.42.2": + version "4.42.2" + resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-4.42.2.tgz#7d0beaf8bad710a9309730b51fb49985f08d0026" + integrity sha512-KFqT8wb/d0bHbzvJEuD/vEU8lUSC5cZDurOMtAR3G+mUABqVWvVswQ/norjFXedjQe+nfQQ9CWrOabWcRP3TKA== + dependencies: + "@tanstack/query-core" "4.41.1" + use-sync-external-store "^1.6.0" + "@testing-library/dom@^10.4.1": version "10.4.1" resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-10.4.1.tgz#d444f8a889e9a46e9a3b4f3b88e0fcb3efb6cf95" @@ -11461,7 +11474,7 @@ url@^0.11.0: punycode "^1.4.1" qs "^6.12.3" -use-sync-external-store@^1.4.0: +use-sync-external-store@^1.4.0, use-sync-external-store@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz#b174bfa65cb2b526732d9f2ac0a408027876f32d" integrity sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w== From 0a6cd38b0b7f4f32b7ff0dd47e5e93ba0f09cf34 Mon Sep 17 00:00:00 2001 From: Dominik Vagner Date: Wed, 21 Jan 2026 13:46:41 +0100 Subject: [PATCH 2/6] chore: run react-query v4 migration codemods --- package.json | 1 - src/AppEntry.tsx | 2 +- src/Hooks/useHasRegisteredSystems.ts | 2 +- src/Hooks/usePageSafe.tsx | 2 +- .../Repositories/ContentListTable/ContentListTable.tsx | 2 +- .../ContentListTable/components/AddContent/AddContent.tsx | 2 +- .../ContentListTable/components/AddContent/helpers.ts | 6 +++--- .../components/DeleteContentModal/DeleteContentModal.tsx | 2 +- .../DeleteSnapshotsModal/DeleteSnapshotsModal.tsx | 2 +- .../ContentListTable/hooks/useContentListFilters.ts | 2 +- .../PopularRepositoriesTable/PopularRepositoriesTable.tsx | 2 +- .../components/AssignTemplateModal/AddSystemModal.test.tsx | 2 +- .../components/AssignTemplateModal/AddSystemModal.tsx | 2 +- .../components/AssignTemplateModal/AssignTemplateModal.tsx | 2 +- .../components/AssignTemplateModal/SystemListView.tsx | 2 +- .../TemplateDetails/components/Tabs/TemplateSystemsTab.tsx | 2 +- .../components/AddOrEditTemplate/AddTemplateContext.tsx | 2 +- .../TemplatesTable/components/DeleteTemplateModal.tsx | 2 +- .../TemplatesTable/components/TemplateFilters.test.tsx | 2 +- .../Templates/TemplatesTable/components/TemplateFilters.tsx | 2 +- src/services/Admin/AdminQueries.ts | 2 +- src/services/Admin/AdminTaskQueries.ts | 2 +- src/services/Content/ContentQueries.ts | 2 +- src/services/Subscriptions/SubscriptionQueries.ts | 2 +- src/services/Systems/SystemsQueries.ts | 2 +- src/services/Templates/TemplateQueries.ts | 2 +- src/testingHelpers.tsx | 2 +- 27 files changed, 28 insertions(+), 29 deletions(-) diff --git a/package.json b/package.json index f312b7c6f..f228c6602 100644 --- a/package.json +++ b/package.json @@ -61,7 +61,6 @@ "react": "^18.3.1", "react-dom": "^18.3.1", "react-jss": "^10.10.0", - "react-query": "^3.39.3", "react-redux": "^9.1.2", "react-router-dom": "^6.30.3", "react18-json-view": "^0.2.8", diff --git a/src/AppEntry.tsx b/src/AppEntry.tsx index ea494427f..db8d2689a 100644 --- a/src/AppEntry.tsx +++ b/src/AppEntry.tsx @@ -1,5 +1,5 @@ import React, { useEffect } from 'react'; -import { QueryClient, QueryClientProvider } from 'react-query'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { Provider as ReduxProvider } from 'react-redux'; import * as Redux from 'redux'; diff --git a/src/Hooks/useHasRegisteredSystems.ts b/src/Hooks/useHasRegisteredSystems.ts index 4a55f5836..1906209d8 100644 --- a/src/Hooks/useHasRegisteredSystems.ts +++ b/src/Hooks/useHasRegisteredSystems.ts @@ -1,4 +1,4 @@ -import { useQueryClient } from 'react-query'; +import { useQueryClient } from '@tanstack/react-query'; import { useSystemsListQuery } from '../services/Systems/SystemsQueries'; import { TemplateItem } from '../services/Templates/TemplateApi'; import { FETCH_TEMPLATE_KEY } from '../services/Templates/TemplateQueries'; diff --git a/src/Hooks/usePageSafe.tsx b/src/Hooks/usePageSafe.tsx index 9f5094cd8..e24042219 100644 --- a/src/Hooks/usePageSafe.tsx +++ b/src/Hooks/usePageSafe.tsx @@ -1,4 +1,4 @@ -import { useIsFetching, useIsMutating } from 'react-query'; +import { useIsFetching, useIsMutating } from '@tanstack/react-query'; import useDebounce from './useDebounce'; function usePageSafe(): boolean { diff --git a/src/Pages/Repositories/ContentListTable/ContentListTable.tsx b/src/Pages/Repositories/ContentListTable/ContentListTable.tsx index 2bce5bd20..dad72beaf 100644 --- a/src/Pages/Repositories/ContentListTable/ContentListTable.tsx +++ b/src/Pages/Repositories/ContentListTable/ContentListTable.tsx @@ -44,7 +44,7 @@ import { BulkSelectValue, } from '@patternfly/react-component-groups/dist/dynamic/BulkSelect'; import flex from '@patternfly/react-styles/css/utilities/Flex/flex'; -import { useQueryClient } from 'react-query'; +import { useQueryClient } from '@tanstack/react-query'; import StatusIcon from './components/StatusIcon'; import spacing from '@patternfly/react-styles/css/utilities/Spacing/spacing'; import { SkeletonTableBody } from '@patternfly/react-component-groups'; diff --git a/src/Pages/Repositories/ContentListTable/components/AddContent/AddContent.tsx b/src/Pages/Repositories/ContentListTable/components/AddContent/AddContent.tsx index c9d1d3f5f..b04008776 100644 --- a/src/Pages/Repositories/ContentListTable/components/AddContent/AddContent.tsx +++ b/src/Pages/Repositories/ContentListTable/components/AddContent/AddContent.tsx @@ -51,7 +51,7 @@ import { useValidateContentList, } from 'services/Content/ContentQueries'; import { ContentOrigin, RepositoryParamsResponse } from 'services/Content/ContentApi'; -import { useQueryClient } from 'react-query'; +import { useQueryClient } from '@tanstack/react-query'; import ConditionalTooltip from 'components/ConditionalTooltip/ConditionalTooltip'; import { isEmpty, isEqual } from 'lodash'; import useDeepCompareEffect from 'Hooks/useDeepCompareEffect'; diff --git a/src/Pages/Repositories/ContentListTable/components/AddContent/helpers.ts b/src/Pages/Repositories/ContentListTable/components/AddContent/helpers.ts index 4dcc3e523..ef6c85130 100644 --- a/src/Pages/Repositories/ContentListTable/components/AddContent/helpers.ts +++ b/src/Pages/Repositories/ContentListTable/components/AddContent/helpers.ts @@ -102,7 +102,7 @@ export const mapFormikToAPIValues = ({ modularityFilteringEnabled, origin, }: FormikValues): EditContentRequestItem => - ({ + (({ uuid, name, url, @@ -112,8 +112,8 @@ export const mapFormikToAPIValues = ({ snapshot, metadata_verification: metadataVerification, module_hotfixes: !modularityFilteringEnabled, - origin, - }) as EditContentRequestItem; + origin + }) as EditContentRequestItem); const mapNoMetaDataError = (response: ValidationResponse): Partial => { if (isEmpty(response)) return {}; diff --git a/src/Pages/Repositories/ContentListTable/components/DeleteContentModal/DeleteContentModal.tsx b/src/Pages/Repositories/ContentListTable/components/DeleteContentModal/DeleteContentModal.tsx index 9b70f6c9c..3a74fa4ff 100644 --- a/src/Pages/Repositories/ContentListTable/components/DeleteContentModal/DeleteContentModal.tsx +++ b/src/Pages/Repositories/ContentListTable/components/DeleteContentModal/DeleteContentModal.tsx @@ -25,7 +25,7 @@ import { useBulkDeleteContentItemMutate, useContentListQuery, } from 'services/Content/ContentQueries'; -import { useQueryClient } from 'react-query'; +import { useQueryClient } from '@tanstack/react-query'; import { useHref, useLocation, useNavigate } from 'react-router-dom'; import { useContentListOutletContext } from '../../ContentListTable'; import useRootPath from 'Hooks/useRootPath'; diff --git a/src/Pages/Repositories/ContentListTable/components/SnapshotListModal/DeleteSnapshotsModal/DeleteSnapshotsModal.tsx b/src/Pages/Repositories/ContentListTable/components/SnapshotListModal/DeleteSnapshotsModal/DeleteSnapshotsModal.tsx index 882c39b79..690c90c91 100644 --- a/src/Pages/Repositories/ContentListTable/components/SnapshotListModal/DeleteSnapshotsModal/DeleteSnapshotsModal.tsx +++ b/src/Pages/Repositories/ContentListTable/components/SnapshotListModal/DeleteSnapshotsModal/DeleteSnapshotsModal.tsx @@ -21,7 +21,7 @@ import { Table, Tbody, Td, Th, Thead, Tr } from '@patternfly/react-table'; import { useEffect, useState } from 'react'; import { createUseStyles } from 'react-jss'; import Hide from 'components/Hide/Hide'; -import { useQueryClient } from 'react-query'; +import { useQueryClient } from '@tanstack/react-query'; import { useHref, useLocation, useNavigate, useParams } from 'react-router-dom'; import { useSnapshotListOutletContext } from '../SnapshotListModal'; import useRootPath from 'Hooks/useRootPath'; diff --git a/src/Pages/Repositories/ContentListTable/hooks/useContentListFilters.ts b/src/Pages/Repositories/ContentListTable/hooks/useContentListFilters.ts index bfba0123e..5c138feba 100644 --- a/src/Pages/Repositories/ContentListTable/hooks/useContentListFilters.ts +++ b/src/Pages/Repositories/ContentListTable/hooks/useContentListFilters.ts @@ -6,7 +6,7 @@ import { } from '../../../../services/Content/ContentApi'; import type { DataViewFilterOption } from '@patternfly/react-data-view/dist/cjs/DataViewFilters'; import { REPOSITORY_PARAMS_KEY } from '../../../../services/Content/ContentQueries'; -import { QueryClient } from 'react-query'; +import { QueryClient } from '@tanstack/react-query'; import useDebounce from '../../../../Hooks/useDebounce'; import { useDataViewFilters } from '@patternfly/react-data-view'; diff --git a/src/Pages/Repositories/PopularRepositoriesTable/PopularRepositoriesTable.tsx b/src/Pages/Repositories/PopularRepositoriesTable/PopularRepositoriesTable.tsx index fe4ac0d65..de2079fd5 100644 --- a/src/Pages/Repositories/PopularRepositoriesTable/PopularRepositoriesTable.tsx +++ b/src/Pages/Repositories/PopularRepositoriesTable/PopularRepositoriesTable.tsx @@ -36,7 +36,7 @@ import { PopularRepository, } from 'services/Content/ContentApi'; import Hide from 'components/Hide/Hide'; -import { useQueryClient } from 'react-query'; +import { useQueryClient } from '@tanstack/react-query'; import { useAppContext } from 'middleware/AppContext'; import ConditionalTooltip from 'components/ConditionalTooltip/ConditionalTooltip'; import UrlWithExternalIcon from 'components/UrlWithLinkIcon/UrlWithLinkIcon'; diff --git a/src/Pages/Templates/TemplateDetails/components/AssignTemplateModal/AddSystemModal.test.tsx b/src/Pages/Templates/TemplateDetails/components/AssignTemplateModal/AddSystemModal.test.tsx index 667d21ebb..1ed0d5f0d 100644 --- a/src/Pages/Templates/TemplateDetails/components/AssignTemplateModal/AddSystemModal.test.tsx +++ b/src/Pages/Templates/TemplateDetails/components/AssignTemplateModal/AddSystemModal.test.tsx @@ -1,6 +1,6 @@ import { render, waitFor, screen, within } from '@testing-library/react'; import AddSystemModal from './AddSystemModal'; -import { useQueryClient } from 'react-query'; +import { useQueryClient } from '@tanstack/react-query'; import { useSystemsListQuery } from 'services/Systems/SystemsQueries'; import { defaultSystemsListItem, diff --git a/src/Pages/Templates/TemplateDetails/components/AssignTemplateModal/AddSystemModal.tsx b/src/Pages/Templates/TemplateDetails/components/AssignTemplateModal/AddSystemModal.tsx index 6941c6e03..c64006c19 100644 --- a/src/Pages/Templates/TemplateDetails/components/AssignTemplateModal/AddSystemModal.tsx +++ b/src/Pages/Templates/TemplateDetails/components/AssignTemplateModal/AddSystemModal.tsx @@ -36,7 +36,7 @@ import { useSystemsListQuery, } from 'services/Systems/SystemsQueries'; import EmptyTableState from 'components/EmptyTableState/EmptyTableState'; -import { useQueryClient } from 'react-query'; +import { useQueryClient } from '@tanstack/react-query'; import type { TemplateItem } from 'services/Templates/TemplateApi'; import { FETCH_TEMPLATE_KEY, useFetchTemplate } from 'services/Templates/TemplateQueries'; import Loader from 'components/Loader'; diff --git a/src/Pages/Templates/TemplateDetails/components/AssignTemplateModal/AssignTemplateModal.tsx b/src/Pages/Templates/TemplateDetails/components/AssignTemplateModal/AssignTemplateModal.tsx index c897c7182..7958ca364 100644 --- a/src/Pages/Templates/TemplateDetails/components/AssignTemplateModal/AssignTemplateModal.tsx +++ b/src/Pages/Templates/TemplateDetails/components/AssignTemplateModal/AssignTemplateModal.tsx @@ -1,4 +1,4 @@ -import { useQueryClient } from 'react-query'; +import { useQueryClient } from '@tanstack/react-query'; import { useParams, useNavigate, useSearchParams } from 'react-router-dom'; import useRootPath from '../../../../../Hooks/useRootPath'; import React, { useState, useMemo, useEffect } from 'react'; diff --git a/src/Pages/Templates/TemplateDetails/components/AssignTemplateModal/SystemListView.tsx b/src/Pages/Templates/TemplateDetails/components/AssignTemplateModal/SystemListView.tsx index 88f5ae179..6c9ec8713 100644 --- a/src/Pages/Templates/TemplateDetails/components/AssignTemplateModal/SystemListView.tsx +++ b/src/Pages/Templates/TemplateDetails/components/AssignTemplateModal/SystemListView.tsx @@ -1,4 +1,4 @@ -import { useQueryClient } from 'react-query'; +import { useQueryClient } from '@tanstack/react-query'; import { useParams } from 'react-router-dom'; import React, { useState, useMemo, useEffect } from 'react'; import useDebounce from '../../../../../Hooks/useDebounce'; diff --git a/src/Pages/Templates/TemplateDetails/components/Tabs/TemplateSystemsTab.tsx b/src/Pages/Templates/TemplateDetails/components/Tabs/TemplateSystemsTab.tsx index 22665dd07..4b3535730 100644 --- a/src/Pages/Templates/TemplateDetails/components/Tabs/TemplateSystemsTab.tsx +++ b/src/Pages/Templates/TemplateDetails/components/Tabs/TemplateSystemsTab.tsx @@ -13,7 +13,7 @@ import { import { useEffect, useMemo, useState } from 'react'; import { createUseStyles } from 'react-jss'; import { Outlet, useNavigate } from 'react-router-dom'; -import { useQueryClient } from 'react-query'; +import { useQueryClient } from '@tanstack/react-query'; import { SortByDirection, type ThProps } from '@patternfly/react-table'; import Loader from 'components/Loader'; import { diff --git a/src/Pages/Templates/TemplatesTable/components/AddOrEditTemplate/AddTemplateContext.tsx b/src/Pages/Templates/TemplatesTable/components/AddOrEditTemplate/AddTemplateContext.tsx index 2ec7a1781..9264bfe59 100644 --- a/src/Pages/Templates/TemplatesTable/components/AddOrEditTemplate/AddTemplateContext.tsx +++ b/src/Pages/Templates/TemplatesTable/components/AddOrEditTemplate/AddTemplateContext.tsx @@ -8,7 +8,7 @@ import { useState, } from 'react'; import { TemplateRequest } from 'services/Templates/TemplateApi'; -import { QueryClient, useQueryClient } from 'react-query'; +import { QueryClient, useQueryClient } from '@tanstack/react-query'; import { useContentListQuery, useRepositoryParams } from 'services/Content/ContentQueries'; import { ContentOrigin, NameLabel } from 'services/Content/ContentApi'; import { hardcodeRedHatReposByArchAndVersion } from '../templateHelpers'; diff --git a/src/Pages/Templates/TemplatesTable/components/DeleteTemplateModal.tsx b/src/Pages/Templates/TemplatesTable/components/DeleteTemplateModal.tsx index 129f263e4..aa4ca2c67 100644 --- a/src/Pages/Templates/TemplatesTable/components/DeleteTemplateModal.tsx +++ b/src/Pages/Templates/TemplatesTable/components/DeleteTemplateModal.tsx @@ -13,7 +13,7 @@ import { import { createUseStyles } from 'react-jss'; import Hide from 'components/Hide/Hide'; -import { useQueryClient } from 'react-query'; +import { useQueryClient } from '@tanstack/react-query'; import { useNavigate } from 'react-router-dom'; import useRootPath from 'Hooks/useRootPath'; import { diff --git a/src/Pages/Templates/TemplatesTable/components/TemplateFilters.test.tsx b/src/Pages/Templates/TemplatesTable/components/TemplateFilters.test.tsx index 50b60e4e4..82cf6bc92 100644 --- a/src/Pages/Templates/TemplatesTable/components/TemplateFilters.test.tsx +++ b/src/Pages/Templates/TemplatesTable/components/TemplateFilters.test.tsx @@ -1,7 +1,7 @@ import { render } from '@testing-library/react'; import { testRepositoryParamsResponse } from 'testingHelpers'; import TemplateFilters from './TemplateFilters'; -import { useQueryClient } from 'react-query'; +import { useQueryClient } from '@tanstack/react-query'; import userEvent from '@testing-library/user-event'; jest.mock('middleware/AppContext', () => ({ diff --git a/src/Pages/Templates/TemplatesTable/components/TemplateFilters.tsx b/src/Pages/Templates/TemplatesTable/components/TemplateFilters.tsx index bd4eedaaa..3ac1e6966 100644 --- a/src/Pages/Templates/TemplatesTable/components/TemplateFilters.tsx +++ b/src/Pages/Templates/TemplatesTable/components/TemplateFilters.tsx @@ -17,7 +17,7 @@ import { import { FilterIcon, SearchIcon } from '@patternfly/react-icons'; import Hide from 'components/Hide/Hide'; import { RepositoryParamsResponse } from 'services/Content/ContentApi'; -import { useQueryClient } from 'react-query'; +import { useQueryClient } from '@tanstack/react-query'; import { REPOSITORY_PARAMS_KEY } from 'services/Content/ContentQueries'; import useDebounce from 'Hooks/useDebounce'; import { createUseStyles } from 'react-jss'; diff --git a/src/services/Admin/AdminQueries.ts b/src/services/Admin/AdminQueries.ts index 7008d07bb..51988c7c1 100644 --- a/src/services/Admin/AdminQueries.ts +++ b/src/services/Admin/AdminQueries.ts @@ -1,4 +1,4 @@ -import { useQuery } from 'react-query'; +import { useQuery } from '@tanstack/react-query'; import useErrorNotification from 'Hooks/useErrorNotification'; import { diff --git a/src/services/Admin/AdminTaskQueries.ts b/src/services/Admin/AdminTaskQueries.ts index 2f8c3164c..84ac100c0 100644 --- a/src/services/Admin/AdminTaskQueries.ts +++ b/src/services/Admin/AdminTaskQueries.ts @@ -1,4 +1,4 @@ -import { useQuery } from 'react-query'; +import { useQuery } from '@tanstack/react-query'; import { AdminTaskFilterData, AdminTaskListResponse, diff --git a/src/services/Content/ContentQueries.ts b/src/services/Content/ContentQueries.ts index 4f1ab201f..3c8426e01 100644 --- a/src/services/Content/ContentQueries.ts +++ b/src/services/Content/ContentQueries.ts @@ -1,6 +1,6 @@ import { AlertVariant } from '@patternfly/react-core'; import { useState } from 'react'; -import { QueryClient, useMutation, useQuery, useQueryClient } from 'react-query'; +import { QueryClient, useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { cloneDeep } from 'lodash'; import { diff --git a/src/services/Subscriptions/SubscriptionQueries.ts b/src/services/Subscriptions/SubscriptionQueries.ts index 2edeac372..0832d9cb3 100644 --- a/src/services/Subscriptions/SubscriptionQueries.ts +++ b/src/services/Subscriptions/SubscriptionQueries.ts @@ -2,7 +2,7 @@ import { Subscriptions, getSubscriptions, getEphemeralSubscriptions } from './Su import useErrorNotification from 'Hooks/useErrorNotification'; import useIsEphemeralEnv from 'Hooks/useIsEphemeralEnv'; import { useMemo } from 'react'; -import { useQuery } from 'react-query'; +import { useQuery } from '@tanstack/react-query'; const SUBSCRIPTION_CHECK_KEY = 'SUBSCRIPTION_CHECK_KEY'; diff --git a/src/services/Systems/SystemsQueries.ts b/src/services/Systems/SystemsQueries.ts index aef0f5f18..cbdedfa9c 100644 --- a/src/services/Systems/SystemsQueries.ts +++ b/src/services/Systems/SystemsQueries.ts @@ -10,7 +10,7 @@ import { TagsResponse, listTags, } from './SystemsApi'; -import { useMutation, useQuery, type QueryClient } from 'react-query'; +import { useMutation, useQuery, type QueryClient } from '@tanstack/react-query'; import useNotification from 'Hooks/useNotification'; import { AlertVariant } from '@patternfly/react-core'; diff --git a/src/services/Templates/TemplateQueries.ts b/src/services/Templates/TemplateQueries.ts index c1e20ae8b..c5c67c674 100644 --- a/src/services/Templates/TemplateQueries.ts +++ b/src/services/Templates/TemplateQueries.ts @@ -1,4 +1,4 @@ -import { QueryClient, useMutation, useQuery } from 'react-query'; +import { QueryClient, useMutation, useQuery } from '@tanstack/react-query'; import useErrorNotification from 'Hooks/useErrorNotification'; import { diff --git a/src/testingHelpers.tsx b/src/testingHelpers.tsx index 6bd50c428..c4fbcea7e 100644 --- a/src/testingHelpers.tsx +++ b/src/testingHelpers.tsx @@ -1,4 +1,4 @@ -import { QueryClient, QueryClientProvider } from 'react-query'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { ContentItem, Links, From c7ee5fc5f322d93d670e9794c8f5cee919f8c5db Mon Sep 17 00:00:00 2001 From: Dominik Vagner Date: Wed, 21 Jan 2026 16:14:09 +0100 Subject: [PATCH 3/6] chore: react-query migration, query keys and tests --- .../components/AdminTaskFilters.test.tsx | 2 +- .../components/AddContent/AddContent.tsx | 2 +- .../DeleteContentModal/DeleteContent.test.tsx | 4 +- .../DeleteContentModal/DeleteContentModal.tsx | 4 +- .../DeleteSnapshotsModal.test.tsx | 4 +- .../hooks/useContentListFilters.ts | 2 +- .../AddSystemModal.test.tsx | 2 +- .../AssignTemplateModal/AddSystemModal.tsx | 2 +- .../AssignTemplateModal/SystemListView.tsx | 2 +- .../Tabs/TemplateErrataTab.test.tsx | 2 +- .../Tabs/TemplatePackageTab.test.tsx | 2 +- .../Tabs/TemplateRepositoriesTab.test.tsx | 2 +- .../Tabs/TemplateSystemsTab.test.tsx | 2 +- .../steps/CustomRepositoriesStep.tsx | 2 +- .../components/DeleteTemplateModal.test.tsx | 4 +- .../components/DeleteTemplateModal.tsx | 4 +- .../components/TemplateFilters.test.tsx | 2 +- .../components/TemplateFilters.tsx | 2 +- src/services/Content/ContentQueries.ts | 116 +++++++++--------- src/services/Systems/SystemsQueries.ts | 10 +- src/services/Templates/TemplateQueries.ts | 20 +-- yarn.lock | 91 ++------------ 22 files changed, 106 insertions(+), 177 deletions(-) diff --git a/src/Pages/Repositories/AdminTaskTable/components/AdminTaskFilters.test.tsx b/src/Pages/Repositories/AdminTaskTable/components/AdminTaskFilters.test.tsx index d7be9d5ea..b4835edc0 100644 --- a/src/Pages/Repositories/AdminTaskTable/components/AdminTaskFilters.test.tsx +++ b/src/Pages/Repositories/AdminTaskTable/components/AdminTaskFilters.test.tsx @@ -6,7 +6,7 @@ jest.mock('middleware/AppContext', () => ({ useAppContext: () => ({}), })); -jest.mock('react-query'); +jest.mock('@tanstack/react-query'); it('Render loading state (disabled)', () => { const { getByRole } = render( diff --git a/src/Pages/Repositories/ContentListTable/components/AddContent/AddContent.tsx b/src/Pages/Repositories/ContentListTable/components/AddContent/AddContent.tsx index b04008776..172936cac 100644 --- a/src/Pages/Repositories/ContentListTable/components/AddContent/AddContent.tsx +++ b/src/Pages/Repositories/ContentListTable/components/AddContent/AddContent.tsx @@ -141,7 +141,7 @@ const AddContent = ({ isEdit = false }: Props) => { const { fetchGpgKey, isLoading: isFetchingGpgKey } = useFetchGpgKey(); const { distribution_arches: distArches = [], distribution_versions: distVersions = [] } = - queryClient.getQueryData(REPOSITORY_PARAMS_KEY) || {}; + queryClient.getQueryData([REPOSITORY_PARAMS_KEY]) || {}; const { distributionArches, distributionVersions } = useMemo(() => { const distributionArches = {}; diff --git a/src/Pages/Repositories/ContentListTable/components/DeleteContentModal/DeleteContent.test.tsx b/src/Pages/Repositories/ContentListTable/components/DeleteContentModal/DeleteContent.test.tsx index 0194c20f3..4c28ffbad 100644 --- a/src/Pages/Repositories/ContentListTable/components/DeleteContentModal/DeleteContent.test.tsx +++ b/src/Pages/Repositories/ContentListTable/components/DeleteContentModal/DeleteContent.test.tsx @@ -11,8 +11,8 @@ import { ContentOrigin } from 'services/Content/ContentApi'; import { DELETE_ROUTE } from 'Routes/constants'; import { useTemplateList } from 'services/Templates/TemplateQueries'; -jest.mock('react-query', () => ({ - ...jest.requireActual('react-query'), +jest.mock('@tanstack/react-query', () => ({ + ...jest.requireActual('@tanstack/react-query'), useQueryClient: jest.fn(), })); diff --git a/src/Pages/Repositories/ContentListTable/components/DeleteContentModal/DeleteContentModal.tsx b/src/Pages/Repositories/ContentListTable/components/DeleteContentModal/DeleteContentModal.tsx index 3a74fa4ff..d3e19c5b7 100644 --- a/src/Pages/Repositories/ContentListTable/components/DeleteContentModal/DeleteContentModal.tsx +++ b/src/Pages/Repositories/ContentListTable/components/DeleteContentModal/DeleteContentModal.tsx @@ -120,8 +120,8 @@ export default function DeleteContentModal() { deleteItems(reposToDelete).then(() => { onClose(); clearCheckedRepositories(); - queryClient.invalidateQueries(CONTENT_LIST_KEY); - queryClient.invalidateQueries(GET_TEMPLATES_KEY); + queryClient.invalidateQueries({ queryKey: [CONTENT_LIST_KEY] }); + queryClient.invalidateQueries({ queryKey: [GET_TEMPLATES_KEY] }); }); }; diff --git a/src/Pages/Repositories/ContentListTable/components/SnapshotListModal/DeleteSnapshotsModal/DeleteSnapshotsModal.test.tsx b/src/Pages/Repositories/ContentListTable/components/SnapshotListModal/DeleteSnapshotsModal/DeleteSnapshotsModal.test.tsx index c8f7154b6..6d536e6d2 100644 --- a/src/Pages/Repositories/ContentListTable/components/SnapshotListModal/DeleteSnapshotsModal/DeleteSnapshotsModal.test.tsx +++ b/src/Pages/Repositories/ContentListTable/components/SnapshotListModal/DeleteSnapshotsModal/DeleteSnapshotsModal.test.tsx @@ -12,8 +12,8 @@ import { useGetSnapshotList } from 'services/Content/ContentQueries'; import { useFetchTemplatesForSnapshots } from 'services/Templates/TemplateQueries'; import { formatDateDDMMMYYYY } from 'helpers'; -jest.mock('react-query', () => ({ - ...jest.requireActual('react-query'), +jest.mock('@tanstack/react-query', () => ({ + ...jest.requireActual('@tanstack/react-query'), useQueryClient: jest.fn(), })); diff --git a/src/Pages/Repositories/ContentListTable/hooks/useContentListFilters.ts b/src/Pages/Repositories/ContentListTable/hooks/useContentListFilters.ts index 5c138feba..099dadc24 100644 --- a/src/Pages/Repositories/ContentListTable/hooks/useContentListFilters.ts +++ b/src/Pages/Repositories/ContentListTable/hooks/useContentListFilters.ts @@ -49,7 +49,7 @@ export const useContentListFilters = (queryClient: QueryClient) => { }); const { distribution_arches = [], distribution_versions = [] } = - queryClient.getQueryData(REPOSITORY_PARAMS_KEY) || {}; + queryClient.getQueryData([REPOSITORY_PARAMS_KEY]) || {}; // Create filter options for the UI const osFilterOptions: DataViewFilterOption[] = useMemo( diff --git a/src/Pages/Templates/TemplateDetails/components/AssignTemplateModal/AddSystemModal.test.tsx b/src/Pages/Templates/TemplateDetails/components/AssignTemplateModal/AddSystemModal.test.tsx index 1ed0d5f0d..034049af1 100644 --- a/src/Pages/Templates/TemplateDetails/components/AssignTemplateModal/AddSystemModal.test.tsx +++ b/src/Pages/Templates/TemplateDetails/components/AssignTemplateModal/AddSystemModal.test.tsx @@ -19,7 +19,7 @@ jest.mock('react-router-dom', () => ({ jest.mock('Hooks/useRootPath', () => () => 'someUrl'); -jest.mock('react-query'); +jest.mock('@tanstack/react-query'); beforeAll(() => { (useQueryClient as jest.Mock).mockImplementation(() => ({ diff --git a/src/Pages/Templates/TemplateDetails/components/AssignTemplateModal/AddSystemModal.tsx b/src/Pages/Templates/TemplateDetails/components/AssignTemplateModal/AddSystemModal.tsx index c64006c19..71c84962b 100644 --- a/src/Pages/Templates/TemplateDetails/components/AssignTemplateModal/AddSystemModal.tsx +++ b/src/Pages/Templates/TemplateDetails/components/AssignTemplateModal/AddSystemModal.tsx @@ -320,7 +320,7 @@ export default function AddSystemModal() { className={classes.refreshSystemsList} icon={isFetching ? : } isDisabled={isLoading || isFetching} - onClick={() => queryClient.invalidateQueries(GET_SYSTEMS_KEY)} + onClick={() => queryClient.invalidateQueries({ queryKey: [GET_SYSTEMS_KEY] })} > Refresh systems list diff --git a/src/Pages/Templates/TemplateDetails/components/AssignTemplateModal/SystemListView.tsx b/src/Pages/Templates/TemplateDetails/components/AssignTemplateModal/SystemListView.tsx index 6c9ec8713..7287f5afb 100644 --- a/src/Pages/Templates/TemplateDetails/components/AssignTemplateModal/SystemListView.tsx +++ b/src/Pages/Templates/TemplateDetails/components/AssignTemplateModal/SystemListView.tsx @@ -250,7 +250,7 @@ const SystemListView = ({ variant='link' icon={isFetching ? : } isDisabled={isLoading || isFetching} - onClick={() => queryClient.invalidateQueries(GET_SYSTEMS_KEY)} + onClick={() => queryClient.invalidateQueries({ queryKey: [GET_SYSTEMS_KEY] })} className={spacing.py_0} > Refresh diff --git a/src/Pages/Templates/TemplateDetails/components/Tabs/TemplateErrataTab.test.tsx b/src/Pages/Templates/TemplateDetails/components/Tabs/TemplateErrataTab.test.tsx index 9868892b7..7eff78b69 100644 --- a/src/Pages/Templates/TemplateDetails/components/Tabs/TemplateErrataTab.test.tsx +++ b/src/Pages/Templates/TemplateDetails/components/Tabs/TemplateErrataTab.test.tsx @@ -21,7 +21,7 @@ jest.mock('dayjs', () => (value) => ({ jest.mock('Hooks/useRootPath', () => () => 'someUrl'); -jest.mock('react-query'); +jest.mock('@tanstack/react-query'); jest.mock('services/Templates/TemplateQueries', () => ({ useFetchTemplateErrataQuery: jest.fn(), diff --git a/src/Pages/Templates/TemplateDetails/components/Tabs/TemplatePackageTab.test.tsx b/src/Pages/Templates/TemplateDetails/components/Tabs/TemplatePackageTab.test.tsx index 2ad1d95a1..9f170ce8c 100644 --- a/src/Pages/Templates/TemplateDetails/components/Tabs/TemplatePackageTab.test.tsx +++ b/src/Pages/Templates/TemplateDetails/components/Tabs/TemplatePackageTab.test.tsx @@ -17,7 +17,7 @@ jest.mock('dayjs', () => (value) => ({ fromNow: () => value })); jest.mock('Hooks/useRootPath', () => () => 'someUrl'); -jest.mock('react-query'); +jest.mock('@tanstack/react-query'); jest.mock('services/Templates/TemplateQueries', () => ({ useFetchTemplatePackages: jest.fn(), diff --git a/src/Pages/Templates/TemplateDetails/components/Tabs/TemplateRepositoriesTab.test.tsx b/src/Pages/Templates/TemplateDetails/components/Tabs/TemplateRepositoriesTab.test.tsx index 182cefbb5..17495a5a6 100644 --- a/src/Pages/Templates/TemplateDetails/components/Tabs/TemplateRepositoriesTab.test.tsx +++ b/src/Pages/Templates/TemplateDetails/components/Tabs/TemplateRepositoriesTab.test.tsx @@ -22,7 +22,7 @@ jest.mock('dayjs', () => (value) => ({ jest.mock('Hooks/useRootPath', () => () => 'someUrl'); -jest.mock('react-query'); +jest.mock('@tanstack/react-query'); jest.mock('services/Templates/TemplateQueries', () => ({ useFetchTemplateSnapshotsQuery: jest.fn(), diff --git a/src/Pages/Templates/TemplateDetails/components/Tabs/TemplateSystemsTab.test.tsx b/src/Pages/Templates/TemplateDetails/components/Tabs/TemplateSystemsTab.test.tsx index c8b480e0c..071428539 100644 --- a/src/Pages/Templates/TemplateDetails/components/Tabs/TemplateSystemsTab.test.tsx +++ b/src/Pages/Templates/TemplateDetails/components/Tabs/TemplateSystemsTab.test.tsx @@ -24,7 +24,7 @@ jest.mock('Hooks/useSafeUUIDParam', () => () => templateUUID); jest.mock('Hooks/useHasRegisteredSystems'); -jest.mock('react-query'); +jest.mock('@tanstack/react-query'); jest.mock('services/Systems/SystemsQueries', () => ({ useListSystemsByTemplateId: jest.fn(), diff --git a/src/Pages/Templates/TemplatesTable/components/AddOrEditTemplate/steps/CustomRepositoriesStep.tsx b/src/Pages/Templates/TemplatesTable/components/AddOrEditTemplate/steps/CustomRepositoriesStep.tsx index a7d9c4bee..29d251e25 100644 --- a/src/Pages/Templates/TemplatesTable/components/AddOrEditTemplate/steps/CustomRepositoriesStep.tsx +++ b/src/Pages/Templates/TemplatesTable/components/AddOrEditTemplate/steps/CustomRepositoriesStep.tsx @@ -162,7 +162,7 @@ export default function CustomRepositoriesStep() { icon={isLoading || isFetching ? undefined : } isLoading={isLoading || isFetching} isDisabled={isLoading || isFetching} - onClick={() => queryClient.invalidateQueries(CONTENT_LIST_KEY)} + onClick={() => queryClient.invalidateQueries({ queryKey: [CONTENT_LIST_KEY] })} > Refresh repository list diff --git a/src/Pages/Templates/TemplatesTable/components/DeleteTemplateModal.test.tsx b/src/Pages/Templates/TemplatesTable/components/DeleteTemplateModal.test.tsx index 35f329bbf..6543dc671 100644 --- a/src/Pages/Templates/TemplatesTable/components/DeleteTemplateModal.test.tsx +++ b/src/Pages/Templates/TemplatesTable/components/DeleteTemplateModal.test.tsx @@ -6,8 +6,8 @@ import { useListSystemsByTemplateId } from 'services/Systems/SystemsQueries'; import { useFetchTemplate } from 'services/Templates/TemplateQueries'; import { DETAILS_ROUTE } from 'Routes/constants'; -jest.mock('react-query', () => ({ - ...jest.requireActual('react-query'), +jest.mock('@tanstack/react-query', () => ({ + ...jest.requireActual('@tanstack/react-query'), useQueryClient: jest.fn(() => ({ invalidateQueries: jest.fn(), })), diff --git a/src/Pages/Templates/TemplatesTable/components/DeleteTemplateModal.tsx b/src/Pages/Templates/TemplatesTable/components/DeleteTemplateModal.tsx index aa4ca2c67..de2084a59 100644 --- a/src/Pages/Templates/TemplatesTable/components/DeleteTemplateModal.tsx +++ b/src/Pages/Templates/TemplatesTable/components/DeleteTemplateModal.tsx @@ -64,13 +64,13 @@ export default function DeleteTemplateModal() { const onSave = async () => { deleteTemplate(uuid).then(() => { - queryClient.invalidateQueries(GET_TEMPLATES_KEY); + queryClient.invalidateQueries({ queryKey: [GET_TEMPLATES_KEY] }); onClose(); }); }; useEffect(() => { - queryClient.invalidateQueries(GET_TEMPLATE_SYSTEMS_KEY); + queryClient.invalidateQueries({ queryKey: [GET_TEMPLATE_SYSTEMS_KEY] }); }, []); const { diff --git a/src/Pages/Templates/TemplatesTable/components/TemplateFilters.test.tsx b/src/Pages/Templates/TemplatesTable/components/TemplateFilters.test.tsx index 82cf6bc92..e5fb18018 100644 --- a/src/Pages/Templates/TemplatesTable/components/TemplateFilters.test.tsx +++ b/src/Pages/Templates/TemplatesTable/components/TemplateFilters.test.tsx @@ -12,7 +12,7 @@ jest.mock('react-router-dom', () => ({ useNavigate: jest.fn(), })); -jest.mock('react-query'); +jest.mock('@tanstack/react-query'); beforeAll(() => { (useQueryClient as jest.Mock).mockImplementation(() => ({ diff --git a/src/Pages/Templates/TemplatesTable/components/TemplateFilters.tsx b/src/Pages/Templates/TemplatesTable/components/TemplateFilters.tsx index 3ac1e6966..3ad32368a 100644 --- a/src/Pages/Templates/TemplatesTable/components/TemplateFilters.tsx +++ b/src/Pages/Templates/TemplatesTable/components/TemplateFilters.tsx @@ -65,7 +65,7 @@ const Filters = ({ isLoading, setFilterData, filterData }: Props) => { const [selectedArch, setSelectedArch] = useState(''); const { distribution_arches = [], distribution_versions = [] } = - queryClient.getQueryData(REPOSITORY_PARAMS_KEY) || {}; + queryClient.getQueryData([REPOSITORY_PARAMS_KEY]) || {}; const hasRHELSubscription = !!subscriptions?.red_hat_enterprise_linux; const isMissingRequirements = !rbac?.templateWrite || !hasRHELSubscription; diff --git a/src/services/Content/ContentQueries.ts b/src/services/Content/ContentQueries.ts index 3c8426e01..a7f19e9bc 100644 --- a/src/services/Content/ContentQueries.ts +++ b/src/services/Content/ContentQueries.ts @@ -180,9 +180,9 @@ export const useAddContentQuery = (request: CreateContentRequest) => { }), }); - queryClient.invalidateQueries(CONTENT_LIST_KEY); - queryClient.invalidateQueries(ADMIN_TASK_LIST_KEY); - queryClient.invalidateQueries(POPULAR_REPOSITORIES_LIST_KEY); + queryClient.invalidateQueries({ queryKey: [CONTENT_LIST_KEY] }); + queryClient.invalidateQueries({ queryKey: [ADMIN_TASK_LIST_KEY] }); + queryClient.invalidateQueries({ queryKey: [POPULAR_REPOSITORIES_LIST_KEY] }); }, // eslint-disable-next-line @typescript-eslint/no-explicit-any onError: (err: any) => { @@ -212,8 +212,8 @@ export const useAddUploadsQuery = (request: AddUploadRequest) => { description: 'This repository will be snapshotted shortly', }); - queryClient.invalidateQueries(CONTENT_LIST_KEY); - queryClient.invalidateQueries(ADMIN_TASK_LIST_KEY); + queryClient.invalidateQueries({ queryKey: [CONTENT_LIST_KEY] }); + queryClient.invalidateQueries({ queryKey: [ADMIN_TASK_LIST_KEY] }); }, // eslint-disable-next-line @typescript-eslint/no-explicit-any onError: (err: any) => { @@ -274,9 +274,9 @@ export const useAddPopularRepositoryQuery = ( : 'Repository introspection data already available', }); - queryClient.invalidateQueries(CONTENT_LIST_KEY); - queryClient.invalidateQueries(ADMIN_TASK_LIST_KEY); - queryClient.invalidateQueries(POPULAR_REPOSITORIES_LIST_KEY); + queryClient.invalidateQueries({ queryKey: [CONTENT_LIST_KEY] }); + queryClient.invalidateQueries({ queryKey: [ADMIN_TASK_LIST_KEY] }); + queryClient.invalidateQueries({ queryKey: [POPULAR_REPOSITORIES_LIST_KEY] }); }, onError: (err, _newData, context) => { if (context) { @@ -306,11 +306,11 @@ export const useEditContentQuery = (request: EditContentRequestItem) => { title: `Successfully edited repository ${request.name}`, }); - queryClient.invalidateQueries(CONTENT_LIST_KEY); - queryClient.invalidateQueries(CONTENT_ITEM_KEY); - queryClient.invalidateQueries(LIST_SNAPSHOTS_KEY); - queryClient.invalidateQueries(ADMIN_TASK_LIST_KEY); - queryClient.invalidateQueries(POPULAR_REPOSITORIES_LIST_KEY); + queryClient.invalidateQueries({ queryKey: [CONTENT_LIST_KEY] }); + queryClient.invalidateQueries({ queryKey: [CONTENT_ITEM_KEY] }); + queryClient.invalidateQueries({ queryKey: [LIST_SNAPSHOTS_KEY] }); + queryClient.invalidateQueries({ queryKey: [ADMIN_TASK_LIST_KEY] }); + queryClient.invalidateQueries({ queryKey: [POPULAR_REPOSITORIES_LIST_KEY] }); }, // eslint-disable-next-line @typescript-eslint/no-explicit-any onError: (err: any) => { @@ -373,9 +373,9 @@ export const useDeletePopularRepositoryMutate = ( return { previousData: previousPopularData, queryClient }; }, onSuccess: () => { - queryClient.invalidateQueries(CONTENT_LIST_KEY); - queryClient.invalidateQueries(ADMIN_TASK_LIST_KEY); - queryClient.invalidateQueries(POPULAR_REPOSITORIES_LIST_KEY); + queryClient.invalidateQueries({ queryKey: [CONTENT_LIST_KEY] }); + queryClient.invalidateQueries({ queryKey: [ADMIN_TASK_LIST_KEY] }); + queryClient.invalidateQueries({ queryKey: [POPULAR_REPOSITORIES_LIST_KEY] }); }, // If the mutation fails, use the context returned from onMutate to roll back // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -437,16 +437,16 @@ export const useDeleteContentItemMutate = ( const { previousData } = context as { previousData: ContentListResponse; }; - queryClient.setQueriesData(CONTENT_LIST_KEY, (data: Partial = {}) => { + queryClient.setQueriesData([CONTENT_LIST_KEY], (data: Partial = {}) => { if (data?.meta?.count) { data.meta.count = previousData?.meta?.count - 1; } return data; }); - queryClient.invalidateQueries(CONTENT_LIST_KEY); - queryClient.invalidateQueries(ADMIN_TASK_LIST_KEY); - queryClient.invalidateQueries(POPULAR_REPOSITORIES_LIST_KEY); + queryClient.invalidateQueries({ queryKey: [CONTENT_LIST_KEY] }); + queryClient.invalidateQueries({ queryKey: [ADMIN_TASK_LIST_KEY] }); + queryClient.invalidateQueries({ queryKey: [POPULAR_REPOSITORIES_LIST_KEY] }); }, // If the mutation fails, use the context returned from onMutate to roll back // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -518,15 +518,18 @@ export const useBulkDeleteContentItemMutate = ( const { newMeta } = context as { newMeta: Meta; }; - queryClient.setQueriesData(CONTENT_LIST_KEY, (data: Partial = {}) => { - if (data?.meta?.count) { - data.meta.count = newMeta?.count; - } - return data; - }); - queryClient.invalidateQueries(CONTENT_LIST_KEY); - queryClient.invalidateQueries(ADMIN_TASK_LIST_KEY); - queryClient.invalidateQueries(POPULAR_REPOSITORIES_LIST_KEY); + queryClient.setQueriesData( + [CONTENT_LIST_KEY], + (data: Partial = {}) => { + if (data?.meta?.count) { + data.meta.count = newMeta?.count; + } + return data; + }, + ); + queryClient.invalidateQueries({ queryKey: [CONTENT_LIST_KEY] }); + queryClient.invalidateQueries({ queryKey: [ADMIN_TASK_LIST_KEY] }); + queryClient.invalidateQueries({ queryKey: [POPULAR_REPOSITORIES_LIST_KEY] }); }, // If the mutation fails, use the context returned from onMutate to roll back onError: (err: { response?: { data: ErrorResponse } }, _newData, context) => { @@ -562,7 +565,7 @@ export const useGetSnapshotsByDates = (uuids: string[], date: string) => { }; export const useRepositoryParams = () => - useQuery(REPOSITORY_PARAMS_KEY, getRepositoryParams, { + useQuery([REPOSITORY_PARAMS_KEY], getRepositoryParams, { keepPreviousData: true, staleTime: Infinity, }); @@ -600,7 +603,6 @@ export const useGetSnapshotList = (uuid: string, page: number, limit: number, so () => getSnapshotList(uuid, page, limit, sortBy), { keepPreviousData: true, - optimisticResults: true, staleTime: 60000, // eslint-disable-next-line @typescript-eslint/no-explicit-any onError: (err: any) => { @@ -628,7 +630,6 @@ export const useGetPackagesQuery = ( () => getPackages(uuid, page, limit, searchQuery, sortBy), { keepPreviousData: true, - optimisticResults: true, staleTime: 60000, // eslint-disable-next-line @typescript-eslint/no-explicit-any onError: (err: any) => { @@ -655,7 +656,6 @@ export const useGetSnapshotPackagesQuery = ( () => getSnapshotPackages(snap_uuid, page, limit, searchQuery), { keepPreviousData: true, - optimisticResults: true, staleTime: 60000, // eslint-disable-next-line @typescript-eslint/no-explicit-any onError: (err: any) => { @@ -685,7 +685,6 @@ export const useGetSnapshotErrataQuery = ( () => getSnapshotErrata(snap_uuid, page, limit, search, type, severity, sortBy), { keepPreviousData: true, - optimisticResults: true, staleTime: 60000, // eslint-disable-next-line @typescript-eslint/no-explicit-any onError: (err: any) => { @@ -709,8 +708,8 @@ export const useTriggerSnapshot = (queryClient: QueryClient) => { variant: AlertVariant.success, title: 'Snapshot triggered successfully', }); - queryClient.invalidateQueries(LIST_SNAPSHOTS_KEY); - queryClient.invalidateQueries(CONTENT_LIST_KEY); + queryClient.invalidateQueries({ queryKey: [LIST_SNAPSHOTS_KEY] }); + queryClient.invalidateQueries({ queryKey: [CONTENT_LIST_KEY] }); }, onError: (err) => { errorNotifier( @@ -771,9 +770,9 @@ export const useIntrospectRepositoryMutate = ( title: 'Repository introspection in progress', }); } - queryClient.invalidateQueries(CONTENT_ITEM_KEY); - queryClient.invalidateQueries(LIST_SNAPSHOTS_KEY); - queryClient.invalidateQueries(ADMIN_TASK_LIST_KEY); + queryClient.invalidateQueries({ queryKey: [CONTENT_ITEM_KEY] }); + queryClient.invalidateQueries({ queryKey: [LIST_SNAPSHOTS_KEY] }); + queryClient.invalidateQueries({ queryKey: [ADMIN_TASK_LIST_KEY] }); }, // If the mutation fails, use the context returned from onMutate to roll back // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -865,24 +864,27 @@ export const useBulkDeleteSnapshotsMutate = ( const { newMeta } = context as { newMeta: Meta; }; - queryClient.setQueriesData(LIST_SNAPSHOTS_KEY, (data: Partial = {}) => { - if (data?.meta?.count) { - data.meta.count = newMeta?.count; - } - return data; - }); - queryClient.invalidateQueries(CONTENT_LIST_KEY); - queryClient.invalidateQueries(GET_TEMPLATES_KEY); - queryClient.invalidateQueries(ADMIN_TASK_LIST_KEY); - queryClient.invalidateQueries(TEMPLATE_SNAPSHOTS_KEY); - queryClient.invalidateQueries(TEMPLATES_FOR_SNAPSHOTS); - queryClient.invalidateQueries(TEMPLATE_ERRATA_KEY); - queryClient.invalidateQueries(GET_TEMPLATE_PACKAGES_KEY); - queryClient.invalidateQueries(LIST_SNAPSHOTS_KEY); - queryClient.invalidateQueries(SNAPSHOT_ERRATA_KEY); - queryClient.invalidateQueries(SNAPSHOT_PACKAGES_KEY); - queryClient.invalidateQueries(REPO_CONFIG_FILE_KEY); - queryClient.invalidateQueries(LATEST_REPO_CONFIG_FILE_KEY); + queryClient.setQueriesData( + [LIST_SNAPSHOTS_KEY], + (data: Partial = {}) => { + if (data?.meta?.count) { + data.meta.count = newMeta?.count; + } + return data; + }, + ); + queryClient.invalidateQueries({ queryKey: [CONTENT_LIST_KEY] }); + queryClient.invalidateQueries({ queryKey: [GET_TEMPLATES_KEY] }); + queryClient.invalidateQueries({ queryKey: [ADMIN_TASK_LIST_KEY] }); + queryClient.invalidateQueries({ queryKey: [TEMPLATE_SNAPSHOTS_KEY] }); + queryClient.invalidateQueries({ queryKey: [TEMPLATES_FOR_SNAPSHOTS] }); + queryClient.invalidateQueries({ queryKey: [TEMPLATE_ERRATA_KEY] }); + queryClient.invalidateQueries({ queryKey: [GET_TEMPLATE_PACKAGES_KEY] }); + queryClient.invalidateQueries({ queryKey: [LIST_SNAPSHOTS_KEY] }); + queryClient.invalidateQueries({ queryKey: [SNAPSHOT_ERRATA_KEY] }); + queryClient.invalidateQueries({ queryKey: [SNAPSHOT_PACKAGES_KEY] }); + queryClient.invalidateQueries({ queryKey: [REPO_CONFIG_FILE_KEY] }); + queryClient.invalidateQueries({ queryKey: [LATEST_REPO_CONFIG_FILE_KEY] }); }, onError: (err: { response?: { data: ErrorResponse } }, _newData, context) => { if (context) { diff --git a/src/services/Systems/SystemsQueries.ts b/src/services/Systems/SystemsQueries.ts index cbdedfa9c..e407d52d0 100644 --- a/src/services/Systems/SystemsQueries.ts +++ b/src/services/Systems/SystemsQueries.ts @@ -30,7 +30,6 @@ export const useSystemsListQuery = ( () => getSystemsList(page, limit, searchQuery, filter, sortBy), { keepPreviousData: true, - optimisticResults: true, staleTime: 60000, // eslint-disable-next-line @typescript-eslint/no-explicit-any onError: (err: any) => { @@ -68,7 +67,6 @@ export const useListSystemsByTemplateId = ( () => listSystemsByTemplateId(id, page, limit, searchQuery, sortBy), { keepPreviousData: true, - optimisticResults: true, staleTime: 25_000, refetchOnWindowFocus: 'always', refetchOnMount: 'always', @@ -100,8 +98,8 @@ export const useAddTemplateToSystemsQuery = ( title: `Template successfully added to ${systemUUIDs.length} system${systemUUIDs.length > 1 ? 's' : ''}`, }); - queryClient.invalidateQueries(GET_TEMPLATE_SYSTEMS_KEY); - queryClient.invalidateQueries(GET_SYSTEMS_KEY); + queryClient.invalidateQueries({ queryKey: [GET_TEMPLATE_SYSTEMS_KEY] }); + queryClient.invalidateQueries({ queryKey: [GET_SYSTEMS_KEY] }); }, // eslint-disable-next-line @typescript-eslint/no-explicit-any onError: (err: any) => { @@ -119,8 +117,8 @@ export const useDeleteTemplateFromSystems = (queryClient: QueryClient) => { const errorNotifier = useErrorNotification(); return useMutation(deleteTemplateFromSystems, { onSuccess: () => { - queryClient.invalidateQueries(GET_SYSTEMS_KEY); - queryClient.invalidateQueries(GET_TEMPLATE_SYSTEMS_KEY); + queryClient.invalidateQueries({ queryKey: [GET_SYSTEMS_KEY] }); + queryClient.invalidateQueries({ queryKey: [GET_TEMPLATE_SYSTEMS_KEY] }); }, // eslint-disable-next-line @typescript-eslint/no-explicit-any onError: (err: any) => { diff --git a/src/services/Templates/TemplateQueries.ts b/src/services/Templates/TemplateQueries.ts index c5c67c674..7c49d641b 100644 --- a/src/services/Templates/TemplateQueries.ts +++ b/src/services/Templates/TemplateQueries.ts @@ -42,12 +42,12 @@ export const useEditTemplateQuery = (queryClient: QueryClient, request: EditTemp title: `Successfully edited template '${request.name}'`, }); - queryClient.invalidateQueries(GET_TEMPLATES_KEY); - queryClient.invalidateQueries(FETCH_TEMPLATE_KEY); - queryClient.invalidateQueries(GET_TEMPLATE_PACKAGES_KEY); - queryClient.invalidateQueries(TEMPLATE_ERRATA_KEY); - queryClient.invalidateQueries(TEMPLATES_FOR_SNAPSHOTS); - queryClient.invalidateQueries(TEMPLATE_SNAPSHOTS_KEY); + queryClient.invalidateQueries({ queryKey: [GET_TEMPLATES_KEY] }); + queryClient.invalidateQueries({ queryKey: [FETCH_TEMPLATE_KEY] }); + queryClient.invalidateQueries({ queryKey: [GET_TEMPLATE_PACKAGES_KEY] }); + queryClient.invalidateQueries({ queryKey: [TEMPLATE_ERRATA_KEY] }); + queryClient.invalidateQueries({ queryKey: [TEMPLATES_FOR_SNAPSHOTS] }); + queryClient.invalidateQueries({ queryKey: [TEMPLATE_SNAPSHOTS_KEY] }); }, // eslint-disable-next-line @typescript-eslint/no-explicit-any onError: (err: any) => { @@ -221,8 +221,8 @@ export const useCreateTemplateQuery = (queryClient: QueryClient, request: Templa title: `Content Template "${request?.name}" created`, }); - queryClient.invalidateQueries(GET_TEMPLATES_KEY); - queryClient.invalidateQueries(FETCH_TEMPLATE_KEY); + queryClient.invalidateQueries({ queryKey: [GET_TEMPLATES_KEY] }); + queryClient.invalidateQueries({ queryKey: [FETCH_TEMPLATE_KEY] }); }, // eslint-disable-next-line @typescript-eslint/no-explicit-any onError: (err: any) => { @@ -268,7 +268,7 @@ export const useDeleteTemplateItemMutate = (queryClient: QueryClient) => { previousData: TemplateCollectionResponse; }; queryClient.setQueriesData( - GET_TEMPLATES_KEY, + [GET_TEMPLATES_KEY], (data: Partial = {}) => { if (data?.meta?.count) { data.meta.count = previousData?.meta?.count - 1; @@ -277,7 +277,7 @@ export const useDeleteTemplateItemMutate = (queryClient: QueryClient) => { return data; }, ); - queryClient.invalidateQueries(GET_TEMPLATES_KEY); + queryClient.invalidateQueries({ queryKey: [GET_TEMPLATES_KEY] }); }, // If the mutation fails, use the context returned from onMutate to roll back // eslint-disable-next-line @typescript-eslint/no-explicit-any diff --git a/yarn.lock b/yarn.lock index c654020d2..4c0d17097 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1093,7 +1093,7 @@ "@babel/plugin-transform-modules-commonjs" "^7.27.1" "@babel/plugin-transform-typescript" "^7.28.5" -"@babel/runtime@^7.12.5", "@babel/runtime@^7.15.4", "@babel/runtime@^7.21.0", "@babel/runtime@^7.23.8", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.2", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.3": +"@babel/runtime@^7.12.5", "@babel/runtime@^7.15.4", "@babel/runtime@^7.21.0", "@babel/runtime@^7.3.1", "@babel/runtime@^7.8.3": version "7.28.4" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.28.4.tgz#a70226016fabe25c5783b2f22d3e1c9bc5ca3326" integrity sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ== @@ -2131,7 +2131,7 @@ clsx "^2.1.1" react-jss "^10.10.0" -"@patternfly/react-drag-drop@^6.4.1": +"@patternfly/react-drag-drop@^6.3.1": version "6.4.1" resolved "https://registry.yarnpkg.com/@patternfly/react-drag-drop/-/react-drag-drop-6.4.1.tgz#672a419b64fd26a6da430725a88e195afb387c3f" integrity sha512-+zkN+6JO/6qPKb1srsKyC4OpeF/dgQvZ0U4soXeh/n22n2YVcrH9QAUGn1QBB7FmLiAoATHB9vr1awafF5HIYw== @@ -4161,11 +4161,6 @@ before-after-hook@^3.0.2: resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-3.0.2.tgz#d5665a5fa8b62294a5aa0a499f933f4a1016195d" integrity sha512-Nik3Sc0ncrMK4UUdXQmAnRtzmNQTAAXmXIopizwZ1W1t8QmfJj+zL4OA2I7XPTPW5z5TDqv4hRo/JzouDJnX3A== -big-integer@^1.6.16: - version "1.6.52" - resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.52.tgz#60a887f3047614a8e1bffe5d7173490a97dc8c85" - integrity sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg== - big.js@^5.2.2: version "5.2.2" resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" @@ -4257,20 +4252,6 @@ braces@^3.0.3, braces@~3.0.2: dependencies: fill-range "^7.1.1" -broadcast-channel@^3.4.1: - version "3.7.0" - resolved "https://registry.yarnpkg.com/broadcast-channel/-/broadcast-channel-3.7.0.tgz#2dfa5c7b4289547ac3f6705f9c00af8723889937" - integrity sha512-cIAKJXAxGJceNZGTZSBzMxzyOn72cVgPnKx4dc6LRjQgbaJUQqhy5rzL3zbMxkMWsGKkv2hSFkPRMEXfoMZ2Mg== - dependencies: - "@babel/runtime" "^7.7.2" - detect-node "^2.1.0" - js-sha3 "0.8.0" - microseconds "0.2.0" - nano-time "1.0.0" - oblivious-set "1.0.0" - rimraf "3.0.2" - unload "2.2.0" - browserify-zlib@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f" @@ -5166,7 +5147,7 @@ detect-newline@^3.0.0: resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== -detect-node@^2.0.4, detect-node@^2.1.0: +detect-node@^2.0.4: version "2.1.0" resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1" integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g== @@ -7868,11 +7849,6 @@ joi@^17.11.0: "@sideway/formula" "^3.0.1" "@sideway/pinpoint" "^2.0.0" -js-sha3@0.8.0: - version "0.8.0" - resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840" - integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q== - "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" @@ -8374,14 +8350,6 @@ makeerror@1.0.12: dependencies: tmpl "1.0.5" -match-sorter@^6.0.2: - version "6.4.0" - resolved "https://registry.yarnpkg.com/match-sorter/-/match-sorter-6.4.0.tgz#ae9c166cb3c9efd337690b3160c0e28cb8377c13" - integrity sha512-d4664ahzdL1QTTvmK1iI0JsrxWeJ6gn33qkYtnPg3mcn+naBLtXSgSPOe+X2vUgtgGwaAk3eiaj7gwKjjMAq+Q== - dependencies: - "@babel/runtime" "^7.23.8" - remove-accents "0.5.0" - math-intrinsics@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9" @@ -8451,11 +8419,6 @@ micromatch@^4.0.0, micromatch@^4.0.2, micromatch@^4.0.4, micromatch@^4.0.5: braces "^3.0.3" picomatch "^2.3.1" -microseconds@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/microseconds/-/microseconds-0.2.0.tgz#233b25f50c62a65d861f978a4a4f8ec18797dc39" - integrity sha512-n7DHHMjR1avBbSpsTBj6fmMGh2AGrifVV4e+WYc3Q9lO+xnSZ3NyhcBND3vzzatt05LFhoKFRxrIyklmLlUtyA== - mime-db@1.52.0: version "1.52.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" @@ -8587,13 +8550,6 @@ nan@^2.19.0, nan@^2.23.0: resolved "https://registry.yarnpkg.com/nan/-/nan-2.24.0.tgz#a8919b36e692aa5b260831910e4f81419fc0a283" integrity sha512-Vpf9qnVW1RaDkoNKFUvfxqAbtI8ncb8OJlqZ9wwpXzWPEsvsB1nvdUi6oYrHIkQ1Y/tMDnr1h4nczS0VB9Xykg== -nano-time@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/nano-time/-/nano-time-1.0.0.tgz#b0554f69ad89e22d0907f7a12b0993a5d96137ef" - integrity sha512-flnngywOoQ0lLQOTRNexn2gGSNuM9bKj9RZAWSzhQ+UJYaAFG9bac4DW9VHjUAzrOaIcajHybCTHe/bkvozQqA== - dependencies: - big-integer "^1.6.16" - nanoclone@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/nanoclone/-/nanoclone-0.2.1.tgz#dd4090f8f1a110d26bb32c49ed2f5b9235209ed4" @@ -8846,11 +8802,6 @@ object.values@^1.1.6, object.values@^1.2.1: define-properties "^1.2.1" es-object-atoms "^1.0.0" -oblivious-set@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/oblivious-set/-/oblivious-set-1.0.0.tgz#c8316f2c2fb6ff7b11b6158db3234c49f733c566" - integrity sha512-z+pI07qxo4c2CulUHCDf9lcqDlMSo72N/4rLUpRXf6fu+q8vjt8y0xS+Tlf8NTJDdTXHbdeO1n3MlbctwEoXZw== - obuf@^1.0.0, obuf@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e" @@ -9777,15 +9728,6 @@ react-jss@^10.10.0: theming "^3.3.0" tiny-warning "^1.0.2" -react-query@^3.39.3: - version "3.39.3" - resolved "https://registry.yarnpkg.com/react-query/-/react-query-3.39.3.tgz#4cea7127c6c26bdea2de5fb63e51044330b03f35" - integrity sha512-nLfLz7GiohKTJDuT4us4X3h/8unOh+00MLb2yJoGTPjxKs2bc1iDhkNx2bd5MKklXnOD3NrVZ+J2UXujA5In4g== - dependencies: - "@babel/runtime" "^7.5.5" - broadcast-channel "^3.4.1" - match-sorter "^6.0.2" - react-redux@^9.1.2: version "9.2.0" resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-9.2.0.tgz#96c3ab23fb9a3af2cb4654be4b51c989e32366f5" @@ -10002,11 +9944,6 @@ release-zalgo@^1.0.0: dependencies: es6-error "^4.0.1" -remove-accents@0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/remove-accents/-/remove-accents-0.5.0.tgz#77991f37ba212afba162e375b627631315bed687" - integrity sha512-8g3/Otx1eJaVD12e31UbJj1YzdtVvzH85HV7t+9MJYk/u3XmkOUJ5Ys9wQrf9PCPK8+xn4ymzqYCiZl6QWKn+A== - renderkid@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/renderkid/-/renderkid-3.0.0.tgz#5fd823e4d6951d37358ecc9a58b1f06836b6268a" @@ -10109,13 +10046,6 @@ retry@0.13.1, retry@^0.13.1: resolved "https://registry.yarnpkg.com/retry/-/retry-0.13.1.tgz#185b1587acf67919d63b357349e03537b2484658" integrity sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg== -rimraf@3.0.2, rimraf@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" - integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== - dependencies: - glob "^7.1.3" - rimraf@^2.6.3: version "2.7.1" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" @@ -10123,6 +10053,13 @@ rimraf@^2.6.3: dependencies: glob "^7.1.3" +rimraf@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + run-applescript@^7.0.0: version "7.1.0" resolved "https://registry.yarnpkg.com/run-applescript/-/run-applescript-7.1.0.tgz#2e9e54c4664ec3106c5b5630e249d3d6595c4911" @@ -11399,14 +11336,6 @@ unleash-proxy-client@^3.7.8: tiny-emitter "^2.1.0" uuid "^9.0.1" -unload@2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/unload/-/unload-2.2.0.tgz#ccc88fdcad345faa06a92039ec0f80b488880ef7" - integrity sha512-B60uB5TNBLtN6/LsgAf3udH9saB5p7gqJwcFfbOEZ8BcBHnGwCf6G/TGiEqkRAxX7zAFIUtzdrXQSdL3Q/wqNA== - dependencies: - "@babel/runtime" "^7.6.2" - detect-node "^2.0.4" - unpipe@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" From 6f5761e9e884e819437c30674f4f9315435cffc6 Mon Sep 17 00:00:00 2001 From: Dominik Vagner Date: Fri, 23 Jan 2026 15:21:41 +0100 Subject: [PATCH 4/6] chore: react-query migration, fix loading states This fixes issues with the changed behavior of 'isLoading' states for disabled (even temporarily) queries. And fixes and issue with loading state merging in the delete content modal. --- src/App.tsx | 20 ++++++++++--------- .../components/AddContent/AddContent.tsx | 6 +++++- .../DeleteContentModal/DeleteContentModal.tsx | 9 ++++----- .../UploadContent/components/FileUploader.tsx | 2 +- .../TemplatesTable/TemplatesTable.tsx | 2 +- .../AddOrEditTemplate/AddTemplateContext.tsx | 2 +- 6 files changed, 23 insertions(+), 18 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 4e03d2793..3ff98e586 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -34,15 +34,17 @@ export default function App() { statuses: [], }); - const { data = { data: [], meta: { count: 0, limit: 20, offset: 0 } }, isLoading } = - useContentListQuery( - 1, - storedPerPage, - filterData, - '', - [ContentOrigin.EXTERNAL, ContentOrigin.UPLOAD], - isDefaultRoute && zeroState, // We only check if the route is correct and zerostate is true (defaults to true) - ); + const { + data = { data: [], meta: { count: 0, limit: 20, offset: 0 } }, + isInitialLoading: isLoading, + } = useContentListQuery( + 1, + storedPerPage, + filterData, + '', + [ContentOrigin.EXTERNAL, ContentOrigin.UPLOAD], + isDefaultRoute && zeroState, // We only check if the route is correct and zerostate is true (defaults to true) + ); // Hide Insights' global filter bar useEffect(() => { diff --git a/src/Pages/Repositories/ContentListTable/components/AddContent/AddContent.tsx b/src/Pages/Repositories/ContentListTable/components/AddContent/AddContent.tsx index 172936cac..228c6ca6b 100644 --- a/src/Pages/Repositories/ContentListTable/components/AddContent/AddContent.tsx +++ b/src/Pages/Repositories/ContentListTable/components/AddContent/AddContent.tsx @@ -99,7 +99,11 @@ const AddContent = ({ isEdit = false }: Props) => { const [errors, setErrors] = useState>({}); const [isActionOpen, setIsActionOpen] = useState(false); - const { data, isLoading: isLoadingInitialContent, isSuccess } = useFetchContent(uuid!, isEdit); + const { + data, + isInitialLoading: isLoadingInitialContent, + isSuccess, + } = useFetchContent(uuid!, isEdit); const [values, setValues] = useState(getDefaultValues({})); const [changeVerified, setChangeVerified] = useState(false); diff --git a/src/Pages/Repositories/ContentListTable/components/DeleteContentModal/DeleteContentModal.tsx b/src/Pages/Repositories/ContentListTable/components/DeleteContentModal/DeleteContentModal.tsx index d3e19c5b7..42bd9c6a9 100644 --- a/src/Pages/Repositories/ContentListTable/components/DeleteContentModal/DeleteContentModal.tsx +++ b/src/Pages/Repositories/ContentListTable/components/DeleteContentModal/DeleteContentModal.tsx @@ -67,7 +67,6 @@ export default function DeleteContentModal() { const rootPath = useRootPath(); const queryClient = useQueryClient(); const { search } = useLocation(); - const [isLoading, setIsLoading] = useState(true); const maxTemplatesToShow = 3; const [expandState, setExpandState] = useState({}); @@ -98,6 +97,7 @@ export default function DeleteContentModal() { const { isError: isRepoError, data: repos = { data: [] as ContentItem[], meta: { count: 0, limit: 20, offset: 0 } }, + isInitialLoading: isRepoLoading, } = useContentListQuery(selectedPage, selectedPerPage, repoFilterData, '', [ ContentOrigin.CUSTOM, ]); @@ -136,17 +136,16 @@ export default function DeleteContentModal() { const { isError: isTemplateError, data: templates = { data: [], meta: { count: 0, limit: 20, offset: 0 } }, + isInitialLoading: isTemplateLoading, } = useTemplateList(page, perPage, '', templateFilterData); useEffect(() => { - if (repos && templates) { - setIsLoading(false); - } if (isRepoError || isTemplateError) { onClose(); } - }, [isRepoError, isTemplateError, repos.data, templates.data]); + }, [isRepoError, isTemplateError]); + const isLoading = isRepoLoading || isTemplateLoading; const actionTakingPlace = isDeletingItems || isLoading; const columnHeaders = ['Name', 'URL', 'Associated templates']; diff --git a/src/Pages/Repositories/ContentListTable/components/UploadContent/components/FileUploader.tsx b/src/Pages/Repositories/ContentListTable/components/UploadContent/components/FileUploader.tsx index 0621739d7..e97bf206f 100644 --- a/src/Pages/Repositories/ContentListTable/components/UploadContent/components/FileUploader.tsx +++ b/src/Pages/Repositories/ContentListTable/components/UploadContent/components/FileUploader.tsx @@ -57,7 +57,7 @@ export default function FileUploader({ setFileUUIDs, isLoading, setChildLoading const { data: repositoryData, - isLoading: isLoadingRepo, + isInitialLoading: isLoadingRepo, refetch: refetchRepo, } = useFetchContent(uuid!, !!uuid); diff --git a/src/Pages/Templates/TemplatesTable/TemplatesTable.tsx b/src/Pages/Templates/TemplatesTable/TemplatesTable.tsx index 4863ee36e..1fdc975bc 100644 --- a/src/Pages/Templates/TemplatesTable/TemplatesTable.tsx +++ b/src/Pages/Templates/TemplatesTable/TemplatesTable.tsx @@ -116,7 +116,7 @@ const TemplatesTable = () => { ); const { - isLoading, + isInitialLoading: isLoading, error, isError, isFetching, diff --git a/src/Pages/Templates/TemplatesTable/components/AddOrEditTemplate/AddTemplateContext.tsx b/src/Pages/Templates/TemplatesTable/components/AddOrEditTemplate/AddTemplateContext.tsx index 9264bfe59..03bdba362 100644 --- a/src/Pages/Templates/TemplatesTable/components/AddOrEditTemplate/AddTemplateContext.tsx +++ b/src/Pages/Templates/TemplatesTable/components/AddOrEditTemplate/AddTemplateContext.tsx @@ -84,7 +84,7 @@ export const AddTemplateContextProvider = ({ children }: { children: ReactNode } !!hardcodedRedhatRepositories.length, ); - const { data: existingRepositoryInformation, isLoading } = useContentListQuery( + const { data: existingRepositoryInformation, isInitialLoading: isLoading } = useContentListQuery( 1, 10, { uuids: editTemplateData?.repository_uuids }, From 8c354f05d0fce8e1ce0dbc10ecb864c815f5f4a9 Mon Sep 17 00:00:00 2001 From: Dominik Vagner Date: Mon, 26 Jan 2026 09:12:29 +0100 Subject: [PATCH 5/6] chore: update react-query dependency to v5 --- package.json | 2 +- yarn.lock | 21 ++++++++++----------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/package.json b/package.json index f228c6602..5081fcf62 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "@redhat-cloud-services/frontend-components-config": "^6.7.51", "@redhat-cloud-services/frontend-components-notifications": "^6.1.41", "@redhat-cloud-services/frontend-components-utilities": "^7.0.36", - "@tanstack/react-query": "^4.42.2", + "@tanstack/react-query": "^5.90.19", "@testing-library/dom": "^10.4.1", "@types/dockerode": "^4.0.1", "@unleash/proxy-client-react": "^5.0.1", diff --git a/yarn.lock b/yarn.lock index 4c0d17097..92b5daca5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2871,18 +2871,17 @@ dependencies: "@swc/counter" "^0.1.3" -"@tanstack/query-core@4.41.1": - version "4.41.1" - resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-4.41.1.tgz#1872f912609b7ca9d24f6b5f56ab3aedb216580d" - integrity sha512-XZvEw2OT+Nmi+ByQjURv3ckxRfzbYXSL6Hb60lgEn4GqUXz8HQTFdySvcSuCdxashqkBLrDvn9NwOhAbMTe9ow== +"@tanstack/query-core@5.90.20": + version "5.90.20" + resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-5.90.20.tgz#e12128e39210715d4ce4fb299c33498ac297771e" + integrity sha512-OMD2HLpNouXEfZJWcKeVKUgQ5n+n3A2JFmBaScpNDUqSrQSjiveC7dKMe53uJUg1nDG16ttFPz2xfilz6i2uVg== -"@tanstack/react-query@^4.42.2": - version "4.42.2" - resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-4.42.2.tgz#7d0beaf8bad710a9309730b51fb49985f08d0026" - integrity sha512-KFqT8wb/d0bHbzvJEuD/vEU8lUSC5cZDurOMtAR3G+mUABqVWvVswQ/norjFXedjQe+nfQQ9CWrOabWcRP3TKA== +"@tanstack/react-query@^5.90.19": + version "5.90.20" + resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-5.90.20.tgz#42bb7018bfedc72f216b6e9b4052c919063f350b" + integrity sha512-vXBxa+qeyveVO7OA0jX1z+DeyCA4JKnThKv411jd5SORpBKgkcVnYKCiBgECvADvniBX7tobwBmg01qq9JmMJw== dependencies: - "@tanstack/query-core" "4.41.1" - use-sync-external-store "^1.6.0" + "@tanstack/query-core" "5.90.20" "@testing-library/dom@^10.4.1": version "10.4.1" @@ -11403,7 +11402,7 @@ url@^0.11.0: punycode "^1.4.1" qs "^6.12.3" -use-sync-external-store@^1.4.0, use-sync-external-store@^1.6.0: +use-sync-external-store@^1.4.0: version "1.6.0" resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz#b174bfa65cb2b526732d9f2ac0a408027876f32d" integrity sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w== From 01241fcdc6af0cfc6884574bd4d3c85e79366ea9 Mon Sep 17 00:00:00 2001 From: Dominik Vagner Date: Tue, 27 Jan 2026 16:46:10 +0100 Subject: [PATCH 6/6] chore: react-query v5 migration fixes This fixes the issues caused by breaking changes in the react-query version 5. Those include mainly the removal of callbacks from useQuery hooks and changes to support single object params. --- src/App.tsx | 26 +- src/AppEntry.tsx | 57 +- src/Hooks/useErrorNotification.tsx | 54 +- .../components/AddContent/AddContent.tsx | 12 +- .../components/AddContent/helpers.ts | 6 +- .../DeleteContentModal/DeleteContentModal.tsx | 6 +- .../DeleteSnapshotsModal.tsx | 2 +- .../UploadContent/UploadContent.tsx | 6 +- .../UploadContent/components/FileUploader.tsx | 2 +- .../PopularRepositoriesTable.tsx | 6 +- .../AssignTemplateModal/AddSystemModal.tsx | 2 +- .../AssignTemplateModal.test.tsx | 4 +- .../AssignTemplateModal.tsx | 2 +- .../components/Tabs/TemplateSystemsTab.tsx | 2 +- .../TemplatesTable/TemplatesTable.tsx | 2 +- .../AddOrEditTemplate/AddOrEditTemplate.tsx | 4 +- .../AddOrEditTemplate/AddTemplateContext.tsx | 2 +- .../components/DeleteTemplateModal.tsx | 2 +- src/services/Admin/AdminQueries.ts | 64 +-- src/services/Admin/AdminTaskQueries.ts | 78 +-- src/services/Content/ContentQueries.ts | 512 +++++++++--------- .../Subscriptions/SubscriptionQueries.ts | 19 +- src/services/Systems/SystemsQueries.ts | 95 ++-- src/services/Templates/TemplateQueries.ts | 191 +++---- 24 files changed, 548 insertions(+), 608 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 3ff98e586..81b31eb10 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,7 +1,7 @@ import '@redhat-cloud-services/frontend-components-utilities/styles/_all'; import 'react18-json-view/src/style.css'; import { useChrome } from '@redhat-cloud-services/frontend-components/useChrome'; -import { NotificationsProvider } from '@redhat-cloud-services/frontend-components-notifications'; + import { Bullseye, Spinner } from '@patternfly/react-core'; import { useEffect, useMemo, useState } from 'react'; import { useLocation } from 'react-router-dom'; @@ -34,17 +34,15 @@ export default function App() { statuses: [], }); - const { - data = { data: [], meta: { count: 0, limit: 20, offset: 0 } }, - isInitialLoading: isLoading, - } = useContentListQuery( - 1, - storedPerPage, - filterData, - '', - [ContentOrigin.EXTERNAL, ContentOrigin.UPLOAD], - isDefaultRoute && zeroState, // We only check if the route is correct and zerostate is true (defaults to true) - ); + const { data = { data: [], meta: { count: 0, limit: 20, offset: 0 } }, isLoading } = + useContentListQuery( + 1, + storedPerPage, + filterData, + '', + [ContentOrigin.EXTERNAL, ContentOrigin.UPLOAD], + isDefaultRoute && zeroState, // We only check if the route is correct and zerostate is true (defaults to true) + ); // Hide Insights' global filter bar useEffect(() => { @@ -69,9 +67,9 @@ export default function App() { } return ( - + <>
- + ); } diff --git a/src/AppEntry.tsx b/src/AppEntry.tsx index db8d2689a..1686ddc7e 100644 --- a/src/AppEntry.tsx +++ b/src/AppEntry.tsx @@ -1,25 +1,24 @@ +import { AlertVariant } from '@patternfly/react-core'; +import { + createStore as createNotificationStore, + NotificationsProvider, +} from '@redhat-cloud-services/frontend-components-notifications'; +import { QueryCache, QueryClient, QueryClientProvider } from '@tanstack/react-query'; import React, { useEffect } from 'react'; -import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { Provider as ReduxProvider } from 'react-redux'; import * as Redux from 'redux'; +import { composeErrorDescription } from 'Hooks/useErrorNotification'; import App from './App'; - import { ContextProvider } from './middleware/AppContext'; import { createStore, restoreStore } from './store'; -const queryClient = new QueryClient({ - defaultOptions: { - queries: { - refetchOnWindowFocus: false, - }, - }, -}); - interface AppEntryProps { logger?: Redux.Middleware; } +const notificationsStore = createNotificationStore(); + export default function AppEntry({ logger }: AppEntryProps) { const store = React.useMemo(() => { restoreStore(); @@ -33,13 +32,41 @@ export default function AppEntry({ logger }: AppEntryProps) { insights?.chrome?.appAction?.('view-list-page'); }, []); + const [queryClient] = React.useState( + new QueryClient({ + defaultOptions: { + queries: { + refetchOnWindowFocus: false, + }, + }, + queryCache: new QueryCache({ + onError: (_, query) => { + if (query.meta?.title) { + const { title, description } = composeErrorDescription( + query.meta.title as string, + 'An error occurred', + query.state.error, + ); + notificationsStore.addNotification({ + title, + description, + variant: AlertVariant.danger, + }); + } + }, + }), + }), + ); + return ( - - - - - + + + + + + + ); } diff --git a/src/Hooks/useErrorNotification.tsx b/src/Hooks/useErrorNotification.tsx index e2108fbb3..053fdadbb 100644 --- a/src/Hooks/useErrorNotification.tsx +++ b/src/Hooks/useErrorNotification.tsx @@ -1,6 +1,38 @@ import { AlertVariant } from '@patternfly/react-core'; import useNotification from './useNotification'; +export function composeErrorDescription( + defaultTitle: string, + defaultDescription: string, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + err: any, +) { + let title = defaultTitle; + + let description = defaultDescription; + + switch (typeof err?.response?.data) { + case 'string': + description = err.response.data; + break; + case 'object': + // Only show the first error + err?.response?.data.errors?.find( + ({ title: errTitle, detail, description: errDescription }) => { + if (errTitle) title = errTitle; + if (errDescription) description = errDescription; + if (detail) description = detail; + if (errTitle || errDescription || detail) return true; + }, + ); + break; + default: + break; + } + + return { title, description }; +} + export default function useErrorNotification() { const { notify } = useNotification(); @@ -11,27 +43,7 @@ export default function useErrorNotification() { err: any, id: string, ) => { - let title = defaultTitle; - let description = defaultDescription; - - switch (typeof err?.response?.data) { - case 'string': - description = err.response.data; - break; - case 'object': - // Only show the first error - err?.response?.data.errors?.find( - ({ title: errTitle, detail, description: errDescription }) => { - if (errTitle) title = errTitle; - if (errDescription) description = errDescription; - if (detail) description = detail; - if (errTitle || errDescription || detail) return true; - }, - ); - break; - default: - break; - } + const { title, description } = composeErrorDescription(defaultTitle, defaultDescription, err); notify({ variant: AlertVariant.danger, diff --git a/src/Pages/Repositories/ContentListTable/components/AddContent/AddContent.tsx b/src/Pages/Repositories/ContentListTable/components/AddContent/AddContent.tsx index 228c6ca6b..4e1bd4b6a 100644 --- a/src/Pages/Repositories/ContentListTable/components/AddContent/AddContent.tsx +++ b/src/Pages/Repositories/ContentListTable/components/AddContent/AddContent.tsx @@ -99,11 +99,7 @@ const AddContent = ({ isEdit = false }: Props) => { const [errors, setErrors] = useState>({}); const [isActionOpen, setIsActionOpen] = useState(false); - const { - data, - isInitialLoading: isLoadingInitialContent, - isSuccess, - } = useFetchContent(uuid!, isEdit); + const { data, isLoading: isLoadingInitialContent, isSuccess } = useFetchContent(uuid!, isEdit); const [values, setValues] = useState(getDefaultValues({})); const [changeVerified, setChangeVerified] = useState(false); @@ -114,7 +110,7 @@ const AddContent = ({ isEdit = false }: Props) => { } }, [isLoadingInitialContent, isSuccess]); - const { mutateAsync: editContent, isLoading: isEditing } = useEditContentQuery( + const { mutateAsync: editContent, isPending: isEditing } = useEditContentQuery( mapFormikToAPIValues(values), ); @@ -176,7 +172,7 @@ const AddContent = ({ isEdit = false }: Props) => { } }; - const { mutateAsync: addContent, isLoading: isAdding } = useAddContentQuery([ + const { mutateAsync: addContent, isPending: isAdding } = useAddContentQuery([ mapFormikToAPIValues(values), ]); @@ -217,7 +213,7 @@ const AddContent = ({ isEdit = false }: Props) => { const { mutateAsync: validateContent, data: validationList, - isLoading: isValidating, + isPending: isValidating, } = useValidateContentList(); useEffect(() => { diff --git a/src/Pages/Repositories/ContentListTable/components/AddContent/helpers.ts b/src/Pages/Repositories/ContentListTable/components/AddContent/helpers.ts index ef6c85130..4dcc3e523 100644 --- a/src/Pages/Repositories/ContentListTable/components/AddContent/helpers.ts +++ b/src/Pages/Repositories/ContentListTable/components/AddContent/helpers.ts @@ -102,7 +102,7 @@ export const mapFormikToAPIValues = ({ modularityFilteringEnabled, origin, }: FormikValues): EditContentRequestItem => - (({ + ({ uuid, name, url, @@ -112,8 +112,8 @@ export const mapFormikToAPIValues = ({ snapshot, metadata_verification: metadataVerification, module_hotfixes: !modularityFilteringEnabled, - origin - }) as EditContentRequestItem); + origin, + }) as EditContentRequestItem; const mapNoMetaDataError = (response: ValidationResponse): Partial => { if (isEmpty(response)) return {}; diff --git a/src/Pages/Repositories/ContentListTable/components/DeleteContentModal/DeleteContentModal.tsx b/src/Pages/Repositories/ContentListTable/components/DeleteContentModal/DeleteContentModal.tsx index 42bd9c6a9..370325805 100644 --- a/src/Pages/Repositories/ContentListTable/components/DeleteContentModal/DeleteContentModal.tsx +++ b/src/Pages/Repositories/ContentListTable/components/DeleteContentModal/DeleteContentModal.tsx @@ -97,14 +97,14 @@ export default function DeleteContentModal() { const { isError: isRepoError, data: repos = { data: [] as ContentItem[], meta: { count: 0, limit: 20, offset: 0 } }, - isInitialLoading: isRepoLoading, + isLoading: isRepoLoading, } = useContentListQuery(selectedPage, selectedPerPage, repoFilterData, '', [ ContentOrigin.CUSTOM, ]); const reposToDelete = new Map(repos.data.map((repo) => [repo.uuid, repo])); - const { mutateAsync: deleteItems, isLoading: isDeletingItems } = useBulkDeleteContentItemMutate( + const { mutateAsync: deleteItems, isPending: isDeletingItems } = useBulkDeleteContentItemMutate( queryClient, reposToDelete, page, @@ -136,7 +136,7 @@ export default function DeleteContentModal() { const { isError: isTemplateError, data: templates = { data: [], meta: { count: 0, limit: 20, offset: 0 } }, - isInitialLoading: isTemplateLoading, + isLoading: isTemplateLoading, } = useTemplateList(page, perPage, '', templateFilterData); useEffect(() => { diff --git a/src/Pages/Repositories/ContentListTable/components/SnapshotListModal/DeleteSnapshotsModal/DeleteSnapshotsModal.tsx b/src/Pages/Repositories/ContentListTable/components/SnapshotListModal/DeleteSnapshotsModal/DeleteSnapshotsModal.tsx index 690c90c91..20d59f3a5 100644 --- a/src/Pages/Repositories/ContentListTable/components/SnapshotListModal/DeleteSnapshotsModal/DeleteSnapshotsModal.tsx +++ b/src/Pages/Repositories/ContentListTable/components/SnapshotListModal/DeleteSnapshotsModal/DeleteSnapshotsModal.tsx @@ -81,7 +81,7 @@ export default function DeleteSnapshotsModal() { : []; const snapshotsToDelete = new Set(uuids); - const { mutateAsync: deleteSnapshots, isLoading: isDeletingSnapshots } = + const { mutateAsync: deleteSnapshots, isPending: isDeletingSnapshots } = useBulkDeleteSnapshotsMutate(queryClient, uuid, snapshotsToDelete); const onClose = () => navigate(`${rootPath}/${REPOSITORIES_ROUTE}/${uuid}/snapshots`); diff --git a/src/Pages/Repositories/ContentListTable/components/UploadContent/UploadContent.tsx b/src/Pages/Repositories/ContentListTable/components/UploadContent/UploadContent.tsx index ee07b2f27..22c4852c4 100644 --- a/src/Pages/Repositories/ContentListTable/components/UploadContent/UploadContent.tsx +++ b/src/Pages/Repositories/ContentListTable/components/UploadContent/UploadContent.tsx @@ -41,7 +41,7 @@ const UploadContent = () => { const onClose = () => navigate(`${rootPath}/${REPOSITORIES_ROUTE}`); - const { mutateAsync: uploadItems, isLoading } = useAddUploadsQuery({ + const { mutateAsync: uploadItems, isPending } = useAddUploadsQuery({ repoUUID: uuid!, uploads: fileUUIDs .filter(({ href }) => !href) @@ -76,7 +76,7 @@ const UploadContent = () => { descriptorId='upload-content-modal-description' /> - + @@ -86,7 +86,7 @@ const UploadContent = () => { key='confirm' ouiaId='modal_save' variant='primary' - isLoading={isLoading} + isLoading={isPending} isDisabled={!fileUUIDs.length || childLoading} onClick={() => uploadItems().then(onClose)} > diff --git a/src/Pages/Repositories/ContentListTable/components/UploadContent/components/FileUploader.tsx b/src/Pages/Repositories/ContentListTable/components/UploadContent/components/FileUploader.tsx index e97bf206f..0621739d7 100644 --- a/src/Pages/Repositories/ContentListTable/components/UploadContent/components/FileUploader.tsx +++ b/src/Pages/Repositories/ContentListTable/components/UploadContent/components/FileUploader.tsx @@ -57,7 +57,7 @@ export default function FileUploader({ setFileUUIDs, isLoading, setChildLoading const { data: repositoryData, - isInitialLoading: isLoadingRepo, + isLoading: isLoadingRepo, refetch: refetchRepo, } = useFetchContent(uuid!, !!uuid); diff --git a/src/Pages/Repositories/PopularRepositoriesTable/PopularRepositoriesTable.tsx b/src/Pages/Repositories/PopularRepositoriesTable/PopularRepositoriesTable.tsx index de2079fd5..3ca8d6017 100644 --- a/src/Pages/Repositories/PopularRepositoriesTable/PopularRepositoriesTable.tsx +++ b/src/Pages/Repositories/PopularRepositoriesTable/PopularRepositoriesTable.tsx @@ -140,7 +140,7 @@ const PopularRepositoriesTable = () => { search: !searchValue ? searchValue : debouncedSearchValue, }); - const { mutateAsync: addContentQuery, isLoading: isAdding } = useAddPopularRepositoryQuery( + const { mutateAsync: addContentQuery, isPending: isAdding } = useAddPopularRepositoryQuery( queryClient, selectedData, page, @@ -237,11 +237,11 @@ const PopularRepositoriesTable = () => { } }, [selectedData]); - const { isLoading: isDeleting } = useDeletePopularRepositoryMutate(queryClient, page, perPage, { + const { isPending: isDeleting } = useDeletePopularRepositoryMutate(queryClient, page, perPage, { search: debouncedSearchValue, } as FilterData); - const { isLoading: isDeletingItems } = useBulkDeleteContentItemMutate( + const { isPending: isDeletingItems } = useBulkDeleteContentItemMutate( queryClient, checkedRepositoriesToDelete, page, diff --git a/src/Pages/Templates/TemplateDetails/components/AssignTemplateModal/AddSystemModal.tsx b/src/Pages/Templates/TemplateDetails/components/AssignTemplateModal/AddSystemModal.tsx index 71c84962b..2664f5e84 100644 --- a/src/Pages/Templates/TemplateDetails/components/AssignTemplateModal/AddSystemModal.tsx +++ b/src/Pages/Templates/TemplateDetails/components/AssignTemplateModal/AddSystemModal.tsx @@ -163,7 +163,7 @@ export default function AddSystemModal() { return selectableSystems.every(({ id }) => selectedList.has(id)); }, [selectedList, systemsList, allSystemsAreMinorReleases, uuid]); - const { mutateAsync: addSystems, isLoading: isAdding } = useAddTemplateToSystemsQuery( + const { mutateAsync: addSystems, isPending: isAdding } = useAddTemplateToSystemsQuery( queryClient, uuid, selected, diff --git a/src/Pages/Templates/TemplateDetails/components/AssignTemplateModal/AssignTemplateModal.test.tsx b/src/Pages/Templates/TemplateDetails/components/AssignTemplateModal/AssignTemplateModal.test.tsx index 1b7d830b4..dde3a9ea5 100644 --- a/src/Pages/Templates/TemplateDetails/components/AssignTemplateModal/AssignTemplateModal.test.tsx +++ b/src/Pages/Templates/TemplateDetails/components/AssignTemplateModal/AssignTemplateModal.test.tsx @@ -1,6 +1,6 @@ import { render, waitFor, screen, within } from '@testing-library/react'; import AssignTemplateModal from './AssignTemplateModal'; -import { useQueryClient } from 'react-query'; +import { useQueryClient } from '@tanstack/react-query'; import { useSystemsListQuery } from 'services/Systems/SystemsQueries'; import { defaultSystemsListItem, @@ -27,7 +27,7 @@ jest.mock('Hooks/useRootPath', () => () => 'someUrl'); jest.mock('Hooks/useHasRegisteredSystems'); -jest.mock('react-query'); +jest.mock('@tanstack/react-query'); jest.mock('services/Systems/SystemsQueries', () => ({ useAddTemplateToSystemsQuery: () => ({ mutate: () => undefined, isLoading: false }), diff --git a/src/Pages/Templates/TemplateDetails/components/AssignTemplateModal/AssignTemplateModal.tsx b/src/Pages/Templates/TemplateDetails/components/AssignTemplateModal/AssignTemplateModal.tsx index 7958ca364..01eb2861f 100644 --- a/src/Pages/Templates/TemplateDetails/components/AssignTemplateModal/AssignTemplateModal.tsx +++ b/src/Pages/Templates/TemplateDetails/components/AssignTemplateModal/AssignTemplateModal.tsx @@ -70,7 +70,7 @@ const AssignTemplateModal = () => { const [selectedSystems, setSelectedSystems] = useState([]); - const { mutateAsync: addSystems, isLoading: isAdding } = useAddTemplateToSystemsQuery( + const { mutateAsync: addSystems, isPending: isAdding } = useAddTemplateToSystemsQuery( queryClient, uuid, selectedSystems, diff --git a/src/Pages/Templates/TemplateDetails/components/Tabs/TemplateSystemsTab.tsx b/src/Pages/Templates/TemplateDetails/components/Tabs/TemplateSystemsTab.tsx index 4b3535730..78956e219 100644 --- a/src/Pages/Templates/TemplateDetails/components/Tabs/TemplateSystemsTab.tsx +++ b/src/Pages/Templates/TemplateDetails/components/Tabs/TemplateSystemsTab.tsx @@ -119,7 +119,7 @@ export default function TemplateSystemsTab() { const { hasRegisteredSystems, isFetchingRegSystems, isErrorFetchingRegSystems } = useHasRegisteredSystems(uuid); - const { mutateAsync: deleteFromSystems, isLoading: isDeleting } = + const { mutateAsync: deleteFromSystems, isPending: isDeleting } = useDeleteTemplateFromSystems(queryClient); const { diff --git a/src/Pages/Templates/TemplatesTable/TemplatesTable.tsx b/src/Pages/Templates/TemplatesTable/TemplatesTable.tsx index 1fdc975bc..4863ee36e 100644 --- a/src/Pages/Templates/TemplatesTable/TemplatesTable.tsx +++ b/src/Pages/Templates/TemplatesTable/TemplatesTable.tsx @@ -116,7 +116,7 @@ const TemplatesTable = () => { ); const { - isInitialLoading: isLoading, + isLoading, error, isError, isFetching, diff --git a/src/Pages/Templates/TemplatesTable/components/AddOrEditTemplate/AddOrEditTemplate.tsx b/src/Pages/Templates/TemplatesTable/components/AddOrEditTemplate/AddOrEditTemplate.tsx index bc3aaec03..284ad6b17 100644 --- a/src/Pages/Templates/TemplatesTable/components/AddOrEditTemplate/AddOrEditTemplate.tsx +++ b/src/Pages/Templates/TemplatesTable/components/AddOrEditTemplate/AddOrEditTemplate.tsx @@ -110,12 +110,12 @@ const AddOrEditTemplateBase = () => { } }; - const { mutateAsync: addTemplate, isLoading: isAdding } = useCreateTemplateQuery(queryClient, { + const { mutateAsync: addTemplate, isPending: isAdding } = useCreateTemplateQuery(queryClient, { ...(templateRequest as TemplateRequest), date: templateRequest.use_latest ? null : formatTemplateDate(templateRequest.date || ''), }); - const { mutateAsync: editTemplate, isLoading: isEditing } = useEditTemplateQuery(queryClient, { + const { mutateAsync: editTemplate, isPending: isEditing } = useEditTemplateQuery(queryClient, { uuid: editUUID as string, ...(templateRequest as TemplateRequest), date: templateRequest.use_latest ? null : formatTemplateDate(templateRequest.date || ''), diff --git a/src/Pages/Templates/TemplatesTable/components/AddOrEditTemplate/AddTemplateContext.tsx b/src/Pages/Templates/TemplatesTable/components/AddOrEditTemplate/AddTemplateContext.tsx index 03bdba362..9264bfe59 100644 --- a/src/Pages/Templates/TemplatesTable/components/AddOrEditTemplate/AddTemplateContext.tsx +++ b/src/Pages/Templates/TemplatesTable/components/AddOrEditTemplate/AddTemplateContext.tsx @@ -84,7 +84,7 @@ export const AddTemplateContextProvider = ({ children }: { children: ReactNode } !!hardcodedRedhatRepositories.length, ); - const { data: existingRepositoryInformation, isInitialLoading: isLoading } = useContentListQuery( + const { data: existingRepositoryInformation, isLoading } = useContentListQuery( 1, 10, { uuids: editTemplateData?.repository_uuids }, diff --git a/src/Pages/Templates/TemplatesTable/components/DeleteTemplateModal.tsx b/src/Pages/Templates/TemplatesTable/components/DeleteTemplateModal.tsx index de2084a59..36c716e1d 100644 --- a/src/Pages/Templates/TemplatesTable/components/DeleteTemplateModal.tsx +++ b/src/Pages/Templates/TemplatesTable/components/DeleteTemplateModal.tsx @@ -55,7 +55,7 @@ export default function DeleteTemplateModal() { const { data: templateData, isLoading: isTemplateLoading } = useFetchTemplate(uuid); - const { mutateAsync: deleteTemplate, isLoading: isDeleting } = + const { mutateAsync: deleteTemplate, isPending: isDeleting } = useDeleteTemplateItemMutate(queryClient); const onClose = () => navigate(`${rootPath}/${TEMPLATES_ROUTE}`); diff --git a/src/services/Admin/AdminQueries.ts b/src/services/Admin/AdminQueries.ts index 51988c7c1..98d990ff8 100644 --- a/src/services/Admin/AdminQueries.ts +++ b/src/services/Admin/AdminQueries.ts @@ -1,51 +1,33 @@ -import { useQuery } from '@tanstack/react-query'; +import { keepPreviousData, useQuery } from '@tanstack/react-query'; -import useErrorNotification from 'Hooks/useErrorNotification'; -import { - getAdminFeature, - getAdminFeatures, - type AdminFeature, - type AdminFeatures, -} from './AdminApi'; +import { getAdminFeature, getAdminFeatures } from './AdminApi'; export const ADMIN_FEATURE_KEY = 'ADMIN_FEATURE_KEY'; export const ADMIN_FEATURE_ITEM_KEY = 'ADMIN_FEATURE_ITEM_KEY'; -export const useAdminFeatureListQuery = () => { - const errorNotifier = useErrorNotification(); - return useQuery([ADMIN_FEATURE_KEY], () => getAdminFeatures(), { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - onError: (err: any) => { - errorNotifier( - 'Unable to get admin features', - 'An error occurred', - err, - 'admin-features-list-error', - ); +export const useAdminFeatureListQuery = () => + useQuery({ + queryKey: [ADMIN_FEATURE_KEY], + queryFn: () => getAdminFeatures(), + meta: { + title: 'Unable to get admin features', + id: 'admin-features-list-error', }, - keepPreviousData: true, + + placeholderData: keepPreviousData, staleTime: Infinity, }); -}; -export const useFetchAdminFeatureQuery = (featureName?: string, enabled?: boolean) => { - const errorNotifier = useErrorNotification(); - return useQuery( - [ADMIN_FEATURE_ITEM_KEY, featureName], - () => getAdminFeature(featureName as string), // Will be disabled if undefined - { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - onError: (err: any) => { - errorNotifier( - 'Unable to find an Admin feature with the given featureName: ' + featureName, - 'An error occurred', - err, - 'fetch-feature-error', - ); - }, - keepPreviousData: true, - staleTime: 20000, - enabled, +export const useFetchAdminFeatureQuery = (featureName?: string, enabled?: boolean) => + useQuery({ + queryKey: [ADMIN_FEATURE_ITEM_KEY, featureName], + queryFn: () => getAdminFeature(featureName as string), + meta: { + title: 'Unable to find an Admin feature with the given featureName: ' + featureName, + id: 'fetch-feature-error', }, - ); -}; + + placeholderData: keepPreviousData, + staleTime: 20000, + enabled, + }); diff --git a/src/services/Admin/AdminTaskQueries.ts b/src/services/Admin/AdminTaskQueries.ts index 84ac100c0..b2c313a8e 100644 --- a/src/services/Admin/AdminTaskQueries.ts +++ b/src/services/Admin/AdminTaskQueries.ts @@ -1,12 +1,5 @@ -import { useQuery } from '@tanstack/react-query'; -import { - AdminTaskFilterData, - AdminTaskListResponse, - getAdminTasks, - AdminTask, - getAdminTask, -} from './AdminTaskApi'; -import useErrorNotification from 'Hooks/useErrorNotification'; +import { keepPreviousData, useQuery } from '@tanstack/react-query'; +import { AdminTaskFilterData, getAdminTasks, getAdminTask } from './AdminTaskApi'; export const ADMIN_TASK_LIST_KEY = 'ADMIN_TASK_LIST_KEY'; export const ADMIN_TASK_KEY = 'ADMIN_TASK_KEY'; @@ -20,47 +13,36 @@ export const useAdminTaskListQuery = ( sortBy: string, polling: boolean, ) => { - const errorNotifier = useErrorNotification(); const flattenedFilterData = Object.values(filterData).flat(1); - return useQuery( - [ADMIN_TASK_LIST_KEY, page, limit, sortBy, ...flattenedFilterData], - () => getAdminTasks(page, limit, filterData, sortBy), - { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - onError: (err: any) => { - errorNotifier( - 'Unable to get admin task list', - 'An error occurred', - err, - 'admin-task-list-error', - ); - }, - refetchInterval: polling ? ADMIN_TASK_LIST_POLLING_TIME : undefined, - refetchIntervalInBackground: false, // This prevents endless polling when our app isn't the focus tab in a browser - refetchOnWindowFocus: polling, // If polling and navigate to another tab, on refocus, we want to poll once more. (This is based off of the stalestime below) - keepPreviousData: true, - staleTime: 20000, + return useQuery({ + queryKey: [ADMIN_TASK_LIST_KEY, page, limit, sortBy, ...flattenedFilterData], + queryFn: () => getAdminTasks(page, limit, filterData, sortBy), + meta: { + title: 'Unable to get admin task list', + id: 'admin-task-list-error', }, - ); + + refetchInterval: polling ? ADMIN_TASK_LIST_POLLING_TIME : undefined, + + // This prevents endless polling when our app isn't the focus tab in a browser + refetchIntervalInBackground: false, + + // If polling and navigate to another tab, on refocus, we want to poll once more. (This is based off of the stalestime below) + refetchOnWindowFocus: polling, + + placeholderData: keepPreviousData, + staleTime: 20000, + }); }; -export const useFetchAdminTaskQuery = (uuid?: string) => { - const errorNotifier = useErrorNotification(); - return useQuery( - [ADMIN_TASK_KEY, uuid], - () => getAdminTask(uuid as string), // Will be disabled if undefined - { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - onError: (err: any) => { - errorNotifier( - 'Unable to find an Admin task with the given UUID.', - 'An error occurred', - err, - 'fetch-admin-task-error', - ); - }, - keepPreviousData: true, - staleTime: 20000, +export const useFetchAdminTaskQuery = (uuid?: string) => + useQuery({ + queryKey: [ADMIN_TASK_KEY, uuid], + queryFn: () => getAdminTask(uuid as string), + meta: { + title: 'Unable to find an Admin task with the given UUID.', + id: 'fetch-admin-task-error', }, - ); -}; + placeholderData: keepPreviousData, + staleTime: 20000, + }); diff --git a/src/services/Content/ContentQueries.ts b/src/services/Content/ContentQueries.ts index a7f19e9bc..fa8f2f496 100644 --- a/src/services/Content/ContentQueries.ts +++ b/src/services/Content/ContentQueries.ts @@ -1,13 +1,18 @@ import { AlertVariant } from '@patternfly/react-core'; import { useState } from 'react'; -import { QueryClient, useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; +import { + keepPreviousData, + QueryClient, + useMutation, + useQuery, + useQueryClient, +} from '@tanstack/react-query'; import { cloneDeep } from 'lodash'; import { ContentListResponse, deleteContentListItem, getContentList, - RepositoryParamsResponse, getRepositoryParams, AddContentListItems, CreateContentRequest, @@ -15,7 +20,6 @@ import { validateContentListItems, EditContentListItem, getGpgKey, - PackagesResponse, getPackages, getPopularRepositories, PopularRepositoriesResponse, @@ -35,7 +39,6 @@ import { getSnapshotsByDate, getSnapshotPackages, getSnapshotErrata, - ErrataResponse, type EditContentRequestItem, type ValidateContentRequestItem, addUploads, @@ -82,47 +85,42 @@ const buildContentListKey = ( '', )}${filterData?.statuses?.join('')}${filterData?.availableForArch}${filterData?.availableForVersion}${filterData?.search}`; -export const useFetchContent = (uuid: string, enabled = true) => { - const errorNotifier = useErrorNotification(); - return useQuery([CONTENT_ITEM_KEY, uuid], () => fetchContentItem(uuid), { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - onError: (err: any) => - errorNotifier( - 'Unable to find associated repository.', - 'An error occurred', - err, - 'fetch-content-error', - ), - keepPreviousData: true, +export const useFetchContent = (uuid: string, enabled = true) => + useQuery({ + queryKey: [CONTENT_ITEM_KEY, uuid], + queryFn: () => fetchContentItem(uuid), + meta: { + title: 'Unable to find associated repository.', + id: 'fetch-content-error', + }, + placeholderData: keepPreviousData, staleTime: 20000, enabled, }); -}; export const usePopularRepositoriesQuery = ( page: number, limit: number, filterData?: Partial, sortBy?: string, -) => { - const errorNotifier = useErrorNotification(); - return useQuery( - [POPULAR_REPOSITORIES_LIST_KEY, page, limit, sortBy, ...Object.values(filterData || {})], // NOTE: Update this if larger list!!!! - () => getPopularRepositories(page, limit, filterData, sortBy), - { - keepPreviousData: true, - staleTime: 20000, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - onError: (err: any) => - errorNotifier( - 'Unable to get popular repositories list', - 'An error occurred', - err, - 'popular-repository-error', - ), - }, - ); -}; +) => + useQuery({ + queryKey: [ + POPULAR_REPOSITORIES_LIST_KEY, + page, + limit, + sortBy, + ...Object.values(filterData || {}), + ], + // NOTE: Update this if larger list!!!! + queryFn: () => getPopularRepositories(page, limit, filterData, sortBy), + placeholderData: keepPreviousData, + staleTime: 20000, + meta: { + title: 'Unable to get popular repositories list', + id: 'popular-repository-error', + }, + }); export const useContentListQuery = ( page: number, @@ -132,36 +130,41 @@ export const useContentListQuery = ( contentOrigin: ContentOrigin[], enabled: boolean = true, polling: boolean = false, -) => { - const errorNotifier = useErrorNotification(); - return useQuery( +) => + useQuery({ // Below MUST match the "contentListKeyArray" seen below in the useDeleteContent. - [CONTENT_LIST_KEY, buildContentListKey(page, limit, sortBy, contentOrigin, filterData)], - () => getContentList(page, limit, filterData, sortBy, contentOrigin), - { - onError: (err) => { - errorNotifier( - 'Unable to get repositories list', - 'An error occurred', - err, - 'content-list-error', - ); - }, - refetchInterval: polling ? CONTENT_LIST_POLLING_TIME : undefined, - refetchIntervalInBackground: false, // This prevents endless polling when our app isn't the focus tab in a browser - refetchOnWindowFocus: polling, // If polling and navigate to another tab, on refocus, we want to poll once more. (This is based off of the stalestime below) - keepPreviousData: true, - staleTime: 20000, - enabled, - }, - ); -}; + queryKey: [ + CONTENT_LIST_KEY, + buildContentListKey(page, limit, sortBy, contentOrigin, filterData), + ], + + queryFn: () => getContentList(page, limit, filterData, sortBy, contentOrigin), + + meta: { + title: 'Unable to get repositories list', + id: 'content-list-error', + }, + + refetchInterval: polling ? CONTENT_LIST_POLLING_TIME : undefined, + + // This prevents endless polling when our app isn't the focus tab in a browser + refetchIntervalInBackground: false, + + // If polling and navigate to another tab, on refocus, we want to poll once more. (This is based off of the stalestime below) + refetchOnWindowFocus: polling, + + placeholderData: keepPreviousData, + staleTime: 20000, + enabled, + }); export const useAddContentQuery = (request: CreateContentRequest) => { const queryClient = useQueryClient(); const errorNotifier = useErrorNotification(); const { notify } = useNotification(); - return useMutation(() => AddContentListItems(request.filter((item) => !!item)), { + return useMutation({ + mutationFn: () => AddContentListItems(request.filter((item) => !!item)), + onSuccess: (data: CreateContentRequestResponse) => { const hasPending = (data as ContentItem[]).some(({ status }) => status === 'Pending'); @@ -184,6 +187,7 @@ export const useAddContentQuery = (request: CreateContentRequest) => { queryClient.invalidateQueries({ queryKey: [ADMIN_TASK_LIST_KEY] }); queryClient.invalidateQueries({ queryKey: [POPULAR_REPOSITORIES_LIST_KEY] }); }, + // eslint-disable-next-line @typescript-eslint/no-explicit-any onError: (err: any) => { errorNotifier( @@ -200,7 +204,9 @@ export const useAddUploadsQuery = (request: AddUploadRequest) => { const queryClient = useQueryClient(); const errorNotifier = useErrorNotification(); const { notify } = useNotification(); - return useMutation(() => addUploads(request), { + return useMutation({ + mutationFn: () => addUploads(request), + onSuccess: (data) => { const uploadCount = (request?.uploads?.length || 0) + (request?.artifacts?.length || 0); notify({ @@ -215,6 +221,7 @@ export const useAddUploadsQuery = (request: AddUploadRequest) => { queryClient.invalidateQueries({ queryKey: [CONTENT_LIST_KEY] }); queryClient.invalidateQueries({ queryKey: [ADMIN_TASK_LIST_KEY] }); }, + // eslint-disable-next-line @typescript-eslint/no-explicit-any onError: (err: any) => { errorNotifier( @@ -244,11 +251,15 @@ export const useAddPopularRepositoryQuery = ( ...Object.values(filterData || {}), ]; const filteredRequest = request.filter((item) => !!item); - return useMutation(() => AddContentListItems(filteredRequest), { + return useMutation({ + mutationFn: () => AddContentListItems(filteredRequest), + onMutate: async () => { const { name } = filteredRequest[0]; // Cancel any outgoing refetches (so they don't overwrite our optimistic update) - await queryClient.cancelQueries(popularRepositoriesKeyArray); + await queryClient.cancelQueries({ + queryKey: popularRepositoriesKeyArray, + }); // Snapshot the previous value const previousPopularData: Partial = queryClient.getQueryData(popularRepositoriesKeyArray) || {}; @@ -264,6 +275,7 @@ export const useAddPopularRepositoryQuery = ( })); return { previousData: previousPopularData }; }, + onSuccess: (data: CreateContentRequestResponse) => { const hasPending = (data as ContentItem[]).some(({ status }) => status === 'Pending'); notify({ @@ -278,6 +290,7 @@ export const useAddPopularRepositoryQuery = ( queryClient.invalidateQueries({ queryKey: [ADMIN_TASK_LIST_KEY] }); queryClient.invalidateQueries({ queryKey: [POPULAR_REPOSITORIES_LIST_KEY] }); }, + onError: (err, _newData, context) => { if (context) { const { previousData } = context as { @@ -299,7 +312,9 @@ export const useEditContentQuery = (request: EditContentRequestItem) => { const queryClient = useQueryClient(); const errorNotifier = useErrorNotification(); const { notify } = useNotification(); - return useMutation(() => EditContentListItem(request), { + return useMutation({ + mutationFn: () => EditContentListItem(request), + onSuccess: () => { notify({ variant: AlertVariant.success, @@ -312,6 +327,7 @@ export const useEditContentQuery = (request: EditContentRequestItem) => { queryClient.invalidateQueries({ queryKey: [ADMIN_TASK_LIST_KEY] }); queryClient.invalidateQueries({ queryKey: [POPULAR_REPOSITORIES_LIST_KEY] }); }, + // eslint-disable-next-line @typescript-eslint/no-explicit-any onError: (err: any) => { errorNotifier( @@ -326,7 +342,9 @@ export const useEditContentQuery = (request: EditContentRequestItem) => { export const useValidateContentList = () => { const errorNotifier = useErrorNotification(); - return useMutation((request: ValidateContentRequestItem) => validateContentListItems(request), { + return useMutation({ + mutationFn: (request: ValidateContentRequestItem) => validateContentListItems(request), + onError: (err) => { errorNotifier( 'Error validating form fields', @@ -352,10 +370,13 @@ export const useDeletePopularRepositoryMutate = ( ...Object.values(filterData || {}), ]; const errorNotifier = useErrorNotification(); - return useMutation(deleteContentListItem, { + return useMutation({ + mutationFn: deleteContentListItem, onMutate: async (uuid: string) => { // Cancel any outgoing refetches (so they don't overwrite our optimistic update) - await queryClient.cancelQueries(popularRepositoriesKeyArray); + await queryClient.cancelQueries({ + queryKey: popularRepositoriesKeyArray, + }); // Snapshot the previous value const previousPopularData: Partial = queryClient.getQueryData(popularRepositoriesKeyArray) || {}; @@ -410,10 +431,13 @@ export const useDeleteContentItemMutate = ( buildContentListKey(page, perPage, sortString, contentOrigin, filterData), ]; const errorNotifier = useErrorNotification(); - return useMutation(deleteContentListItem, { + return useMutation({ + mutationFn: deleteContentListItem, onMutate: async (uuid: string) => { // Cancel any outgoing refetches (so they don't overwrite our optimistic update) - await queryClient.cancelQueries(contentListKeyArray); + await queryClient.cancelQueries({ + queryKey: contentListKeyArray, + }); // Snapshot the previous value const previousData: Partial = queryClient.getQueryData(contentListKeyArray) || {}; @@ -437,13 +461,16 @@ export const useDeleteContentItemMutate = ( const { previousData } = context as { previousData: ContentListResponse; }; - queryClient.setQueriesData([CONTENT_LIST_KEY], (data: Partial = {}) => { - if (data?.meta?.count) { - data.meta.count = previousData?.meta?.count - 1; - } + queryClient.setQueriesData( + { queryKey: [CONTENT_LIST_KEY] }, + (data: Partial = {}) => { + if (data?.meta?.count) { + data.meta.count = previousData?.meta?.count - 1; + } - return data; - }); + return data; + }, + ); queryClient.invalidateQueries({ queryKey: [CONTENT_LIST_KEY] }); queryClient.invalidateQueries({ queryKey: [ADMIN_TASK_LIST_KEY] }); queryClient.invalidateQueries({ queryKey: [POPULAR_REPOSITORIES_LIST_KEY] }); @@ -484,75 +511,80 @@ export const useBulkDeleteContentItemMutate = ( buildContentListKey(page, perPage, sortString, contentOrigin, filterData), ]; const errorNotifier = useErrorNotification(); - return useMutation( - (selected: Map) => { + return useMutation({ + mutationFn: (selected: Map) => { const uuids = Array.from(selected.keys()); return deleteContentListItems(uuids); }, - { - onMutate: async (selected: Map) => { - // Cancel any outgoing refetches (so they don't overwrite our optimistic update) - await queryClient.cancelQueries(contentListKeyArray); - // Snapshot the previous value - const previousData: Partial = - queryClient.getQueryData(contentListKeyArray) || {}; - const newMeta = previousData.meta - ? { - ...previousData.meta, - count: previousData.meta.count ? previousData.meta.count - selected.size : 1, - } - : undefined; - - // Optimistically update to the new value - queryClient.setQueryData(contentListKeyArray, () => ({ - ...previousData, - data: previousData.data?.filter((data) => !selected.has(data.uuid)), - meta: newMeta, - })); - // Return a context object with the snapshotted value - return { previousData, newMeta, queryClient }; - }, - onSuccess: (_data, _variables, context) => { - // Update all of the existing calls "count" to prevent number jumping on pagination - const { newMeta } = context as { - newMeta: Meta; + onMutate: async (selected: Map) => { + // Cancel any outgoing refetches (so they don't overwrite our optimistic update) + await queryClient.cancelQueries({ + queryKey: contentListKeyArray, + }); + // Snapshot the previous value + const previousData: Partial = + queryClient.getQueryData(contentListKeyArray) || {}; + + const newMeta = previousData.meta + ? { + ...previousData.meta, + count: previousData.meta.count ? previousData.meta.count - selected.size : 1, + } + : undefined; + + // Optimistically update to the new value + queryClient.setQueryData(contentListKeyArray, () => ({ + ...previousData, + data: previousData.data?.filter((data) => !selected.has(data.uuid)), + meta: newMeta, + })); + // Return a context object with the snapshotted value + return { previousData, newMeta, queryClient }; + }, + + onSuccess: (_data, _variables, context) => { + // Update all of the existing calls "count" to prevent number jumping on pagination + const { newMeta } = context as { + newMeta: Meta; + }; + queryClient.setQueriesData( + { queryKey: [CONTENT_LIST_KEY] }, + (data: Partial = {}) => { + if (data?.meta?.count) { + data.meta.count = newMeta?.count; + } + return data; + }, + ); + queryClient.invalidateQueries({ queryKey: [CONTENT_LIST_KEY] }); + queryClient.invalidateQueries({ queryKey: [ADMIN_TASK_LIST_KEY] }); + queryClient.invalidateQueries({ queryKey: [POPULAR_REPOSITORIES_LIST_KEY] }); + }, + + // If the mutation fails, use the context returned from onMutate to roll back + onError: (err: { response?: { data: ErrorResponse } }, _newData, context) => { + if (context) { + const { previousData } = context as { + previousData: ContentListResponse; }; - queryClient.setQueriesData( - [CONTENT_LIST_KEY], - (data: Partial = {}) => { - if (data?.meta?.count) { - data.meta.count = newMeta?.count; - } - return data; - }, - ); - queryClient.invalidateQueries({ queryKey: [CONTENT_LIST_KEY] }); - queryClient.invalidateQueries({ queryKey: [ADMIN_TASK_LIST_KEY] }); - queryClient.invalidateQueries({ queryKey: [POPULAR_REPOSITORIES_LIST_KEY] }); - }, - // If the mutation fails, use the context returned from onMutate to roll back - onError: (err: { response?: { data: ErrorResponse } }, _newData, context) => { - if (context) { - const { previousData } = context as { - previousData: ContentListResponse; - }; - queryClient.setQueryData(contentListKeyArray, previousData); - } - errorNotifier( - 'Error deleting items from content list', - 'An error occurred', - err, - 'bulk-delete-error', - ); - }, - }, - ); + queryClient.setQueryData(contentListKeyArray, previousData); + } + errorNotifier( + 'Error deleting items from content list', + 'An error occurred', + err, + 'bulk-delete-error', + ); + }, + }); }; export const useGetSnapshotsByDates = (uuids: string[], date: string) => { const errorNotifier = useErrorNotification(); - return useMutation(() => getSnapshotsByDate(uuids, date), { + return useMutation({ + mutationFn: () => getSnapshotsByDate(uuids, date), + onError: (err) => { errorNotifier( 'Error deleting items from content list', @@ -565,8 +597,10 @@ export const useGetSnapshotsByDates = (uuids: string[], date: string) => { }; export const useRepositoryParams = () => - useQuery([REPOSITORY_PARAMS_KEY], getRepositoryParams, { - keepPreviousData: true, + useQuery({ + queryKey: [REPOSITORY_PARAMS_KEY], + queryFn: getRepositoryParams, + placeholderData: keepPreviousData, staleTime: Infinity, }); @@ -596,26 +630,17 @@ export const useFetchGpgKey = () => { return { fetchGpgKey, isLoading }; }; -export const useGetSnapshotList = (uuid: string, page: number, limit: number, sortBy: string) => { - const errorNotifier = useErrorNotification(); - return useQuery( - [LIST_SNAPSHOTS_KEY, uuid, page, limit, sortBy], - () => getSnapshotList(uuid, page, limit, sortBy), - { - keepPreviousData: true, - staleTime: 60000, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - onError: (err: any) => { - errorNotifier( - 'Unable to find snapshots with the given UUID.', - 'An error occurred', - err, - 'snapshot-list-error', - ); - }, - }, - ); -}; +export const useGetSnapshotList = (uuid: string, page: number, limit: number, sortBy: string) => + useQuery({ + queryKey: [LIST_SNAPSHOTS_KEY, uuid, page, limit, sortBy], + queryFn: () => getSnapshotList(uuid, page, limit, sortBy), + placeholderData: keepPreviousData, + staleTime: 60000, + meta: { + title: 'Unable to find snapshots with the given UUID.', + id: 'snapshot-list-error', + }, + }); export const useGetPackagesQuery = ( uuid: string, @@ -623,52 +648,34 @@ export const useGetPackagesQuery = ( limit: number, searchQuery: string, sortBy?: string, -) => { - const errorNotifier = useErrorNotification(); - return useQuery( - [PACKAGES_KEY, uuid, page, limit, searchQuery, sortBy], - () => getPackages(uuid, page, limit, searchQuery, sortBy), - { - keepPreviousData: true, - staleTime: 60000, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - onError: (err: any) => { - errorNotifier( - 'Unable to find packages with the given UUID.', - 'An error occurred', - err, - 'packages-list-error', - ); - }, - }, - ); -}; +) => + useQuery({ + queryKey: [PACKAGES_KEY, uuid, page, limit, searchQuery, sortBy], + queryFn: () => getPackages(uuid, page, limit, searchQuery, sortBy), + placeholderData: keepPreviousData, + staleTime: 60000, + meta: { + title: 'Unable to find packages with the given UUID.', + id: 'packages-list-error', + }, + }); export const useGetSnapshotPackagesQuery = ( snap_uuid: string, page: number, limit: number, searchQuery: string, -) => { - const errorNotifier = useErrorNotification(); - return useQuery( - [SNAPSHOT_PACKAGES_KEY, snap_uuid, page, limit, searchQuery], - () => getSnapshotPackages(snap_uuid, page, limit, searchQuery), - { - keepPreviousData: true, - staleTime: 60000, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - onError: (err: any) => { - errorNotifier( - 'Unable to find packages with the given UUID.', - 'An error occurred', - err, - 'snapshot-package-list-error', - ); - }, - }, - ); -}; +) => + useQuery({ + queryKey: [SNAPSHOT_PACKAGES_KEY, snap_uuid, page, limit, searchQuery], + queryFn: () => getSnapshotPackages(snap_uuid, page, limit, searchQuery), + placeholderData: keepPreviousData, + staleTime: 60000, + meta: { + title: 'Unable to find packages with the given UUID.', + id: 'snapshot-package-list-error', + }, + }); export const useGetSnapshotErrataQuery = ( snap_uuid: string, @@ -678,31 +685,23 @@ export const useGetSnapshotErrataQuery = ( type: string[], severity: string[], sortBy: string, -) => { - const errorNotifier = useErrorNotification(); - return useQuery( - [SNAPSHOT_ERRATA_KEY, snap_uuid, page, limit, search, type, severity, sortBy], - () => getSnapshotErrata(snap_uuid, page, limit, search, type, severity, sortBy), - { - keepPreviousData: true, - staleTime: 60000, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - onError: (err: any) => { - errorNotifier( - 'Unable to find errata with the given UUID.', - 'An error occurred', - err, - 'snapshot-errata-list-error', - ); - }, - }, - ); -}; +) => + useQuery({ + queryKey: [SNAPSHOT_ERRATA_KEY, snap_uuid, page, limit, search, type, severity, sortBy], + queryFn: () => getSnapshotErrata(snap_uuid, page, limit, search, type, severity, sortBy), + placeholderData: keepPreviousData, + staleTime: 60000, + meta: { + title: 'Unable to find errata with the given UUID.', + id: 'snapshot-errata-list-error', + }, + }); export const useTriggerSnapshot = (queryClient: QueryClient) => { const errorNotifier = useErrorNotification(); const { notify } = useNotification(); - return useMutation(triggerSnapshot, { + return useMutation({ + mutationFn: triggerSnapshot, onSuccess: () => { notify({ variant: AlertVariant.success, @@ -738,10 +737,13 @@ export const useIntrospectRepositoryMutate = ( const errorNotifier = useErrorNotification(); const { notify } = useNotification(); let hasSnapshottingEnabled: boolean | undefined = false; - return useMutation(introspectRepository, { + return useMutation({ + mutationFn: introspectRepository, onMutate: async (item: IntrospectRepositoryRequestItem) => { // Cancel any outgoing refetches (so they don't overwrite our optimistic update) - await queryClient.cancelQueries(contentListKeyArray); + await queryClient.cancelQueries({ + queryKey: contentListKeyArray, + }); // Snapshot the previous value const previousData: Partial = queryClient.getQueryData(contentListKeyArray) || {}; @@ -795,40 +797,38 @@ export const useIntrospectRepositoryMutate = ( export const useGetRepoConfigFileQuery = (repo_uuid: string, snapshot_uuid: string) => { const errorNotifier = useErrorNotification(); - return useMutation( - [REPO_CONFIG_FILE_KEY, repo_uuid, snapshot_uuid], - async () => await getRepoConfigFile(snapshot_uuid), - { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - onError: (err: any) => { - errorNotifier( - 'Unable to find config.repo with the given UUID.', - 'An error occurred', - err, - 'repo-config-error', - ); - }, - }, - ); + return useMutation({ + mutationKey: [REPO_CONFIG_FILE_KEY, repo_uuid, snapshot_uuid], + mutationFn: async () => await getRepoConfigFile(snapshot_uuid), + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + onError: (err: any) => { + errorNotifier( + 'Unable to find config.repo with the given UUID.', + 'An error occurred', + err, + 'repo-config-error', + ); + }, + }); }; export const useGetLatestRepoConfigFileQuery = (repo_uuid: string) => { const errorNotifier = useErrorNotification(); - return useMutation( - [LATEST_REPO_CONFIG_FILE_KEY, repo_uuid], - async () => await getLatestRepoConfigFile(repo_uuid), - { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - onError: (err: any) => { - errorNotifier( - 'Unable to find config.repo with the given UUID.', - 'An error occurred', - err, - 'repo-config-error', - ); - }, - }, - ); + return useMutation({ + mutationKey: [LATEST_REPO_CONFIG_FILE_KEY, repo_uuid], + mutationFn: async () => await getLatestRepoConfigFile(repo_uuid), + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + onError: (err: any) => { + errorNotifier( + 'Unable to find config.repo with the given UUID.', + 'An error occurred', + err, + 'repo-config-error', + ); + }, + }); }; export const useBulkDeleteSnapshotsMutate = ( @@ -840,9 +840,13 @@ export const useBulkDeleteSnapshotsMutate = ( const snapshotListKeyArray = [LIST_SNAPSHOTS_KEY, repoUuid]; const errorNotifier = useErrorNotification(); - return useMutation(() => deleteSnapshots(repoUuid, uuids), { + return useMutation({ + mutationFn: () => deleteSnapshots(repoUuid, uuids), + onMutate: async (checkedSnapshots: Set) => { - await queryClient.cancelQueries(snapshotListKeyArray); + await queryClient.cancelQueries({ + queryKey: snapshotListKeyArray, + }); const previousData: Partial = queryClient.getQueryData(snapshotListKeyArray) || {}; @@ -860,12 +864,13 @@ export const useBulkDeleteSnapshotsMutate = ( })); return { previousData, newMeta, queryClient }; }, + onSuccess: (_data, _variables, context) => { const { newMeta } = context as { newMeta: Meta; }; queryClient.setQueriesData( - [LIST_SNAPSHOTS_KEY], + { queryKey: [LIST_SNAPSHOTS_KEY] }, (data: Partial = {}) => { if (data?.meta?.count) { data.meta.count = newMeta?.count; @@ -886,6 +891,7 @@ export const useBulkDeleteSnapshotsMutate = ( queryClient.invalidateQueries({ queryKey: [REPO_CONFIG_FILE_KEY] }); queryClient.invalidateQueries({ queryKey: [LATEST_REPO_CONFIG_FILE_KEY] }); }, + onError: (err: { response?: { data: ErrorResponse } }, _newData, context) => { if (context) { const { previousData } = context as { diff --git a/src/services/Subscriptions/SubscriptionQueries.ts b/src/services/Subscriptions/SubscriptionQueries.ts index 0832d9cb3..ec9ef3605 100644 --- a/src/services/Subscriptions/SubscriptionQueries.ts +++ b/src/services/Subscriptions/SubscriptionQueries.ts @@ -1,5 +1,4 @@ -import { Subscriptions, getSubscriptions, getEphemeralSubscriptions } from './SubscriptionApi'; -import useErrorNotification from 'Hooks/useErrorNotification'; +import { getSubscriptions, getEphemeralSubscriptions } from './SubscriptionApi'; import useIsEphemeralEnv from 'Hooks/useIsEphemeralEnv'; import { useMemo } from 'react'; import { useQuery } from '@tanstack/react-query'; @@ -7,20 +6,18 @@ import { useQuery } from '@tanstack/react-query'; const SUBSCRIPTION_CHECK_KEY = 'SUBSCRIPTION_CHECK_KEY'; export const useFetchSubscriptionsQuery = () => { - const errorNotifier = useErrorNotification(); const isEphemeral = useIsEphemeralEnv(); const queryFn = useMemo( () => (isEphemeral ? getEphemeralSubscriptions() : getSubscriptions()), [isEphemeral], ); - return useQuery([SUBSCRIPTION_CHECK_KEY], () => queryFn, { - onError: (err) => - errorNotifier( - 'Error fetching subscriptions', - 'An error occurred', - err, - 'fetch-subscriptions-error', - ), + return useQuery({ + queryKey: [SUBSCRIPTION_CHECK_KEY], + queryFn: () => queryFn, + meta: { + title: 'Error fetching subscriptions', + id: 'fetch-subscriptions-error', + }, }); }; diff --git a/src/services/Systems/SystemsQueries.ts b/src/services/Systems/SystemsQueries.ts index e407d52d0..90efe2270 100644 --- a/src/services/Systems/SystemsQueries.ts +++ b/src/services/Systems/SystemsQueries.ts @@ -4,13 +4,10 @@ import { getSystemsList, listSystemsByTemplateId, deleteTemplateFromSystems, - type IDSystemsCollectionResponse, - type SystemsCollectionResponse, type SystemsFilters, - TagsResponse, listTags, } from './SystemsApi'; -import { useMutation, useQuery, type QueryClient } from '@tanstack/react-query'; +import { keepPreviousData, useMutation, useQuery, type QueryClient } from '@tanstack/react-query'; import useNotification from 'Hooks/useNotification'; import { AlertVariant } from '@patternfly/react-core'; @@ -23,36 +20,29 @@ export const useSystemsListQuery = ( searchQuery: string, filter: SystemsFilters, sortBy?: string, -) => { - const errorNotifier = useErrorNotification(); - return useQuery( - [GET_SYSTEMS_KEY, page, limit, searchQuery, filter, sortBy], - () => getSystemsList(page, limit, searchQuery, filter, sortBy), - { - keepPreviousData: true, - staleTime: 60000, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - onError: (err: any) => { - errorNotifier('Unable to get systems.', 'An error occurred', err, 'systems-list-error'); - }, +) => + useQuery({ + queryKey: [GET_SYSTEMS_KEY, page, limit, searchQuery, filter, sortBy], + queryFn: () => getSystemsList(page, limit, searchQuery, filter, sortBy), + placeholderData: keepPreviousData, + staleTime: 60000, + meta: { + title: 'Unable to get systems.', + id: 'systems-list-error', }, - ); -}; + }); -export const useTagsQuery = (page: number, limit: number, search?: string) => { - const errorNotifier = useErrorNotification(); - return useQuery( - ['TAGS', page, limit, search], - () => listTags(page, limit, search), - { - keepPreviousData: false, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - onError: (err: any) => { - errorNotifier('Unable to get tags', 'An error occurred', err, 'tags-err'); - }, +export const useTagsQuery = (page: number, limit: number, search?: string) => + useQuery({ + queryKey: ['TAGS', page, limit, search], + queryFn: () => listTags(page, limit, search), + placeholderData: keepPreviousData, + + meta: { + title: 'Unable to get tags', + id: 'tags-err', }, - ); -}; + }); export const useListSystemsByTemplateId = ( id: string, @@ -60,29 +50,20 @@ export const useListSystemsByTemplateId = ( limit: number, searchQuery: string, sortBy?: string, -) => { - const errorNotifier = useErrorNotification(); - return useQuery( - [GET_TEMPLATE_SYSTEMS_KEY, id, page, limit, searchQuery, sortBy], - () => listSystemsByTemplateId(id, page, limit, searchQuery, sortBy), - { - keepPreviousData: true, - staleTime: 25_000, - refetchOnWindowFocus: 'always', - refetchOnMount: 'always', - refetchInterval: 20_000, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - onError: (err: any) => { - errorNotifier( - `Unable to find systems with the given template id: ${id}`, - 'An error occurred', - err, - 'systems-list-error', - ); - }, +) => + useQuery({ + queryKey: [GET_TEMPLATE_SYSTEMS_KEY, id, page, limit, searchQuery, sortBy], + queryFn: () => listSystemsByTemplateId(id, page, limit, searchQuery, sortBy), + placeholderData: keepPreviousData, + staleTime: 25_000, + refetchOnWindowFocus: 'always', + refetchOnMount: 'always', + refetchInterval: 20_000, + meta: { + title: `Unable to find systems with the given template id: ${id}`, + id: 'systems-list-error', }, - ); -}; + }); export const useAddTemplateToSystemsQuery = ( queryClient: QueryClient, @@ -91,7 +72,9 @@ export const useAddTemplateToSystemsQuery = ( ) => { const errorNotifier = useErrorNotification(); const { notify } = useNotification(); - return useMutation(() => addTemplateToSystems(templateId, systemUUIDs), { + return useMutation({ + mutationFn: () => addTemplateToSystems(templateId, systemUUIDs), + onSuccess: () => { notify({ variant: AlertVariant.success, @@ -101,6 +84,7 @@ export const useAddTemplateToSystemsQuery = ( queryClient.invalidateQueries({ queryKey: [GET_TEMPLATE_SYSTEMS_KEY] }); queryClient.invalidateQueries({ queryKey: [GET_SYSTEMS_KEY] }); }, + // eslint-disable-next-line @typescript-eslint/no-explicit-any onError: (err: any) => { errorNotifier( @@ -115,7 +99,8 @@ export const useAddTemplateToSystemsQuery = ( export const useDeleteTemplateFromSystems = (queryClient: QueryClient) => { const errorNotifier = useErrorNotification(); - return useMutation(deleteTemplateFromSystems, { + return useMutation({ + mutationFn: deleteTemplateFromSystems, onSuccess: () => { queryClient.invalidateQueries({ queryKey: [GET_SYSTEMS_KEY] }); queryClient.invalidateQueries({ queryKey: [GET_TEMPLATE_SYSTEMS_KEY] }); diff --git a/src/services/Templates/TemplateQueries.ts b/src/services/Templates/TemplateQueries.ts index 7c49d641b..663d91d2b 100644 --- a/src/services/Templates/TemplateQueries.ts +++ b/src/services/Templates/TemplateQueries.ts @@ -1,9 +1,8 @@ -import { QueryClient, useMutation, useQuery } from '@tanstack/react-query'; +import { keepPreviousData, QueryClient, useMutation, useQuery } from '@tanstack/react-query'; import useErrorNotification from 'Hooks/useErrorNotification'; import { TemplateFilterData, - TemplateItem, fetchTemplate, getTemplates, TemplateCollectionResponse, @@ -12,7 +11,6 @@ import { deleteTemplateItem, EditTemplateRequest, EditTemplate, - type SnapshotRpmCollectionResponse, getTemplatePackages, getTemplateErrata, getTemplateSnapshots, @@ -20,7 +18,6 @@ import { } from './TemplateApi'; import useNotification from 'Hooks/useNotification'; import { AlertVariant } from '@patternfly/react-core'; -import { ErrataResponse, SnapshotListResponse } from 'services/Content/ContentApi'; export const FETCH_TEMPLATE_KEY = 'FETCH_TEMPLATE_KEY'; export const GET_TEMPLATES_KEY = 'GET_TEMPLATES_KEY'; @@ -35,7 +32,9 @@ const TEMPLATE_FETCH_POLLING_TIME = 5000; // 5 seconds export const useEditTemplateQuery = (queryClient: QueryClient, request: EditTemplateRequest) => { const errorNotifier = useErrorNotification(); const { notify } = useNotification(); - return useMutation(() => EditTemplate(request), { + return useMutation({ + mutationFn: () => EditTemplate(request), + onSuccess: () => { notify({ variant: AlertVariant.success, @@ -49,6 +48,7 @@ export const useEditTemplateQuery = (queryClient: QueryClient, request: EditTemp queryClient.invalidateQueries({ queryKey: [TEMPLATES_FOR_SNAPSHOTS] }); queryClient.invalidateQueries({ queryKey: [TEMPLATE_SNAPSHOTS_KEY] }); }, + // eslint-disable-next-line @typescript-eslint/no-explicit-any onError: (err: any) => { errorNotifier( @@ -61,52 +61,36 @@ export const useEditTemplateQuery = (queryClient: QueryClient, request: EditTemp }); }; -export const useFetchTemplate = ( - uuid: string, - enabled: boolean = true, - polling: boolean = false, -) => { - const errorNotifier = useErrorNotification(); - return useQuery([FETCH_TEMPLATE_KEY, uuid], () => fetchTemplate(uuid), { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - onError: (err: any) => - errorNotifier( - 'Unable to find associated content template.', - 'An error occurred', - err, - 'fetch-template-error', - ), +export const useFetchTemplate = (uuid: string, enabled: boolean = true, polling: boolean = false) => + useQuery({ + queryKey: [FETCH_TEMPLATE_KEY, uuid], + queryFn: () => fetchTemplate(uuid), + meta: { + title: 'Unable to find associated content template.', + id: 'fetch-template-error', + }, refetchInterval: polling ? TEMPLATE_FETCH_POLLING_TIME : undefined, - keepPreviousData: true, + placeholderData: keepPreviousData, staleTime: 20000, enabled, }); -}; export const useFetchTemplatePackages = ( page: number, limit: number, search: string, uuid: string, -) => { - const errorNotifier = useErrorNotification(); - return useQuery( - [GET_TEMPLATE_PACKAGES_KEY, page, limit, search, uuid], - () => getTemplatePackages(page, limit, search, uuid), - { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - onError: (err: any) => - errorNotifier( - 'Unable to find associated packages for content template.', - 'An error occurred', - err, - 'fetch-packages-template-error', - ), - keepPreviousData: true, - staleTime: 60000, +) => + useQuery({ + queryKey: [GET_TEMPLATE_PACKAGES_KEY, page, limit, search, uuid], + queryFn: () => getTemplatePackages(page, limit, search, uuid), + meta: { + title: 'Unable to find associated packages for content template.', + id: 'fetch-packages-template-error', }, - ); -}; + placeholderData: keepPreviousData, + staleTime: 60000, + }); export const useFetchTemplateErrataQuery = ( uuid: string, @@ -116,26 +100,17 @@ export const useFetchTemplateErrataQuery = ( type: string[], severity: string[], sortBy: string, -) => { - const errorNotifier = useErrorNotification(); - return useQuery( - [TEMPLATE_ERRATA_KEY, uuid, page, limit, search, type, severity, sortBy], - () => getTemplateErrata(uuid, page, limit, search, type, severity, sortBy), - { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - onError: (err: any) => { - errorNotifier( - 'Unable to find errata with the given UUID.', - 'An error occurred', - err, - 'Template-errata-list-error', - ); - }, - keepPreviousData: true, - staleTime: 60000, +) => + useQuery({ + queryKey: [TEMPLATE_ERRATA_KEY, uuid, page, limit, search, type, severity, sortBy], + queryFn: () => getTemplateErrata(uuid, page, limit, search, type, severity, sortBy), + meta: { + title: 'Unable to find errata with the given UUID.', + id: 'Template-errata-list-error', }, - ); -}; + placeholderData: keepPreviousData, + staleTime: 60000, + }); export const useFetchTemplateSnapshotsQuery = ( uuid: string, @@ -143,45 +118,29 @@ export const useFetchTemplateSnapshotsQuery = ( limit: number, search: string, sortBy: string, -) => { - const errorNotifier = useErrorNotification(); - return useQuery( - [TEMPLATE_SNAPSHOTS_KEY, uuid, page, limit, search, sortBy], - () => getTemplateSnapshots(uuid, page, limit, search, sortBy), - { - onError: (err) => { - errorNotifier( - 'Unable to find snapshots for the given template UUID.', - 'An error occurred', - err, - 'template-snapshots-list-error', - ); - }, - keepPreviousData: true, - staleTime: 60000, +) => + useQuery({ + queryKey: [TEMPLATE_SNAPSHOTS_KEY, uuid, page, limit, search, sortBy], + queryFn: () => getTemplateSnapshots(uuid, page, limit, search, sortBy), + meta: { + title: 'Unable to find snapshots for the given template UUID.', + id: 'template-snapshots-list-error', }, - ); -}; + placeholderData: keepPreviousData, + staleTime: 60000, + }); -export const useFetchTemplatesForSnapshots = (repoUuid: string, snapshotUuids: string[]) => { - const errorNotifier = useErrorNotification(); - return useQuery( - [TEMPLATES_FOR_SNAPSHOTS, repoUuid, ...snapshotUuids], - () => getTemplatesForSnapshots(snapshotUuids), - { - onError: (err) => { - errorNotifier( - 'Unable to find templates for the given snapshots.', - 'An error occurred', - err, - 'template-for-snapshots-error', - ); - }, - keepPreviousData: true, - staleTime: 20000, +export const useFetchTemplatesForSnapshots = (repoUuid: string, snapshotUuids: string[]) => + useQuery({ + queryKey: [TEMPLATES_FOR_SNAPSHOTS, repoUuid, ...snapshotUuids], + queryFn: () => getTemplatesForSnapshots(snapshotUuids), + meta: { + title: 'Unable to find templates for the given snapshots.', + id: 'template-for-snapshots-error', }, - ); -}; + placeholderData: keepPreviousData, + staleTime: 20000, + }); export const useTemplateList = ( page: number, @@ -189,32 +148,26 @@ export const useTemplateList = ( sortBy: string, filterData: TemplateFilterData, polling: boolean = false, -) => { - const errorNotifier = useErrorNotification(); - return useQuery( +) => + useQuery({ // Below MUST match the "templateListKeyArray" seen below (once written) in the useDeleteTemplate. - [GET_TEMPLATES_KEY, page, limit, sortBy, ...Object.values(filterData)], - () => getTemplates(page, limit, sortBy, filterData), - { - onError: (err) => { - errorNotifier( - 'Unable to get content template list', - 'An error occurred', - err, - 'template-list-error', - ); - }, - refetchInterval: polling ? TEMPLATE_LIST_POLLING_TIME : undefined, - keepPreviousData: true, - staleTime: 20000, + queryKey: [GET_TEMPLATES_KEY, page, limit, sortBy, ...Object.values(filterData)], + queryFn: () => getTemplates(page, limit, sortBy, filterData), + meta: { + title: 'Unable to get content template list', + id: 'template-list-error', }, - ); -}; + refetchInterval: polling ? TEMPLATE_LIST_POLLING_TIME : undefined, + placeholderData: keepPreviousData, + staleTime: 20000, + }); export const useCreateTemplateQuery = (queryClient: QueryClient, request: TemplateRequest) => { const errorNotifier = useErrorNotification(); const { notify } = useNotification(); - return useMutation(() => createTemplate(request), { + return useMutation({ + mutationFn: () => createTemplate(request), + onSuccess: () => { notify({ variant: AlertVariant.success, @@ -224,6 +177,7 @@ export const useCreateTemplateQuery = (queryClient: QueryClient, request: Templa queryClient.invalidateQueries({ queryKey: [GET_TEMPLATES_KEY] }); queryClient.invalidateQueries({ queryKey: [FETCH_TEMPLATE_KEY] }); }, + // eslint-disable-next-line @typescript-eslint/no-explicit-any onError: (err: any) => { errorNotifier( @@ -240,10 +194,11 @@ export const useDeleteTemplateItemMutate = (queryClient: QueryClient) => { // Below MUST match the "useTemplateList" key found above or updates will fail. const contentListKeyArray = [GET_TEMPLATES_KEY]; const errorNotifier = useErrorNotification(); - return useMutation(deleteTemplateItem, { + return useMutation({ + mutationFn: deleteTemplateItem, onMutate: async (uuid: string) => { // Cancel any outgoing refetches (so they don't overwrite our optimistic update) - await queryClient.cancelQueries(contentListKeyArray); + await queryClient.cancelQueries({ queryKey: contentListKeyArray }); // Snapshot the previous value const previousData: Partial = queryClient.getQueryData(contentListKeyArray) || {}; @@ -268,7 +223,7 @@ export const useDeleteTemplateItemMutate = (queryClient: QueryClient) => { previousData: TemplateCollectionResponse; }; queryClient.setQueriesData( - [GET_TEMPLATES_KEY], + { queryKey: [GET_TEMPLATES_KEY] }, (data: Partial = {}) => { if (data?.meta?.count) { data.meta.count = previousData?.meta?.count - 1;