From 5bd9c7a2a3d23c219b68c09d593c8ba757537a23 Mon Sep 17 00:00:00 2001 From: pengx17 Date: Thu, 6 Jun 2024 06:29:41 +0000 Subject: [PATCH] feat: allow search for doc without showing modal (#7138) depends on https://github.com/toeverything/blocksuite/pull/7199#pullrequestreview-2095567573 fix TOV-858, fix AFF-1132 --- .../block-suite-editor/lit-adaper.tsx | 29 ++++++++++++- .../specs/custom/spec-patchers.ts | 36 +++++++++++++--- tests/affine-local/e2e/quick-search.spec.ts | 43 ++++++++++++++++++- 3 files changed, 99 insertions(+), 9 deletions(-) diff --git a/packages/frontend/core/src/components/blocksuite/block-suite-editor/lit-adaper.tsx b/packages/frontend/core/src/components/blocksuite/block-suite-editor/lit-adaper.tsx index ed4b7793f..1eba5a13e 100644 --- a/packages/frontend/core/src/components/blocksuite/block-suite-editor/lit-adaper.tsx +++ b/packages/frontend/core/src/components/blocksuite/block-suite-editor/lit-adaper.tsx @@ -208,9 +208,36 @@ export const BlocksuiteEdgelessEditor = forwardRef< BlocksuiteEditorProps >(function BlocksuiteEdgelessEditor({ page }, ref) { const [specs, portals] = usePatchSpecs(page, EdgelessModeSpecs); + const editorRef = useRef(null); + + const onDocRef = useCallback( + (el: EdgelessEditor) => { + editorRef.current = el; + if (ref) { + if (typeof ref === 'function') { + ref(el); + } else { + ref.current = el; + } + } + }, + [ref] + ); + + useEffect(() => { + if (editorRef.current) { + editorRef.current.updateComplete + .then(() => { + // make sure editor can get keyboard events on showing up + editorRef.current?.querySelector('affine-edgeless-root')?.click(); + }) + .catch(console.error); + } + }, []); + return ( <> - + {portals} ); diff --git a/packages/frontend/core/src/components/blocksuite/block-suite-editor/specs/custom/spec-patchers.ts b/packages/frontend/core/src/components/blocksuite/block-suite-editor/specs/custom/spec-patchers.ts index 604d536c5..3be4804ea 100644 --- a/packages/frontend/core/src/components/blocksuite/block-suite-editor/specs/custom/spec-patchers.ts +++ b/packages/frontend/core/src/components/blocksuite/block-suite-editor/specs/custom/spec-patchers.ts @@ -7,7 +7,10 @@ import { type useConfirmModal, type usePromptModal, } from '@affine/component'; -import type { QuickSearchService } from '@affine/core/modules/cmdk'; +import type { + QuickSearchService, + SearchCallbackResult, +} from '@affine/core/modules/cmdk'; import type { PeekViewService } from '@affine/core/modules/peek-view'; import type { ActivePeekView } from '@affine/core/modules/peek-view/entities/peek-view'; import { DebugLogger } from '@affine/debug'; @@ -254,13 +257,34 @@ export function patchQuickSearchService( patchSpecService(rootSpec, pageService => { pageService.quickSearchService = { async searchDoc(options) { - const result = await service.quickSearch.search(options.userInput); - if (result) { - if ('docId' in result) { - return result; + let searchResult: SearchCallbackResult | null = null; + if (options.skipSelection) { + const query = options.userInput; + if (!query) { + logger.error('No user input provided'); + } else { + const searchedDoc = service.quickSearch + .getSearchedDocs(query) + .at(0); + if (searchedDoc) { + searchResult = { + docId: searchedDoc.doc.id, + blockId: searchedDoc.blockId, + action: 'insert', + query, + }; + } + } + } else { + searchResult = await service.quickSearch.search(options.userInput); + } + + if (searchResult) { + if ('docId' in searchResult) { + return searchResult; } else { return { - userInput: result.query, + userInput: searchResult.query, action: 'insert', }; } diff --git a/tests/affine-local/e2e/quick-search.spec.ts b/tests/affine-local/e2e/quick-search.spec.ts index 25ef4cb5b..1189822fb 100644 --- a/tests/affine-local/e2e/quick-search.spec.ts +++ b/tests/affine-local/e2e/quick-search.spec.ts @@ -1,4 +1,5 @@ import { test } from '@affine-test/kit/playwright'; +import { clickEdgelessModeButton } from '@affine-test/kit/utils/editor'; import { withCtrlOrMeta } from '@affine-test/kit/utils/keyboard'; import { openHomePage } from '@affine-test/kit/utils/load-page'; import { @@ -467,7 +468,7 @@ test('disable quick search when the link-popup is visitable', async ({ await openQuickSearchByShortcut(page); const quickSearch = page.locator('[data-testid=cmdk-quick-search]'); await expect(quickSearch).toBeVisible(); - await withCtrlOrMeta(page, () => page.keyboard.press('k', { delay: 50 })); + await withCtrlOrMeta(page, () => page.keyboard.press('k')); await getBlockSuiteEditorTitle(page).click(); await getBlockSuiteEditorTitle(page).fill(specialTitle); @@ -475,9 +476,47 @@ test('disable quick search when the link-popup is visitable', async ({ await page.keyboard.insertText('1234567890'); await page.getByText('1234567890').dblclick(); - await withCtrlOrMeta(page, () => page.keyboard.press('k', { delay: 50 })); + await withCtrlOrMeta(page, () => page.keyboard.press('k')); const linkPopup = page.locator('.affine-link-popover'); await expect(linkPopup).toBeVisible(); const currentQuickSearch = page.locator('[data-testid=cmdk-quick-search]'); await expect(currentQuickSearch).not.toBeVisible(); }); + +test('can use @ to open quick search to search for doc and insert into canvas', async ({ + page, +}) => { + await openHomePage(page); + await waitForEditorLoad(page); + + const url = page.url(); + + await clickNewPageButton(page); + await clickEdgelessModeButton(page); + await page.locator('affine-edgeless-root').press('@'); + + const quickSearch = page.locator('[data-testid=cmdk-quick-search]'); + await expect(quickSearch).toBeVisible(); + + // search by using url + await insertInputText(page, url); + + // expect the default page to be selected + await expect(page.locator('[cmdk-group-items] [cmdk-item]')).toHaveCount(1); + + // press enter to insert the page to canvas + await page.keyboard.press('Enter'); + await expect(page.locator('affine-embed-synced-doc-block')).toBeVisible(); + + await page.locator('affine-embed-synced-doc-block').click(); + // change to linked card + await page.locator('edgeless-tool-icon-button.card').click(); + + await expect( + page.locator('.affine-embed-linked-doc-content-title') + ).toContainText('Write, Draw, Plan all at Once'); + + // double clock to show peek view + await page.locator('affine-embed-linked-doc-block').dblclick(); + await expect(page.getByTestId('peek-view-modal')).toBeVisible(); +});