♻️(frontend) stop to use provider with version

Version are not editable, we don't need to activate
the collaboration provider for them.
Simplify the code by removing the provider
from the version.
This commit is contained in:
Anthony LC
2024-12-03 15:24:38 +01:00
committed by Anthony LC
parent aff036d9fb
commit f606826098
7 changed files with 108 additions and 52 deletions

View File

@@ -19,6 +19,7 @@ and this project adheres to
- 🔨(frontend) encapsulated title to its own component #474
- 🐛(frontend) Fix hidden menu on Firefox #468
- ⚡️(backend) optimize number of queries on document list view #411
- ♻️(frontend) stop to use provider with version #480
- 🚚(collaboration) change the websocket key name #480

View File

@@ -6,6 +6,7 @@ import { useCreateBlockNote } from '@blocknote/react';
import { HocuspocusProvider } from '@hocuspocus/provider';
import React, { useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import * as Y from 'yjs';
import { Box, TextErrors } from '@/components';
import { useAuthStore } from '@/core/auth';
@@ -65,19 +66,14 @@ const cssEditor = (readonly: boolean) => `
interface BlockNoteEditorProps {
doc: Doc;
provider: HocuspocusProvider;
storeId: string;
}
export const BlockNoteEditor = ({
doc,
provider,
storeId,
}: BlockNoteEditorProps) => {
const isVersion = doc.id !== storeId;
export const BlockNoteEditor = ({ doc, provider }: BlockNoteEditorProps) => {
const { userData } = useAuthStore();
const { setEditor } = useEditorStore();
const { t } = useTranslation();
const readOnly = !doc.abilities.partial_update || isVersion;
const readOnly = !doc.abilities.partial_update;
useSaveDoc(doc.id, provider.document, !readOnly);
const { setHeadings, resetHeadings } = useHeadingStore();
const { i18n } = useTranslation();
@@ -174,3 +170,46 @@ export const BlockNoteEditor = ({
</Box>
);
};
interface BlockNoteEditorVersionProps {
initialContent: Y.XmlFragment;
}
export const BlockNoteEditorVersion = ({
initialContent,
}: BlockNoteEditorVersionProps) => {
const readOnly = true;
const { setHeadings, resetHeadings } = useHeadingStore();
const editor = useCreateBlockNote(
{
collaboration: {
fragment: initialContent,
user: {
name: '',
color: '',
},
provider: undefined,
},
},
[initialContent],
);
useEffect(() => {
setHeadings(editor);
editor?.onEditorContentChange(() => {
setHeadings(editor);
});
return () => {
resetHeadings();
};
}, [editor, resetHeadings, setHeadings]);
return (
<Box $css={cssEditor(readOnly)}>
<BlockNoteView editor={editor} editable={!readOnly} theme="light" />
</Box>
);
};

View File

@@ -1,19 +1,23 @@
import { Alert, Loader, VariantType } from '@openfun/cunningham-react';
import { useRouter } from 'next/router';
import React, { useEffect } from 'react';
import React, { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import * as Y from 'yjs';
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';
import {
Doc,
base64ToBlocknoteXmlFragment,
useDocStore,
} from '@/features/docs/doc-management';
import { Versions, useDocVersion } from '@/features/docs/doc-versioning/';
import { useResponsiveStore } from '@/stores';
import { useHeadingStore } from '../stores';
import { BlockNoteEditor } from './BlockNoteEditor';
import { BlockNoteEditor, BlockNoteEditorVersion } from './BlockNoteEditor';
import { IconOpenPanelEditor, PanelEditor } from './PanelEditor';
interface DocEditorProps {
@@ -41,7 +45,7 @@ export const DocEditor = ({ doc }: DocEditorProps) => {
return (
<>
<DocHeader doc={doc} versionId={versionId as Versions['version_id']} />
<DocHeader doc={doc} />
{!doc.abilities.partial_update && (
<Box $margin={{ all: 'small', top: 'none' }}>
<Alert type={VariantType.WARNING}>
@@ -71,9 +75,9 @@ export const DocEditor = ({ doc }: DocEditorProps) => {
$position="relative"
>
{isVersion ? (
<DocVersionEditor doc={doc} versionId={versionId} />
<DocVersionEditor docId={doc.id} versionId={versionId} />
) : (
<BlockNoteEditor doc={doc} storeId={doc.id} provider={provider} />
<BlockNoteEditor doc={doc} provider={provider} />
)}
{!isMobile && <IconOpenPanelEditor headings={headings} />}
</Card>
@@ -84,35 +88,34 @@ export const DocEditor = ({ doc }: DocEditorProps) => {
};
interface DocVersionEditorProps {
doc: Doc;
docId: Doc['id'];
versionId: Versions['version_id'];
}
export const DocVersionEditor = ({ doc, versionId }: DocVersionEditorProps) => {
export const DocVersionEditor = ({
docId,
versionId,
}: DocVersionEditorProps) => {
const {
data: version,
isLoading,
isError,
error,
} = useDocVersion({
docId: doc.id,
docId,
versionId,
});
const { createProvider, providers } = useDocStore();
const collaborationUrl = useCollaborationUrl(versionId);
const { replace } = useRouter();
const [initialContent, setInitialContent] = useState<Y.XmlFragment>();
useEffect(() => {
if (!version?.id || !collaborationUrl) {
if (!version?.content) {
return;
}
const provider = providers?.[version.id];
if (!provider || provider.document.guid !== version.id) {
createProvider(collaborationUrl, version.id, version.content);
}
}, [createProvider, providers, version, collaborationUrl]);
setInitialContent(base64ToBlocknoteXmlFragment(version.content));
}, [version?.content]);
if (isError && error) {
if (error.status === 404) {
@@ -136,7 +139,7 @@ export const DocVersionEditor = ({ doc, versionId }: DocVersionEditorProps) => {
);
}
if (isLoading || !version) {
if (isLoading || !version || !initialContent) {
return (
<Box $align="center" $justify="center" $height="100%">
<Loader />
@@ -144,11 +147,5 @@ export const DocVersionEditor = ({ doc, versionId }: DocVersionEditorProps) => {
);
}
const provider = providers?.[version.id];
if (!provider) {
return null;
}
return <BlockNoteEditor doc={doc} storeId={version.id} provider={provider} />;
return <BlockNoteEditorVersion initialContent={initialContent} />;
};

View File

@@ -5,7 +5,6 @@ import { css } from 'styled-components';
import { Box, Card, StyledLink, Text } from '@/components';
import { useCunninghamTheme } from '@/cunningham';
import { Doc, currentDocRole, useTrans } from '@/features/docs/doc-management';
import { Versions } from '@/features/docs/doc-versioning';
import { useDate } from '@/hook';
import { useResponsiveStore } from '@/stores';
@@ -15,10 +14,9 @@ import { DocToolBox } from './DocToolBox';
interface DocHeaderProps {
doc: Doc;
versionId?: Versions['version_id'];
}
export const DocHeader = ({ doc, versionId }: DocHeaderProps) => {
export const DocHeader = ({ doc }: DocHeaderProps) => {
const { colorsTokens } = useCunninghamTheme();
const { t } = useTranslation();
const { formatDate } = useDate();
@@ -69,7 +67,7 @@ export const DocHeader = ({ doc, versionId }: DocHeaderProps) => {
$align="center"
>
<DocTitle doc={doc} />
<DocToolBox doc={doc} versionId={versionId} />
<DocToolBox doc={doc} />
</Box>
</Box>
<Box

View File

@@ -3,6 +3,7 @@ import {
VariantType,
useToastProvider,
} from '@openfun/cunningham-react';
import { useRouter } from 'next/router';
import React, { useState } from 'react';
import { useTranslation } from 'react-i18next';
@@ -17,17 +18,19 @@ import {
ModalRemoveDoc,
ModalShare,
} from '@/features/docs/doc-management';
import { ModalVersion, Versions } from '@/features/docs/doc-versioning';
import { ModalVersion } from '@/features/docs/doc-versioning';
import { useResponsiveStore } from '@/stores';
import { ModalPDF } from './ModalExport';
interface DocToolBoxProps {
doc: Doc;
versionId?: Versions['version_id'];
}
export const DocToolBox = ({ doc, versionId }: DocToolBoxProps) => {
export const DocToolBox = ({ doc }: DocToolBoxProps) => {
const {
query: { versionId },
} = useRouter();
const { t } = useTranslation();
const [isModalShareOpen, setIsModalShareOpen] = useState(false);
const [isModalRemoveOpen, setIsModalRemoveOpen] = useState(false);
@@ -194,7 +197,7 @@ export const DocToolBox = ({ doc, versionId }: DocToolBoxProps) => {
<ModalVersion
onClose={() => setIsModalVersionOpen(false)}
docId={doc.id}
versionId={versionId}
versionId={versionId as string}
/>
)}
</Box>

View File

@@ -28,3 +28,14 @@ export const blocksToYDoc = (blocks: BasicBlock[], doc: Y.Doc) => {
xmlFragment.push([xmlElement]);
});
};
export const base64ToYDoc = (base64: string) => {
const uint8Array = Buffer.from(base64, 'base64');
const ydoc = new Y.Doc();
Y.applyUpdate(ydoc, uint8Array);
return ydoc;
};
export const base64ToBlocknoteXmlFragment = (base64: string) => {
return base64ToYDoc(base64).getXmlFragment('document-store');
};

View File

@@ -8,12 +8,16 @@ import {
} from '@openfun/cunningham-react';
import { useRouter } from 'next/router';
import { useTranslation } from 'react-i18next';
import * as Y from 'yjs';
import { Box, Text } from '@/components';
import { toBase64 } from '@/features/docs/doc-editor';
import { Doc, useDocStore, useUpdateDoc } from '@/features/docs/doc-management';
import {
Doc,
base64ToYDoc,
useDocStore,
useUpdateDoc,
} from '@/features/docs/doc-management';
import { useDocVersion } from '../api';
import { KEY_LIST_DOC_VERSIONS } from '../api/useDocVersions';
import { Versions } from '../types';
import { revertUpdate } from '../utils';
@@ -21,7 +25,6 @@ import { revertUpdate } from '../utils';
interface ModalVersionProps {
onClose: () => void;
docId: Doc['id'];
versionId: Versions['version_id'];
}
@@ -30,6 +33,10 @@ export const ModalVersion = ({
docId,
versionId,
}: ModalVersionProps) => {
const { data: version } = useDocVersion({
docId,
versionId,
});
const { t } = useTranslation();
const { toast } = useToastProvider();
const { push } = useRouter();
@@ -42,7 +49,7 @@ export const ModalVersion = ({
void push(`/docs/${docId}`);
};
if (!providers?.[docId] || !providers?.[versionId]) {
if (!providers?.[docId] || !version?.content) {
onDisplaySuccess();
return;
}
@@ -50,7 +57,7 @@ export const ModalVersion = ({
revertUpdate(
providers[docId].document,
providers[docId].document,
providers[versionId].document,
base64ToYDoc(version.content),
);
onDisplaySuccess();
@@ -79,13 +86,13 @@ export const ModalVersion = ({
color="primary"
fullWidth
onClick={() => {
const newDoc = toBase64(
Y.encodeStateAsUpdate(providers?.[versionId].document),
);
if (!version?.content) {
return;
}
updateDoc({
id: docId,
content: newDoc,
content: version.content,
});
onClose();