diff --git a/packages/blocks/src/database-block/columns/rich-text/define.ts b/packages/blocks/src/database-block/columns/rich-text/define.ts index 1a8b15ad1cdd..ea38f75b3313 100644 --- a/packages/blocks/src/database-block/columns/rich-text/define.ts +++ b/packages/blocks/src/database-block/columns/rich-text/define.ts @@ -1,5 +1,6 @@ import { nanoid, Text } from '@blocksuite/store'; +import { clamp } from '../../../_common/utils/math.js'; import { columnType } from '../../data-view/column/column-config.js'; import { tRichText } from '../../data-view/logical/data-type.js'; import { getTagColor } from '../../data-view/utils/tags/colors.js'; @@ -37,6 +38,7 @@ export const richTextColumnModelConfig = }; }, }); + richTextColumnModelConfig.addConvert('select', (_column, cells) => { const options: Record = {}; const getTag = (name: string) => { @@ -93,3 +95,33 @@ richTextColumnModelConfig.addConvert('multi-select', (_column, cells) => { }, }; }); + +richTextColumnModelConfig.addConvert('number', (_column, cells) => { + return { + column: { decimal: 0 }, + cells: cells.map(v => { + const num = v ? parseFloat(v.toString()) : NaN; + return isNaN(num) ? undefined : num; + }), + }; +}); + +richTextColumnModelConfig.addConvert('progress', (_column, cells) => { + return { + column: {}, + cells: cells.map(v => { + const progress = v ? parseInt(v.toString()) : NaN; + return !isNaN(progress) ? clamp(progress, 0, 100) : undefined; + }), + }; +}); + +richTextColumnModelConfig.addConvert('checkbox', (_column, cells) => { + const truthyValues = ['yes', 'true']; + return { + column: {}, + cells: cells.map(v => + v && truthyValues.includes(v.toString().toLowerCase()) ? true : undefined + ), + }; +}); diff --git a/packages/blocks/src/database-block/data-view/column/manager.ts b/packages/blocks/src/database-block/data-view/column/manager.ts index 1f64e7a8a072..feae50d2da01 100644 --- a/packages/blocks/src/database-block/data-view/column/manager.ts +++ b/packages/blocks/src/database-block/data-view/column/manager.ts @@ -46,7 +46,8 @@ declare global { export interface ColumnConfigMap {} } -export type GetColumnDataFromConfig = +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export type GetColumnDataFromConfig> = // eslint-disable-next-line @typescript-eslint/no-explicit-any T extends ColumnConfig ? R : never; export type GetCellDataFromConfig = diff --git a/packages/blocks/src/database-block/data-view/column/presets/checkbox/define.ts b/packages/blocks/src/database-block/data-view/column/presets/checkbox/define.ts index 8c3882578f6b..b1fa345b18d3 100644 --- a/packages/blocks/src/database-block/data-view/column/presets/checkbox/define.ts +++ b/packages/blocks/src/database-block/data-view/column/presets/checkbox/define.ts @@ -1,15 +1,17 @@ +import { Text } from '@blocksuite/store'; + import { tBoolean } from '../../../logical/data-type.js'; import { columnType } from '../../column-config.js'; -export const chceckboxColumnType = columnType('checkbox'); +export const checkboxColumnType = columnType('checkbox'); declare global { interface ColumnConfigMap { - [chceckboxColumnType.type]: typeof checkboxColumnModelConfig; + [checkboxColumnType.type]: typeof checkboxColumnModelConfig.model; } } export const checkboxColumnModelConfig = - chceckboxColumnType.modelConfig({ + checkboxColumnType.modelConfig({ name: 'Checkbox', type: () => tBoolean.create(), defaultData: () => ({}), @@ -21,3 +23,10 @@ export const checkboxColumnModelConfig = }, cellToJson: data => data ?? null, }); + +checkboxColumnModelConfig.addConvert('rich-text', (_columns, cells) => { + return { + column: {}, + cells: cells.map(v => new Text(v ? 'Yes' : 'No').yText), + }; +}); diff --git a/packages/blocks/src/database-block/data-view/column/presets/date/define.ts b/packages/blocks/src/database-block/data-view/column/presets/date/define.ts index 72c0441e52c2..50e2ebc37500 100644 --- a/packages/blocks/src/database-block/data-view/column/presets/date/define.ts +++ b/packages/blocks/src/database-block/data-view/column/presets/date/define.ts @@ -4,7 +4,7 @@ import { columnType } from '../../column-config.js'; export const dateColumnType = columnType('date'); declare global { interface ColumnConfigMap { - [dateColumnType.type]: typeof dateColumnModelConfig; + [dateColumnType.type]: typeof dateColumnModelConfig.model; } } export const dateColumnModelConfig = dateColumnType.modelConfig({ diff --git a/packages/blocks/src/database-block/data-view/column/presets/number/define.ts b/packages/blocks/src/database-block/data-view/column/presets/number/define.ts index c48705aeb190..24b04636478c 100644 --- a/packages/blocks/src/database-block/data-view/column/presets/number/define.ts +++ b/packages/blocks/src/database-block/data-view/column/presets/number/define.ts @@ -1,5 +1,6 @@ import { Text } from '@blocksuite/store'; +import { clamp } from '../../../../../_common/utils/math.js'; import { tNumber } from '../../../logical/data-type.js'; import { columnType } from '../../column-config.js'; @@ -28,7 +29,13 @@ export const numberColumnModelConfig = numberColumnType.modelConfig< }, cellToJson: data => data ?? null, }); + numberColumnModelConfig.addConvert('rich-text', (_column, cells) => ({ column: {}, cells: cells.map(v => new Text(v?.toString()).yText), })); + +numberColumnModelConfig.addConvert('progress', (_column, cells) => ({ + column: {}, + cells: cells.map(v => clamp(v ?? 0, 0, 100)), +})); diff --git a/packages/blocks/src/database-block/data-view/column/presets/progress/define.ts b/packages/blocks/src/database-block/data-view/column/presets/progress/define.ts index b2b6b85e9eed..8c907fcfa6d0 100644 --- a/packages/blocks/src/database-block/data-view/column/presets/progress/define.ts +++ b/packages/blocks/src/database-block/data-view/column/presets/progress/define.ts @@ -25,7 +25,13 @@ export const progressColumnModelConfig = progressColumnType.modelConfig( cellToJson: data => data ?? null, } ); + progressColumnModelConfig.addConvert('rich-text', (_column, cells) => ({ column: {}, cells: cells.map(v => new Text(v?.toString()).yText), })); + +progressColumnModelConfig.addConvert('number', (_column, cells) => ({ + column: { decimal: 0 }, + cells: cells.map(v => v), +})); diff --git a/tests/database/column.spec.ts b/tests/database/column.spec.ts index 9d74e3368dd1..9864486b1771 100644 --- a/tests/database/column.spec.ts +++ b/tests/database/column.spec.ts @@ -276,7 +276,7 @@ test.describe('switch column type', () => { await switchColumnType(page, 'Number'); await assertDatabaseCellNumber(page, { - text: '', + text: '123', }); }); @@ -322,6 +322,43 @@ test.describe('switch column type', () => { await expect(checkbox).not.toHaveClass('checked'); }); + test('checkbox to text', async ({ page }) => { + await enterPlaygroundRoom(page); + await initEmptyDatabaseState(page); + + await initDatabaseColumn(page); + await initDatabaseDynamicRowWithData(page, '', true); + await pressEscape(page); + await switchColumnType(page, 'Checkbox'); + + let checkbox = getFirstColumnCell(page, 'checkbox'); + await expect(checkbox).not.toHaveClass('checked'); + + // checked + await checkbox.click(); + await switchColumnType(page, 'Text'); + await clickDatabaseOutside(page); + await waitNextFrame(page, 100); + await assertDatabaseCellRichTexts(page, { text: 'Yes' }); + await clickDatabaseOutside(page); + await waitNextFrame(page, 100); + await switchColumnType(page, 'Checkbox'); + checkbox = getFirstColumnCell(page, 'checkbox'); + await expect(checkbox).toHaveClass(/checked/); + + // not checked + await checkbox.click(); + await switchColumnType(page, 'Text'); + await clickDatabaseOutside(page); + await waitNextFrame(page, 100); + await assertDatabaseCellRichTexts(page, { text: 'No' }); + await clickDatabaseOutside(page); + await waitNextFrame(page, 100); + await switchColumnType(page, 'Checkbox'); + checkbox = getFirstColumnCell(page, 'checkbox'); + await expect(checkbox).not.toHaveClass('checked'); + }); + test('switch to progress', async ({ page }) => { await enterPlaygroundRoom(page); await initEmptyDatabaseState(page);