mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-19 11:06:25 +08:00
feat: new collections (#4530)
Co-authored-by: Peng Xiao <pengxiao@outlook.com>
This commit is contained in:
@@ -169,7 +169,6 @@ test.describe('collaboration', () => {
|
||||
const page2 = await context.newPage();
|
||||
await loginUser(page2, user.email);
|
||||
await page2.goto(page.url());
|
||||
await waitForEditorLoad(page2);
|
||||
const collections = page2.getByTestId('collections');
|
||||
await expect(collections.getByText('test collection')).toBeVisible();
|
||||
}
|
||||
|
||||
@@ -25,11 +25,9 @@ import type { Page } from '@playwright/test';
|
||||
import { expect } from '@playwright/test';
|
||||
|
||||
function getAllPage(page: Page) {
|
||||
const newPageButton = page
|
||||
.locator('table')
|
||||
.getByRole('button', { name: 'New Page' });
|
||||
const newPageButton = page.getByTestId('new-page-button');
|
||||
const newPageDropdown = newPageButton.locator('svg');
|
||||
const edgelessBlockCard = page.getByTestId('new-edgeless-button-in-all-page');
|
||||
const edgelessBlockCard = page.getByTestId('switch-edgeless-mode-button');
|
||||
|
||||
async function clickNewPageButton() {
|
||||
return newPageButton.click();
|
||||
@@ -91,7 +89,7 @@ test('allow creation of filters by created time', async ({ page }) => {
|
||||
await clickNewPageButton(page);
|
||||
await clickSideBarAllPageButton(page);
|
||||
await waitForAllPagesLoad(page);
|
||||
const pages = await page.locator('[data-testid="title"]').all();
|
||||
const pages = await page.locator('[data-testid="page-list-item"]').all();
|
||||
const pageCount = pages.length;
|
||||
expect(pageCount).not.toBe(0);
|
||||
await createFirstFilter(page, 'Created');
|
||||
@@ -123,7 +121,7 @@ test('creation of filters by created time, then click date picker to modify the
|
||||
await clickNewPageButton(page);
|
||||
await clickSideBarAllPageButton(page);
|
||||
await waitForAllPagesLoad(page);
|
||||
const pages = await page.locator('[data-testid="title"]').all();
|
||||
const pages = await page.locator('[data-testid="page-list-item"]').all();
|
||||
const pageCount = pages.length;
|
||||
expect(pageCount).not.toBe(0);
|
||||
await createFirstFilter(page, 'Created');
|
||||
@@ -176,18 +174,19 @@ test('allow creation of filters by tags', async ({ page }) => {
|
||||
await waitForEditorLoad(page);
|
||||
await clickSideBarAllPageButton(page);
|
||||
await waitForAllPagesLoad(page);
|
||||
const pages = await page.locator('[data-testid="title"]').all();
|
||||
const pages = await page.locator('[data-testid="page-list-item"]').all();
|
||||
const pageCount = pages.length;
|
||||
expect(pageCount).not.toBe(0);
|
||||
await createFirstFilter(page, 'Tags');
|
||||
await checkFilterName(page, 'is not empty');
|
||||
const pagesWithTags = await page.locator('[data-testid="title"]').all();
|
||||
const pagesWithTags = await page
|
||||
.locator('[data-testid="page-list-item"]')
|
||||
.all();
|
||||
const pagesWithTagsCount = pagesWithTags.length;
|
||||
expect(pagesWithTagsCount).not.toBe(0);
|
||||
await createPageWithTag(page, { title: 'Page A', tags: ['A'] });
|
||||
await createPageWithTag(page, { title: 'Page B', tags: ['B'] });
|
||||
await clickSideBarAllPageButton(page);
|
||||
await createFirstFilter(page, 'Tags');
|
||||
await checkFilterName(page, 'is not empty');
|
||||
await checkPagesCount(page, pagesWithTagsCount + 2);
|
||||
await changeFilter(page, 'contains all');
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { test } from '@affine-test/kit/playwright';
|
||||
import { openHomePage } from '@affine-test/kit/utils/load-page';
|
||||
import { waitForEditorLoad } from '@affine-test/kit/utils/page-logic';
|
||||
import { dragTo, waitForEditorLoad } from '@affine-test/kit/utils/page-logic';
|
||||
import { expect } from '@playwright/test';
|
||||
|
||||
test('drag a page from "All pages" list onto the "Trash" folder in the sidebar to move it to trash list', async ({
|
||||
@@ -11,19 +11,17 @@ test('drag a page from "All pages" list onto the "Trash" folder in the sidebar t
|
||||
{
|
||||
await openHomePage(page);
|
||||
await waitForEditorLoad(page);
|
||||
await page.getByText('All Pages').click();
|
||||
await page.getByTestId('app-sidebar').getByText('All Pages').click();
|
||||
await page.waitForTimeout(500);
|
||||
}
|
||||
|
||||
const title = 'AFFiNE - not just a note-taking app';
|
||||
|
||||
// Drag-and-drop
|
||||
// Ref: https://playwright.dev/docs/input#dragging-manually
|
||||
await page.getByText(title).hover();
|
||||
await page.mouse.down();
|
||||
await page.waitForTimeout(1000);
|
||||
await page.getByText('Trash').hover();
|
||||
await page.mouse.up();
|
||||
await dragTo(
|
||||
page,
|
||||
page.locator(`[role="button"]:has-text("${title}")`),
|
||||
page.getByTestId('app-sidebar').getByText('Trash')
|
||||
);
|
||||
|
||||
await expect(
|
||||
page.getByText('Successfully deleted'),
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
import { test } from '@affine-test/kit/playwright';
|
||||
import {
|
||||
checkDatePicker,
|
||||
selectDateFromDatePicker,
|
||||
} from '@affine-test/kit/utils/filter';
|
||||
import { openHomePage } from '@affine-test/kit/utils/load-page';
|
||||
import {
|
||||
clickNewPageButton,
|
||||
@@ -29,16 +25,17 @@ const createAndPinCollection = async (
|
||||
await getBlockSuiteEditorTitle(page).click();
|
||||
await getBlockSuiteEditorTitle(page).fill('test page');
|
||||
await page.getByTestId('all-pages').click();
|
||||
const cell = page.getByRole('cell', {
|
||||
name: 'test page',
|
||||
});
|
||||
const cell = page.getByTestId('page-list-item-title').getByText('test page');
|
||||
await expect(cell).toBeVisible();
|
||||
await page.getByTestId('create-first-filter').click({
|
||||
delay: 200,
|
||||
});
|
||||
await page.getByTestId(`filler-tag-Created`).click({
|
||||
delay: 200,
|
||||
});
|
||||
await page
|
||||
.getByTestId('variable-select')
|
||||
.getByTestId(`filler-tag-Created`)
|
||||
.click({
|
||||
delay: 200,
|
||||
});
|
||||
await page.getByTestId('save-as-collection').click({
|
||||
delay: 200,
|
||||
});
|
||||
@@ -47,8 +44,6 @@ const createAndPinCollection = async (
|
||||
await title.fill(options?.collectionName ?? 'test collection');
|
||||
await page.getByTestId('save-collection').click();
|
||||
await page.waitForTimeout(100);
|
||||
await page.getByTestId('collection-bar-option-pin').click();
|
||||
await page.waitForTimeout(100);
|
||||
};
|
||||
|
||||
test('Show collections items in sidebar', async ({ page }) => {
|
||||
@@ -93,32 +88,6 @@ test('Show collections items in sidebar', async ({ page }) => {
|
||||
await page.getByTestId('workspace-card').nth(0).click();
|
||||
});
|
||||
|
||||
test('pin and unpin collection', async ({ page }) => {
|
||||
const name = 'asd';
|
||||
await createAndPinCollection(page, { collectionName: name });
|
||||
const collections = page.getByTestId('collections');
|
||||
const items = collections.getByTestId('collection-item');
|
||||
await page.waitForTimeout(50);
|
||||
expect(await items.count()).toBe(1);
|
||||
const first = items.first();
|
||||
await first.hover();
|
||||
await first.getByTestId('collection-options').click();
|
||||
const deleteCollection = page
|
||||
.getByTestId('collection-option')
|
||||
.getByText('Unpin');
|
||||
await deleteCollection.click();
|
||||
await page.waitForTimeout(50);
|
||||
expect(await items.count()).toBe(0);
|
||||
await page.getByTestId('collection-select').click();
|
||||
const option = page.locator('[data-testid=collection-select-option]', {
|
||||
hasText: name,
|
||||
});
|
||||
await option.hover();
|
||||
await option.getByTestId('collection-select-option-pin').click();
|
||||
await page.waitForTimeout(100);
|
||||
expect(await items.count()).toBe(1);
|
||||
});
|
||||
|
||||
test('edit collection', async ({ page }) => {
|
||||
await createAndPinCollection(page);
|
||||
const collections = page.getByTestId('collections');
|
||||
@@ -129,7 +98,7 @@ test('edit collection', async ({ page }) => {
|
||||
await first.getByTestId('collection-options').click();
|
||||
const editCollection = page
|
||||
.getByTestId('collection-option')
|
||||
.getByText('Edit Filter');
|
||||
.getByText('Rename');
|
||||
await editCollection.click();
|
||||
const title = page.getByTestId('input-collection-title');
|
||||
await title.fill('123');
|
||||
@@ -148,14 +117,10 @@ test('edit collection and change filter date', async ({ page }) => {
|
||||
await first.getByTestId('collection-options').click();
|
||||
const editCollection = page
|
||||
.getByTestId('collection-option')
|
||||
.getByText('Edit Filter');
|
||||
.getByText('Rename');
|
||||
await editCollection.click();
|
||||
const title = page.getByTestId('input-collection-title');
|
||||
await title.fill('123');
|
||||
const today = new Date();
|
||||
await page.locator('[data-testid="filter-arg"]').locator('input').click();
|
||||
await selectDateFromDatePicker(page, today);
|
||||
await checkDatePicker(page, today);
|
||||
await page.getByTestId('save-collection').click();
|
||||
await page.waitForTimeout(100);
|
||||
expect(await first.textContent()).toBe('123');
|
||||
@@ -173,15 +138,15 @@ test('create temporary filter by click tag', async ({ page }) => {
|
||||
await page.keyboard.press('Enter');
|
||||
await page.keyboard.press('Escape');
|
||||
await page.locator('.tag', { hasText: 'TODO Tag' }).click();
|
||||
const cell = page.getByRole('cell', {
|
||||
name: 'test page',
|
||||
});
|
||||
const cell = page.getByTestId('page-list-item-title').getByText('test page');
|
||||
await expect(cell).toBeVisible();
|
||||
expect(await page.getByTestId('title').count()).toBe(1);
|
||||
expect(await page.getByTestId('page-list-item').count()).toBe(1);
|
||||
await page.getByTestId('filter-arg').click();
|
||||
|
||||
await page.getByTestId('multi-select-TODO Tag').click();
|
||||
expect(await page.getByTestId('title').count()).toBeGreaterThanOrEqual(2);
|
||||
expect(
|
||||
await page.getByTestId('page-list-item').count()
|
||||
).toBeGreaterThanOrEqual(2);
|
||||
});
|
||||
|
||||
test('add collection from sidebar', async ({ page }) => {
|
||||
@@ -191,9 +156,7 @@ test('add collection from sidebar', async ({ page }) => {
|
||||
await getBlockSuiteEditorTitle(page).click();
|
||||
await getBlockSuiteEditorTitle(page).fill('test page');
|
||||
await page.getByTestId('all-pages').click();
|
||||
const cell = page.getByRole('cell', {
|
||||
name: 'test page',
|
||||
});
|
||||
const cell = page.getByTestId('page-list-item-title').getByText('test page');
|
||||
await expect(cell).toBeVisible();
|
||||
const nullCollection = page.getByTestId(
|
||||
'slider-bar-collection-null-description'
|
||||
|
||||
@@ -3,6 +3,8 @@ import { openHomePage } from '@affine-test/kit/utils/load-page';
|
||||
import {
|
||||
clickNewPageButton,
|
||||
getBlockSuiteEditorTitle,
|
||||
getPageItem,
|
||||
getPageOperationButton,
|
||||
waitForEditorLoad,
|
||||
} from '@affine-test/kit/utils/page-logic';
|
||||
import { expect } from '@playwright/test';
|
||||
@@ -22,22 +24,14 @@ test('page delete -> refresh page -> it should be disappear', async ({
|
||||
name: 'this is a new page delete',
|
||||
});
|
||||
expect(cell).not.toBeUndefined();
|
||||
await page
|
||||
.getByTestId('more-actions-' + newPageId)
|
||||
.getByRole('button')
|
||||
.first()
|
||||
.click();
|
||||
await getPageOperationButton(page, newPageId).click();
|
||||
const deleteBtn = page.getByTestId('move-to-trash');
|
||||
await deleteBtn.click();
|
||||
const confirmTip = page.getByText('Delete page?');
|
||||
expect(confirmTip).not.toBeUndefined();
|
||||
await page.getByRole('button', { name: 'Delete' }).click();
|
||||
await page.getByTestId('trash-page').click();
|
||||
await page
|
||||
.getByTestId('more-actions-' + newPageId)
|
||||
.getByRole('button')
|
||||
.nth(1)
|
||||
.click();
|
||||
await getPageItem(page, newPageId).getByTestId('delete-page-button').click();
|
||||
await page.getByText('Delete permanently?').dblclick();
|
||||
await page.getByRole('button', { name: 'Delete' }).click();
|
||||
await page.reload();
|
||||
@@ -65,21 +59,15 @@ test('page delete -> create new page -> refresh page -> new page should be appea
|
||||
name: 'this is a new page delete',
|
||||
});
|
||||
expect(cellDelete).not.toBeUndefined();
|
||||
await page
|
||||
.getByTestId('more-actions-' + newPageDeleteId)
|
||||
.getByRole('button')
|
||||
.first()
|
||||
.click();
|
||||
await getPageOperationButton(page, newPageDeleteId).click();
|
||||
const deleteBtn = page.getByTestId('move-to-trash');
|
||||
await deleteBtn.click();
|
||||
const confirmTip = page.getByText('Delete page?');
|
||||
expect(confirmTip).not.toBeUndefined();
|
||||
await page.getByRole('button', { name: 'Delete' }).click();
|
||||
await page.getByTestId('trash-page').click();
|
||||
await page
|
||||
.getByTestId('more-actions-' + newPageDeleteId)
|
||||
.getByRole('button')
|
||||
.nth(1)
|
||||
await getPageItem(page, newPageDeleteId)
|
||||
.getByTestId('delete-page-button')
|
||||
.click();
|
||||
await page.getByText('Delete permanently?').dblclick();
|
||||
await page.getByRole('button', { name: 'Delete' }).click();
|
||||
@@ -100,9 +88,9 @@ test('page delete -> create new page -> refresh page -> new page should be appea
|
||||
const newPageId2 = page.url().split('/').reverse()[0];
|
||||
await page.getByTestId('all-pages').click();
|
||||
await page.reload();
|
||||
await page.getByTestId(`page-list-item-${newPageId1}`).click();
|
||||
await getPageItem(page, newPageId1).click();
|
||||
await page.getByTestId('all-pages').click();
|
||||
await page.getByTestId(`page-list-item-${newPageId2}`).click();
|
||||
await getPageItem(page, newPageId2).click();
|
||||
await page.getByTestId('all-pages').click();
|
||||
|
||||
const currentWorkspace = await workspace.current();
|
||||
@@ -134,22 +122,14 @@ test('delete multiple pages -> create multiple pages -> refresh', async ({
|
||||
name: 'this is a new page1',
|
||||
});
|
||||
expect(cellDelete1).not.toBeUndefined();
|
||||
await page
|
||||
.getByTestId('more-actions-' + newPageId1)
|
||||
.getByRole('button')
|
||||
.first()
|
||||
.click();
|
||||
await getPageOperationButton(page, newPageId1).click();
|
||||
const deleteBtn1 = page.getByTestId('move-to-trash');
|
||||
await deleteBtn1.click();
|
||||
const confirmTip1 = page.getByText('Delete page?');
|
||||
expect(confirmTip1).not.toBeUndefined();
|
||||
await page.getByRole('button', { name: 'Delete' }).click();
|
||||
await page.getByTestId('trash-page').click();
|
||||
await page
|
||||
.getByTestId('more-actions-' + newPageId1)
|
||||
.getByRole('button')
|
||||
.nth(1)
|
||||
.click();
|
||||
await getPageItem(page, newPageId1).getByTestId('delete-page-button').click();
|
||||
await page.getByText('Delete permanently?').dblclick();
|
||||
await page.getByRole('button', { name: 'Delete' }).click();
|
||||
await page.getByTestId('all-pages').click();
|
||||
@@ -159,22 +139,14 @@ test('delete multiple pages -> create multiple pages -> refresh', async ({
|
||||
name: 'this is a new page2',
|
||||
});
|
||||
expect(cellDelete2).not.toBeUndefined();
|
||||
await page
|
||||
.getByTestId('more-actions-' + newPageId2)
|
||||
.getByRole('button')
|
||||
.first()
|
||||
.click();
|
||||
await getPageOperationButton(page, newPageId2).click();
|
||||
const deleteBtn2 = page.getByTestId('move-to-trash');
|
||||
await deleteBtn2.click();
|
||||
const confirmTip2 = page.getByText('Delete page?');
|
||||
expect(confirmTip2).not.toBeUndefined();
|
||||
await page.getByRole('button', { name: 'Delete' }).click();
|
||||
await page.getByTestId('trash-page').click();
|
||||
await page
|
||||
.getByTestId('more-actions-' + newPageId2)
|
||||
.getByRole('button')
|
||||
.nth(1)
|
||||
.click();
|
||||
await getPageItem(page, newPageId2).getByTestId('delete-page-button').click();
|
||||
await page.getByText('Delete permanently?').dblclick();
|
||||
await page.getByRole('button', { name: 'Delete' }).click();
|
||||
await page.getByTestId('all-pages').click();
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
clickNewPageButton,
|
||||
clickPageMoreActions,
|
||||
getBlockSuiteEditorTitle,
|
||||
getPageByTitle,
|
||||
waitForEditorLoad,
|
||||
} from '@affine-test/kit/utils/page-logic';
|
||||
import { waitForLogMessage } from '@affine-test/kit/utils/utils';
|
||||
@@ -19,9 +20,9 @@ test('New a page and open it ,then favorite it', async ({
|
||||
await getBlockSuiteEditorTitle(page).click();
|
||||
await getBlockSuiteEditorTitle(page).fill('this is a new page to favorite');
|
||||
await page.getByTestId('all-pages').click();
|
||||
const cell = page.getByRole('cell', {
|
||||
name: 'this is a new page to favorite',
|
||||
});
|
||||
const cell = page
|
||||
.getByTestId('page-list-item')
|
||||
.getByText('this is a new page to favorite');
|
||||
expect(cell).not.toBeUndefined();
|
||||
|
||||
await cell.click();
|
||||
@@ -85,9 +86,7 @@ test('Cancel favorite', async ({ page, workspace }) => {
|
||||
await getBlockSuiteEditorTitle(page).click();
|
||||
await getBlockSuiteEditorTitle(page).fill('this is a new page to favorite');
|
||||
await page.getByTestId('all-pages').click();
|
||||
const cell = page.getByRole('cell', {
|
||||
name: 'this is a new page to favorite',
|
||||
});
|
||||
const cell = getPageByTitle(page, 'this is a new page to favorite');
|
||||
expect(cell).not.toBeUndefined();
|
||||
|
||||
await cell.click();
|
||||
@@ -105,9 +104,10 @@ test('Cancel favorite', async ({ page, workspace }) => {
|
||||
|
||||
await page.getByTestId('all-pages').click();
|
||||
|
||||
const box = await page
|
||||
.getByRole('cell', { name: 'this is a new page to favorite' })
|
||||
.boundingBox();
|
||||
const box = await getPageByTitle(
|
||||
page,
|
||||
'this is a new page to favorite'
|
||||
).boundingBox();
|
||||
//hover table record
|
||||
await page.mouse.move((box?.x ?? 0) + 10, (box?.y ?? 0) + 10);
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
clickPageMoreActions,
|
||||
createLinkedPage,
|
||||
getBlockSuiteEditorTitle,
|
||||
getPageByTitle,
|
||||
waitForEditorLoad,
|
||||
} from '@affine-test/kit/utils/page-logic';
|
||||
import { expect } from '@playwright/test';
|
||||
@@ -17,9 +18,7 @@ test('Show favorite items in sidebar', async ({ page, workspace }) => {
|
||||
await getBlockSuiteEditorTitle(page).fill('this is a new page to favorite');
|
||||
const newPageId = page.url().split('/').reverse()[0];
|
||||
await page.getByTestId('all-pages').click();
|
||||
const cell = page.getByRole('cell', {
|
||||
name: 'this is a new page to favorite',
|
||||
});
|
||||
const cell = getPageByTitle(page, 'this is a new page to favorite');
|
||||
await expect(cell).toBeVisible();
|
||||
await cell.click();
|
||||
await clickPageMoreActions(page);
|
||||
|
||||
@@ -3,6 +3,7 @@ import { openHomePage } from '@affine-test/kit/utils/load-page';
|
||||
import {
|
||||
clickNewPageButton,
|
||||
getBlockSuiteEditorTitle,
|
||||
getPageOperationButton,
|
||||
waitForEditorLoad,
|
||||
} from '@affine-test/kit/utils/page-logic';
|
||||
import { expect } from '@playwright/test';
|
||||
@@ -18,11 +19,7 @@ test('click btn bew page and open in tab', async ({ page, workspace }) => {
|
||||
|
||||
await page.getByTestId('all-pages').click();
|
||||
|
||||
await page
|
||||
.getByTestId('more-actions-' + newPageId)
|
||||
.getByRole('button')
|
||||
.first()
|
||||
.click();
|
||||
await getPageOperationButton(page, newPageId).click();
|
||||
const [newTabPage] = await Promise.all([
|
||||
page.waitForEvent('popup'),
|
||||
page.getByRole('menuitem', { name: 'Open in new tab' }).click(),
|
||||
|
||||
@@ -3,6 +3,7 @@ import { openHomePage } from '@affine-test/kit/utils/load-page';
|
||||
import {
|
||||
clickNewPageButton,
|
||||
getBlockSuiteEditorTitle,
|
||||
getPageOperationButton,
|
||||
waitForEditorLoad,
|
||||
} from '@affine-test/kit/utils/page-logic';
|
||||
import { expect } from '@playwright/test';
|
||||
@@ -23,11 +24,7 @@ test('New a page , then delete it in all pages, restore it', async ({
|
||||
});
|
||||
expect(cell).not.toBeUndefined();
|
||||
|
||||
await page
|
||||
.getByTestId('more-actions-' + newPageId)
|
||||
.getByRole('button')
|
||||
.first()
|
||||
.click();
|
||||
await getPageOperationButton(page, newPageId).click();
|
||||
const deleteBtn = page.getByTestId('move-to-trash');
|
||||
await deleteBtn.click();
|
||||
const confirmTip = page.getByText('Delete page?');
|
||||
@@ -39,11 +36,7 @@ test('New a page , then delete it in all pages, restore it', async ({
|
||||
await page.waitForTimeout(50);
|
||||
const trashPage = page.url();
|
||||
// restore it
|
||||
await page
|
||||
.getByTestId('more-actions-' + newPageId)
|
||||
.getByRole('button')
|
||||
.first()
|
||||
.click();
|
||||
await page.getByTestId('restore-page-button').click();
|
||||
|
||||
// stay in trash page
|
||||
expect(page.url()).toBe(trashPage);
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
clickNewPageButton,
|
||||
clickPageMoreActions,
|
||||
getBlockSuiteEditorTitle,
|
||||
getPageOperationButton,
|
||||
waitForEditorLoad,
|
||||
} from '@affine-test/kit/utils/page-logic';
|
||||
import { expect } from '@playwright/test';
|
||||
@@ -18,9 +19,9 @@ test('New a page ,then open it and show delete modal', async ({
|
||||
await getBlockSuiteEditorTitle(page).click();
|
||||
await getBlockSuiteEditorTitle(page).fill('this is a new page to delete');
|
||||
await page.getByTestId('all-pages').click();
|
||||
const cell = page.getByRole('cell', {
|
||||
name: 'this is a new page to delete',
|
||||
});
|
||||
const cell = page
|
||||
.getByTestId('page-list-item')
|
||||
.getByText('this is a new page to delete');
|
||||
expect(cell).not.toBeUndefined();
|
||||
|
||||
await cell.click();
|
||||
@@ -50,11 +51,7 @@ test('New a page ,then go to all pages and show delete modal', async ({
|
||||
});
|
||||
expect(cell).not.toBeUndefined();
|
||||
|
||||
await page
|
||||
.getByTestId('more-actions-' + newPageId)
|
||||
.getByRole('button')
|
||||
.first()
|
||||
.click();
|
||||
await getPageOperationButton(page, newPageId).click();
|
||||
const deleteBtn = page.getByTestId('move-to-trash');
|
||||
await deleteBtn.click();
|
||||
const confirmTip = page.getByText('Delete page?');
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
clickNewPageButton,
|
||||
clickPageMoreActions,
|
||||
getBlockSuiteEditorTitle,
|
||||
getPageOperationButton,
|
||||
waitForEditorLoad,
|
||||
} from '@affine-test/kit/utils/page-logic';
|
||||
import { expect } from '@playwright/test';
|
||||
@@ -24,11 +25,7 @@ test('New a page , then delete it in all pages, finally find it in trash', async
|
||||
});
|
||||
expect(cell).not.toBeUndefined();
|
||||
|
||||
await page
|
||||
.getByTestId('more-actions-' + newPageId)
|
||||
.getByRole('button')
|
||||
.first()
|
||||
.click();
|
||||
await getPageOperationButton(page, newPageId).click();
|
||||
const deleteBtn = page.getByTestId('move-to-trash');
|
||||
await deleteBtn.click();
|
||||
const confirmTip = page.getByText('Delete page?');
|
||||
|
||||
@@ -47,15 +47,15 @@ test('create one workspace in the workspace list', async ({
|
||||
//check page list length
|
||||
await page.keyboard.press('Escape');
|
||||
await clickSideBarAllPageButton(page);
|
||||
await page.waitForTimeout(1000);
|
||||
await page.waitForTimeout(2000);
|
||||
const pageList = page.locator('[data-testid=page-list-item]');
|
||||
const result = await pageList.count();
|
||||
expect(result).toBe(0);
|
||||
expect(result).toBe(13);
|
||||
await page.reload();
|
||||
await page.waitForTimeout(1000);
|
||||
await page.waitForTimeout(4000);
|
||||
const pageList1 = page.locator('[data-testid=page-list-item]');
|
||||
const result1 = await pageList1.count();
|
||||
expect(result1).toBe(0);
|
||||
expect(result1).toBe(13);
|
||||
const currentWorkspace = await workspace.current();
|
||||
|
||||
expect(currentWorkspace.flavour).toContain('local');
|
||||
|
||||
@@ -22,7 +22,6 @@ const keyboardDownAndSelect = async (page: Page, label: string) => {
|
||||
) {
|
||||
await keyboardDownAndSelect(page, label);
|
||||
} else {
|
||||
await page.pause();
|
||||
await page.keyboard.press('Enter');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -19,10 +19,7 @@ const monthNames = [
|
||||
];
|
||||
|
||||
export const createFirstFilter = async (page: Page, name: string) => {
|
||||
await page
|
||||
.locator('[data-testid="header"]')
|
||||
.locator('button', { hasText: 'Filter' })
|
||||
.click();
|
||||
await page.locator('[data-testid="create-first-filter"]').click();
|
||||
await page
|
||||
.locator('[data-testid="variable-select-item"]', { hasText: name })
|
||||
.click();
|
||||
@@ -42,9 +39,9 @@ const dateFormat = (date: Date) => {
|
||||
};
|
||||
|
||||
export const checkPagesCount = async (page: Page, count: number) => {
|
||||
expect((await page.locator('[data-testid="title"]').all()).length).toBe(
|
||||
count
|
||||
);
|
||||
expect(
|
||||
(await page.locator('[data-testid="page-list-item"]').all()).length
|
||||
).toBe(count);
|
||||
};
|
||||
|
||||
export const checkDatePicker = async (page: Page, date: Date) => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { Page } from '@playwright/test';
|
||||
import type { Locator, Page } from '@playwright/test';
|
||||
import { expect } from '@playwright/test';
|
||||
|
||||
export async function waitForEditorLoad(page: Page) {
|
||||
@@ -16,7 +16,7 @@ export async function waitForAllPagesLoad(page: Page) {
|
||||
|
||||
export async function clickNewPageButton(page: Page) {
|
||||
// fixme(himself65): if too fast, the page will crash
|
||||
await page.getByTestId('new-page-button').click({
|
||||
await page.getByTestId('new-page-button').first().click({
|
||||
delay: 100,
|
||||
});
|
||||
await waitForEditorLoad(page);
|
||||
@@ -51,3 +51,28 @@ export async function clickPageMoreActions(page: Page) {
|
||||
.getByTestId('header-dropDownButton')
|
||||
.click();
|
||||
}
|
||||
|
||||
export const getPageOperationButton = (page: Page, id: string) => {
|
||||
return getPageItem(page, id).getByTestId('page-list-operation-button');
|
||||
};
|
||||
|
||||
export const getPageItem = (page: Page, id: string) => {
|
||||
return page.locator(`[data-page-id="${id}"][data-testid="page-list-item"]`);
|
||||
};
|
||||
|
||||
export const getPageByTitle = (page: Page, title: string) => {
|
||||
return page.getByTestId('page-list-item').getByText(title);
|
||||
};
|
||||
|
||||
export const dragTo = async (page: Page, locator: Locator, target: Locator) => {
|
||||
await locator.hover();
|
||||
await page.mouse.down();
|
||||
await page.waitForTimeout(1000);
|
||||
const targetElement = await target.boundingBox();
|
||||
if (!targetElement) {
|
||||
throw new Error('target element not found');
|
||||
}
|
||||
await page.mouse.move(targetElement.x, targetElement.y);
|
||||
await target.hover();
|
||||
await page.mouse.up();
|
||||
};
|
||||
|
||||
@@ -59,6 +59,6 @@ export const Basic: StoryFn<typeof Checkbox> = props => {
|
||||
Basic.args = {
|
||||
checked: true,
|
||||
disabled: false,
|
||||
intermediate: false,
|
||||
indeterminate: false,
|
||||
onChange: console.log,
|
||||
};
|
||||
|
||||
@@ -1,22 +1,30 @@
|
||||
import { Empty, toast } from '@affine/component';
|
||||
import type { OperationCellProps } from '@affine/component/page-list';
|
||||
import { toast } from '@affine/component';
|
||||
import {
|
||||
FloatingToolbar,
|
||||
NewPageButton,
|
||||
OperationCell,
|
||||
type OperationCellProps,
|
||||
PageList,
|
||||
PageListTrashView,
|
||||
PageListItem,
|
||||
type PageListItemProps,
|
||||
type PageListProps,
|
||||
PageListScrollContainer,
|
||||
PageTags,
|
||||
type PageTagsProps,
|
||||
} from '@affine/component/page-list';
|
||||
import type { Collection } from '@affine/env/filter';
|
||||
import { PageIcon } from '@blocksuite/icons';
|
||||
import { expect } from '@storybook/jest';
|
||||
import { __unstableSchemas, AffineSchemas } from '@blocksuite/blocks/models';
|
||||
import { PageIcon, TagsIcon } from '@blocksuite/icons';
|
||||
import { Schema, Workspace } from '@blocksuite/store';
|
||||
import type { Meta, StoryFn } from '@storybook/react';
|
||||
import { userEvent } from '@storybook/testing-library';
|
||||
import { atom } from 'jotai';
|
||||
import { initEmptyPage } from '@toeverything/infra/blocksuite';
|
||||
import { useState } from 'react';
|
||||
import { withRouter } from 'storybook-addon-react-router-v6';
|
||||
|
||||
export default {
|
||||
title: 'AFFiNE/PageList',
|
||||
component: PageList,
|
||||
parameters: {
|
||||
layout: 'fullscreen',
|
||||
chromatic: { disableSnapshot: true },
|
||||
},
|
||||
} satisfies Meta;
|
||||
@@ -30,7 +38,6 @@ AffineOperationCell.args = {
|
||||
isPublic: true,
|
||||
onToggleFavoritePage: () => toast('Toggle favorite page'),
|
||||
onDisablePublicSharing: () => toast('Disable public sharing'),
|
||||
onOpenPageInNewTab: () => toast('Open page in new tab'),
|
||||
onRemoveToTrash: () => toast('Remove to trash'),
|
||||
};
|
||||
AffineOperationCell.play = async ({ canvasElement }) => {
|
||||
@@ -59,163 +66,235 @@ AffineNewPageButton.play = async ({ canvasElement }) => {
|
||||
await userEvent.click(dropdown);
|
||||
};
|
||||
|
||||
export const AffineAllPageList: StoryFn<typeof PageList> = ({ ...props }) => (
|
||||
<PageList {...props} />
|
||||
const testTags = [
|
||||
{
|
||||
color: 'red',
|
||||
id: 'test-tag-id-0',
|
||||
value: 'foo',
|
||||
},
|
||||
{
|
||||
color: 'pink',
|
||||
id: 'test-tag-id-1',
|
||||
value: 'bar',
|
||||
},
|
||||
{
|
||||
color: 'purple',
|
||||
id: 'test-tag-id-2',
|
||||
value: 'foobar',
|
||||
},
|
||||
{
|
||||
color: 'black',
|
||||
id: 'test-tag-id-3',
|
||||
value: 'affine',
|
||||
},
|
||||
{
|
||||
color: 'orange',
|
||||
id: 'test-tag-id-4',
|
||||
value: 'blocksuite',
|
||||
},
|
||||
{
|
||||
color: 'yellow',
|
||||
id: 'test-tag-id-5',
|
||||
value: 'toeverything',
|
||||
},
|
||||
{
|
||||
color: 'green',
|
||||
id: 'test-tag-id-6',
|
||||
value: 'toeverything',
|
||||
},
|
||||
{
|
||||
color: 'blue',
|
||||
id: 'test-tag-id-7',
|
||||
value: 'toeverything',
|
||||
},
|
||||
{
|
||||
color: 'indigo',
|
||||
id: 'test-tag-id-8',
|
||||
value: 'toeverything',
|
||||
},
|
||||
{
|
||||
color: 'teal',
|
||||
id: 'test-tag-id-9',
|
||||
value: 'toeverything',
|
||||
},
|
||||
{
|
||||
color: 'cyan',
|
||||
id: 'test-tag-id-10',
|
||||
value: 'toeverything',
|
||||
},
|
||||
{
|
||||
color: 'gray',
|
||||
id: 'test-tag-id-11',
|
||||
value: 'toeverything',
|
||||
},
|
||||
{
|
||||
color: 'red',
|
||||
id: 'test-tag-id-12',
|
||||
value: 'toeverything',
|
||||
},
|
||||
];
|
||||
|
||||
export const ListItem: StoryFn<PageListItemProps> = props => (
|
||||
<PageListItem {...props}></PageListItem>
|
||||
);
|
||||
|
||||
const baseAtom = atom<Collection[]>([]);
|
||||
AffineAllPageList.args = {
|
||||
isPublicWorkspace: false,
|
||||
onCreateNewPage: () => toast('Create new page'),
|
||||
onCreateNewEdgeless: () => toast('Create new edgeless'),
|
||||
onImportFile: () => toast('Import file'),
|
||||
collectionsAtom: atom(
|
||||
get => get(baseAtom),
|
||||
async (_, set, update) => {
|
||||
set(baseAtom, update);
|
||||
}
|
||||
),
|
||||
list: [
|
||||
{
|
||||
pageId: '1',
|
||||
favorite: false,
|
||||
icon: <PageIcon />,
|
||||
isPublicPage: true,
|
||||
title: 'Last Page',
|
||||
tags: [],
|
||||
preview: 'this is page preview',
|
||||
createDate: new Date('2021-01-01'),
|
||||
updatedDate: new Date('2023-08-15'),
|
||||
bookmarkPage: () => toast('Bookmark page'),
|
||||
onClickPage: () => toast('Click page'),
|
||||
onDisablePublicSharing: () => toast('Disable public sharing'),
|
||||
onOpenPageInNewTab: () => toast('Open page in new tab'),
|
||||
removeToTrash: () => toast('Remove to trash'),
|
||||
},
|
||||
{
|
||||
pageId: '3',
|
||||
favorite: false,
|
||||
icon: <PageIcon />,
|
||||
isPublicPage: true,
|
||||
title:
|
||||
'1 Example Public Page with long title that will be truncated because it is too too long',
|
||||
tags: [],
|
||||
preview:
|
||||
'this is page preview and it is very long and will be truncated because it is too long and it is very long and will be truncated because it is too long',
|
||||
createDate: new Date('2021-01-01'),
|
||||
updatedDate: new Date('2021-01-02'),
|
||||
bookmarkPage: () => toast('Bookmark page'),
|
||||
onClickPage: () => toast('Click page'),
|
||||
onDisablePublicSharing: () => toast('Disable public sharing'),
|
||||
onOpenPageInNewTab: () => toast('Open page in new tab'),
|
||||
removeToTrash: () => toast('Remove to trash'),
|
||||
},
|
||||
{
|
||||
pageId: '2',
|
||||
favorite: true,
|
||||
isPublicPage: false,
|
||||
icon: <PageIcon />,
|
||||
title: '2 Favorited Page 2021',
|
||||
tags: [],
|
||||
createDate: new Date('2021-01-02'),
|
||||
updatedDate: new Date('2021-01-01'),
|
||||
bookmarkPage: () => toast('Bookmark page'),
|
||||
onClickPage: () => toast('Click page'),
|
||||
onDisablePublicSharing: () => toast('Disable public sharing'),
|
||||
onOpenPageInNewTab: () => toast('Open page in new tab'),
|
||||
removeToTrash: () => toast('Remove to trash'),
|
||||
},
|
||||
{
|
||||
pageId: '4',
|
||||
favorite: false,
|
||||
isPublicPage: false,
|
||||
icon: <PageIcon />,
|
||||
title: 'page created in 2023-04-01',
|
||||
tags: [],
|
||||
createDate: new Date('2023-04-01'),
|
||||
updatedDate: new Date('2023-04-01'),
|
||||
bookmarkPage: () => toast('Bookmark page'),
|
||||
onClickPage: () => toast('Click page'),
|
||||
onDisablePublicSharing: () => toast('Disable public sharing'),
|
||||
onOpenPageInNewTab: () => toast('Open page in new tab'),
|
||||
removeToTrash: () => toast('Remove to trash'),
|
||||
},
|
||||
],
|
||||
ListItem.args = {
|
||||
pageId: 'test-page-id',
|
||||
title: 'Test Page Title',
|
||||
preview:
|
||||
'this is page preview and it is very long and will be truncated because it is too long and it is very long and will be truncated because it is too long',
|
||||
icon: <PageIcon />,
|
||||
to: '/hello',
|
||||
selectable: true,
|
||||
createDate: new Date('2021-01-01'),
|
||||
updatedDate: new Date('2023-08-15'),
|
||||
draggable: true,
|
||||
tags: testTags,
|
||||
selected: true,
|
||||
};
|
||||
|
||||
export const AffineEmptyAllPageList: StoryFn<typeof PageList> = ({
|
||||
...props
|
||||
}) => <PageList {...props} />;
|
||||
ListItem.decorators = [withRouter];
|
||||
|
||||
AffineEmptyAllPageList.args = {
|
||||
isPublicWorkspace: false,
|
||||
onCreateNewPage: () => toast('Create new page'),
|
||||
onCreateNewEdgeless: () => toast('Create new edgeless'),
|
||||
onImportFile: () => toast('Import file'),
|
||||
list: [],
|
||||
fallback: (
|
||||
<Empty
|
||||
title="Empty"
|
||||
description={
|
||||
<div>
|
||||
empty description, click{' '}
|
||||
<button
|
||||
onClick={() => {
|
||||
toast('click');
|
||||
}}
|
||||
>
|
||||
button
|
||||
</button>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
),
|
||||
export const ListItemTags: StoryFn<PageTagsProps> = props => (
|
||||
<div style={{ display: 'flex', justifyContent: 'flex-end' }}>
|
||||
<div style={{ width: '300px' }}>
|
||||
<PageTags {...props}></PageTags>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
ListItemTags.args = {
|
||||
tags: testTags,
|
||||
hoverExpandDirection: 'left',
|
||||
widthOnHover: 600,
|
||||
maxItems: 5,
|
||||
};
|
||||
|
||||
export const AffinePublicPageList: StoryFn<typeof PageList> = ({
|
||||
...props
|
||||
}) => <PageList {...props} />;
|
||||
AffinePublicPageList.args = {
|
||||
...AffineAllPageList.args,
|
||||
isPublicWorkspace: true,
|
||||
export const PageListStory: StoryFn<PageListProps> = (props, { loaded }) => {
|
||||
return (
|
||||
<PageListScrollContainer
|
||||
style={{
|
||||
height: '100vh',
|
||||
}}
|
||||
>
|
||||
<PageList {...props} {...loaded}></PageList>
|
||||
</PageListScrollContainer>
|
||||
);
|
||||
};
|
||||
|
||||
export const AffineAllPageMobileList: StoryFn<typeof PageList> = ({
|
||||
...props
|
||||
}) => <PageList {...props} />;
|
||||
PageListStory.args = {
|
||||
groupBy: 'createDate',
|
||||
};
|
||||
|
||||
AffineAllPageMobileList.args = AffineAllPageList.args;
|
||||
AffineAllPageMobileList.parameters = {
|
||||
viewport: {
|
||||
defaultViewport: 'mobile2',
|
||||
PageListStory.argTypes = {
|
||||
selectable: {
|
||||
control: 'radio',
|
||||
options: [true, 'toggle', false],
|
||||
},
|
||||
hideHeader: {
|
||||
type: 'boolean',
|
||||
},
|
||||
};
|
||||
|
||||
export const AffineTrashPageList: StoryFn<typeof PageListTrashView> = ({
|
||||
...props
|
||||
}) => <PageListTrashView {...props} />;
|
||||
async function createAndInitPage(
|
||||
workspace: Workspace,
|
||||
title: string,
|
||||
preview: string
|
||||
) {
|
||||
const page = workspace.createPage();
|
||||
await initEmptyPage(page, title);
|
||||
page.getBlockByFlavour('affine:paragraph').at(0)?.text?.insert(preview, 0);
|
||||
return page;
|
||||
}
|
||||
|
||||
AffineTrashPageList.args = {
|
||||
list: [
|
||||
{
|
||||
pageId: '1',
|
||||
icon: <PageIcon />,
|
||||
title: 'Example Page',
|
||||
preview: 'this is trash page preview',
|
||||
createDate: new Date('2021-01-01'),
|
||||
trashDate: new Date('2021-01-01'),
|
||||
onClickPage: () => toast('Click page'),
|
||||
onPermanentlyDeletePage: () => toast('Permanently delete page'),
|
||||
onRestorePage: () => toast('Restore page'),
|
||||
},
|
||||
{
|
||||
pageId: '2',
|
||||
icon: <PageIcon />,
|
||||
title: 'Example Page with long title that will be truncated',
|
||||
createDate: new Date('2021-01-01'),
|
||||
onClickPage: () => toast('Click page'),
|
||||
onPermanentlyDeletePage: () => toast('Permanently delete page'),
|
||||
onRestorePage: () => toast('Restore page'),
|
||||
},
|
||||
],
|
||||
PageListStory.loaders = [
|
||||
async () => {
|
||||
const schema = new Schema();
|
||||
schema.register(AffineSchemas).register(__unstableSchemas);
|
||||
const workspace = new Workspace({
|
||||
id: 'test-workspace-id',
|
||||
schema,
|
||||
});
|
||||
|
||||
workspace.meta.setProperties({
|
||||
tags: {
|
||||
options: structuredClone(testTags),
|
||||
},
|
||||
});
|
||||
|
||||
const page1 = await createAndInitPage(
|
||||
workspace,
|
||||
'This is page 1',
|
||||
'Hello World from page 1'
|
||||
);
|
||||
const page2 = await createAndInitPage(
|
||||
workspace,
|
||||
'This is page 2',
|
||||
'Hello World from page 2'
|
||||
);
|
||||
const page3 = await createAndInitPage(
|
||||
workspace,
|
||||
'This is page 3',
|
||||
'Hello World from page 3Hello World from page 3Hello World from page 3Hello World from page 3Hello World from page 3'
|
||||
);
|
||||
|
||||
await createAndInitPage(
|
||||
workspace,
|
||||
'This is page 4',
|
||||
'Hello World from page 3Hello World from page 3Hello World from page 3Hello World from page 3Hello World from page 3'
|
||||
);
|
||||
|
||||
page1.meta.createDate = new Date('2021-01-01').getTime();
|
||||
page2.meta.createDate = page2.meta.createDate - 3600 * 1000 * 24;
|
||||
page3.meta.createDate = page3.meta.createDate - 3600 * 1000 * 24 * 7;
|
||||
|
||||
workspace.meta.pageMetas[3].tags = testTags.slice(0, 3).map(t => t.id);
|
||||
workspace.meta.pageMetas[2].tags = testTags.slice(0, 12).map(t => t.id);
|
||||
|
||||
return {
|
||||
blockSuiteWorkspace: workspace,
|
||||
pages: workspace.meta.pages,
|
||||
};
|
||||
},
|
||||
];
|
||||
|
||||
export const FloatingToolbarStory: StoryFn<typeof FloatingToolbar> = props => {
|
||||
const [open, setOpen] = useState(false);
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
height: '100vh',
|
||||
overflow: 'auto',
|
||||
}}
|
||||
>
|
||||
<button
|
||||
style={{
|
||||
border: '1px solid black',
|
||||
padding: '10px',
|
||||
}}
|
||||
onClick={() => setOpen(o => !o)}
|
||||
>
|
||||
{open ? 'hide' : 'show'}
|
||||
</button>
|
||||
<FloatingToolbar
|
||||
style={{ position: 'fixed', bottom: '20px', width: '100%' }}
|
||||
{...props}
|
||||
open={open}
|
||||
onOpenChange={setOpen}
|
||||
>
|
||||
<FloatingToolbar.Item>10 Selected</FloatingToolbar.Item>
|
||||
<FloatingToolbar.Separator />
|
||||
<FloatingToolbar.Button
|
||||
icon={<TagsIcon />}
|
||||
label="Add Tags"
|
||||
onClick={console.log}
|
||||
/>
|
||||
<FloatingToolbar.Button
|
||||
icon={<TagsIcon />}
|
||||
label="Add Tags"
|
||||
onClick={console.log}
|
||||
/>
|
||||
</FloatingToolbar>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user