From 41c8232472b050354d0867d45626276366e64155 Mon Sep 17 00:00:00 2001 From: liuyi Date: Thu, 26 Dec 2024 21:43:12 +0800 Subject: [PATCH 01/11] chore(infra): remove blocksuite from infra (#9353) --- packages/common/infra/src/index.ts | 1 - packages/common/infra/src/sync/blob/blob.ts | 12 +++++++++--- packages/common/infra/tsconfig.json | 3 --- packages/common/nbstore/tsconfig.json | 3 +++ .../core/src/blocksuite}/initialization/index.ts | 0 .../affine/quota-reached-modal/cloud-quota-modal.tsx | 4 ++-- .../affine/quota-reached-modal/local-quota-modal.tsx | 6 +++--- .../specs/custom/spec-patchers.tsx | 3 ++- .../blocksuite/block-suite-page-list/utils.tsx | 3 ++- .../frontend/core/src/modules/doc/services/docs.ts | 7 +++---- .../core/src/modules/journal/services/journal.ts | 7 +++++-- .../core/src/modules/quicksearch/services/cmdk.ts | 2 +- 12 files changed, 30 insertions(+), 21 deletions(-) rename packages/{common/infra/src => frontend/core/src/blocksuite}/initialization/index.ts (100%) diff --git a/packages/common/infra/src/index.ts b/packages/common/infra/src/index.ts index 79d9f035f1a40..b7e8174a24b9a 100644 --- a/packages/common/infra/src/index.ts +++ b/packages/common/infra/src/index.ts @@ -1,7 +1,6 @@ export * from './app-config-storage'; export * from './atom'; export * from './framework'; -export * from './initialization'; export * from './livedata'; export * from './orm'; export * from './storage'; diff --git a/packages/common/infra/src/sync/blob/blob.ts b/packages/common/infra/src/sync/blob/blob.ts index 7e7b35a0a6130..b289c968ddd4b 100644 --- a/packages/common/infra/src/sync/blob/blob.ts +++ b/packages/common/infra/src/sync/blob/blob.ts @@ -1,5 +1,5 @@ import { DebugLogger } from '@affine/debug'; -import { Slot } from '@blocksuite/affine/global/utils'; +import EventEmitter2 from 'eventemitter2'; import { difference } from 'lodash-es'; import { LiveData } from '../../livedata'; @@ -32,13 +32,19 @@ export interface BlobStatus { export class BlobEngine { readonly name = 'blob-engine'; readonly readonly = this.local.readonly; + readonly event = new EventEmitter2(); private abort: AbortController | null = null; readonly isStorageOverCapacity$ = new LiveData(false); singleBlobSizeLimit: number = 100 * 1024 * 1024; - onAbortLargeBlob = new Slot(); + onAbortLargeBlob = (callback: (blob: Blob) => void) => { + this.event.on('abort-large-blob', callback); + return () => { + this.event.off('abort-large-blob', callback); + }; + }; constructor( private readonly local: BlobStorage, @@ -153,7 +159,7 @@ export class BlobEngine { } if (value.size > this.singleBlobSizeLimit) { - this.onAbortLargeBlob.emit(value); + this.event.emit('abort-large-blob', value); logger.error('blob over limit, abort set'); return key; } diff --git a/packages/common/infra/tsconfig.json b/packages/common/infra/tsconfig.json index ee7b751d96034..a4ea7715edbde 100644 --- a/packages/common/infra/tsconfig.json +++ b/packages/common/infra/tsconfig.json @@ -12,9 +12,6 @@ }, { "path": "../debug" - }, - { - "path": "../../../blocksuite/affine/all" } ] } diff --git a/packages/common/nbstore/tsconfig.json b/packages/common/nbstore/tsconfig.json index e5276f5627270..183d9103b4062 100644 --- a/packages/common/nbstore/tsconfig.json +++ b/packages/common/nbstore/tsconfig.json @@ -15,6 +15,9 @@ }, { "path": "../infra" + }, + { + "path": "../../../blocksuite/affine/all" } ] } diff --git a/packages/common/infra/src/initialization/index.ts b/packages/frontend/core/src/blocksuite/initialization/index.ts similarity index 100% rename from packages/common/infra/src/initialization/index.ts rename to packages/frontend/core/src/blocksuite/initialization/index.ts diff --git a/packages/frontend/core/src/components/affine/quota-reached-modal/cloud-quota-modal.tsx b/packages/frontend/core/src/components/affine/quota-reached-modal/cloud-quota-modal.tsx index 0c375e0155a61..232eaed073616 100644 --- a/packages/frontend/core/src/components/affine/quota-reached-modal/cloud-quota-modal.tsx +++ b/packages/frontend/core/src/components/affine/quota-reached-modal/cloud-quota-modal.tsx @@ -88,9 +88,9 @@ export const CloudQuotaModal = () => { currentWorkspace.engine.blob.singleBlobSizeLimit = workspaceQuota.blobLimit; const disposable = - currentWorkspace.engine.blob.onAbortLargeBlob.on(onAbortLargeBlob); + currentWorkspace.engine.blob.onAbortLargeBlob(onAbortLargeBlob); return () => { - disposable?.dispose(); + disposable(); }; }, [currentWorkspace.engine.blob, onAbortLargeBlob, workspaceQuota]); diff --git a/packages/frontend/core/src/components/affine/quota-reached-modal/local-quota-modal.tsx b/packages/frontend/core/src/components/affine/quota-reached-modal/local-quota-modal.tsx index 9703c672fc124..06f7d833335d9 100644 --- a/packages/frontend/core/src/components/affine/quota-reached-modal/local-quota-modal.tsx +++ b/packages/frontend/core/src/components/affine/quota-reached-modal/local-quota-modal.tsx @@ -16,13 +16,13 @@ export const LocalQuotaModal = () => { }, [setOpen]); useEffect(() => { - const disposable = currentWorkspace.engine.blob.onAbortLargeBlob.on(() => { + const disposable = currentWorkspace.engine.blob.onAbortLargeBlob(() => { setOpen(true); }); return () => { - disposable?.dispose(); + disposable(); }; - }, [currentWorkspace.engine.blob.onAbortLargeBlob, setOpen]); + }, [currentWorkspace.engine.blob, setOpen]); return ( { diff --git a/packages/frontend/core/src/modules/doc/services/docs.ts b/packages/frontend/core/src/modules/doc/services/docs.ts index 37fbfd3a80e7d..ed10a53ac42b6 100644 --- a/packages/frontend/core/src/modules/doc/services/docs.ts +++ b/packages/frontend/core/src/modules/doc/services/docs.ts @@ -3,13 +3,12 @@ import { Unreachable } from '@affine/env/constant'; import type { DocMode } from '@blocksuite/affine/blocks'; import type { DeltaInsert } from '@blocksuite/affine/inline'; import type { AffineTextAttributes } from '@blocksuite/affine-shared/types'; +import { ObjectPool, Service } from '@toeverything/infra'; + import { type DocProps, initDocFromProps, - ObjectPool, - Service, -} from '@toeverything/infra'; - +} from '../../../blocksuite/initialization'; import type { Doc } from '../entities/doc'; import { DocPropertyList } from '../entities/property-list'; import { DocRecordList } from '../entities/record-list'; diff --git a/packages/frontend/core/src/modules/journal/services/journal.ts b/packages/frontend/core/src/modules/journal/services/journal.ts index 6796d668461a6..6a21c704070a9 100644 --- a/packages/frontend/core/src/modules/journal/services/journal.ts +++ b/packages/frontend/core/src/modules/journal/services/journal.ts @@ -1,8 +1,11 @@ import { Text } from '@blocksuite/affine/store'; -import type { DocProps } from '@toeverything/infra'; -import { initDocFromProps, LiveData, Service } from '@toeverything/infra'; +import { LiveData, Service } from '@toeverything/infra'; import dayjs from 'dayjs'; +import { + type DocProps, + initDocFromProps, +} from '../../../blocksuite/initialization'; import type { DocsService } from '../../doc'; import type { EditorSettingService } from '../../editor-setting'; import type { JournalStore } from '../store/journal'; diff --git a/packages/frontend/core/src/modules/quicksearch/services/cmdk.ts b/packages/frontend/core/src/modules/quicksearch/services/cmdk.ts index f64d5a52f7d02..bfbc28e3ce388 100644 --- a/packages/frontend/core/src/modules/quicksearch/services/cmdk.ts +++ b/packages/frontend/core/src/modules/quicksearch/services/cmdk.ts @@ -1,8 +1,8 @@ import { track } from '@affine/track'; import { Text } from '@blocksuite/affine/store'; -import type { DocProps } from '@toeverything/infra'; import { Service } from '@toeverything/infra'; +import type { DocProps } from '../../../blocksuite/initialization'; import type { DocsService } from '../../doc'; import { EditorSettingService } from '../../editor-setting'; import type { WorkbenchService } from '../../workbench'; From 040f427e9e79de6b5357feaae6e7ce153f584c79 Mon Sep 17 00:00:00 2001 From: darkskygit Date: Thu, 26 Dec 2024 13:44:11 +0000 Subject: [PATCH 02/11] fix(server): test shuold forbid only (#9349) --- .github/workflows/build-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index 25f5253a637a5..0674eb48548b4 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -376,7 +376,7 @@ jobs: uses: ./.github/actions/server-test-env - name: Run server tests - run: yarn affine @affine/server test:coverage + run: yarn affine @affine/server test:coverage --forbid-only env: CARGO_TARGET_DIR: '${{ github.workspace }}/target' COPILOT_OPENAI_API_KEY: 'use_fake_openai_api_key' From 188cabc7d7dfd2c80e69dcc6aeccb218759c41ee Mon Sep 17 00:00:00 2001 From: zzj3720 <17165520+zzj3720@users.noreply.github.com> Date: Thu, 26 Dec 2024 14:00:11 +0000 Subject: [PATCH 03/11] refactor(editor): enable the noUncheckedIndexedAccess rule for the data-view package (#9351) close: BS-2230 --- .../src/core/component/overflow/overflow.ts | 4 +- .../src/core/component/tags/colors.ts | 3 +- .../core/component/tags/multi-tag-select.ts | 5 +- .../affine/data-view/src/core/data-view.ts | 3 + .../affine/data-view/src/core/filter/eval.ts | 2 +- .../src/core/filter/filter-fn/create.ts | 2 +- .../src/core/filter/filter-fn/multi-tag.ts | 8 +- .../core/filter/generate-default-values.ts | 1 + .../affine/data-view/src/core/filter/utils.ts | 9 ++- .../data-view/src/core/group-by/setting.ts | 13 +++- .../data-view/src/core/group-by/trait.ts | 13 ++-- .../src/core/logical/type-variable.ts | 2 +- .../affine/data-view/src/core/sort/eval.ts | 7 +- .../data-view/src/core/statistics/number.ts | 7 +- .../src/core/utils/wc-dnd/sensors/mouse.ts | 8 +- .../core/utils/wc-dnd/sort/sort-context.ts | 5 +- .../strategies/horizontal-list-sorting.ts | 23 ++++-- .../sort/strategies/vertical-list-sorting.ts | 2 +- .../src/core/utils/wc-dnd/utils/array-move.ts | 10 +-- .../src/core/view-manager/single-view.ts | 26 ++++--- .../src/core/view-manager/view-manager.ts | 10 ++- .../src/property-presets/select/define.ts | 3 + .../src/view-presets/kanban/define.ts | 6 ++ .../kanban/kanban-view-manager.ts | 7 +- .../kanban/pc/controller/selection.ts | 73 ++++++++++++------- .../src/view-presets/kanban/pc/group.ts | 16 ++-- .../src/view-presets/kanban/pc/kanban-view.ts | 13 +++- .../table/pc/controller/clipboard.ts | 16 ++-- .../table/pc/controller/hotkeys.ts | 3 +- .../table/pc/controller/selection.ts | 29 +++++--- .../src/view-presets/table/pc/menu.ts | 1 + .../table/stats/column-stats-column.ts | 9 ++- .../view-presets/table/table-view-manager.ts | 5 +- .../filter/condition-view.ts | 9 ++- .../filter/group-panel-view.ts | 3 + .../filter/root-panel-view.ts | 3 + .../presets/view-options/view-options.ts | 11 +-- .../widget-presets/views-bar/views-view.ts | 6 +- blocksuite/affine/data-view/tsconfig.json | 3 +- packages/common/env/src/ua-helper.ts | 2 +- 40 files changed, 258 insertions(+), 123 deletions(-) diff --git a/blocksuite/affine/data-view/src/core/component/overflow/overflow.ts b/blocksuite/affine/data-view/src/core/component/overflow/overflow.ts index dd9bde3894e76..bcdecaea5108e 100644 --- a/blocksuite/affine/data-view/src/core/component/overflow/overflow.ts +++ b/blocksuite/affine/data-view/src/core/component/overflow/overflow.ts @@ -56,7 +56,9 @@ export class Overflow extends SignalWatcher(WithDisposable(ShadowlessElement)) { let width = 0; for (let i = 0; i < this.items.length; i++) { - const itemWidth = this.items[i].getBoundingClientRect().width; + const item = this.items[i]; + if (!item) continue; + const itemWidth = item.getBoundingClientRect().width; // Try to calculate the width occupied by rendering n+1 items; // if it exceeds the limit, render n items(in i++ round). const totalWidth = diff --git a/blocksuite/affine/data-view/src/core/component/tags/colors.ts b/blocksuite/affine/data-view/src/core/component/tags/colors.ts index 36f852050c4cb..5b693018b67db 100644 --- a/blocksuite/affine/data-view/src/core/component/tags/colors.ts +++ b/blocksuite/affine/data-view/src/core/component/tags/colors.ts @@ -74,12 +74,13 @@ const selectTagColorPoll = selectOptionColors.map(color => color.color); function tagColorHelper() { let colors = [...selectTagColorPoll]; - return () => { + return (): string => { if (colors.length === 0) { colors = [...selectTagColorPoll]; } const index = Math.floor(Math.random() * colors.length); const color = colors.splice(index, 1)[0]; + if (!color) return ''; return color; }; } diff --git a/blocksuite/affine/data-view/src/core/component/tags/multi-tag-select.ts b/blocksuite/affine/data-view/src/core/component/tags/multi-tag-select.ts index 9c12fbef21743..61e58c914e372 100644 --- a/blocksuite/affine/data-view/src/core/component/tags/multi-tag-select.ts +++ b/blocksuite/affine/data-view/src/core/component/tags/multi-tag-select.ts @@ -243,7 +243,10 @@ export class MultiTagSelect extends SignalWatcher( event.stopPropagation(); const inputValue = this.text.value.trim(); if (event.key === 'Backspace' && inputValue === '') { - this.tagManager.deleteTag(this.value.value[this.value.value.length - 1]); + const lastId = this.value.value[this.value.value.length - 1]; + if (lastId) { + this.tagManager.deleteTag(lastId); + } } else if (event.key === 'Enter' && !event.isComposing) { this.selectedTag$.value?.select(); } else if (event.key === 'ArrowUp') { diff --git a/blocksuite/affine/data-view/src/core/data-view.ts b/blocksuite/affine/data-view/src/core/data-view.ts index ad8e938189747..b58a7f32bf458 100644 --- a/blocksuite/affine/data-view/src/core/data-view.ts +++ b/blocksuite/affine/data-view/src/core/data-view.ts @@ -87,6 +87,9 @@ export class DataViewRenderer extends SignalWatcher( return; } const view = this.viewMap$.value[currentViewId]; + if (!view) { + return; + } return { view: view, selection$: computed(() => { diff --git a/blocksuite/affine/data-view/src/core/filter/eval.ts b/blocksuite/affine/data-view/src/core/filter/eval.ts index 9e860f3a9fa41..7794bd9dfe0b1 100644 --- a/blocksuite/affine/data-view/src/core/filter/eval.ts +++ b/blocksuite/affine/data-view/src/core/filter/eval.ts @@ -25,7 +25,7 @@ export const evalFilter = ( for (let i = 0; i < expectArgLen; i++) { const argValue = evalValue(filter.args[i]); const argType = func.args[i]; - if (argValue == null) { + if (argValue == null || argType == null) { return true; } if (!argType.valueValidate(argValue)) { diff --git a/blocksuite/affine/data-view/src/core/filter/filter-fn/create.ts b/blocksuite/affine/data-view/src/core/filter/filter-fn/create.ts index 4358450fdb0b6..fb84eed5d04a4 100644 --- a/blocksuite/affine/data-view/src/core/filter/filter-fn/create.ts +++ b/blocksuite/affine/data-view/src/core/filter/filter-fn/create.ts @@ -32,7 +32,7 @@ export type FilterConfig< ) => boolean; defaultValue?: (args: { [K in keyof Args]: ValueTypeOf>; - }) => ValueTypeOf>; + }) => ValueTypeOf> | undefined; }; type FindVar< Vars extends TypeVarDefinitionInstance[], diff --git a/blocksuite/affine/data-view/src/core/filter/filter-fn/multi-tag.ts b/blocksuite/affine/data-view/src/core/filter/filter-fn/multi-tag.ts index 3e75e09b68389..e5cac0c44b99a 100644 --- a/blocksuite/affine/data-view/src/core/filter/filter-fn/multi-tag.ts +++ b/blocksuite/affine/data-view/src/core/filter/filter-fn/multi-tag.ts @@ -23,7 +23,13 @@ export const multiTagFilter = [ } return value.some(v => self.includes(v)); }, - defaultValue: args => [args[0][0]], + defaultValue: args => { + const value = args[0][0]; + if (value != null) { + return [value]; + } + return; + }, }), createFilter({ name: 'doesNotContainOneOf', diff --git a/blocksuite/affine/data-view/src/core/filter/generate-default-values.ts b/blocksuite/affine/data-view/src/core/filter/generate-default-values.ts index d2746968857e2..91a252703b8e2 100644 --- a/blocksuite/affine/data-view/src/core/filter/generate-default-values.ts +++ b/blocksuite/affine/data-view/src/core/filter/generate-default-values.ts @@ -28,6 +28,7 @@ export function generateDefaultValues( for (const [propertyId, conditions] of propertyConditions) { if (conditions.length === 1) { const condition = conditions[0]; + if (!condition) continue; const filterConfig = filterMatcher.getFilterByName(condition.function); if (filterConfig?.defaultValue) { const argValues = condition.args.map(arg => arg.value); diff --git a/blocksuite/affine/data-view/src/core/filter/utils.ts b/blocksuite/affine/data-view/src/core/filter/utils.ts index 04de5ec1ab766..8dc056866ef47 100644 --- a/blocksuite/affine/data-view/src/core/filter/utils.ts +++ b/blocksuite/affine/data-view/src/core/filter/utils.ts @@ -27,9 +27,16 @@ export const firstFilterByRef = ( }; }; export const firstFilter = (vars: Variable[]): SingleFilter => { + const variable = vars[0]; + if (!variable) { + throw new BlockSuiteError( + ErrorCode.DatabaseBlockError, + `can't find any variable` + ); + } const ref: VariableRef = { type: 'ref', - name: vars[0].id, + name: variable.id, }; const filter = firstFilterName(vars, ref); if (!filter) { diff --git a/blocksuite/affine/data-view/src/core/group-by/setting.ts b/blocksuite/affine/data-view/src/core/group-by/setting.ts index 259bd11ca32a1..2332a2760357a 100644 --- a/blocksuite/affine/data-view/src/core/group-by/setting.ts +++ b/blocksuite/affine/data-view/src/core/group-by/setting.ts @@ -78,8 +78,8 @@ export class GroupSetting extends SignalWatcher( const activeId = evt.active.id; const groups = this.groups$.value; if (over && over.id !== activeId && groups) { - const activeIndex = groups.findIndex(data => data.key === activeId); - const overIndex = groups.findIndex(data => data.key === over.id); + const activeIndex = groups.findIndex(data => data?.key === activeId); + const overIndex = groups.findIndex(data => data?.key === over.id); this.groupTrait.moveGroupTo( activeId, @@ -104,7 +104,11 @@ export class GroupSetting extends SignalWatcher( }, ], items: computed(() => { - return this.groupTrait.groupsDataList$.value?.map(v => v.key) ?? []; + return ( + this.groupTrait.groupsDataList$.value?.map( + v => v?.key ?? 'default key' + ) ?? [] + ); }), strategy: verticalListSortingStrategy, }); @@ -136,8 +140,9 @@ export class GroupSetting extends SignalWatcher( > ${repeat( groups, - group => group.key, + group => group?.key ?? 'default key', group => { + if (!group) return; const props: GroupRenderProps = { value: group.value, data: group.property.data$.value, diff --git a/blocksuite/affine/data-view/src/core/group-by/trait.ts b/blocksuite/affine/data-view/src/core/group-by/trait.ts index 699b8f009583b..5547541f272b5 100644 --- a/blocksuite/affine/data-view/src/core/group-by/trait.ts +++ b/blocksuite/affine/data-view/src/core/group-by/trait.ts @@ -110,9 +110,12 @@ export class GroupTrait { } const sortedGroup = this.ops.sortGroup(Object.keys(groupMap)); sortedGroup.forEach(key => { + if (!groupMap[key]) return; groupMap[key].rows = this.ops.sortRow(key, groupMap[key].rows); }); - return (this.preDataList = sortedGroup.map(key => groupMap[key])); + return (this.preDataList = sortedGroup + .map(key => groupMap[key]) + .filter((v): v is GroupData => v != null)); }); groupsDataList$ = computed(() => { @@ -166,7 +169,7 @@ export class GroupTrait { } const addTo = this.config$.value?.addToGroup ?? (value => value); const newValue = addTo( - groupMap[key].value, + groupMap[key]?.value, this.view.cellJsonValueGet(rowId, propertyId) ); this.view.cellValueSet(rowId, propertyId, newValue); @@ -240,10 +243,10 @@ export class GroupTrait { ); } const addTo = this.config$.value?.addToGroup ?? (value => value); - newValue = addTo(groupMap[toGroupKey].value, newValue); + newValue = addTo(groupMap[toGroupKey]?.value, newValue); this.view.cellValueSet(rowId, propertyId, newValue); } - const rows = groupMap[toGroupKey].rows.filter(id => id !== rowId); + const rows = groupMap[toGroupKey]?.rows.filter(id => id !== rowId) ?? []; const index = insertPositionToIndex(position, rows, id => id); rows.splice(index, 0, rowId); this.changeCardSort(toGroupKey, rows); @@ -275,7 +278,7 @@ export class GroupTrait { } const remove = this.config$.value?.removeFromGroup ?? (() => undefined); const newValue = remove( - groupMap[key].value, + groupMap[key]?.value, this.view.cellJsonValueGet(rowId, propertyId) ); this.view.cellValueSet(rowId, propertyId, newValue); diff --git a/blocksuite/affine/data-view/src/core/logical/type-variable.ts b/blocksuite/affine/data-view/src/core/logical/type-variable.ts index d6676ed17b566..2d95501117853 100644 --- a/blocksuite/affine/data-view/src/core/logical/type-variable.ts +++ b/blocksuite/affine/data-view/src/core/logical/type-variable.ts @@ -29,7 +29,7 @@ export class TypeVarReferenceInstance constructor(readonly varName: Name) {} subst(ctx: TypeVarContext): void | TypeInstance { - return ctx[this.varName].type; + return ctx[this.varName]?.type; } unify(_ctx: TypeVarContext, _type: TypeInstance, _unify: Unify): boolean { diff --git a/blocksuite/affine/data-view/src/core/sort/eval.ts b/blocksuite/affine/data-view/src/core/sort/eval.ts index f5510b3b75bab..485f8d532ea68 100644 --- a/blocksuite/affine/data-view/src/core/sort/eval.ts +++ b/blocksuite/affine/data-view/src/core/sort/eval.ts @@ -34,7 +34,12 @@ const compareList = ( ) => { let i = 0; while (i < listA.length && i < listB.length) { - const result = compare(listA[i], listB[i]); + const a = listA[i]; + const b = listB[i]; + if (a == null || b == null) { + continue; + } + const result = compare(a, b); if (result !== 0) { return result; } diff --git a/blocksuite/affine/data-view/src/core/statistics/number.ts b/blocksuite/affine/data-view/src/core/statistics/number.ts index 26662f6cd46d3..e19af57275c71 100644 --- a/blocksuite/affine/data-view/src/core/statistics/number.ts +++ b/blocksuite/affine/data-view/src/core/statistics/number.ts @@ -41,12 +41,15 @@ export const numberStatsFunctions: StatisticsConfig[] = [ dataType: t.number.instance(), impl: data => { const arr = withoutNull(data).sort((a, b) => a - b); - let result = 0; + let result: number | undefined = undefined; if (arr.length % 2 === 1) { result = arr[(arr.length - 1) / 2]; } else { const index = arr.length / 2; - result = (arr[index] + arr[index - 1]) / 2; + const a = arr[index]; + const b = arr[index - 1]; + if (a == null || b == null) return 'None'; + result = (a + b) / 2; } return result?.toString() ?? 'None'; }, diff --git a/blocksuite/affine/data-view/src/core/utils/wc-dnd/sensors/mouse.ts b/blocksuite/affine/data-view/src/core/utils/wc-dnd/sensors/mouse.ts index 5057feca7cba7..e3d8a40d3e69d 100644 --- a/blocksuite/affine/data-view/src/core/utils/wc-dnd/sensors/mouse.ts +++ b/blocksuite/affine/data-view/src/core/utils/wc-dnd/sensors/mouse.ts @@ -77,14 +77,18 @@ export function hasViewportRelativeCoordinates( const getEventCoordinates = (event: Event) => { if (event instanceof TouchEvent) { if (event.touches && event.touches.length) { - const { clientX: x, clientY: y } = event.touches[0]; + const touch = event.touches[0]; + if (!touch) return; + const { clientX: x, clientY: y } = touch; return { x, y, }; } else if (event.changedTouches && event.changedTouches.length) { - const { clientX: x, clientY: y } = event.changedTouches[0]; + const touch = event.changedTouches[0]; + if (!touch) return; + const { clientX: x, clientY: y } = touch; return { x, diff --git a/blocksuite/affine/data-view/src/core/utils/wc-dnd/sort/sort-context.ts b/blocksuite/affine/data-view/src/core/utils/wc-dnd/sort/sort-context.ts index 102082c4230e9..abf32f0273a47 100644 --- a/blocksuite/affine/data-view/src/core/utils/wc-dnd/sort/sort-context.ts +++ b/blocksuite/affine/data-view/src/core/utils/wc-dnd/sort/sort-context.ts @@ -68,7 +68,10 @@ export class SortContext extends DndContext { overIndex: list.findIndex(v => v.id === this.overId$.value), }); transforms.forEach((transform, i) => { - const node = list[i].node; + const node = list[i]?.node; + if (!node) { + return; + } if (transform != null) { node.style.transform = `translate3d(${Math.round(transform.x)}px,${Math.round(transform.y)}px,0) scaleX(${transform.scaleX}) scaleY(${transform.scaleY})`; diff --git a/blocksuite/affine/data-view/src/core/utils/wc-dnd/sort/strategies/horizontal-list-sorting.ts b/blocksuite/affine/data-view/src/core/utils/wc-dnd/sort/strategies/horizontal-list-sorting.ts index e8512257e5957..ffd2b6a40729d 100644 --- a/blocksuite/affine/data-view/src/core/utils/wc-dnd/sort/strategies/horizontal-list-sorting.ts +++ b/blocksuite/affine/data-view/src/core/utils/wc-dnd/sort/strategies/horizontal-list-sorting.ts @@ -12,6 +12,7 @@ export const horizontalListSortingStrategy: SortingStrategy = ({ overIndex, }) => { const activeNodeRect = rects[activeIndex] ?? fallbackActiveRect; + if (!activeNodeRect) return []; const strategy = (index: number) => { const itemGap = getItemGap(rects, index, activeIndex); @@ -73,12 +74,22 @@ function getItemGap( } if (activeIndex < index) { - return previousRect - ? currentRect.left - (previousRect.left + previousRect.width) - : nextRect.left - (currentRect.left + currentRect.width); + if (previousRect) { + return currentRect.left - (previousRect.left + previousRect.width); + } + if (nextRect) { + return nextRect.left - (currentRect.left + currentRect.width); + } + return 0; + } + + if (nextRect) { + return nextRect.left - (currentRect.left + currentRect.width); + } + + if (previousRect) { + return currentRect.left - (previousRect.left + previousRect.width); } - return nextRect - ? nextRect.left - (currentRect.left + currentRect.width) - : currentRect.left - (previousRect.left + previousRect.width); + return 0; } diff --git a/blocksuite/affine/data-view/src/core/utils/wc-dnd/sort/strategies/vertical-list-sorting.ts b/blocksuite/affine/data-view/src/core/utils/wc-dnd/sort/strategies/vertical-list-sorting.ts index 03d7908af97c4..bf546a15516bd 100644 --- a/blocksuite/affine/data-view/src/core/utils/wc-dnd/sort/strategies/vertical-list-sorting.ts +++ b/blocksuite/affine/data-view/src/core/utils/wc-dnd/sort/strategies/vertical-list-sorting.ts @@ -12,7 +12,7 @@ export const verticalListSortingStrategy: SortingStrategy = ({ overIndex, }) => { const activeNodeRect = rects[activeIndex] ?? fallbackActiveRect; - + if (!activeNodeRect) return []; const strategy = (index: number) => { if (index === activeIndex) { const overIndexRect = rects[overIndex]; diff --git a/blocksuite/affine/data-view/src/core/utils/wc-dnd/utils/array-move.ts b/blocksuite/affine/data-view/src/core/utils/wc-dnd/utils/array-move.ts index d0f89b6a9f0b4..41db96374cceb 100644 --- a/blocksuite/affine/data-view/src/core/utils/wc-dnd/utils/array-move.ts +++ b/blocksuite/affine/data-view/src/core/utils/wc-dnd/utils/array-move.ts @@ -3,11 +3,11 @@ */ export function arrayMove(array: T[], from: number, to: number): T[] { const newArray = array.slice(); - newArray.splice( - to < 0 ? newArray.length + to : to, - 0, - newArray.splice(from, 1)[0] - ); + const value = newArray.splice(from, 1)[0]; + if (value == null) { + return newArray; + } + newArray.splice(to < 0 ? newArray.length + to : to, 0, value); return newArray; } diff --git a/blocksuite/affine/data-view/src/core/view-manager/single-view.ts b/blocksuite/affine/data-view/src/core/view-manager/single-view.ts index 84520c178fa35..de69c8b1d7f72 100644 --- a/blocksuite/affine/data-view/src/core/view-manager/single-view.ts +++ b/blocksuite/affine/data-view/src/core/view-manager/single-view.ts @@ -76,9 +76,9 @@ export interface SingleView { rowGet(rowId: string): Row; - rowPrevGet(rowId: string): string; + rowPrevGet(rowId: string): string | undefined; - rowNextGet(rowId: string): string; + rowNextGet(rowId: string): string | undefined; readonly propertyMetas: PropertyMetaConfig[]; @@ -116,7 +116,7 @@ export interface SingleView { propertyIndexGet(propertyId: string): number; - propertyIdGetByIndex(index: number): string; + propertyIdGetByIndex(index: number): string | undefined; propertyReadonlyGet(propertyId: string): boolean; @@ -387,7 +387,7 @@ export abstract class SingleViewBase< return this.dataSource.propertyMetaGet(type).renderer.icon; } - propertyIdGetByIndex(index: number): string { + propertyIdGetByIndex(index: number): string | undefined { return this.propertyIds$.value[index]; } @@ -410,9 +410,10 @@ export abstract class SingleViewBase< } propertyNextGet(propertyId: string): Property | undefined { - return this.propertyGet( - this.propertyIdGetByIndex(this.propertyIndexGet(propertyId) + 1) - ); + const index = this.propertyIndexGet(propertyId); + const nextId = this.propertyIdGetByIndex(index + 1); + if (!nextId) return; + return this.propertyGet(nextId); } propertyParseValueFromString(propertyId: string, cellData: string) { @@ -430,9 +431,10 @@ export abstract class SingleViewBase< } propertyPreGet(propertyId: string): Property | undefined { - return this.propertyGet( - this.propertyIdGetByIndex(this.propertyIndexGet(propertyId) - 1) - ); + const index = this.propertyIndexGet(propertyId); + const prevId = this.propertyIdGetByIndex(index - 1); + if (!prevId) return; + return this.propertyGet(prevId); } propertyReadonlyGet(propertyId: string): boolean { @@ -463,9 +465,9 @@ export abstract class SingleViewBase< this.dataSource.rowMove(rowId, position); } - abstract rowNextGet(rowId: string): string; + abstract rowNextGet(rowId: string): string | undefined; - abstract rowPrevGet(rowId: string): string; + abstract rowPrevGet(rowId: string): string | undefined; protected rowsMapping(rows: string[]): string[] { return this.searchRowsMapping(rows, this.searchString.value); diff --git a/blocksuite/affine/data-view/src/core/view-manager/view-manager.ts b/blocksuite/affine/data-view/src/core/view-manager/view-manager.ts index 431769bcc1289..0be42c4828604 100644 --- a/blocksuite/affine/data-view/src/core/view-manager/view-manager.ts +++ b/blocksuite/affine/data-view/src/core/view-manager/view-manager.ts @@ -15,8 +15,8 @@ export interface ViewManager { dataSource: DataSource; readonly$: ReadonlySignal; - currentViewId$: ReadonlySignal; - currentView$: ReadonlySignal; + currentViewId$: ReadonlySignal; + currentView$: ReadonlySignal; setCurrentView(id: string): void; @@ -49,7 +49,9 @@ export class ViewManagerBase implements ViewManager { }); currentView$ = computed(() => { - return this.viewGet(this.currentViewId$.value); + const id = this.currentViewId$.value; + if (!id) return; + return this.viewGet(id); }); readonly$ = computed(() => { @@ -66,7 +68,7 @@ export class ViewManagerBase implements ViewManager { this.dataSource.viewDataMoveTo(id, position); } - setCurrentView(id: string): void { + setCurrentView(id: string | undefined): void { this._currentViewId$.value = id; } diff --git a/blocksuite/affine/data-view/src/property-presets/select/define.ts b/blocksuite/affine/data-view/src/property-presets/select/define.ts index 4503eb4d3fc20..ed611152c2715 100644 --- a/blocksuite/affine/data-view/src/property-presets/select/define.ts +++ b/blocksuite/affine/data-view/src/property-presets/select/define.ts @@ -37,6 +37,9 @@ export const selectPropertyModelConfig = selectPropertyType.modelConfig< .split(',') .map(v => v.trim()) .filter(v => v)[0]; + if (!name) { + return { value: null, data: data }; + } let value: string | undefined; const option = optionMap[name]; diff --git a/blocksuite/affine/data-view/src/view-presets/kanban/define.ts b/blocksuite/affine/data-view/src/view-presets/kanban/define.ts index e8bfb3b22eadd..a713bb470edc6 100644 --- a/blocksuite/affine/data-view/src/view-presets/kanban/define.ts +++ b/blocksuite/affine/data-view/src/view-presets/kanban/define.ts @@ -53,6 +53,12 @@ export const kanbanViewModel = kanbanViewType.createModel({ return 1; }; const columnId = allowList.sort((a, b) => getWeight(b) - getWeight(a))[0]; + if (!columnId) { + throw new BlockSuiteError( + ErrorCode.DatabaseBlockError, + 'no groupable column found' + ); + } const type = viewManager.dataSource.propertyTypeGet(columnId); const meta = type && viewManager.dataSource.propertyMetaGet(type); const data = viewManager.dataSource.propertyDataGet(columnId); diff --git a/blocksuite/affine/data-view/src/view-presets/kanban/kanban-view-manager.ts b/blocksuite/affine/data-view/src/view-presets/kanban/kanban-view-manager.ts index e0c8580ce5575..c9b6b774ebb2c 100644 --- a/blocksuite/affine/data-view/src/view-presets/kanban/kanban-view-manager.ts +++ b/blocksuite/affine/data-view/src/view-presets/kanban/kanban-view-manager.ts @@ -285,6 +285,9 @@ export class KanbanSingleView extends SingleViewBase { } const columns = [...view.columns]; const [column] = columns.splice(columnIndex, 1); + if (!column) { + return {}; + } const index = insertPositionToIndex(toAfterOfColumn, columns); columns.splice(index, 0, column); return { @@ -297,12 +300,12 @@ export class KanbanSingleView extends SingleViewBase { this.dataSource.rowMove(rowId, position); } - override rowNextGet(rowId: string): string { + override rowNextGet(rowId: string): string | undefined { const index = this.rows$.value.indexOf(rowId); return this.rows$.value[index + 1]; } - override rowPrevGet(rowId: string): string { + override rowPrevGet(rowId: string): string | undefined { const index = this.rows$.value.indexOf(rowId); return this.rows$.value[index - 1]; } diff --git a/blocksuite/affine/data-view/src/view-presets/kanban/pc/controller/selection.ts b/blocksuite/affine/data-view/src/view-presets/kanban/pc/controller/selection.ts index a2cc30058dce6..17ea1caf77889 100644 --- a/blocksuite/affine/data-view/src/view-presets/kanban/pc/controller/selection.ts +++ b/blocksuite/affine/data-view/src/view-presets/kanban/pc/controller/selection.ts @@ -183,7 +183,7 @@ export class KanbanSelectionController implements ReactiveController { if (selection.selectionType === 'card') { const card = getSelectedCards(this.host, selection)[0]; const cell = card?.querySelector('affine-data-view-kanban-cell'); - if (cell) { + if (card && cell) { this.selection = { groupKey: card.groupKey, cardId: card.cardId, @@ -209,11 +209,9 @@ export class KanbanSelectionController implements ReactiveController { const index = kanbanCells.findIndex( cell => cell.column.id === selection.columnId ); - const { cell, cardId, groupKey } = this.getNextFocusCell( - selection, - index, - position - ); + const result = this.getNextFocusCell(selection, index, position); + if (!result) return; + const { cell, cardId, groupKey } = result; if (cell instanceof KanbanCell) { this.selection = { ...selection, @@ -234,7 +232,9 @@ export class KanbanSelectionController implements ReactiveController { const index = cardElements.findIndex( card => card.cardId === selection.cards[0].cardId ); - const { card, cards } = this.getNextFocusCard(selection, index, position); + const result = this.getNextFocusCard(selection, index, position); + if (!result) return; + const { card, cards } = result; if (card instanceof KanbanCard) { const newCards = cards ?? selection.cards; this.selection = atLeastOne(newCards) @@ -286,10 +286,12 @@ export class KanbanSelectionController implements ReactiveController { selection: KanbanCardSelection, index: number, nextPosition: 'up' | 'down' | 'left' | 'right' - ): { - card: KanbanCard; - cards: KanbanCardSelectionCard[]; - } { + ): + | { + card: KanbanCard; + cards: KanbanCardSelectionCard[]; + } + | undefined { const group = this.host.querySelector( `affine-data-view-kanban-group[data-key="${selection.cards[0].groupKey}"]` ); @@ -301,7 +303,7 @@ export class KanbanSelectionController implements ReactiveController { const nextIndex = index - 1; const nextCardIndex = nextIndex < 0 ? kanbanCards.length - 1 : nextIndex; const card = kanbanCards[nextCardIndex]; - + if (!card) return; return { card, cards: [ @@ -317,7 +319,7 @@ export class KanbanSelectionController implements ReactiveController { const nextIndex = index + 1; const nextCardIndex = nextIndex > kanbanCards.length - 1 ? 0 : nextIndex; const card = kanbanCards[nextCardIndex]; - + if (!card) return; return { card, cards: [ @@ -360,11 +362,13 @@ export class KanbanSelectionController implements ReactiveController { selection: KanbanCellSelection, index: number, nextPosition: 'up' | 'down' | 'left' | 'right' - ): { - cell: KanbanCell; - cardId?: string; - groupKey?: string; - } { + ): + | { + cell: KanbanCell; + cardId?: string; + groupKey?: string; + } + | undefined { const kanbanCells = getCardCellsBySelection(this.host, selection); const group = this.host.querySelector( `affine-data-view-kanban-group[data-key="${selection.groupKey}"]` @@ -384,11 +388,14 @@ export class KanbanSelectionController implements ReactiveController { cardIndex => (cardIndex === 0 ? cards.length - 1 : cardIndex - 1) ); } else { + const cell = kanbanCells[kanbanCells.length - 1]; + if (!cell) return; return { - cell: kanbanCells[kanbanCells.length - 1], + cell, }; } } + if (!kanbanCells[nextIndex]) return; return { cell: kanbanCells[nextIndex], }; @@ -405,11 +412,14 @@ export class KanbanSelectionController implements ReactiveController { cardIndex => (cardIndex === cards.length - 1 ? 0 : cardIndex + 1) ); } else { + const cell = kanbanCells[0]; + if (!cell) return; return { - cell: kanbanCells[0], + cell, }; } } + if (!kanbanCells[nextIndex]) return; return { cell: kanbanCells[nextIndex], }; @@ -569,19 +579,19 @@ function getNextGroupFocusElement( groups: KanbanGroup[], selection: KanbanCellSelection, getNextGroupIndex: (groupIndex: number) => number -): NextFocusCell; +): NextFocusCell | undefined; function getNextGroupFocusElement( viewElement: Element, groups: KanbanGroup[], selection: KanbanCardSelection, getNextGroupIndex: (groupIndex: number) => number -): NextFocusCard; +): NextFocusCard | undefined; function getNextGroupFocusElement( viewElement: Element, groups: KanbanGroup[], selection: KanbanCellSelection | KanbanCardSelection, getNextGroupIndex: (groupIndex: number) => number -): NextFocusCell | NextFocusCard { +): NextFocusCell | NextFocusCard | undefined { const groupIndex = groups.findIndex(group => { if (selection.selectionType === 'cell') { return group.group.key === selection.groupKey; @@ -591,10 +601,11 @@ function getNextGroupFocusElement( let nextGroupIndex = getNextGroupIndex(groupIndex); let nextGroup = groups[nextGroupIndex]; - while (nextGroup.group.rows.length === 0) { + while (nextGroup?.group.rows.length === 0) { nextGroupIndex = getNextGroupIndex(nextGroupIndex); nextGroup = groups[nextGroupIndex]; } + if (!nextGroup) return; const element = selection.selectionType === 'cell' @@ -621,6 +632,7 @@ function getNextGroupFocusElement( }); const nextCard = nextCards[cardPos.index]; + if (!nextCard) return; if (selection.selectionType === 'card') { return { card: nextCard, @@ -652,6 +664,7 @@ function getNextGroupFocusElement( }); const nextCell = cells[cellPos.index]; + if (!nextCell) return; return { cell: nextCell, cardId: nextCard.cardId, @@ -664,17 +677,21 @@ function getNextCardFocusCell( cards: KanbanCard[], selection: KanbanCellSelection, getNextCardIndex: (cardIndex: number) => number -): { - cell: KanbanCell; - cardId: string; -} { +): + | { + cell: KanbanCell; + cardId: string; + } + | undefined { const cardIndex = cards.findIndex(card => card.cardId === selection.cardId); const nextCardIndex = getNextCardIndex(cardIndex); const nextCard = cards[nextCardIndex]; + if (!nextCard) return; const nextCells = Array.from( nextCard.querySelectorAll('affine-data-view-kanban-cell') ); const nextCellIndex = nextPosition === 'up' ? nextCells.length - 1 : 0; + if (!nextCells[nextCellIndex]) return; return { cell: nextCells[nextCellIndex], cardId: nextCard.cardId, diff --git a/blocksuite/affine/data-view/src/view-presets/kanban/pc/group.ts b/blocksuite/affine/data-view/src/view-presets/kanban/pc/group.ts index be27e1114c3f3..d49e75744b50f 100644 --- a/blocksuite/affine/data-view/src/view-presets/kanban/pc/group.ts +++ b/blocksuite/affine/data-view/src/view-presets/kanban/pc/group.ts @@ -101,13 +101,15 @@ export class KanbanGroup extends SignalWatcher( requestAnimationFrame(() => { const kanban = this.closest('affine-data-view-kanban'); if (kanban) { + const columnId = + this.view.mainProperties$.value.titleColumn || + this.view.propertyIds$.value[0]; + if (!columnId) return; kanban.selectionController.selection = { selectionType: 'cell', groupKey: this.group.key, cardId: id, - columnId: - this.view.mainProperties$.value.titleColumn || - this.view.propertyIds$.value[0], + columnId, isEditing: true, }; } @@ -119,13 +121,15 @@ export class KanbanGroup extends SignalWatcher( requestAnimationFrame(() => { const kanban = this.closest('affine-data-view-kanban'); if (kanban) { + const columnId = + this.view.mainProperties$.value.titleColumn || + this.view.propertyIds$.value[0]; + if (!columnId) return; kanban.selectionController.selection = { selectionType: 'cell', groupKey: this.group.key, cardId: id, - columnId: - this.view.mainProperties$.value.titleColumn || - this.view.propertyIds$.value[0], + columnId, isEditing: true, }; } diff --git a/blocksuite/affine/data-view/src/view-presets/kanban/pc/kanban-view.ts b/blocksuite/affine/data-view/src/view-presets/kanban/pc/kanban-view.ts index 5c55c8fd0d78c..46f6b7237b933 100644 --- a/blocksuite/affine/data-view/src/view-presets/kanban/pc/kanban-view.ts +++ b/blocksuite/affine/data-view/src/view-presets/kanban/pc/kanban-view.ts @@ -166,8 +166,8 @@ export class DataViewKanban extends DataViewBase< const activeId = evt.active.id; const groups = this.groupManager.groupsDataList$.value; if (over && over.id !== activeId && groups) { - const activeIndex = groups.findIndex(data => data.key === activeId); - const overIndex = groups.findIndex(data => data.key === over.id); + const activeIndex = groups.findIndex(data => data?.key === activeId); + const overIndex = groups.findIndex(data => data?.key === over.id); this.groupManager.moveGroupTo( activeId, @@ -192,7 +192,11 @@ export class DataViewKanban extends DataViewBase< }, ], items: computed(() => { - return this.groupManager.groupsDataList$.value?.map(v => v.key) ?? []; + return ( + this.groupManager.groupsDataList$.value?.map( + v => v?.key ?? 'default key' + ) ?? [] + ); }), strategy: horizontalListSortingStrategy, }); @@ -268,8 +272,9 @@ export class DataViewKanban extends DataViewBase< > ${repeat( groups, - group => group.key, + group => group?.key ?? 'default key', group => { + if (!group) return; return html` group.rows.map(id => ({ groupKey: group.key, id })) + group => + group?.rows.map(id => ({ groupKey: group.key, id })) ?? [] ) ?? this.host.props.view.rows$.value.map(id => ({ groupKey: undefined, diff --git a/blocksuite/affine/data-view/src/view-presets/table/pc/controller/selection.ts b/blocksuite/affine/data-view/src/view-presets/table/pc/controller/selection.ts index e541dfb3a0eae..484b01fcd0edc 100644 --- a/blocksuite/affine/data-view/src/view-presets/table/pc/controller/selection.ts +++ b/blocksuite/affine/data-view/src/view-presets/table/pc/controller/selection.ts @@ -234,7 +234,7 @@ export class TableSelectionController implements ReactiveController { } const rows = groupKey != null - ? this.view.groupTrait.groupDataMap$.value?.[groupKey].rows + ? this.view.groupTrait.groupDataMap$.value?.[groupKey]?.rows : this.view.rows$.value; requestAnimationFrame(() => { const index = this.host.props.view.properties$.value.findIndex( @@ -285,7 +285,8 @@ export class TableSelectionController implements ReactiveController { length: selection.rowsSelection.end - selection.rowsSelection.start + 1, }) .map((_, index) => index + selection.rowsSelection.start) - .map(row => rows[row]?.rowId); + .map(row => rows[row]?.rowId) + .filter((id): id is string => id != null); return ids.map(id => ({ id, groupKey: selection.groupKey })); } @@ -314,6 +315,7 @@ export class TableSelectionController implements ReactiveController { }; for (let i = 0; i < rowOffsets.length; i++) { const offset = rowOffsets[i]; + if (offset == null) continue; if (offset < startY) { row.start = i; } @@ -323,6 +325,7 @@ export class TableSelectionController implements ReactiveController { } for (let i = 0; i < columnOffsets.length; i++) { const offset = columnOffsets[i]; + if (offset == null) continue; if (offset < startX) { column.start = i; } @@ -544,20 +547,21 @@ export class TableSelectionController implements ReactiveController { if (!TableRowSelection.is(this.selection)) return; const rows = this.selection.rows; const lastRow = rows[rows.length - 1]; + if (!lastRow) return; const lastRowIndex = ( - this.getGroup(lastRow.groupKey)?.querySelector( - `data-view-table-row[data-row-id='${lastRow.id}']` + this.getGroup(lastRow?.groupKey)?.querySelector( + `data-view-table-row[data-row-id='${lastRow?.id}']` ) as TableRow | null )?.rowIndex ?? 0; const getRowByIndex = (index: number) => { - const tableRow = this.rows(lastRow.groupKey)?.item(index); + const tableRow = this.rows(lastRow?.groupKey)?.item(index); if (!tableRow) { return; } return { id: tableRow.rowId, - groupKey: lastRow.groupKey, + groupKey: lastRow?.groupKey, }; }; const prevRow = getRowByIndex(lastRowIndex - 1); @@ -621,10 +625,15 @@ export class TableSelectionController implements ReactiveController { add.forEach(row => rows.add(key(row))); const result = [...rows] .map(r => r.split('.')) - .map(([id, groupKey]) => ({ - id, - groupKey: groupKey ? groupKey : undefined, - })); + .flatMap(([id, groupKey]) => { + if (id == null) return []; + return [ + { + id, + groupKey: groupKey ? groupKey : undefined, + }, + ]; + }); this.selection = TableRowSelection.create({ rows: result, }); diff --git a/blocksuite/affine/data-view/src/view-presets/table/pc/menu.ts b/blocksuite/affine/data-view/src/view-presets/table/pc/menu.ts index ef3e62bdd2271..c8b4621fc9897 100644 --- a/blocksuite/affine/data-view/src/view-presets/table/pc/menu.ts +++ b/blocksuite/affine/data-view/src/view-presets/table/pc/menu.ts @@ -79,6 +79,7 @@ export const popRowMenu = ( return; } const row = selection.rows[0]; + if (!row) return; popFilterableSimpleMenu(ele, [ menu.action({ name: 'Expand Row', diff --git a/blocksuite/affine/data-view/src/view-presets/table/stats/column-stats-column.ts b/blocksuite/affine/data-view/src/view-presets/table/stats/column-stats-column.ts index 6b503d8e0c4d5..04fb1d8d29689 100644 --- a/blocksuite/affine/data-view/src/view-presets/table/stats/column-stats-column.ts +++ b/blocksuite/affine/data-view/src/view-presets/table/stats/column-stats-column.ts @@ -94,12 +94,15 @@ export class DatabaseColumnStatsCell extends SignalWatcher( if (!groups[func.group]) { groups[func.group] = {}; } - const oldFunc = groups[func.group][func.type]; + const oldFunc = groups[func.group]?.[func.type]; if (!oldFunc || typeSystem.unify(func.dataType, oldFunc.dataType)) { if (!func.impl) { - delete groups[func.group][func.type]; + delete groups[func.group]?.[func.type]; } else { - groups[func.group][func.type] = func; + const group = groups[func.group]; + if (group) { + group[func.type] = func; + } } } }); diff --git a/blocksuite/affine/data-view/src/view-presets/table/table-view-manager.ts b/blocksuite/affine/data-view/src/view-presets/table/table-view-manager.ts index 1c2f7da0ee671..ea549e71bc245 100644 --- a/blocksuite/affine/data-view/src/view-presets/table/table-view-manager.ts +++ b/blocksuite/affine/data-view/src/view-presets/table/table-view-manager.ts @@ -306,6 +306,7 @@ export class TableSingleView extends SingleViewBase { } const columns = [...this.computedColumns$.value]; const [column] = columns.splice(columnIndex, 1); + if (!column) return {}; const index = insertPositionToIndex(toAfterOfColumn, columns); columns.splice(index, 0, column); return { @@ -356,12 +357,12 @@ export class TableSingleView extends SingleViewBase { this.groupTrait.moveCardTo(rowId, fromGroup, toGroup, position); } - override rowNextGet(rowId: string): string { + override rowNextGet(rowId: string): string | undefined { const index = this.rows$.value.indexOf(rowId); return this.rows$.value[index + 1]; } - override rowPrevGet(rowId: string): string { + override rowPrevGet(rowId: string): string | undefined { const index = this.rows$.value.indexOf(rowId); return this.rows$.value[index - 1]; } diff --git a/blocksuite/affine/data-view/src/widget-presets/quick-setting-bar/filter/condition-view.ts b/blocksuite/affine/data-view/src/widget-presets/quick-setting-bar/filter/condition-view.ts index ccc9717a4190d..33cd4340832a6 100644 --- a/blocksuite/affine/data-view/src/widget-presets/quick-setting-bar/filter/condition-view.ts +++ b/blocksuite/affine/data-view/src/widget-presets/quick-setting-bar/filter/condition-view.ts @@ -233,9 +233,12 @@ export class FilterConditionView extends SignalWatcher(ShadowlessElement) { if (!type || !argValues || !data) { return; } - const argDataList = argValues.map((v, i) => - v ? { value: v, type: type.args[i + 1] } : undefined - ); + const argDataList = argValues.map((v, i) => { + if (v == null) return undefined; + const argType = type.args[i + 1]; + if (!argType) return undefined; + return { value: v, type: argType }; + }); const valueString = data.shortString?.(...argDataList) ?? ''; if (valueString) { return `${name}${valueString}`; diff --git a/blocksuite/affine/data-view/src/widget-presets/quick-setting-bar/filter/group-panel-view.ts b/blocksuite/affine/data-view/src/widget-presets/quick-setting-bar/filter/group-panel-view.ts index db4bda2b344c8..90e1004844d84 100644 --- a/blocksuite/affine/data-view/src/widget-presets/quick-setting-bar/filter/group-panel-view.ts +++ b/blocksuite/affine/data-view/src/widget-presets/quick-setting-bar/filter/group-panel-view.ts @@ -262,6 +262,9 @@ export class FilterGroupView extends SignalWatcher(ShadowlessElement) { private _clickConditionOps(target: HTMLElement, i: number) { const filter = this.filterGroup.value.conditions[i]; + if (!filter) { + return; + } popFilterableSimpleMenu(popupTargetFromElement(target), [ menu.group({ items: [ diff --git a/blocksuite/affine/data-view/src/widget-presets/quick-setting-bar/filter/root-panel-view.ts b/blocksuite/affine/data-view/src/widget-presets/quick-setting-bar/filter/root-panel-view.ts index 083f80e96cab2..1f88d215433ad 100644 --- a/blocksuite/affine/data-view/src/widget-presets/quick-setting-bar/filter/root-panel-view.ts +++ b/blocksuite/affine/data-view/src/widget-presets/quick-setting-bar/filter/root-panel-view.ts @@ -202,6 +202,9 @@ export class FilterRootView extends SignalWatcher(ShadowlessElement) { private _clickConditionOps(target: HTMLElement, i: number) { const filter = this.filterGroup.value.conditions[i]; + if (!filter) { + return; + } popFilterableSimpleMenu(popupTargetFromElement(target), [ menu.action({ name: filter.type === 'filter' ? 'Turn into group' : 'Wrap in group', diff --git a/blocksuite/affine/data-view/src/widget-presets/tools/presets/view-options/view-options.ts b/blocksuite/affine/data-view/src/widget-presets/tools/presets/view-options/view-options.ts index f2070c95d79be..a0dc70a52687a 100644 --- a/blocksuite/affine/data-view/src/widget-presets/tools/presets/view-options/view-options.ts +++ b/blocksuite/affine/data-view/src/widget-presets/tools/presets/view-options/view-options.ts @@ -259,7 +259,7 @@ export const popViewOptions = ( return; } const isSelected = - meta.type === view.manager.currentView$.value.type; + meta.type === view.manager.currentView$.value?.type; const iconStyle = styleMap({ fontSize: '24px', color: isSelected @@ -285,10 +285,11 @@ export const popViewOptions = ( `, select: () => { - view.manager.viewChangeType( - view.manager.currentViewId$.value, - meta.type - ); + const id = view.manager.currentViewId$.value; + if (!id) { + return; + } + view.manager.viewChangeType(id, meta.type); dataViewInstance.clearSelection(); }, class: {}, diff --git a/blocksuite/affine/data-view/src/widget-presets/views-bar/views-view.ts b/blocksuite/affine/data-view/src/widget-presets/views-bar/views-view.ts index dbcf8a1fbb0eb..b92e690bd24be 100644 --- a/blocksuite/affine/data-view/src/widget-presets/views-bar/views-view.ts +++ b/blocksuite/affine/data-view/src/widget-presets/views-bar/views-view.ts @@ -148,7 +148,11 @@ export class DataViewHeaderViews extends WidgetBase { } const views = this.viewManager.views$.value; const index = views.findIndex(v => v === id); - const view = this.viewManager.viewGet(views[index]); + const viewId = views[index]; + if (!viewId) { + return; + } + const view = this.viewManager.viewGet(viewId); if (!view) { return; } diff --git a/blocksuite/affine/data-view/tsconfig.json b/blocksuite/affine/data-view/tsconfig.json index fb83679c1d49c..d290cc280679f 100644 --- a/blocksuite/affine/data-view/tsconfig.json +++ b/blocksuite/affine/data-view/tsconfig.json @@ -3,7 +3,8 @@ "compilerOptions": { "rootDir": "./src/", "outDir": "./dist/", - "noEmit": false + "noEmit": false, + "noUncheckedIndexedAccess": true }, "include": ["./src"], "references": [ diff --git a/packages/common/env/src/ua-helper.ts b/packages/common/env/src/ua-helper.ts index f1149f00beb44..1e458bacc6abf 100644 --- a/packages/common/env/src/ua-helper.ts +++ b/packages/common/env/src/ua-helper.ts @@ -19,7 +19,7 @@ export class UaHelper { console.error('Cannot get chrome version'); return 0; } - return parseInt(raw[2], 10); + return parseInt(raw[2] ?? '', 10); }; constructor(private readonly navigator: Navigator) { From 7d0160c8fb0c65268d93692646a8fc6f835e1da7 Mon Sep 17 00:00:00 2001 From: pengx17 Date: Thu, 26 Dec 2024 15:37:56 +0000 Subject: [PATCH 04/11] feat(electron): enable vscode debugger for electron (#9333) --- packages/frontend/apps/electron/scripts/dev.ts | 7 ++++++- .../apps/electron/src/main/windows-manager/onboarding.ts | 5 +++++ .../core/src/modules/desktop-api/service/desktop-api.ts | 7 ++++++- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/packages/frontend/apps/electron/scripts/dev.ts b/packages/frontend/apps/electron/scripts/dev.ts index 718f22413579c..b1e6be6c7296e 100644 --- a/packages/frontend/apps/electron/scripts/dev.ts +++ b/packages/frontend/apps/electron/scripts/dev.ts @@ -34,7 +34,12 @@ function spawnOrReloadElectron() { const ext = process.platform === 'win32' ? '.cmd' : ''; const exe = resolve(rootDir, 'node_modules', '.bin', `electron${ext}`); - delete process.env['NODE_OPTIONS']; + // remove import loader option + const NODE_OPTIONS = process.env.NODE_OPTIONS; + if (NODE_OPTIONS) { + process.env.NODE_OPTIONS = NODE_OPTIONS.replace(/--import=[^\s]*/, ''); + } + spawnProcess = spawn(exe, ['.'], { cwd: electronDir, env: process.env, diff --git a/packages/frontend/apps/electron/src/main/windows-manager/onboarding.ts b/packages/frontend/apps/electron/src/main/windows-manager/onboarding.ts index 206562cbd9be8..d340c17a39dd8 100644 --- a/packages/frontend/apps/electron/src/main/windows-manager/onboarding.ts +++ b/packages/frontend/apps/electron/src/main/windows-manager/onboarding.ts @@ -4,6 +4,7 @@ import type { Display } from 'electron'; import { BrowserWindow, screen } from 'electron'; import { isMacOS } from '../../shared/utils'; +import { isDev } from '../config'; import { onboardingViewUrl } from '../constants'; // import { getExposedMeta } from './exposed'; import { logger } from '../logger'; @@ -90,6 +91,10 @@ async function createOnboardingWindow(additionalArguments: string[]) { fullscreenAndCenter(browserWindow); }); + if (isDev) { + browserWindow.webContents.openDevTools(); + } + await browserWindow.loadURL(onboardingViewUrl); return browserWindow; diff --git a/packages/frontend/core/src/modules/desktop-api/service/desktop-api.ts b/packages/frontend/core/src/modules/desktop-api/service/desktop-api.ts index 9f2beb7783193..4020872aaef0d 100644 --- a/packages/frontend/core/src/modules/desktop-api/service/desktop-api.ts +++ b/packages/frontend/core/src/modules/desktop-api/service/desktop-api.ts @@ -88,6 +88,10 @@ export class DesktopApiService extends Service { } private setupCommonUIEvents() { + if (this.api.appInfo.windowName !== 'main') { + return; + } + const handleMaximized = (maximized: boolean | undefined) => { document.documentElement.dataset.maximized = String(maximized); }; @@ -102,12 +106,13 @@ export class DesktopApiService extends Service { .isFullScreen() .then(handleFullscreen) .catch(console.error); + this.api.events.ui.onMaximized(handleMaximized); this.api.events.ui.onFullScreen(handleFullscreen); const tabId = this.api.appInfo.viewId; - if (tabId && this.api.appInfo.windowName === 'main') { + if (tabId) { let isActive = false; const handleActiveTabChange = (active: boolean) => { isActive = active; From d66bec3b917bfd5726fa8f778a461de21fdf2946 Mon Sep 17 00:00:00 2001 From: renovate <29139614+renovate@users.noreply.github.com> Date: Fri, 27 Dec 2024 02:24:50 +0000 Subject: [PATCH 05/11] chore: bump up happy-dom version to v16 (#9358) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Change | Age | Adoption | Passing | Confidence | |---|---|---|---|---|---| | [happy-dom](https://redirect.github.com/capricorn86/happy-dom) | [`^15.11.7` -> `^16.0.0`](https://renovatebot.com/diffs/npm/happy-dom/15.11.7/16.0.0) | [![age](https://developer.mend.io/api/mc/badges/age/npm/happy-dom/16.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/happy-dom/16.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/happy-dom/15.11.7/16.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/happy-dom/15.11.7/16.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | --- ### Release Notes
capricorn86/happy-dom (happy-dom) ### [`v16.0.0`](https://redirect.github.com/capricorn86/happy-dom/releases/tag/v16.0.0) [Compare Source](https://redirect.github.com/capricorn86/happy-dom/compare/v15.11.7...v16.0.0) ##### :bomb: Breaking Changes - Refactors XML and HTML parsing and serialization - By **[@​capricorn86](https://redirect.github.com/capricorn86)** in task [#​1615](https://redirect.github.com/capricorn86/happy-dom/issues/1615) - This change may break your tests as the serialized output may differ from v15 ##### :art: Features - Adds support for parsing XML in `DOMParser` - By **[@​capricorn86](https://redirect.github.com/capricorn86)** in task [#​284](https://redirect.github.com/capricorn86/happy-dom/issues/284) ##### :construction_worker_man: Patch fixes - Fix for handling ``, `` and `` during parsing - By **[@​capricorn86](https://redirect.github.com/capricorn86)** in task [#​1615](https://redirect.github.com/capricorn86/happy-dom/issues/1615) - Fix for handling HTML entities correctly when parsing and serializing - By **[@​capricorn86](https://redirect.github.com/capricorn86)** in task [#​1494](https://redirect.github.com/capricorn86/happy-dom/issues/1494) and [#​1498](https://redirect.github.com/capricorn86/happy-dom/issues/1498) - Fix for handling attribute names containing "\[" or "]" - By **[@​capricorn86](https://redirect.github.com/capricorn86)** in task [#​1638](https://redirect.github.com/capricorn86/happy-dom/issues/1638) - Fix for handling comments containing HTML tags - By **[@​capricorn86](https://redirect.github.com/capricorn86)** in task [#​1630](https://redirect.github.com/capricorn86/happy-dom/issues/1630) - Handles rules for parsing table elements - By **[@​capricorn86](https://redirect.github.com/capricorn86)** in task [#​1126](https://redirect.github.com/capricorn86/happy-dom/issues/1126) - Loads scripts asynchronously when "defer" is set or "type" is "module" - By **[@​capricorn86](https://redirect.github.com/capricorn86)** in task [#​1615](https://redirect.github.com/capricorn86/happy-dom/issues/1615)
--- ### Configuration 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/toeverything/AFFiNE). --- package.json | 2 +- yarn.lock | 11 +++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index deb61ffbc2beb..13d2af7cfd501 100644 --- a/package.json +++ b/package.json @@ -78,7 +78,7 @@ "eslint-plugin-simple-import-sort": "^12.1.1", "eslint-plugin-sonarjs": "^3.0.1", "eslint-plugin-unicorn": "^56.0.1", - "happy-dom": "^15.11.7", + "happy-dom": "^16.0.0", "husky": "^9.1.7", "lint-staged": "^15.2.11", "msw": "^2.6.8", diff --git a/yarn.lock b/yarn.lock index 16d9dadbfb5ec..f6f0863a23a8e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -666,7 +666,7 @@ __metadata: eslint-plugin-simple-import-sort: "npm:^12.1.1" eslint-plugin-sonarjs: "npm:^3.0.1" eslint-plugin-unicorn: "npm:^56.0.1" - happy-dom: "npm:^15.11.7" + happy-dom: "npm:^16.0.0" husky: "npm:^9.1.7" lint-staged: "npm:^15.2.11" msw: "npm:^2.6.8" @@ -22523,14 +22523,13 @@ __metadata: languageName: node linkType: hard -"happy-dom@npm:^15.11.7": - version: 15.11.7 - resolution: "happy-dom@npm:15.11.7" +"happy-dom@npm:^16.0.0": + version: 16.0.0 + resolution: "happy-dom@npm:16.0.0" dependencies: - entities: "npm:^4.5.0" webidl-conversions: "npm:^7.0.0" whatwg-mimetype: "npm:^3.0.0" - checksum: 10/82fb8505a940ebc2b732d1c70ae4ba08128cc82f2d469702f73e541d3bf10fc69b726386f8aaf579ccd2697f85e86dee87aa9d4f229b781fb05628d733fc93d7 + checksum: 10/4ab8acdc19bf01c510ae4e8186195426fa75eb3eb23b01288a392dc127a530d89fcf839d5341da75a1193ecf7f79bf8d28603f77b6277cb992c2bb06bd76be81 languageName: node linkType: hard From 20c5c28a95c0a68198fdabf70a11d45414a1f3dd Mon Sep 17 00:00:00 2001 From: fundon Date: Fri, 27 Dec 2024 02:57:21 +0000 Subject: [PATCH 06/11] fix(core): circular dependency in pdf embed view (#9331) --- .../components/attachment-viewer/index.tsx | 8 ++----- .../pdf-viewer-embedded-inner.tsx | 6 ++--- .../attachment-viewer/pdf-viewer-embedded.tsx | 23 +++++++++---------- .../attachment-viewer/pdf-viewer.tsx | 9 +------- .../src/components/attachment-viewer/types.ts | 12 ++++++++++ .../src/components/attachment-viewer/utils.ts | 2 +- .../specs/custom/spec-patchers.tsx | 11 ++------- 7 files changed, 31 insertions(+), 40 deletions(-) create mode 100644 packages/frontend/core/src/components/attachment-viewer/types.ts diff --git a/packages/frontend/core/src/components/attachment-viewer/index.tsx b/packages/frontend/core/src/components/attachment-viewer/index.tsx index 3ed74e0f91181..d36e81344aaba 100644 --- a/packages/frontend/core/src/components/attachment-viewer/index.tsx +++ b/packages/frontend/core/src/components/attachment-viewer/index.tsx @@ -1,16 +1,12 @@ import { ViewBody, ViewHeader } from '@affine/core/modules/workbench'; -import type { AttachmentBlockModel } from '@blocksuite/affine/blocks'; import { AttachmentPreviewErrorBoundary, Error } from './error'; -import { PDFViewer, type PDFViewerProps } from './pdf-viewer'; +import { PDFViewer } from './pdf-viewer'; import * as styles from './styles.css'; import { Titlebar } from './titlebar'; +import type { AttachmentViewerProps, PDFViewerProps } from './types'; import { buildAttachmentProps } from './utils'; -export type AttachmentViewerProps = { - model: AttachmentBlockModel; -}; - // In Peek view export const AttachmentViewer = ({ model }: AttachmentViewerProps) => { const props = buildAttachmentProps(model); diff --git a/packages/frontend/core/src/components/attachment-viewer/pdf-viewer-embedded-inner.tsx b/packages/frontend/core/src/components/attachment-viewer/pdf-viewer-embedded-inner.tsx index 660b13dcb39db..026431e7a439b 100644 --- a/packages/frontend/core/src/components/attachment-viewer/pdf-viewer-embedded-inner.tsx +++ b/packages/frontend/core/src/components/attachment-viewer/pdf-viewer-embedded-inner.tsx @@ -28,9 +28,9 @@ import { useState, } from 'react'; -import type { PDFViewerProps } from './pdf-viewer'; import * as styles from './styles.css'; import * as embeddedStyles from './styles.embedded.css'; +import type { PDFViewerProps } from './types'; function defaultMeta() { return { @@ -40,9 +40,7 @@ function defaultMeta() { }; } -type PDFViewerEmbeddedInnerProps = PDFViewerProps; - -export function PDFViewerEmbeddedInner({ model }: PDFViewerEmbeddedInnerProps) { +export function PDFViewerEmbeddedInner({ model }: PDFViewerProps) { const scale = window.devicePixelRatio; const peekView = useService(PeekViewService).peekView; const pdfService = useService(PDFService); diff --git a/packages/frontend/core/src/components/attachment-viewer/pdf-viewer-embedded.tsx b/packages/frontend/core/src/components/attachment-viewer/pdf-viewer-embedded.tsx index a0846beb36536..302870db72fa3 100644 --- a/packages/frontend/core/src/components/attachment-viewer/pdf-viewer-embedded.tsx +++ b/packages/frontend/core/src/components/attachment-viewer/pdf-viewer-embedded.tsx @@ -1,14 +1,13 @@ -import type { AttachmentBlockModel } from '@blocksuite/affine/blocks'; - +import { AttachmentPreviewErrorBoundary } from './error'; import { PDFViewerEmbeddedInner } from './pdf-viewer-embedded-inner'; +import type { AttachmentViewerProps } from './types'; +import { buildAttachmentProps } from './utils'; -export interface PDFViewerEmbeddedProps { - model: AttachmentBlockModel; - name: string; - ext: string; - size: string; -} - -export function PDFViewerEmbedded(props: PDFViewerEmbeddedProps) { - return ; -} +// In Embed view +export const AttachmentEmbedPreview = ({ model }: AttachmentViewerProps) => { + return ( + + + + ); +}; diff --git a/packages/frontend/core/src/components/attachment-viewer/pdf-viewer.tsx b/packages/frontend/core/src/components/attachment-viewer/pdf-viewer.tsx index 49c4c30cef3a7..27b397c19a54a 100644 --- a/packages/frontend/core/src/components/attachment-viewer/pdf-viewer.tsx +++ b/packages/frontend/core/src/components/attachment-viewer/pdf-viewer.tsx @@ -1,11 +1,11 @@ import { type PDF, PDFService, PDFStatus } from '@affine/core/modules/pdf'; import { LoadingSvg } from '@affine/core/modules/pdf/views'; import track from '@affine/track'; -import type { AttachmentBlockModel } from '@blocksuite/affine/blocks'; import { useLiveData, useService } from '@toeverything/infra'; import { useEffect, useState } from 'react'; import { PDFViewerInner } from './pdf-viewer-inner'; +import type { PDFViewerProps } from './types'; function PDFViewerStatus({ pdf, ...props }: PDFViewerProps & { pdf: PDF }) { const state = useLiveData(pdf.state$); @@ -23,13 +23,6 @@ function PDFViewerStatus({ pdf, ...props }: PDFViewerProps & { pdf: PDF }) { return ; } -export interface PDFViewerProps { - model: AttachmentBlockModel; - name: string; - ext: string; - size: string; -} - export function PDFViewer({ model, ...props }: PDFViewerProps) { const pdfService = useService(PDFService); const [pdf, setPdf] = useState(null); diff --git a/packages/frontend/core/src/components/attachment-viewer/types.ts b/packages/frontend/core/src/components/attachment-viewer/types.ts new file mode 100644 index 0000000000000..956417afc99b1 --- /dev/null +++ b/packages/frontend/core/src/components/attachment-viewer/types.ts @@ -0,0 +1,12 @@ +import type { AttachmentBlockModel } from '@blocksuite/affine/blocks'; + +export type AttachmentViewerProps = { + model: AttachmentBlockModel; +}; + +export type PDFViewerProps = { + model: AttachmentBlockModel; + name: string; + ext: string; + size: string; +}; diff --git a/packages/frontend/core/src/components/attachment-viewer/utils.ts b/packages/frontend/core/src/components/attachment-viewer/utils.ts index 445dbf2ece5c6..f241e05b014f9 100644 --- a/packages/frontend/core/src/components/attachment-viewer/utils.ts +++ b/packages/frontend/core/src/components/attachment-viewer/utils.ts @@ -3,7 +3,7 @@ import type { AttachmentBlockModel } from '@blocksuite/affine/blocks'; import { filesize } from 'filesize'; import { downloadBlob } from '../../utils/resource'; -import type { PDFViewerProps } from './pdf-viewer'; +import type { PDFViewerProps } from './types'; export async function getAttachmentBlob(model: AttachmentBlockModel) { const sourceId = model.sourceId; diff --git a/packages/frontend/core/src/components/blocksuite/block-suite-editor/specs/custom/spec-patchers.tsx b/packages/frontend/core/src/components/blocksuite/block-suite-editor/specs/custom/spec-patchers.tsx index e958ec08eb7c5..961a297b25061 100644 --- a/packages/frontend/core/src/components/blocksuite/block-suite-editor/specs/custom/spec-patchers.tsx +++ b/packages/frontend/core/src/components/blocksuite/block-suite-editor/specs/custom/spec-patchers.tsx @@ -8,9 +8,6 @@ import { type useConfirmModal, } from '@affine/component'; import { AIChatBlockSchema } from '@affine/core/blocksuite/blocks'; -import { AttachmentPreviewErrorBoundary } from '@affine/core/components/attachment-viewer/error'; -import { PDFViewerEmbedded } from '@affine/core/components/attachment-viewer/pdf-viewer-embedded'; -import { buildAttachmentProps } from '@affine/core/components/attachment-viewer/utils'; import { WorkspaceServerService } from '@affine/core/modules/cloud'; import { type DocService, DocsService } from '@affine/core/modules/doc'; import type { EditorService } from '@affine/core/modules/editor'; @@ -74,6 +71,7 @@ import { literal } from 'lit/static-html.js'; import { pick } from 'lodash-es'; import type { DocProps } from '../../../../../blocksuite/initialization'; +import { AttachmentEmbedPreview } from '../../../../attachment-viewer/pdf-viewer-embedded'; import { generateUrl } from '../../../../hooks/affine/use-share-url'; import { createKeyboardToolbarConfig } from './widgets/keyboard-toolbar'; @@ -624,12 +622,7 @@ export function patchForAttachmentEmbedViews( }); }, template: (model, _blobUrl) => - reactToLit( - - - , - false - ), + reactToLit(, false), })); }, }; From 5eb48343a3f938957fdcaa38bea06cbfffa7b185 Mon Sep 17 00:00:00 2001 From: Saul-Mirone Date: Fri, 27 Dec 2024 03:13:23 +0000 Subject: [PATCH 07/11] chore(editor): cleanup dead code (#9359) --- .../edgeless/clipboard/clipboard.ts | 37 ---------------- .../rects/edgeless-selected-rect.ts | 44 ++++++++++++++----- .../root-block/edgeless/edgeless-keyboard.ts | 43 ------------------ .../edgeless/edgeless-root-block.ts | 19 +------- .../edgeless/edgeless-root-service.ts | 6 --- .../drag-handle/watchers/edgeless-watcher.ts | 6 --- 6 files changed, 35 insertions(+), 120 deletions(-) diff --git a/blocksuite/blocks/src/root-block/edgeless/clipboard/clipboard.ts b/blocksuite/blocks/src/root-block/edgeless/clipboard/clipboard.ts index ed06f9c759c30..781eebe5e1e11 100644 --- a/blocksuite/blocks/src/root-block/edgeless/clipboard/clipboard.ts +++ b/blocksuite/blocks/src/root-block/edgeless/clipboard/clipboard.ts @@ -87,7 +87,6 @@ import { } from '../utils/query.js'; const BLOCKSUITE_SURFACE = 'blocksuite/surface'; -const IMAGE_PNG = 'image/png'; const { GROUP, MINDMAP, CONNECTOR } = CanvasElementType; const IMAGE_PADDING = 5; // for rotated shapes some padding is needed @@ -1200,42 +1199,6 @@ export class EdgelessClipboardController extends PageClipboard { ); } - async copyAsPng( - blocks: BlockSuite.EdgelessBlockModelType[], - shapes: BlockSuite.SurfaceModel[] - ) { - const blocksLen = blocks.length; - const shapesLen = shapes.length; - - if (blocksLen + shapesLen === 0) return; - const canvas = await this.toCanvas(blocks, shapes); - assertExists(canvas); - // @ts-expect-error FIXME: ts error - if (window.apis?.clipboard?.copyAsImageFromString) { - // @ts-expect-error FIXME: ts error - await window.apis.clipboard?.copyAsImageFromString( - canvas.toDataURL(IMAGE_PNG) - ); - } else { - const blob: Blob = await new Promise((resolve, reject) => - canvas.toBlob( - blob => (blob ? resolve(blob) : reject('Canvas can not export blob')), - IMAGE_PNG - ) - ); - assertExists(blob); - - this.std.clipboard - .writeToClipboard(_items => { - return { - ..._items, - [IMAGE_PNG]: blob, - }; - }) - .catch(console.error); - } - } - async createElementsFromClipboardData( elementsRawData: (SerializedElement | BlockSnapshot)[], pasteCenter?: IVec diff --git a/blocksuite/blocks/src/root-block/edgeless/components/rects/edgeless-selected-rect.ts b/blocksuite/blocks/src/root-block/edgeless/components/rects/edgeless-selected-rect.ts index abf8e2b955945..889482c38a098 100644 --- a/blocksuite/blocks/src/root-block/edgeless/components/rects/edgeless-selected-rect.ts +++ b/blocksuite/blocks/src/root-block/edgeless/components/rects/edgeless-selected-rect.ts @@ -1312,7 +1312,7 @@ export class EdgelessSelectedRectWidget extends WidgetComponent< } override firstUpdated() { - const { _disposables, edgelessSlots, block, selection, gfx } = this; + const { _disposables, block, selection, gfx } = this; _disposables.add( // viewport zooming / scrolling @@ -1331,15 +1331,6 @@ export class EdgelessSelectedRectWidget extends WidgetComponent< this.doc.slots.blockUpdated.on(this._updateOnElementChange) ); - _disposables.add( - edgelessSlots.pressShiftKeyUpdated.on(pressed => { - this._shiftKey = pressed; - this._resizeManager.onPressShiftKey(pressed); - this._updateSelectedRect(); - this._updateMode(); - }) - ); - _disposables.add(selection.slots.updated.on(this._updateOnSelectionChange)); _disposables.add( @@ -1355,6 +1346,39 @@ export class EdgelessSelectedRectWidget extends WidgetComponent< _disposables.add(() => { this._propDisposables.forEach(disposable => disposable.dispose()); }); + + this.block.handleEvent( + 'keyDown', + ctx => { + const event = ctx.get('defaultState').event; + if (event instanceof KeyboardEvent) { + this._shift(event); + } + }, + { global: true } + ); + + this.block.handleEvent( + 'keyUp', + ctx => { + const event = ctx.get('defaultState').event; + if (event instanceof KeyboardEvent) { + this._shift(event); + } + }, + { global: true } + ); + } + + private _shift(event: KeyboardEvent) { + if (event.repeat) return; + + const pressed = event.key.toLowerCase() === 'shift' && event.shiftKey; + + this._shiftKey = pressed; + this._resizeManager.onPressShiftKey(pressed); + this._updateSelectedRect(); + this._updateMode(); } override render() { diff --git a/blocksuite/blocks/src/root-block/edgeless/edgeless-keyboard.ts b/blocksuite/blocks/src/root-block/edgeless/edgeless-keyboard.ts index 5f8fad0ae1f12..3e8750adde8ed 100644 --- a/blocksuite/blocks/src/root-block/edgeless/edgeless-keyboard.ts +++ b/blocksuite/blocks/src/root-block/edgeless/edgeless-keyboard.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/no-non-null-assertion */ import { ConnectorElementModel, ConnectorMode, @@ -163,7 +162,6 @@ export class EdgelessPageKeyboardManager extends PageKeyboardManager { const std = this.rootComponent.std; if ( std.selection.getGroup('note').length > 0 || - // eslint-disable-next-line std.selection.find('text') || Boolean(std.selection.find('surface')?.editing) ) { @@ -430,35 +428,9 @@ export class EdgelessPageKeyboardManager extends PageKeyboardManager { } ); - this._bindShiftKey(); this._bindToggleHand(); } - private _bindShiftKey() { - this.rootComponent.handleEvent( - 'keyDown', - ctx => { - const event = ctx.get('defaultState').event; - if (event instanceof KeyboardEvent) { - this._shift(event); - } - }, - { global: true } - ); - this.rootComponent.handleEvent( - 'keyUp', - ctx => { - const event = ctx.get('defaultState').event; - if (event instanceof KeyboardEvent) { - this._shift(event); - } - }, - { - global: true, - } - ); - } - private _bindToggleHand() { this.rootComponent.handleEvent( 'keyDown', @@ -685,21 +657,6 @@ export class EdgelessPageKeyboardManager extends PageKeyboardManager { ); } - private _shift(event: KeyboardEvent) { - const edgeless = this.rootComponent; - - if (event.repeat) return; - - const shiftKeyPressed = - event.key.toLowerCase() === 'shift' && event.shiftKey; - - if (shiftKeyPressed) { - edgeless.slots.pressShiftKeyUpdated.emit(true); - } else { - edgeless.slots.pressShiftKeyUpdated.emit(false); - } - } - private _space(event: KeyboardEvent) { /* Call this function with a check for !event.repeat to consider only the first keydown (not repeat). This way, you can use onPressSpaceBar in a tool to determine if the space bar is pressed or not. diff --git a/blocksuite/blocks/src/root-block/edgeless/edgeless-root-block.ts b/blocksuite/blocks/src/root-block/edgeless/edgeless-root-block.ts index f44af80c64eca..5142cf5793d2c 100644 --- a/blocksuite/blocks/src/root-block/edgeless/edgeless-root-block.ts +++ b/blocksuite/blocks/src/root-block/edgeless/edgeless-root-block.ts @@ -3,7 +3,6 @@ import type { SurfaceBlockModel, } from '@blocksuite/affine-block-surface'; import { CommonUtils } from '@blocksuite/affine-block-surface'; -import { toast } from '@blocksuite/affine-components/toast'; import type { RootBlockModel, ShapeElementModel, @@ -320,7 +319,7 @@ export class EdgelessRootBlockComponent extends BlockComponent< } private _initSlotEffects() { - const { disposables, slots } = this; + const { disposables } = this; this.disposables.add( this.std.get(ThemeProvider).theme$.subscribe(() => this.surface.refresh()) @@ -331,22 +330,6 @@ export class EdgelessRootBlockComponent extends BlockComponent< this.style.cursor = this.gfx.cursor$.value; }) ); - - let canCopyAsPng = true; - disposables.add( - slots.copyAsPng.on(({ blocks, shapes }) => { - if (!canCopyAsPng) return; - canCopyAsPng = false; - - this.clipboardController - .copyAsPng(blocks, shapes) - .then(() => toast(this.host, 'Copied to clipboard')) - .catch(() => toast(this.host, 'Failed to copy as PNG')) - .finally(() => { - canCopyAsPng = true; - }); - }) - ); } private _initViewport() { diff --git a/blocksuite/blocks/src/root-block/edgeless/edgeless-root-service.ts b/blocksuite/blocks/src/root-block/edgeless/edgeless-root-service.ts index 42b21d96529dc..bb2e9a4d20737 100644 --- a/blocksuite/blocks/src/root-block/edgeless/edgeless-root-service.ts +++ b/blocksuite/blocks/src/root-block/edgeless/edgeless-root-service.ts @@ -60,13 +60,7 @@ export class EdgelessRootService extends RootService implements SurfaceContext { elementRenderers: Record = elementRenderers; slots = { - pressShiftKeyUpdated: new Slot(), - copyAsPng: new Slot<{ - blocks: BlockSuite.EdgelessBlockModelType[]; - shapes: BlockSuite.SurfaceModel[]; - }>(), readonlyUpdated: new Slot(), - draggingAreaUpdated: new Slot(), navigatorSettingUpdated: new Slot<{ hideToolbar?: boolean; blackBackground?: boolean; diff --git a/blocksuite/blocks/src/root-block/widgets/drag-handle/watchers/edgeless-watcher.ts b/blocksuite/blocks/src/root-block/widgets/drag-handle/watchers/edgeless-watcher.ts index a4fd747e1365d..c871858816ceb 100644 --- a/blocksuite/blocks/src/root-block/widgets/drag-handle/watchers/edgeless-watcher.ts +++ b/blocksuite/blocks/src/root-block/widgets/drag-handle/watchers/edgeless-watcher.ts @@ -243,12 +243,6 @@ export class EdgelessWatcher { }) ); - disposables.add( - edgelessSlots.draggingAreaUpdated.on(() => { - this.checkTopLevelBlockSelection(); - }) - ); - disposables.add( edgelessSlots.elementResizeStart.on(() => { this.widget.hide(); From 706b6140069cf90716c71908153bf5070c88b56d Mon Sep 17 00:00:00 2001 From: Brooooooklyn Date: Fri, 27 Dec 2024 03:30:20 +0000 Subject: [PATCH 08/11] style: add sonarjs/no-gratuitous-expressions rule (#9360) --- .prettierignore | 1 + .../widgets/edgeless-auto-connect/edgeless-auto-connect.ts | 3 +-- blocksuite/tests-legacy/utils/playwright.ts | 6 +++--- eslint.config.mjs | 1 + 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.prettierignore b/.prettierignore index 5d782d85d9471..d883ecd156b9f 100644 --- a/.prettierignore +++ b/.prettierignore @@ -34,3 +34,4 @@ packages/frontend/graphql/src/schema.ts packages/frontend/apps/android/App/app/build/** blocksuite/tests-legacy/snapshots **/.storybook +**/.coverage diff --git a/blocksuite/blocks/src/root-block/widgets/edgeless-auto-connect/edgeless-auto-connect.ts b/blocksuite/blocks/src/root-block/widgets/edgeless-auto-connect/edgeless-auto-connect.ts index 23a666430a6c9..303b6ac01cc43 100644 --- a/blocksuite/blocks/src/root-block/widgets/edgeless-auto-connect/edgeless-auto-connect.ts +++ b/blocksuite/blocks/src/root-block/widgets/edgeless-auto-connect/edgeless-auto-connect.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/no-non-null-assertion */ import { AutoConnectLeftIcon, AutoConnectRightIcon, @@ -48,7 +47,7 @@ function calculatePosition(gap: number, count: number, iconWidth: number) { for (let j = 0; j < count; j++) { let left = 10; if (isEven) { - if (Math.abs(j - middleIndex) < 1 && isEven) { + if (Math.abs(j - middleIndex) < 1) { left = 10 + middleOffset * getSign(j); } else { left = diff --git a/blocksuite/tests-legacy/utils/playwright.ts b/blocksuite/tests-legacy/utils/playwright.ts index bd7f2f4cf4454..9355ed6900749 100644 --- a/blocksuite/tests-legacy/utils/playwright.ts +++ b/blocksuite/tests-legacy/utils/playwright.ts @@ -61,7 +61,7 @@ export const test = baseTest.extend<{}>({ }); if (scope) { test.beforeEach(async ({ browser }, testInfo) => { - if (scope && !testInfo.title.startsWith(scope)) { + if (!testInfo.title.startsWith(scope!)) { testInfo.fn = () => { testInfo.skip(); }; @@ -76,9 +76,9 @@ if (scope) { page = await browser.newPage(); }); - // eslint-disable-next-line no-empty-pattern + // oxlint-disable-next-line no-empty-pattern test.afterAll(async ({}, testInfo) => { - if (!scope || !testInfo.title.startsWith(scope)) { + if (!testInfo.title.startsWith(scope!)) { return; } const focusInSecondEditor = await page.evaluate( diff --git a/eslint.config.mjs b/eslint.config.mjs index 47b14599f25cf..f456783944f8d 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -192,6 +192,7 @@ export default tseslint.config( 'sonarjs/no-duplicated-branches': 'error', 'sonarjs/no-collection-size-mischeck': 'error', 'sonarjs/no-identical-functions': 'error', + 'sonarjs/no-gratuitous-expressions': 'error', 'simple-import-sort/imports': 'error', 'simple-import-sort/exports': 'error', From f336d688665273af295048af73333d574e3f4cc5 Mon Sep 17 00:00:00 2001 From: devin-ai-integration <158243242+devin-ai-integration@users.noreply.github.com> Date: Fri, 27 Dec 2024 03:45:52 +0000 Subject: [PATCH 09/11] ci: add graphite ci optimizer and update job dependencies (#9362) feat(ci): add graphite ci optimizer and update job dependencies This PR adds the Graphite CI optimizer to improve CI efficiency by skipping unnecessary jobs. All workflow jobs have been updated to depend on the optimizer's output. Changes: - Add `optimize_ci` job using graphite-ci-action - Update all jobs to depend on `optimize_ci` - Add skip conditions based on optimizer output - Preserve existing job dependencies while adding optimizer dependency - Handle Redis service configurations and command syntax updates Note: This PR requires the `GRAPHITE_CI_OPTIMIZER_TOKEN` secret to be configured in the repository settings before the optimizer can be used. Testing: - [x] Verified workflow file syntax - [x] Updated all job dependencies correctly - [x] Maintained existing job configurations Link to Devin run: https://app.devin.ai/sessions/3872f4dc4c3341b899646a90c46c4fe3 --- .github/workflows/build-test.yml | 52 +++++++++++++++++++++++++++----- 1 file changed, 45 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index 0674eb48548b4..4d87525047c94 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -27,9 +27,24 @@ concurrency: cancel-in-progress: true jobs: + optimize_ci: + name: Optimize CI + runs-on: ubuntu-latest + outputs: + skip: ${{ steps.graphite.outputs.skip }} + steps: + - uses: actions/checkout@v4 + - name: Graphite CI Optimizer + uses: withgraphite/graphite-ci-action@main + id: graphite + with: + token: ${{ secrets.GRAPHITE_CI_OPTIMIZER_TOKEN }} + analyze: name: Analyze runs-on: ubuntu-latest + needs: optimize_ci + if: needs.optimize_ci.outputs.skip == 'false' permissions: actions: read contents: read @@ -77,6 +92,8 @@ jobs: lint: name: Lint runs-on: ubuntu-latest + needs: optimize_ci + if: needs.optimize_ci.outputs.skip == 'false' steps: - uses: actions/checkout@v4 @@ -105,6 +122,8 @@ jobs: check-yarn-binary: name: Check yarn binary runs-on: ubuntu-latest + needs: optimize_ci + if: needs.optimize_ci.outputs.skip == 'false' steps: - uses: actions/checkout@v4 - name: Run check @@ -115,6 +134,8 @@ jobs: e2e-legacy-blocksuite-test: name: Legacy Blocksuite E2E Test runs-on: ubuntu-latest + needs: optimize_ci + if: needs.optimize_ci.outputs.skip == 'false' strategy: fail-fast: false matrix: @@ -145,6 +166,8 @@ jobs: e2e-test: name: E2E Test runs-on: ubuntu-latest + needs: optimize_ci + if: needs.optimize_ci.outputs.skip == 'false' env: DISTRIBUTION: web IN_CI_TEST: true @@ -175,6 +198,8 @@ jobs: e2e-mobile-test: name: E2E Mobile Test runs-on: ubuntu-latest + needs: optimize_ci + if: needs.optimize_ci.outputs.skip == 'false' env: DISTRIBUTION: mobile IN_CI_TEST: true @@ -206,7 +231,9 @@ jobs: name: Unit Test runs-on: ubuntu-latest needs: + - optimize_ci - build-native + if: needs.optimize_ci.outputs.skip == 'false' env: DISTRIBUTION: web strategy: @@ -243,6 +270,8 @@ jobs: build-native: name: Build AFFiNE native (${{ matrix.spec.target }}) runs-on: ${{ matrix.spec.os }} + needs: optimize_ci + if: needs.optimize_ci.outputs.skip == 'false' env: CARGO_PROFILE_RELEASE_DEBUG: '1' strategy: @@ -330,7 +359,10 @@ jobs: server-test: name: Server Test runs-on: ubuntu-latest - needs: build-server-native + needs: + - optimize_ci + - build-server-native + if: needs.optimize_ci.outputs.skip == 'false' env: NODE_ENV: test DISTRIBUTION: web @@ -410,7 +442,9 @@ jobs: name: Server Copilot Api Test runs-on: ubuntu-latest needs: + - optimize_ci - build-server-native + if: needs.optimize_ci.outputs.skip == 'false' env: NODE_ENV: test DISTRIBUTION: web @@ -576,6 +610,11 @@ jobs: server-e2e-test: name: ${{ matrix.tests.name }} runs-on: ubuntu-latest + needs: + - optimize_ci + - build-server-native + - build-native + if: needs.optimize_ci.outputs.skip == 'false' env: DISTRIBUTION: web DATABASE_URL: postgresql://affine:affine@localhost:5432/affine @@ -599,9 +638,6 @@ jobs: # Reference: https://github.com/electron/electron/issues/42510 sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0 xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- yarn affine @affine-test/affine-desktop-cloud e2e - needs: - - build-server-native - - build-native services: postgres: image: postgres @@ -666,6 +702,11 @@ jobs: desktop-test: name: Desktop Test (${{ matrix.spec.os }}, ${{ matrix.spec.platform }}, ${{ matrix.spec.arch }}, ${{ matrix.spec.target }}, ${{ matrix.spec.test }}) runs-on: ${{ matrix.spec.os }} + needs: + - optimize_ci + - build-electron-renderer + - build-native + if: needs.optimize_ci.outputs.skip == 'false' strategy: fail-fast: false matrix: @@ -698,9 +739,6 @@ jobs: target: x86_64-pc-windows-msvc, test: true, } - needs: - - build-electron-renderer - - build-native steps: - uses: actions/checkout@v4 - name: Setup Node.js From 71272203b0b36d157aa5e4c083cc6d07cfdaceb5 Mon Sep 17 00:00:00 2001 From: doouding Date: Fri, 27 Dec 2024 04:02:57 +0000 Subject: [PATCH 10/11] fix: beginPath before drawing drag indicator (#9364) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes [BS-2238](https://linear.app/affine-design/issue/BS-2238/frame-套一个-mindmap-,拖动行为不可用) --- .../gfx-tool/default-tool-ext/mind-map-ext/indicator-overlay.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/blocksuite/blocks/src/root-block/edgeless/gfx-tool/default-tool-ext/mind-map-ext/indicator-overlay.ts b/blocksuite/blocks/src/root-block/edgeless/gfx-tool/default-tool-ext/mind-map-ext/indicator-overlay.ts index 6835308381852..53632b342952b 100644 --- a/blocksuite/blocks/src/root-block/edgeless/gfx-tool/default-tool-ext/mind-map-ext/indicator-overlay.ts +++ b/blocksuite/blocks/src/root-block/edgeless/gfx-tool/default-tool-ext/mind-map-ext/indicator-overlay.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/no-non-null-assertion */ import { NODE_HORIZONTAL_SPACING, NODE_VERTICAL_SPACING, @@ -191,6 +190,7 @@ export class MindMapIndicatorOverlay extends Overlay { ctx.fillStyle = color; ctx.lineWidth = 3; + ctx.beginPath(); ctx.roundRect(targetPos.x, targetPos.y, targetPos.w, targetPos.h, 4); ctx.fill(); From 3ae3ae98c89a6abd145e7f47c73428a8e1d69f71 Mon Sep 17 00:00:00 2001 From: Saul-Mirone Date: Fri, 27 Dec 2024 04:22:52 +0000 Subject: [PATCH 11/11] refactor(editor): extract edgeless legacy slots (#9363) --- .../affine/block-attachment/package.json | 1 + .../src/attachment-edgeless-block.ts | 20 +++----- .../affine/block-attachment/tsconfig.json | 3 ++ .../src/common/insert-embed-card.ts | 8 +-- .../src/common/to-edgeless-embed-block.ts | 12 +++-- blocksuite/affine/block-embed/src/effects.ts | 4 ++ blocksuite/affine/block-embed/tsconfig.json | 3 ++ blocksuite/affine/block-latex/src/index.ts | 2 +- blocksuite/affine/block-note/package.json | 1 + .../block-note/src/note-edgeless-block.ts | 21 ++++---- blocksuite/affine/block-note/tsconfig.json | 3 ++ .../block-surface/src/extensions/index.ts | 1 + .../src/extensions/legacy-slot-extension.ts | 40 +++++++++++++++ .../affine/block-surface/src/surface-spec.ts | 14 ++++-- .../block-surface/src/utils/rough/core.ts | 4 +- .../edgeless/edgeless-root-block.ts | 7 ++- .../edgeless/edgeless-root-service.ts | 24 ++------- .../drag-handle/watchers/edgeless-watcher.ts | 50 +++++++++---------- .../edgeless-auto-connect.ts | 22 ++++---- .../widgets/edgeless-zoom-toolbar/index.ts | 7 ++- .../frame-panel/header/frame-panel-header.ts | 11 ++-- .../frame-panel/header/frames-setting-menu.ts | 18 +++++-- tools/utils/src/workspace.gen.ts | 2 + yarn.lock | 2 + 24 files changed, 167 insertions(+), 113 deletions(-) create mode 100644 blocksuite/affine/block-surface/src/extensions/legacy-slot-extension.ts diff --git a/blocksuite/affine/block-attachment/package.json b/blocksuite/affine/block-attachment/package.json index 227341f6219b9..a4a3a4271187f 100644 --- a/blocksuite/affine/block-attachment/package.json +++ b/blocksuite/affine/block-attachment/package.json @@ -14,6 +14,7 @@ "license": "MIT", "dependencies": { "@blocksuite/affine-block-embed": "workspace:*", + "@blocksuite/affine-block-surface": "workspace:*", "@blocksuite/affine-components": "workspace:*", "@blocksuite/affine-model": "workspace:*", "@blocksuite/affine-shared": "workspace:*", diff --git a/blocksuite/affine/block-attachment/src/attachment-edgeless-block.ts b/blocksuite/affine/block-attachment/src/attachment-edgeless-block.ts index 72614b2deaa65..0ad0736d0cea2 100644 --- a/blocksuite/affine/block-attachment/src/attachment-edgeless-block.ts +++ b/blocksuite/affine/block-attachment/src/attachment-edgeless-block.ts @@ -1,11 +1,11 @@ +import { EdgelessLegacySlotIdentifier } from '@blocksuite/affine-block-surface'; import type { HoverController } from '@blocksuite/affine-components/hover'; import { AttachmentBlockStyles } from '@blocksuite/affine-model'; import { EMBED_CARD_HEIGHT, EMBED_CARD_WIDTH, } from '@blocksuite/affine-shared/consts'; -import { type BlockService, toGfxBlockComponent } from '@blocksuite/block-std'; -import type { Slot } from '@blocksuite/store'; +import { toGfxBlockComponent } from '@blocksuite/block-std'; import { styleMap } from 'lit/directives/style-map.js'; import { AttachmentBlockComponent } from './attachment-block.js'; @@ -17,30 +17,22 @@ export class AttachmentEdgelessBlockComponent extends toGfxBlockComponent( override blockDraggable = false; - get rootService(): null | (BlockService & { slots: Record }) { - return this.std.getService('affine:page'); + get slots() { + return this.std.get(EdgelessLegacySlotIdentifier); } override connectedCallback(): void { super.connectedCallback(); - const rootService = this.rootService; - if (!rootService) { - console.warn('rootService is not found'); - return; - } - - // TODO: move root service slots to extension this._disposables.add( - rootService.slots.elementResizeStart.on(() => { + this.slots.elementResizeStart.on(() => { this._isResizing = true; this._showOverlay = true; }) ); - // TODO: move root service slots to extension this._disposables.add( - rootService.slots.elementResizeEnd.on(() => { + this.slots.elementResizeEnd.on(() => { this._isResizing = false; this._showOverlay = this._isResizing || this._isDragging || !this._isSelected; diff --git a/blocksuite/affine/block-attachment/tsconfig.json b/blocksuite/affine/block-attachment/tsconfig.json index 54b5d3348b995..622857f8c4770 100644 --- a/blocksuite/affine/block-attachment/tsconfig.json +++ b/blocksuite/affine/block-attachment/tsconfig.json @@ -30,6 +30,9 @@ }, { "path": "../block-embed" + }, + { + "path": "../block-surface" } ] } diff --git a/blocksuite/affine/block-embed/src/common/insert-embed-card.ts b/blocksuite/affine/block-embed/src/common/insert-embed-card.ts index 6dfcf2f93a69e..c3b5397445daf 100644 --- a/blocksuite/affine/block-embed/src/common/insert-embed-card.ts +++ b/blocksuite/affine/block-embed/src/common/insert-embed-card.ts @@ -76,9 +76,9 @@ export function insertEmbedCard( editing: false, }); - // @ts-expect-error TODO: fix after edgeless refactor - edgelessRoot.tools.setEdgelessTool({ - type: 'default', - }); + gfx.tool.setTool( + // @ts-expect-error FIXME: resolve after gfx tool refactor + 'default' + ); } } diff --git a/blocksuite/affine/block-embed/src/common/to-edgeless-embed-block.ts b/blocksuite/affine/block-embed/src/common/to-edgeless-embed-block.ts index 2643f6f711121..880b910613ff1 100644 --- a/blocksuite/affine/block-embed/src/common/to-edgeless-embed-block.ts +++ b/blocksuite/affine/block-embed/src/common/to-edgeless-embed-block.ts @@ -1,3 +1,4 @@ +import { EdgelessLegacySlotIdentifier } from '@blocksuite/affine-block-surface'; import { blockComponentSymbol, type BlockService, @@ -49,21 +50,22 @@ export function toEdgelessEmbedBlock< return; } + get edgelessSlots() { + return this.std.get(EdgelessLegacySlotIdentifier); + } + override connectedCallback(): void { super.connectedCallback(); - const rootService = this.rootService; this._disposables.add( - // @ts-expect-error TODO: fix after edgeless slots are migrated to extension - rootService.slots.elementResizeStart.on(() => { + this.edgelessSlots.elementResizeStart.on(() => { this._isResizing = true; this._showOverlay = true; }) ); this._disposables.add( - // @ts-expect-error TODO: fix after edgeless slots are migrated to extension - rootService.slots.elementResizeEnd.on(() => { + this.edgelessSlots.elementResizeEnd.on(() => { this._isResizing = false; this._showOverlay = this._isResizing || this._isDragging || !this._isSelected; diff --git a/blocksuite/affine/block-embed/src/effects.ts b/blocksuite/affine/block-embed/src/effects.ts index fd6045d580e86..df55e512a5b42 100644 --- a/blocksuite/affine/block-embed/src/effects.ts +++ b/blocksuite/affine/block-embed/src/effects.ts @@ -1,3 +1,5 @@ +import type * as SurfaceEffects from '@blocksuite/affine-block-surface/effects'; + import { EmbedFigmaBlockComponent } from './embed-figma-block'; import { EmbedEdgelessBlockComponent } from './embed-figma-block/embed-edgeless-figma-block'; import type { EmbedFigmaBlockService } from './embed-figma-block/embed-figma-service'; @@ -90,6 +92,8 @@ export function effects() { ); } +declare type _GLOBAL = typeof SurfaceEffects; + declare global { interface HTMLElementTagNameMap { 'affine-embed-figma-block': EmbedFigmaBlockComponent; diff --git a/blocksuite/affine/block-embed/tsconfig.json b/blocksuite/affine/block-embed/tsconfig.json index c1a5453aa5056..f86f39bde9ab6 100644 --- a/blocksuite/affine/block-embed/tsconfig.json +++ b/blocksuite/affine/block-embed/tsconfig.json @@ -27,6 +27,9 @@ }, { "path": "../shared" + }, + { + "path": "../block-surface" } ] } diff --git a/blocksuite/affine/block-latex/src/index.ts b/blocksuite/affine/block-latex/src/index.ts index 727dfa7c7b6ef..db59377ad619c 100644 --- a/blocksuite/affine/block-latex/src/index.ts +++ b/blocksuite/affine/block-latex/src/index.ts @@ -7,7 +7,7 @@ export * from './latex-block'; export * from './latex-spec'; // Global types -declare type _Global = +declare type _GLOBAl = | typeof NoteType | typeof CommandsType | typeof RemarkMathType; diff --git a/blocksuite/affine/block-note/package.json b/blocksuite/affine/block-note/package.json index 492e515999f05..707f46576b697 100644 --- a/blocksuite/affine/block-note/package.json +++ b/blocksuite/affine/block-note/package.json @@ -14,6 +14,7 @@ "license": "MIT", "dependencies": { "@blocksuite/affine-block-embed": "workspace:*", + "@blocksuite/affine-block-surface": "workspace:*", "@blocksuite/affine-components": "workspace:*", "@blocksuite/affine-model": "workspace:*", "@blocksuite/affine-shared": "workspace:*", diff --git a/blocksuite/affine/block-note/src/note-edgeless-block.ts b/blocksuite/affine/block-note/src/note-edgeless-block.ts index 6f69d7ac4091e..217d8df94aa31 100644 --- a/blocksuite/affine/block-note/src/note-edgeless-block.ts +++ b/blocksuite/affine/block-note/src/note-edgeless-block.ts @@ -1,3 +1,4 @@ +import { EdgelessLegacySlotIdentifier } from '@blocksuite/affine-block-surface'; import { MoreIndicatorIcon } from '@blocksuite/affine-components/icons'; import type { NoteBlockModel } from '@blocksuite/affine-model'; import { @@ -13,11 +14,7 @@ import { matchFlavours, stopPropagation, } from '@blocksuite/affine-shared/utils'; -import type { - BlockComponent, - BlockService, - EditorHost, -} from '@blocksuite/block-std'; +import type { BlockComponent, EditorHost } from '@blocksuite/block-std'; import { ShadowlessElement, toGfxBlockComponent } from '@blocksuite/block-std'; import { almostEqual, @@ -26,7 +23,7 @@ import { Point, WithDisposable, } from '@blocksuite/global/utils'; -import type { BlockModel, Slot } from '@blocksuite/store'; +import type { BlockModel } from '@blocksuite/store'; import { css, html, nothing } from 'lit'; import { property, query, state } from 'lit/decorators.js'; import { classMap } from 'lit/directives/class-map.js'; @@ -153,9 +150,7 @@ export class EdgelessNoteBlockComponent extends toGfxBlockComponent( } get rootService() { - return this.std.getService('affine:page') as BlockService & { - slots: Record; - }; + return this.std.getService('affine:page'); } private _collapsedContent() { @@ -330,12 +325,16 @@ export class EdgelessNoteBlockComponent extends toGfxBlockComponent( ); } + get edgelessSlots() { + return this.std.get(EdgelessLegacySlotIdentifier); + } + override firstUpdated() { const { _disposables } = this; const selection = this.gfx.selection; _disposables.add( - this.rootService.slots.elementResizeStart.on(() => { + this.edgelessSlots.elementResizeStart.on(() => { if (selection.selectedElements.includes(this.model)) { this._isResizing = true; } @@ -343,7 +342,7 @@ export class EdgelessNoteBlockComponent extends toGfxBlockComponent( ); _disposables.add( - this.rootService.slots.elementResizeEnd.on(() => { + this.edgelessSlots.elementResizeEnd.on(() => { this._isResizing = false; }) ); diff --git a/blocksuite/affine/block-note/tsconfig.json b/blocksuite/affine/block-note/tsconfig.json index 54b5d3348b995..622857f8c4770 100644 --- a/blocksuite/affine/block-note/tsconfig.json +++ b/blocksuite/affine/block-note/tsconfig.json @@ -30,6 +30,9 @@ }, { "path": "../block-embed" + }, + { + "path": "../block-surface" } ] } diff --git a/blocksuite/affine/block-surface/src/extensions/index.ts b/blocksuite/affine/block-surface/src/extensions/index.ts index bfa3d9b634c1c..9059d6d9e1e4a 100644 --- a/blocksuite/affine/block-surface/src/extensions/index.ts +++ b/blocksuite/affine/block-surface/src/extensions/index.ts @@ -1 +1,2 @@ export * from './crud-extension'; +export * from './legacy-slot-extension'; diff --git a/blocksuite/affine/block-surface/src/extensions/legacy-slot-extension.ts b/blocksuite/affine/block-surface/src/extensions/legacy-slot-extension.ts new file mode 100644 index 0000000000000..df2e9d8ae2c9c --- /dev/null +++ b/blocksuite/affine/block-surface/src/extensions/legacy-slot-extension.ts @@ -0,0 +1,40 @@ +import type { FrameBlockModel } from '@blocksuite/affine-model'; +import type { ExtensionType } from '@blocksuite/block-std'; +import { createIdentifier } from '@blocksuite/global/di'; +import { Slot } from '@blocksuite/global/utils'; + +export const EdgelessLegacySlotIdentifier = createIdentifier<{ + readonlyUpdated: Slot; + navigatorSettingUpdated: Slot<{ + hideToolbar?: boolean; + blackBackground?: boolean; + fillScreen?: boolean; + }>; + navigatorFrameChanged: Slot; + fullScreenToggled: Slot; + + elementResizeStart: Slot; + elementResizeEnd: Slot; + toggleNoteSlicer: Slot; + + toolbarLocked: Slot; +}>('AffineEdgelessLegacySlotService'); + +export const EdgelessLegacySlotExtension: ExtensionType = { + setup: di => { + di.addImpl(EdgelessLegacySlotIdentifier, () => ({ + readonlyUpdated: new Slot(), + navigatorSettingUpdated: new Slot<{ + hideToolbar?: boolean; + blackBackground?: boolean; + fillScreen?: boolean; + }>(), + navigatorFrameChanged: new Slot(), + fullScreenToggled: new Slot(), + elementResizeStart: new Slot(), + elementResizeEnd: new Slot(), + toggleNoteSlicer: new Slot(), + toolbarLocked: new Slot(), + })); + }, +}; diff --git a/blocksuite/affine/block-surface/src/surface-spec.ts b/blocksuite/affine/block-surface/src/surface-spec.ts index 8e89e55e39a18..6013224a47967 100644 --- a/blocksuite/affine/block-surface/src/surface-spec.ts +++ b/blocksuite/affine/block-surface/src/surface-spec.ts @@ -10,11 +10,14 @@ import { literal } from 'lit/static-html.js'; import { EdgelessSurfaceBlockAdapterExtensions, SurfaceBlockAdapterExtensions, -} from './adapters/extension.js'; -import { commands } from './commands/index.js'; -import { EdgelessCRUDExtension } from './extensions/crud-extension.js'; -import { SurfaceBlockService } from './surface-service.js'; -import { MindMapView } from './view/mindmap.js'; +} from './adapters/extension'; +import { commands } from './commands'; +import { + EdgelessCRUDExtension, + EdgelessLegacySlotExtension, +} from './extensions'; +import { SurfaceBlockService } from './surface-service'; +import { MindMapView } from './view/mindmap'; const CommonSurfaceBlockSpec: ExtensionType[] = [ FlavourExtension('affine:surface'), @@ -23,6 +26,7 @@ const CommonSurfaceBlockSpec: ExtensionType[] = [ HighlightSelectionExtension, MindMapView, EdgelessCRUDExtension, + EdgelessLegacySlotExtension, ]; export const PageSurfaceBlockSpec: ExtensionType[] = [ diff --git a/blocksuite/affine/block-surface/src/utils/rough/core.ts b/blocksuite/affine/block-surface/src/utils/rough/core.ts index 0486d3d4dba05..60a2ccefe665a 100644 --- a/blocksuite/affine/block-surface/src/utils/rough/core.ts +++ b/blocksuite/affine/block-surface/src/utils/rough/core.ts @@ -64,8 +64,8 @@ export interface ResolvedOptions extends Options { preserveVertices: boolean; } -export declare type OpType = 'move' | 'bcurveTo' | 'lineTo'; -export declare type OpSetType = 'path' | 'fillPath' | 'fillSketch'; +export type OpType = 'move' | 'bcurveTo' | 'lineTo'; +export type OpSetType = 'path' | 'fillPath' | 'fillSketch'; export interface Op { op: OpType; diff --git a/blocksuite/blocks/src/root-block/edgeless/edgeless-root-block.ts b/blocksuite/blocks/src/root-block/edgeless/edgeless-root-block.ts index 5142cf5793d2c..083868dceec74 100644 --- a/blocksuite/blocks/src/root-block/edgeless/edgeless-root-block.ts +++ b/blocksuite/blocks/src/root-block/edgeless/edgeless-root-block.ts @@ -2,7 +2,10 @@ import type { SurfaceBlockComponent, SurfaceBlockModel, } from '@blocksuite/affine-block-surface'; -import { CommonUtils } from '@blocksuite/affine-block-surface'; +import { + CommonUtils, + EdgelessLegacySlotIdentifier, +} from '@blocksuite/affine-block-surface'; import type { RootBlockModel, ShapeElementModel, @@ -143,7 +146,7 @@ export class EdgelessRootBlockComponent extends BlockComponent< } get slots() { - return this.service.slots; + return this.std.get(EdgelessLegacySlotIdentifier); } get surfaceBlockModel() { diff --git a/blocksuite/blocks/src/root-block/edgeless/edgeless-root-service.ts b/blocksuite/blocks/src/root-block/edgeless/edgeless-root-service.ts index bb2e9a4d20737..ad01a5b22abf1 100644 --- a/blocksuite/blocks/src/root-block/edgeless/edgeless-root-service.ts +++ b/blocksuite/blocks/src/root-block/edgeless/edgeless-root-service.ts @@ -1,5 +1,6 @@ import { EdgelessCRUDIdentifier, + EdgelessLegacySlotIdentifier, type ElementRenderer, elementRenderers, type SurfaceBlockModel, @@ -7,7 +8,6 @@ import { } from '@blocksuite/affine-block-surface'; import { type ConnectorElementModel, - type FrameBlockModel, type GroupElementModel, MindmapElementModel, RootBlockSchema, @@ -28,7 +28,6 @@ import { } from '@blocksuite/block-std/gfx'; import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions'; import { Bound, getCommonBound } from '@blocksuite/global/utils'; -import { Slot } from '@blocksuite/store'; import { effect } from '@preact/signals-core'; import { getSurfaceBlock } from '../../surface-ref-block/utils.js'; @@ -59,23 +58,6 @@ export class EdgelessRootService extends RootService implements SurfaceContext { elementRenderers: Record = elementRenderers; - slots = { - readonlyUpdated: new Slot(), - navigatorSettingUpdated: new Slot<{ - hideToolbar?: boolean; - blackBackground?: boolean; - fillScreen?: boolean; - }>(), - navigatorFrameChanged: new Slot(), - fullScreenToggled: new Slot(), - - elementResizeStart: new Slot(), - elementResizeEnd: new Slot(), - toggleNoteSlicer: new Slot(), - - toolbarLocked: new Slot(), - }; - TemplateJob = TemplateJob; get blocks(): GfxBlockModel[] { @@ -168,12 +150,14 @@ export class EdgelessRootService extends RootService implements SurfaceContext { private _initReadonlyListener() { const doc = this.doc; + const slots = this.std.get(EdgelessLegacySlotIdentifier); + let readonly = doc.readonly; this.disposables.add( doc.awarenessStore.slots.update.on(() => { if (readonly !== doc.readonly) { readonly = doc.readonly; - this.slots.readonlyUpdated.emit(readonly); + slots.readonlyUpdated.emit(readonly); } }) ); diff --git a/blocksuite/blocks/src/root-block/widgets/drag-handle/watchers/edgeless-watcher.ts b/blocksuite/blocks/src/root-block/widgets/drag-handle/watchers/edgeless-watcher.ts index c871858816ceb..0867bebb8fce0 100644 --- a/blocksuite/blocks/src/root-block/widgets/drag-handle/watchers/edgeless-watcher.ts +++ b/blocksuite/blocks/src/root-block/widgets/drag-handle/watchers/edgeless-watcher.ts @@ -1,3 +1,7 @@ +import { + EdgelessLegacySlotIdentifier, + type SurfaceBlockComponent, +} from '@blocksuite/affine-block-surface'; import type { DndEventState } from '@blocksuite/block-std'; import { GfxControllerIdentifier, @@ -6,10 +10,6 @@ import { import { type IVec, Rect } from '@blocksuite/global/utils'; import { effect } from '@preact/signals-core'; -import type { - EdgelessRootBlockComponent, - EdgelessRootService, -} from '../../../edgeless/index.js'; import { getSelectedRect, isTopLevelBlock, @@ -64,8 +64,12 @@ export class EdgelessWatcher { private readonly _showDragHandleOnTopLevelBlocks = async () => { if (this.widget.mode === 'page') return; - const { edgelessRoot } = this; - await edgelessRoot.surface.updateComplete; + + const surfaceModel = this.widget.doc.getBlockByFlavour('affine:surface'); + const surface = this.widget.std.view.getBlock( + surfaceModel[0]!.id + ) as SurfaceBlockComponent; + await surface.updateComplete; if (!this.widget.anchorBlockId) return; @@ -121,9 +125,11 @@ export class EdgelessWatcher { return; } - const { edgelessRoot } = this; - const editing = edgelessRoot.service.selection.editing; - const selectedElements = edgelessRoot.service.selection.selectedElements; + const { std } = this.widget; + const gfx = std.get(GfxControllerIdentifier); + const { selection } = gfx; + const editing = selection.editing; + const selectedElements = selection.selectedElements; if (editing || selectedElements.length !== 1) { this.widget.hide(); return; @@ -158,10 +164,6 @@ export class EdgelessWatcher { this.widget.dragPreview.style.opacity = altKey ? '1' : '0.5'; }; - get edgelessRoot() { - return this.widget.rootComponent as EdgelessRootBlockComponent; - } - get hoverAreaRectTopLevelBlock() { const area = this.hoverAreaTopLevelBlock; if (!area) return null; @@ -174,12 +176,11 @@ export class EdgelessWatcher { if (!edgelessElement) return null; - const { edgelessRoot } = this; + const { std } = this.widget; + const gfx = std.get(GfxControllerIdentifier); + const { viewport } = gfx; const rect = getSelectedRect([edgelessElement]); - let [left, top] = edgelessRoot.service.viewport.toViewCoord( - rect.left, - rect.top - ); + let [left, top] = viewport.toViewCoord(rect.left, rect.top); const scale = this.widget.scale.peek(); const width = rect.width * scale; const height = rect.height * scale; @@ -212,26 +213,23 @@ export class EdgelessWatcher { watch() { const { disposables, std } = this.widget; - const gfxController = std.get(GfxControllerIdentifier); - const { viewport } = gfxController; - const edgelessService = std.getService( - 'affine:page' - ) as EdgelessRootService; - const edgelessSlots = edgelessService.slots; + const gfx = std.get(GfxControllerIdentifier); + const { viewport, selection, tool } = gfx; + const edgelessSlots = std.get(EdgelessLegacySlotIdentifier); disposables.add( viewport.viewportUpdated.on(this._handleEdgelessViewPortUpdated) ); disposables.add( - edgelessService.selection.slots.updated.on(() => { + selection.slots.updated.on(() => { this.checkTopLevelBlockSelection(); }) ); disposables.add( effect(() => { - const value = gfxController.tool.currentToolOption$.value; + const value = tool.currentToolOption$.value; value && this._handleEdgelessToolUpdated(value); }) diff --git a/blocksuite/blocks/src/root-block/widgets/edgeless-auto-connect/edgeless-auto-connect.ts b/blocksuite/blocks/src/root-block/widgets/edgeless-auto-connect/edgeless-auto-connect.ts index 303b6ac01cc43..dbbd9184fae49 100644 --- a/blocksuite/blocks/src/root-block/widgets/edgeless-auto-connect/edgeless-auto-connect.ts +++ b/blocksuite/blocks/src/root-block/widgets/edgeless-auto-connect/edgeless-auto-connect.ts @@ -1,3 +1,4 @@ +import { EdgelessLegacySlotIdentifier } from '@blocksuite/affine-block-surface'; import { AutoConnectLeftIcon, AutoConnectRightIcon, @@ -16,6 +17,7 @@ import { stopPropagation, } from '@blocksuite/affine-shared/utils'; import { WidgetComponent } from '@blocksuite/block-std'; +import { GfxControllerIdentifier } from '@blocksuite/block-std/gfx'; import { Bound } from '@blocksuite/global/utils'; import { css, html, nothing, type TemplateResult } from 'lit'; import { state } from 'lit/decorators.js'; @@ -426,7 +428,7 @@ export class EdgelessAutoConnectWidget extends WidgetComponent< justifyContent: 'center', alignItems: 'center', }); - const components = []; + const components: TemplateResult[] = []; const count = counts[i]; const initGap = 24 / count - 24; const positions = calculatePosition( @@ -509,17 +511,19 @@ export class EdgelessAutoConnectWidget extends WidgetComponent< } override firstUpdated(): void { - const { _disposables, service } = this; + const { _disposables, std } = this; + const slots = std.get(EdgelessLegacySlotIdentifier); + const gfx = std.get(GfxControllerIdentifier); _disposables.add( - service.viewport.viewportUpdated.on(() => { + gfx.viewport.viewportUpdated.on(() => { this.requestUpdate(); }) ); _disposables.add( - service.selection.slots.updated.on(() => { - const { selectedElements } = service.selection; + gfx.selection.slots.updated.on(() => { + const { selectedElements } = gfx.selection; if ( !(selectedElements.length === 1 && isNoteBlock(selectedElements[0])) ) { @@ -529,22 +533,22 @@ export class EdgelessAutoConnectWidget extends WidgetComponent< ); _disposables.add( - service.uiEventDispatcher.add('dragStart', () => { + std.event.add('dragStart', () => { this._dragging = true; }) ); _disposables.add( - service.uiEventDispatcher.add('dragEnd', () => { + std.event.add('dragEnd', () => { this._dragging = false; }) ); _disposables.add( - service.slots.elementResizeStart.on(() => { + slots.elementResizeStart.on(() => { this._dragging = true; }) ); _disposables.add( - service.slots.elementResizeEnd.on(() => { + slots.elementResizeEnd.on(() => { this._dragging = false; }) ); diff --git a/blocksuite/blocks/src/root-block/widgets/edgeless-zoom-toolbar/index.ts b/blocksuite/blocks/src/root-block/widgets/edgeless-zoom-toolbar/index.ts index fc6695a9d1e52..3559642455f6f 100644 --- a/blocksuite/blocks/src/root-block/widgets/edgeless-zoom-toolbar/index.ts +++ b/blocksuite/blocks/src/root-block/widgets/edgeless-zoom-toolbar/index.ts @@ -1,3 +1,4 @@ +import { EdgelessLegacySlotIdentifier } from '@blocksuite/affine-block-surface'; import type { RootBlockModel } from '@blocksuite/affine-model'; import { WidgetComponent } from '@blocksuite/block-std'; import { effect } from '@preact/signals-core'; @@ -58,10 +59,8 @@ export class AffineEdgelessZoomToolbarWidget extends WidgetComponent< } override firstUpdated() { - const { - disposables, - edgeless: { slots }, - } = this; + const { disposables, std } = this; + const slots = std.get(EdgelessLegacySlotIdentifier); disposables.add( slots.navigatorSettingUpdated.on(({ hideToolbar }) => { diff --git a/blocksuite/presets/src/fragments/frame-panel/header/frame-panel-header.ts b/blocksuite/presets/src/fragments/frame-panel/header/frame-panel-header.ts index 43be03979cc0f..9744725d8703b 100644 --- a/blocksuite/presets/src/fragments/frame-panel/header/frame-panel-header.ts +++ b/blocksuite/presets/src/fragments/frame-panel/header/frame-panel-header.ts @@ -2,6 +2,7 @@ import type { EditorHost } from '@blocksuite/block-std'; import { createButtonPopper, DocModeProvider, + EdgelessLegacySlotIdentifier, EdgelessRootService, EditPropsStore, type NavigatorMode, @@ -134,14 +135,14 @@ export class FramePanelHeader extends WithDisposable(LitElement) { private readonly _setEdgelessDisposables = () => { if (!this._edgelessRootService) return; + const slots = this.editorHost.std.get(EdgelessLegacySlotIdentifier); + this._clearEdgelessDisposables(); this._edgelessDisposables = new DisposableGroup(); this._edgelessDisposables.add( - this._edgelessRootService.slots.navigatorSettingUpdated.on( - ({ fillScreen }) => { - this._navigatorMode = fillScreen ? 'fill' : 'fit'; - } - ) + slots.navigatorSettingUpdated.on(({ fillScreen }) => { + this._navigatorMode = fillScreen ? 'fill' : 'fit'; + }) ); }; diff --git a/blocksuite/presets/src/fragments/frame-panel/header/frames-setting-menu.ts b/blocksuite/presets/src/fragments/frame-panel/header/frames-setting-menu.ts index 4482a11120af3..f05c5973edcc1 100644 --- a/blocksuite/presets/src/fragments/frame-panel/header/frames-setting-menu.ts +++ b/blocksuite/presets/src/fragments/frame-panel/header/frames-setting-menu.ts @@ -1,5 +1,9 @@ import type { EditorHost } from '@blocksuite/block-std'; -import { EdgelessRootService, EditPropsStore } from '@blocksuite/blocks'; +import { + EdgelessLegacySlotIdentifier, + EdgelessRootService, + EditPropsStore, +} from '@blocksuite/blocks'; import { WithDisposable } from '@blocksuite/global/utils'; import { css, html, LitElement, type PropertyValues } from 'lit'; import { property, state } from 'lit/decorators.js'; @@ -72,16 +76,20 @@ export const AFFINE_FRAMES_SETTING_MENU = 'affine-frames-setting-menu'; export class FramesSettingMenu extends WithDisposable(LitElement) { static override styles = styles; + get slots() { + return this.editorHost.std.get(EdgelessLegacySlotIdentifier); + } + private readonly _onBlackBackgroundChange = (checked: boolean) => { this.blackBackground = checked; - this._edgelessRootService?.slots.navigatorSettingUpdated.emit({ + this.slots.navigatorSettingUpdated.emit({ blackBackground: this.blackBackground, }); }; private readonly _onFillScreenChange = (checked: boolean) => { this.fillScreen = checked; - this._edgelessRootService?.slots.navigatorSettingUpdated.emit({ + this.slots.navigatorSettingUpdated.emit({ fillScreen: this.fillScreen, }); this._editPropsStore.setStorage('presentFillScreen', this.fillScreen); @@ -89,7 +97,7 @@ export class FramesSettingMenu extends WithDisposable(LitElement) { private readonly _onHideToolBarChange = (checked: boolean) => { this.hideToolbar = checked; - this._edgelessRootService?.slots.navigatorSettingUpdated.emit({ + this.slots.navigatorSettingUpdated.emit({ hideToolbar: this.hideToolbar, }); this._editPropsStore.setStorage('presentHideToolbar', this.hideToolbar); @@ -170,7 +178,7 @@ export class FramesSettingMenu extends WithDisposable(LitElement) { if (_changedProperties.has('editorHost')) { if (this._edgelessRootService) { this.disposables.add( - this._edgelessRootService.slots.navigatorSettingUpdated.on( + this.slots.navigatorSettingUpdated.on( ({ blackBackground, hideToolbar }) => { if ( blackBackground !== undefined && diff --git a/tools/utils/src/workspace.gen.ts b/tools/utils/src/workspace.gen.ts index abe5a3d27de6c..2d82398b99e1f 100644 --- a/tools/utils/src/workspace.gen.ts +++ b/tools/utils/src/workspace.gen.ts @@ -18,6 +18,7 @@ export const PackageList = [ name: '@blocksuite/affine-block-attachment', workspaceDependencies: [ 'blocksuite/affine/block-embed', + 'blocksuite/affine/block-surface', 'blocksuite/affine/components', 'blocksuite/affine/model', 'blocksuite/affine/shared', @@ -113,6 +114,7 @@ export const PackageList = [ name: '@blocksuite/affine-block-note', workspaceDependencies: [ 'blocksuite/affine/block-embed', + 'blocksuite/affine/block-surface', 'blocksuite/affine/components', 'blocksuite/affine/model', 'blocksuite/affine/shared', diff --git a/yarn.lock b/yarn.lock index f6f0863a23a8e..cbf81011ec557 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3244,6 +3244,7 @@ __metadata: resolution: "@blocksuite/affine-block-attachment@workspace:blocksuite/affine/block-attachment" dependencies: "@blocksuite/affine-block-embed": "workspace:*" + "@blocksuite/affine-block-surface": "workspace:*" "@blocksuite/affine-components": "workspace:*" "@blocksuite/affine-model": "workspace:*" "@blocksuite/affine-shared": "workspace:*" @@ -3407,6 +3408,7 @@ __metadata: resolution: "@blocksuite/affine-block-note@workspace:blocksuite/affine/block-note" dependencies: "@blocksuite/affine-block-embed": "workspace:*" + "@blocksuite/affine-block-surface": "workspace:*" "@blocksuite/affine-components": "workspace:*" "@blocksuite/affine-model": "workspace:*" "@blocksuite/affine-shared": "workspace:*"