123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484 |
- import React from 'react';
- import { FieldType, NumberFormat, NumberTypeOptionPB, SelectOptionCellDataPB, ViewLayoutPB } from '@/services/backend';
- import { Log } from '$app/utils/log';
- import {
- assert,
- assertFieldName,
- assertNumberOfFields,
- assertNumberOfRows,
- assertTextCell,
- createSingleSelectOptions,
- createTestDatabaseView,
- editTextCell,
- findFirstFieldInfoWithFieldType,
- makeCheckboxCellController,
- makeDateCellController,
- makeMultiSelectCellController,
- makeSingleSelectCellController,
- makeTextCellController,
- makeURLCellController,
- openTestDatabase,
- } from './DatabaseTestHelper';
- import { SelectOptionCellBackendService } from '$app/stores/effects/database/cell/select_option_bd_svc';
- import { TypeOptionController } from '$app/stores/effects/database/field/type_option/type_option_controller';
- import { None, Some } from 'ts-results';
- import { RowBackendService } from '$app/stores/effects/database/row/row_bd_svc';
- import { makeNumberTypeOptionContext } from '$app/stores/effects/database/field/type_option/type_option_context';
- import { CalendarData } from '$app/stores/effects/database/cell/controller_builder';
- import { DatabaseEventMoveField } from '@/services/backend/events/flowy-database';
- export const RunAllGridTests = () => {
- async function run() {
- await createBuildInGrid();
- await testEditGridCell();
- await testCreateRow();
- await testDeleteRow();
- await testCreateOptionInCell();
- await testGetSingleSelectFieldData();
- await testSwitchFromSingleSelectToNumber();
- await testSwitchFromMultiSelectToRichText();
- await testEditField();
- await testCreateNewField();
- await testDeleteField();
- }
- return (
- <React.Fragment>
- <div>
- <button className='rounded-md bg-red-400 p-4' type='button' onClick={() => run()}>
- Run all grid tests
- </button>
- </div>
- </React.Fragment>
- );
- };
- async function createBuildInGrid() {
- const view = await createTestDatabaseView(ViewLayoutPB.Grid);
- const databaseController = await openTestDatabase(view.id);
- databaseController.subscribe({
- onViewChanged: (databasePB) => {
- Log.debug('Did receive database:' + databasePB);
- },
- // onRowsChanged: async (rows) => {
- // if (rows.length !== 3) {
- // throw Error('Expected number of rows is 3, but receive ' + rows.length);
- // }
- // },
- onFieldsChanged: (fields) => {
- if (fields.length !== 3) {
- throw Error('Expected number of fields is 3, but receive ' + fields.length);
- }
- },
- });
- await databaseController.open().then((result) => result.unwrap());
- await databaseController.dispose();
- }
- async function testEditGridCell() {
- const view = await createTestDatabaseView(ViewLayoutPB.Grid);
- const databaseController = await openTestDatabase(view.id);
- await databaseController.open().then((result) => result.unwrap());
- for (const [index, row] of databaseController.databaseViewCache.rowInfos.entries()) {
- const cellContent = index.toString();
- const fieldInfo = findFirstFieldInfoWithFieldType(row, FieldType.RichText).unwrap();
- await editTextCell(fieldInfo.field.id, row, databaseController, cellContent);
- await assertTextCell(fieldInfo.field.id, row, databaseController, cellContent);
- }
- }
- async function testEditTextCell() {
- const view = await createTestDatabaseView(ViewLayoutPB.Grid);
- const databaseController = await openTestDatabase(view.id);
- await databaseController.open().then((result) => result.unwrap());
- const row = databaseController.databaseViewCache.rowInfos[0];
- const textField = findFirstFieldInfoWithFieldType(row, FieldType.RichText).unwrap();
- const textCellController = await makeTextCellController(textField.field.id, row, databaseController).then((result) =>
- result.unwrap()
- );
- textCellController.subscribeChanged({
- onCellChanged: (content) => {
- Log.info('Receive text:', content);
- },
- });
- await textCellController.saveCellData('hello react');
- await new Promise((resolve) => setTimeout(resolve, 200));
- await databaseController.dispose();
- }
- async function testEditURLCell() {
- const view = await createTestDatabaseView(ViewLayoutPB.Grid);
- const databaseController = await openTestDatabase(view.id);
- await databaseController.open().then((result) => result.unwrap());
- const typeOptionController = new TypeOptionController(view.id, None, FieldType.URL);
- await typeOptionController.initialize();
- const row = databaseController.databaseViewCache.rowInfos[0];
- const urlCellController = await makeURLCellController(typeOptionController.fieldId, row, databaseController).then(
- (result) => result.unwrap()
- );
- urlCellController.subscribeChanged({
- onCellChanged: (content) => {
- const pb = content.unwrap();
- Log.info('Receive url data:', pb.url, pb.content);
- },
- });
- await urlCellController.saveCellData('hello react');
- await new Promise((resolve) => setTimeout(resolve, 200));
- await urlCellController.saveCellData('appflowy.io');
- await new Promise((resolve) => setTimeout(resolve, 200));
- }
- async function testEditDateCell() {
- const view = await createTestDatabaseView(ViewLayoutPB.Grid);
- const databaseController = await openTestDatabase(view.id);
- await databaseController.open().then((result) => result.unwrap());
- const typeOptionController = new TypeOptionController(view.id, None, FieldType.DateTime);
- await typeOptionController.initialize();
- const row = databaseController.databaseViewCache.rowInfos[0];
- const dateCellController = await makeDateCellController(typeOptionController.fieldId, row, databaseController).then(
- (result) => result.unwrap()
- );
- dateCellController.subscribeChanged({
- onCellChanged: (content) => {
- const pb = content.unwrap();
- Log.info('Receive date data:', pb.date, pb.time);
- },
- });
- const date = new CalendarData(new Date(), true, '13:00');
- await dateCellController.saveCellData(date);
- await new Promise((resolve) => setTimeout(resolve, 200));
- }
- async function testCheckboxCell() {
- const view = await createTestDatabaseView(ViewLayoutPB.Grid);
- const databaseController = await openTestDatabase(view.id);
- await databaseController.open().then((result) => result.unwrap());
- const typeOptionController = new TypeOptionController(view.id, None, FieldType.Checkbox);
- await typeOptionController.initialize();
- const row = databaseController.databaseViewCache.rowInfos[0];
- const checkboxCellController = await makeCheckboxCellController(
- typeOptionController.fieldId,
- row,
- databaseController
- ).then((result) => result.unwrap());
- checkboxCellController.subscribeChanged({
- onCellChanged: (content) => {
- const pb = content.unwrap();
- Log.info('Receive checkbox data:', pb);
- },
- });
- await checkboxCellController.saveCellData('true');
- await new Promise((resolve) => setTimeout(resolve, 200));
- }
- async function testCreateRow() {
- const view = await createTestDatabaseView(ViewLayoutPB.Grid);
- const databaseController = await openTestDatabase(view.id);
- await databaseController.open().then((result) => result.unwrap());
- await assertNumberOfRows(view.id, 3);
- // Create a row from a DatabaseController or create using the RowBackendService
- await databaseController.createRow();
- await assertNumberOfRows(view.id, 4);
- await databaseController.dispose();
- }
- async function testDeleteRow() {
- const view = await createTestDatabaseView(ViewLayoutPB.Grid);
- const databaseController = await openTestDatabase(view.id);
- await databaseController.open().then((result) => result.unwrap());
- const rows = databaseController.databaseViewCache.rowInfos;
- const svc = new RowBackendService(view.id);
- await svc.deleteRow(rows[0].row.id);
- await assertNumberOfRows(view.id, 2);
- // Wait the databaseViewCache get the change notification and
- // update the rows.
- await new Promise((resolve) => setTimeout(resolve, 200));
- if (databaseController.databaseViewCache.rowInfos.length !== 2) {
- throw Error('The number of rows is not match');
- }
- await databaseController.dispose();
- }
- async function testCreateOptionInCell() {
- const view = await createTestDatabaseView(ViewLayoutPB.Grid);
- const databaseController = await openTestDatabase(view.id);
- await databaseController.open().then((result) => result.unwrap());
- for (const [index, row] of databaseController.databaseViewCache.rowInfos.entries()) {
- if (index === 0) {
- const fieldInfo = findFirstFieldInfoWithFieldType(row, FieldType.SingleSelect).unwrap();
- const cellController = await makeSingleSelectCellController(fieldInfo.field.id, row, databaseController).then(
- (result) => result.unwrap()
- );
- // eslint-disable-next-line @typescript-eslint/await-thenable
- await cellController.subscribeChanged({
- onCellChanged: (value) => {
- if (value.some) {
- const option: SelectOptionCellDataPB = value.unwrap();
- console.log(option);
- }
- },
- });
- const backendSvc = new SelectOptionCellBackendService(cellController.cellIdentifier);
- await backendSvc.createOption({ name: 'option' + index });
- await cellController.dispose();
- }
- }
- await databaseController.dispose();
- }
- async function testMoveField() {
- const view = await createTestDatabaseView(ViewLayoutPB.Grid);
- const databaseController = await openTestDatabase(view.id);
- await databaseController.open().then((result) => result.unwrap());
- databaseController.subscribe({
- onFieldsChanged: (value) => {
- Log.info('Receive fields data:', value);
- },
- });
- const fieldInfos = [...databaseController.fieldController.fieldInfos];
- const field_id = fieldInfos[0].field.id;
- await databaseController.moveField({ fieldId: field_id, fromIndex: 0, toIndex: 1 });
- await new Promise((resolve) => setTimeout(resolve, 200));
- assert(databaseController.fieldController.fieldInfos[1].field.id === field_id);
- }
- async function testGetSingleSelectFieldData() {
- const view = await createTestDatabaseView(ViewLayoutPB.Grid);
- const databaseController = await openTestDatabase(view.id);
- await databaseController.open().then((result) => result.unwrap());
- // Find the single select column
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
- const singleSelect = databaseController.fieldController.fieldInfos.find(
- (fieldInfo) => fieldInfo.field.field_type === FieldType.SingleSelect
- )!;
- // Create options
- const singleSelectTypeOptionContext = await createSingleSelectOptions(view.id, singleSelect, [
- 'Task 1',
- 'Task 2',
- 'Task 3',
- ]);
- // Read options
- const options = await singleSelectTypeOptionContext.getTypeOption().then((result) => result.unwrap());
- console.log(options);
- await databaseController.dispose();
- }
- async function testSwitchFromSingleSelectToNumber() {
- const view = await createTestDatabaseView(ViewLayoutPB.Grid);
- const databaseController = await openTestDatabase(view.id);
- await databaseController.open().then((result) => result.unwrap());
- // Find the single select column
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
- const singleSelect = databaseController.fieldController.fieldInfos.find(
- (fieldInfo) => fieldInfo.field.field_type === FieldType.SingleSelect
- )!;
- const typeOptionController = new TypeOptionController(view.id, Some(singleSelect));
- await typeOptionController.switchToField(FieldType.Number);
- // Check the number type option
- const numberTypeOptionContext = makeNumberTypeOptionContext(typeOptionController);
- const numberTypeOption: NumberTypeOptionPB = await numberTypeOptionContext
- .getTypeOption()
- .then((result) => result.unwrap());
- const format: NumberFormat = numberTypeOption.format;
- if (format !== NumberFormat.Num) {
- throw Error('The default format should be number');
- }
- await databaseController.dispose();
- }
- async function testSwitchFromMultiSelectToRichText() {
- const view = await createTestDatabaseView(ViewLayoutPB.Grid);
- const databaseController = await openTestDatabase(view.id);
- await databaseController.open().then((result) => result.unwrap());
- // Create multi-select field
- const typeOptionController = new TypeOptionController(view.id, None, FieldType.MultiSelect);
- await typeOptionController.initialize();
- // Insert options to first row
- const row = databaseController.databaseViewCache.rowInfos[0];
- const multiSelectField = typeOptionController.getFieldInfo();
- // const multiSelectField = findFirstFieldInfoWithFieldType(row, FieldType.MultiSelect).unwrap();
- const selectOptionCellController = await makeMultiSelectCellController(
- multiSelectField.field.id,
- row,
- databaseController
- ).then((result) => result.unwrap());
- const backendSvc = new SelectOptionCellBackendService(selectOptionCellController.cellIdentifier);
- await backendSvc.createOption({ name: 'A' });
- await backendSvc.createOption({ name: 'B' });
- await backendSvc.createOption({ name: 'C' });
- const selectOptionCellData = await selectOptionCellController.getCellData().then((result) => result.unwrap());
- if (selectOptionCellData.options.length !== 3) {
- throw Error('The options should equal to 3');
- }
- if (selectOptionCellData.select_options.length !== 3) {
- throw Error('The selected options should equal to 3');
- }
- await selectOptionCellController.dispose();
- // Switch to RichText field type
- await typeOptionController.switchToField(FieldType.RichText).then((result) => result.unwrap());
- if (typeOptionController.fieldType !== FieldType.RichText) {
- throw Error('The field type should be text');
- }
- const textCellController = await makeTextCellController(multiSelectField.field.id, row, databaseController).then(
- (result) => result.unwrap()
- );
- const cellContent = await textCellController.getCellData();
- if (cellContent.unwrap() !== 'A,B,C') {
- throw Error('The cell content should be A,B,C, but receive: ' + cellContent.unwrap());
- }
- await databaseController.dispose();
- }
- async function testEditField() {
- const view = await createTestDatabaseView(ViewLayoutPB.Grid);
- const databaseController = await openTestDatabase(view.id);
- await databaseController.open().then((result) => result.unwrap());
- const fieldInfos = databaseController.fieldController.fieldInfos;
- // Modify the name of the field
- const firstFieldInfo = fieldInfos[0];
- const controller = new TypeOptionController(view.id, Some(firstFieldInfo));
- await controller.initialize();
- const newName = 'hello world';
- await controller.setFieldName(newName);
- await new Promise((resolve) => setTimeout(resolve, 200));
- await assertFieldName(view.id, firstFieldInfo.field.id, firstFieldInfo.field.field_type, newName);
- await databaseController.dispose();
- }
- async function testCreateNewField() {
- const view = await createTestDatabaseView(ViewLayoutPB.Grid);
- const databaseController = await openTestDatabase(view.id);
- await databaseController.open().then((result) => result.unwrap());
- await assertNumberOfFields(view.id, 3);
- // Modify the name of the field
- const controller = new TypeOptionController(view.id, None);
- await controller.initialize();
- await assertNumberOfFields(view.id, 4);
- await databaseController.dispose();
- }
- async function testDeleteField() {
- const view = await createTestDatabaseView(ViewLayoutPB.Grid);
- const databaseController = await openTestDatabase(view.id);
- await databaseController.open().then((result) => result.unwrap());
- // Modify the name of the field.
- // The fieldInfos[0] is the primary field by default, we can't delete it.
- // So let choose the second fieldInfo.
- const fieldInfo = databaseController.fieldController.fieldInfos[1];
- const controller = new TypeOptionController(view.id, Some(fieldInfo));
- await controller.initialize();
- await assertNumberOfFields(view.id, 3);
- await controller.deleteField();
- await assertNumberOfFields(view.id, 2);
- await databaseController.dispose();
- }
- export const TestCreateGrid = () => {
- return TestButton('Test create build-in grid', createBuildInGrid);
- };
- export const TestEditCell = () => {
- return TestButton('Test editing cell', testEditGridCell);
- };
- export const TestEditTextCell = () => {
- return TestButton('Test editing text cell', testEditTextCell);
- };
- export const TestEditURLCell = () => {
- return TestButton('Test editing URL cell', testEditURLCell);
- };
- export const TestEditDateCell = () => {
- return TestButton('Test editing date cell', testEditDateCell);
- };
- export const TestEditCheckboxCell = () => {
- return TestButton('Test editing checkbox cell', testCheckboxCell);
- };
- export const TestCreateRow = () => {
- return TestButton('Test create row', testCreateRow);
- };
- export const TestDeleteRow = () => {
- return TestButton('Test delete row', testDeleteRow);
- };
- export const TestCreateSelectOptionInCell = () => {
- return TestButton('Test create a select option in cell', testCreateOptionInCell);
- };
- export const TestGetSingleSelectFieldData = () => {
- return TestButton('Test get single-select column data', testGetSingleSelectFieldData);
- };
- export const TestSwitchFromSingleSelectToNumber = () => {
- return TestButton('Test switch from single-select to number column', testSwitchFromSingleSelectToNumber);
- };
- export const TestSwitchFromMultiSelectToText = () => {
- return TestButton('Test switch from multi-select to text column', testSwitchFromMultiSelectToRichText);
- };
- export const TestMoveField = () => {
- return TestButton('Test move field', testMoveField);
- };
- export const TestEditField = () => {
- return TestButton('Test edit the column name', testEditField);
- };
- export const TestCreateNewField = () => {
- return TestButton('Test create a new column', testCreateNewField);
- };
- export const TestDeleteField = () => {
- return TestButton('Test delete a new column', testDeleteField);
- };
- export const TestButton = (title: string, onClick: () => void) => {
- return (
- <React.Fragment>
- <div>
- <button className='rounded-md bg-blue-400 p-4' type='button' onClick={() => onClick()}>
- {title}
- </button>
- </div>
- </React.Fragment>
- );
- };
|