chore: bump bs with new extension api (#8042)

This commit is contained in:
Saul-Mirone
2024-09-02 10:32:22 +00:00
parent 61e37d8873
commit 56f4634c1f
90 changed files with 1300 additions and 988 deletions
@@ -1,4 +1,4 @@
import type { DocMode } from '@blocksuite/blocks';
import { DocMode } from '@blocksuite/blocks';
import type { AffineEditorContainer } from '@blocksuite/presets';
import type { DocService, WorkspaceService } from '@toeverything/infra';
import { Entity, LiveData } from '@toeverything/infra';
@@ -18,7 +18,9 @@ export class Editor extends Entity<{ defaultMode: DocMode }> {
readonly editorContainer$ = new LiveData<AffineEditorContainer | null>(null);
toggleMode() {
this.mode$.next(this.mode$.value === 'edgeless' ? 'page' : 'edgeless');
this.mode$.next(
this.mode$.value === 'edgeless' ? DocMode.Page : DocMode.Edgeless
);
}
setMode(mode: DocMode) {
@@ -25,19 +25,19 @@ afterEach(() => {
const testCases: [string, ReturnType<typeof resolveLinkToDoc>][] = [
['http://example.com/', null],
[
'/workspace/48__RTCSwASvWZxyAk3Jw/-Uge-K6SYcAbcNYfQ5U-j#xxxx',
'/workspace/48__RTCSwASvWZxyAk3Jw/-Uge-K6SYcAbcNYfQ5U-j?blockIds=xxxx',
{
workspaceId: '48__RTCSwASvWZxyAk3Jw',
docId: '-Uge-K6SYcAbcNYfQ5U-j',
blockId: 'xxxx',
blockIds: ['xxxx'],
},
],
[
'http://affine.pro/workspace/48__RTCSwASvWZxyAk3Jw/-Uge-K6SYcAbcNYfQ5U-j#xxxx',
'http://affine.pro/workspace/48__RTCSwASvWZxyAk3Jw/-Uge-K6SYcAbcNYfQ5U-j?blockIds=xxxx',
{
workspaceId: '48__RTCSwASvWZxyAk3Jw',
docId: '-Uge-K6SYcAbcNYfQ5U-j',
blockId: 'xxxx',
blockIds: ['xxxx'],
},
],
['http://affine.pro/workspace/48__RTCSwASvWZxyAk3Jw/all', null],
@@ -45,19 +45,19 @@ const testCases: [string, ReturnType<typeof resolveLinkToDoc>][] = [
['http://affine.pro/workspace/48__RTCSwASvWZxyAk3Jw/tag', null],
['http://affine.pro/workspace/48__RTCSwASvWZxyAk3Jw/trash', null],
[
'file//./workspace/48__RTCSwASvWZxyAk3Jw/-Uge-K6SYcAbcNYfQ5U-j#xxxx',
'file//./workspace/48__RTCSwASvWZxyAk3Jw/-Uge-K6SYcAbcNYfQ5U-j?blockIds=xxxx',
{
workspaceId: '48__RTCSwASvWZxyAk3Jw',
docId: '-Uge-K6SYcAbcNYfQ5U-j',
blockId: 'xxxx',
blockIds: ['xxxx'],
},
],
[
'http//localhost:8000/workspace/48__RTCSwASvWZxyAk3Jw/-Uge-K6SYcAbcNYfQ5U-j#xxxx',
'http//localhost:8000/workspace/48__RTCSwASvWZxyAk3Jw/-Uge-K6SYcAbcNYfQ5U-j?blockIds=xxxx',
{
workspaceId: '48__RTCSwASvWZxyAk3Jw',
docId: '-Uge-K6SYcAbcNYfQ5U-j',
blockId: 'xxxx',
blockIds: ['xxxx'],
},
],
];
@@ -1,3 +1,6 @@
import type { DocMode } from '@blocksuite/blocks';
import queryString from 'query-string';
function maybeAffineOrigin(origin: string) {
return (
origin.startsWith('file://') ||
@@ -73,9 +76,23 @@ const isRouteModulePath = (
export const resolveLinkToDoc = (href: string) => {
const meta = resolveRouteLinkMeta(href);
if (!meta || meta.moduleName !== 'doc') return null;
const params: {
mode?: DocMode;
blockIds?: string[];
elementIds?: string[];
} = queryString.parse(meta.location.search, {
arrayFormat: 'none',
types: {
mode: value => (value === 'edgeless' ? 'edgeless' : 'page') as DocMode,
blockIds: value => value.split(','),
elementIds: value => value.split(','),
},
});
return {
workspaceId: meta.workspaceId,
docId: meta.docId,
blockId: meta.blockId,
...params,
};
};
@@ -1,6 +1,7 @@
import type { BlockComponent, EditorHost } from '@blocksuite/block-std';
import {
AffineReference,
type DocMode,
type EmbedLinkedDocModel,
type EmbedSyncedDocModel,
type ImageBlockModel,
@@ -9,7 +10,7 @@ import {
} from '@blocksuite/blocks';
import type { AIChatBlockModel } from '@blocksuite/presets';
import type { BlockModel } from '@blocksuite/store';
import { type DocMode, Entity, LiveData } from '@toeverything/infra';
import { Entity, LiveData } from '@toeverything/infra';
import type { TemplateResult } from 'lit';
import { firstValueFrom, map, race } from 'rxjs';
@@ -21,20 +22,21 @@ export type PeekViewTarget =
| BlockComponent
| AffineReference
| HTMLAnchorElement
| { docId: string; blockId?: string };
| { docId: string; blockIds?: string[] };
export interface DocPeekViewInfo {
type: 'doc';
docId: string;
blockId?: string;
mode?: DocMode;
blockIds?: string[];
elementIds?: string[];
xywh?: `[${number},${number},${number},${number}]`;
}
export type ImagePeekViewInfo = {
type: 'image';
docId: string;
blockId: string;
blockIds: [string];
};
export type AIChatBlockPeekViewInfo = {
@@ -58,15 +60,16 @@ export type ActivePeekView = {
| AIChatBlockPeekViewInfo;
};
const EMBED_DOC_FLAVOURS = [
'affine:embed-linked-doc',
'affine:embed-synced-doc',
];
const isEmbedDocModel = (
const isEmbedLinkedDocModel = (
blockModel: BlockModel
): blockModel is EmbedSyncedDocModel | EmbedLinkedDocModel => {
return EMBED_DOC_FLAVOURS.includes(blockModel.flavour);
): blockModel is EmbedLinkedDocModel => {
return blockModel.flavour === 'affine:embed-linked-doc';
};
const isEmbedSyncedDocModel = (
blockModel: BlockModel
): blockModel is EmbedSyncedDocModel => {
return blockModel.flavour === 'affine:embed-synced-doc';
};
const isImageBlockModel = (
@@ -99,15 +102,26 @@ function resolvePeekInfoFromPeekTarget(
}
if (peekTarget instanceof AffineReference) {
if (peekTarget.refMeta) {
return {
const referenceInfo = peekTarget.referenceInfo;
if (referenceInfo) {
const { pageId: docId } = referenceInfo;
const info: DocPeekViewInfo = {
type: 'doc',
docId: peekTarget.refMeta.id,
docId,
};
Object.assign(info, referenceInfo.params);
return info;
}
} else if ('model' in peekTarget) {
const blockModel = peekTarget.model;
if (isEmbedDocModel(blockModel)) {
if (isEmbedLinkedDocModel(blockModel)) {
const info: DocPeekViewInfo = {
type: 'doc',
docId: blockModel.pageId,
};
Object.assign(info, blockModel.params);
return info;
} else if (isEmbedSyncedDocModel(blockModel)) {
return {
type: 'doc',
docId: blockModel.pageId,
@@ -121,7 +135,7 @@ function resolvePeekInfoFromPeekTarget(
return {
type: 'doc',
docId,
mode: 'edgeless',
mode: 'edgeless' as DocMode,
xywh: refModel.xywh,
};
}
@@ -129,7 +143,7 @@ function resolvePeekInfoFromPeekTarget(
return {
type: 'image',
docId: blockModel.doc.id,
blockId: blockModel.id,
blockIds: [blockModel.id],
};
} else if (isAIChatBlockModel(blockModel)) {
return {
@@ -142,17 +156,28 @@ function resolvePeekInfoFromPeekTarget(
} else if (peekTarget instanceof HTMLAnchorElement) {
const maybeDoc = resolveLinkToDoc(peekTarget.href);
if (maybeDoc) {
return {
const info: DocPeekViewInfo = {
type: 'doc',
docId: maybeDoc.docId,
blockId: maybeDoc.blockId,
};
if (maybeDoc.mode) {
info.mode = maybeDoc.mode;
}
if (maybeDoc.blockIds?.length) {
info.blockIds = maybeDoc.blockIds;
}
if (maybeDoc.elementIds?.length) {
info.elementIds = maybeDoc.elementIds;
}
return info;
}
} else if ('docId' in peekTarget) {
return {
type: 'doc',
docId: peekTarget.docId,
blockId: peekTarget.blockId,
blockIds: peekTarget.blockIds,
};
}
return;
@@ -7,10 +7,9 @@ import { EditorOutlineViewer } from '@affine/core/components/blocksuite/outline-
import { useNavigateHelper } from '@affine/core/hooks/use-navigate-helper';
import { PageNotFound } from '@affine/core/pages/404';
import { DebugLogger } from '@affine/debug';
import { type EdgelessRootService } from '@blocksuite/blocks';
import { DocMode, type EdgelessRootService } from '@blocksuite/blocks';
import { Bound, DisposableGroup } from '@blocksuite/global/utils';
import type { AffineEditorContainer } from '@blocksuite/presets';
import type { DocMode } from '@toeverything/infra';
import { DocsService, FrameworkScope, useService } from '@toeverything/infra';
import clsx from 'clsx';
import { useCallback, useEffect, useState } from 'react';
@@ -32,7 +31,7 @@ function fitViewport(
}
const rootService =
editor.host.std.spec.getService<EdgelessRootService>('affine:page');
editor.host.std.getService<EdgelessRootService>('affine:page');
rootService.viewport.onResize();
if (xywh) {
@@ -60,12 +59,14 @@ function fitViewport(
export function DocPeekPreview({
docId,
blockId,
blockIds,
elementIds,
mode,
xywh,
}: {
docId: string;
blockId?: string;
blockIds?: string[];
elementIds?: string[];
mode?: DocMode;
xywh?: `[${number},${number},${number},${number}]`;
}) {
@@ -97,7 +98,7 @@ export function DocPeekPreview({
useEffect(() => {
if (!mode || !resolvedMode) {
setResolvedMode(
docs.list.doc$(docId).value?.primaryMode$.value || 'page'
docs.list.doc$(docId).value?.primaryMode$.value || DocMode.Page
);
}
}, [docId, docs.list, resolvedMode, mode]);
@@ -125,12 +126,17 @@ export function DocPeekPreview({
return;
}
const rootService =
editorElement.host.std.spec.getService('affine:page');
const rootService = editorElement.host.std.getService('affine:page');
// doc change event inside peek view should be handled by peek view
disposableGroup.add(
rootService.slots.docLinkClicked.on(({ docId, blockId }) => {
peekView.open({ docId, blockId }).catch(console.error);
rootService.slots.docLinkClicked.on(options => {
peekView
.open({
type: 'doc',
docId: options.pageId,
...options.params,
})
.catch(console.error);
})
);
// TODO(@Peng): no tag peek view yet
@@ -175,7 +181,8 @@ export function DocPeekPreview({
ref={onRef}
className={styles.editor}
mode={resolvedMode}
defaultSelectedBlockId={blockId}
blockIds={blockIds}
elementIds={elementIds}
page={doc.blockSuiteDoc}
/>
</FrameworkScope>
@@ -1,12 +1,13 @@
import { IconButton } from '@affine/component';
import { useI18n } from '@affine/i18n';
import type { DocMode } from '@blocksuite/blocks';
import {
CloseIcon,
ExpandFullIcon,
OpenInNewIcon,
SplitViewIcon,
} from '@blocksuite/icons/rc';
import { type DocMode, useService } from '@toeverything/infra';
import { useService } from '@toeverything/infra';
import { clsx } from 'clsx';
import {
type HTMLAttributes,
@@ -27,13 +27,16 @@ function renderPeekView({ info }: ActivePeekView) {
mode={info.mode}
xywh={info.xywh}
docId={info.docId}
blockId={info.blockId}
blockIds={info.blockIds}
elementIds={info.elementIds}
/>
);
}
if (info.type === 'image') {
return <ImagePreviewPeekView docId={info.docId} blockId={info.blockId} />;
return (
<ImagePreviewPeekView docId={info.docId} blockId={info.blockIds[0]} />
);
}
if (info.type === 'ai-chat-block') {
@@ -1,4 +1,5 @@
import type { Doc, DocMode } from '@toeverything/infra';
import type { DocMode } from '@blocksuite/blocks';
import type { Doc } from '@toeverything/infra';
import {
DocsService,
useLiveData,
@@ -4,7 +4,8 @@ import {
type CommandCategory,
PreconditionStrategy,
} from '@affine/core/commands';
import type { DocMode, GlobalContextService } from '@toeverything/infra';
import type { DocMode } from '@blocksuite/blocks';
import type { GlobalContextService } from '@toeverything/infra';
import { Entity, LiveData } from '@toeverything/infra';
import Fuse from 'fuse.js';
@@ -1,5 +1,6 @@
import type { DocMode } from '@blocksuite/blocks';
import { EdgelessIcon, PageIcon } from '@blocksuite/icons/rc';
import { type DocMode, Entity, LiveData } from '@toeverything/infra';
import { Entity, LiveData } from '@toeverything/infra';
import type { QuickSearchSession } from '../providers/quick-search-provider';
import type { QuickSearchGroup } from '../types/group';
@@ -66,7 +66,7 @@ export class DocsQuickSearchSession
{
docId: resolvedDoc.docId,
score: 100,
blockId: resolvedDoc.blockId,
blockId: resolvedDoc.blockIds?.[0],
blockContent: '',
},
...docs,
@@ -1,4 +1,5 @@
import { track } from '@affine/core/mixpanel';
import { DocMode } from '@blocksuite/blocks';
import type { DocsService } from '@toeverything/infra';
import { Service } from '@toeverything/infra';
@@ -67,13 +68,13 @@ export class CMDKQuickSearchService extends Service {
} else if (result.source === 'creation') {
if (result.id === 'creation:create-page') {
const newDoc = this.docsService.createDoc({
primaryMode: 'page',
primaryMode: DocMode.Page,
title: result.payload.title,
});
this.workbenchService.workbench.openDoc(newDoc.id);
} else if (result.id === 'creation:create-edgeless') {
const newDoc = this.docsService.createDoc({
primaryMode: 'edgeless',
primaryMode: DocMode.Edgeless,
title: result.payload.title,
});
this.workbenchService.workbench.openDoc(newDoc.id);
@@ -1,6 +1,6 @@
import { UserFriendlyError } from '@affine/graphql';
import type { DocMode } from '@blocksuite/blocks';
import {
type DocMode,
effect,
Entity,
fromPromise,
@@ -1,5 +1,6 @@
import { ErrorNames, UserFriendlyError } from '@affine/graphql';
import { type DocMode, Store } from '@toeverything/infra';
import type { DocMode } from '@blocksuite/blocks';
import { Store } from '@toeverything/infra';
import { type FetchService, isBackendError } from '../../cloud';
@@ -1,6 +1,7 @@
import { Entity, LiveData } from '@toeverything/infra';
import type { Location, To } from 'history';
import { isEqual } from 'lodash-es';
import type { ParseOptions } from 'query-string';
import queryString from 'query-string';
import { Observable } from 'rxjs';
@@ -79,15 +80,14 @@ export class View extends Entity<{
icon$ = new LiveData(this.props.icon ?? 'allDocs');
queryString$<T extends Record<string, unknown>>({
parseNumbers = true,
}: { parseNumbers?: boolean } = {}) {
queryString$<T extends Record<string, unknown>>(
options: ParseOptions = {
parseNumbers: true,
parseBooleans: true,
}
) {
return this.location$.map(
location =>
queryString.parse(location.search, {
parseBooleans: true,
parseNumbers: parseNumbers,
}) as Partial<T>
location => queryString.parse(location.search, options) as Partial<T>
);
}
@@ -128,9 +128,15 @@ export class Workbench extends Entity {
const docId = typeof id === 'string' ? id : id.docId;
const blockId = typeof id === 'string' ? undefined : id.blockId;
const mode = typeof id === 'string' ? undefined : id.mode;
const hash = blockId ? `#${blockId}` : '';
const query = mode ? `?mode=${mode}` : '';
this.open(`/${docId}${query}${hash}`, options);
let query = '';
if (mode || blockId) {
const search = new URLSearchParams();
if (mode) search.set('mode', mode);
if (blockId) search.set('blockIds', blockId);
query = `?${search.toString()}`;
}
this.open(`/${docId}${query}`, options);
}
openCollections(options?: WorkbenchOpenOptions) {