chore(deps): update dependency @tanstack/react-query to v5 (#2404)

* fix(deps): update dependency @tanstack/react-query to v5

* chore: update for compatibility with React Query v5

* chore: update for compatibility with React Query v5

* test: update tests

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Braden MacDonald <braden@opencraft.com>
This commit is contained in:
renovate[bot]
2025-09-17 16:10:08 -07:00
committed by GitHub
parent 61c87fe6a6
commit b95b3a60ad
23 changed files with 110 additions and 124 deletions

29
package-lock.json generated
View File

@@ -41,7 +41,7 @@
"@openedx/paragon": "^23.5.0",
"@redux-devtools/extension": "^3.3.0",
"@reduxjs/toolkit": "1.9.7",
"@tanstack/react-query": "4.40.1",
"@tanstack/react-query": "5.89.0",
"@tinymce/tinymce-react": "^3.14.0",
"classnames": "2.5.1",
"codemirror": "^6.0.0",
@@ -5889,9 +5889,9 @@
}
},
"node_modules/@tanstack/query-core": {
"version": "4.40.0",
"resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-4.40.0.tgz",
"integrity": "sha512-7MJTtZkCSuehMC7IxMOCGsLvHS3jHx4WjveSrGsG1Nc1UQLjaFwwkpLA2LmPfvOAxnH4mszMOBFD6LlZE+aB+Q==",
"version": "5.89.0",
"resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.89.0.tgz",
"integrity": "sha512-joFV1MuPhSLsKfTzwjmPDrp8ENfZ9N23ymFu07nLfn3JCkSHy0CFgsyhHTJOmWaumC/WiNIKM0EJyduCF/Ih/Q==",
"license": "MIT",
"funding": {
"type": "github",
@@ -5899,30 +5899,19 @@
}
},
"node_modules/@tanstack/react-query": {
"version": "4.40.1",
"resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-4.40.1.tgz",
"integrity": "sha512-mgD07S5N8e5v81CArKDWrHE4LM7HxZ9k/KLeD3+NUD9WimGZgKIqojUZf/rXkfAMYZU9p0Chzj2jOXm7xpgHHQ==",
"version": "5.89.0",
"resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.89.0.tgz",
"integrity": "sha512-SXbtWSTSRXyBOe80mszPxpEbaN4XPRUp/i0EfQK1uyj3KCk/c8FuPJNIRwzOVe/OU3rzxrYtiNabsAmk1l714A==",
"license": "MIT",
"dependencies": {
"@tanstack/query-core": "4.40.0",
"use-sync-external-store": "^1.2.0"
"@tanstack/query-core": "5.89.0"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/tannerlinsley"
},
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0",
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0",
"react-native": "*"
},
"peerDependenciesMeta": {
"react-dom": {
"optional": true
},
"react-native": {
"optional": true
}
"react": "^18 || ^19"
}
},
"node_modules/@testing-library/dom": {

View File

@@ -64,7 +64,7 @@
"@openedx/paragon": "^23.5.0",
"@redux-devtools/extension": "^3.3.0",
"@reduxjs/toolkit": "1.9.7",
"@tanstack/react-query": "4.40.1",
"@tanstack/react-query": "5.89.0",
"@tinymce/tinymce-react": "^3.14.0",
"classnames": "2.5.1",
"codemirror": "^6.0.0",

View File

@@ -435,8 +435,8 @@ const ContentTagsCollapsible = ({
onKeyDown={handleSelectOnKeyDown}
ref={/** @type {React.RefObject} */(selectRef)}
isMulti
isLoading={updateTags.isLoading}
isDisabled={updateTags.isLoading}
isLoading={updateTags.isPending}
isDisabled={updateTags.isPending}
name="tags-select"
placeholder={intl.formatMessage(messages.collapsibleAddTagsPlaceholderText)}
isSearchable

View File

@@ -719,14 +719,16 @@ describe('<ContentTagsDrawer />', () => {
await waitFor(() => expect(axiosMock.history.put[0].url).toEqual(url));
expect(mockInvalidateQueries).toHaveBeenCalledTimes(5);
expect(mockInvalidateQueries).toHaveBeenNthCalledWith(5, [
'contentLibrary',
'lib:org:lib',
'content',
'container',
containerId,
'children',
]);
expect(mockInvalidateQueries).toHaveBeenNthCalledWith(5, {
queryKey: [
'contentLibrary',
'lib:org:lib',
'content',
'container',
containerId,
'children',
],
});
});
});

View File

@@ -1,4 +1,3 @@
// @ts-check
import { useMemo } from 'react';
import { getConfig } from '@edx/frontend-platform';
import {
@@ -8,6 +7,7 @@ import {
useQueryClient,
} from '@tanstack/react-query';
import { useParams } from 'react-router';
import { TagData, TagListData } from '@src/taxonomy/data/types';
import {
getTaxonomyTagsData,
getContentTaxonomyTagsData,
@@ -17,18 +17,16 @@ import {
} from './api';
import { libraryAuthoringQueryKeys, libraryQueryPredicate, xblockQueryKeys } from '../../library-authoring/data/apiHooks';
import { getLibraryId } from '../../generic/key-utils';
/** @typedef {import("../../taxonomy/data/types.js").TagListData} TagListData */
/** @typedef {import("../../taxonomy/data/types.js").TagData} TagData */
import { UpdateTagsData } from './types';
/**
* Builds the query to get the taxonomy tags
* @param {number} taxonomyId The id of the taxonomy to fetch tags for
* @param {string|null} parentTag The tag whose children we're loading, if any
* @param {string} searchTerm The term passed in to perform search on tags
* @param {number} numPages How many pages of tags to load at this level
* @param taxonomyId The id of the taxonomy to fetch tags for
* @param parentTag The tag whose children we're loading, if any
* @param searchTerm The term passed in to perform search on tags
* @param numPages How many pages of tags to load at this level
*/
export const useTaxonomyTagsData = (taxonomyId, parentTag = null, numPages = 1, searchTerm = '') => {
export const useTaxonomyTagsData = (taxonomyId: number, parentTag: string | null = null, numPages = 1, searchTerm = '') => {
const queryClient = useQueryClient();
const queryFn = async ({ queryKey }) => {
@@ -36,8 +34,7 @@ export const useTaxonomyTagsData = (taxonomyId, parentTag = null, numPages = 1,
return getTaxonomyTagsData(taxonomyId, { parentTag: parentTag || '', searchTerm, page });
};
/** @type {{queryKey: any[], queryFn: typeof queryFn, staleTime: number}[]} */
const queries = [];
const queries: { queryKey: any[]; queryFn: typeof queryFn; staleTime: number }[] = [];
for (let page = 1; page <= numPages; page++) {
queries.push(
{ queryKey: ['taxonomyTags', taxonomyId, parentTag, page, searchTerm], queryFn, staleTime: Infinity },
@@ -54,8 +51,7 @@ export const useTaxonomyTagsData = (taxonomyId, parentTag = null, numPages = 1,
const preLoadedData = new Map();
const newTags = dataPages.map(result => {
/** @type {TagData[]} */
const simplifiedTagsList = [];
const simplifiedTagsList: TagData[] = [];
result.data?.results?.forEach((tag) => {
if (tag.parentValue === parentTag) {
@@ -73,8 +69,7 @@ export const useTaxonomyTagsData = (taxonomyId, parentTag = null, numPages = 1,
// Store the pre-loaded descendants into the query cache:
preLoadedData.forEach((tags, parentValue) => {
const queryKey = ['taxonomyTags', taxonomyId, parentValue, 1, searchTerm];
/** @type {TagListData} */
const cachedData = {
const cachedData: TagListData = {
next: '',
previous: '',
count: tags.length,
@@ -101,9 +96,9 @@ export const useTaxonomyTagsData = (taxonomyId, parentTag = null, numPages = 1,
/**
* Builds the query to get the taxonomy tags applied to the content object
* @param {string} contentId The ID of the content object to fetch the applied tags for (e.g. an XBlock usage key)
* @param contentId The ID of the content object to fetch the applied tags for (e.g. an XBlock usage key)
*/
export const useContentTaxonomyTagsData = (contentId) => (
export const useContentTaxonomyTagsData = (contentId: string) => (
useQuery({
queryKey: ['contentTaxonomyTags', contentId],
queryFn: () => getContentTaxonomyTagsData(contentId),
@@ -112,10 +107,10 @@ export const useContentTaxonomyTagsData = (contentId) => (
/**
* Builds the query to get meta data about the content object
* @param {string} contentId The id of the content object
* @param {boolean} enabled Flag to enable/disable the query
* @param contentId The id of the content object
* @param enabled Flag to enable/disable the query
*/
export const useContentData = (contentId, enabled) => (
export const useContentData = (contentId: string, enabled: boolean) => (
useQuery({
queryKey: ['contentData', contentId],
queryFn: enabled ? () => getContentData(contentId) : undefined,
@@ -125,24 +120,17 @@ export const useContentData = (contentId, enabled) => (
/**
* Builds the mutation to update the tags applied to the content object
* @param {string} contentId The id of the content object to update tags for
* @param contentId The id of the content object to update tags for
*/
export const useContentTaxonomyTagsUpdater = (contentId) => {
export const useContentTaxonomyTagsUpdater = (contentId: string) => {
const queryClient = useQueryClient();
const unitIframe = window.frames['xblock-iframe'];
const { containerId } = useParams();
return useMutation({
/**
* @type {import("@tanstack/react-query").MutateFunction<
* any,
* any,
* {
* tagsData: Promise<import("./types.js").UpdateTagsData[]>
* }
* >}
*/
mutationFn: ({ tagsData }) => updateContentTaxonomyTags(contentId, tagsData),
mutationFn: ({ tagsData }: { tagsData: Promise<UpdateTagsData[]> }) => (
updateContentTaxonomyTags(contentId, tagsData)
),
onSettled: () => {
queryClient.invalidateQueries({ queryKey: ['contentTaxonomyTags', contentId] });
/// Invalidate query with pattern on course outline
@@ -157,13 +145,13 @@ export const useContentTaxonomyTagsUpdater = (contentId) => {
// Obtain library id from contentId
const libraryId = getLibraryId(contentId);
// Invalidate component metadata to update tags count
queryClient.invalidateQueries(xblockQueryKeys.componentMetadata(contentId));
queryClient.invalidateQueries({ queryKey: xblockQueryKeys.componentMetadata(contentId) });
// Invalidate content search to update tags count
queryClient.invalidateQueries(['content_search'], { predicate: (query) => libraryQueryPredicate(query, libraryId) });
queryClient.invalidateQueries({ queryKey: ['content_search'], predicate: (query) => libraryQueryPredicate(query, libraryId) });
// If the tags for an item were edited from a container page (Unit, Subsection, Section),
// invalidate children query to fetch count again.
if (containerId) {
queryClient.invalidateQueries(libraryAuthoringQueryKeys.containerChildren(containerId));
queryClient.invalidateQueries({ queryKey: libraryAuthoringQueryKeys.containerChildren(containerId) });
}
}
},

View File

@@ -32,14 +32,14 @@ export const OutOfSyncAlert: React.FC<OutOfSyncAlertProps> = ({
onReview,
}) => {
const intl = useIntl();
const { data, isLoading } = useEntityLinksSummaryByDownstreamContext(courseId);
const { data, isPending } = useEntityLinksSummaryByDownstreamContext(courseId);
const outOfSyncCount = data?.reduce((count, lib) => count + (lib.readyToSyncCount || 0), 0);
const lastPublishedDate = data?.map(lib => new Date(lib.lastPublishedAt || 0).getTime())
.reduce((acc, lastPublished) => Math.max(lastPublished, acc), 0);
const alertKey = `outOfSyncCountAlert-${courseId}`;
useEffect(() => {
if (isLoading) {
if (isPending) {
return;
}
if (outOfSyncCount === 0) {
@@ -50,7 +50,7 @@ export const OutOfSyncAlert: React.FC<OutOfSyncAlertProps> = ({
const dismissedAlertDate = parseInt(localStorage.getItem(alertKey) ?? '0', 10);
setShowAlert((lastPublishedDate ?? 0) > dismissedAlertDate);
}, [outOfSyncCount, lastPublishedDate, isLoading, data]);
}, [outOfSyncCount, lastPublishedDate, isPending, data]);
const dismissAlert = () => {
setShowAlert(false);

View File

@@ -314,7 +314,7 @@ const ReviewTabContent = ({ courseId }: Props) => {
const intl = useIntl();
const {
data: outOfSyncItems,
isLoading: isSyncItemsLoading,
isPending: isSyncItemsLoading,
isError,
error,
} = useEntityLinks({

View File

@@ -8,7 +8,7 @@ import { getWaffleFlags, waffleFlagDefaults } from './api';
export const useWaffleFlags = (courseId?: string) => {
const queryClient = useQueryClient();
const { data, isLoading, isError } = useQuery({
const { data, isPending: isLoading, isError } = useQuery({
queryKey: ['waffleFlags', courseId],
queryFn: () => getWaffleFlags(courseId),
// Waffle flags change rarely, so never bother refetching them:

View File

@@ -34,7 +34,7 @@ const useClipboard = (canEdit: boolean = true) => {
const { data: clipboardData } = useQuery({
queryKey: ['clipboard'],
queryFn: getClipboard,
refetchInterval: (data) => (data?.content?.status === CLIPBOARD_STATUS.loading ? 1000 : false),
refetchInterval: (query) => (query.state.data?.content?.status === CLIPBOARD_STATUS.loading ? 1000 : false),
});
const { showToast } = useContext(ToastContext);

View File

@@ -478,7 +478,7 @@ const AddContent = () => {
};
/* istanbul ignore next */
if (pasteClipboardMutation.isLoading) {
if (pasteClipboardMutation.isPending) {
showToast(intl.formatMessage(messages.pastingClipboardMessage));
}

View File

@@ -112,12 +112,12 @@ const LibraryCollectionPage = () => {
const {
data: collectionData,
isLoading,
isPending: isLoading,
isError,
error,
} = useCollection(libraryId, collectionId);
const { data: libraryData, isLoading: isLibLoading } = useContentLibrary(libraryId);
const { data: libraryData, isPending: isLibLoading } = useContentLibrary(libraryId);
if (!collectionId || !libraryId) {
// istanbul ignore next - This shouldn't be possible; it's just here to satisfy the type checker.

View File

@@ -78,10 +78,10 @@ const ComponentAdvancedInfoInner: React.FC<Record<never, never>> = () => {
{
isEditingOLX ? (
<>
<Button variant="primary" onClick={updateOlx} disabled={olxUpdater.isLoading}>
<Button variant="primary" onClick={updateOlx} disabled={olxUpdater.isPending}>
<FormattedMessage {...messages.advancedDetailsOLXSaveButton} />
</Button>
<Button variant="link" onClick={() => setEditingOLX(false)} disabled={olxUpdater.isLoading}>
<Button variant="link" onClick={() => setEditingOLX(false)} disabled={olxUpdater.isPending}>
<FormattedMessage {...messages.advancedDetailsOLXCancelButton} />
</Button>
</>

View File

@@ -24,14 +24,14 @@ const ComponentDetails = () => {
data: componentMetadata,
isError,
error,
isLoading,
isPending,
} = useLibraryBlockMetadata(usageKey);
if (isError) {
return <AlertError error={error} />;
}
if (isLoading) {
if (isPending) {
return <Loading />;
}

View File

@@ -129,7 +129,10 @@ describe('<ComponentPicker />', () => {
// Wait for the content library to load
await screen.findByText(/Change Library/i);
expect(await screen.findByText('Test Library 1')).toBeInTheDocument();
await waitFor(() => {
expect(screen.getByText('Test Library 1')).toBeInTheDocument();
expect(screen.queryAllByText('Introduction to Testing')[0]).toBeInTheDocument();
});
// Click on the component card to open the sidebar
fireEvent.click(screen.queryAllByText('Introduction to Testing')[0]);
@@ -173,7 +176,10 @@ describe('<ComponentPicker />', () => {
// Wait for the content library to load
await screen.findByText(/Change Library/i);
expect(await screen.findByText('Test Library 1')).toBeInTheDocument();
await waitFor(() => {
expect(screen.getByText('Test Library 1')).toBeInTheDocument();
expect(screen.queryAllByText('Collection 1')[0]).toBeInTheDocument();
});
// Mock the collection search result
mockSearchResult(mockCollectionResult);
@@ -194,7 +200,10 @@ describe('<ComponentPicker />', () => {
// Wait for the content library to load
await screen.findByText(/Change Library/i);
expect(await screen.findByText('Test Library 1')).toBeInTheDocument();
await waitFor(() => {
expect(screen.getByText('Test Library 1')).toBeInTheDocument();
expect(screen.queryAllByText('Collection 1')[0]).toBeInTheDocument();
});
// Click on the collection card to open the sidebar
fireEvent.click(screen.queryAllByText('Collection 1')[0]);
@@ -229,7 +238,10 @@ describe('<ComponentPicker />', () => {
// Wait for the content library to load
await screen.findByText(/Change Library/i);
expect(await screen.findByText('Test Library 1')).toBeInTheDocument();
await waitFor(() => {
expect(screen.getByText('Test Library 1')).toBeInTheDocument();
expect(screen.queryAllByText('Collection 1')[0]).toBeInTheDocument();
});
// Click on the collection card to open the sidebar
fireEvent.click(screen.queryAllByText('Collection 1')[0]);
@@ -283,7 +295,10 @@ describe('<ComponentPicker />', () => {
// Wait for the content library to load
await screen.findByText(/Change Library/i);
expect(await screen.findByText('Test Library 1')).toBeInTheDocument();
await waitFor(() => {
expect(screen.getByText('Test Library 1')).toBeInTheDocument();
expect(screen.queryAllByRole('button', { name: 'Select' })[0]).toBeInTheDocument();
});
// Select the first component
fireEvent.click(screen.queryAllByRole('button', { name: 'Select' })[0]);
@@ -330,7 +345,10 @@ describe('<ComponentPicker />', () => {
// Wait for the content library to load
await screen.findByText(/Change Library/i);
expect(await screen.findByText('Test Library 1')).toBeInTheDocument();
await waitFor(() => {
expect(screen.getByText('Test Library 1')).toBeInTheDocument();
expect(screen.queryAllByText('Introduction to Testing')[0]).toBeInTheDocument();
});
// Click on the component card to open the sidebar
fireEvent.click(screen.queryAllByText('Introduction to Testing')[0]);
@@ -413,7 +431,10 @@ describe('<ComponentPicker />', () => {
// Wait for the content library to load
await screen.findByText(/Change Library/i);
expect(await screen.findByText('Test Library 1')).toBeInTheDocument();
await waitFor(() => {
expect(screen.getByText('Test Library 1')).toBeInTheDocument();
expect(screen.queryAllByText('Collection 1')[0]).toBeInTheDocument();
});
// Click on the collection card to open the sidebar
fireEvent.click(screen.queryAllByText('Collection 1')[0]);

View File

@@ -57,7 +57,7 @@ const SelectLibrary = ({ selectedLibrary, setSelectedLibrary, itemType }: Select
const {
data,
isLoading,
isPending,
isError,
error,
} = useContentLibraryV2List({
@@ -70,7 +70,7 @@ const SelectLibrary = ({ selectedLibrary, setSelectedLibrary, itemType }: Select
return <AlertError error={error} />;
}
if (isLoading) {
if (isPending) {
return <Loading />;
}

View File

@@ -32,7 +32,7 @@ const CreateLibrary = () => {
const {
mutate,
data,
isLoading,
isPending,
isError,
error,
} = useCreateLibraryV2();
@@ -149,7 +149,7 @@ const CreateLibrary = () => {
type="submit"
variant="primary"
className="action btn-primary"
state={isLoading ? 'disabled' : 'enabled'}
state={isPending ? 'disabled' : 'enabled'}
disabledStates={['disabled']}
labels={{
enabled: intl.formatMessage(messages.createLibraryButton),

View File

@@ -6,6 +6,7 @@ import {
type Query,
type QueryClient,
replaceEqualDeep,
keepPreviousData,
} from '@tanstack/react-query';
import { useCallback } from 'react';
import { type MeiliSearch } from 'meilisearch';
@@ -201,7 +202,7 @@ export const useUpdateLibraryMetadata = () => {
mutationFn: api.updateLibraryMetadata,
onMutate: async (data) => {
const queryKey = libraryAuthoringQueryKeys.contentLibrary(data.id);
const previousLibraryData = queryClient.getQueriesData(queryKey)[0][1] as api.ContentLibrary;
const previousLibraryData = queryClient.getQueriesData({ queryKey })[0][1] as api.ContentLibrary;
const newLibraryData = {
...previousLibraryData,
@@ -231,7 +232,7 @@ export const useContentLibraryV2List = (customParams: api.GetLibrariesV2CustomPa
useQuery({
queryKey: libraryAuthoringQueryKeys.contentLibraryList(customParams),
queryFn: () => api.getContentLibraryV2List(customParams),
keepPreviousData: true,
placeholderData: keepPreviousData,
})
);
@@ -366,7 +367,7 @@ export const useUpdateXBlockFields = (usageKey: string) => {
mutationFn: (data: api.UpdateXBlockFieldsRequest) => api.updateXBlockFields(usageKey, data),
onMutate: async (data) => {
const queryKey = xblockQueryKeys.xblockFields(usageKey);
const previousBlockData = queryClient.getQueriesData(queryKey)?.[0]?.[1] as api.XBlockFields | undefined;
const previousBlockData = queryClient.getQueriesData({ queryKey })?.[0]?.[1] as api.XBlockFields | undefined;
const formatedData = camelCaseObject(data);
if (!previousBlockData) {

View File

@@ -87,11 +87,11 @@ export const ItemHierarchy = ({
const {
data,
isLoading,
isPending,
isError,
} = useLibraryItemHierarchy(itemId);
if (isLoading) {
if (isPending) {
return <Loading />;
}

View File

@@ -31,11 +31,11 @@ export const ItemHierarchyPublisher = ({
const {
data: hierarchy,
isLoading,
isPending,
isError,
} = useLibraryItemHierarchy(itemId);
if (isLoading) {
if (isPending) {
return <Loading />;
}

View File

@@ -41,7 +41,7 @@ describe('search manager api hooks', () => {
fetchMockResponse();
const { result } = renderHook(() => useGetBlockTypes('filter'), { wrapper });
await waitFor(() => {
expect(result.current.isLoading).toBeFalsy();
expect(result.current.isPending).toBeFalsy();
});
const expectedData = {
chapter: 1,

View File

@@ -1,5 +1,5 @@
import React from 'react';
import { useInfiniteQuery, useQuery } from '@tanstack/react-query';
import { keepPreviousData, useInfiniteQuery, useQuery } from '@tanstack/react-query';
import { type Filter, MeiliSearch } from 'meilisearch';
import {
@@ -26,7 +26,7 @@ export const useContentSearchConnection = (): {
const { data: connectionDetails, isError: hasConnectionError } = useQuery({
queryKey: ['content_search'],
queryFn: getContentSearchConfig,
cacheTime: 60 * 60_000, // Even if we're not actively using the search modal, keep it in memory up to an hour
gcTime: 60 * 60_000, // Even if we're not actively using the search modal, keep it in memory up to an hour
staleTime: 60 * 60_000, // If cache is up to one hour old, no need to re-fetch
refetchInterval: 60 * 60_000,
refetchOnWindowFocus: false, // This doesn't need to be refreshed when the user switches back to this tab.
@@ -135,7 +135,7 @@ export const useContentSearchResults = ({
tagsFilter,
sort,
}),
queryFn: ({ pageParam = 0 }) => {
queryFn: ({ pageParam }) => {
// istanbul ignore if: this should never happen
if (client === undefined || indexName === undefined) {
throw new Error('Required data unexpectedly undefined. Check "enable" condition of useQuery.');
@@ -157,9 +157,10 @@ export const useContentSearchResults = ({
limit,
});
},
initialPageParam: 0,
getNextPageParam: (lastPage) => lastPage.nextOffset,
// Avoid flickering results when user is typing... keep old results until new is available.
keepPreviousData: true,
placeholderData: keepPreviousData,
refetchOnWindowFocus: false, // This doesn't need to be refreshed when the user switches back to this tab.
});
@@ -176,7 +177,7 @@ export const useContentSearchResults = ({
problemTypes: pages?.[0]?.problemTypes ?? {},
publishStatus: pages?.[0]?.publishStatus ?? {},
status: query.status,
isLoading: query.isLoading,
isLoading: query.isPending,
isError: query.isError,
error: query.error,
isFetchingNextPage: query.isFetchingNextPage,
@@ -232,7 +233,7 @@ export const useTagFilterOptions = (args: {
return fetchAvailableTagOptions({ ...args, client, indexName });
},
// Avoid flickering results when user is typing... keep old results until new is available.
keepPreviousData: true,
placeholderData: keepPreviousData,
refetchOnWindowFocus: false, // This doesn't need to be refreshed when the user switches back to this tab.
});
@@ -257,7 +258,7 @@ export const useTagFilterOptions = (args: {
return fetchTagsThatMatchKeyword({ ...args, client, indexName });
},
// Avoid flickering results when user is typing... keep old results until new is available.
keepPreviousData: true,
placeholderData: keepPreviousData,
refetchOnWindowFocus: false, // This doesn't need to be refreshed when the user switches back to this tab.
});

View File

@@ -1,15 +1,10 @@
// @ts-check
import { camelCaseObject, getConfig } from '@edx/frontend-platform';
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
import { useQueryClient, useMutation } from '@tanstack/react-query';
const getApiBaseUrl = () => getConfig().STUDIO_BASE_URL;
/**
* @param {number} taxonomyId
* @returns {string}
*/
export const getManageOrgsApiUrl = (taxonomyId) => new URL(
export const getManageOrgsApiUrl = (taxonomyId: number): string => new URL(
`api/content_tagging/v1/taxonomies/${taxonomyId}/orgs/`,
getApiBaseUrl(),
).href;
@@ -20,18 +15,7 @@ export const getManageOrgsApiUrl = (taxonomyId) => new URL(
export const useManageOrgs = () => {
const queryClient = useQueryClient();
return useMutation({
/**
* @type {import("@tanstack/react-query").MutateFunction<
* any,
* any,
* {
* taxonomyId: number,
* orgs?: string[],
* allOrgs: boolean,
* }
* >}
*/
mutationFn: async ({ taxonomyId, orgs, allOrgs }) => {
mutationFn: async ({ taxonomyId, orgs, allOrgs }: { taxonomyId: number, orgs?: string[], allOrgs: boolean }) => {
const { data } = await getAuthenticatedHttpClient().put(
getManageOrgsApiUrl(taxonomyId),
{

View File

@@ -12,7 +12,7 @@ import { useTagListData, useSubTags } from '../data/apiHooks';
const SubTagsExpanded = ({ taxonomyId, parentTagValue }) => {
const subTagsData = useSubTags(taxonomyId, parentTagValue);
if (subTagsData.isLoading) {
if (subTagsData.isPending) {
return <LoadingSpinner />;
}
if (subTagsData.isError) {