🐛(frontend) Fixed side effects between comments and versionning

We fixed 2 side effects between comments and versionning:
- When going from a version, it was not possible
to add a comment anymore. This was due to the fact
that the versionning was resetting the comment store.
- When restoring a version, we now reset the comment
store to avoid having comments that are not relevant
anymore.
This commit is contained in:
Anthony LC
2026-04-07 16:39:03 +02:00
parent 563a6d0e08
commit dba762759e
7 changed files with 74 additions and 7 deletions

View File

@@ -15,6 +15,10 @@ and this project adheres to
- 🐛(frontend) Fix drop cursor creating columns #2185 - 🐛(frontend) Fix drop cursor creating columns #2185
### Fixed
- 🐛 Fixed side effects between comments and versioning #2183
## [v4.8.5] - 2026-04-03 ## [v4.8.5] - 2026-04-03
### Added ### Added

View File

@@ -133,14 +133,20 @@ test.describe('Doc Version', () => {
const [randomDoc] = await createDoc(page, 'doc-version', browserName, 1); const [randomDoc] = await createDoc(page, 'doc-version', browserName, 1);
await verifyDocName(page, randomDoc); await verifyDocName(page, randomDoc);
await page.locator('.bn-block-outer').last().click(); const editor = await writeInEditor({ page, text: 'Hello' });
await page.locator('.bn-block-outer').last().fill('Hello');
// Add a comment
await editor.getByText('Hello').selectText();
await page.getByRole('button', { name: 'Add comment' }).click();
const thread = page.locator('.bn-thread');
await thread.getByRole('paragraph').first().fill('This is a comment');
await thread.locator('[data-test="save"]').click();
await goToGridDoc(page, { await goToGridDoc(page, {
title: randomDoc, title: randomDoc,
}); });
const editor = page.locator('.ProseMirror');
await expect(editor.getByText('Hello')).toBeVisible(); await expect(editor.getByText('Hello')).toBeVisible();
await page.locator('.bn-block-outer').last().click(); await page.locator('.bn-block-outer').last().click();
await page.keyboard.press('Enter'); await page.keyboard.press('Enter');
@@ -152,6 +158,11 @@ test.describe('Doc Version', () => {
await expect(page.getByText('World')).toBeVisible(); await expect(page.getByText('World')).toBeVisible();
await editor.getByText('Hello').click();
await thread.getByText('This is a comment').first().hover();
await thread.locator('[data-test="resolve"]').click();
await expect(thread).toBeHidden();
await page.getByLabel('Open the document options').click(); await page.getByLabel('Open the document options').click();
await page.getByRole('menuitem', { name: 'Version history' }).click(); await page.getByRole('menuitem', { name: 'Version history' }).click();
@@ -175,7 +186,21 @@ test.describe('Doc Version', () => {
await page.waitForTimeout(500); await page.waitForTimeout(500);
await expect(page.getByText('Hello')).toBeVisible(); await expect(editor.getByText('Hello')).toBeVisible();
await expect(page.getByText('World')).toBeHidden(); await expect(editor.getByText('World')).toBeHidden();
// The old comment is not restored
await expect(editor.getByText('Hello')).toHaveCSS(
'background-color',
'rgba(0, 0, 0, 0)',
);
// We can add a new comment
await editor.getByText('Hello').selectText();
await page.getByRole('button', { name: 'Add comment' }).click();
await thread.getByRole('paragraph').first().fill('This is a comment');
await thread.locator('[data-test="save"]').click();
await expect(editor.getByText('Hello')).toHaveClass('bn-thread-mark');
}); });
}); });

View File

@@ -303,11 +303,13 @@ export const BlockNoteEditor = ({ doc, provider }: BlockNoteEditorProps) => {
interface BlockNoteReaderProps { interface BlockNoteReaderProps {
docId: Doc['id']; docId: Doc['id'];
initialContent: Y.XmlFragment; initialContent: Y.XmlFragment;
isMainEditor?: boolean;
} }
export const BlockNoteReader = ({ export const BlockNoteReader = ({
docId, docId,
initialContent, initialContent,
isMainEditor = true,
}: BlockNoteReaderProps) => { }: BlockNoteReaderProps) => {
const { user } = useAuth(); const { user } = useAuth();
const { setEditor } = useEditorStore(); const { setEditor } = useEditorStore();
@@ -336,12 +338,19 @@ export const BlockNoteReader = ({
); );
useEffect(() => { useEffect(() => {
if (!isMainEditor) {
return;
}
setEditor(editor); setEditor(editor);
return () => { return () => {
if (!isMainEditor) {
return;
}
setEditor(undefined); setEditor(undefined);
}; };
}, [setEditor, editor]); }, [setEditor, editor, isMainEditor]);
useHeadings(editor); useHeadings(editor);

View File

@@ -3,6 +3,7 @@ import { useTranslation } from 'react-i18next';
import { useCunninghamTheme } from '@/cunningham'; import { useCunninghamTheme } from '@/cunningham';
import { User, avatarUrlFromName } from '@/features/auth'; import { User, avatarUrlFromName } from '@/features/auth';
import { useEditorStore } from '@/features/docs/doc-editor/stores';
import { Doc, useProviderStore } from '@/features/docs/doc-management'; import { Doc, useProviderStore } from '@/features/docs/doc-management';
import { DocsThreadStore } from './DocsThreadStore'; import { DocsThreadStore } from './DocsThreadStore';
@@ -16,6 +17,7 @@ export function useComments(
const { provider } = useProviderStore(); const { provider } = useProviderStore();
const { t } = useTranslation(); const { t } = useTranslation();
const { themeTokens } = useCunninghamTheme(); const { themeTokens } = useCunninghamTheme();
const { setThreadStore } = useEditorStore();
const threadStore = useMemo(() => { const threadStore = useMemo(() => {
return new DocsThreadStore( return new DocsThreadStore(
@@ -28,6 +30,18 @@ export function useComments(
); );
}, [docId, canComment, provider?.awareness, user?.full_name]); }, [docId, canComment, provider?.awareness, user?.full_name]);
useEffect(() => {
if (canComment) {
setThreadStore(threadStore);
}
return () => {
if (canComment) {
setThreadStore(undefined);
}
};
}, [threadStore, setThreadStore, canComment]);
useEffect(() => { useEffect(() => {
return () => { return () => {
threadStore?.destroy(); threadStore?.destroy();

View File

@@ -1,15 +1,22 @@
import { create } from 'zustand'; import { create } from 'zustand';
import type { DocsThreadStore } from '../components/comments/DocsThreadStore';
import { DocsBlockNoteEditor } from '../types'; import { DocsBlockNoteEditor } from '../types';
export interface UseEditorstore { export interface UseEditorstore {
editor?: DocsBlockNoteEditor; editor?: DocsBlockNoteEditor;
threadStore?: DocsThreadStore;
setEditor: (editor: DocsBlockNoteEditor | undefined) => void; setEditor: (editor: DocsBlockNoteEditor | undefined) => void;
setThreadStore: (threadStore: DocsThreadStore | undefined) => void;
} }
export const useEditorStore = create<UseEditorstore>((set) => ({ export const useEditorStore = create<UseEditorstore>((set) => ({
editor: undefined, editor: undefined,
threadStore: undefined,
setEditor: (editor) => { setEditor: (editor) => {
set({ editor }); set({ editor });
}, },
setThreadStore: (threadStore) => {
set({ threadStore });
},
})); }));

View File

@@ -86,7 +86,11 @@ export const DocVersionEditor = ({
<DocEditorContainer <DocEditorContainer
docHeader={<DocVersionHeader />} docHeader={<DocVersionHeader />}
docEditor={ docEditor={
<BlockNoteReader initialContent={initialContent} docId={version.id} /> <BlockNoteReader
initialContent={initialContent}
docId={version.id}
isMainEditor={false}
/>
} }
isDeletedDoc={false} isDeletedDoc={false}
readOnly={true} readOnly={true}

View File

@@ -9,6 +9,7 @@ import { useTranslation } from 'react-i18next';
import { createGlobalStyle } from 'styled-components'; import { createGlobalStyle } from 'styled-components';
import { Box, Text } from '@/components'; import { Box, Text } from '@/components';
import { useEditorStore } from '@/docs/doc-editor/stores';
import { import {
Doc, Doc,
base64ToYDoc, base64ToYDoc,
@@ -47,6 +48,7 @@ export const ModalConfirmationVersion = ({
const { t } = useTranslation(); const { t } = useTranslation();
const { toast } = useToastProvider(); const { toast } = useToastProvider();
const { provider } = useProviderStore(); const { provider } = useProviderStore();
const { threadStore } = useEditorStore();
const { mutate: updateDoc } = useUpdateDoc({ const { mutate: updateDoc } = useUpdateDoc({
listInvalidQueries: [KEY_LIST_DOC_VERSIONS], listInvalidQueries: [KEY_LIST_DOC_VERSIONS],
onSuccess: () => { onSuccess: () => {
@@ -66,6 +68,8 @@ export const ModalConfirmationVersion = ({
base64ToYDoc(version.content), base64ToYDoc(version.content),
); );
threadStore?.refreshThreads();
onDisplaySuccess(); onDisplaySuccess();
}, },
}); });