Skip to content

Commit 4adf2ff

Browse files
authored
fix: Refresh section list on subsection page (#2103)
Invalidates the query in the subsection page used to get the list of sections that contains the subsection
1 parent 569a981 commit 4adf2ff

File tree

4 files changed

+104
-10
lines changed

4 files changed

+104
-10
lines changed

src/library-authoring/data/apiHooks.test.tsx

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,26 @@ describe('library api hooks', () => {
311311
});
312312
});
313313

314+
it('should invalidate subsection when added to section', async () => {
315+
const spy = jest.spyOn(queryClient, 'invalidateQueries');
316+
const subsectionId1 = 'lct:org:lib:subsection:1';
317+
const subsectionId2 = 'lct:org:lib:subsection:2';
318+
const sectionId = 'lct:org:lib:section:1';
319+
const url = getLibraryContainerChildrenApiUrl(sectionId);
320+
321+
axiosMock.onPost(url).reply(200);
322+
323+
const { result } = renderHook(() => useAddItemsToContainer(sectionId), { wrapper });
324+
325+
await result.current.mutateAsync([subsectionId1, subsectionId2]);
326+
327+
expect(axiosMock.history.post[0].url).toEqual(url);
328+
329+
// Two call for `containerChildren` and library predicate
330+
// and two more calls to invalidate the subsections.
331+
expect(spy).toHaveBeenCalledTimes(4);
332+
});
333+
314334
describe('publishContainer', () => {
315335
it('should publish a container', async () => {
316336
const containerId = 'lct:org:lib:unit:1';

src/library-authoring/data/apiHooks.ts

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,12 @@ import {
88
replaceEqualDeep,
99
} from '@tanstack/react-query';
1010
import { useCallback } from 'react';
11+
import { type MeiliSearch } from 'meilisearch';
1112

12-
import { getLibraryId } from '../../generic/key-utils';
13+
import { getBlockType, getLibraryId } from '../../generic/key-utils';
1314
import * as api from './api';
1415
import { VersionSpec } from '../LibraryBlock';
15-
import { useContentSearchConnection, useContentSearchResults } from '../../search-manager';
16+
import { useContentSearchConnection, useContentSearchResults, buildSearchQueryKey } from '../../search-manager';
1617

1718
export const libraryQueryPredicate = (query: Query, libraryId: string): boolean => {
1819
// Invalidate all content queries related to this library.
@@ -697,11 +698,34 @@ export const useContainerChildren = (containerId?: string, published: boolean =
697698
})
698699
);
699700

701+
/**
702+
* If you work with `useContentFromSearchIndex`, you can use this
703+
* function to get the query key, usually to invalidate the query.
704+
*/
705+
const getSearchQueryKeyFromContent = (
706+
contentIds: string[],
707+
client?: MeiliSearch,
708+
indexName?: string,
709+
) => (
710+
buildSearchQueryKey({
711+
client,
712+
indexName,
713+
extraFilter: [`usage_key IN ["${contentIds.join('","')}"]`],
714+
searchKeywords: '',
715+
blockTypesFilter: [],
716+
problemTypesFilter: [],
717+
publishStatusFilter: [],
718+
tagsFilter: [],
719+
sort: [],
720+
})
721+
);
722+
700723
/**
701724
* Use this mutation to add items to a container
702725
*/
703726
export const useAddItemsToContainer = (containerId?: string) => {
704727
const queryClient = useQueryClient();
728+
const { client, indexName } = useContentSearchConnection();
705729
return useMutation({
706730
mutationFn: async (itemIds: string[]) => {
707731
// istanbul ignore if: this should never happen
@@ -710,7 +734,7 @@ export const useAddItemsToContainer = (containerId?: string) => {
710734
}
711735
return api.addComponentsToContainer(containerId, itemIds);
712736
},
713-
onSettled: () => {
737+
onSettled: (_data, _error, variables) => {
714738
// istanbul ignore if: this should never happen
715739
if (!containerId) {
716740
return;
@@ -720,6 +744,17 @@ export const useAddItemsToContainer = (containerId?: string) => {
720744
const libraryId = getLibraryId(containerId);
721745
queryClient.invalidateQueries({ queryKey: libraryAuthoringQueryKeys.containerChildren(containerId) });
722746
queryClient.invalidateQueries({ predicate: (query) => libraryQueryPredicate(query, libraryId) });
747+
748+
const containerType = getBlockType(containerId);
749+
if (containerType === 'section') {
750+
// We invalidate the search query of the each itemId if the container is a section.
751+
// This because the subsection page calls this query individually.
752+
variables.forEach((itemId) => {
753+
queryClient.invalidateQueries({
754+
queryKey: getSearchQueryKeyFromContent([itemId], client, indexName),
755+
});
756+
});
757+
}
723758
},
724759
});
725760
};

src/search-manager/data/apiHooks.ts

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,43 @@ export const useContentSearchConnection = (): {
4444
return { client, indexName, hasConnectionError };
4545
};
4646

47+
export const buildSearchQueryKey = ({
48+
client,
49+
indexName,
50+
extraFilter,
51+
searchKeywords,
52+
blockTypesFilter,
53+
problemTypesFilter,
54+
publishStatusFilter,
55+
tagsFilter,
56+
sort,
57+
}: {
58+
client?: MeiliSearch;
59+
indexName?: string;
60+
extraFilter?: Filter;
61+
searchKeywords: string;
62+
blockTypesFilter: string[];
63+
problemTypesFilter: string[];
64+
publishStatusFilter: PublishStatus[];
65+
tagsFilter: string[];
66+
sort: SearchSortOption[];
67+
}) => (
68+
[
69+
'content_search',
70+
'results',
71+
client?.config.apiKey,
72+
client?.config.host,
73+
indexName,
74+
extraFilter,
75+
searchKeywords,
76+
blockTypesFilter,
77+
problemTypesFilter,
78+
publishStatusFilter,
79+
tagsFilter,
80+
sort,
81+
]
82+
);
83+
4784
/**
4885
* Get the results of a search
4986
*/
@@ -87,11 +124,8 @@ export const useContentSearchResults = ({
87124
}) => {
88125
const query = useInfiniteQuery({
89126
enabled: enabled && client !== undefined && indexName !== undefined,
90-
queryKey: [
91-
'content_search',
92-
'results',
93-
client?.config.apiKey,
94-
client?.config.host,
127+
queryKey: buildSearchQueryKey({
128+
client,
95129
indexName,
96130
extraFilter,
97131
searchKeywords,
@@ -100,7 +134,7 @@ export const useContentSearchResults = ({
100134
publishStatusFilter,
101135
tagsFilter,
102136
sort,
103-
],
137+
}),
104138
queryFn: ({ pageParam = 0 }) => {
105139
// istanbul ignore if: this should never happen
106140
if (client === undefined || indexName === undefined) {

src/search-manager/index.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,12 @@ export { default as SearchKeywordsField } from './SearchKeywordsField';
99
export { default as SearchSortWidget } from './SearchSortWidget';
1010
export { default as Stats } from './Stats';
1111
export { HIGHLIGHT_PRE_TAG, HIGHLIGHT_POST_TAG, PublishStatus } from './data/api';
12-
export { useContentSearchConnection, useContentSearchResults, useGetBlockTypes } from './data/apiHooks';
12+
export {
13+
useContentSearchConnection,
14+
useContentSearchResults,
15+
useGetBlockTypes,
16+
buildSearchQueryKey,
17+
} from './data/apiHooks';
1318
export { TypesFilterData } from './hooks';
1419

1520
export type {

0 commit comments

Comments
 (0)