diff --git a/blocksuite/affine/block-data-view/src/data-source.ts b/blocksuite/affine/block-data-view/src/data-source.ts index 871e8af95..11bc04b91 100644 --- a/blocksuite/affine/block-data-view/src/data-source.ts +++ b/blocksuite/affine/block-data-view/src/data-source.ts @@ -211,7 +211,7 @@ export class BlockQueryDataSource extends DataSourceBase { } } - propertyDuplicate(_columnId: string): string { + propertyDuplicate(_columnId: string): string | undefined { throw new Error('Method not implemented.'); } diff --git a/blocksuite/affine/block-database/src/commands.ts b/blocksuite/affine/block-database/src/commands.ts index 8369b5dd6..e7572683f 100644 --- a/blocksuite/affine/block-database/src/commands.ts +++ b/blocksuite/affine/block-database/src/commands.ts @@ -1,4 +1,11 @@ +import type { DatabaseBlockModel } from '@blocksuite/affine-model'; import type { BlockCommands, Command } from '@blocksuite/block-std'; +import type { BlockModel, Store } from '@blocksuite/store'; + +import { + DatabaseBlockDataSource, + databaseViewInitTemplate, +} from './data-source'; export const insertDatabaseBlockCommand: Command< 'selectedModels', @@ -17,8 +24,7 @@ export const insertDatabaseBlockCommand: Command< ? selectedModels[0] : selectedModels[selectedModels.length - 1]; - const service = std.getService('affine:database'); - if (!service || !targetModel) return; + if (!targetModel) return; const result = std.store.addSiblingBlocks( targetModel, @@ -29,7 +35,7 @@ export const insertDatabaseBlockCommand: Command< if (string == null) return; - service.initDatabaseBlock(std.store, targetModel, string, viewType, false); + initDatabaseBlock(std.store, targetModel, string, viewType, false); if (removeEmptyLine && targetModel.text?.length === 0) { std.store.deleteBlock(targetModel); @@ -38,6 +44,28 @@ export const insertDatabaseBlockCommand: Command< next({ insertedDatabaseBlockId: string }); }; +export const initDatabaseBlock = ( + doc: Store, + model: BlockModel, + databaseId: string, + viewType: string, + isAppendNewRow = true +) => { + const blockModel = doc.getBlock(databaseId)?.model as + | DatabaseBlockModel + | undefined; + if (!blockModel) { + return; + } + const datasource = new DatabaseBlockDataSource(blockModel); + databaseViewInitTemplate(datasource, viewType); + if (isAppendNewRow) { + const parent = doc.getParent(model); + if (!parent) return; + doc.addBlock('affine:paragraph', {}, parent.id); + } +}; + export const commands: BlockCommands = { insertDatabaseBlock: insertDatabaseBlockCommand, }; diff --git a/blocksuite/affine/block-database/src/data-source.ts b/blocksuite/affine/block-database/src/data-source.ts index eeadc45fe..5b5f308df 100644 --- a/blocksuite/affine/block-database/src/data-source.ts +++ b/blocksuite/affine/block-database/src/data-source.ts @@ -1,4 +1,8 @@ -import type { DatabaseBlockModel } from '@blocksuite/affine-model'; +import type { + Column, + ColumnUpdater, + DatabaseBlockModel, +} from '@blocksuite/affine-model'; import { FeatureFlagService } from '@blocksuite/affine-shared/services'; import { insertPositionToIndex, @@ -19,7 +23,6 @@ import { import { propertyPresets } from '@blocksuite/data-view/property-presets'; import { IS_MOBILE } from '@blocksuite/global/env'; import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions'; -import { assertExists } from '@blocksuite/global/utils'; import { type BlockModel, nanoid, Text } from '@blocksuite/store'; import { computed, type ReadonlySignal } from '@preact/signals-core'; @@ -29,7 +32,6 @@ import { databaseBlockPropertyList, databasePropertyConverts, } from './properties/index.js'; -import { titlePropertyModelConfig } from './properties/title/define.js'; import { addProperty, applyCellsUpdate, @@ -38,7 +40,6 @@ import { deleteRows, deleteView, duplicateView, - findPropertyIndex, getCell, getProperty, moveViewTo, @@ -69,7 +70,17 @@ export class DatabaseBlockDataSource extends DataSourceBase { }); properties$: ReadonlySignal = computed(() => { - return this._model.columns$.value.map(column => column.id); + const fixedPropertiesSet = new Set(this.fixedProperties$.value); + const properties: string[] = []; + this._model.columns$.value.forEach(column => { + if (fixedPropertiesSet.has(column.type)) { + fixedPropertiesSet.delete(column.type); + } + properties.push(column.id); + }); + + const result = [...fixedPropertiesSet, ...properties]; + return result; }); readonly$: ReadonlySignal = computed(() => { @@ -98,9 +109,15 @@ export class DatabaseBlockDataSource extends DataSourceBase { return this._model.doc; } - get propertyMetas(): PropertyMetaConfig[] { + allPropertyMetas$ = computed[]>(() => { return databaseBlockPropertyList; - } + }); + + propertyMetas$ = computed(() => { + return this.allPropertyMetas$.value.filter( + v => !v.config.fixed && !v.config.hide + ); + }); constructor(model: DatabaseBlockModel) { super(); @@ -147,13 +164,6 @@ export class DatabaseBlockDataSource extends DataSourceBase { newValue: value, }); } - if (type === 'title' && newValue instanceof Text) { - this._model.doc.transact(() => { - this._model.text?.clear(); - this._model.text?.join(newValue); - }); - return; - } if (this._model.columns$.value.some(v => v.id === propertyId)) { updateCell(this._model, rowId, { columnId: propertyId, @@ -193,34 +203,108 @@ export class DatabaseBlockDataSource extends DataSourceBase { return result; } - propertyDataGet(propertyId: string): Record { - return ( - this._model.columns$.value.find(v => v.id === propertyId)?.data ?? {} + protected override getNormalPropertyAndIndex(propertyId: string): + | { + column: Column>; + index: number; + } + | undefined { + const index = this._model.columns$.value.findIndex( + v => v.id === propertyId ); + if (index >= 0) { + const column = this._model.columns$.value[index]; + if (!column) { + return; + } + return { + column, + index, + }; + } + return; + } + + private getPropertyAndIndex(propertyId: string): + | { + column: Column>; + index: number; + } + | undefined { + const result = this.getNormalPropertyAndIndex(propertyId); + if (result) { + return result; + } + if (this.isFixedProperty(propertyId)) { + const meta = this.propertyMetaGet(propertyId); + const defaultData = meta.config.fixed?.defaultData ?? {}; + return { + column: { + data: defaultData, + id: propertyId, + type: propertyId, + name: meta.config.name, + }, + index: -1, + }; + } + return undefined; + } + + private updateProperty(id: string, updater: ColumnUpdater) { + const result = this.getPropertyAndIndex(id); + if (!result) { + return; + } + const { column: prevColumn, index } = result; + this._model.doc.transact(() => { + if (index >= 0) { + const result = updater(prevColumn); + this._model.columns[index] = { ...prevColumn, ...result }; + } else { + const result = updater(prevColumn); + this._model.columns = [ + ...this._model.columns, + { ...prevColumn, ...result }, + ]; + } + }); + return id; + } + + propertyDataGet(propertyId: string): Record { + const result = this.getPropertyAndIndex(propertyId); + if (!result) { + return {}; + } + return result.column.data; } propertyDataSet(propertyId: string, data: Record): void { this._runCapture(); - - updateProperty(this._model, propertyId, () => ({ data })); + this.updateProperty(propertyId, () => ({ data })); applyPropertyUpdate(this._model); } propertyDataTypeGet(propertyId: string): TypeInstance | undefined { - const data = this._model.columns$.value.find(v => v.id === propertyId); - if (!data) { + const result = this.getPropertyAndIndex(propertyId); + if (!result) { return; } - const meta = this.propertyMetaGet(data.type); + const { column } = result; + const meta = this.propertyMetaGet(column.type); return meta.config.type({ - data: data.data, + data: column.data, dataSource: this, }); } propertyDelete(id: string): void { + if (this.isFixedProperty(id)) { + return; + } this.doc.captureSync(); - const index = findPropertyIndex(this._model, id); + const index = this._model.columns.findIndex(v => v.id === id); if (index < 0) return; this.doc.transact(() => { @@ -228,10 +312,15 @@ export class DatabaseBlockDataSource extends DataSourceBase { }); } - propertyDuplicate(propertyId: string): string { + propertyDuplicate(propertyId: string): string | undefined { + if (this.isFixedProperty(propertyId)) { + return; + } this.doc.captureSync(); const currentSchema = getProperty(this._model, propertyId); - assertExists(currentSchema); + if (!currentSchema) { + return; + } const { id: copyId, ...nonIdProps } = currentSchema; const names = new Set(this._model.columns$.value.map(v => v.name)); let index = 1; @@ -267,14 +356,16 @@ export class DatabaseBlockDataSource extends DataSourceBase { if (propertyId === 'type') { return 'Block Type'; } - return ( - this._model.columns$.value.find(v => v.id === propertyId)?.name ?? '' - ); + const result = this.getPropertyAndIndex(propertyId); + if (!result) { + return ''; + } + return result.column.name; } propertyNameSet(propertyId: string, name: string): void { this.doc.captureSync(); - updateProperty(this._model, propertyId, () => ({ name })); + this.updateProperty(propertyId, () => ({ name })); applyPropertyUpdate(this._model); } @@ -287,12 +378,17 @@ export class DatabaseBlockDataSource extends DataSourceBase { if (propertyId === 'type') { return 'image'; } - return ( - this._model.columns$.value.find(v => v.id === propertyId)?.type ?? '' - ); + const result = this.getPropertyAndIndex(propertyId); + if (!result) { + return ''; + } + return result.column.type; } propertyTypeSet(propertyId: string, toType: string): void { + if (this.isFixedProperty(propertyId)) { + return; + } const currentType = this.propertyTypeGet(propertyId); const currentData = this.propertyDataGet(propertyId); const rows = this.rows$.value; @@ -409,77 +505,54 @@ export class DatabaseBlockDataSource extends DataSourceBase { } } -export const databaseViewAddView = ( - model: DatabaseBlockModel, - viewType: string -) => { - const dataSource = new DatabaseBlockDataSource(model); - dataSource.viewManager.viewAdd(viewType); -}; -export const databaseViewInitEmpty = ( - model: DatabaseBlockModel, - viewType: string -) => { - addProperty( - model, - 'start', - titlePropertyModelConfig.create(titlePropertyModelConfig.config.name) - ); - databaseViewAddView(model, viewType); -}; -export const databaseViewInitConvert = ( - model: DatabaseBlockModel, - viewType: string -) => { - addProperty( - model, - 'end', - propertyPresets.multiSelectPropertyConfig.create('Tag', { options: [] }) - ); - databaseViewInitEmpty(model, viewType); -}; export const databaseViewInitTemplate = ( - model: DatabaseBlockModel, + datasource: DatabaseBlockDataSource, viewType: string ) => { const ids = [nanoid(), nanoid(), nanoid()] as const; - const statusId = addProperty( - model, + const titleId = datasource.properties$.value[0]; + const statusId = datasource.propertyAdd( 'end', - propertyPresets.selectPropertyConfig.create('Status', { - options: [ - { - id: ids[0], - color: getTagColor(), - value: 'TODO', - }, - { - id: ids[1], - color: getTagColor(), - value: 'In Progress', - }, - { - id: ids[2], - color: getTagColor(), - value: 'Done', - }, - ], - }) + propertyPresets.selectPropertyConfig.type ); - for (let i = 0; i < 4; i++) { - const rowId = model.doc.addBlock( - 'affine:paragraph', + datasource.propertyNameSet(statusId, 'Status'); + datasource.propertyDataSet(statusId, { + options: [ { - text: new Text(`Task ${i + 1}`), + id: ids[0], + color: getTagColor(), + value: 'TODO', }, - model.id - ); - updateCell(model, rowId, { - columnId: statusId, - value: ids[i], - }); + { + id: ids[1], + color: getTagColor(), + value: 'In Progress', + }, + { + id: ids[2], + color: getTagColor(), + value: 'Done', + }, + ], + }); + for (let i = 0; i < 4; i++) { + const rowId = datasource.rowAdd('end'); + if (titleId) { + const text = datasource.cellValueGet(rowId, titleId); + if (text instanceof Text) { + text.replace(0, text.length, `Task ${i + 1}`); + } + } + datasource.cellValueChange(rowId, statusId, ids[i]); + // const rowId = model.doc.addBlock( + // 'affine:paragraph', + // { + // text: new Text(`Task ${i + 1}`), + // }, + // model.id + // ); } - databaseViewInitEmpty(model, viewType); + datasource.viewManager.viewAdd(viewType); }; export const convertToDatabase = (host: EditorHost, viewType: string) => { const [_, ctx] = host.std.command @@ -511,8 +584,8 @@ export const convertToDatabase = (host: EditorHost, viewType: string) => { if (!databaseModel) { return; } - databaseViewInitConvert(databaseModel, viewType); - applyPropertyUpdate(databaseModel); + const datasource = new DatabaseBlockDataSource(databaseModel); + datasource.viewManager.viewAdd(viewType); host.doc.moveBlocks(selectedModels, databaseModel); const selectionManager = host.selection; diff --git a/blocksuite/affine/block-database/src/database-block.ts b/blocksuite/affine/block-database/src/database-block.ts index c54ee352c..82a4e7547 100644 --- a/blocksuite/affine/block-database/src/database-block.ts +++ b/blocksuite/affine/block-database/src/database-block.ts @@ -51,17 +51,13 @@ import { popSideDetail } from './components/layout.js'; import type { DatabaseOptionsConfig } from './config.js'; import { HostContextKey } from './context/host-context.js'; import { DatabaseBlockDataSource } from './data-source.js'; -import type { DatabaseBlockService } from './database-service.js'; import { BlockRenderer } from './detail-panel/block-renderer.js'; import { NoteRenderer } from './detail-panel/note-renderer.js'; import { DatabaseSelection } from './selection.js'; import { currentViewStorage } from './utils/current-view.js'; import { getSingleDocIdFromText } from './utils/title-doc.js'; -export class DatabaseBlockComponent extends CaptionedBlockComponent< - DatabaseBlockModel, - DatabaseBlockService -> { +export class DatabaseBlockComponent extends CaptionedBlockComponent { static override styles = css` ${unsafeCSS(dataViewCommonStyle('affine-database'))} affine-database { diff --git a/blocksuite/affine/block-database/src/database-service.ts b/blocksuite/affine/block-database/src/database-service.ts deleted file mode 100644 index 7cbda707b..000000000 --- a/blocksuite/affine/block-database/src/database-service.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { - type DatabaseBlockModel, - DatabaseBlockSchema, -} from '@blocksuite/affine-model'; -import { BlockService } from '@blocksuite/block-std'; -import { viewPresets } from '@blocksuite/data-view/view-presets'; -import type { BlockModel, Store } from '@blocksuite/store'; - -import { - databaseViewAddView, - databaseViewInitEmpty, - databaseViewInitTemplate, -} from './data-source.js'; -import { - addProperty, - applyPropertyUpdate, - updateCell, - updateView, -} from './utils/block-utils.js'; - -export class DatabaseBlockService extends BlockService { - static override readonly flavour = DatabaseBlockSchema.model.flavour; - - addColumn = addProperty; - - applyColumnUpdate = applyPropertyUpdate; - - databaseViewAddView = databaseViewAddView; - - databaseViewInitEmpty = databaseViewInitEmpty; - - updateCell = updateCell; - - updateView = updateView; - - viewPresets = viewPresets; - - initDatabaseBlock( - doc: Store, - model: BlockModel, - databaseId: string, - viewType: string, - isAppendNewRow = true - ) { - const blockModel = doc.getBlock(databaseId)?.model as - | DatabaseBlockModel - | undefined; - if (!blockModel) { - return; - } - databaseViewInitTemplate(blockModel, viewType); - if (isAppendNewRow) { - const parent = doc.getParent(model); - if (!parent) return; - doc.addBlock('affine:paragraph', {}, parent.id); - } - applyPropertyUpdate(blockModel); - } -} diff --git a/blocksuite/affine/block-database/src/database-spec.ts b/blocksuite/affine/block-database/src/database-spec.ts index c86ba5e1e..f2f174f6f 100644 --- a/blocksuite/affine/block-database/src/database-spec.ts +++ b/blocksuite/affine/block-database/src/database-spec.ts @@ -8,11 +8,9 @@ import { literal } from 'lit/static-html.js'; import { DatabaseBlockAdapterExtensions } from './adapters/extension.js'; import { commands } from './commands.js'; -import { DatabaseBlockService } from './database-service.js'; export const DatabaseBlockSpec: ExtensionType[] = [ FlavourExtension('affine:database'), - DatabaseBlockService, CommandExtension(commands), BlockViewExtension('affine:database', literal`affine-database`), DatabaseBlockAdapterExtensions, diff --git a/blocksuite/affine/block-database/src/effects.ts b/blocksuite/affine/block-database/src/effects.ts index 766092753..c33e34ff8 100644 --- a/blocksuite/affine/block-database/src/effects.ts +++ b/blocksuite/affine/block-database/src/effects.ts @@ -3,7 +3,6 @@ import { CenterPeek } from './components/layout'; import { DatabaseTitle } from './components/title'; import type { DatabaseOptionsConfig } from './config'; import { DatabaseBlockComponent } from './database-block'; -import type { DatabaseBlockService } from './database-service'; import { BlockRenderer } from './detail-panel/block-renderer'; import { NoteRenderer } from './detail-panel/note-renderer'; import { LinkCell, LinkCellEditing } from './properties/link/cell-renderer'; @@ -60,9 +59,5 @@ declare global { */ insertDatabaseBlock: typeof insertDatabaseBlockCommand; } - - interface BlockServices { - 'affine:database': DatabaseBlockService; - } } } diff --git a/blocksuite/affine/block-database/src/index.ts b/blocksuite/affine/block-database/src/index.ts index 6d826b0dd..8857b5ec2 100644 --- a/blocksuite/affine/block-database/src/index.ts +++ b/blocksuite/affine/block-database/src/index.ts @@ -6,7 +6,6 @@ export * from './adapters'; export type { DatabaseOptionsConfig } from './config'; export * from './data-source'; export * from './database-block'; -export * from './database-service'; export * from './database-spec'; export * from './detail-panel/block-renderer'; export * from './detail-panel/note-renderer'; diff --git a/blocksuite/affine/block-database/src/properties/index.ts b/blocksuite/affine/block-database/src/properties/index.ts index 4fadec677..ecabd3e17 100644 --- a/blocksuite/affine/block-database/src/properties/index.ts +++ b/blocksuite/affine/block-database/src/properties/index.ts @@ -21,18 +21,12 @@ export const databaseBlockColumns = { numberColumnConfig: numberPropertyConfig, progressColumnConfig: progressPropertyConfig, selectColumnConfig: selectPropertyConfig, + imageColumnConfig: propertyPresets.imagePropertyConfig, linkColumnConfig, richTextColumnConfig, + titleColumnConfig, }; export const databaseBlockPropertyList = Object.values(databaseBlockColumns); -export const databaseBlockHiddenColumns = [ - propertyPresets.imagePropertyConfig, - titleColumnConfig, -]; -const databaseBlockAllColumns = [ - ...databaseBlockPropertyList, - ...databaseBlockHiddenColumns, -]; export const databaseBlockAllPropertyMap = Object.fromEntries( - databaseBlockAllColumns.map(v => [v.type, v as PropertyMetaConfig]) + databaseBlockPropertyList.map(v => [v.type, v as PropertyMetaConfig]) ); diff --git a/blocksuite/affine/block-database/src/properties/rich-text/cell-renderer.ts b/blocksuite/affine/block-database/src/properties/rich-text/cell-renderer.ts index 619cfa631..1579c0128 100644 --- a/blocksuite/affine/block-database/src/properties/rich-text/cell-renderer.ts +++ b/blocksuite/affine/block-database/src/properties/rich-text/cell-renderer.ts @@ -3,7 +3,6 @@ import type { RichText, } from '@blocksuite/affine-components/rich-text'; import { DefaultInlineManagerExtension } from '@blocksuite/affine-components/rich-text'; -import type { RootBlockModel } from '@blocksuite/affine-model'; import { ParseDocUrlProvider, TelemetryProvider, @@ -23,8 +22,7 @@ import { assertExists } from '@blocksuite/global/utils'; import type { DeltaInsert } from '@blocksuite/inline'; import type { BlockSnapshot } from '@blocksuite/store'; import { Text } from '@blocksuite/store'; -import { computed, signal } from '@preact/signals-core'; -import { css, nothing } from 'lit'; +import { css } from 'lit'; import { query } from 'lit/decorators.js'; import { keyed } from 'lit/directives/keyed.js'; import { html } from 'lit/static-html.js'; @@ -143,12 +141,6 @@ abstract class BaseRichTextCell extends BaseCellRenderer { ?.std.get(DefaultInlineManagerExtension.identifier); } - get service() { - return this.view - .contextGet(HostContextKey) - ?.std.getService('affine:database'); - } - get topContenteditableElement() { const databaseBlock = this.closest('affine-database'); @@ -172,19 +164,6 @@ abstract class BaseRichTextCell extends BaseCellRenderer { @query('.affine-database-rich-text') accessor _richTextElement!: HTMLElement; - - docId$ = signal(); - - isLinkedDoc$ = computed(() => false); - - linkedDocTitle$ = computed(() => { - if (!this.docId$.value) { - return this.value; - } - const doc = this.host?.std.workspace.getDoc(this.docId$.value); - const root = doc?.root as RootBlockModel; - return root.title; - }); } export class RichTextCell extends BaseRichTextCell { @@ -232,7 +211,6 @@ export class RichTextCell extends BaseRichTextCell { } override render() { - if (!this.service) return nothing; if (!this.value || !(this.value instanceof Text)) { return html`
`; } @@ -492,7 +470,6 @@ export class RichTextCellEditing extends BaseRichTextCell { override connectedCallback() { super.connectedCallback(); - if (!this.value || typeof this.value === 'string') { this._initYText(this.value); } @@ -540,7 +517,6 @@ export class RichTextCellEditing extends BaseRichTextCell { } override render() { - if (!this.service) return nothing; return html` { + if (!value) return null; const host = dataSource.contextGet(HostContextKey); if (host) { const collection = host.std.workspace; diff --git a/blocksuite/affine/block-database/src/properties/title/define.ts b/blocksuite/affine/block-database/src/properties/title/define.ts index ba8ffca14..9631a1d4e 100644 --- a/blocksuite/affine/block-database/src/properties/title/define.ts +++ b/blocksuite/affine/block-database/src/properties/title/define.ts @@ -8,6 +8,10 @@ export const titleColumnType = propertyType('title'); export const titlePropertyModelConfig = titleColumnType.modelConfig({ name: 'Title', + fixed: { + defaultData: {}, + defaultShow: true, + }, type: () => t.richText.instance(), defaultData: () => ({}), cellToString: ({ value }) => value?.toString() ?? '', @@ -17,6 +21,7 @@ export const titlePropertyModelConfig = titleColumnType.modelConfig({ }; }, cellToJson: ({ value, dataSource }) => { + if (!value) return null; const host = dataSource.contextGet(HostContextKey); if (host) { const collection = host.std.workspace; diff --git a/blocksuite/affine/block-database/src/utils/block-utils.ts b/blocksuite/affine/block-database/src/utils/block-utils.ts index 0a02b3488..40d33789f 100644 --- a/blocksuite/affine/block-database/src/utils/block-utils.ts +++ b/blocksuite/affine/block-database/src/utils/block-utils.ts @@ -77,7 +77,7 @@ export function deleteColumn( model: DatabaseBlockModel, columnId: Column['id'] ) { - const index = findPropertyIndex(model, columnId); + const index = model.columns.findIndex(v => v.id === columnId); if (index < 0) return; model.doc.transact(() => { @@ -116,10 +116,6 @@ export function duplicateView(model: DatabaseBlockModel, id: string): string { return newId; } -export function findPropertyIndex(model: DatabaseBlockModel, id: Column['id']) { - return model.columns.findIndex(v => v.id === id); -} - export function getCell( model: DatabaseBlockModel, rowId: BlockModel['id'], @@ -228,7 +224,8 @@ export function updateCells( export function updateProperty( model: DatabaseBlockModel, id: string, - updater: ColumnUpdater + updater: ColumnUpdater, + defaultValue?: Record ) { const index = model.columns.findIndex(v => v.id === id); if (index == null) { @@ -240,7 +237,7 @@ export function updateProperty( return; } const result = updater(column); - model.columns[index] = { ...column, ...result }; + model.columns[index] = { ...defaultValue, ...column, ...result }; }); return id; } diff --git a/blocksuite/affine/data-view/src/core/common/properties.ts b/blocksuite/affine/data-view/src/core/common/properties.ts index 2192221e1..54529ac29 100644 --- a/blocksuite/affine/data-view/src/core/common/properties.ts +++ b/blocksuite/affine/data-view/src/core/common/properties.ts @@ -136,16 +136,15 @@ export class DataViewPropertiesSettingView extends SignalWatcher( }); renderProperty = (property: Property) => { - const isTitle = property.type$.value === 'title'; const icon = property.hide$.value ? InvisibleIcon() : ViewIcon(); const changeVisible = () => { - if (property.type$.value !== 'title') { + if (property.hideCanSet) { property.hideSet(!property.hide$.value); } }; const classList = classMap({ 'property-item-op-icon': true, - disabled: isTitle, + disabled: !property.hideCanSet, }); return html`
!v.hide$.value); const clickChangeAll = () => { props.view.propertiesWithoutFilter$.value.forEach(id => { - if (props.view.propertyTypeGet(id) !== 'title') { + if (props.view.propertyCanHide(id)) { props.view.propertyHideSet(id, isAllShowed); } }); diff --git a/blocksuite/affine/data-view/src/core/common/property-menu.ts b/blocksuite/affine/data-view/src/core/common/property-menu.ts index b5fea71f2..914454690 100644 --- a/blocksuite/affine/data-view/src/core/common/property-menu.ts +++ b/blocksuite/affine/data-view/src/core/common/property-menu.ts @@ -36,13 +36,13 @@ export const typeConfig = (property: Property) => { items: [ menu.subMenu({ name: 'Type', - hide: () => !property.typeSet || property.type$.value === 'title', + hide: () => !property.typeCanSet, postfix: html`
${renderUniLit(property.icon)} - ${property.view.propertyMetas.find( + ${property.view.propertyMetas$.value.find( v => v.type === property.type$.value )?.config.name}
`, @@ -52,7 +52,7 @@ export const typeConfig = (property: Property) => { }, items: [ menu.group({ - items: property.view.propertyMetas.map(config => { + items: property.view.propertyMetas$.value.map(config => { return menu.action({ isSelected: config.type === property.type$.value, name: config.config.name, diff --git a/blocksuite/affine/data-view/src/core/data-source/base.ts b/blocksuite/affine/data-view/src/core/data-source/base.ts index e7643e5d4..ae96e01d0 100644 --- a/blocksuite/affine/data-view/src/core/data-source/base.ts +++ b/blocksuite/affine/data-view/src/core/data-source/base.ts @@ -1,3 +1,4 @@ +import type { Column } from '@blocksuite/affine-model'; import type { InsertToPosition } from '@blocksuite/affine-shared/utils'; import { computed, type ReadonlySignal } from '@preact/signals-core'; @@ -26,7 +27,8 @@ export interface DataSource { rowDelete(ids: string[]): void; rowMove(rowId: string, position: InsertToPosition): void; - propertyMetas: PropertyMetaConfig[]; + propertyMetas$: ReadonlySignal; + allPropertyMetas$: ReadonlySignal; propertyNameGet$(propertyId: string): ReadonlySignal; propertyNameGet(propertyId: string): string; @@ -35,6 +37,7 @@ export interface DataSource { propertyTypeGet(propertyId: string): string | undefined; propertyTypeGet$(propertyId: string): ReadonlySignal; propertyTypeSet(propertyId: string, type: string): void; + propertyTypeCanSet(propertyId: string): boolean; propertyDataGet(propertyId: string): Record; propertyDataGet$( @@ -52,8 +55,12 @@ export interface DataSource { propertyMetaGet(type: string): PropertyMetaConfig; propertyAdd(insertToPosition: InsertToPosition, type?: string): string; - propertyDuplicate(propertyId: string): string; + + propertyDuplicate(propertyId: string): string | undefined; + propertyCanDuplicate(propertyId: string): boolean; + propertyDelete(id: string): void; + propertyCanDelete(propertyId: string): boolean; contextGet(key: DataViewContextKey): T; @@ -82,13 +89,24 @@ export interface DataSource { } export abstract class DataSourceBase implements DataSource { + propertyTypeCanSet(propertyId: string): boolean { + return !this.isFixedProperty(propertyId); + } + propertyCanDuplicate(propertyId: string): boolean { + return !this.isFixedProperty(propertyId); + } + propertyCanDelete(propertyId: string): boolean { + return !this.isFixedProperty(propertyId); + } context = new Map(); abstract featureFlags$: ReadonlySignal; abstract properties$: ReadonlySignal; - abstract propertyMetas: PropertyMetaConfig[]; + abstract propertyMetas$: ReadonlySignal; + + abstract allPropertyMetas$: ReadonlySignal; abstract readonly$: ReadonlySignal; @@ -159,7 +177,7 @@ export abstract class DataSourceBase implements DataSource { abstract propertyDelete(id: string): void; - abstract propertyDuplicate(propertyId: string): string; + abstract propertyDuplicate(propertyId: string): string | undefined; abstract propertyMetaGet(type: string): PropertyMetaConfig; @@ -223,4 +241,31 @@ export abstract class DataSourceBase implements DataSource { viewMetaGetById$(viewId: string): ReadonlySignal { return computed(() => this.viewMetaGetById(viewId)); } + + fixedProperties$ = computed(() => { + return this.allPropertyMetas$.value + .filter(v => v.config.fixed) + .map(v => v.type); + }); + fixedPropertySet = computed(() => { + return new Set(this.fixedProperties$.value); + }); + + protected abstract getNormalPropertyAndIndex(propertyId: string): + | { + column: Column>; + index: number; + } + | undefined; + + isFixedProperty(propertyId: string) { + if (this.fixedPropertySet.value.has(propertyId)) { + return true; + } + const result = this.getNormalPropertyAndIndex(propertyId); + if (result) { + return this.fixedPropertySet.value.has(result.column.type); + } + return false; + } } diff --git a/blocksuite/affine/data-view/src/core/detail/detail.ts b/blocksuite/affine/data-view/src/core/detail/detail.ts index dea9ecda7..dd9de5966 100644 --- a/blocksuite/affine/data-view/src/core/detail/detail.ts +++ b/blocksuite/affine/data-view/src/core/detail/detail.ts @@ -119,7 +119,7 @@ export class RecordDetail extends SignalWatcher( }, items: [ menu.group({ - items: this.view.propertyMetas.map(meta => { + items: this.view.propertyMetas$.value.map(meta => { return menu.action({ name: meta.config.name, prefix: renderUniLit(this.view.propertyIconGet(meta.type)), diff --git a/blocksuite/affine/data-view/src/core/detail/field.ts b/blocksuite/affine/data-view/src/core/detail/field.ts index effe05fb7..c0e02d49d 100644 --- a/blocksuite/affine/data-view/src/core/detail/field.ts +++ b/blocksuite/affine/data-view/src/core/detail/field.ts @@ -184,8 +184,7 @@ export class RecordField extends SignalWatcher( menu.action({ name: 'Duplicate', prefix: DuplicateIcon(), - hide: () => - !this.column.duplicate || this.column.type$.value === 'title', + hide: () => !this.column.canDuplicate, select: () => { this.column.duplicate?.(); }, @@ -193,8 +192,7 @@ export class RecordField extends SignalWatcher( menu.action({ name: 'Delete', prefix: DeleteIcon(), - hide: () => - !this.column.delete || this.column.type$.value === 'title', + hide: () => !this.column.canDelete, select: () => { this.column.delete?.(); }, diff --git a/blocksuite/affine/data-view/src/core/group-by/index.ts b/blocksuite/affine/data-view/src/core/group-by/index.ts new file mode 100644 index 000000000..5c36099e4 --- /dev/null +++ b/blocksuite/affine/data-view/src/core/group-by/index.ts @@ -0,0 +1 @@ +export * from './trait.js'; diff --git a/blocksuite/affine/data-view/src/core/index.ts b/blocksuite/affine/data-view/src/core/index.ts index 004f392af..b95c88590 100644 --- a/blocksuite/affine/data-view/src/core/index.ts +++ b/blocksuite/affine/data-view/src/core/index.ts @@ -3,6 +3,7 @@ export * from './component/index.js'; export { DataSourceBase } from './data-source/base.js'; export { DataView } from './data-view.js'; export * from './filter/index.js'; +export * from './group-by'; export * from './logical/index.js'; export * from './property/index.js'; export type { DataViewSelection } from './types.js'; diff --git a/blocksuite/affine/data-view/src/core/property/types.ts b/blocksuite/affine/data-view/src/core/property/types.ts index b1a995dfe..06333ae3f 100644 --- a/blocksuite/affine/data-view/src/core/property/types.ts +++ b/blocksuite/affine/data-view/src/core/property/types.ts @@ -15,6 +15,12 @@ export type PropertyConfig< Value = unknown, > = { name: string; + hide?: boolean; + fixed?: { + defaultData: Data; + defaultOrder?: string; + defaultShow?: boolean; + }; defaultData: () => Data; type: ( config: WithCommonPropertyConfig<{ @@ -50,7 +56,7 @@ export type PropertyConfig< }; cellToJson: ( config: WithCommonPropertyConfig<{ - value: Value; + value?: Value; data: Data; }> ) => DVJSON; diff --git a/blocksuite/affine/data-view/src/core/view-manager/property.ts b/blocksuite/affine/data-view/src/core/view-manager/property.ts index e7d62b2b7..de4a6646b 100644 --- a/blocksuite/affine/data-view/src/core/view-manager/property.ts +++ b/blocksuite/affine/data-view/src/core/view-manager/property.ts @@ -23,7 +23,10 @@ export interface Property< readonly icon?: UniComponent; readonly delete?: () => void; + get canDelete(): boolean; + readonly duplicate?: () => void; + get canDuplicate(): boolean; cellGet(rowId: string): Cell; @@ -32,12 +35,14 @@ export interface Property< readonly type$: ReadonlySignal; readonly typeSet?: (type: string) => void; + get typeCanSet(): boolean; readonly name$: ReadonlySignal; nameSet(name: string): void; readonly hide$: ReadonlySignal; hideSet(hide: boolean): void; + get hideCanSet(): boolean; valueGet(rowId: string): Value | undefined; valueSet(rowId: string, value: Value | undefined): void; @@ -123,6 +128,18 @@ export abstract class PropertyBase< public view: SingleView, public propertyId: string ) {} + get canDelete(): boolean { + return this.view.propertyCanDelete(this.id); + } + get canDuplicate(): boolean { + return this.view.propertyCanDuplicate(this.id); + } + get typeCanSet(): boolean { + return this.view.propertyTypeCanSet(this.id); + } + get hideCanSet(): boolean { + return this.view.propertyCanHide(this.id); + } cellGet(rowId: string): Cell { return this.view.cellGet(rowId, this.id) as Cell; 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 0cf230bc7..56b39681d 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 @@ -80,13 +80,15 @@ export interface SingleView { rowNextGet(rowId: string): string | undefined; - readonly propertyMetas: PropertyMetaConfig[]; + readonly propertyMetas$: ReadonlySignal; propertyAdd(toAfterOfProperty: InsertToPosition, type?: string): string; propertyDelete(propertyId: string): void; + propertyCanDelete(propertyId: string): boolean; propertyDuplicate(propertyId: string): void; + propertyCanDuplicate(propertyId: string): boolean; propertyGet(propertyId: string): Property; @@ -103,10 +105,12 @@ export interface SingleView { propertyTypeGet(propertyId: string): string | undefined; propertyTypeSet(propertyId: string, type: string): void; + propertyTypeCanSet(propertyId: string): boolean; propertyHideGet(propertyId: string): boolean; propertyHideSet(propertyId: string, hide: boolean): void; + propertyCanHide(propertyId: string): boolean; propertyDataGet(propertyId: string): Record; @@ -215,8 +219,8 @@ export abstract class SingleViewBase< return this.dataSource.viewMetaGet(this.type); } - get propertyMetas(): PropertyMetaConfig[] { - return this.dataSource.propertyMetas; + get propertyMetas$() { + return this.dataSource.propertyMetas$; } abstract get type(): string; @@ -225,6 +229,18 @@ export abstract class SingleViewBase< public manager: ViewManager, public id: string ) {} + propertyCanDelete(propertyId: string): boolean { + return this.dataSource.propertyCanDelete(propertyId); + } + propertyCanDuplicate(propertyId: string): boolean { + return this.dataSource.propertyCanDuplicate(propertyId); + } + propertyTypeCanSet(propertyId: string): boolean { + return this.dataSource.propertyTypeCanSet(propertyId); + } + propertyCanHide(propertyId: string): boolean { + return this.propertyTypeGet(propertyId) !== 'title'; + } private searchRowsMapping(rows: string[], searchString: string): string[] { return rows.filter(id => { @@ -370,6 +386,9 @@ export abstract class SingleViewBase< propertyDuplicate(propertyId: string): void { const id = this.dataSource.propertyDuplicate(propertyId); + if (!id) { + return; + } this.propertyMove(id, { before: false, id: propertyId, diff --git a/blocksuite/affine/data-view/src/property-presets/image/define.ts b/blocksuite/affine/data-view/src/property-presets/image/define.ts index 3bdf8b6b2..722038d8a 100644 --- a/blocksuite/affine/data-view/src/property-presets/image/define.ts +++ b/blocksuite/affine/data-view/src/property-presets/image/define.ts @@ -5,6 +5,7 @@ export const imagePropertyType = propertyType('image'); export const imagePropertyModelConfig = imagePropertyType.modelConfig({ name: 'image', + hide: true, type: () => t.image.instance(), defaultData: () => ({}), cellToString: ({ value }) => value ?? '', diff --git a/blocksuite/affine/data-view/src/view-presets/table/mobile/column-header.ts b/blocksuite/affine/data-view/src/view-presets/table/mobile/column-header.ts index ed3a1f3cf..5455ded7c 100644 --- a/blocksuite/affine/data-view/src/view-presets/table/mobile/column-header.ts +++ b/blocksuite/affine/data-view/src/view-presets/table/mobile/column-header.ts @@ -123,9 +123,7 @@ export class MobileTableColumnHeader extends SignalWatcher( menu.action({ name: 'Hide In View', prefix: ViewIcon(), - hide: () => - this.column.hide$.value || - this.column.type$.value === 'title', + hide: () => !this.column.hideCanSet, select: () => { this.column.hideSet(true); }, @@ -220,8 +218,7 @@ export class MobileTableColumnHeader extends SignalWatcher( menu.action({ name: 'Duplicate', prefix: DuplicateIcon(), - hide: () => - !this.column.duplicate || this.column.type$.value === 'title', + hide: () => !this.column.canDuplicate, select: () => { this.column.duplicate?.(); }, @@ -229,8 +226,7 @@ export class MobileTableColumnHeader extends SignalWatcher( menu.action({ name: 'Delete', prefix: DeleteIcon(), - hide: () => - !this.column.delete || this.column.type$.value === 'title', + hide: () => !this.column.canDelete, select: () => { this.column.delete?.(); }, diff --git a/blocksuite/affine/data-view/src/view-presets/table/pc/header/database-header-column.ts b/blocksuite/affine/data-view/src/view-presets/table/pc/header/database-header-column.ts index b518e13e5..9a4e2404d 100644 --- a/blocksuite/affine/data-view/src/view-presets/table/pc/header/database-header-column.ts +++ b/blocksuite/affine/data-view/src/view-presets/table/pc/header/database-header-column.ts @@ -80,7 +80,7 @@ export class DatabaseHeaderColumn extends SignalWatcher( event.stopPropagation(); popMenu(popupTargetFromElement(this), { options: { - items: this.tableViewManager.propertyMetas.map(config => { + items: this.tableViewManager.propertyMetas$.value.map(config => { return menu.action({ name: config.config.name, isSelected: config.type === this.column.type$.value, @@ -254,9 +254,7 @@ export class DatabaseHeaderColumn extends SignalWatcher( menu.action({ name: 'Hide In View', prefix: ViewIcon(), - hide: () => - this.column.hide$.value || - this.column.type$.value === 'title', + hide: () => !this.column.hideCanSet, select: () => { this.column.hideSet(true); }, @@ -370,8 +368,7 @@ export class DatabaseHeaderColumn extends SignalWatcher( menu.action({ name: 'Duplicate', prefix: DuplicateIcon(), - hide: () => - !this.column.duplicate || this.column.type$.value === 'title', + hide: () => !this.column.canDuplicate, select: () => { this.column.duplicate?.(); }, @@ -379,8 +376,7 @@ export class DatabaseHeaderColumn extends SignalWatcher( menu.action({ name: 'Delete', prefix: DeleteIcon(), - hide: () => - !this.column.delete || this.column.type$.value === 'title', + hide: () => !this.column.canDelete, select: () => { this.column.delete?.(); }, diff --git a/blocksuite/playground/apps/starter/data/database.ts b/blocksuite/playground/apps/starter/data/database.ts index 5b676f3ba..1a03a5449 100644 --- a/blocksuite/playground/apps/starter/data/database.ts +++ b/blocksuite/playground/apps/starter/data/database.ts @@ -1,16 +1,16 @@ import { databaseBlockColumns, + DatabaseBlockDataSource, type DatabaseBlockModel, type ListType, type ParagraphType, - type ViewBasicDataType, } from '@blocksuite/blocks'; +import { groupTraitKey } from '@blocksuite/data-view'; +import { propertyPresets } from '@blocksuite/data-view/property-presets'; import { viewPresets } from '@blocksuite/data-view/view-presets'; import { assertExists } from '@blocksuite/global/utils'; import { Text, type Workspace } from '@blocksuite/store'; -// eslint-disable-next-line @typescript-eslint/no-restricted-imports -import { propertyPresets } from '../../../../affine/data-view/src/property-presets'; import type { InitFn } from './utils.js'; export const database: InitFn = (collection: Workspace, id: string) => { @@ -37,105 +37,74 @@ export const database: InitFn = (collection: Workspace, id: string) => { }, noteId ); + const database = doc.getBlockById(databaseId) as DatabaseBlockModel; + const datasource = new DatabaseBlockDataSource(database); + datasource.viewManager.viewAdd('table'); + database.title = new Text(title); + const richTextId = datasource.propertyAdd( + 'end', + databaseBlockColumns.richTextColumnConfig.type + ); + Object.values([ + propertyPresets.multiSelectPropertyConfig, + propertyPresets.datePropertyConfig, + propertyPresets.numberPropertyConfig, + databaseBlockColumns.linkColumnConfig, + propertyPresets.checkboxPropertyConfig, + propertyPresets.progressPropertyConfig, + ]).forEach(column => { + datasource.propertyAdd('end', column.type); + }); + if (group) { + const groupTrait = + datasource.viewManager.currentView$.value?.traitGet(groupTraitKey); + groupTrait?.changeGroup(database.columns[1].id); + } + const paragraphTypes: ParagraphType[] = [ + 'text', + 'quote', + 'h1', + 'h2', + 'h3', + 'h4', + 'h5', + 'h6', + ]; + paragraphTypes.forEach(type => { + const id = doc.addBlock( + 'affine:paragraph', + { type: type, text: new Text(`Paragraph type ${type}`) }, + databaseId + ); + datasource.cellValueChange( + id, + richTextId, + new Text(`Paragraph type ${type}`) + ); + }); + const listTypes: ListType[] = ['numbered', 'bulleted', 'todo', 'toggle']; - new Promise(resolve => requestAnimationFrame(resolve)) - .then(() => { - const service = window.host.std.getService('affine:database'); - if (!service) return; - service.initDatabaseBlock( - doc, - model, - databaseId, - viewPresets.tableViewMeta.type, - true - ); - const database = doc.getBlockById(databaseId) as DatabaseBlockModel; - database.title = new Text(title); - const richTextId = service.addColumn( - database, - 'end', - databaseBlockColumns.richTextColumnConfig.create( - databaseBlockColumns.richTextColumnConfig.config.name - ) - ); - Object.values([ - propertyPresets.multiSelectPropertyConfig, - propertyPresets.datePropertyConfig, - propertyPresets.numberPropertyConfig, - databaseBlockColumns.linkColumnConfig, - propertyPresets.checkboxPropertyConfig, - propertyPresets.progressPropertyConfig, - ]).forEach(column => { - service.addColumn( - database, - 'end', - column.create(column.config.name) - ); - }); - service.updateView(database, database.views[0].id, () => { - return { - groupBy: group - ? { - columnId: database.columns[1].id, - type: 'groupBy', - name: 'select', - } - : undefined, - } as Partial; - }); - const paragraphTypes: ParagraphType[] = [ - 'text', - 'quote', - 'h1', - 'h2', - 'h3', - 'h4', - 'h5', - 'h6', - ]; - paragraphTypes.forEach(type => { - const id = doc.addBlock( - 'affine:paragraph', - { type: type, text: new Text(`Paragraph type ${type}`) }, - databaseId - ); - service.updateCell(database, id, { - columnId: richTextId, - value: new Text(`Paragraph type ${type}`), - }); - }); - const listTypes: ListType[] = [ - 'numbered', - 'bulleted', - 'todo', - 'toggle', - ]; + listTypes.forEach(type => { + const id = doc.addBlock( + 'affine:list', + { type: type, text: new Text(`List type ${type}`) }, + databaseId + ); + datasource.cellValueChange( + id, + richTextId, + new Text(`List type ${type}`) + ); + }); + // Add a paragraph after database + doc.addBlock('affine:paragraph', {}, noteId); + doc.addBlock('affine:paragraph', {}, noteId); + doc.addBlock('affine:paragraph', {}, noteId); + doc.addBlock('affine:paragraph', {}, noteId); + doc.addBlock('affine:paragraph', {}, noteId); + datasource.viewManager.viewAdd(viewPresets.kanbanViewMeta.type); - listTypes.forEach(type => { - const id = doc.addBlock( - 'affine:list', - { type: type, text: new Text(`List type ${type}`) }, - databaseId - ); - service.updateCell(database, id, { - columnId: richTextId, - value: new Text(`List type ${type}`), - }); - }); - // Add a paragraph after database - doc.addBlock('affine:paragraph', {}, noteId); - doc.addBlock('affine:paragraph', {}, noteId); - doc.addBlock('affine:paragraph', {}, noteId); - doc.addBlock('affine:paragraph', {}, noteId); - doc.addBlock('affine:paragraph', {}, noteId); - service.databaseViewAddView( - database, - viewPresets.kanbanViewMeta.type - ); - - doc.resetHistory(); - }) - .catch(console.error); + doc.resetHistory(); }; // Add database block inside note block addDatabase('Database 1', false); diff --git a/blocksuite/tests-legacy/embed-synced-doc.spec.ts b/blocksuite/tests-legacy/embed-synced-doc.spec.ts index bf1fc2c73..92f58dc49 100644 --- a/blocksuite/tests-legacy/embed-synced-doc.spec.ts +++ b/blocksuite/tests-legacy/embed-synced-doc.spec.ts @@ -237,16 +237,9 @@ test.describe('Embed synced doc', () => { noteId ); const model = doc2.getBlockById(databaseId) as DatabaseBlockModel; - await new Promise(resolve => setTimeout(resolve, 100)); - const databaseBlock = document.querySelector('affine-database'); - const databaseService = databaseBlock?.service; - if (databaseService) { - databaseService.databaseViewInitEmpty( - model, - databaseService.viewPresets.tableViewMeta.type - ); - databaseService.applyColumnUpdate(model); - } + const datasource = + new window.$blocksuite.blocks.DatabaseBlockDataSource(model); + datasource.viewManager.viewAdd('table'); }); // go back to previous doc diff --git a/blocksuite/tests-legacy/utils/actions/misc.ts b/blocksuite/tests-legacy/utils/actions/misc.ts index fbf06ccfb..e0002ec77 100644 --- a/blocksuite/tests-legacy/utils/actions/misc.ts +++ b/blocksuite/tests-legacy/utils/actions/misc.ts @@ -526,17 +526,10 @@ export async function initEmptyDatabaseState(page: Page, rootId?: string) { noteId ); const model = doc.getBlockById(databaseId) as DatabaseBlockModel; - await new Promise(resolve => setTimeout(resolve, 100)); - const databaseBlock = document.querySelector('affine-database'); - const databaseService = databaseBlock?.service; - if (databaseService) { - databaseService.databaseViewInitEmpty( - model, - databaseService.viewPresets.tableViewMeta.type - ); - databaseService.applyColumnUpdate(model); - } - + const datasource = new window.$blocksuite.blocks.DatabaseBlockDataSource( + model + ); + datasource.viewManager.viewAdd('table'); doc.captureSync(); return { rootId, noteId, databaseId }; }, rootId); @@ -570,43 +563,34 @@ export async function initKanbanViewState( noteId ); const model = doc.getBlockById(databaseId) as DatabaseBlockModel; - await new Promise(resolve => setTimeout(resolve, 100)); - const databaseBlock = document.querySelector('affine-database'); - const databaseService = databaseBlock?.service; - if (databaseService) { - const rowIds = config.rows.map(rowText => { - const rowId = doc.addBlock( - 'affine:paragraph', - { type: 'text', text: new window.$blocksuite.store.Text(rowText) }, - databaseId - ); - return rowId; - }); - config.columns.forEach(column => { - const columnId = databaseService.addColumn(model, 'end', { - data: {}, - name: column.type, - type: column.type, - }); - rowIds.forEach((rowId, index) => { - const value = column.value?.[index]; - if (value !== undefined) { - databaseService.updateCell(model, rowId, { - columnId, - value: - column.type === 'rich-text' - ? new window.$blocksuite.store.Text(value as string) - : value, - }); - } - }); - }); - databaseService.databaseViewInitEmpty( - model, - databaseService.viewPresets.kanbanViewMeta.type + const datasource = new window.$blocksuite.blocks.DatabaseBlockDataSource( + model + ); + const rowIds = config.rows.map(rowText => { + const rowId = doc.addBlock( + 'affine:paragraph', + { type: 'text', text: new window.$blocksuite.store.Text(rowText) }, + databaseId ); - databaseService.applyColumnUpdate(model); - } + return rowId; + }); + config.columns.forEach(column => { + const columnId = datasource.propertyAdd('end', column.type); + datasource.propertyNameSet(columnId, column.type); + rowIds.forEach((rowId, index) => { + const value = column.value?.[index]; + if (value !== undefined) { + datasource.cellValueChange( + rowId, + columnId, + column.type === 'rich-text' + ? new window.$blocksuite.store.Text(value as string) + : value + ); + } + }); + }); + datasource.viewManager.viewAdd('kanban'); doc.captureSync(); return { rootId, noteId, databaseId }; }, @@ -636,18 +620,11 @@ export async function initEmptyDatabaseWithParagraphState( noteId ); const model = doc.getBlockById(databaseId) as DatabaseBlockModel; - await new Promise(resolve => setTimeout(resolve, 100)); - const databaseBlock = document.querySelector('affine-database'); - const databaseService = databaseBlock?.service; - if (databaseService) { - databaseService.databaseViewInitEmpty( - model, - databaseService.viewPresets.tableViewMeta.type - ); - databaseService.applyColumnUpdate(model); - } + const datasource = new window.$blocksuite.blocks.DatabaseBlockDataSource( + model + ); + datasource.viewManager.viewAdd('table'); doc.addBlock('affine:paragraph', {}, noteId); - doc.captureSync(); return { rootId, noteId, databaseId }; }, rootId); diff --git a/blocksuite/tests-legacy/utils/declare-test-window.ts b/blocksuite/tests-legacy/utils/declare-test-window.ts index 08cc70c70..bbe1221b9 100644 --- a/blocksuite/tests-legacy/utils/declare-test-window.ts +++ b/blocksuite/tests-legacy/utils/declare-test-window.ts @@ -19,26 +19,26 @@ declare global { * the following instance are initialized in `packages/playground/apps/starter/main.ts` */ $blocksuite: { - store: typeof import('../../packages/framework/store/src/index.js'); - blocks: typeof import('../../packages/blocks/src/index.js'); + store: typeof import('../../framework/store/src/index.js'); + blocks: typeof import('../../blocks/src/index.js'); global: { - utils: typeof import('../../packages/framework/global/src/utils.js'); + utils: typeof import('../../framework/global/src/utils.js'); }; - editor: typeof import('../../packages/presets/src/index.js'); + editor: typeof import('../../presets/src/index.js'); identifiers: { WidgetViewMapIdentifier: typeof WidgetViewMapIdentifier; - QuickSearchProvider: typeof import('../../packages/affine/shared/src/services/quick-search-service.js').QuickSearchProvider; - DocModeProvider: typeof import('../../packages/affine/shared/src/services/doc-mode-service.js').DocModeProvider; - ThemeProvider: typeof import('../../packages/affine/shared/src/services/theme-service.js').ThemeProvider; + QuickSearchProvider: typeof import('../../affine/shared/src/services/quick-search-service.js').QuickSearchProvider; + DocModeProvider: typeof import('../../affine/shared/src/services/doc-mode-service.js').DocModeProvider; + ThemeProvider: typeof import('../../affine/shared/src/services/theme-service.js').ThemeProvider; RefNodeSlotsProvider: typeof RefNodeSlotsProvider; - ParseDocUrlService: typeof import('../../packages/affine/shared/src/services/parse-url-service.js').ParseDocUrlProvider; + ParseDocUrlService: typeof import('../../affine/shared/src/services/parse-url-service.js').ParseDocUrlProvider; }; defaultExtensions: () => ExtensionType[]; extensions: { - WidgetViewMapExtension: typeof import('../../packages/framework/block-std/src/extension/widget-view-map.js').WidgetViewMapExtension; + WidgetViewMapExtension: typeof import('../../framework/block-std/src/extension/widget-view-map.js').WidgetViewMapExtension; }; mockServices: { - mockDocModeService: typeof import('../../packages/playground/apps/_common/mock-services.js').mockDocModeService; + mockDocModeService: typeof import('../../playground/apps/_common/mock-services.js').mockDocModeService; }; }; collection: Workspace;