Skip to content

Commit fbdeb90

Browse files
committed
🛂(frontend) invalidate doc query when lost connection
When the provider reports a lost connection, we invalidate the doc query to refetch the document data. This ensures that if a user has lost is rights to access a document, he will be redirected to a 403 page without needing to refresh the page.
1 parent b773f09 commit fbdeb90

File tree

4 files changed

+44
-3
lines changed

4 files changed

+44
-3
lines changed

src/frontend/apps/e2e/__tests__/app-impress/doc-member-create.spec.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {
77
randomName,
88
verifyDocName,
99
} from './utils-common';
10-
import { connectOtherUserToDoc } from './utils-share';
10+
import { connectOtherUserToDoc, updateRoleUser } from './utils-share';
1111
import { createRootSubPage } from './utils-sub-pages';
1212

1313
test.describe('Document create member', () => {
@@ -274,6 +274,12 @@ test.describe('Document create member', () => {
274274
await verifyDocName(otherPage, docTitle);
275275
await expect(otherPage.getByText('Hello World')).toBeVisible();
276276

277+
// Revoke access
278+
await updateRoleUser(page, 'Remove access', emailRequest);
279+
await expect(
280+
otherPage.getByText('Insufficient access rights to view the document.'),
281+
).toBeVisible();
282+
277283
// Cleanup: other user logout
278284
await cleanup();
279285
});

src/frontend/apps/e2e/__tests__/app-impress/utils-share.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,20 @@ export const updateShareLink = async (
6868
}
6969
};
7070

71+
export const updateRoleUser = async (
72+
page: Page,
73+
role: Role | 'Remove access',
74+
email: string,
75+
) => {
76+
const list = page.getByTestId('doc-share-quick-search');
77+
78+
const currentUser = list.getByTestId(`doc-share-member-row-${email}`);
79+
const currentUserRole = currentUser.getByLabel('doc-role-dropdown');
80+
await currentUserRole.click();
81+
await page.getByLabel(role).click();
82+
await list.click();
83+
};
84+
7185
/**
7286
* Connects another user to a document.
7387
* Useful to test real-time collaboration features.

src/frontend/apps/impress/src/features/docs/doc-management/stores/useProviderStore.tsx

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,14 @@ export interface UseCollaborationStore {
1313
destroyProvider: () => void;
1414
provider: HocuspocusProvider | undefined;
1515
isConnected: boolean;
16+
hasLostConnection: boolean;
17+
resetLostConnection: () => void;
1618
}
1719

1820
const defaultValues = {
1921
provider: undefined,
2022
isConnected: false,
23+
hasLostConnection: false,
2124
};
2225

2326
export const useProviderStore = create<UseCollaborationStore>((set, get) => ({
@@ -36,8 +39,15 @@ export const useProviderStore = create<UseCollaborationStore>((set, get) => ({
3639
name: storeId,
3740
document: doc,
3841
onStatus: ({ status }) => {
39-
set({
40-
isConnected: status === WebSocketStatus.Connected,
42+
set((state) => {
43+
const nextConnected = status === WebSocketStatus.Connected;
44+
return {
45+
isConnected: nextConnected,
46+
hasLostConnection:
47+
state.isConnected && !nextConnected
48+
? true
49+
: state.hasLostConnection,
50+
};
4151
});
4252
},
4353
});
@@ -56,4 +66,5 @@ export const useProviderStore = create<UseCollaborationStore>((set, get) => ({
5666

5767
set(defaultValues);
5868
},
69+
resetLostConnection: () => set({ hasLostConnection: false }),
5970
}));

src/frontend/apps/impress/src/pages/docs/[id]/index.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
useCollaboration,
1616
useDoc,
1717
useDocStore,
18+
useProviderStore,
1819
} from '@/docs/doc-management/';
1920
import { KEY_AUTH, setAuthUrl, useAuth } from '@/features/auth';
2021
import { getDocChildren, subPageToTree } from '@/features/docs/doc-tree/';
@@ -57,6 +58,7 @@ interface DocProps {
5758
}
5859

5960
const DocPage = ({ id }: DocProps) => {
61+
const { hasLostConnection, resetLostConnection } = useProviderStore();
6062
const {
6163
data: docQuery,
6264
isError,
@@ -87,6 +89,14 @@ const DocPage = ({ id }: DocProps) => {
8789
const { t } = useTranslation();
8890
const { authenticated } = useAuth();
8991

92+
// Invalidate when provider store reports a lost connection
93+
useEffect(() => {
94+
if (hasLostConnection && doc?.id) {
95+
queryClient.invalidateQueries({ queryKey: [KEY_DOC, { id: doc.id }] });
96+
resetLostConnection();
97+
}
98+
}, [hasLostConnection, doc?.id, queryClient, resetLostConnection]);
99+
90100
useEffect(() => {
91101
if (!docQuery || isFetching) {
92102
return;

0 commit comments

Comments
 (0)