fix(core): polling to search in cmdk (#5274)

This is a temporary solution until https://github.com/toeverything/blocksuite/issues/5668 be solved.
This commit is contained in:
EYHN
2023-12-12 10:22:34 +00:00
committed by JimmFly
parent 9aa33d0228
commit b782b3fb1b
3 changed files with 74 additions and 27 deletions

View File

@@ -25,7 +25,7 @@ import {
} from '@toeverything/infra/command'; } from '@toeverything/infra/command';
import { atom, useAtomValue } from 'jotai'; import { atom, useAtomValue } from 'jotai';
import { groupBy } from 'lodash-es'; import { groupBy } from 'lodash-es';
import { useCallback, useMemo } from 'react'; import { useCallback, useEffect, useMemo, useState } from 'react';
import { import {
openQuickSearchModalAtom, openQuickSearchModalAtom,
@@ -173,13 +173,21 @@ export const pageToCommand = (
title: title, 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 { return {
id: page.id, id,
label: commandLabel, label: commandLabel,
// hack: when comparing, the part between >>> and <<< will be ignored value: id,
// adding this patch so that CMDK will not complain about duplicated commands
value:
title + valueWrapperStart + page.id + '.' + category + valueWrapperEnd,
originalValue: title, originalValue: title,
category: category, category: category,
run: () => { run: () => {
@@ -216,7 +224,25 @@ export const usePageCommands = () => {
const navigationHelper = useNavigateHelper(); const navigationHelper = useNavigateHelper();
const t = useAFFiNEI18N(); const t = useAFFiNEI18N();
const [searchTime, setSearchTime] = useState<number>(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(() => { return useMemo(() => {
searchTime; // hack to make the searchTime as a dependency
let results: CMDKCommand[] = []; let results: CMDKCommand[] = [];
if (query.trim() === '') { if (query.trim() === '') {
results = recentPages.map(page => { results = recentPages.map(page => {
@@ -322,6 +348,7 @@ export const usePageCommands = () => {
store, store,
t, t,
workspace.blockSuiteWorkspace, workspace.blockSuiteWorkspace,
searchTime,
]); ]);
}; };

View File

@@ -7,7 +7,13 @@ import { useAsyncCallback } from '@toeverything/hooks/affine-async-hooks';
import type { CommandCategory } from '@toeverything/infra/command'; import type { CommandCategory } from '@toeverything/infra/command';
import clsx from 'clsx'; import clsx from 'clsx';
import { useAtom, useAtomValue } from 'jotai'; import { useAtom, useAtomValue } from 'jotai';
import { Suspense, useLayoutEffect, useMemo, useState } from 'react'; import {
Suspense,
useCallback,
useLayoutEffect,
useMemo,
useState,
} from 'react';
import { import {
cmdkQueryAtom, cmdkQueryAtom,
@@ -189,6 +195,12 @@ export const CMDKContainer = ({
const isInEditor = pageMeta !== undefined; const isInEditor = pageMeta !== undefined;
const [opening, setOpening] = useState(open); const [opening, setOpening] = useState(open);
const handleFocus = useCallback((ref: HTMLInputElement | null) => {
if (ref) {
window.setTimeout(() => ref.focus(), 0);
}
}, []);
// fix list height animation on openning // fix list height animation on openning
useLayoutEffect(() => { useLayoutEffect(() => {
if (open) { if (open) {
@@ -235,7 +247,7 @@ export const CMDKContainer = ({
) : null} ) : null}
<Command.Input <Command.Input
placeholder={t['com.affine.cmdk.placeholder']()} placeholder={t['com.affine.cmdk.placeholder']()}
autoFocus ref={handleFocus}
{...rest} {...rest}
value={query} value={query}
onValueChange={onQueryChange} onValueChange={onQueryChange}

View File

@@ -16,6 +16,12 @@ const openQuickSearchByShortcut = async (page: Page, checkVisible = true) => {
} }
}; };
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) => { const keyboardDownAndSelect = async (page: Page, label: string) => {
await page.keyboard.press('ArrowDown'); await page.keyboard.press('ArrowDown');
if ( if (
@@ -77,14 +83,16 @@ async function waitForScrollToFinish(page: Page) {
} }
async function assertResultList(page: Page, texts: string[]) { async function assertResultList(page: Page, texts: string[]) {
const actual = await page await expect(async () => {
.locator('[cmdk-item] [data-testid=cmdk-label]') const actual = await page
.allInnerTexts(); .locator('[cmdk-item] [data-testid=cmdk-label]')
const actualSplit = actual[0].split('\n'); .allInnerTexts();
expect(actualSplit[0]).toEqual(texts[0]); const actualSplit = actual[0].split('\n');
if (actualSplit[1]) { expect(actualSplit[0]).toEqual(texts[0]);
expect(actualSplit[1]).toEqual(texts[1]); if (actualSplit[1]) {
} expect(actualSplit[1]).toEqual(texts[1]);
}
}).toPass();
} }
async function titleIsFocused(page: Page) { async function titleIsFocused(page: Page) {
@@ -137,7 +145,7 @@ test('Create a new page with keyword', async ({ page }) => {
await waitForEditorLoad(page); await waitForEditorLoad(page);
await clickNewPageButton(page); await clickNewPageButton(page);
await openQuickSearchByShortcut(page); await openQuickSearchByShortcut(page);
await page.keyboard.insertText('"test123456"'); await insertInputText(page, '"test123456"');
const addNewPage = page.locator( const addNewPage = page.locator(
'[cmdk-item] >> text=New ""test123456"" Page' '[cmdk-item] >> text=New ""test123456"" Page'
); );
@@ -151,9 +159,7 @@ test('Enter a keyword to search for', async ({ page }) => {
await waitForEditorLoad(page); await waitForEditorLoad(page);
await clickNewPageButton(page); await clickNewPageButton(page);
await openQuickSearchByShortcut(page); await openQuickSearchByShortcut(page);
await page.keyboard.insertText('test123456'); await insertInputText(page, 'test123456');
const actual = await page.locator('[cmdk-input]').inputValue();
expect(actual).toBe('test123456');
}); });
test('Create a new page and search this page', async ({ page }) => { 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 clickNewPageButton(page);
await openQuickSearchByShortcut(page); await openQuickSearchByShortcut(page);
// input title and create new page // input title and create new page
await page.keyboard.insertText('test123456'); await insertInputText(page, 'test123456');
await page.waitForTimeout(300); await page.waitForTimeout(300);
const addNewPage = page.locator('[cmdk-item] >> text=New "test123456" Page'); const addNewPage = page.locator('[cmdk-item] >> text=New "test123456" Page');
await addNewPage.click(); await addNewPage.click();
@@ -170,7 +176,7 @@ test('Create a new page and search this page', async ({ page }) => {
await page.waitForTimeout(300); await page.waitForTimeout(300);
await assertTitle(page, 'test123456'); await assertTitle(page, 'test123456');
await openQuickSearchByShortcut(page); await openQuickSearchByShortcut(page);
await page.keyboard.insertText('test123456'); await insertInputText(page, 'test123456');
await page.waitForTimeout(300); await page.waitForTimeout(300);
await assertResultList(page, ['test123456', 'test123456']); await assertResultList(page, ['test123456', 'test123456']);
await page.keyboard.press('Enter'); await page.keyboard.press('Enter');
@@ -180,7 +186,7 @@ test('Create a new page and search this page', async ({ page }) => {
await page.reload(); await page.reload();
await waitForEditorLoad(page); await waitForEditorLoad(page);
await openQuickSearchByShortcut(page); await openQuickSearchByShortcut(page);
await page.keyboard.insertText('test123456'); await insertInputText(page, 'test123456');
await page.waitForTimeout(300); await page.waitForTimeout(300);
await assertResultList(page, ['test123456', 'test123456']); await assertResultList(page, ['test123456', 'test123456']);
await page.keyboard.press('Enter'); await page.keyboard.press('Enter');
@@ -375,7 +381,7 @@ test('show not found item', async ({ page }) => {
await clickNewPageButton(page); await clickNewPageButton(page);
await openQuickSearchByShortcut(page); await openQuickSearchByShortcut(page);
// input title and create new page // input title and create new page
await page.keyboard.insertText('test123456'); await insertInputText(page, 'test123456');
const notFoundItem = page.getByTestId('cmdk-search-not-found'); const notFoundItem = page.getByTestId('cmdk-search-not-found');
await expect(notFoundItem).toBeVisible(); await expect(notFoundItem).toBeVisible();
await expect(notFoundItem).toHaveText('Search for "test123456"'); 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.press('Enter', { delay: 10 });
} }
await page.keyboard.insertText('123456'); await page.keyboard.insertText('123456');
const textBlock = page.getByText('123456');
await expect(textBlock).toBeVisible();
await clickSideBarAllPageButton(page); await clickSideBarAllPageButton(page);
await openQuickSearchByShortcut(page); await openQuickSearchByShortcut(page);
await page.keyboard.insertText('123456'); await insertInputText(page, '123456');
await page.waitForTimeout(300); await page.waitForTimeout(300);
await assertResultList(page, [ await assertResultList(page, [
'this is a new page to search for content', 'this is a new page to search for content',
'123456', '123456',
]); ]);
await page.keyboard.press('Enter'); await page.locator('[cmdk-item] [data-testid=cmdk-label]').first().click();
await waitForScrollToFinish(page); await waitForScrollToFinish(page);
const isVisitable = await checkElementIsInView(page, '123456'); const isVisitable = await checkElementIsInView(page, '123456');
expect(isVisitable).toBe(true); 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 getBlockSuiteEditorTitle(page).fill(specialTitle);
await openQuickSearchByShortcut(page); await openQuickSearchByShortcut(page);
await page.keyboard.insertText(specialTitle); await insertInputText(page, specialTitle);
await page.waitForTimeout(300); await page.waitForTimeout(300);
await assertResultList(page, [specialTitle, specialTitle]); await assertResultList(page, [specialTitle, specialTitle]);