Skip to content

Commit 93f7544

Browse files
arbrandesclaude
andcommitted
fix: stop replacing the shell's query client site-wide
App providers wrap the whole site, so gradebook's QueryClientProvider imposed its settings on every other app sharing the site. Its query options now live on gradebook's own hooks. Fixes #634 Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 92d6b7d commit 93f7544

18 files changed

Lines changed: 140 additions & 141 deletions

File tree

‎README.rst‎

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -176,16 +176,12 @@ Directory Structure
176176

177177
* ``app.ts``
178178

179-
* The ``App`` object consumed by ``site.config.*.tsx`` — wires ``appId``, ``routes``, and ``providers`` for frontend-base to register.
179+
* The ``App`` object consumed by ``site.config.*.tsx`` - wires ``appId``, ``routes``, and ``slots`` for frontend-base to register.
180180

181181
* ``routes.tsx``
182182

183183
* React Router route definitions for the app.
184184

185-
* ``providers.tsx``
186-
187-
* App-scoped context providers registered with frontend-base.
188-
189185
* ``slots``
190186

191187
* Slots this app exposes for host sites to plug into.

‎src/app.ts‎

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
import { App } from '@openedx/frontend-base';
22
import { appId } from './constants';
33
import routes from './routes';
4-
import providers from './providers';
54
import slots from './slots';
65

76
const app: App = {
87
appId,
98
routes,
10-
providers,
119
slots,
1210
};
1311

‎src/components/BulkManagementHistoryView/data/apiHook.ts‎

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
import { useQuery } from '@tanstack/react-query';
2-
31
import { useAssignmentTypes, useCourseIdWithGate } from '@src/data/apiHook';
2+
import { useGradebookQuery } from '@src/data/query';
43

54
import { getBulkOperationHistory } from './api';
65
import { bulkOperationHistoryQueryKeys } from './queryKeys';
@@ -18,7 +17,7 @@ const EMPTY_ARRAY: never[] = [];
1817
export const useBulkOperationHistory = (
1918
courseId: string,
2019
{ enabled = true }: { enabled?: boolean } = {},
21-
) => useQuery({
20+
) => useGradebookQuery({
2221
queryKey: bulkOperationHistoryQueryKeys.byCourse(courseId),
2322
queryFn: () => getBulkOperationHistory(courseId),
2423
enabled: !!courseId && enabled,

‎src/components/GradebookFilters/data/apiHook.ts‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useQuery } from '@tanstack/react-query';
1+
import { useGradebookQuery } from '@src/data/query';
22

33
import { getCohorts, getTracks } from './api';
44
import { cohortsQueryKeys, tracksQueryKeys } from './queryKeys';
@@ -11,7 +11,7 @@ import { cohortsQueryKeys, tracksQueryKeys } from './queryKeys';
1111
export const useCohorts = (
1212
courseId: string,
1313
{ enabled = true }: { enabled?: boolean } = {},
14-
) => useQuery({
14+
) => useGradebookQuery({
1515
queryKey: cohortsQueryKeys.byCourse(courseId),
1616
queryFn: () => getCohorts(courseId),
1717
enabled: !!courseId && enabled,
@@ -25,7 +25,7 @@ export const useCohorts = (
2525
export const useTracks = (
2626
courseId: string,
2727
{ enabled = true }: { enabled?: boolean } = {},
28-
) => useQuery({
28+
) => useGradebookQuery({
2929
queryKey: tracksQueryKeys.byCourse(courseId),
3030
queryFn: () => getTracks(courseId),
3131
enabled: !!courseId && enabled,

‎src/components/GradesView/data/apiHook.ts‎

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import { useMemo } from 'react';
2-
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
2+
import { useMutation, useQueryClient } from '@tanstack/react-query';
33

44
import lms from '@src/data/services/lms';
55
import { sortAlphaAsc } from '@src/data/formatUtils';
66
import { filtersSnapshot } from '@src/data/filtersSnapshot';
77
import { useGradebookUi } from '@src/data/gradebookUiContext';
88
import { useCourseIdWithGate } from '@src/data/apiHook';
99
import { useCourseId } from '@src/data/courseIdContext';
10+
import { useGradebookQuery } from '@src/data/query';
1011
import {
1112
trackGradesDisplayed,
1213
trackGradeOverrideSucceeded,
@@ -19,7 +20,7 @@ import {
1920
import { bulkOperationHistoryQueryKeys } from '@src/components/BulkManagementHistoryView/data/queryKeys';
2021

2122
import { getGradeOverrideHistory, getGrades, getGradesPage } from './api';
22-
import { gradeOverrideHistoryQueryKeys, gradesQueryKeys } from './queryKeys';
23+
import { gradeMutationKeys, gradeOverrideHistoryQueryKeys, gradesQueryKeys } from './queryKeys';
2324
import { buildGradesFetchParams } from './utils';
2425

2526
/**
@@ -45,7 +46,7 @@ export const useGrades = (
4546
courseId: string,
4647
gradesPageEndpoint: string | null,
4748
{ enabled = true }: { enabled?: boolean } = {},
48-
) => useQuery({
49+
) => useGradebookQuery({
4950
queryKey: [...gradesQueryKeys.byCourse(courseId), gradesPageEndpoint ?? 'base'],
5051
queryFn: async () => {
5152
const data = gradesPageEndpoint
@@ -143,7 +144,7 @@ export const useGradesData = (): GradesData => {
143144
* is not worth retrying.
144145
*/
145146
export const useGradeOverrideHistory = (subsectionId?: string, userId?: string | number) => (
146-
useQuery({
147+
useGradebookQuery({
147148
queryKey: gradeOverrideHistoryQueryKeys.byCell(subsectionId ?? null, userId ?? null),
148149
queryFn: () => getGradeOverrideHistory(subsectionId as string, userId as string | number),
149150
enabled: !!subsectionId && userId !== undefined && userId !== null,
@@ -187,6 +188,7 @@ export const useUpdateGrades = () => {
187188
const courseId = useCourseId();
188189
const { setShowSuccess, setGradesPageEndpoint, modalState } = useGradebookUi();
189190
const mutation = useMutation({
191+
mutationKey: gradeMutationKeys.updateGrades,
190192
mutationFn: (updateData: GradeOverrideUpdate[]) => lms.api.updateGradebookData(courseId, updateData),
191193
onSuccess: ({ data }, updateData) => {
192194
trackGradeOverrideSucceeded(courseId, data);
@@ -238,6 +240,7 @@ export const useSubmitImportGradesButtonData = () => {
238240
setCsvUploadErrors,
239241
} = useGradebookUi();
240242
const mutation = useMutation<unknown, CsvUploadError, FormData>({
243+
mutationKey: gradeMutationKeys.uploadGradeCsv,
241244
mutationFn: (formData) => lms.api.uploadGradeCsv(courseId, formData),
242245
onMutate: () => {
243246
resetCsvUpload();

‎src/components/GradesView/data/hooks.js‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { useFilters } from '@src/data/filtersContext';
77
import { useGradebookUi } from '@src/data/gradebookUiContext';
88
import { useCanViewGradebook } from '@src/data/apiHook';
99
import { useCourseId } from '@src/data/courseIdContext';
10+
import { BASE_KEY } from '@src/data/queryKeys';
1011
import {
1112
useSelectedCohortEntry,
1213
useSelectedTrackEntry,
@@ -87,12 +88,13 @@ export const useSelectedAssignmentLabel = () => useSelectedAssignmentData()?.lab
8788
/**
8889
* useShouldShowSpinner()
8990
* The busy indicator: the roles gate combined with the grades query fetching or
90-
* any in-flight mutation (grade override save / CSV upload).
91+
* one of the gradebook's own mutations in flight (grade override save / CSV
92+
* upload).
9193
*/
9294
export const useShouldShowSpinner = () => {
9395
const canViewGradebook = useCanViewGradebook();
9496
const { isFetching } = useGradesData();
95-
const mutatingCount = useIsMutating();
97+
const mutatingCount = useIsMutating({ mutationKey: BASE_KEY });
9698
return canViewGradebook && (isFetching || mutatingCount > 0);
9799
};
98100

‎src/components/GradesView/data/hooks.test.ts‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { useFilters } from '@src/data/filtersContext';
66
import { useGradebookUi } from '@src/data/gradebookUiContext';
77
import { useCanViewGradebook } from '@src/data/apiHook';
88
import { useCourseId } from '@src/data/courseIdContext';
9+
import { BASE_KEY } from '@src/data/queryKeys';
910
import {
1011
useSelectedCohortEntry, useSelectedTrackEntry,
1112
} from '@src/components/GradebookFilters/data/hooks';
@@ -217,6 +218,11 @@ describe('GradesView/data hooks', () => {
217218
const { result } = renderHook(useShouldShowSpinner);
218219
expect(result.current).toBe(true);
219220
});
221+
222+
it('only counts the gradebook\'s own mutations', () => {
223+
renderHook(useShouldShowSpinner);
224+
expect(useIsMutatingMock).toHaveBeenCalledWith({ mutationKey: BASE_KEY });
225+
});
220226
});
221227

222228
describe('read-model hooks', () => {

‎src/components/GradesView/data/queryKeys.ts‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ export const gradesQueryKeys = {
99
byCourse: (courseId: string) => [...BASE_KEY, courseId, 'grades'] as const,
1010
};
1111

12+
export const gradeMutationKeys = {
13+
updateGrades: [...BASE_KEY, 'updateGrades'] as const,
14+
uploadGradeCsv: [...BASE_KEY, 'uploadGradeCsv'] as const,
15+
};
16+
1217
/** Grade-override history for one learner on one subsection (edit modal). */
1318
export const gradeOverrideHistoryQueryKeys = {
1419
all: [...BASE_KEY, 'gradeOverrideHistory'] as const,

‎src/data/apiHook.test.ts‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,8 @@ describe('root apiHook', () => {
7777
});
7878

7979
it('returns false when the roles query errors out', async () => {
80-
canViewMock.mockRejectedValue(new Error('boom'));
80+
// 4xx-shaped so the shared retry rule (`query.ts`) doesn't retry it.
81+
canViewMock.mockRejectedValue({ response: { status: 403 } });
8182
const { result } = renderQueryHook(useCanViewGradebook);
8283
await waitFor(() => expect(result.current).toBe(false));
8384
});

‎src/data/apiHook.ts‎

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
import { useQuery } from '@tanstack/react-query';
2-
31
import { getAssignmentTypes, getCanUserViewGradebook } from './api';
42
import { useCourseId } from './courseIdContext';
3+
import { useGradebookQuery } from './query';
54
import { assignmentTypesQueryKeys, rolesQueryKeys } from './queryKeys';
65

76
/**
@@ -12,7 +11,7 @@ import { assignmentTypesQueryKeys, rolesQueryKeys } from './queryKeys';
1211
*/
1312
export const useCanUserViewGradebook = () => {
1413
const courseId = useCourseId();
15-
return useQuery({
14+
return useGradebookQuery({
1615
queryKey: rolesQueryKeys.byCourse(courseId),
1716
queryFn: () => getCanUserViewGradebook(courseId),
1817
enabled: !!courseId,
@@ -28,7 +27,7 @@ export const useCanUserViewGradebook = () => {
2827
export const useAssignmentTypes = (
2928
courseId: string,
3029
{ enabled = true }: { enabled?: boolean } = {},
31-
) => useQuery({
30+
) => useGradebookQuery({
3231
queryKey: assignmentTypesQueryKeys.byCourse(courseId),
3332
queryFn: () => getAssignmentTypes(courseId),
3433
enabled: !!courseId && enabled,

0 commit comments

Comments
 (0)