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 dd9bde3894..bcdecaea51 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 36f852050c..5b693018b6 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 9c12fbef21..61e58c914e 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 ad8e938189..b58a7f32bf 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 9e860f3a9f..7794bd9dfe 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 4358450fdb..fb84eed5d0 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 3e75e09b68..e5cac0c44b 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 d274696885..91a252703b 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 04de5ec1ab..8dc056866e 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 259bd11ca3..2332a27603 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 699b8f0095..5547541f27 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 d6676ed17b..2d95501117 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 f5510b3b75..485f8d532e 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 26662f6cd4..e19af57275 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 5057feca7c..e3d8a40d3e 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 102082c423..abf32f0273 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 e8512257e5..ffd2b6a407 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; } - return nextRect - ? nextRect.left - (currentRect.left + currentRect.width) - : currentRect.left - (previousRect.left + previousRect.width); + if (nextRect) { + return nextRect.left - (currentRect.left + currentRect.width); + } + + if (previousRect) { + return 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 03d7908af9..bf546a1551 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 d0f89b6a9f..41db96374c 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 84520c178f..de69c8b1d7 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 431769bcc1..0be42c4828 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 4503eb4d3f..ed611152c2 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 e8bfb3b22e..a713bb470e 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 e0c8580ce5..c9b6b774eb 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 a2cc30058d..17ea1caf77 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 be27e1114c..d49e75744b 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 5c55c8fd0d..46f6b7237b 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 e541dfb3a0..484b01fcd0 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 ef3e62bdd2..c8b4621fc9 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 6b503d8e0c..04fb1d8d29 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 1c2f7da0ee..ea549e71bc 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 ccc9717a41..33cd434083 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 db4bda2b34..90e1004844 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 083f80e96c..1f88d21543 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 f2070c95d7..a0dc70a526 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 dbcf8a1fbb..b92e690bd2 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 fb83679c1d..d290cc2806 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 f1149f00be..1e458bacc6 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) {