diff --git a/src/frontend/Dockerfile b/src/frontend/Dockerfile index 972c7160..8a179a9a 100644 --- a/src/frontend/Dockerfile +++ b/src/frontend/Dockerfile @@ -61,9 +61,6 @@ FROM impress AS impress-builder WORKDIR /home/frontend/apps/impress -ARG Y_PROVIDER_URL -ENV NEXT_PUBLIC_Y_PROVIDER_URL=${Y_PROVIDER_URL} - ARG API_ORIGIN ENV NEXT_PUBLIC_API_ORIGIN=${API_ORIGIN} diff --git a/src/frontend/apps/e2e/__tests__/app-impress/config.spec.ts b/src/frontend/apps/e2e/__tests__/app-impress/config.spec.ts index 5e63d5a2..2ae8746f 100644 --- a/src/frontend/apps/e2e/__tests__/app-impress/config.spec.ts +++ b/src/frontend/apps/e2e/__tests__/app-impress/config.spec.ts @@ -110,4 +110,26 @@ test.describe('Config', () => { /http:\/\/localhost:8083\/media\/.*\/attachments\/.*.png/, ); }); + + test('it checks that collaboration server is configured from config endpoint', async ({ + page, + browserName, + }) => { + const webSocketPromise = page.waitForEvent('websocket', (webSocket) => { + return webSocket.url().includes('ws://localhost:4444/'); + }); + + await page.goto('/'); + + const randomDoc = await createDoc( + page, + 'doc-collaboration', + browserName, + 1, + ); + await expect(page.locator('h2').getByText(randomDoc[0])).toBeVisible(); + + const webSocket = await webSocketPromise; + expect(webSocket.url()).toContain('ws://localhost:4444/'); + }); }); diff --git a/src/frontend/apps/impress/.env b/src/frontend/apps/impress/.env index afe20085..3cf0e897 100644 --- a/src/frontend/apps/impress/.env +++ b/src/frontend/apps/impress/.env @@ -1,3 +1,2 @@ NEXT_PUBLIC_API_ORIGIN= -NEXT_PUBLIC_Y_PROVIDER_URL= NEXT_PUBLIC_SW_DEACTIVATED= diff --git a/src/frontend/apps/impress/.env.development b/src/frontend/apps/impress/.env.development index e174f537..f26afb11 100644 --- a/src/frontend/apps/impress/.env.development +++ b/src/frontend/apps/impress/.env.development @@ -1,3 +1,2 @@ NEXT_PUBLIC_API_ORIGIN=http://localhost:8071 -NEXT_PUBLIC_Y_PROVIDER_URL=ws://localhost:4444 NEXT_PUBLIC_SW_DEACTIVATED=true diff --git a/src/frontend/apps/impress/src/core/conf.ts b/src/frontend/apps/impress/src/core/conf.ts index 1424dfa6..118f5814 100644 --- a/src/frontend/apps/impress/src/core/conf.ts +++ b/src/frontend/apps/impress/src/core/conf.ts @@ -4,11 +4,3 @@ export const backendUrl = () => export const baseApiUrl = (apiVersion: string = '1.0') => `${backendUrl()}/api/v${apiVersion}/`; - -export const providerUrl = (docId: string) => { - const base = - process.env.NEXT_PUBLIC_Y_PROVIDER_URL || - (typeof window !== 'undefined' ? `wss://${window.location.host}/ws` : ''); - - return `${base}/${docId}`; -}; diff --git a/src/frontend/apps/impress/src/core/config/hooks/index.ts b/src/frontend/apps/impress/src/core/config/hooks/index.ts index 41d6d8de..e1b2dff2 100644 --- a/src/frontend/apps/impress/src/core/config/hooks/index.ts +++ b/src/frontend/apps/impress/src/core/config/hooks/index.ts @@ -1 +1,2 @@ export * from './useMediaUrl'; +export * from './useCollaborationUrl'; diff --git a/src/frontend/apps/impress/src/core/config/hooks/useCollaborationUrl.tsx b/src/frontend/apps/impress/src/core/config/hooks/useCollaborationUrl.tsx new file mode 100644 index 00000000..d945cb23 --- /dev/null +++ b/src/frontend/apps/impress/src/core/config/hooks/useCollaborationUrl.tsx @@ -0,0 +1,15 @@ +import { useConfig } from '../api'; + +export const useCollaborationUrl = (room?: string) => { + const { data: conf } = useConfig(); + + if (!room) { + return; + } + + const base = + conf?.COLLABORATION_SERVER_URL || + (typeof window !== 'undefined' ? `wss://${window.location.host}/ws` : ''); + + return `${base}/${room}`; +}; diff --git a/src/frontend/apps/impress/src/core/index.ts b/src/frontend/apps/impress/src/core/index.ts index 97ec4897..99176076 100644 --- a/src/frontend/apps/impress/src/core/index.ts +++ b/src/frontend/apps/impress/src/core/index.ts @@ -1,3 +1,4 @@ export * from './AppProvider'; export * from './auth'; export * from './conf'; +export * from './config'; diff --git a/src/frontend/apps/impress/src/custom-next.d.ts b/src/frontend/apps/impress/src/custom-next.d.ts index 9dadec0c..2f5af638 100644 --- a/src/frontend/apps/impress/src/custom-next.d.ts +++ b/src/frontend/apps/impress/src/custom-next.d.ts @@ -20,7 +20,6 @@ declare module '*.svg?url' { namespace NodeJS { interface ProcessEnv { NEXT_PUBLIC_API_ORIGIN?: string; - NEXT_PUBLIC_Y_PROVIDER_URL?: string; NEXT_PUBLIC_SW_DEACTIVATED?: string; } } 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 a664eb35..50b2b73a 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 @@ -4,6 +4,7 @@ import React, { useEffect } from 'react'; import { useTranslation } from 'react-i18next'; import { Box, Card, Text, TextErrors } from '@/components'; +import { useCollaborationUrl } from '@/core'; import { useCunninghamTheme } from '@/cunningham'; import { DocHeader } from '@/features/docs/doc-header'; import { Doc, useDocStore } from '@/features/docs/doc-management'; @@ -98,19 +99,20 @@ export const DocVersionEditor = ({ doc, versionId }: DocVersionEditorProps) => { versionId, }); const { createProvider, providers } = useDocStore(); + const collaborationUrl = useCollaborationUrl(versionId); const { replace } = useRouter(); useEffect(() => { - if (!version?.id) { + if (!version?.id || !collaborationUrl) { return; } const provider = providers?.[version.id]; if (!provider || provider.document.guid !== version.id) { - createProvider(version.id, version.content); + createProvider(collaborationUrl, version.id, version.content); } - }, [createProvider, providers, version]); + }, [createProvider, providers, version, collaborationUrl]); if (isError && error) { if (error.status === 404) { diff --git a/src/frontend/apps/impress/src/features/docs/doc-management/stores/useDocStore.tsx b/src/frontend/apps/impress/src/features/docs/doc-management/stores/useDocStore.tsx index 3bc2a95c..3b01ecc0 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-management/stores/useDocStore.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-management/stores/useDocStore.tsx @@ -2,7 +2,6 @@ import { HocuspocusProvider } from '@hocuspocus/provider'; import * as Y from 'yjs'; import { create } from 'zustand'; -import { providerUrl } from '@/core'; import { Base64, Doc, blocksToYDoc } from '@/features/docs/doc-management'; export interface UseDocStore { @@ -10,7 +9,11 @@ export interface UseDocStore { providers: { [storeId: string]: HocuspocusProvider; }; - createProvider: (storeId: string, initialDoc: Base64) => HocuspocusProvider; + createProvider: ( + providerUrl: string, + storeId: string, + initialDoc: Base64, + ) => HocuspocusProvider; setProviders: (storeId: string, providers: HocuspocusProvider) => void; setCurrentDoc: (doc: Doc | undefined) => void; } @@ -18,7 +21,7 @@ export interface UseDocStore { export const useDocStore = create((set, get) => ({ currentDoc: undefined, providers: {}, - createProvider: (storeId: string, initialDoc: Base64) => { + createProvider: (providerUrl, storeId, initialDoc) => { const doc = new Y.Doc({ guid: storeId, }); @@ -37,7 +40,7 @@ export const useDocStore = create((set, get) => ({ } const provider = new HocuspocusProvider({ - url: providerUrl(storeId), + url: providerUrl, name: storeId, document: doc, }); diff --git a/src/frontend/apps/impress/src/pages/docs/[id]/index.tsx b/src/frontend/apps/impress/src/pages/docs/[id]/index.tsx index 7ea5fd50..92410f8e 100644 --- a/src/frontend/apps/impress/src/pages/docs/[id]/index.tsx +++ b/src/frontend/apps/impress/src/pages/docs/[id]/index.tsx @@ -6,6 +6,7 @@ import { useEffect, useState } from 'react'; import { Box, Text } from '@/components'; import { TextErrors } from '@/components/TextErrors'; +import { useCollaborationUrl } from '@/core'; import { useAuthStore } from '@/core/auth'; import { DocEditor } from '@/features/docs/doc-editor'; import { KEY_DOC, useDoc, useDocStore } from '@/features/docs/doc-management'; @@ -47,6 +48,7 @@ const DocPage = ({ id }: DocProps) => { const queryClient = useQueryClient(); const { replace } = useRouter(); const provider = providers?.[id]; + const collaborationUrl = useCollaborationUrl(doc?.id); useEffect(() => { if (doc?.title) { @@ -70,17 +72,17 @@ const DocPage = ({ id }: DocProps) => { }, [docQuery, setCurrentDoc]); useEffect(() => { - if (!doc?.id) { + if (!doc?.id || !collaborationUrl) { return; } let newProvider = provider; if (!provider || provider.document.guid !== doc.id) { - newProvider = createProvider(doc.id, doc.content); + newProvider = createProvider(collaborationUrl, doc.id, doc.content); } setBroadcastProvider(newProvider); - }, [createProvider, doc, provider, setBroadcastProvider]); + }, [createProvider, doc, provider, setBroadcastProvider, collaborationUrl]); /** * We add a broadcast task to reset the query cache