fundon
2024-09-12 08:25:28 +00:00
parent 2cba8a4ccd
commit 8a9d9b42a3
5 changed files with 191 additions and 68 deletions

View File

@@ -16,7 +16,7 @@ import type { ActivePeekView } from '@affine/core/modules/peek-view/entities/pee
import {
CreationQuickSearchSession,
DocsQuickSearchSession,
type QuickSearchItem,
LinksQuickSearchSession,
QuickSearchService,
RecentDocsQuickSearchSession,
} from '@affine/core/modules/quicksearch';
@@ -32,6 +32,8 @@ import type {
AffineReference,
DocMode,
DocModeProvider,
QuickSearchResult,
ReferenceParams,
RootService,
} from '@blocksuite/blocks';
import {
@@ -46,7 +48,6 @@ import {
QuickSearchProvider,
ReferenceNodeConfigExtension,
} from '@blocksuite/blocks';
import { LinkIcon } from '@blocksuite/icons/rc';
import { AIChatBlockSchema } from '@blocksuite/presets';
import type { BlockSnapshot } from '@blocksuite/store';
import {
@@ -282,10 +283,7 @@ export function patchDocModeService(
export function patchQuickSearchService(framework: FrameworkProvider) {
const QuickSearch = QuickSearchExtension({
async searchDoc(options) {
let searchResult:
| { docId: string; isNewDoc?: boolean }
| { userInput: string }
| null = null;
let searchResult: QuickSearchResult = null;
if (options.skipSelection) {
const query = options.userInput;
if (!query) {
@@ -319,43 +317,45 @@ export function patchQuickSearchService(framework: FrameworkProvider) {
framework.get(QuickSearchService).quickSearch.show(
[
framework.get(RecentDocsQuickSearchSession),
framework.get(DocsQuickSearchSession),
framework.get(CreationQuickSearchSession),
(query: string) => {
if (
(query.startsWith('http://') ||
query.startsWith('https://')) &&
resolveLinkToDoc(query) === null
) {
return [
{
id: 'link',
source: 'link',
icon: LinkIcon,
label: {
key: 'com.affine.cmdk.affine.insert-link',
},
payload: { url: query },
} as QuickSearchItem<'link', { url: string }>,
];
}
return [];
},
framework.get(DocsQuickSearchSession),
framework.get(LinksQuickSearchSession),
],
result => {
if (result === null) {
resolve(null);
return;
}
if (result.source === 'docs' || result.source === 'recent-doc') {
if (result.source === 'docs') {
resolve({
docId: result.payload.docId,
});
} else if (result.source === 'link') {
return;
}
if (result.source === 'recent-doc') {
resolve({
userInput: result.payload.url,
docId: result.payload.docId,
});
} else if (result.source === 'creation') {
return;
}
if (result.source === 'link') {
if (result.payload.external) {
const userInput = result.payload.external.url;
resolve({ userInput });
return;
}
if (result.payload.internal) {
const { docId, params } = result.payload.internal;
resolve({ docId, params });
}
return;
}
if (result.source === 'creation') {
const docsService = framework.get(DocsService);
const mode =
result.id === 'creation:create-edgeless'
@@ -365,10 +365,12 @@ export function patchQuickSearchService(framework: FrameworkProvider) {
primaryMode: mode,
title: result.payload.title,
});
resolve({
docId: newDoc.id,
isNewDoc: true,
});
return;
}
},
{
@@ -413,17 +415,27 @@ export function patchQuickSearchService(framework: FrameworkProvider) {
const linkedDoc = std.collection.getDoc(result.docId);
if (!linkedDoc) return;
host.doc.addSiblingBlocks(model, [
{
flavour: 'affine:embed-linked-doc',
pageId: linkedDoc.id,
},
]);
const props: {
flavour: string;
pageId: string;
params?: ReferenceParams;
} = {
flavour: 'affine:embed-linked-doc',
pageId: linkedDoc.id,
};
if (!result.isNewDoc && result.params) {
props.params = result.params;
}
host.doc.addSiblingBlocks(model, [props]);
if (result.isNewDoc) {
track.doc.editor.slashMenu.createDoc({ control: 'linkDoc' });
track.doc.editor.slashMenu.linkDoc({ control: 'createDoc' });
} else {
track.doc.editor.slashMenu.linkDoc({ control: 'linkDoc' });
}
track.doc.editor.slashMenu.linkDoc({ control: 'linkDoc' });
} else if ('userInput' in result) {
const embedOptions = std
.get(EmbedOptionProvider)

View File

@@ -10,7 +10,6 @@ import { truncate } from 'lodash-es';
import { EMPTY, map, mergeMap, of, switchMap } from 'rxjs';
import type { DocsSearchService } from '../../docs-search';
import { resolveLinkToDoc } from '../../navigation';
import type { QuickSearchSession } from '../providers/quick-search-provider';
import type { DocDisplayMetaService } from '../services/doc-display-meta';
import type { QuickSearchItem } from '../types/item';
@@ -55,29 +54,7 @@ export class DocsQuickSearchSession
if (!query) {
out = of([] as QuickSearchItem<'docs', DocsPayload>[]);
} else {
const resolvedDoc = resolveLinkToDoc(query);
const resolvedDocId = resolvedDoc?.docId;
const resolvedBlockId = resolvedDoc?.blockIds?.[0];
out = this.docsSearchService.search$(query).pipe(
map(docs => {
if (
resolvedDocId &&
!docs.some(doc => doc.docId === resolvedDocId)
) {
return [
{
docId: resolvedDocId,
score: 100,
blockId: resolvedBlockId,
blockContent: '',
},
...docs,
];
}
return docs;
}),
map(docs =>
docs
.map(doc => {

View File

@@ -0,0 +1,107 @@
import type { ReferenceParams } from '@blocksuite/blocks';
import { BlockLinkIcon, LinkIcon } from '@blocksuite/icons/rc';
import type { DocsService } from '@toeverything/infra';
import { Entity, LiveData } from '@toeverything/infra';
import { isEmpty, pick, truncate } from 'lodash-es';
import { resolveLinkToDoc } from '../../navigation';
import type { QuickSearchSession } from '../providers/quick-search-provider';
import type { DocDisplayMetaService } from '../services/doc-display-meta';
import type { QuickSearchItem } from '../types/item';
type LinkPayload = {
internal?: {
docId: string;
title?: string;
blockId?: string;
blockContent?: string;
params?: ReferenceParams;
};
external?: {
url: string;
};
};
export class LinksQuickSearchSession
extends Entity
implements QuickSearchSession<'link', LinkPayload>
{
constructor(
private readonly docsService: DocsService,
private readonly docDisplayMetaService: DocDisplayMetaService
) {
super();
}
query$ = new LiveData('');
items$ = LiveData.computed(get => {
const query = get(this.query$);
if (!query) return [];
const isLink = query.startsWith('http://') || query.startsWith('https://');
if (!isLink) return [];
const resolvedDoc = resolveLinkToDoc(query);
if (!resolvedDoc) {
return [
{
id: 'link',
source: 'link',
icon: LinkIcon,
label: {
key: 'com.affine.cmdk.affine.insert-link',
},
payload: { external: { url: query } },
} as QuickSearchItem<'link', LinkPayload>,
];
}
const docId = resolvedDoc.docId;
const doc = this.docsService.list.doc$(docId).value;
if (!doc || get(doc.trash$)) return [];
const params = pick(resolvedDoc, ['mode', 'blockIds', 'elementIds']);
const { title, icon, updatedDate } =
this.docDisplayMetaService.getDocDisplayMeta(doc);
const blockId = params?.blockIds?.[0];
const linkToNode = Boolean(blockId);
const score = 100;
const internal = {
docId,
score,
blockId,
blockContent: '',
};
if (linkToNode && !isEmpty(params)) {
Object.assign(internal, { params });
}
return [
{
id: ['doc', doc.id, linkToNode ? blockId : ''].join(':'),
source: 'link',
group: {
id: 'docs',
label: {
key: 'com.affine.quicksearch.group.searchfor',
options: { query: truncate(query) },
},
score: 5,
},
label: {
title: title,
},
score,
icon: linkToNode ? BlockLinkIcon : icon,
timestamp: updatedDate,
payload: { internal },
} as QuickSearchItem<'link', LinkPayload>,
];
});
query(query: string) {
this.query$.next(query);
}
}

View File

@@ -16,6 +16,7 @@ import { CollectionsQuickSearchSession } from './impls/collections';
import { CommandsQuickSearchSession } from './impls/commands';
import { CreationQuickSearchSession } from './impls/creation';
import { DocsQuickSearchSession } from './impls/docs';
import { LinksQuickSearchSession } from './impls/links';
import { RecentDocsQuickSearchSession } from './impls/recent-docs';
import { TagsQuickSearchSession } from './impls/tags';
import { CMDKQuickSearchService } from './services/cmdk';
@@ -29,6 +30,7 @@ export { CollectionsQuickSearchSession } from './impls/collections';
export { CommandsQuickSearchSession } from './impls/commands';
export { CreationQuickSearchSession } from './impls/creation';
export { DocsQuickSearchSession } from './impls/docs';
export { LinksQuickSearchSession } from './impls/links';
export { RecentDocsQuickSearchSession } from './impls/recent-docs';
export { TagsQuickSearchSession } from './impls/tags';
export type { QuickSearchItem } from './types/item';
@@ -53,6 +55,7 @@ export function configureQuickSearchModule(framework: Framework) {
DocsService,
DocDisplayMetaService,
])
.entity(LinksQuickSearchSession, [DocsService, DocDisplayMetaService])
.entity(CreationQuickSearchSession)
.entity(CollectionsQuickSearchSession, [CollectionService])
.entity(TagsQuickSearchSession, [TagService])

View File

@@ -7,6 +7,7 @@ import { CollectionsQuickSearchSession } from '../impls/collections';
import { CommandsQuickSearchSession } from '../impls/commands';
import { CreationQuickSearchSession } from '../impls/creation';
import { DocsQuickSearchSession } from '../impls/docs';
import { LinksQuickSearchSession } from '../impls/links';
import { RecentDocsQuickSearchSession } from '../impls/recent-docs';
import { TagsQuickSearchSession } from '../impls/tags';
import type { QuickSearchService } from './quick-search';
@@ -31,20 +32,33 @@ export class CMDKQuickSearchService extends Service {
this.framework.createEntity(CommandsQuickSearchSession),
this.framework.createEntity(CreationQuickSearchSession),
this.framework.createEntity(DocsQuickSearchSession),
this.framework.createEntity(LinksQuickSearchSession),
this.framework.createEntity(TagsQuickSearchSession),
],
result => {
if (!result) {
return;
}
if (result.source === 'commands') {
result.payload.run()?.catch(err => {
console.error(err);
});
} else if (
result.source === 'recent-doc' ||
result.source === 'docs'
) {
return;
}
if (result.source === 'link') {
if (result.payload.internal) {
const { docId, params } = result.payload.internal;
this.workbenchService.workbench.openDoc({
docId,
...params,
});
}
return;
}
if (result.source === 'recent-doc' || result.source === 'docs') {
const doc: {
docId: string;
blockId?: string;
@@ -62,13 +76,22 @@ export class CMDKQuickSearchService extends Service {
}
this.workbenchService.workbench.openDoc(options);
} else if (result.source === 'collections') {
return;
}
if (result.source === 'collections') {
this.workbenchService.workbench.openCollection(
result.payload.collectionId
);
} else if (result.source === 'tags') {
return;
}
if (result.source === 'tags') {
this.workbenchService.workbench.openTag(result.payload.tagId);
} else if (result.source === 'creation') {
return;
}
if (result.source === 'creation') {
if (result.id === 'creation:create-page') {
const newDoc = this.docsService.createDoc({
primaryMode: 'page',
@@ -82,6 +105,7 @@ export class CMDKQuickSearchService extends Service {
});
this.workbenchService.workbench.openDoc(newDoc.id);
}
return;
}
},
{