♻️(frontend) replace y-webrtc by @hocuspocus
y-webrtc had some issues, users had difficulties to connect with each others. We replace it by @hocuspocus/provider.
This commit is contained in:
@@ -9,7 +9,7 @@ test.beforeEach(async ({ page }) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test.describe('Doc Editor', () => {
|
test.describe('Doc Editor', () => {
|
||||||
test('checks the Doc is connected to the webrtc server', async ({
|
test('checks the Doc is connected to the provider server', async ({
|
||||||
page,
|
page,
|
||||||
browserName,
|
browserName,
|
||||||
}) => {
|
}) => {
|
||||||
@@ -29,12 +29,7 @@ test.describe('Doc Editor', () => {
|
|||||||
await page.locator('.ProseMirror.bn-editor').fill('Hello World');
|
await page.locator('.ProseMirror.bn-editor').fill('Hello World');
|
||||||
|
|
||||||
const framesent = await framesentPromise;
|
const framesent = await framesentPromise;
|
||||||
const payload = JSON.parse(framesent.payload as string) as {
|
expect(framesent.payload).not.toBeNull();
|
||||||
type: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
const typeCases = ['publish', 'subscribe', 'unsubscribe', 'ping'];
|
|
||||||
expect(typeCases.includes(payload.type)).toBeTruthy();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('markdown button converts from markdown to the editor syntax json', async ({
|
test('markdown button converts from markdown to the editor syntax json', async ({
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
NEXT_PUBLIC_API_ORIGIN=
|
NEXT_PUBLIC_API_ORIGIN=
|
||||||
|
NEXT_PUBLIC_Y_PROVIDER_URL=
|
||||||
NEXT_PUBLIC_MEDIA_URL=
|
NEXT_PUBLIC_MEDIA_URL=
|
||||||
NEXT_PUBLIC_SIGNALING_URL=
|
|
||||||
NEXT_PUBLIC_THEME=dsfr
|
NEXT_PUBLIC_THEME=dsfr
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
NEXT_PUBLIC_API_ORIGIN=http://localhost:8071
|
NEXT_PUBLIC_API_ORIGIN=http://localhost:8071
|
||||||
NEXT_PUBLIC_SIGNALING_URL=ws://localhost:4444
|
NEXT_PUBLIC_Y_PROVIDER_URL=ws://localhost:4444
|
||||||
NEXT_PUBLIC_MEDIA_URL=http://localhost:8083
|
NEXT_PUBLIC_MEDIA_URL=http://localhost:8083
|
||||||
NEXT_PUBLIC_SW_DEACTIVATED=true
|
NEXT_PUBLIC_SW_DEACTIVATED=true
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
"@blocknote/mantine": "*",
|
"@blocknote/mantine": "*",
|
||||||
"@blocknote/react": "*",
|
"@blocknote/react": "*",
|
||||||
"@gouvfr-lasuite/integration": "1.0.2",
|
"@gouvfr-lasuite/integration": "1.0.2",
|
||||||
|
"@hocuspocus/provider": "2.13.5",
|
||||||
"@openfun/cunningham-react": "2.9.4",
|
"@openfun/cunningham-react": "2.9.4",
|
||||||
"@tanstack/react-query": "5.53.2",
|
"@tanstack/react-query": "5.53.2",
|
||||||
"i18next": "23.14.0",
|
"i18next": "23.14.0",
|
||||||
@@ -32,7 +33,6 @@
|
|||||||
"react-i18next": "15.0.1",
|
"react-i18next": "15.0.1",
|
||||||
"react-select": "5.8.0",
|
"react-select": "5.8.0",
|
||||||
"styled-components": "6.1.13",
|
"styled-components": "6.1.13",
|
||||||
"y-webrtc": "10.3.0",
|
|
||||||
"yjs": "*",
|
"yjs": "*",
|
||||||
"zustand": "4.5.5"
|
"zustand": "4.5.5"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ export const backendUrl = () =>
|
|||||||
export const baseApiUrl = (apiVersion: string = '1.0') =>
|
export const baseApiUrl = (apiVersion: string = '1.0') =>
|
||||||
`${backendUrl()}/api/v${apiVersion}/`;
|
`${backendUrl()}/api/v${apiVersion}/`;
|
||||||
|
|
||||||
export const signalingUrl = (docId: string) => {
|
export const providerUrl = (docId: string) => {
|
||||||
const base =
|
const base =
|
||||||
process.env.NEXT_PUBLIC_SIGNALING_URL ||
|
process.env.NEXT_PUBLIC_Y_PROVIDER_URL ||
|
||||||
(typeof window !== 'undefined' ? `wss://${window.location.host}/ws` : '');
|
(typeof window !== 'undefined' ? `wss://${window.location.host}/ws` : '');
|
||||||
|
|
||||||
return `${base}/${docId}`;
|
return `${base}/${docId}`;
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ namespace NodeJS {
|
|||||||
interface ProcessEnv {
|
interface ProcessEnv {
|
||||||
NEXT_PUBLIC_API_ORIGIN?: string;
|
NEXT_PUBLIC_API_ORIGIN?: string;
|
||||||
NEXT_PUBLIC_MEDIA_URL?: string;
|
NEXT_PUBLIC_MEDIA_URL?: string;
|
||||||
NEXT_PUBLIC_SIGNALING_URL?: string;
|
NEXT_PUBLIC_Y_PROVIDER_URL?: string;
|
||||||
NEXT_PUBLIC_SW_DEACTIVATED?: string;
|
NEXT_PUBLIC_SW_DEACTIVATED?: string;
|
||||||
NEXT_PUBLIC_THEME?: string;
|
NEXT_PUBLIC_THEME?: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ import { BlockNoteEditor as BlockNoteEditorCore } from '@blocknote/core';
|
|||||||
import '@blocknote/core/fonts/inter.css';
|
import '@blocknote/core/fonts/inter.css';
|
||||||
import { BlockNoteView } from '@blocknote/mantine';
|
import { BlockNoteView } from '@blocknote/mantine';
|
||||||
import '@blocknote/mantine/style.css';
|
import '@blocknote/mantine/style.css';
|
||||||
|
import { HocuspocusProvider } from '@hocuspocus/provider';
|
||||||
import React, { useCallback, useEffect, useMemo } from 'react';
|
import React, { useCallback, useEffect, useMemo } from 'react';
|
||||||
import { WebrtcProvider } from 'y-webrtc';
|
|
||||||
|
|
||||||
import { Box, TextErrors } from '@/components';
|
import { Box, TextErrors } from '@/components';
|
||||||
import { mediaUrl } from '@/core';
|
import { mediaUrl } from '@/core';
|
||||||
@@ -44,7 +44,7 @@ export const BlockNoteEditor = ({ doc, version }: BlockNoteEditorProps) => {
|
|||||||
const provider = docsStore?.[storeId]?.provider;
|
const provider = docsStore?.[storeId]?.provider;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!provider || provider.doc.guid !== storeId) {
|
if (!provider || provider.document.guid !== storeId) {
|
||||||
createProvider(storeId, initialContent);
|
createProvider(storeId, initialContent);
|
||||||
}
|
}
|
||||||
}, [createProvider, initialContent, provider, storeId]);
|
}, [createProvider, initialContent, provider, storeId]);
|
||||||
@@ -58,7 +58,7 @@ export const BlockNoteEditor = ({ doc, version }: BlockNoteEditorProps) => {
|
|||||||
|
|
||||||
interface BlockNoteContentProps {
|
interface BlockNoteContentProps {
|
||||||
doc: Doc;
|
doc: Doc;
|
||||||
provider: WebrtcProvider;
|
provider: HocuspocusProvider;
|
||||||
storeId: string;
|
storeId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,7 +71,7 @@ export const BlockNoteContent = ({
|
|||||||
const { userData } = useAuthStore();
|
const { userData } = useAuthStore();
|
||||||
const { setStore, docsStore } = useDocStore();
|
const { setStore, docsStore } = useDocStore();
|
||||||
const canSave = doc.abilities.partial_update && !isVersion;
|
const canSave = doc.abilities.partial_update && !isVersion;
|
||||||
useSaveDoc(doc.id, provider.doc, canSave);
|
useSaveDoc(doc.id, provider.document, canSave);
|
||||||
const storedEditor = docsStore?.[storeId]?.editor;
|
const storedEditor = docsStore?.[storeId]?.editor;
|
||||||
const {
|
const {
|
||||||
mutateAsync: createDocAttachment,
|
mutateAsync: createDocAttachment,
|
||||||
@@ -102,7 +102,7 @@ export const BlockNoteContent = ({
|
|||||||
return BlockNoteEditorCore.create({
|
return BlockNoteEditorCore.create({
|
||||||
collaboration: {
|
collaboration: {
|
||||||
provider,
|
provider,
|
||||||
fragment: provider.doc.getXmlFragment('document-store'),
|
fragment: provider.document.getXmlFragment('document-store'),
|
||||||
user: {
|
user: {
|
||||||
name: userData?.email || 'Anonymous',
|
name: userData?.email || 'Anonymous',
|
||||||
color: randomColor(),
|
color: randomColor(),
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
import { BlockNoteEditor } from '@blocknote/core';
|
import { BlockNoteEditor } from '@blocknote/core';
|
||||||
import { WebrtcProvider } from 'y-webrtc';
|
import { HocuspocusProvider } from '@hocuspocus/provider';
|
||||||
import * as Y from 'yjs';
|
import * as Y from 'yjs';
|
||||||
import { create } from 'zustand';
|
import { create } from 'zustand';
|
||||||
|
|
||||||
import { signalingUrl } from '@/core';
|
import { providerUrl } from '@/core';
|
||||||
import { Base64 } from '@/features/docs/doc-management';
|
import { Base64 } from '@/features/docs/doc-management';
|
||||||
|
|
||||||
interface DocStore {
|
interface DocStore {
|
||||||
provider: WebrtcProvider;
|
provider: HocuspocusProvider;
|
||||||
editor?: BlockNoteEditor;
|
editor?: BlockNoteEditor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -15,7 +15,7 @@ export interface UseDocStore {
|
|||||||
docsStore: {
|
docsStore: {
|
||||||
[storeId: string]: DocStore;
|
[storeId: string]: DocStore;
|
||||||
};
|
};
|
||||||
createProvider: (storeId: string, initialDoc: Base64) => WebrtcProvider;
|
createProvider: (storeId: string, initialDoc: Base64) => HocuspocusProvider;
|
||||||
setStore: (storeId: string, props: Partial<DocStore>) => void;
|
setStore: (storeId: string, props: Partial<DocStore>) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,9 +30,10 @@ export const useDocStore = create<UseDocStore>((set, get) => ({
|
|||||||
Y.applyUpdate(doc, Buffer.from(initialDoc, 'base64'));
|
Y.applyUpdate(doc, Buffer.from(initialDoc, 'base64'));
|
||||||
}
|
}
|
||||||
|
|
||||||
const provider = new WebrtcProvider(storeId, doc, {
|
const provider = new HocuspocusProvider({
|
||||||
signaling: [signalingUrl(storeId)],
|
url: providerUrl(storeId),
|
||||||
maxConns: 5,
|
name: storeId,
|
||||||
|
document: doc,
|
||||||
});
|
});
|
||||||
|
|
||||||
get().setStore(storeId, { provider });
|
get().setStore(storeId, { provider });
|
||||||
|
|||||||
@@ -51,9 +51,9 @@ export const ModalVersion = ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
revertUpdate(
|
revertUpdate(
|
||||||
docsStore[docId].provider.doc,
|
docsStore[docId].provider.document,
|
||||||
docsStore[docId].provider.doc,
|
docsStore[docId].provider.document,
|
||||||
docsStore[versionId].provider.doc,
|
docsStore[versionId].provider.document,
|
||||||
);
|
);
|
||||||
|
|
||||||
onDisplaySuccess();
|
onDisplaySuccess();
|
||||||
@@ -83,7 +83,7 @@ export const ModalVersion = ({
|
|||||||
fullWidth
|
fullWidth
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
const newDoc = toBase64(
|
const newDoc = toBase64(
|
||||||
Y.encodeStateAsUpdate(docsStore?.[versionId]?.provider.doc),
|
Y.encodeStateAsUpdate(docsStore?.[versionId]?.provider.document),
|
||||||
);
|
);
|
||||||
|
|
||||||
updateDoc({
|
updateDoc({
|
||||||
|
|||||||
Reference in New Issue
Block a user