diff --git a/src/frontend/apps/e2e/__tests__/app-impress/doc-visibility.spec.ts b/src/frontend/apps/e2e/__tests__/app-impress/doc-visibility.spec.ts index b39cb5c0..24cf4bfb 100644 --- a/src/frontend/apps/e2e/__tests__/app-impress/doc-visibility.spec.ts +++ b/src/frontend/apps/e2e/__tests__/app-impress/doc-visibility.spec.ts @@ -7,6 +7,7 @@ import { keyCloakSignIn, verifyDocName, } from './utils-common'; +import { writeInEditor } from './utils-editor'; import { addNewMember, connectOtherUserToDoc } from './utils-share'; import { createRootSubPage } from './utils-sub-pages'; @@ -151,18 +152,15 @@ test.describe('Doc Visibility: Restricted', () => { await verifyDocName(page, docTitle); - await page - .locator('.ProseMirror') - .locator('.bn-block-outer') - .last() - .fill('Hello World'); + await writeInEditor({ page, text: 'Hello World' }); const docUrl = page.url(); - const { otherBrowserName, otherPage } = await connectOtherUserToDoc({ - browserName, - docUrl, - }); + const { otherBrowserName, otherPage, cleanup } = + await connectOtherUserToDoc({ + browserName, + docUrl, + }); await expect( otherPage.getByText('Insufficient access rights to view the document.'), @@ -178,6 +176,8 @@ test.describe('Doc Visibility: Restricted', () => { await expect(otherPage.getByText('Hello World')).toBeVisible({ timeout: 10000, }); + + await cleanup(); }); }); diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteEditor.tsx b/src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteEditor.tsx index 80188c33..3b6a67ad 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteEditor.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteEditor.tsx @@ -83,10 +83,9 @@ export const BlockNoteEditor = ({ doc, provider }: BlockNoteEditorProps) => { const { user } = useAuth(); const { setEditor } = useEditorStore(); const { t } = useTranslation(); - const { isSynced } = useProviderStore(); + const { isSynced: isConnectedToCollabServer } = useProviderStore(); const { isEditable, isLoading } = useIsCollaborativeEditable(doc); - const isConnectedToCollabServer = isSynced; const readOnly = !doc.abilities.partial_update || !isEditable || isLoading; const isDeletedDoc = !!doc.deleted_at; diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/components/DocEditor.tsx b/src/frontend/apps/impress/src/features/docs/doc-editor/components/DocEditor.tsx index c405fe96..7ad0a941 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-editor/components/DocEditor.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-editor/components/DocEditor.tsx @@ -25,10 +25,10 @@ interface DocEditorProps { export const DocEditor = ({ doc, versionId }: DocEditorProps) => { const { isDesktop } = useResponsiveStore(); const isVersion = !!versionId && typeof versionId === 'string'; - const { provider } = useProviderStore(); + const { provider, isReady } = useProviderStore(); // TODO: Use skeleton instead of loading - if (!provider) { + if (!provider || !isReady) { return ; } diff --git a/src/frontend/apps/impress/src/features/docs/doc-management/stores/useProviderStore.tsx b/src/frontend/apps/impress/src/features/docs/doc-management/stores/useProviderStore.tsx index 6971c614..33eb3d6a 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-management/stores/useProviderStore.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-management/stores/useProviderStore.tsx @@ -14,6 +14,7 @@ export interface UseCollaborationStore { destroyProvider: () => void; provider: HocuspocusProvider | undefined; isConnected: boolean; + isReady: boolean; isSynced: boolean; hasLostConnection: boolean; resetLostConnection: () => void; @@ -22,6 +23,7 @@ export interface UseCollaborationStore { const defaultValues = { provider: undefined, isConnected: false, + isReady: false, isSynced: false, hasLostConnection: false, }; @@ -46,14 +48,18 @@ export const useProviderStore = create((set, get) => ({ onDisconnect(data) { // Attempt to reconnect if the disconnection was clean (initiated by the client or server) if ((data.event as ExtendedCloseEvent).wasClean) { - provider.connect(); + void provider.connect(); } }, + onAuthenticationFailed() { + set({ isReady: true }); + }, onStatus: ({ status }) => { set((state) => { const nextConnected = status === WebSocketStatus.Connected; return { isConnected: nextConnected, + isReady: state.isReady || status === WebSocketStatus.Disconnected, hasLostConnection: state.isConnected && !nextConnected ? true @@ -62,7 +68,7 @@ export const useProviderStore = create((set, get) => ({ }); }, onSynced: ({ state }) => { - set({ isSynced: state }); + set({ isSynced: state, isReady: true }); }, onClose(data) { /**