♻️(frontend) open version panel from docs options

Versions panel is a feature that will not be used
by all users, so it should be hidden
by default. The user can open it from the docs
options.
This commit is contained in:
Anthony LC
2024-09-02 13:53:25 +02:00
committed by Anthony LC
parent f2a78ada47
commit accbda44e2
7 changed files with 203 additions and 25 deletions

View File

@@ -0,0 +1,128 @@
import { expect, test } from '@playwright/test';
import { createDoc, goToGridDoc, mockedDocument } from './common';
test.beforeEach(async ({ page }) => {
await page.goto('/');
});
test.describe('Doc Version', () => {
test('it displays the doc versions', async ({ page, browserName }) => {
const [randomDoc] = await createDoc(page, 'doc-version', browserName, 1);
await expect(page.locator('h2').getByText(randomDoc)).toBeVisible();
await page.getByLabel('Open the document options').click();
await page
.getByRole('button', {
name: 'Version history',
})
.click();
const panel = page.getByLabel('Document version panel');
await expect(panel.getByText('Current version')).toBeVisible();
expect(await panel.locator('li').count()).toBe(1);
await page.locator('.ProseMirror.bn-editor').click();
await page.locator('.ProseMirror.bn-editor').last().fill('Hello World');
await goToGridDoc(page, {
title: randomDoc,
});
await expect(page.getByText('Hello World')).toBeVisible();
await page
.locator('.ProseMirror .bn-block')
.getByText('Hello World')
.fill('It will create a version');
await goToGridDoc(page, {
title: randomDoc,
});
await expect(page.getByText('Hello World')).toBeHidden();
await expect(page.getByText('It will create a version')).toBeVisible();
await expect(panel.getByText('Current version')).toBeVisible();
expect(await panel.locator('li').count()).toBe(2);
await panel.locator('li').nth(1).click();
await expect(
page.getByText('Read only, you cannot edit document versions.'),
).toBeVisible();
await expect(page.getByText('Hello World')).toBeVisible();
await expect(page.getByText('It will create a version')).toBeHidden();
await panel.getByText('Current version').click();
await expect(page.getByText('Hello World')).toBeHidden();
await expect(page.getByText('It will create a version')).toBeVisible();
});
test('it does not display the doc versions if not allowed', async ({
page,
}) => {
await mockedDocument(page, {
abilities: {
versions_list: false,
partial_update: true,
},
});
await goToGridDoc(page);
await expect(page.locator('h2').getByText('Mocked document')).toBeVisible();
await page.getByLabel('Open the document options').click();
await expect(
page.getByRole('button', { name: 'Version history' }),
).toBeHidden();
await expect(page.getByLabel('Document version panel')).toBeHidden();
});
test('it restores the doc version', async ({ page, browserName }) => {
const [randomDoc] = await createDoc(page, 'doc-version', browserName, 1);
await expect(page.locator('h2').getByText(randomDoc)).toBeVisible();
await page.locator('.bn-block-outer').last().click();
await page.locator('.bn-block-outer').last().fill('Hello');
await goToGridDoc(page, {
title: randomDoc,
});
await expect(page.getByText('Hello')).toBeVisible();
await page.locator('.bn-block-outer').last().click();
await page.keyboard.press('Enter');
await page.locator('.bn-block-outer').last().fill('World');
await goToGridDoc(page, {
title: randomDoc,
});
await expect(page.getByText('World')).toBeVisible();
await page.getByLabel('Open the document options').click();
await page
.getByRole('button', {
name: 'Version history',
})
.click();
const panel = page.getByLabel('Document version panel');
await panel.locator('li').nth(1).click();
await expect(page.getByText('World')).toBeHidden();
await panel.getByLabel('Open the version options').click();
await page.getByText('Restore the version').click();
await expect(panel.locator('li')).toHaveCount(3);
await panel.getByText('Current version').click();
await expect(page.getByText('Hello')).toBeVisible();
await expect(page.getByText('World')).toBeHidden();
});
});

View File

@@ -8,7 +8,12 @@ import { Box, Card, Text, TextErrors } from '@/components';
import { useCunninghamTheme } from '@/cunningham';
import { DocHeader } from '@/features/docs/doc-header';
import { Doc } from '@/features/docs/doc-management';
import { Versions, useDocVersion } from '@/features/docs/doc-versioning/';
import {
Panel,
Versions,
useDocVersion,
useDocVersionStore,
} from '@/features/docs/doc-versioning/';
import { BlockNoteEditor } from './BlockNoteEditor';
@@ -20,6 +25,7 @@ export const DocEditor = ({ doc }: DocEditorProps) => {
const {
query: { versionId },
} = useRouter();
const { isPanelOpen } = useDocVersionStore();
const { t } = useTranslation();
@@ -58,6 +64,7 @@ export const DocEditor = ({ doc }: DocEditorProps) => {
<BlockNoteEditor doc={doc} />
)}
</Card>
{doc.abilities.versions_list && isPanelOpen && <Panel doc={doc} />}
</Box>
</>
);

View File

@@ -9,6 +9,7 @@ import {
ModalShare,
ModalUpdateDoc,
} from '@/features/docs/doc-management';
import { useDocVersionStore } from '@/features/docs/doc-versioning';
import { ModalPDF } from './ModalExport';
@@ -23,6 +24,7 @@ export const DocToolBox = ({ doc }: DocToolBoxProps) => {
const [isModalRemoveOpen, setIsModalRemoveOpen] = useState(false);
const [isModalPDFOpen, setIsModalPDFOpen] = useState(false);
const [isDropOpen, setIsDropOpen] = useState(false);
const { setIsPanelOpen } = useDocVersionStore();
return (
<Box
@@ -77,6 +79,19 @@ export const DocToolBox = ({ doc }: DocToolBoxProps) => {
<Text $theme="primary">{t('Delete document')}</Text>
</Button>
)}
{doc.abilities.versions_list && (
<Button
onClick={() => {
setIsPanelOpen(true);
setIsDropOpen(false);
}}
color="primary-text"
icon={<span className="material-icons">history</span>}
size="small"
>
<Text $theme="primary">{t('Version history')}</Text>
</Button>
)}
<Button
onClick={() => {
setIsModalPDFOpen(true);

View File

@@ -1,10 +1,12 @@
import React, { useState } from 'react';
import React, { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Box, Card, IconBG, Text } from '@/components';
import { useCunninghamTheme } from '@/cunningham';
import { Doc } from '@/features/docs/doc-management';
import { useDocVersionStore } from '../stores';
import { VersionList } from './VersionList';
interface PanelProps {
@@ -14,8 +16,13 @@ interface PanelProps {
export const Panel = ({ doc }: PanelProps) => {
const { t } = useTranslation();
const { colorsTokens } = useCunninghamTheme();
const { setIsPanelOpen } = useDocVersionStore();
const [isOpen, setIsOpen] = useState(true);
const [isOpen, setIsOpen] = useState(false);
useEffect(() => {
setIsOpen(true);
}, []);
const closedOverridingStyles = !isOpen && {
$width: '0',
@@ -46,28 +53,6 @@ export const Panel = ({ doc }: PanelProps) => {
aria-label={t('Document version panel')}
{...closedOverridingStyles}
>
<IconBG
iconName="menu_open"
aria-label={
isOpen
? t('Close the document version panel')
: t('Open the document version panel')
}
$background="transparent"
$size="h2"
$zIndex={1}
$css={`
cursor: pointer;
left: ${isOpen ? '0' : '-3.3'}rem;
top: 0.1rem;
transform: rotate(${isOpen ? '180' : '0'}deg);
transition: ${transition};
user-select: none;
`}
$position="absolute"
onClick={() => setIsOpen(!isOpen)}
$radius="2px"
/>
<Box
$overflow="hidden"
$css={`
@@ -82,6 +67,34 @@ export const Panel = ({ doc }: PanelProps) => {
$justify="center"
$css={`border-top: 2px solid ${colorsTokens()['primary-600']};`}
>
<IconBG
iconName="menu_open"
aria-label={
isOpen
? t('Close the document version panel')
: t('Open the document version panel')
}
$background="transparent"
$size="h2"
$zIndex={1}
$css={`
cursor: pointer;
left: 0rem;
top: 0.1rem;
transition: ${transition};
transform: rotate(180deg);
opacity: ${isOpen ? '1' : '0'};
user-select: none;
`}
$position="absolute"
onClick={() => {
setIsOpen(false);
setTimeout(() => {
setIsPanelOpen(false);
}, 400);
}}
$radius="2px"
/>
<Text $weight="bold" $size="l" $theme="primary">
{t('VERSIONS')}
</Text>

View File

@@ -1,3 +1,4 @@
export * from './api';
export * from './components';
export * from './stores';
export * from './types';

View File

@@ -0,0 +1 @@
export * from './useDocVersionStore';

View File

@@ -0,0 +1,13 @@
import { create } from 'zustand';
export interface UseDocVersionStore {
isPanelOpen: boolean;
setIsPanelOpen: (isOpen: boolean) => void;
}
export const useDocVersionStore = create<UseDocVersionStore>((set) => ({
isPanelOpen: false,
setIsPanelOpen: (isPanelOpen) => {
set(() => ({ isPanelOpen }));
},
}));