Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ and this project adheres to

- 🐛(service-worker) Fix useOffline Maximum update depth exceeded #1196
- 🐛(helm) charts generate invalid YAML for collaboration API / WS #890
- 🐛(frontend) 401 redirection overridden #1214

## [3.4.2] - 2025-07-18

Expand Down
17 changes: 9 additions & 8 deletions src/frontend/apps/e2e/__tests__/app-impress/doc-routing.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
mockedDocument,
verifyDocName,
} from './utils-common';
import { createRootSubPage } from './utils-sub-pages';

test.describe('Doc Routing', () => {
test.beforeEach(async ({ page }) => {
Expand Down Expand Up @@ -60,16 +61,20 @@ test.describe('Doc Routing', () => {
});

test('checks 401 on docs/[id] page', async ({ page, browserName }) => {
const [docTitle] = await createDoc(page, '401-doc', browserName, 1);
const [docTitle] = await createDoc(page, '401-doc-parent', browserName, 1);
await verifyDocName(page, docTitle);

await createRootSubPage(page, browserName, '401-doc-child');

await page.locator('.ProseMirror.bn-editor').fill('Hello World');

const responsePromise = page.route(
/.*\/link-configuration\/$|users\/me\/$/,
/.*\/documents\/.*\/$|users\/me\/$/,
async (route) => {
const request = route.request();

if (
request.method().includes('PUT') ||
request.method().includes('PATCH') ||
request.method().includes('GET')
) {
await route.fulfill({
Expand All @@ -84,11 +89,7 @@ test.describe('Doc Routing', () => {
},
);

await page.getByRole('button', { name: 'Share' }).click();

const selectVisibility = page.getByLabel('Visibility', { exact: true });
await selectVisibility.click();
await page.getByLabel('Connected').click();
await page.getByRole('link', { name: '401-doc-parent' }).click();

await responsePromise;

Expand Down
47 changes: 28 additions & 19 deletions src/frontend/apps/impress/src/core/AppProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { CunninghamProvider } from '@openfun/cunningham-react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import {
MutationCache,
QueryClient,
QueryClientProvider,
} from '@tanstack/react-query';
import { useRouter } from 'next/router';
import { useEffect } from 'react';

Expand All @@ -24,8 +28,24 @@ const defaultOptions = {
retry: DEFAULT_QUERY_RETRY,
},
};

let globalRouterReplace: ((url: string) => void) | null = null;

const queryClient = new QueryClient({
defaultOptions,
mutationCache: new MutationCache({
onError: (error) => {
if (error instanceof Error && 'status' in error && error.status === 401) {
void queryClient.resetQueries({
queryKey: [KEY_AUTH],
});
setAuthUrl();
if (globalRouterReplace) {
void globalRouterReplace('/401');
}
}
},
}),
});

export function AppProvider({ children }: { children: React.ReactNode }) {
Expand All @@ -40,25 +60,14 @@ export function AppProvider({ children }: { children: React.ReactNode }) {
return initializeResizeListener();
}, [initializeResizeListener]);

/**
* Update the global router replace function
* This allows us to use the router replace function globally
*/
useEffect(() => {
queryClient.setDefaultOptions({
...defaultOptions,
mutations: {
onError: (error) => {
if (
error instanceof Error &&
'status' in error &&
error.status === 401
) {
void queryClient.resetQueries({
queryKey: [KEY_AUTH],
});
setAuthUrl();
void replace(`/401`);
}
},
},
});
globalRouterReplace = (url: string) => {
void replace(url);
};
}, [replace]);

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,16 @@ export function useUpdateDoc(queryConfig?: UseUpdateDoc) {
void queryConfig.onSuccess(data, variables, context);
}
},
onError: () => {
onError: (error, variables, context) => {
// If error it means the user is probably not allowed to edit the doc
// so we invalidate the canEdit query to update the UI accordingly
void queryClient.invalidateQueries({
queryKey: [KEY_CAN_EDIT],
});

if (queryConfig?.onError) {
queryConfig.onError(error, variables, context);
}
},
});
}
Loading