♻️(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:
128
src/frontend/apps/e2e/__tests__/app-impress/doc-version.spec.ts
Normal file
128
src/frontend/apps/e2e/__tests__/app-impress/doc-version.spec.ts
Normal 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();
|
||||
});
|
||||
});
|
||||
@@ -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>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
export * from './api';
|
||||
export * from './components';
|
||||
export * from './stores';
|
||||
export * from './types';
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export * from './useDocVersionStore';
|
||||
@@ -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 }));
|
||||
},
|
||||
}));
|
||||
Reference in New Issue
Block a user