From b782b3fb1bca10536f312cc5d6e79488bc74b33e Mon Sep 17 00:00:00 2001 From: EYHN Date: Tue, 12 Dec 2023 10:22:34 +0000 Subject: [PATCH] fix(core): polling to search in cmdk (#5274) This is a temporary solution until https://github.com/toeverything/blocksuite/issues/5668 be solved. --- .../core/src/components/pure/cmdk/data.tsx | 39 +++++++++++++--- .../core/src/components/pure/cmdk/main.tsx | 16 ++++++- tests/affine-local/e2e/quick-search.spec.ts | 46 +++++++++++-------- 3 files changed, 74 insertions(+), 27 deletions(-) diff --git a/packages/frontend/core/src/components/pure/cmdk/data.tsx b/packages/frontend/core/src/components/pure/cmdk/data.tsx index 0be2d3c3df..b32b2d67ee 100644 --- a/packages/frontend/core/src/components/pure/cmdk/data.tsx +++ b/packages/frontend/core/src/components/pure/cmdk/data.tsx @@ -25,7 +25,7 @@ import { } from '@toeverything/infra/command'; import { atom, useAtomValue } from 'jotai'; import { groupBy } from 'lodash-es'; -import { useCallback, useMemo } from 'react'; +import { useCallback, useEffect, useMemo, useState } from 'react'; import { openQuickSearchModalAtom, @@ -173,13 +173,21 @@ export const pageToCommand = ( title: title, }; + // hack: when comparing, the part between >>> and <<< will be ignored + // adding this patch so that CMDK will not complain about duplicated commands + const id = + title + + (label?.subTitle || '') + + valueWrapperStart + + page.id + + '.' + + category + + valueWrapperEnd; + return { - id: page.id, + id, label: commandLabel, - // hack: when comparing, the part between >>> and <<< will be ignored - // adding this patch so that CMDK will not complain about duplicated commands - value: - title + valueWrapperStart + page.id + '.' + category + valueWrapperEnd, + value: id, originalValue: title, category: category, run: () => { @@ -216,7 +224,25 @@ export const usePageCommands = () => { const navigationHelper = useNavigateHelper(); const t = useAFFiNEI18N(); + const [searchTime, setSearchTime] = useState(0); + + // HACK: blocksuite indexer is async, + // so we need to re-search after it has been updated + useEffect(() => { + let timer: NodeJS.Timeout | null = null; + const dosearch = () => { + setSearchTime(Date.now()); + timer = setTimeout(dosearch, 500); + }; + timer = setTimeout(dosearch, 500); + return () => { + if (timer) clearTimeout(timer); + }; + }, []); + return useMemo(() => { + searchTime; // hack to make the searchTime as a dependency + let results: CMDKCommand[] = []; if (query.trim() === '') { results = recentPages.map(page => { @@ -322,6 +348,7 @@ export const usePageCommands = () => { store, t, workspace.blockSuiteWorkspace, + searchTime, ]); }; diff --git a/packages/frontend/core/src/components/pure/cmdk/main.tsx b/packages/frontend/core/src/components/pure/cmdk/main.tsx index 918b78e539..f91e57849f 100644 --- a/packages/frontend/core/src/components/pure/cmdk/main.tsx +++ b/packages/frontend/core/src/components/pure/cmdk/main.tsx @@ -7,7 +7,13 @@ import { useAsyncCallback } from '@toeverything/hooks/affine-async-hooks'; import type { CommandCategory } from '@toeverything/infra/command'; import clsx from 'clsx'; import { useAtom, useAtomValue } from 'jotai'; -import { Suspense, useLayoutEffect, useMemo, useState } from 'react'; +import { + Suspense, + useCallback, + useLayoutEffect, + useMemo, + useState, +} from 'react'; import { cmdkQueryAtom, @@ -189,6 +195,12 @@ export const CMDKContainer = ({ const isInEditor = pageMeta !== undefined; const [opening, setOpening] = useState(open); + const handleFocus = useCallback((ref: HTMLInputElement | null) => { + if (ref) { + window.setTimeout(() => ref.focus(), 0); + } + }, []); + // fix list height animation on openning useLayoutEffect(() => { if (open) { @@ -235,7 +247,7 @@ export const CMDKContainer = ({ ) : null} { } }; +const insertInputText = async (page: Page, text: string) => { + await page.locator('[cmdk-input]').fill(text); + const actual = await page.locator('[cmdk-input]').inputValue(); + expect(actual).toBe(text); +}; + const keyboardDownAndSelect = async (page: Page, label: string) => { await page.keyboard.press('ArrowDown'); if ( @@ -77,14 +83,16 @@ async function waitForScrollToFinish(page: Page) { } async function assertResultList(page: Page, texts: string[]) { - const actual = await page - .locator('[cmdk-item] [data-testid=cmdk-label]') - .allInnerTexts(); - const actualSplit = actual[0].split('\n'); - expect(actualSplit[0]).toEqual(texts[0]); - if (actualSplit[1]) { - expect(actualSplit[1]).toEqual(texts[1]); - } + await expect(async () => { + const actual = await page + .locator('[cmdk-item] [data-testid=cmdk-label]') + .allInnerTexts(); + const actualSplit = actual[0].split('\n'); + expect(actualSplit[0]).toEqual(texts[0]); + if (actualSplit[1]) { + expect(actualSplit[1]).toEqual(texts[1]); + } + }).toPass(); } async function titleIsFocused(page: Page) { @@ -137,7 +145,7 @@ test('Create a new page with keyword', async ({ page }) => { await waitForEditorLoad(page); await clickNewPageButton(page); await openQuickSearchByShortcut(page); - await page.keyboard.insertText('"test123456"'); + await insertInputText(page, '"test123456"'); const addNewPage = page.locator( '[cmdk-item] >> text=New ""test123456"" Page' ); @@ -151,9 +159,7 @@ test('Enter a keyword to search for', async ({ page }) => { await waitForEditorLoad(page); await clickNewPageButton(page); await openQuickSearchByShortcut(page); - await page.keyboard.insertText('test123456'); - const actual = await page.locator('[cmdk-input]').inputValue(); - expect(actual).toBe('test123456'); + await insertInputText(page, 'test123456'); }); test('Create a new page and search this page', async ({ page }) => { @@ -162,7 +168,7 @@ test('Create a new page and search this page', async ({ page }) => { await clickNewPageButton(page); await openQuickSearchByShortcut(page); // input title and create new page - await page.keyboard.insertText('test123456'); + await insertInputText(page, 'test123456'); await page.waitForTimeout(300); const addNewPage = page.locator('[cmdk-item] >> text=New "test123456" Page'); await addNewPage.click(); @@ -170,7 +176,7 @@ test('Create a new page and search this page', async ({ page }) => { await page.waitForTimeout(300); await assertTitle(page, 'test123456'); await openQuickSearchByShortcut(page); - await page.keyboard.insertText('test123456'); + await insertInputText(page, 'test123456'); await page.waitForTimeout(300); await assertResultList(page, ['test123456', 'test123456']); await page.keyboard.press('Enter'); @@ -180,7 +186,7 @@ test('Create a new page and search this page', async ({ page }) => { await page.reload(); await waitForEditorLoad(page); await openQuickSearchByShortcut(page); - await page.keyboard.insertText('test123456'); + await insertInputText(page, 'test123456'); await page.waitForTimeout(300); await assertResultList(page, ['test123456', 'test123456']); await page.keyboard.press('Enter'); @@ -375,7 +381,7 @@ test('show not found item', async ({ page }) => { await clickNewPageButton(page); await openQuickSearchByShortcut(page); // input title and create new page - await page.keyboard.insertText('test123456'); + await insertInputText(page, 'test123456'); const notFoundItem = page.getByTestId('cmdk-search-not-found'); await expect(notFoundItem).toBeVisible(); await expect(notFoundItem).toHaveText('Search for "test123456"'); @@ -395,15 +401,17 @@ test('can use cmdk to search page content and scroll to it, then the block will await page.keyboard.press('Enter', { delay: 10 }); } await page.keyboard.insertText('123456'); + const textBlock = page.getByText('123456'); + await expect(textBlock).toBeVisible(); await clickSideBarAllPageButton(page); await openQuickSearchByShortcut(page); - await page.keyboard.insertText('123456'); + await insertInputText(page, '123456'); await page.waitForTimeout(300); await assertResultList(page, [ 'this is a new page to search for content', '123456', ]); - await page.keyboard.press('Enter'); + await page.locator('[cmdk-item] [data-testid=cmdk-label]').first().click(); await waitForScrollToFinish(page); const isVisitable = await checkElementIsInView(page, '123456'); expect(isVisitable).toBe(true); @@ -424,7 +432,7 @@ test('Create a new page with special characters in the title and search for this await getBlockSuiteEditorTitle(page).fill(specialTitle); await openQuickSearchByShortcut(page); - await page.keyboard.insertText(specialTitle); + await insertInputText(page, specialTitle); await page.waitForTimeout(300); await assertResultList(page, [specialTitle, specialTitle]);