Skip to content

Commit

Permalink
fix(core): optimize at menu config loading 2 (#9366)
Browse files Browse the repository at this point in the history
  • Loading branch information
pengx17 committed Dec 27, 2024
1 parent 1fbb462 commit 6977b0a
Show file tree
Hide file tree
Showing 3 changed files with 157 additions and 126 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,12 @@ export type LinkedMenuGroup = {
styles?: string;
// maximum quantity displayed by default
maxDisplay?: number;
// if the menu is loading
loading?: boolean | Signal<boolean>;
// copywriting when display quantity exceeds
overflowText?: string;
overflowText?: string | Signal<string>;
// loading text
loadingText?: string | Signal<string>;
};

export type LinkedDocContext = {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { LoadingIcon } from '@blocksuite/affine-block-image';
import type { IconButton } from '@blocksuite/affine-components/icon-button';
import { MoreHorizontalIcon } from '@blocksuite/affine-components/icons';
import {
Expand Down Expand Up @@ -90,22 +91,34 @@ export class LinkedDocPopover extends SignalWatcher(

private _getActionItems(group: LinkedMenuGroup) {
const isExpanded = !!this._expanded.get(group.name);
const items = resolveSignal(group.items);
if (isExpanded) {
return items;
}
let items = resolveSignal(group.items);

const isOverflow = !!group.maxDisplay && items.length > group.maxDisplay;
if (isOverflow) {
return items.slice(0, group.maxDisplay).concat({
const isLoading = resolveSignal(group.loading);

items = isExpanded ? items : items.slice(0, group.maxDisplay);

if (isLoading) {
items = items.concat({
key: 'loading',
name: resolveSignal(group.loadingText) || 'loading',
icon: LoadingIcon,
action: () => {},
});
}

if (isOverflow && !isExpanded && group.maxDisplay) {
items = items.concat({
key: `${group.name} More`,
name: group.overflowText || 'more',
name: resolveSignal(group.overflowText) || 'more',
icon: MoreHorizontalIcon,
action: () => {
this._expanded.set(group.name, true);
this.requestUpdate();
},
});
}

return items;
}

Expand Down
250 changes: 132 additions & 118 deletions packages/frontend/core/src/modules/at-menu-config/services/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { LoadingIcon } from '@affine/core/blocksuite/presets/blocks/_common/icon';
import { fuzzyMatch } from '@affine/core/utils/fuzzy-match';
import { I18n, i18nTime } from '@affine/i18n';
import track from '@affine/track';
Expand All @@ -11,18 +10,20 @@ import {
LinkedWidgetUtils,
} from '@blocksuite/affine/blocks';
import { Text } from '@blocksuite/affine/store';
import { createSignalFromObservable } from '@blocksuite/affine-shared/utils';
import type { EditorHost } from '@blocksuite/block-std';
import {
DateTimeIcon,
NewXxxEdgelessIcon,
NewXxxPageIcon,
} from '@blocksuite/icons/lit';
import type { DocMeta } from '@blocksuite/store';
import { signal } from '@preact/signals-core';
import { computed } from '@preact/signals-core';
import { Service } from '@toeverything/infra';
import { cssVarV2 } from '@toeverything/theme/v2';
import { html } from 'lit';
import { unsafeHTML } from 'lit/directives/unsafe-html.js';
import { map } from 'rxjs';

import type { WorkspaceDialogService } from '../../dialogs';
import type { DocsService } from '../../doc';
Expand All @@ -34,7 +35,6 @@ import type { RecentDocsService } from '../../quicksearch';
import type { WorkspaceService } from '../../workspace';

const MAX_DOCS = 3;
const LOAD_CHUNK = 100;
export class AtMenuConfigService extends Service {
constructor(
private readonly workspaceService: WorkspaceService,
Expand Down Expand Up @@ -75,7 +75,6 @@ export class AtMenuConfigService extends Service {
const rawMetas = currentWorkspace.docCollection.meta.docMetas;
const isJournal = (d: DocMeta) =>
!!this.journalService.journalDate$(d.id).value;
const docItems = signal<LinkedMenuItem[]>([]);

const docDisplayMetaService = this.docDisplayMetaService;

Expand Down Expand Up @@ -123,83 +122,94 @@ export class AtMenuConfigService extends Service {

const showRecent = query.trim().length === 0;

(async () => {
const isIndexerLoading =
this.docsSearch.indexer.status$.value.remaining !== undefined &&
this.docsSearch.indexer.status$.value.remaining > 0;

if (!showRecent && isIndexerLoading) {
// add a loading item
docItems.value = [
{
key: 'loading',
name: I18n.t('com.affine.editor.at-menu.loading'),
icon: LoadingIcon,
action: () => {
// no action
},
},
];
// wait for indexer to finish
await this.docsSearch.indexer.status$.waitFor(
status => status.remaining === 0
);
// remove the loading item
docItems.value = [];
}

const docMetas = (
showRecent
? this.recentDocsService.getRecentDocs()
: await this.searchDocs(query)
)
.map(doc => {
const meta = rawMetas.find(meta => meta.id === doc.id);

if (!meta) {
return null;
}

const highlights = 'highlights' in doc ? doc.highlights : undefined;
return {
...meta,
highlights,
};
})
.filter((m): m is DocMetaWithHighlights => !!m);
if (showRecent) {
const recentDocs = this.recentDocsService.getRecentDocs();
return {
name: I18n.t('com.affine.editor.at-menu.recent-docs'),
items: recentDocs
.map(doc => {
const meta = rawMetas.find(meta => meta.id === doc.id);
if (!meta) {
return null;
}
const item = toDocItem({
...meta,
highlights: undefined,
});
if (!item) {
return null;
}
return item;
})
.filter(item => !!item),
};
} else {
const { signal: docsSignal, cleanup } = createSignalFromObservable(
this.searchDocs$(query).pipe(
map(result => {
const docs = result
.map(doc => {
const meta = rawMetas.find(meta => meta.id === doc.id);

if (!meta) {
return null;
}

const highlights =
'highlights' in doc ? doc.highlights : undefined;

const docItem = toDocItem({
...meta,
highlights,
});

for (const [index, meta] of docMetas.entries()) {
if (abortSignal.aborted) {
return;
}
if (!docItem) {
return null;
}

const item = toDocItem(meta);
if (item) {
docItems.value = [...docItems.value, item];
}
return docItem;
})
.filter(m => !!m);

if (index % LOAD_CHUNK === 0) {
// use scheduler.yield?
await new Promise(resolve => setTimeout(resolve, 0));
}
}
})().catch(console.error);
return docs;
})
),
[]
);

const { signal: isIndexerLoading, cleanup: cleanupIndexerLoading } =
createSignalFromObservable(
this.docsSearch.indexer.status$.pipe(
map(
status => status.remaining !== undefined && status.remaining > 0
)
),
false
);

return {
name: showRecent
? I18n.t('com.affine.editor.at-menu.recent-docs')
: I18n.t('com.affine.editor.at-menu.link-to-doc', {
query,
}),
items: docItems,
maxDisplay: MAX_DOCS,
get overflowText() {
const overflowCount = docItems.value.length - MAX_DOCS;
const overflowText = computed(() => {
const overflowCount = docsSignal.value.length - MAX_DOCS;
return I18n.t('com.affine.editor.at-menu.more-docs-hint', {
count: overflowCount > 100 ? '100+' : overflowCount,
});
},
};
});

abortSignal.addEventListener('abort', () => {
cleanup();
cleanupIndexerLoading();
});

return {
name: I18n.t('com.affine.editor.at-menu.link-to-doc', {
query,
}),
loading: isIndexerLoading,
loadingText: I18n.t('com.affine.editor.at-menu.loading'),
items: docsSignal,
maxDisplay: MAX_DOCS,
overflowText,
};
}
}

private newDocMenuGroup(
Expand Down Expand Up @@ -418,54 +428,58 @@ export class AtMenuConfigService extends Service {
}

// only search docs by title, excluding blocks
private async searchDocs(query: string) {
const { buckets } = await this.docsSearch.indexer.blockIndex.aggregate(
{
type: 'boolean',
occur: 'must',
queries: [
{
type: 'match',
field: 'content',
match: query,
},
{
type: 'boolean',
occur: 'should',
queries: [
{
type: 'match',
field: 'flavour',
match: 'affine:page',
},
],
},
],
},
'docId',
{
hits: {
fields: ['docId', 'content'],
pagination: {
limit: 1,
},
highlights: [
private searchDocs$(query: string) {
return this.docsSearch.indexer.blockIndex
.aggregate$(
{
type: 'boolean',
occur: 'must',
queries: [
{
type: 'match',
field: 'content',
before: `<span style="color: ${cssVarV2('text/emphasis')}">`,
end: '</span>',
match: query,
},
{
type: 'boolean',
occur: 'should',
queries: [
{
type: 'match',
field: 'flavour',
match: 'affine:page',
},
],
},
],
},
}
);
const result = buckets.map(bucket => {
return {
id: bucket.key,
title: bucket.hits.nodes[0].fields.content,
highlights: bucket.hits.nodes[0].highlights.content[0],
};
});
return result;
'docId',
{
hits: {
fields: ['docId', 'content'],
pagination: {
limit: 1,
},
highlights: [
{
field: 'content',
before: `<span style="color: ${cssVarV2('text/emphasis')}">`,
end: '</span>',
},
],
},
}
)
.pipe(
map(({ buckets }) =>
buckets.map(bucket => {
return {
id: bucket.key,
title: bucket.hits.nodes[0].fields.content,
highlights: bucket.hits.nodes[0].highlights.content[0],
};
})
)
);
}
}

0 comments on commit 6977b0a

Please sign in to comment.