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:
29
package-lock.json
generated
29
package-lock.json
generated
@@ -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": {
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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',
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -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) });
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -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);
|
||||
|
||||
@@ -314,7 +314,7 @@ const ReviewTabContent = ({ courseId }: Props) => {
|
||||
const intl = useIntl();
|
||||
const {
|
||||
data: outOfSyncItems,
|
||||
isLoading: isSyncItemsLoading,
|
||||
isPending: isSyncItemsLoading,
|
||||
isError,
|
||||
error,
|
||||
} = useEntityLinks({
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -478,7 +478,7 @@ const AddContent = () => {
|
||||
};
|
||||
|
||||
/* istanbul ignore next */
|
||||
if (pasteClipboardMutation.isLoading) {
|
||||
if (pasteClipboardMutation.isPending) {
|
||||
showToast(intl.formatMessage(messages.pastingClipboardMessage));
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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>
|
||||
</>
|
||||
|
||||
@@ -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 />;
|
||||
}
|
||||
|
||||
|
||||
@@ -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]);
|
||||
|
||||
@@ -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 />;
|
||||
}
|
||||
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -87,11 +87,11 @@ export const ItemHierarchy = ({
|
||||
|
||||
const {
|
||||
data,
|
||||
isLoading,
|
||||
isPending,
|
||||
isError,
|
||||
} = useLibraryItemHierarchy(itemId);
|
||||
|
||||
if (isLoading) {
|
||||
if (isPending) {
|
||||
return <Loading />;
|
||||
}
|
||||
|
||||
|
||||
@@ -31,11 +31,11 @@ export const ItemHierarchyPublisher = ({
|
||||
|
||||
const {
|
||||
data: hierarchy,
|
||||
isLoading,
|
||||
isPending,
|
||||
isError,
|
||||
} = useLibraryItemHierarchy(itemId);
|
||||
|
||||
if (isLoading) {
|
||||
if (isPending) {
|
||||
return <Loading />;
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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.
|
||||
});
|
||||
|
||||
|
||||
@@ -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),
|
||||
{
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user