Skip to content

Commit 37138c1

Browse files
committed
✨(frontend) add trashbin list
List the docs deleted in the trashbin list, it is displayed in the docs grid.
1 parent 2c1a9ff commit 37138c1

File tree

16 files changed

+460
-39
lines changed

16 files changed

+460
-39
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ and this project adheres to
99
### Added
1010

1111
- ✨(frontend) add pdf block to the editor #1293
12+
- ✨List and restore deleted docs #1450
1213

1314
### Changed
1415

src/frontend/apps/e2e/__tests__/app-impress/doc-grid.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ test.describe('Document grid item options', () => {
139139
const row = await getGridRow(page, docTitle);
140140
await row.getByText(`more_horiz`).click();
141141

142-
await page.getByRole('menuitem', { name: 'Remove' }).click();
142+
await page.getByRole('menuitem', { name: 'Delete' }).click();
143143

144144
await expect(
145145
page.getByRole('heading', { name: 'Delete a doc' }),
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import { expect, test } from '@playwright/test';
2+
3+
import {
4+
clickInGridMenu,
5+
createDoc,
6+
getGridRow,
7+
verifyDocName,
8+
} from './utils-common';
9+
import { addNewMember } from './utils-share';
10+
11+
test.beforeEach(async ({ page }) => {
12+
await page.goto('/');
13+
});
14+
15+
test.describe('Doc Trashbin', () => {
16+
test('it controls UI and interaction from the grid page', async ({
17+
page,
18+
browserName,
19+
}) => {
20+
const [title1] = await createDoc(page, 'my-trash-doc-1', browserName, 1);
21+
const [title2] = await createDoc(page, 'my-trash-doc-2', browserName, 1);
22+
await verifyDocName(page, title2);
23+
await page.getByRole('button', { name: 'Share' }).click();
24+
await addNewMember(page, 0, 'Editor');
25+
await page.getByRole('button', { name: 'close' }).click();
26+
27+
await page.getByRole('button', { name: 'Back to homepage' }).click();
28+
29+
const row1 = await getGridRow(page, title1);
30+
await clickInGridMenu(page, row1, 'Delete');
31+
await page.getByRole('button', { name: 'Delete document' }).click();
32+
33+
const row2 = await getGridRow(page, title2);
34+
await clickInGridMenu(page, row2, 'Delete');
35+
await page.getByRole('button', { name: 'Delete document' }).click();
36+
37+
await page.getByRole('link', { name: 'Trashbin' }).click();
38+
39+
const docsGrid = page.getByTestId('docs-grid');
40+
await expect(docsGrid.getByText('Days remaining')).toBeVisible();
41+
await expect(row1.getByText(title1)).toBeVisible();
42+
await expect(row1.getByText('30 days')).toBeVisible();
43+
await expect(row2.getByText(title2)).toBeVisible();
44+
await expect(
45+
row2.getByRole('button', {
46+
name: 'Open the sharing settings for the document',
47+
}),
48+
).toBeVisible();
49+
await expect(
50+
row2.getByRole('button', {
51+
name: 'Open the sharing settings for the document',
52+
}),
53+
).toBeDisabled();
54+
});
55+
});

src/frontend/apps/e2e/__tests__/app-impress/utils-common.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Page, expect } from '@playwright/test';
1+
import { Locator, Page, expect } from '@playwright/test';
22

33
export type BrowserName = 'chromium' | 'firefox' | 'webkit';
44
export const BROWSERS: BrowserName[] = ['chromium', 'webkit', 'firefox'];
@@ -326,3 +326,14 @@ export async function waitForLanguageSwitch(
326326

327327
await page.getByRole('menuitem', { name: lang.label }).click();
328328
}
329+
330+
export const clickInGridMenu = async (
331+
page: Page,
332+
row: Locator,
333+
textButton: string,
334+
) => {
335+
await row
336+
.getByRole('button', { name: /Open the menu of actions for the document/ })
337+
.click();
338+
await page.getByRole('menuitem', { name: textButton }).click();
339+
};
Lines changed: 87 additions & 0 deletions
Loading

src/frontend/apps/impress/src/features/docs/doc-management/components/SimpleDocItem.tsx

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,15 @@ import { css } from 'styled-components';
44

55
import { Box, Text } from '@/components';
66
import { useCunninghamTheme } from '@/cunningham';
7-
import { Doc, getEmojiAndTitle, useTrans } from '@/docs/doc-management';
7+
import {
8+
Doc,
9+
getEmojiAndTitle,
10+
useDocUtils,
11+
useTrans,
12+
} from '@/docs/doc-management';
813
import { useResponsiveStore } from '@/stores';
914

15+
import ChildDocument from '../assets/child-document.svg';
1016
import PinnedDocumentIcon from '../assets/pinned-document.svg';
1117
import SimpleFileIcon from '../assets/simple-document.svg';
1218

@@ -37,6 +43,7 @@ export const SimpleDocItem = ({
3743
const { spacingsTokens, colorsTokens } = useCunninghamTheme();
3844
const { isDesktop } = useResponsiveStore();
3945
const { untitledDocument } = useTrans();
46+
const { isChild } = useDocUtils(doc);
4047

4148
const { emoji, titleWithoutEmoji: displayTitle } = getEmojiAndTitle(
4249
doc.title || untitledDocument,
@@ -73,11 +80,19 @@ export const SimpleDocItem = ({
7380
<DocIcon
7481
emoji={emoji}
7582
defaultIcon={
76-
<SimpleFileIcon
77-
aria-hidden="true"
78-
data-testid="doc-simple-icon"
79-
color={colorsTokens['primary-500']}
80-
/>
83+
isChild ? (
84+
<ChildDocument
85+
aria-hidden="true"
86+
data-testid="doc-child-icon"
87+
color={colorsTokens['primary-500']}
88+
/>
89+
) : (
90+
<SimpleFileIcon
91+
aria-hidden="true"
92+
data-testid="doc-simple-icon"
93+
color={colorsTokens['primary-500']}
94+
/>
95+
)
8196
}
8297
$size="25px"
8398
/>

src/frontend/apps/impress/src/features/docs/doc-management/types.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ export interface Doc {
5656
content: Base64;
5757
created_at: string;
5858
creator: string;
59+
deleted_at: string | null;
5960
depth: number;
6061
path: string;
6162
is_favorite: boolean;
@@ -107,6 +108,7 @@ export enum DocDefaultFilter {
107108
ALL_DOCS = 'all_docs',
108109
MY_DOCS = 'my_docs',
109110
SHARED_WITH_ME = 'shared_with_me',
111+
TRASHBIN = 'trashbin',
110112
}
111113

112114
export type DocsOrdering =

src/frontend/apps/impress/src/features/docs/docs-grid/components/DocsGrid.tsx

Lines changed: 45 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { Box, Card, Text } from '@/components';
77
import { DocDefaultFilter, useInfiniteDocs } from '@/docs/doc-management';
88
import { useResponsiveStore } from '@/stores';
99

10+
import { useInfiniteDocsTrashbin } from '../api';
1011
import { useResponsiveDocGrid } from '../hooks/useResponsiveDocGrid';
1112

1213
import {
@@ -33,13 +34,7 @@ export const DocsGrid = ({
3334
isLoading,
3435
fetchNextPage,
3536
hasNextPage,
36-
} = useInfiniteDocs({
37-
page: 1,
38-
...(target &&
39-
target !== DocDefaultFilter.ALL_DOCS && {
40-
is_creator_me: target === DocDefaultFilter.MY_DOCS,
41-
}),
42-
});
37+
} = useDocsQuery(target);
4338

4439
const docs = data?.pages.flatMap((page) => page.results) ?? [];
4540

@@ -52,12 +47,20 @@ export const DocsGrid = ({
5247
void fetchNextPage();
5348
};
5449

55-
const title =
56-
target === DocDefaultFilter.MY_DOCS
57-
? t('My docs')
58-
: target === DocDefaultFilter.SHARED_WITH_ME
59-
? t('Shared with me')
60-
: t('All docs');
50+
let title = t('All docs');
51+
switch (target) {
52+
case DocDefaultFilter.MY_DOCS:
53+
title = t('My docs');
54+
break;
55+
case DocDefaultFilter.SHARED_WITH_ME:
56+
title = t('Shared with me');
57+
break;
58+
case DocDefaultFilter.TRASHBIN:
59+
title = t('Trashbin');
60+
break;
61+
default:
62+
title = t('All docs');
63+
}
6164

6265
return (
6366
<Box
@@ -121,7 +124,9 @@ export const DocsGrid = ({
121124
role="columnheader"
122125
>
123126
<Text $size="xs" $weight="500" $variation="600">
124-
{t('Updated at')}
127+
{DocDefaultFilter.TRASHBIN === target
128+
? t('Days remaining')
129+
: t('Updated at')}
125130
</Text>
126131
</Box>
127132
)}
@@ -157,3 +162,29 @@ export const DocsGrid = ({
157162
</Box>
158163
);
159164
};
165+
166+
const useDocsQuery = (target: DocDefaultFilter) => {
167+
const trashbinQuery = useInfiniteDocsTrashbin(
168+
{
169+
page: 1,
170+
},
171+
{
172+
enabled: target === DocDefaultFilter.TRASHBIN,
173+
},
174+
);
175+
176+
const docsQuery = useInfiniteDocs(
177+
{
178+
page: 1,
179+
...(target &&
180+
target !== DocDefaultFilter.ALL_DOCS && {
181+
is_creator_me: target === DocDefaultFilter.MY_DOCS,
182+
}),
183+
},
184+
{
185+
enabled: target !== DocDefaultFilter.TRASHBIN,
186+
},
187+
);
188+
189+
return target === DocDefaultFilter.TRASHBIN ? trashbinQuery : docsQuery;
190+
};

src/frontend/apps/impress/src/features/docs/docs-grid/components/DocsGridActions.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ export const DocsGridActions = ({
4545
}
4646
},
4747
testId: `docs-grid-actions-${doc.is_favorite ? 'unpin' : 'pin'}-${doc.id}`,
48+
showSeparator: true,
4849
},
4950
{
5051
label: t('Share'),
@@ -66,9 +67,10 @@ export const DocsGridActions = ({
6667
canSave: false,
6768
});
6869
},
70+
showSeparator: true,
6971
},
7072
{
71-
label: t('Remove'),
73+
label: t('Delete'),
7274
icon: 'delete',
7375
callback: () => deleteModal.open(),
7476
disabled: !doc.abilities.destroy,

0 commit comments

Comments
 (0)