diff --git a/frontend/app_flowy/lib/workspace/application/doc/doc_service.dart b/frontend/app_flowy/lib/workspace/application/doc/doc_service.dart index 6ad08814f4..930e01ff22 100644 --- a/frontend/app_flowy/lib/workspace/application/doc/doc_service.dart +++ b/frontend/app_flowy/lib/workspace/application/doc/doc_service.dart @@ -3,7 +3,7 @@ import 'package:flowy_sdk/dispatch/dispatch.dart'; import 'package:flowy_sdk/protobuf/flowy-folder-data-model/view.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; -import 'package:flowy_sdk/protobuf/flowy-sync/text_block_info.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-sync/text_block.pb.dart'; class DocumentService { Future> openDocument({ diff --git a/frontend/app_flowy/lib/workspace/application/grid/block/block_listener.dart b/frontend/app_flowy/lib/workspace/application/grid/block/block_listener.dart index d4895a652f..225f969a84 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/block/block_listener.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/block/block_listener.dart @@ -7,13 +7,12 @@ import 'package:dartz/dartz.dart'; import 'package:flowy_infra/notifier.dart'; import 'package:flowy_sdk/log.dart'; import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/block_entities.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/dart_notification.pb.dart'; class GridBlockCache { final String gridId; void Function(GridBlockUpdateNotifierValue)? _onBlockChanged; - final LinkedHashMap _listeners = LinkedHashMap(); GridBlockCache({required this.gridId}); diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_service.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_service.dart index 5425542b44..a78a66d67e 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_service.dart @@ -6,10 +6,9 @@ import 'package:equatable/equatable.dart'; import 'package:flowy_sdk/dispatch/dispatch.dart'; import 'package:flowy_sdk/log.dart'; import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid-data-model/field.pb.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/cell_entities.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/url_type_option.pb.dart'; import 'package:flutter/foundation.dart'; diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/date_cell_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/date_cell_bloc.dart index 0cb4c8f051..00780143cc 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/date_cell_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/date_cell_bloc.dart @@ -1,5 +1,5 @@ -import 'package:flowy_sdk/protobuf/flowy-grid-data-model/field.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'dart:async'; diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/field_action_sheet_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/field/field_action_sheet_bloc.dart index ef0522b505..801678d929 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/field/field_action_sheet_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/field/field_action_sheet_bloc.dart @@ -1,5 +1,5 @@ import 'package:flowy_sdk/log.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid-data-model/field.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'dart:async'; diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/field_cell_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/field/field_cell_bloc.dart index 0101327a04..774a7fb82b 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/field/field_cell_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/field/field_cell_bloc.dart @@ -1,7 +1,7 @@ import 'package:app_flowy/workspace/application/grid/field/field_listener.dart'; import 'package:app_flowy/workspace/application/grid/field/field_service.dart'; import 'package:flowy_sdk/log.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid-data-model/field.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'dart:async'; diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/field_editor_pannel_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/field/field_editor_pannel_bloc.dart index ba3350b2c2..6310452d48 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/field/field_editor_pannel_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/field/field_editor_pannel_bloc.dart @@ -1,4 +1,4 @@ -import 'package:flowy_sdk/protobuf/flowy-grid-data-model/field.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'dart:async'; diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/field_listener.dart b/frontend/app_flowy/lib/workspace/application/grid/field/field_listener.dart index 1cf711e72f..c6dd832973 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/field/field_listener.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/field/field_listener.dart @@ -1,11 +1,11 @@ import 'package:dartz/dartz.dart'; import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid-data-model/field.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/dart_notification.pb.dart'; import 'package:flowy_infra/notifier.dart'; import 'dart:async'; import 'dart:typed_data'; import 'package:app_flowy/core/notification_helper.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart'; typedef UpdateFieldNotifiedValue = Either; diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart b/frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart index d4b2b78b43..99fef626c0 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart @@ -2,9 +2,8 @@ import 'package:dartz/dartz.dart'; import 'package:flowy_sdk/dispatch/dispatch.dart'; import 'package:flowy_sdk/log.dart'; import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid-data-model/field.pb.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/grid_entities.pb.dart'; import 'package:flutter/foundation.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:protobuf/protobuf.dart'; diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/grid_listenr.dart b/frontend/app_flowy/lib/workspace/application/grid/field/grid_listenr.dart index 58fa59a1e7..869ade19c0 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/field/grid_listenr.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/field/grid_listenr.dart @@ -1,11 +1,11 @@ import 'package:dartz/dartz.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid-data-model/field.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/dart_notification.pb.dart'; import 'package:flowy_infra/notifier.dart'; import 'dart:async'; import 'dart:typed_data'; import 'package:app_flowy/core/notification_helper.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart'; typedef UpdateFieldNotifiedValue = Either; diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/type_option/number_format_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/number_format_bloc.dart index a0a853913c..7086f3385a 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/field/type_option/number_format_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/number_format_bloc.dart @@ -86,7 +86,7 @@ extension NumberFormatExtension on NumberFormat { return "New Zealand dollar"; case NumberFormat.NorwegianKrone: return "Norwegian krone"; - case NumberFormat.Number: + case NumberFormat.Num: return "Number"; case NumberFormat.Percent: return "Percent"; diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/type_option/type_option_service.dart b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/type_option_service.dart index 683b13e9ec..c6abc71cbb 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/field/type_option/type_option_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/type_option_service.dart @@ -4,7 +4,6 @@ import 'package:app_flowy/workspace/application/grid/field/field_service.dart'; import 'package:dartz/dartz.dart'; import 'package:flowy_sdk/dispatch/dispatch.dart'; import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid-data-model/field.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/cell_entities.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart'; diff --git a/frontend/app_flowy/lib/workspace/application/grid/grid_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/grid_bloc.dart index bc61e5828a..813c101d53 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/grid_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/grid_bloc.dart @@ -4,7 +4,7 @@ import 'package:equatable/equatable.dart'; import 'package:flowy_sdk/log.dart'; import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-folder-data-model/view.pb.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid-data-model/protobuf.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/protobuf.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'block/block_listener.dart'; @@ -30,6 +30,7 @@ class GridBloc extends Bloc { super(GridState.initial(view.id)) { rowCache = GridRowCache( gridId: view.id, + blockId: "", fieldDelegate: GridRowCacheDelegateImpl(fieldCache), ); @@ -96,8 +97,8 @@ class GridBloc extends Bloc { for (final block in grid.blocks) { blockCache.addBlockListener(block.id); } - final rowOrders = grid.blocks.expand((block) => block.rowOrders).toList(); - rowCache.initialRows(rowOrders); + final rowInfos = grid.blocks.expand((block) => block.rowInfos).toList(); + rowCache.initialRows(rowInfos); await _loadFields(grid, emit); }, diff --git a/frontend/app_flowy/lib/workspace/application/grid/grid_header_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/grid_header_bloc.dart index 3e6bd57d71..74c801f4ff 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/grid_header_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/grid_header_bloc.dart @@ -1,6 +1,6 @@ import 'package:app_flowy/workspace/application/grid/field/field_service.dart'; import 'package:flowy_sdk/log.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid-data-model/field.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'dart:async'; diff --git a/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart b/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart index 984b50d0a2..c21d548ae0 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart @@ -6,8 +6,10 @@ import 'package:flowy_sdk/dispatch/dispatch.dart'; import 'package:flowy_sdk/log.dart'; import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-folder-data-model/view.pb.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid-data-model/field.pb.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/block_entities.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/grid_entities.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/row_entities.pb.dart'; import 'package:flutter/foundation.dart'; import 'cell/cell_service/cell_service.dart'; import 'row/row_service.dart'; diff --git a/frontend/app_flowy/lib/workspace/application/grid/row/row_action_sheet_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/row/row_action_sheet_bloc.dart index 16f8679b2c..8754917223 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/row/row_action_sheet_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/row/row_action_sheet_bloc.dart @@ -12,7 +12,11 @@ class RowActionSheetBloc extends Bloc final RowService _rowService; RowActionSheetBloc({required GridRow rowData}) - : _rowService = RowService(gridId: rowData.gridId, rowId: rowData.rowId), + : _rowService = RowService( + gridId: rowData.gridId, + blockId: rowData.blockId, + rowId: rowData.rowId, + ), super(RowActionSheetState.initial(rowData)) { on( (event, emit) async { diff --git a/frontend/app_flowy/lib/workspace/application/grid/row/row_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/row/row_bloc.dart index 56d3397da0..72acc08720 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/row/row_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/row/row_bloc.dart @@ -1,7 +1,7 @@ import 'dart:collection'; import 'package:app_flowy/workspace/application/grid/cell/cell_service/cell_service.dart'; import 'package:equatable/equatable.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid-data-model/field.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'dart:async'; @@ -17,7 +17,11 @@ class RowBloc extends Bloc { RowBloc({ required GridRow rowData, required GridRowCache rowCache, - }) : _rowService = RowService(gridId: rowData.gridId, rowId: rowData.rowId), + }) : _rowService = RowService( + gridId: rowData.gridId, + blockId: rowData.blockId, + rowId: rowData.rowId, + ), _rowCache = rowCache, super(RowState.initial(rowData, rowCache.loadGridCells(rowData.rowId))) { on( diff --git a/frontend/app_flowy/lib/workspace/application/grid/row/row_listener.dart b/frontend/app_flowy/lib/workspace/application/grid/row/row_listener.dart index 19dd8229d3..5cf46acd11 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/row/row_listener.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/row/row_listener.dart @@ -1,12 +1,12 @@ import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid-data-model/field.pb.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/block_entities.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/dart_notification.pb.dart'; import 'package:flowy_infra/notifier.dart'; import 'dart:async'; import 'dart:typed_data'; import 'package:app_flowy/core/notification_helper.dart'; import 'package:dartz/dartz.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart'; typedef UpdateRowNotifiedValue = Either; typedef UpdateFieldNotifiedValue = Either, FlowyError>; diff --git a/frontend/app_flowy/lib/workspace/application/grid/row/row_service.dart b/frontend/app_flowy/lib/workspace/application/grid/row/row_service.dart index ed60c63c13..24ef1807c0 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/row/row_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/row/row_service.dart @@ -5,8 +5,9 @@ import 'package:dartz/dartz.dart'; import 'package:flowy_sdk/dispatch/dispatch.dart'; import 'package:flowy_sdk/log.dart'; import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid-data-model/field.pb.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/block_entities.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/grid_entities.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/row_entities.pb.dart'; import 'package:flutter/foundation.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; @@ -22,18 +23,23 @@ abstract class GridRowFieldDelegate { class GridRowCache { final String gridId; + final String blockId; final RowsNotifier _rowsNotifier; final GridRowFieldDelegate _fieldDelegate; List get clonedRows => _rowsNotifier.clonedRows; - GridRowCache({required this.gridId, required GridRowFieldDelegate fieldDelegate}) - : _rowsNotifier = RowsNotifier( - rowBuilder: (rowOrder) { + GridRowCache({ + required this.gridId, + required this.blockId, + required GridRowFieldDelegate fieldDelegate, + }) : _rowsNotifier = RowsNotifier( + rowBuilder: (rowInfo) { return GridRow( gridId: gridId, + blockId: "test", fields: fieldDelegate.fields, - rowId: rowOrder.rowId, - height: rowOrder.height.toDouble(), + rowId: rowInfo.rowId, + height: rowInfo.height.toDouble(), ); }, ), @@ -119,13 +125,14 @@ class GridRowCache { return _makeGridCells(rowId, data); } - void initialRows(List rowOrders) { - _rowsNotifier.initialRows(rowOrders); + void initialRows(List rowInfos) { + _rowsNotifier.initialRows(rowInfos); } Future _loadRow(String rowId) async { - final payload = RowIdentifierPayload.create() + final payload = GridRowIdPayload.create() ..gridId = gridId + ..blockId = blockId ..rowId = rowId; final result = await GridEventGetRow(payload).send(); @@ -155,34 +162,34 @@ class GridRowCache { } class RowsNotifier extends ChangeNotifier { - List _rows = []; - HashMap _rowDataMap = HashMap(); + List _allRows = []; + HashMap _rowByRowId = HashMap(); GridRowChangeReason _changeReason = const InitialListState(); - final GridRow Function(RowOrder) rowBuilder; + final GridRow Function(BlockRowInfo) rowBuilder; RowsNotifier({ required this.rowBuilder, }); - List get clonedRows => [..._rows]; + List get clonedRows => [..._allRows]; - void initialRows(List rowOrders) { - _rowDataMap = HashMap(); - final rows = rowOrders.map((rowOrder) => rowBuilder(rowOrder)).toList(); + void initialRows(List rowInfos) { + _rowByRowId = HashMap(); + final rows = rowInfos.map((rowOrder) => rowBuilder(rowOrder)).toList(); _update(rows, const GridRowChangeReason.initial()); } - void deleteRows(List deletedRows) { + void deleteRows(List deletedRows) { if (deletedRows.isEmpty) { return; } final List newRows = []; final DeletedIndexs deletedIndex = []; - final Map deletedRowMap = {for (var e in deletedRows) e.rowId: e}; + final Map deletedRowByRowId = {for (var e in deletedRows) e.rowId: e}; - _rows.asMap().forEach((index, row) { - if (deletedRowMap[row.rowId] == null) { + _allRows.asMap().forEach((index, row) { + if (deletedRowByRowId[row.rowId] == null) { newRows.add(row); } else { deletedIndex.add(DeletedIndex(index: index, row: row)); @@ -202,10 +209,10 @@ class RowsNotifier extends ChangeNotifier { for (final insertRow in insertRows) { final insertIndex = InsertedIndex( index: insertRow.index, - rowId: insertRow.rowOrder.rowId, + rowId: insertRow.rowInfo.rowId, ); insertIndexs.add(insertIndex); - newRows.insert(insertRow.index, (rowBuilder(insertRow.rowOrder))); + newRows.insert(insertRow.index, (rowBuilder(insertRow.rowInfo))); } _update(newRows, GridRowChangeReason.insert(insertIndexs)); } @@ -218,14 +225,15 @@ class RowsNotifier extends ChangeNotifier { final UpdatedIndexs updatedIndexs = UpdatedIndexs(); final List newRows = clonedRows; for (final updatedRow in updatedRows) { - final rowOrder = updatedRow.rowOrder; - final index = newRows.indexWhere((row) => row.rowId == rowOrder.rowId); + final rowOrder = updatedRow.rowInfo; + final rowId = updatedRow.rowInfo.rowId; + final index = newRows.indexWhere((row) => row.rowId == rowId); if (index != -1) { - _rowDataMap[rowOrder.rowId] = updatedRow.row; + _rowByRowId[rowId] = updatedRow.row; newRows.removeAt(index); newRows.insert(index, rowBuilder(rowOrder)); - updatedIndexs[rowOrder.rowId] = UpdatedIndex(index: index, rowId: rowOrder.rowId); + updatedIndexs[rowId] = UpdatedIndex(index: index, rowId: rowId); } } @@ -233,11 +241,11 @@ class RowsNotifier extends ChangeNotifier { } void fieldDidChange() { - _update(_rows, const GridRowChangeReason.fieldDidChange()); + _update(_allRows, const GridRowChangeReason.fieldDidChange()); } void _update(List rows, GridRowChangeReason reason) { - _rows = rows; + _allRows = rows; _changeReason = reason; _changeReason.map( @@ -252,13 +260,13 @@ class RowsNotifier extends ChangeNotifier { set rowData(Row rowData) { rowData.freeze(); - _rowDataMap[rowData.id] = rowData; - final index = _rows.indexWhere((row) => row.rowId == rowData.id); + _rowByRowId[rowData.id] = rowData; + final index = _allRows.indexWhere((row) => row.rowId == rowData.id); if (index != -1) { // update the corresponding row in _rows if they are not the same - if (_rows[index].data != rowData) { - final row = _rows.removeAt(index).copyWith(data: rowData); - _rows.insert(index, row); + if (_allRows[index].data != rowData) { + final row = _allRows.removeAt(index).copyWith(data: rowData); + _allRows.insert(index, row); // Calculate the update index final UpdatedIndexs updatedIndexs = UpdatedIndexs(); @@ -272,15 +280,16 @@ class RowsNotifier extends ChangeNotifier { } Row? rowDataWithId(String rowId) { - return _rowDataMap[rowId]; + return _rowByRowId[rowId]; } } class RowService { final String gridId; + final String blockId; final String rowId; - RowService({required this.gridId, required this.rowId}); + RowService({required this.gridId, required this.blockId, required this.rowId}); Future> createRow() { CreateRowPayload payload = CreateRowPayload.create() @@ -302,24 +311,27 @@ class RowService { } Future> getRow() { - final payload = RowIdentifierPayload.create() + final payload = GridRowIdPayload.create() ..gridId = gridId + ..blockId = blockId ..rowId = rowId; return GridEventGetRow(payload).send(); } Future> deleteRow() { - final payload = RowIdentifierPayload.create() + final payload = GridRowIdPayload.create() ..gridId = gridId + ..blockId = blockId ..rowId = rowId; return GridEventDeleteRow(payload).send(); } Future> duplicateRow() { - final payload = RowIdentifierPayload.create() + final payload = GridRowIdPayload.create() ..gridId = gridId + ..blockId = blockId ..rowId = rowId; return GridEventDuplicateRow(payload).send(); @@ -330,6 +342,7 @@ class RowService { class GridRow with _$GridRow { const factory GridRow({ required String gridId, + required String blockId, required String rowId, required UnmodifiableListView fields, required double height, diff --git a/frontend/app_flowy/lib/workspace/application/grid/setting/property_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/setting/property_bloc.dart index 69729d8224..587bebcfe4 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/setting/property_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/setting/property_bloc.dart @@ -1,7 +1,7 @@ import 'package:app_flowy/workspace/application/grid/field/field_service.dart'; import 'package:app_flowy/workspace/application/grid/grid_service.dart'; import 'package:flowy_sdk/log.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid-data-model/field.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'dart:async'; diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/layout/layout.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/layout/layout.dart index 73ed2221ec..36c603b7b4 100755 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/layout/layout.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/layout/layout.dart @@ -1,4 +1,4 @@ -import 'package:flowy_sdk/protobuf/flowy-grid-data-model/field.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart'; import 'sizes.dart'; class GridLayout { diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/cell_builder.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/cell_builder.dart index b7f9b8e86f..64b5cda4ef 100755 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/cell_builder.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/cell_builder.dart @@ -1,5 +1,5 @@ import 'package:app_flowy/workspace/application/grid/cell/cell_service/cell_service.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid-data-model/field.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart'; import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter/material.dart'; diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_cell.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_cell.dart index 12a633ee92..9237c71be0 100755 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_cell.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_cell.dart @@ -6,7 +6,7 @@ import 'package:flowy_infra/theme.dart'; import 'package:flowy_infra_ui/style_widget/button.dart'; import 'package:flowy_infra_ui/style_widget/hover.dart'; import 'package:flowy_infra_ui/style_widget/text.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid-data-model/field.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'field_type_extension.dart'; diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_editor_pannel.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_editor_pannel.dart index 73d99a7966..7ec5144458 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_editor_pannel.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_editor_pannel.dart @@ -10,7 +10,7 @@ import 'package:flowy_infra_ui/flowy_infra_ui.dart'; import 'package:flowy_infra_ui/style_widget/button.dart'; import 'package:flowy_infra_ui/style_widget/text.dart'; import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid-data-model/field.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:app_flowy/workspace/application/grid/prelude.dart'; diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_type_extension.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_type_extension.dart index cf498926d9..0f6da9951e 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_type_extension.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_type_extension.dart @@ -1,6 +1,6 @@ -import 'package:flowy_sdk/protobuf/flowy-grid-data-model/field.pb.dart'; import 'package:app_flowy/generated/locale_keys.g.dart'; import 'package:easy_localization/easy_localization.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart'; extension FieldTypeListExtension on FieldType { String iconName() { diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_type_list.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_type_list.dart index be1e32906c..0ea53fb547 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_type_list.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_type_list.dart @@ -6,7 +6,7 @@ import 'package:flowy_infra_ui/style_widget/button.dart'; import 'package:flowy_infra_ui/style_widget/scrolling/styled_list.dart'; import 'package:flowy_infra_ui/style_widget/text.dart'; import 'package:flowy_infra_ui/widget/spacing.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid-data-model/field.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart'; import 'package:flutter/material.dart'; import 'field_type_extension.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart index 4686ae755f..cc968d15cb 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart @@ -5,7 +5,7 @@ import 'package:flowy_infra/image.dart'; import 'package:flowy_infra/theme.dart'; import 'package:flowy_infra_ui/style_widget/button.dart'; import 'package:flowy_infra_ui/style_widget/text.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid-data-model/field.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:reorderables/reorderables.dart'; diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/row_detail.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/row_detail.dart index 637489362d..23f8b50f63 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/row_detail.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/row_detail.dart @@ -14,9 +14,9 @@ import 'package:flowy_infra_ui/flowy_infra_ui.dart'; import 'package:flowy_infra_ui/style_widget/icon_button.dart'; import 'package:flowy_infra_ui/style_widget/scrolling/styled_scroll_bar.dart'; import 'package:flowy_infra_ui/widget/spacing.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid-data-model/field.pb.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:app_flowy/generated/locale_keys.g.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:window_size/window_size.dart'; diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_property.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_property.dart index 4185fcef51..e19c90ecea 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_property.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_property.dart @@ -12,7 +12,7 @@ import 'package:flowy_infra_ui/style_widget/button.dart'; import 'package:flowy_infra_ui/style_widget/icon_button.dart'; import 'package:flowy_infra_ui/style_widget/text.dart'; import 'package:flowy_infra_ui/widget/spacing.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid-data-model/field.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:styled_widget/styled_widget.dart'; diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/dispatch/dispatch.dart b/frontend/app_flowy/packages/flowy_sdk/lib/dispatch/dispatch.dart index 11d53a31df..3e168b05f3 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/dispatch/dispatch.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/dispatch/dispatch.dart @@ -4,15 +4,9 @@ import 'package:flowy_sdk/log.dart'; // ignore: unnecessary_import import 'package:flowy_sdk/protobuf/dart-ffi/ffi_response.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid/cell_entities.pb.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option.pb.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid/row_entities.pb.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-net/network_state.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-user/event_map.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-folder/event_map.pb.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid/event_map.pb.dart'; import 'package:isolates/isolates.dart'; import 'package:isolates/ports.dart'; import 'package:ffi/ffi.dart'; @@ -25,7 +19,7 @@ import 'package:flowy_sdk/protobuf/flowy-user-data-model/protobuf.dart'; import 'package:flowy_sdk/protobuf/dart-ffi/protobuf.dart'; import 'package:flowy_sdk/protobuf/flowy-folder-data-model/protobuf.dart'; import 'package:flowy_sdk/protobuf/flowy-text-block/protobuf.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid-data-model/protobuf.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/protobuf.dart'; import 'package:flowy_sdk/protobuf/flowy-sync/protobuf.dart'; // ignore: unused_import diff --git a/frontend/rust-lib/Cargo.lock b/frontend/rust-lib/Cargo.lock index aa7cd8aef7..fa89ab3137 100644 --- a/frontend/rust-lib/Cargo.lock +++ b/frontend/rust-lib/Cargo.lock @@ -973,17 +973,13 @@ name = "flowy-grid-data-model" version = "0.1.0" dependencies = [ "bytes", - "flowy-derive", "flowy-error-code", "indexmap", "lib-infra", "nanoid", - "protobuf", "serde", "serde_json", "serde_repr", - "strum", - "strum_macros", ] [[package]] diff --git a/frontend/rust-lib/flowy-folder/src/services/view/controller.rs b/frontend/rust-lib/flowy-folder/src/services/view/controller.rs index d51c1c1235..1491373b20 100644 --- a/frontend/rust-lib/flowy-folder/src/services/view/controller.rs +++ b/frontend/rust-lib/flowy-folder/src/services/view/controller.rs @@ -17,7 +17,7 @@ use flowy_database::kv::KV; use flowy_folder_data_model::entities::view::{gen_view_id, ViewDataType}; use flowy_folder_data_model::entities::ViewInfo; use flowy_folder_data_model::revision::ViewRevision; -use flowy_sync::entities::text_block_info::TextBlockId; +use flowy_sync::entities::text_block::TextBlockId; use futures::{FutureExt, StreamExt}; use std::{collections::HashSet, sync::Arc}; diff --git a/frontend/rust-lib/flowy-folder/tests/workspace/script.rs b/frontend/rust-lib/flowy-folder/tests/workspace/script.rs index e8303f9c42..5d62e31d9e 100644 --- a/frontend/rust-lib/flowy-folder/tests/workspace/script.rs +++ b/frontend/rust-lib/flowy-folder/tests/workspace/script.rs @@ -17,7 +17,7 @@ use flowy_folder_data_model::entities::{ use flowy_revision::disk::RevisionState; use flowy_revision::REVISION_WRITE_INTERVAL_IN_MILLIS; -use flowy_sync::entities::text_block_info::TextBlockInfo; +use flowy_sync::entities::text_block::TextBlockInfo; use flowy_test::{event_builder::*, FlowySDKTest}; use std::{sync::Arc, time::Duration}; use tokio::time::sleep; diff --git a/frontend/rust-lib/flowy-grid/src/entities/block_entities.rs b/frontend/rust-lib/flowy-grid/src/entities/block_entities.rs new file mode 100644 index 0000000000..5ff7fea0f4 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/entities/block_entities.rs @@ -0,0 +1,213 @@ +use crate::entities::GridRowId; +use flowy_derive::ProtoBuf; +use flowy_error::ErrorCode; +use flowy_grid_data_model::parser::NotEmptyStr; +use flowy_grid_data_model::revision::RowRevision; +use std::sync::Arc; + +#[derive(Debug, Clone, Default, ProtoBuf)] +pub struct GridBlock { + #[pb(index = 1)] + pub id: String, + + #[pb(index = 2)] + pub row_infos: Vec, +} + +impl GridBlock { + pub fn new(block_id: &str, row_orders: Vec) -> Self { + Self { + id: block_id.to_owned(), + row_infos: row_orders, + } + } +} + +#[derive(Debug, Default, Clone, ProtoBuf)] +pub struct BlockRowInfo { + #[pb(index = 1)] + pub block_id: String, + + #[pb(index = 2)] + pub row_id: String, + + #[pb(index = 3)] + pub height: i32, +} + +impl BlockRowInfo { + pub fn row_id(&self) -> &str { + &self.row_id + } + + pub fn block_id(&self) -> &str { + &self.block_id + } +} + +impl std::convert::From<&RowRevision> for BlockRowInfo { + fn from(rev: &RowRevision) -> Self { + Self { + block_id: rev.block_id.clone(), + row_id: rev.id.clone(), + height: rev.height, + } + } +} + +impl std::convert::From<&Arc> for BlockRowInfo { + fn from(rev: &Arc) -> Self { + Self { + block_id: rev.block_id.clone(), + row_id: rev.id.clone(), + height: rev.height, + } + } +} + +#[derive(Debug, Default, ProtoBuf)] +pub struct Row { + #[pb(index = 1)] + pub id: String, + + #[pb(index = 2)] + pub height: i32, +} + +#[derive(Debug, Default, ProtoBuf)] +pub struct OptionalRow { + #[pb(index = 1, one_of)] + pub row: Option, +} + +#[derive(Debug, Default, ProtoBuf)] +pub struct RepeatedRow { + #[pb(index = 1)] + pub items: Vec, +} + +impl std::convert::From> for RepeatedRow { + fn from(items: Vec) -> Self { + Self { items } + } +} +#[derive(Debug, Default, ProtoBuf)] +pub struct RepeatedGridBlock { + #[pb(index = 1)] + pub items: Vec, +} + +impl std::convert::From> for RepeatedGridBlock { + fn from(items: Vec) -> Self { + Self { items } + } +} + +#[derive(Debug, Clone, Default, ProtoBuf)] +pub struct IndexRowOrder { + #[pb(index = 1)] + pub row_info: BlockRowInfo, + + #[pb(index = 2, one_of)] + pub index: Option, +} + +#[derive(Debug, Default, ProtoBuf)] +pub struct UpdatedRowOrder { + #[pb(index = 1)] + pub row_info: BlockRowInfo, + + #[pb(index = 2)] + pub row: Row, +} + +impl UpdatedRowOrder { + pub fn new(row_rev: &RowRevision, row: Row) -> Self { + Self { + row_info: BlockRowInfo::from(row_rev), + row, + } + } +} + +impl std::convert::From for IndexRowOrder { + fn from(row_info: BlockRowInfo) -> Self { + Self { row_info, index: None } + } +} + +impl std::convert::From<&RowRevision> for IndexRowOrder { + fn from(row: &RowRevision) -> Self { + let row_order = BlockRowInfo::from(row); + Self::from(row_order) + } +} + +#[derive(Debug, Default, ProtoBuf)] +pub struct GridRowsChangeset { + #[pb(index = 1)] + pub block_id: String, + + #[pb(index = 2)] + pub inserted_rows: Vec, + + #[pb(index = 3)] + pub deleted_rows: Vec, + + #[pb(index = 4)] + pub updated_rows: Vec, +} +impl GridRowsChangeset { + pub fn insert(block_id: &str, inserted_rows: Vec) -> Self { + Self { + block_id: block_id.to_owned(), + inserted_rows, + deleted_rows: vec![], + updated_rows: vec![], + } + } + + pub fn delete(block_id: &str, deleted_rows: Vec) -> Self { + Self { + block_id: block_id.to_owned(), + inserted_rows: vec![], + deleted_rows, + updated_rows: vec![], + } + } + + pub fn update(block_id: &str, updated_rows: Vec) -> Self { + Self { + block_id: block_id.to_owned(), + inserted_rows: vec![], + deleted_rows: vec![], + updated_rows, + } + } +} + +#[derive(ProtoBuf, Default)] +pub struct QueryGridBlocksPayload { + #[pb(index = 1)] + pub grid_id: String, + + #[pb(index = 2)] + pub block_ids: Vec, +} + +pub struct QueryGridBlocksParams { + pub grid_id: String, + pub block_ids: Vec, +} + +impl TryInto for QueryGridBlocksPayload { + type Error = ErrorCode; + + fn try_into(self) -> Result { + let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?; + Ok(QueryGridBlocksParams { + grid_id: grid_id.0, + block_ids: self.block_ids, + }) + } +} diff --git a/frontend/rust-lib/flowy-grid/src/entities/cell_entities.rs b/frontend/rust-lib/flowy-grid/src/entities/cell_entities.rs index 4d09fe0eda..391a63fa3f 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/cell_entities.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/cell_entities.rs @@ -2,6 +2,8 @@ use crate::entities::{FieldIdentifier, FieldIdentifierPayload}; use flowy_derive::ProtoBuf; use flowy_error::ErrorCode; use flowy_grid_data_model::parser::NotEmptyStr; +use flowy_grid_data_model::revision::{CellRevision, RowMetaChangeset}; +use std::collections::HashMap; #[derive(ProtoBuf, Default)] pub struct CreateSelectOptionPayload { @@ -70,3 +72,85 @@ impl TryInto for CellIdentifierPayload { }) } } +#[derive(Debug, Default, ProtoBuf)] +pub struct Cell { + #[pb(index = 1)] + pub field_id: String, + + #[pb(index = 2)] + pub data: Vec, +} + +impl Cell { + pub fn new(field_id: &str, data: Vec) -> Self { + Self { + field_id: field_id.to_owned(), + data, + } + } + + pub fn empty(field_id: &str) -> Self { + Self { + field_id: field_id.to_owned(), + data: vec![], + } + } +} + +#[derive(Debug, Default, ProtoBuf)] +pub struct RepeatedCell { + #[pb(index = 1)] + pub items: Vec, +} + +impl std::ops::Deref for RepeatedCell { + type Target = Vec; + fn deref(&self) -> &Self::Target { + &self.items + } +} + +impl std::ops::DerefMut for RepeatedCell { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.items + } +} + +impl std::convert::From> for RepeatedCell { + fn from(items: Vec) -> Self { + Self { items } + } +} + +#[derive(Debug, Clone, Default, ProtoBuf)] +pub struct CellChangeset { + #[pb(index = 1)] + pub grid_id: String, + + #[pb(index = 2)] + pub row_id: String, + + #[pb(index = 3)] + pub field_id: String, + + #[pb(index = 4, one_of)] + pub cell_content_changeset: Option, +} + +impl std::convert::From for RowMetaChangeset { + fn from(changeset: CellChangeset) -> Self { + let mut cell_by_field_id = HashMap::with_capacity(1); + let field_id = changeset.field_id; + let cell_rev = CellRevision { + data: changeset.cell_content_changeset.unwrap_or_else(|| "".to_owned()), + }; + cell_by_field_id.insert(field_id, cell_rev); + + RowMetaChangeset { + row_id: changeset.row_id, + height: None, + visibility: None, + cell_by_field_id, + } + } +} diff --git a/frontend/rust-lib/flowy-grid/src/entities/field_entities.rs b/frontend/rust-lib/flowy-grid/src/entities/field_entities.rs index 553c833fd6..137693e13a 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/field_entities.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/field_entities.rs @@ -1,7 +1,571 @@ -use flowy_derive::ProtoBuf; +use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; use flowy_error::ErrorCode; use flowy_grid_data_model::parser::NotEmptyStr; +use flowy_grid_data_model::revision::{FieldRevision, FieldTypeRevision}; +use flowy_sync::entities::grid::FieldChangesetParams; +use serde_repr::*; +use std::sync::Arc; +use strum_macros::{Display, EnumCount as EnumCountMacro, EnumIter, EnumString}; + +#[derive(Debug, Clone, Default, ProtoBuf)] +pub struct Field { + #[pb(index = 1)] + pub id: String, + + #[pb(index = 2)] + pub name: String, + + #[pb(index = 3)] + pub desc: String, + + #[pb(index = 4)] + pub field_type: FieldType, + + #[pb(index = 5)] + pub frozen: bool, + + #[pb(index = 6)] + pub visibility: bool, + + #[pb(index = 7)] + pub width: i32, + + #[pb(index = 8)] + pub is_primary: bool, +} + +impl std::convert::From for Field { + fn from(field_rev: FieldRevision) -> Self { + Self { + id: field_rev.id, + name: field_rev.name, + desc: field_rev.desc, + field_type: field_rev.field_type_rev.into(), + frozen: field_rev.frozen, + visibility: field_rev.visibility, + width: field_rev.width, + is_primary: field_rev.is_primary, + } + } +} + +impl std::convert::From> for Field { + fn from(field_rev: Arc) -> Self { + let field_rev = field_rev.as_ref().clone(); + Field::from(field_rev) + } +} +#[derive(Debug, Clone, Default, ProtoBuf)] +pub struct FieldOrder { + #[pb(index = 1)] + pub field_id: String, +} + +impl std::convert::From<&str> for FieldOrder { + fn from(s: &str) -> Self { + FieldOrder { field_id: s.to_owned() } + } +} + +impl std::convert::From for FieldOrder { + fn from(s: String) -> Self { + FieldOrder { field_id: s } + } +} + +impl std::convert::From<&Arc> for FieldOrder { + fn from(field_rev: &Arc) -> Self { + Self { + field_id: field_rev.id.clone(), + } + } +} +#[derive(Debug, Clone, Default, ProtoBuf)] +pub struct GridFieldChangeset { + #[pb(index = 1)] + pub grid_id: String, + + #[pb(index = 2)] + pub inserted_fields: Vec, + + #[pb(index = 3)] + pub deleted_fields: Vec, + + #[pb(index = 4)] + pub updated_fields: Vec, +} + +impl GridFieldChangeset { + pub fn insert(grid_id: &str, inserted_fields: Vec) -> Self { + Self { + grid_id: grid_id.to_owned(), + inserted_fields, + deleted_fields: vec![], + updated_fields: vec![], + } + } + + pub fn delete(grid_id: &str, deleted_fields: Vec) -> Self { + Self { + grid_id: grid_id.to_string(), + inserted_fields: vec![], + deleted_fields, + updated_fields: vec![], + } + } + + pub fn update(grid_id: &str, updated_fields: Vec) -> Self { + Self { + grid_id: grid_id.to_string(), + inserted_fields: vec![], + deleted_fields: vec![], + updated_fields, + } + } +} + +#[derive(Debug, Clone, Default, ProtoBuf)] +pub struct IndexField { + #[pb(index = 1)] + pub field: Field, + + #[pb(index = 2)] + pub index: i32, +} + +impl IndexField { + pub fn from_field_rev(field_rev: &Arc, index: usize) -> Self { + Self { + field: Field::from(field_rev.as_ref().clone()), + index: index as i32, + } + } +} + +#[derive(Debug, Default, ProtoBuf)] +pub struct GetEditFieldContextPayload { + #[pb(index = 1)] + pub grid_id: String, + + #[pb(index = 2, one_of)] + pub field_id: Option, + + #[pb(index = 3)] + pub field_type: FieldType, +} + +#[derive(Debug, Default, ProtoBuf)] +pub struct EditFieldPayload { + #[pb(index = 1)] + pub grid_id: String, + + #[pb(index = 2)] + pub field_id: String, + + #[pb(index = 3)] + pub field_type: FieldType, + + #[pb(index = 4)] + pub create_if_not_exist: bool, +} + +pub struct EditFieldParams { + pub grid_id: String, + pub field_id: String, + pub field_type: FieldType, +} + +impl TryInto for EditFieldPayload { + type Error = ErrorCode; + + fn try_into(self) -> Result { + let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?; + let field_id = NotEmptyStr::parse(self.field_id).map_err(|_| ErrorCode::FieldIdIsEmpty)?; + Ok(EditFieldParams { + grid_id: grid_id.0, + field_id: field_id.0, + field_type: self.field_type, + }) + } +} + +pub struct CreateFieldParams { + pub grid_id: String, + pub field_type: FieldType, +} + +impl TryInto for EditFieldPayload { + type Error = ErrorCode; + + fn try_into(self) -> Result { + let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?; + + Ok(CreateFieldParams { + grid_id: grid_id.0, + field_type: self.field_type, + }) + } +} + +#[derive(Debug, Default, ProtoBuf)] +pub struct FieldTypeOptionContext { + #[pb(index = 1)] + pub grid_id: String, + + #[pb(index = 2)] + pub grid_field: Field, + + #[pb(index = 3)] + pub type_option_data: Vec, +} + +#[derive(Debug, Default, ProtoBuf)] +pub struct FieldTypeOptionData { + #[pb(index = 1)] + pub grid_id: String, + + #[pb(index = 2)] + pub field: Field, + + #[pb(index = 3)] + pub type_option_data: Vec, +} + +#[derive(Debug, Default, ProtoBuf)] +pub struct RepeatedField { + #[pb(index = 1)] + pub items: Vec, +} +impl std::ops::Deref for RepeatedField { + type Target = Vec; + fn deref(&self) -> &Self::Target { + &self.items + } +} + +impl std::ops::DerefMut for RepeatedField { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.items + } +} + +impl std::convert::From> for RepeatedField { + fn from(items: Vec) -> Self { + Self { items } + } +} + +#[derive(Debug, Clone, Default, ProtoBuf)] +pub struct RepeatedFieldOrder { + #[pb(index = 1)] + pub items: Vec, +} + +impl std::ops::Deref for RepeatedFieldOrder { + type Target = Vec; + fn deref(&self) -> &Self::Target { + &self.items + } +} + +impl std::convert::From> for RepeatedFieldOrder { + fn from(field_orders: Vec) -> Self { + RepeatedFieldOrder { items: field_orders } + } +} + +impl std::convert::From for RepeatedFieldOrder { + fn from(s: String) -> Self { + RepeatedFieldOrder { + items: vec![FieldOrder::from(s)], + } + } +} + +#[derive(ProtoBuf, Default)] +pub struct InsertFieldPayload { + #[pb(index = 1)] + pub grid_id: String, + + #[pb(index = 2)] + pub field: Field, + + #[pb(index = 3)] + pub type_option_data: Vec, + + #[pb(index = 4, one_of)] + pub start_field_id: Option, +} + +#[derive(Clone)] +pub struct InsertFieldParams { + pub grid_id: String, + pub field: Field, + pub type_option_data: Vec, + pub start_field_id: Option, +} + +impl TryInto for InsertFieldPayload { + type Error = ErrorCode; + + fn try_into(self) -> Result { + let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?; + let _ = NotEmptyStr::parse(self.field.id.clone()).map_err(|_| ErrorCode::FieldIdIsEmpty)?; + + let start_field_id = match self.start_field_id { + None => None, + Some(id) => Some(NotEmptyStr::parse(id).map_err(|_| ErrorCode::FieldIdIsEmpty)?.0), + }; + + Ok(InsertFieldParams { + grid_id: grid_id.0, + field: self.field, + type_option_data: self.type_option_data, + start_field_id, + }) + } +} + +#[derive(ProtoBuf, Default)] +pub struct UpdateFieldTypeOptionPayload { + #[pb(index = 1)] + pub grid_id: String, + + #[pb(index = 2)] + pub field_id: String, + + #[pb(index = 3)] + pub type_option_data: Vec, +} + +#[derive(Clone)] +pub struct UpdateFieldTypeOptionParams { + pub grid_id: String, + pub field_id: String, + pub type_option_data: Vec, +} + +impl TryInto for UpdateFieldTypeOptionPayload { + type Error = ErrorCode; + + fn try_into(self) -> Result { + let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?; + let _ = NotEmptyStr::parse(self.field_id.clone()).map_err(|_| ErrorCode::FieldIdIsEmpty)?; + + Ok(UpdateFieldTypeOptionParams { + grid_id: grid_id.0, + field_id: self.field_id, + type_option_data: self.type_option_data, + }) + } +} + +#[derive(ProtoBuf, Default)] +pub struct QueryFieldPayload { + #[pb(index = 1)] + pub grid_id: String, + + #[pb(index = 2)] + pub field_orders: RepeatedFieldOrder, +} + +pub struct QueryFieldParams { + pub grid_id: String, + pub field_orders: RepeatedFieldOrder, +} + +impl TryInto for QueryFieldPayload { + type Error = ErrorCode; + + fn try_into(self) -> Result { + let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?; + Ok(QueryFieldParams { + grid_id: grid_id.0, + field_orders: self.field_orders, + }) + } +} + +#[derive(Debug, Clone, Default, ProtoBuf)] +pub struct FieldChangesetPayload { + #[pb(index = 1)] + pub field_id: String, + + #[pb(index = 2)] + pub grid_id: String, + + #[pb(index = 3, one_of)] + pub name: Option, + + #[pb(index = 4, one_of)] + pub desc: Option, + + #[pb(index = 5, one_of)] + pub field_type: Option, + + #[pb(index = 6, one_of)] + pub frozen: Option, + + #[pb(index = 7, one_of)] + pub visibility: Option, + + #[pb(index = 8, one_of)] + pub width: Option, + + #[pb(index = 9, one_of)] + pub type_option_data: Option>, +} + +impl TryInto for FieldChangesetPayload { + type Error = ErrorCode; + + fn try_into(self) -> Result { + let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?; + let field_id = NotEmptyStr::parse(self.field_id).map_err(|_| ErrorCode::FieldIdIsEmpty)?; + let field_type = self.field_type.map(FieldTypeRevision::from); + if let Some(type_option_data) = self.type_option_data.as_ref() { + if type_option_data.is_empty() { + return Err(ErrorCode::TypeOptionDataIsEmpty); + } + } + + Ok(FieldChangesetParams { + field_id: field_id.0, + grid_id: grid_id.0, + name: self.name, + desc: self.desc, + field_type, + frozen: self.frozen, + visibility: self.visibility, + width: self.width, + type_option_data: self.type_option_data, + }) + } +} + +#[derive( + Debug, + Clone, + PartialEq, + Hash, + Eq, + ProtoBuf_Enum, + EnumCountMacro, + EnumString, + EnumIter, + Display, + Serialize_repr, + Deserialize_repr, +)] +#[repr(u8)] +pub enum FieldType { + RichText = 0, + Number = 1, + DateTime = 2, + SingleSelect = 3, + MultiSelect = 4, + Checkbox = 5, + URL = 6, +} + +impl std::default::Default for FieldType { + fn default() -> Self { + FieldType::RichText + } +} + +impl AsRef for FieldType { + fn as_ref(&self) -> &FieldType { + self + } +} + +impl From<&FieldType> for FieldType { + fn from(field_type: &FieldType) -> Self { + field_type.clone() + } +} + +impl FieldType { + pub fn type_id(&self) -> String { + (self.clone() as u8).to_string() + } + + pub fn default_cell_width(&self) -> i32 { + match self { + FieldType::DateTime => 180, + _ => 150, + } + } + + pub fn is_number(&self) -> bool { + self == &FieldType::Number + } + + pub fn is_text(&self) -> bool { + self == &FieldType::RichText + } + + pub fn is_checkbox(&self) -> bool { + self == &FieldType::Checkbox + } + + pub fn is_date(&self) -> bool { + self == &FieldType::DateTime + } + + pub fn is_single_select(&self) -> bool { + self == &FieldType::SingleSelect + } + + pub fn is_multi_select(&self) -> bool { + self == &FieldType::MultiSelect + } + + pub fn is_url(&self) -> bool { + self == &FieldType::URL + } + + pub fn is_select_option(&self) -> bool { + self == &FieldType::MultiSelect || self == &FieldType::SingleSelect + } +} + +impl std::convert::From<&FieldType> for FieldTypeRevision { + fn from(ty: &FieldType) -> Self { + ty.clone() as u8 + } +} + +impl std::convert::From for FieldTypeRevision { + fn from(ty: FieldType) -> Self { + ty as u8 + } +} + +impl std::convert::From<&FieldTypeRevision> for FieldType { + fn from(ty: &FieldTypeRevision) -> Self { + FieldType::from(*ty) + } +} +impl std::convert::From for FieldType { + fn from(ty: FieldTypeRevision) -> Self { + match ty { + 0 => FieldType::RichText, + 1 => FieldType::Number, + 2 => FieldType::DateTime, + 3 => FieldType::SingleSelect, + 4 => FieldType::MultiSelect, + 5 => FieldType::Checkbox, + 6 => FieldType::URL, + _ => { + tracing::error!("Can't parser FieldTypeRevision: {} to FieldType", ty); + FieldType::RichText + } + } + } +} #[derive(Debug, Clone, Default, ProtoBuf)] pub struct FieldIdentifierPayload { #[pb(index = 1)] diff --git a/shared-lib/flowy-grid-data-model/src/entities/grid_filter.rs b/frontend/rust-lib/flowy-grid/src/entities/filter_entities.rs similarity index 71% rename from shared-lib/flowy-grid-data-model/src/entities/grid_filter.rs rename to frontend/rust-lib/flowy-grid/src/entities/filter_entities.rs index b6eda47d1e..747c7787a8 100644 --- a/shared-lib/flowy-grid-data-model/src/entities/grid_filter.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/filter_entities.rs @@ -1,10 +1,11 @@ -use crate::parser::NotEmptyStr; -use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; -use flowy_error_code::ErrorCode; - use crate::entities::FieldType; -use crate::revision::{FieldRevision, GridFilterRevision}; +use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; +use flowy_error::ErrorCode; +use flowy_grid_data_model::parser::NotEmptyStr; +use flowy_grid_data_model::revision::{FieldRevision, GridFilterRevision}; +use flowy_sync::entities::grid::{CreateGridFilterParams, DeleteFilterParams}; use std::convert::TryInto; +use std::sync::Arc; #[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)] pub struct GridFilter { @@ -18,14 +19,14 @@ pub struct RepeatedGridFilter { pub items: Vec, } -impl std::convert::From<&GridFilterRevision> for GridFilter { - fn from(rev: &GridFilterRevision) -> Self { +impl std::convert::From<&Arc> for GridFilter { + fn from(rev: &Arc) -> Self { Self { id: rev.id.clone() } } } -impl std::convert::From<&Vec> for RepeatedGridFilter { - fn from(revs: &Vec) -> Self { +impl std::convert::From<&Vec>> for RepeatedGridFilter { + fn from(revs: &Vec>) -> Self { RepeatedGridFilter { items: revs.iter().map(|rev| rev.into()).collect(), } @@ -38,6 +39,29 @@ impl std::convert::From> for RepeatedGridFilter { } } +#[derive(ProtoBuf, Debug, Default, Clone)] +pub struct DeleteFilterPayload { + #[pb(index = 1)] + pub filter_id: String, + + #[pb(index = 2)] + pub field_type: FieldType, +} + +impl TryInto for DeleteFilterPayload { + type Error = ErrorCode; + + fn try_into(self) -> Result { + let filter_id = NotEmptyStr::parse(self.filter_id) + .map_err(|_| ErrorCode::UnexpectedEmptyString)? + .0; + Ok(DeleteFilterParams { + filter_id, + field_type_rev: self.field_type.into(), + }) + } +} + #[derive(ProtoBuf, Debug, Default, Clone)] pub struct CreateGridFilterPayload { #[pb(index = 1)] @@ -58,20 +82,13 @@ impl CreateGridFilterPayload { pub fn new>(field_rev: &FieldRevision, condition: T, content: Option) -> Self { Self { field_id: field_rev.id.clone(), - field_type: field_rev.field_type.clone(), + field_type: field_rev.field_type_rev.into(), condition: condition.into(), content, } } } -pub struct CreateGridFilterParams { - pub field_id: String, - pub field_type: FieldType, - pub condition: u8, - pub content: Option, -} - impl TryInto for CreateGridFilterPayload { type Error = ErrorCode; @@ -81,9 +98,12 @@ impl TryInto for CreateGridFilterPayload { .0; let condition = self.condition as u8; match self.field_type { - FieldType::RichText | FieldType::Checkbox | FieldType::URL => { + FieldType::RichText | FieldType::URL => { let _ = TextFilterCondition::try_from(condition)?; } + FieldType::Checkbox => { + let _ = CheckboxCondition::try_from(condition)?; + } FieldType::Number => { let _ = NumberFilterCondition::try_from(condition)?; } @@ -97,7 +117,7 @@ impl TryInto for CreateGridFilterPayload { Ok(CreateGridFilterParams { field_id, - field_type: self.field_type, + field_type_rev: self.field_type.into(), condition, content: self.content, }) @@ -154,11 +174,11 @@ impl std::convert::TryFrom for TextFilterCondition { } } -impl std::convert::From for GridTextFilter { - fn from(rev: GridFilterRevision) -> Self { +impl std::convert::From> for GridTextFilter { + fn from(rev: Arc) -> Self { GridTextFilter { condition: TextFilterCondition::try_from(rev.condition).unwrap_or(TextFilterCondition::Is), - content: rev.content, + content: rev.content.clone(), } } } @@ -213,11 +233,11 @@ impl std::convert::TryFrom for NumberFilterCondition { } } -impl std::convert::From for GridNumberFilter { - fn from(rev: GridFilterRevision) -> Self { +impl std::convert::From> for GridNumberFilter { + fn from(rev: Arc) -> Self { GridNumberFilter { condition: NumberFilterCondition::try_from(rev.condition).unwrap_or(NumberFilterCondition::Equal), - content: rev.content, + content: rev.content.clone(), } } } @@ -266,11 +286,11 @@ impl std::convert::TryFrom for SelectOptionCondition { } } -impl std::convert::From for GridSelectOptionFilter { - fn from(rev: GridFilterRevision) -> Self { +impl std::convert::From> for GridSelectOptionFilter { + fn from(rev: Arc) -> Self { GridSelectOptionFilter { condition: SelectOptionCondition::try_from(rev.condition).unwrap_or(SelectOptionCondition::OptionIs), - content: rev.content, + content: rev.content.clone(), } } } @@ -318,11 +338,56 @@ impl std::convert::TryFrom for DateFilterCondition { } } } -impl std::convert::From for GridDateFilter { - fn from(rev: GridFilterRevision) -> Self { +impl std::convert::From> for GridDateFilter { + fn from(rev: Arc) -> Self { GridDateFilter { condition: DateFilterCondition::try_from(rev.condition).unwrap_or(DateFilterCondition::DateIs), - content: rev.content, + content: rev.content.clone(), + } + } +} + +#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)] +pub struct GridCheckboxFilter { + #[pb(index = 1)] + pub condition: CheckboxCondition, +} + +#[derive(Debug, Clone, PartialEq, Eq, ProtoBuf_Enum)] +#[repr(u8)] +pub enum CheckboxCondition { + IsChecked = 0, + IsUnChecked = 1, +} + +impl std::convert::From for i32 { + fn from(value: CheckboxCondition) -> Self { + value as i32 + } +} + +impl std::default::Default for CheckboxCondition { + fn default() -> Self { + CheckboxCondition::IsChecked + } +} + +impl std::convert::TryFrom for CheckboxCondition { + type Error = ErrorCode; + + fn try_from(value: u8) -> Result { + match value { + 0 => Ok(CheckboxCondition::IsChecked), + 1 => Ok(CheckboxCondition::IsUnChecked), + _ => Err(ErrorCode::InvalidData), + } + } +} + +impl std::convert::From> for GridCheckboxFilter { + fn from(rev: Arc) -> Self { + GridCheckboxFilter { + condition: CheckboxCondition::try_from(rev.condition).unwrap_or(CheckboxCondition::IsChecked), } } } diff --git a/frontend/rust-lib/flowy-grid/src/entities/grid_entities.rs b/frontend/rust-lib/flowy-grid/src/entities/grid_entities.rs new file mode 100644 index 0000000000..c05df11414 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/entities/grid_entities.rs @@ -0,0 +1,106 @@ +use crate::entities::{FieldOrder, GridBlock}; +use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; +use flowy_error::ErrorCode; +use flowy_grid_data_model::parser::NotEmptyStr; +#[derive(Debug, Clone, Default, ProtoBuf)] +pub struct Grid { + #[pb(index = 1)] + pub id: String, + + #[pb(index = 2)] + pub field_orders: Vec, + + #[pb(index = 3)] + pub blocks: Vec, +} + +#[derive(ProtoBuf, Default)] +pub struct CreateGridPayload { + #[pb(index = 1)] + pub name: String, +} + +#[derive(Clone, ProtoBuf, Default, Debug)] +pub struct GridId { + #[pb(index = 1)] + pub value: String, +} + +impl AsRef for GridId { + fn as_ref(&self) -> &str { + &self.value + } +} + +#[derive(Clone, ProtoBuf, Default, Debug)] +pub struct GridBlockId { + #[pb(index = 1)] + pub value: String, +} + +impl AsRef for GridBlockId { + fn as_ref(&self) -> &str { + &self.value + } +} + +impl std::convert::From<&str> for GridBlockId { + fn from(s: &str) -> Self { + GridBlockId { value: s.to_owned() } + } +} + +#[derive(Debug, Clone, ProtoBuf_Enum)] +pub enum MoveItemType { + MoveField = 0, + MoveRow = 1, +} + +impl std::default::Default for MoveItemType { + fn default() -> Self { + MoveItemType::MoveField + } +} + +#[derive(Debug, Clone, Default, ProtoBuf)] +pub struct MoveItemPayload { + #[pb(index = 1)] + pub grid_id: String, + + #[pb(index = 2)] + pub item_id: String, + + #[pb(index = 3)] + pub from_index: i32, + + #[pb(index = 4)] + pub to_index: i32, + + #[pb(index = 5)] + pub ty: MoveItemType, +} + +#[derive(Clone)] +pub struct MoveItemParams { + pub grid_id: String, + pub item_id: String, + pub from_index: i32, + pub to_index: i32, + pub ty: MoveItemType, +} + +impl TryInto for MoveItemPayload { + type Error = ErrorCode; + + fn try_into(self) -> Result { + let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?; + let item_id = NotEmptyStr::parse(self.item_id).map_err(|_| ErrorCode::InvalidData)?; + Ok(MoveItemParams { + grid_id: grid_id.0, + item_id: item_id.0, + from_index: self.from_index, + to_index: self.to_index, + ty: self.ty, + }) + } +} diff --git a/shared-lib/flowy-grid-data-model/src/entities/grid_group.rs b/frontend/rust-lib/flowy-grid/src/entities/group_entities.rs similarity index 90% rename from shared-lib/flowy-grid-data-model/src/entities/grid_group.rs rename to frontend/rust-lib/flowy-grid/src/entities/group_entities.rs index c12a0b6522..dc090e6ea1 100644 --- a/shared-lib/flowy-grid-data-model/src/entities/grid_group.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/group_entities.rs @@ -1,8 +1,8 @@ -use crate::parser::NotEmptyStr; use flowy_derive::ProtoBuf; -use flowy_error_code::ErrorCode; - -use crate::revision::GridGroupRevision; +use flowy_error::ErrorCode; +use flowy_grid_data_model::parser::NotEmptyStr; +use flowy_grid_data_model::revision::GridGroupRevision; +use flowy_sync::entities::grid::CreateGridGroupParams; use std::convert::TryInto; #[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)] @@ -56,11 +56,6 @@ pub struct CreateGridGroupPayload { pub sub_field_id: Option, } -pub struct CreateGridGroupParams { - pub field_id: Option, - pub sub_field_id: Option, -} - impl TryInto for CreateGridGroupPayload { type Error = ErrorCode; diff --git a/frontend/rust-lib/flowy-grid/src/entities/mod.rs b/frontend/rust-lib/flowy-grid/src/entities/mod.rs index 61bcf6ebed..96c7a9ba60 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/mod.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/mod.rs @@ -1,7 +1,19 @@ +mod block_entities; mod cell_entities; mod field_entities; +mod filter_entities; +mod grid_entities; +mod group_entities; mod row_entities; +mod setting_entities; +mod sort_entities; +pub use block_entities::*; pub use cell_entities::*; pub use field_entities::*; +pub use filter_entities::*; +pub use grid_entities::*; +pub use group_entities::*; pub use row_entities::*; +pub use setting_entities::*; +pub use sort_entities::*; diff --git a/frontend/rust-lib/flowy-grid/src/entities/row_entities.rs b/frontend/rust-lib/flowy-grid/src/entities/row_entities.rs index c97becbd34..146c7e9715 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/row_entities.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/row_entities.rs @@ -3,29 +3,77 @@ use flowy_error::ErrorCode; use flowy_grid_data_model::parser::NotEmptyStr; #[derive(ProtoBuf, Default)] -pub struct RowIdentifierPayload { +pub struct GridRowIdPayload { #[pb(index = 1)] pub grid_id: String, + #[pb(index = 2)] + pub block_id: String, + #[pb(index = 3)] pub row_id: String, } -pub struct RowIdentifier { +#[derive(Debug, Default, Clone, ProtoBuf)] +pub struct GridRowId { + #[pb(index = 1)] pub grid_id: String, + + #[pb(index = 2)] + pub block_id: String, + + #[pb(index = 3)] pub row_id: String, } -impl TryInto for RowIdentifierPayload { +impl TryInto for GridRowIdPayload { type Error = ErrorCode; - fn try_into(self) -> Result { + fn try_into(self) -> Result { let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?; + // let block_id = NotEmptyStr::parse(self.block_id).map_err(|_| ErrorCode::BlockIdIsEmpty)?; let row_id = NotEmptyStr::parse(self.row_id).map_err(|_| ErrorCode::RowIdIsEmpty)?; - Ok(RowIdentifier { + Ok(GridRowId { grid_id: grid_id.0, + block_id: self.block_id, row_id: row_id.0, }) } } + +#[derive(Debug, Default, Clone, ProtoBuf)] +pub struct BlockRowId { + #[pb(index = 1)] + pub block_id: String, + + #[pb(index = 2)] + pub row_id: String, +} + +#[derive(ProtoBuf, Default)] +pub struct CreateRowPayload { + #[pb(index = 1)] + pub grid_id: String, + + #[pb(index = 2, one_of)] + pub start_row_id: Option, +} + +#[derive(Default)] +pub struct CreateRowParams { + pub grid_id: String, + pub start_row_id: Option, +} + +impl TryInto for CreateRowPayload { + type Error = ErrorCode; + + fn try_into(self) -> Result { + let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?; + Ok(CreateRowParams { + grid_id: grid_id.0, + start_row_id: self.start_row_id, + }) + } +} diff --git a/shared-lib/flowy-grid-data-model/src/entities/grid_setting.rs b/frontend/rust-lib/flowy-grid/src/entities/setting_entities.rs similarity index 62% rename from shared-lib/flowy-grid-data-model/src/entities/grid_setting.rs rename to frontend/rust-lib/flowy-grid/src/entities/setting_entities.rs index 130f267c98..ce2d623b0c 100644 --- a/shared-lib/flowy-grid-data-model/src/entities/grid_setting.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/setting_entities.rs @@ -1,11 +1,12 @@ use crate::entities::{ - CreateGridFilterParams, CreateGridFilterPayload, CreateGridGroupParams, CreateGridGroupPayload, - CreateGridSortParams, CreateGridSortPayload, RepeatedGridFilter, RepeatedGridGroup, RepeatedGridSort, + CreateGridFilterPayload, CreateGridGroupPayload, CreateGridSortPayload, DeleteFilterPayload, RepeatedGridFilter, + RepeatedGridGroup, RepeatedGridSort, }; -use crate::parser::NotEmptyStr; -use crate::revision::{GridLayoutRevision, GridSettingRevision}; use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; -use flowy_error_code::ErrorCode; +use flowy_error::ErrorCode; +use flowy_grid_data_model::parser::NotEmptyStr; +use flowy_grid_data_model::revision::GridLayoutRevision; +use flowy_sync::entities::grid::GridSettingChangesetParams; use std::collections::HashMap; use std::convert::TryInto; @@ -21,34 +22,35 @@ pub struct GridSetting { pub sorts_by_layout_ty: HashMap, } -impl std::convert::From<&GridSettingRevision> for GridSetting { - fn from(rev: &GridSettingRevision) -> Self { - let filters_by_layout_ty: HashMap = rev - .filters - .iter() - .map(|(layout_rev, filter_revs)| (layout_rev.to_string(), filter_revs.into())) - .collect(); - - let groups_by_layout_ty: HashMap = rev - .groups - .iter() - .map(|(layout_rev, group_revs)| (layout_rev.to_string(), group_revs.into())) - .collect(); - - let sorts_by_layout_ty: HashMap = rev - .sorts - .iter() - .map(|(layout_rev, sort_revs)| (layout_rev.to_string(), sort_revs.into())) - .collect(); - - GridSetting { - filters_by_layout_ty, - groups_by_layout_ty, - sorts_by_layout_ty, - } - } -} - +// +// impl std::convert::From<&GridSettingRevision> for GridSetting { +// fn from(rev: &GridSettingRevision) -> Self { +// let filters_by_layout_ty: HashMap = rev +// .filters +// .iter() +// .map(|(layout_rev, filter_revs)| (layout_rev.to_string(), filter_revs.into())) +// .collect(); +// +// let groups_by_layout_ty: HashMap = rev +// .groups +// .iter() +// .map(|(layout_rev, group_revs)| (layout_rev.to_string(), group_revs.into())) +// .collect(); +// +// let sorts_by_layout_ty: HashMap = rev +// .sorts +// .iter() +// .map(|(layout_rev, sort_revs)| (layout_rev.to_string(), sort_revs.into())) +// .collect(); +// +// GridSetting { +// filters_by_layout_ty, +// groups_by_layout_ty, +// sorts_by_layout_ty, +// } +// } +// } +// #[derive(Debug, Clone, PartialEq, Eq, ProtoBuf_Enum)] #[repr(u8)] pub enum GridLayoutType { @@ -92,7 +94,7 @@ pub struct GridSettingChangesetPayload { pub insert_filter: Option, #[pb(index = 4, one_of)] - pub delete_filter: Option, + pub delete_filter: Option, #[pb(index = 5, one_of)] pub insert_group: Option, @@ -107,23 +109,6 @@ pub struct GridSettingChangesetPayload { pub delete_sort: Option, } -pub struct GridSettingChangesetParams { - pub grid_id: String, - pub layout_type: GridLayoutType, - pub insert_filter: Option, - pub delete_filter: Option, - pub insert_group: Option, - pub delete_group: Option, - pub insert_sort: Option, - pub delete_sort: Option, -} - -impl GridSettingChangesetParams { - pub fn is_filter_changed(&self) -> bool { - self.insert_filter.is_some() || self.delete_filter.is_some() - } -} - impl TryInto for GridSettingChangesetPayload { type Error = ErrorCode; @@ -139,7 +124,7 @@ impl TryInto for GridSettingChangesetPayload { let delete_filter = match self.delete_filter { None => None, - Some(filter_id) => Some(NotEmptyStr::parse(filter_id).map_err(|_| ErrorCode::FieldIdIsEmpty)?.0), + Some(payload) => Some(payload.try_into()?), }; let insert_group = match self.insert_group { @@ -164,7 +149,7 @@ impl TryInto for GridSettingChangesetPayload { Ok(GridSettingChangesetParams { grid_id: view_id, - layout_type: self.layout_type, + layout_type: self.layout_type.into(), insert_filter, delete_filter, insert_group, diff --git a/shared-lib/flowy-grid-data-model/src/entities/grid_sort.rs b/frontend/rust-lib/flowy-grid/src/entities/sort_entities.rs similarity index 89% rename from shared-lib/flowy-grid-data-model/src/entities/grid_sort.rs rename to frontend/rust-lib/flowy-grid/src/entities/sort_entities.rs index 4ebadb7036..1f03808fa8 100644 --- a/shared-lib/flowy-grid-data-model/src/entities/grid_sort.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/sort_entities.rs @@ -1,8 +1,8 @@ -use crate::parser::NotEmptyStr; use flowy_derive::ProtoBuf; -use flowy_error_code::ErrorCode; - -use crate::revision::GridSortRevision; +use flowy_error::ErrorCode; +use flowy_grid_data_model::parser::NotEmptyStr; +use flowy_grid_data_model::revision::GridSortRevision; +use flowy_sync::entities::grid::CreateGridSortParams; use std::convert::TryInto; #[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)] @@ -50,10 +50,6 @@ pub struct CreateGridSortPayload { pub field_id: Option, } -pub struct CreateGridSortParams { - pub field_id: Option, -} - impl TryInto for CreateGridSortPayload { type Error = ErrorCode; diff --git a/frontend/rust-lib/flowy-grid/src/event_handler.rs b/frontend/rust-lib/flowy-grid/src/event_handler.rs index 9a121e58bd..cbe43c8f82 100644 --- a/frontend/rust-lib/flowy-grid/src/event_handler.rs +++ b/frontend/rust-lib/flowy-grid/src/event_handler.rs @@ -3,8 +3,8 @@ use crate::manager::GridManager; use crate::services::field::type_options::*; use crate::services::field::{default_type_option_builder_from_type, type_option_builder_from_json_str}; use flowy_error::{ErrorCode, FlowyError, FlowyResult}; -use flowy_grid_data_model::entities::*; use flowy_grid_data_model::revision::FieldRevision; +use flowy_sync::entities::grid::{FieldChangesetParams, GridSettingChangesetParams}; use lib_dispatch::prelude::{data_result, AppData, Data, DataResult}; use std::sync::Arc; @@ -59,7 +59,12 @@ pub(crate) async fn get_fields_handler( ) -> DataResult { let params: QueryFieldParams = data.into_inner().try_into()?; let editor = manager.get_grid_editor(¶ms.grid_id)?; - let field_orders = params.field_orders.items; + let field_orders = params + .field_orders + .items + .into_iter() + .map(|field_order| field_order.field_id) + .collect(); let field_revs = editor.get_field_revs(Some(field_orders)).await?; let repeated_field: RepeatedField = field_revs.into_iter().map(Field::from).collect::>().into(); data_result(repeated_field) @@ -126,7 +131,7 @@ pub(crate) async fn switch_to_field_handler( let field_rev = editor .get_field_rev(¶ms.field_id) .await - .unwrap_or(editor.next_field_rev(¶ms.field_type).await?); + .unwrap_or(Arc::new(editor.next_field_rev(¶ms.field_type).await?)); let type_option_data = get_type_option_data(&field_rev, ¶ms.field_type).await?; let data = FieldTypeOptionData { @@ -160,7 +165,8 @@ pub(crate) async fn get_field_type_option_data_handler( match editor.get_field_rev(¶ms.field_id).await { None => Err(FlowyError::record_not_found()), Some(field_rev) => { - let type_option_data = get_type_option_data(&field_rev, &field_rev.field_type).await?; + let field_type = field_rev.field_type_rev.into(); + let type_option_data = get_type_option_data(&field_rev, &field_type).await?; let data = FieldTypeOptionData { grid_id: params.grid_id, field: field_rev.into(), @@ -180,7 +186,8 @@ pub(crate) async fn create_field_type_option_data_handler( let params: CreateFieldParams = data.into_inner().try_into()?; let editor = manager.get_grid_editor(¶ms.grid_id)?; let field_rev = editor.create_next_field_rev(¶ms.field_type).await?; - let type_option_data = get_type_option_data(&field_rev, &field_rev.field_type).await?; + let field_type: FieldType = field_rev.field_type_rev.into(); + let type_option_data = get_type_option_data(&field_rev, &field_type).await?; data_result(FieldTypeOptionData { grid_id: params.grid_id, @@ -205,7 +212,8 @@ async fn get_type_option_data(field_rev: &FieldRevision, field_type: &FieldType) let s = field_rev .get_type_option_str(field_type) .unwrap_or_else(|| default_type_option_builder_from_type(field_type).entry().json_str()); - let builder = type_option_builder_from_json_str(&s, &field_rev.field_type); + let field_type: FieldType = field_rev.field_type_rev.into(); + let builder = type_option_builder_from_json_str(&s, &field_type); let type_option_data = builder.entry().protobuf_bytes().to_vec(); Ok(type_option_data) @@ -213,10 +221,10 @@ async fn get_type_option_data(field_rev: &FieldRevision, field_type: &FieldType) #[tracing::instrument(level = "debug", skip(data, manager), err)] pub(crate) async fn get_row_handler( - data: Data, + data: Data, manager: AppData>, ) -> DataResult { - let params: RowIdentifier = data.into_inner().try_into()?; + let params: GridRowId = data.into_inner().try_into()?; let editor = manager.get_grid_editor(¶ms.grid_id)?; let row = OptionalRow { row: editor.get_row(¶ms.row_id).await?, @@ -226,10 +234,10 @@ pub(crate) async fn get_row_handler( #[tracing::instrument(level = "debug", skip(data, manager), err)] pub(crate) async fn delete_row_handler( - data: Data, + data: Data, manager: AppData>, ) -> Result<(), FlowyError> { - let params: RowIdentifier = data.into_inner().try_into()?; + let params: GridRowId = data.into_inner().try_into()?; let editor = manager.get_grid_editor(¶ms.grid_id)?; let _ = editor.delete_row(¶ms.row_id).await?; Ok(()) @@ -237,10 +245,10 @@ pub(crate) async fn delete_row_handler( #[tracing::instrument(level = "debug", skip(data, manager), err)] pub(crate) async fn duplicate_row_handler( - data: Data, + data: Data, manager: AppData>, ) -> Result<(), FlowyError> { - let params: RowIdentifier = data.into_inner().try_into()?; + let params: GridRowId = data.into_inner().try_into()?; let editor = manager.get_grid_editor(¶ms.grid_id)?; let _ = editor.duplicate_row(¶ms.row_id).await?; Ok(()) @@ -307,7 +315,8 @@ pub(crate) async fn update_select_option_handler( let editor = manager.get_grid_editor(&changeset.cell_identifier.grid_id)?; if let Some(mut field_rev) = editor.get_field_rev(&changeset.cell_identifier.field_id).await { - let mut type_option = select_option_operation(&field_rev)?; + let mut_field_rev = Arc::make_mut(&mut field_rev); + let mut type_option = select_option_operation(mut_field_rev)?; let mut cell_content_changeset = None; if let Some(option) = changeset.insert_option { @@ -324,7 +333,7 @@ pub(crate) async fn update_select_option_handler( type_option.delete_option(option); } - field_rev.insert_type_option_entry(&*type_option); + mut_field_rev.insert_type_option_entry(&*type_option); let _ = editor.replace_field(field_rev).await?; let changeset = CellChangeset { diff --git a/frontend/rust-lib/flowy-grid/src/event_map.rs b/frontend/rust-lib/flowy-grid/src/event_map.rs index f697f1e8d9..8739be5257 100644 --- a/frontend/rust-lib/flowy-grid/src/event_map.rs +++ b/frontend/rust-lib/flowy-grid/src/event_map.rs @@ -99,13 +99,13 @@ pub enum GridEvent { #[event(input = "CreateRowPayload", output = "Row")] CreateRow = 50, - #[event(input = "RowIdentifierPayload", output = "OptionalRow")] + #[event(input = "GridRowIdPayload", output = "OptionalRow")] GetRow = 51, - #[event(input = "RowIdentifierPayload")] + #[event(input = "GridRowIdPayload")] DeleteRow = 52, - #[event(input = "RowIdentifierPayload")] + #[event(input = "GridRowIdPayload")] DuplicateRow = 53, #[event(input = "CellIdentifierPayload", output = "Cell")] diff --git a/frontend/rust-lib/flowy-grid/src/macros.rs b/frontend/rust-lib/flowy-grid/src/macros.rs index 5d670aa6c3..8433964477 100644 --- a/frontend/rust-lib/flowy-grid/src/macros.rs +++ b/frontend/rust-lib/flowy-grid/src/macros.rs @@ -30,7 +30,16 @@ macro_rules! impl_type_option { ($target: ident, $field_type:expr) => { impl std::convert::From<&FieldRevision> for $target { fn from(field_rev: &FieldRevision) -> $target { - match field_rev.get_type_option_entry::<$target>(&$field_type) { + match field_rev.get_type_option_entry::<$target, _>(&$field_type) { + None => $target::default(), + Some(target) => target, + } + } + } + + impl std::convert::From<&std::sync::Arc> for $target { + fn from(field_rev: &std::sync::Arc) -> $target { + match field_rev.get_type_option_entry::<$target, _>(&$field_type) { None => $target::default(), Some(target) => target, } @@ -44,10 +53,6 @@ macro_rules! impl_type_option { } impl TypeOptionDataEntry for $target { - fn field_type(&self) -> FieldType { - $field_type - } - fn json_str(&self) -> String { match serde_json::to_string(&self) { Ok(s) => s, diff --git a/frontend/rust-lib/flowy-grid/src/services/block_manager.rs b/frontend/rust-lib/flowy-grid/src/services/block_manager.rs index a78f6fa37b..9594beab33 100644 --- a/frontend/rust-lib/flowy-grid/src/services/block_manager.rs +++ b/frontend/rust-lib/flowy-grid/src/services/block_manager.rs @@ -1,15 +1,13 @@ use crate::dart_notification::{send_dart_notification, GridNotification}; +use crate::entities::{BlockRowInfo, CellChangeset, GridRowId, GridRowsChangeset, IndexRowOrder, Row, UpdatedRowOrder}; use crate::manager::GridUser; use crate::services::block_revision_editor::GridBlockRevisionEditor; use crate::services::persistence::block_index::BlockIndexCache; use crate::services::row::{block_from_row_orders, GridBlockSnapshot}; use dashmap::DashMap; use flowy_error::FlowyResult; -use flowy_grid_data_model::entities::{ - CellChangeset, GridRowsChangeset, IndexRowOrder, Row, RowOrder, UpdatedRowOrder, -}; use flowy_grid_data_model::revision::{ - CellRevision, GridBlockMetaRevision, GridBlockMetaRevisionChangeset, RowMetaChangeset, RowRevision, + GridBlockMetaRevision, GridBlockMetaRevisionChangeset, RowMetaChangeset, RowRevision, }; use flowy_revision::disk::SQLiteGridBlockMetaRevisionPersistence; use flowy_revision::{RevisionManager, RevisionPersistence}; @@ -23,7 +21,7 @@ pub(crate) struct GridBlockManager { grid_id: String, user: Arc, persistence: Arc, - block_editor_map: DashMap>, + block_editors: DashMap>, } impl GridBlockManager { @@ -33,13 +31,13 @@ impl GridBlockManager { block_meta_revs: Vec>, persistence: Arc, ) -> FlowyResult { - let editor_map = make_block_meta_editor_map(user, block_meta_revs).await?; + let block_editors = make_block_editors(user, block_meta_revs).await?; let user = user.clone(); let grid_id = grid_id.to_owned(); let manager = Self { grid_id, user, - block_editor_map: editor_map, + block_editors, persistence, }; Ok(manager) @@ -48,11 +46,11 @@ impl GridBlockManager { // #[tracing::instrument(level = "trace", skip(self))] pub(crate) async fn get_editor(&self, block_id: &str) -> FlowyResult> { debug_assert!(!block_id.is_empty()); - match self.block_editor_map.get(block_id) { + match self.block_editors.get(block_id) { None => { tracing::error!("This is a fatal error, block with id:{} is not exist", block_id); - let editor = Arc::new(make_block_meta_editor(&self.user, block_id).await?); - self.block_editor_map.insert(block_id.to_owned(), editor.clone()); + let editor = Arc::new(make_block_editor(&self.user, block_id).await?); + self.block_editors.insert(block_id.to_owned(), editor.clone()); Ok(editor) } Some(editor) => Ok(editor.clone()), @@ -135,12 +133,18 @@ impl GridBlockManager { let row_id = row_id.to_owned(); let block_id = self.persistence.get_block_id(&row_id)?; let editor = self.get_editor(&block_id).await?; - match editor.get_row_order(&row_id).await? { + match editor.get_row_info(&row_id).await? { None => {} - Some(row_order) => { + Some(row_info) => { let _ = editor.delete_rows(vec![Cow::Borrowed(&row_id)]).await?; + + let row_identifier = GridRowId { + grid_id: self.grid_id.clone(), + block_id: row_info.block_id, + row_id: row_info.row_id, + }; let _ = self - .notify_did_update_block(&block_id, GridRowsChangeset::delete(&block_id, vec![row_order])) + .notify_did_update_block(&block_id, GridRowsChangeset::delete(&block_id, vec![row_identifier])) .await?; } } @@ -150,18 +154,18 @@ impl GridBlockManager { pub(crate) async fn delete_rows( &self, - row_orders: Vec, + row_orders: Vec, ) -> FlowyResult> { let mut changesets = vec![]; - for block_order in block_from_row_orders(row_orders) { - let editor = self.get_editor(&block_order.id).await?; - let row_ids = block_order - .row_orders + for grid_block in block_from_row_orders(row_orders) { + let editor = self.get_editor(&grid_block.id).await?; + let row_ids = grid_block + .row_infos .into_iter() - .map(|row_order| Cow::Owned(row_order.row_id)) + .map(|row_info| Cow::Owned(row_info.row_id().to_owned())) .collect::>>(); let row_count = editor.delete_rows(row_ids).await?; - let changeset = GridBlockMetaRevisionChangeset::from_row_count(&block_order.id, row_count); + let changeset = GridBlockMetaRevisionChangeset::from_row_count(&grid_block.id, row_count); changesets.push(changeset); } @@ -175,15 +179,21 @@ impl GridBlockManager { match editor.get_row_revs(Some(vec![Cow::Borrowed(row_id)])).await?.pop() { None => {} Some(row_rev) => { - let row_order = RowOrder::from(&row_rev); + let row_info = BlockRowInfo::from(&row_rev); let insert_row = IndexRowOrder { - row_order: row_order.clone(), + row_info: row_info.clone(), index: Some(to as i32), }; + + let deleted_row = GridRowId { + grid_id: self.grid_id.clone(), + block_id: row_info.block_id, + row_id: row_info.row_id, + }; let notified_changeset = GridRowsChangeset { block_id: editor.block_id.clone(), inserted_rows: vec![insert_row], - deleted_rows: vec![row_order], + deleted_rows: vec![deleted_row], updated_rows: vec![], }; @@ -217,38 +227,36 @@ impl GridBlockManager { } } - pub async fn get_row_orders(&self, block_id: &str) -> FlowyResult> { + pub async fn get_row_orders(&self, block_id: &str) -> FlowyResult> { let editor = self.get_editor(block_id).await?; - editor.get_row_orders::<&str>(None).await + editor.get_row_infos::<&str>(None).await } - pub(crate) async fn make_block_snapshots(&self, block_ids: Vec) -> FlowyResult> { + pub(crate) async fn get_block_snapshots( + &self, + block_ids: Option>, + ) -> FlowyResult> { let mut snapshots = vec![]; - for block_id in block_ids { - let editor = self.get_editor(&block_id).await?; - let row_revs = editor.get_row_revs::<&str>(None).await?; - snapshots.push(GridBlockSnapshot { block_id, row_revs }); + match block_ids { + None => { + for iter in self.block_editors.iter() { + let editor = iter.value(); + let block_id = editor.block_id.clone(); + let row_revs = editor.get_row_revs::<&str>(None).await?; + snapshots.push(GridBlockSnapshot { block_id, row_revs }); + } + } + Some(block_ids) => { + for block_id in block_ids { + let editor = self.get_editor(&block_id).await?; + let row_revs = editor.get_row_revs::<&str>(None).await?; + snapshots.push(GridBlockSnapshot { block_id, row_revs }); + } + } } Ok(snapshots) } - // Optimization: Using the shared memory(Arc, Cow,etc.) to reduce memory usage. - #[allow(dead_code)] - pub async fn get_cell_revs( - &self, - block_ids: Vec, - field_id: &str, - row_ids: Option>>, - ) -> FlowyResult> { - let mut block_cell_revs = vec![]; - for block_id in block_ids { - let editor = self.get_editor(&block_id).await?; - let cell_revs = editor.get_cell_revs(field_id, row_ids.clone()).await?; - block_cell_revs.extend(cell_revs); - } - Ok(block_cell_revs) - } - async fn notify_did_update_block(&self, block_id: &str, changeset: GridRowsChangeset) -> FlowyResult<()> { send_dart_notification(block_id, GridNotification::DidUpdateGridBlock) .payload(changeset) @@ -263,20 +271,20 @@ impl GridBlockManager { } } -async fn make_block_meta_editor_map( +async fn make_block_editors( user: &Arc, block_meta_revs: Vec>, ) -> FlowyResult>> { let editor_map = DashMap::new(); for block_meta_rev in block_meta_revs { - let editor = make_block_meta_editor(user, &block_meta_rev.block_id).await?; + let editor = make_block_editor(user, &block_meta_rev.block_id).await?; editor_map.insert(block_meta_rev.block_id.clone(), Arc::new(editor)); } Ok(editor_map) } -async fn make_block_meta_editor(user: &Arc, block_id: &str) -> FlowyResult { +async fn make_block_editor(user: &Arc, block_id: &str) -> FlowyResult { tracing::trace!("Open block:{} meta editor", block_id); let token = user.token()?; let user_id = user.user_id()?; diff --git a/frontend/rust-lib/flowy-grid/src/services/block_revision_editor.rs b/frontend/rust-lib/flowy-grid/src/services/block_revision_editor.rs index 6546b71b2e..6506b0a367 100644 --- a/frontend/rust-lib/flowy-grid/src/services/block_revision_editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/block_revision_editor.rs @@ -1,6 +1,6 @@ +use crate::entities::BlockRowInfo; use bytes::Bytes; use flowy_error::{FlowyError, FlowyResult}; -use flowy_grid_data_model::entities::RowOrder; use flowy_grid_data_model::revision::{CellRevision, GridBlockRevision, RowMetaChangeset, RowRevision}; use flowy_revision::{RevisionCloudService, RevisionCompactor, RevisionManager, RevisionObjectBuilder}; use flowy_sync::client_grid::{GridBlockMetaChange, GridBlockRevisionPad}; @@ -123,24 +123,24 @@ impl GridBlockRevisionEditor { Ok(cell_revs) } - pub async fn get_row_order(&self, row_id: &str) -> FlowyResult> { + pub async fn get_row_info(&self, row_id: &str) -> FlowyResult> { let row_ids = Some(vec![Cow::Borrowed(row_id)]); - Ok(self.get_row_orders(row_ids).await?.pop()) + Ok(self.get_row_infos(row_ids).await?.pop()) } - pub async fn get_row_orders(&self, row_ids: Option>>) -> FlowyResult> + pub async fn get_row_infos(&self, row_ids: Option>>) -> FlowyResult> where T: AsRef + ToOwned + ?Sized, { - let row_orders = self + let row_infos = self .pad .read() .await .get_row_revs(row_ids)? .iter() - .map(RowOrder::from) - .collect::>(); - Ok(row_orders) + .map(BlockRowInfo::from) + .collect::>(); + Ok(row_infos) } async fn modify(&self, f: F) -> FlowyResult<()> diff --git a/frontend/rust-lib/flowy-grid/src/services/field/field_builder.rs b/frontend/rust-lib/flowy-grid/src/services/field/field_builder.rs index 12b665a62b..352d3e7f5c 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/field_builder.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/field_builder.rs @@ -1,6 +1,6 @@ +use crate::entities::{Field, FieldType}; use crate::services::field::type_options::*; use bytes::Bytes; -use flowy_grid_data_model::entities::{Field, FieldType}; use flowy_grid_data_model::revision::{FieldRevision, TypeOptionDataEntry}; use indexmap::IndexMap; @@ -14,7 +14,9 @@ pub type BoxTypeOptionBuilder = Box; impl FieldBuilder { pub fn new>(type_option_builder: T) -> Self { let type_option_builder = type_option_builder.into(); - let field_rev = FieldRevision::new("", "", type_option_builder.field_type(), false); + let field_type = type_option_builder.field_type(); + let width = field_type.default_cell_width(); + let field_rev = FieldRevision::new("", "", field_type, width, false); Self { field_rev, type_option_builder, @@ -31,7 +33,7 @@ impl FieldBuilder { id: field.id, name: field.name, desc: field.desc, - field_type: field.field_type, + field_type_rev: field.field_type.into(), frozen: field.frozen, visibility: field.visibility, width: field.width, @@ -75,7 +77,6 @@ impl FieldBuilder { } pub fn build(self) -> FieldRevision { - debug_assert_eq!(self.field_rev.field_type, self.type_option_builder.field_type()); let mut field_rev = self.field_rev; field_rev.insert_type_option_entry(self.type_option_builder.entry()); field_rev diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option.rs index 7558b0a010..807f3d1fb7 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option.rs @@ -1,10 +1,10 @@ +use crate::entities::{FieldType, GridCheckboxFilter}; use crate::impl_type_option; use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder}; use crate::services::row::{CellContentChangeset, CellDataOperation, DecodedCellData}; use bytes::Bytes; use flowy_derive::ProtoBuf; use flowy_error::{FlowyError, FlowyResult}; -use flowy_grid_data_model::entities::FieldType; use flowy_grid_data_model::revision::{CellRevision, FieldRevision, TypeOptionDataDeserializer, TypeOptionDataEntry}; use serde::{Deserialize, Serialize}; @@ -22,7 +22,7 @@ impl CheckboxTypeOptionBuilder { impl TypeOptionBuilder for CheckboxTypeOptionBuilder { fn field_type(&self) -> FieldType { - self.0.field_type() + FieldType::Checkbox } fn entry(&self) -> &dyn TypeOptionDataEntry { @@ -40,7 +40,7 @@ impl_type_option!(CheckboxTypeOption, FieldType::Checkbox); const YES: &str = "Yes"; const NO: &str = "No"; -impl CellDataOperation for CheckboxTypeOption { +impl CellDataOperation for CheckboxTypeOption { fn decode_cell_data( &self, encoded_data: T, @@ -62,6 +62,10 @@ impl CellDataOperation for CheckboxTypeOption { Ok(DecodedCellData::default()) } + fn apply_filter(&self, _filter: GridCheckboxFilter) -> bool { + todo!() + } + fn apply_changeset(&self, changeset: C, _cell_rev: Option) -> Result where C: Into, @@ -95,7 +99,7 @@ mod tests { use crate::services::field::FieldBuilder; use crate::services::row::{apply_cell_data_changeset, decode_cell_data}; - use flowy_grid_data_model::entities::FieldType; + use crate::entities::FieldType; #[test] fn checkout_box_description_test() { diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs index 9dcf88e2aa..a0bfd33cd2 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs @@ -1,3 +1,4 @@ +use crate::entities::{CellChangeset, FieldType, GridDateFilter}; use crate::entities::{CellIdentifier, CellIdentifierPayload}; use crate::impl_type_option; use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder}; @@ -7,7 +8,6 @@ use chrono::format::strftime::StrftimeItems; use chrono::{NaiveDateTime, Timelike}; use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; use flowy_error::{ErrorCode, FlowyError, FlowyResult}; -use flowy_grid_data_model::entities::{CellChangeset, FieldType}; use flowy_grid_data_model::revision::{CellRevision, FieldRevision, TypeOptionDataDeserializer, TypeOptionDataEntry}; use serde::{Deserialize, Serialize}; use strum_macros::EnumIter; @@ -115,7 +115,7 @@ impl DateTypeOption { } } -impl CellDataOperation for DateTypeOption { +impl CellDataOperation for DateTypeOption { fn decode_cell_data( &self, encoded_data: T, @@ -138,6 +138,10 @@ impl CellDataOperation for DateTypeOption { DecodedCellData::try_from_bytes(date) } + fn apply_filter(&self, _filter: GridDateFilter) -> bool { + todo!() + } + fn apply_changeset(&self, changeset: C, _cell_rev: Option) -> Result where C: Into, @@ -177,7 +181,7 @@ impl DateTypeOptionBuilder { } impl TypeOptionBuilder for DateTypeOptionBuilder { fn field_type(&self) -> FieldType { - self.0.field_type() + FieldType::DateTime } fn entry(&self) -> &dyn TypeOptionDataEntry { @@ -354,11 +358,11 @@ impl std::convert::From for CellContentChangeset { #[cfg(test)] mod tests { + use crate::entities::FieldType; use crate::services::field::FieldBuilder; use crate::services::field::{DateCellContentChangeset, DateCellData, DateFormat, DateTypeOption, TimeFormat}; use crate::services::row::CellDataOperation; - use flowy_grid_data_model::entities::FieldType; - use flowy_grid_data_model::revision::{FieldRevision, TypeOptionDataEntry}; + use flowy_grid_data_model::revision::FieldRevision; use strum::IntoEnumIterator; #[test] @@ -530,7 +534,7 @@ mod tests { fn date_type_option_apply_changeset_error_test() { let mut type_option = DateTypeOption::new(); type_option.include_time = true; - let field_rev = FieldBuilder::from_field_type(&type_option.field_type()).build(); + let field_rev = FieldBuilder::from_field_type(&FieldType::DateTime).build(); let date_timestamp = "1653609600".to_owned(); assert_changeset_result( @@ -539,7 +543,7 @@ mod tests { date: Some(date_timestamp.clone()), time: Some("1:".to_owned()), }, - &type_option.field_type(), + &FieldType::DateTime, &field_rev, "May 27,2022 01:00", ); @@ -550,7 +554,7 @@ mod tests { date: Some(date_timestamp), time: Some("1:00".to_owned()), }, - &type_option.field_type(), + &FieldType::DateTime, &field_rev, "May 27,2022 01:00", ); @@ -561,7 +565,7 @@ mod tests { fn date_type_option_twelve_hours_to_twenty_four_hours() { let mut type_option = DateTypeOption::new(); type_option.include_time = true; - let field_rev = FieldBuilder::from_field_type(&type_option.field_type()).build(); + let field_rev = FieldBuilder::from_field_type(&FieldType::DateTime).build(); let date_timestamp = "1653609600".to_owned(); assert_changeset_result( @@ -570,7 +574,7 @@ mod tests { date: Some(date_timestamp), time: Some("1:00 am".to_owned()), }, - &type_option.field_type(), + &FieldType::DateTime, &field_rev, "May 27,2022 01:00", ); diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/format.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/format.rs index 149404fa9f..00de383096 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/format.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/format.rs @@ -15,7 +15,7 @@ lazy_static! { #[derive(Clone, Copy, Debug, PartialEq, Eq, EnumIter, Serialize, Deserialize, ProtoBuf_Enum)] pub enum NumberFormat { - Number = 0, + Num = 0, USD = 1, CanadianDollar = 2, EUR = 4, @@ -55,7 +55,7 @@ pub enum NumberFormat { impl std::default::Default for NumberFormat { fn default() -> Self { - NumberFormat::Number + NumberFormat::Num } } @@ -400,7 +400,7 @@ define_currency_set!( impl NumberFormat { pub fn currency(&self) -> &'static number_currency::Currency { match self { - NumberFormat::Number => number_currency::NUMBER, + NumberFormat::Num => number_currency::NUMBER, NumberFormat::USD => number_currency::USD, NumberFormat::CanadianDollar => number_currency::CANADIAN_DOLLAR, NumberFormat::EUR => number_currency::EUR, diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_type_option.rs index 6a7600f8fb..f912879ad9 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_type_option.rs @@ -1,12 +1,12 @@ use crate::impl_type_option; +use crate::entities::{FieldType, GridNumberFilter}; use crate::services::field::type_options::number_type_option::format::*; use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder}; use crate::services::row::{CellContentChangeset, CellDataOperation, DecodedCellData}; use bytes::Bytes; use flowy_derive::ProtoBuf; use flowy_error::{FlowyError, FlowyResult}; -use flowy_grid_data_model::entities::FieldType; use flowy_grid_data_model::revision::{CellRevision, FieldRevision, TypeOptionDataDeserializer, TypeOptionDataEntry}; use rust_decimal::Decimal; use serde::{Deserialize, Serialize}; @@ -41,7 +41,7 @@ impl NumberTypeOptionBuilder { impl TypeOptionBuilder for NumberTypeOptionBuilder { fn field_type(&self) -> FieldType { - self.0.field_type() + FieldType::Number } fn entry(&self) -> &dyn TypeOptionDataEntry { @@ -76,7 +76,7 @@ impl NumberTypeOption { fn cell_content_from_number_str(&self, s: &str) -> FlowyResult { match self.format { - NumberFormat::Number => { + NumberFormat::Num => { if let Ok(v) = s.parse::() { return Ok(v.to_string()); } @@ -139,7 +139,7 @@ impl NumberTypeOption { } } -impl CellDataOperation for NumberTypeOption { +impl CellDataOperation for NumberTypeOption { fn decode_cell_data( &self, encoded_data: T, @@ -155,7 +155,7 @@ impl CellDataOperation for NumberTypeOption { let cell_data = encoded_data.into(); match self.format { - NumberFormat::Number => { + NumberFormat::Num => { if let Ok(v) = cell_data.parse::() { return Ok(DecodedCellData::new(v.to_string())); } @@ -179,6 +179,10 @@ impl CellDataOperation for NumberTypeOption { } } + fn apply_filter(&self, _filter: GridNumberFilter) -> bool { + todo!() + } + fn apply_changeset(&self, changeset: C, _cell_rev: Option) -> Result where C: Into, @@ -206,10 +210,10 @@ impl std::default::Default for NumberTypeOption { #[cfg(test)] mod tests { + use crate::entities::FieldType; use crate::services::field::FieldBuilder; use crate::services::field::{NumberFormat, NumberTypeOption}; use crate::services::row::CellDataOperation; - use flowy_grid_data_model::entities::FieldType; use flowy_grid_data_model::revision::FieldRevision; use strum::IntoEnumIterator; @@ -241,7 +245,7 @@ mod tests { for format in NumberFormat::iter() { type_option.format = format; match format { - NumberFormat::Number => { + NumberFormat::Num => { assert_equal(&type_option, "18443", "18443", &field_type, &field_rev); } NumberFormat::USD => { @@ -270,7 +274,7 @@ mod tests { for format in NumberFormat::iter() { type_option.format = format; match format { - NumberFormat::Number => { + NumberFormat::Num => { assert_equal(&type_option, "18443", "18443", &field_type, &field_rev); assert_equal(&type_option, "0.2", "0.2", &field_type, &field_rev); } @@ -310,7 +314,7 @@ mod tests { for format in NumberFormat::iter() { type_option.format = format; match format { - NumberFormat::Number => { + NumberFormat::Num => { assert_equal(&type_option, "18443", "18443", &field_type, &field_rev); } NumberFormat::USD => { diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option.rs index 9988a60864..f4e0bd24e2 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option.rs @@ -1,3 +1,4 @@ +use crate::entities::{CellChangeset, FieldType, GridSelectOptionFilter}; use crate::entities::{CellIdentifier, CellIdentifierPayload}; use crate::impl_type_option; use crate::services::field::type_options::util::get_cell_data; @@ -6,7 +7,6 @@ use crate::services::row::{CellContentChangeset, CellDataOperation, DecodedCellD use bytes::Bytes; use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; use flowy_error::{ErrorCode, FlowyError, FlowyResult}; -use flowy_grid_data_model::entities::{CellChangeset, FieldType}; use flowy_grid_data_model::parser::NotEmptyStr; use flowy_grid_data_model::revision::{CellRevision, FieldRevision, TypeOptionDataDeserializer, TypeOptionDataEntry}; use nanoid::nanoid; @@ -49,7 +49,8 @@ pub trait SelectOptionOperation: TypeOptionDataEntry + Send + Sync { } pub fn select_option_operation(field_rev: &FieldRevision) -> FlowyResult> { - match &field_rev.field_type { + let field_type: FieldType = field_rev.field_type_rev.into(); + match &field_type { FieldType::SingleSelect => { let type_option = SingleSelectTypeOption::from(field_rev); Ok(Box::new(type_option)) @@ -94,7 +95,7 @@ impl SelectOptionOperation for SingleSelectTypeOption { } } -impl CellDataOperation for SingleSelectTypeOption { +impl CellDataOperation for SingleSelectTypeOption { fn decode_cell_data( &self, encoded_data: T, @@ -122,6 +123,10 @@ impl CellDataOperation for SingleSelectTypeOption { DecodedCellData::try_from_bytes(cell_data) } + fn apply_filter(&self, _filter: GridSelectOptionFilter) -> bool { + todo!() + } + fn apply_changeset(&self, changeset: C, _cell_rev: Option) -> Result where C: Into, @@ -155,7 +160,7 @@ impl SingleSelectTypeOptionBuilder { impl TypeOptionBuilder for SingleSelectTypeOptionBuilder { fn field_type(&self) -> FieldType { - self.0.field_type() + FieldType::SingleSelect } fn entry(&self) -> &dyn TypeOptionDataEntry { @@ -192,7 +197,7 @@ impl SelectOptionOperation for MultiSelectTypeOption { } } -impl CellDataOperation for MultiSelectTypeOption { +impl CellDataOperation for MultiSelectTypeOption { fn decode_cell_data( &self, encoded_data: T, @@ -220,6 +225,10 @@ impl CellDataOperation for MultiSelectTypeOption { DecodedCellData::try_from_bytes(cell_data) } + fn apply_filter(&self, _filter: GridSelectOptionFilter) -> bool { + todo!() + } + fn apply_changeset(&self, changeset: T, cell_rev: Option) -> Result where T: Into, @@ -269,7 +278,7 @@ impl MultiSelectTypeOptionBuilder { impl TypeOptionBuilder for MultiSelectTypeOptionBuilder { fn field_type(&self) -> FieldType { - self.0.field_type() + FieldType::MultiSelect } fn entry(&self) -> &dyn TypeOptionDataEntry { @@ -502,6 +511,7 @@ fn make_select_context_from(cell_rev: &Option, options: &[SelectOp #[cfg(test)] mod tests { + use crate::entities::FieldType; use crate::services::field::FieldBuilder; use crate::services::field::{ MultiSelectTypeOption, MultiSelectTypeOptionBuilder, SelectOption, SelectOptionCellContentChangeset, @@ -606,10 +616,11 @@ mod tests { field_rev: &FieldRevision, expected: Vec, ) { + let field_type: FieldType = field_rev.field_type_rev.into(); assert_eq!( expected, type_option - .decode_cell_data(cell_data, &field_rev.field_type, field_rev) + .decode_cell_data(cell_data, &field_type, field_rev) .unwrap() .parse::() .unwrap() @@ -623,10 +634,11 @@ mod tests { field_rev: &FieldRevision, expected: Vec, ) { + let field_type: FieldType = field_rev.field_type_rev.into(); assert_eq!( expected, type_option - .decode_cell_data(cell_data, &field_rev.field_type, field_rev) + .decode_cell_data(cell_data, &field_type, field_rev) .unwrap() .parse::() .unwrap() diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option.rs index 0fb2d4e48d..2d9a9d129e 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option.rs @@ -1,10 +1,10 @@ +use crate::entities::{FieldType, GridTextFilter}; use crate::impl_type_option; use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder}; use crate::services::row::{try_decode_cell_data, CellContentChangeset, CellDataOperation, DecodedCellData}; use bytes::Bytes; use flowy_derive::ProtoBuf; use flowy_error::{FlowyError, FlowyResult}; -use flowy_grid_data_model::entities::FieldType; use flowy_grid_data_model::revision::{CellRevision, FieldRevision, TypeOptionDataDeserializer, TypeOptionDataEntry}; use serde::{Deserialize, Serialize}; @@ -15,7 +15,7 @@ impl_builder_from_json_str_and_from_bytes!(RichTextTypeOptionBuilder, RichTextTy impl TypeOptionBuilder for RichTextTypeOptionBuilder { fn field_type(&self) -> FieldType { - self.0.field_type() + FieldType::RichText } fn entry(&self) -> &dyn TypeOptionDataEntry { @@ -30,7 +30,7 @@ pub struct RichTextTypeOption { } impl_type_option!(RichTextTypeOption, FieldType::RichText); -impl CellDataOperation for RichTextTypeOption { +impl CellDataOperation for RichTextTypeOption { fn decode_cell_data( &self, encoded_data: T, @@ -45,13 +45,17 @@ impl CellDataOperation for RichTextTypeOption { || decoded_field_type.is_multi_select() || decoded_field_type.is_number() { - try_decode_cell_data(encoded_data, field_rev, decoded_field_type, decoded_field_type) + try_decode_cell_data(encoded_data.into(), field_rev, decoded_field_type, decoded_field_type) } else { let cell_data = encoded_data.into(); Ok(DecodedCellData::new(cell_data)) } } + fn apply_filter(&self, _filter: GridTextFilter) -> bool { + todo!() + } + fn apply_changeset(&self, changeset: C, _cell_rev: Option) -> Result where C: Into, @@ -67,10 +71,10 @@ impl CellDataOperation for RichTextTypeOption { #[cfg(test)] mod tests { + use crate::entities::FieldType; use crate::services::field::FieldBuilder; use crate::services::field::*; use crate::services::row::CellDataOperation; - use flowy_grid_data_model::entities::FieldType; #[test] fn text_description_test() { diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option.rs index eef90655c2..beb0ce623a 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option.rs @@ -1,3 +1,4 @@ +use crate::entities::{FieldType, GridTextFilter}; use crate::impl_type_option; use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder}; use crate::services::row::{CellContentChangeset, CellDataOperation, DecodedCellData, EncodedCellData}; @@ -5,7 +6,6 @@ use bytes::Bytes; use fancy_regex::Regex; use flowy_derive::ProtoBuf; use flowy_error::{internal_error, FlowyError, FlowyResult}; -use flowy_grid_data_model::entities::FieldType; use flowy_grid_data_model::revision::{CellRevision, FieldRevision, TypeOptionDataDeserializer, TypeOptionDataEntry}; use lazy_static::lazy_static; use serde::{Deserialize, Serialize}; @@ -18,7 +18,7 @@ impl_builder_from_json_str_and_from_bytes!(URLTypeOptionBuilder, URLTypeOption); impl TypeOptionBuilder for URLTypeOptionBuilder { fn field_type(&self) -> FieldType { - self.0.field_type() + FieldType::URL } fn entry(&self) -> &dyn TypeOptionDataEntry { @@ -33,7 +33,7 @@ pub struct URLTypeOption { } impl_type_option!(URLTypeOption, FieldType::URL); -impl CellDataOperation> for URLTypeOption { +impl CellDataOperation, GridTextFilter> for URLTypeOption { fn decode_cell_data( &self, encoded_data: T, @@ -50,6 +50,10 @@ impl CellDataOperation> for URLTypeOption { DecodedCellData::try_from_bytes(cell_data) } + fn apply_filter(&self, _filter: GridTextFilter) -> bool { + todo!() + } + fn apply_changeset(&self, changeset: C, _cell_rev: Option) -> Result where C: Into, @@ -122,10 +126,10 @@ lazy_static! { #[cfg(test)] mod tests { + use crate::entities::FieldType; use crate::services::field::FieldBuilder; use crate::services::field::{URLCellData, URLTypeOption}; use crate::services::row::{CellDataOperation, EncodedCellData}; - use flowy_grid_data_model::entities::FieldType; use flowy_grid_data_model::revision::FieldRevision; #[test] diff --git a/frontend/rust-lib/flowy-grid/src/services/filter/filter_service.rs b/frontend/rust-lib/flowy-grid/src/services/filter/filter_service.rs index c22c154600..54e2984bd9 100644 --- a/frontend/rust-lib/flowy-grid/src/services/filter/filter_service.rs +++ b/frontend/rust-lib/flowy-grid/src/services/filter/filter_service.rs @@ -1,58 +1,293 @@ -use crate::manager::GridTaskSchedulerRwLock; +use crate::entities::{ + FieldType, GridCheckboxFilter, GridDateFilter, GridNumberFilter, GridSelectOptionFilter, GridTextFilter, +}; use crate::services::block_manager::GridBlockManager; -use crate::services::tasks::Task; +use crate::services::grid_editor_task::GridServiceTaskScheduler; +use crate::services::row::GridBlockSnapshot; +use crate::services::tasks::{FilterTaskContext, Task, TaskContent}; use flowy_error::FlowyResult; - +use flowy_grid_data_model::revision::{CellRevision, FieldId, FieldRevision, RowRevision}; use flowy_sync::client_grid::GridRevisionPad; +use flowy_sync::entities::grid::GridSettingChangesetParams; +use std::collections::HashMap; use std::sync::Arc; use tokio::sync::RwLock; pub(crate) struct GridFilterService { #[allow(dead_code)] - scheduler: GridTaskSchedulerRwLock, - #[allow(dead_code)] + grid_id: String, + scheduler: Arc, grid_pad: Arc>, - #[allow(dead_code)] block_manager: Arc, + filter_cache: Arc>, + filter_result_cache: Arc>, } impl GridFilterService { - pub fn new( + pub async fn new( grid_pad: Arc>, block_manager: Arc, - scheduler: GridTaskSchedulerRwLock, + scheduler: S, ) -> Self { + let grid_id = grid_pad.read().await.grid_id(); + let filter_cache = Arc::new(RwLock::new(FilterCache::from_grid_pad(&grid_pad).await)); + let filter_result_cache = Arc::new(RwLock::new(FilterResultCache::default())); Self { + grid_id, grid_pad, block_manager, - scheduler, + scheduler: Arc::new(scheduler), + filter_cache, + filter_result_cache, } } - pub async fn process_task(&self, _task: Task) -> FlowyResult<()> { + pub async fn process(&self, task_context: FilterTaskContext) -> FlowyResult<()> { + let field_revs = self + .grid_pad + .read() + .await + .get_field_revs(None)? + .into_iter() + .map(|field_rev| (field_rev.id.clone(), field_rev)) + .collect::>>(); + + let mut show_rows = vec![]; + let mut hide_rows = vec![]; + for block in task_context.blocks { + block.row_revs.iter().for_each(|row_rev| { + let result = filter_row(row_rev, &self.filter_cache, &self.filter_result_cache, &field_revs); + + if result.is_row_hidden() { + hide_rows.push(result.row_id); + } else { + show_rows.push(result.row_id); + } + }); + } + self.notify(hide_rows, show_rows).await; Ok(()) } - pub async fn notify_changed(&self) { - // - // let grid_pad = self.grid_pad.read().await; - // match grid_pad.get_filters(None) { - // None => {} - // Some(filter_revs) => { - // filter_revs - // .iter() - // .for_each(|filter_rev| match grid_pad.get_field_rev(&filter_rev.field_id) { - // None => {} - // Some((_, _field_rev)) => match field_rev.field_type { - // FieldType::RichText => {} - // FieldType::Number => {} - // FieldType::DateTime => {} - // FieldType::SingleSelect => {} - // FieldType::MultiSelect => {} - // FieldType::Checkbox => {} - // FieldType::URL => {} - // }, - // }); - // } - // } + pub async fn apply_changeset(&self, changeset: GridFilterChangeset) { + if !changeset.is_changed() { + return; + } + + if let Some(filter_id) = &changeset.insert_filter { + let mut cache = self.filter_cache.write().await; + let field_ids = Some(vec![filter_id.field_id.clone()]); + reload_filter_cache(&mut cache, field_ids, &self.grid_pad).await; + } + + if let Some(filter_id) = &changeset.delete_filter { + self.filter_cache.write().await.remove(filter_id); + } + + if let Ok(blocks) = self.block_manager.get_block_snapshots(None).await { + let task = self.gen_task(blocks).await; + let _ = self.scheduler.register_task(task).await; + } + } + + async fn gen_task(&self, blocks: Vec) -> Task { + let task_id = self.scheduler.gen_task_id().await; + let handler_id = self.grid_pad.read().await.grid_id(); + + let context = FilterTaskContext { blocks }; + Task { + handler_id, + id: task_id, + content: TaskContent::Filter(context), + } + } + + async fn notify(&self, _hide_rows: Vec, _show_rows: Vec) { + // let notification = GridNotification {}; + // send_dart_notification(grid_id, GridNotification::DidUpdateGridBlock) + // .payload(notification) + // .send(); + } +} + +fn filter_row( + row_rev: &Arc, + _filter_cache: &Arc>, + _filter_result_cache: &Arc>, + _field_revs: &HashMap>, +) -> FilterResult { + let filter_result = FilterResult::new(row_rev); + row_rev.cells.iter().for_each(|(_k, cell_rev)| { + let _cell_rev: &CellRevision = cell_rev; + }); + filter_result +} + +pub struct GridFilterChangeset { + insert_filter: Option, + delete_filter: Option, +} + +impl GridFilterChangeset { + fn is_changed(&self) -> bool { + self.insert_filter.is_some() || self.delete_filter.is_some() + } +} + +impl std::convert::From<&GridSettingChangesetParams> for GridFilterChangeset { + fn from(params: &GridSettingChangesetParams) -> Self { + let insert_filter = params.insert_filter.as_ref().map(|insert_filter_params| FilterId { + field_id: insert_filter_params.field_id.clone(), + field_type: insert_filter_params.field_type_rev.into(), + }); + + let delete_filter = params.delete_filter.as_ref().map(|delete_filter_params| FilterId { + field_id: delete_filter_params.filter_id.clone(), + field_type: delete_filter_params.field_type_rev.into(), + }); + GridFilterChangeset { + insert_filter, + delete_filter, + } + } +} + +#[derive(Default)] +struct FilterResultCache { + #[allow(dead_code)] + rows: HashMap, +} + +impl FilterResultCache { + #[allow(dead_code)] + fn insert(&mut self, row_id: &str, result: FilterResult) { + self.rows.insert(row_id.to_owned(), result); + } +} + +#[derive(Default)] +struct FilterResult { + row_id: String, + #[allow(dead_code)] + cell_by_field_id: HashMap, +} + +impl FilterResult { + fn new(row_rev: &RowRevision) -> Self { + Self { + row_id: row_rev.id.clone(), + cell_by_field_id: row_rev.cells.iter().map(|(k, _)| (k.clone(), true)).collect(), + } + } + + #[allow(dead_code)] + fn update_cell(&mut self, cell_id: &str, exist: bool) { + self.cell_by_field_id.insert(cell_id.to_owned(), exist); + } + + fn is_row_hidden(&self) -> bool { + todo!() + } +} + +#[derive(Default)] +struct FilterCache { + text_filter: HashMap, + url_filter: HashMap, + number_filter: HashMap, + date_filter: HashMap, + select_option_filter: HashMap, + checkbox_filter: HashMap, +} + +impl FilterCache { + async fn from_grid_pad(grid_pad: &Arc>) -> Self { + let mut this = Self::default(); + let _ = reload_filter_cache(&mut this, None, grid_pad).await; + this + } + + fn remove(&mut self, filter_id: &FilterId) { + let _ = match filter_id.field_type { + FieldType::RichText => { + let _ = self.text_filter.remove(filter_id); + } + FieldType::Number => { + let _ = self.number_filter.remove(filter_id); + } + FieldType::DateTime => { + let _ = self.date_filter.remove(filter_id); + } + FieldType::SingleSelect => { + let _ = self.select_option_filter.remove(filter_id); + } + FieldType::MultiSelect => { + let _ = self.select_option_filter.remove(filter_id); + } + FieldType::Checkbox => { + let _ = self.checkbox_filter.remove(filter_id); + } + FieldType::URL => { + let _ = self.url_filter.remove(filter_id); + } + }; + } +} + +async fn reload_filter_cache( + cache: &mut FilterCache, + field_ids: Option>, + grid_pad: &Arc>, +) { + let grid_pad = grid_pad.read().await; + let filters_revs = grid_pad.get_filters(None, field_ids).unwrap_or_default(); + + for filter_rev in filters_revs { + match grid_pad.get_field_rev(&filter_rev.field_id) { + None => {} + Some((_, field_rev)) => { + let filter_id = FilterId::from(field_rev); + let field_type: FieldType = field_rev.field_type_rev.into(); + match &field_type { + FieldType::RichText => { + let _ = cache.text_filter.insert(filter_id, GridTextFilter::from(filter_rev)); + } + FieldType::Number => { + let _ = cache + .number_filter + .insert(filter_id, GridNumberFilter::from(filter_rev)); + } + FieldType::DateTime => { + let _ = cache.date_filter.insert(filter_id, GridDateFilter::from(filter_rev)); + } + FieldType::SingleSelect | FieldType::MultiSelect => { + let _ = cache + .select_option_filter + .insert(filter_id, GridSelectOptionFilter::from(filter_rev)); + } + FieldType::Checkbox => { + let _ = cache + .checkbox_filter + .insert(filter_id, GridCheckboxFilter::from(filter_rev)); + } + FieldType::URL => { + let _ = cache.url_filter.insert(filter_id, GridTextFilter::from(filter_rev)); + } + } + } + } + } +} +#[derive(Hash, Eq, PartialEq)] +struct FilterId { + field_id: String, + field_type: FieldType, +} + +impl std::convert::From<&Arc> for FilterId { + fn from(rev: &Arc) -> Self { + Self { + field_id: rev.id.clone(), + field_type: rev.field_type_rev.into(), + } } } diff --git a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs index 97e36566b4..d973b8a190 100644 --- a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs @@ -3,16 +3,17 @@ use crate::entities::CellIdentifier; use crate::manager::{GridTaskSchedulerRwLock, GridUser}; use crate::services::block_manager::GridBlockManager; use crate::services::field::{default_type_option_builder_from_type, type_option_builder_from_bytes, FieldBuilder}; -use crate::services::filter::GridFilterService; +use crate::services::filter::{GridFilterChangeset, GridFilterService}; use crate::services::persistence::block_index::BlockIndexCache; use crate::services::row::*; +use crate::entities::*; use bytes::Bytes; use flowy_error::{ErrorCode, FlowyError, FlowyResult}; -use flowy_grid_data_model::entities::*; use flowy_grid_data_model::revision::*; use flowy_revision::{RevisionCloudService, RevisionCompactor, RevisionManager, RevisionObjectBuilder}; use flowy_sync::client_grid::{GridChangeset, GridRevisionPad, JsonDeserializer}; +use flowy_sync::entities::grid::{FieldChangesetParams, GridSettingChangesetParams}; use flowy_sync::entities::revision::Revision; use flowy_sync::errors::CollaborateResult; use flowy_sync::util::make_delta_from_revisions; @@ -53,11 +54,8 @@ impl GridRevisionEditor { let grid_pad = Arc::new(RwLock::new(grid_pad)); let block_meta_revs = grid_pad.read().await.get_block_meta_revs(); let block_manager = Arc::new(GridBlockManager::new(grid_id, &user, block_meta_revs, persistence).await?); - let filter_service = Arc::new(GridFilterService::new( - grid_pad.clone(), - block_manager.clone(), - task_scheduler.clone(), - )); + let filter_service = + Arc::new(GridFilterService::new(grid_pad.clone(), block_manager.clone(), task_scheduler.clone()).await); let editor = Arc::new(Self { grid_id: grid_id.to_owned(), user, @@ -87,7 +85,7 @@ impl GridRevisionEditor { grid_id, name: Some(field.name), desc: Some(field.desc), - field_type: Some(field.field_type), + field_type: Some(field.field_type.into()), frozen: Some(field.frozen), visibility: Some(field.visibility), width: Some(field.width), @@ -126,7 +124,8 @@ impl GridRevisionEditor { let field_rev = result.unwrap(); let _ = self .modify(|grid| { - let deserializer = TypeOptionJsonDeserializer(field_rev.field_type.clone()); + let field_type = field_rev.field_type_rev.into(); + let deserializer = TypeOptionJsonDeserializer(field_type); let changeset = FieldChangesetParams { field_id: field_id.to_owned(), grid_id: grid_id.to_owned(), @@ -164,7 +163,7 @@ impl GridRevisionEditor { let field_id = params.field_id.clone(); let json_deserializer = match self.grid_pad.read().await.get_field_rev(params.field_id.as_str()) { None => return Err(ErrorCode::FieldDoesNotExist.into()), - Some((_, field_rev)) => TypeOptionJsonDeserializer(field_rev.field_type.clone()), + Some((_, field_rev)) => TypeOptionJsonDeserializer(field_rev.field_type_rev.into()), }; let _ = self @@ -175,7 +174,7 @@ impl GridRevisionEditor { Ok(()) } - pub async fn replace_field(&self, field_rev: FieldRevision) -> FlowyResult<()> { + pub async fn replace_field(&self, field_rev: Arc) -> FlowyResult<()> { let field_id = field_rev.id.clone(); let _ = self .modify(|grid_pad| Ok(grid_pad.replace_field_rev(field_rev)?)) @@ -204,8 +203,9 @@ impl GridRevisionEditor { // .get_cell_revs(block_ids, field_id, None) // .await?; - let type_option_json_builder = |field_type: &FieldType| -> String { - return default_type_option_builder_from_type(field_type).entry().json_str(); + let type_option_json_builder = |field_type: &FieldTypeRevision| -> String { + let field_type: FieldType = field_type.into(); + return default_type_option_builder_from_type(&field_type).entry().json_str(); }; let _ = self @@ -227,24 +227,20 @@ impl GridRevisionEditor { Ok(()) } - pub async fn get_field_rev(&self, field_id: &str) -> Option { + pub async fn get_field_rev(&self, field_id: &str) -> Option> { let field_rev = self.grid_pad.read().await.get_field_rev(field_id)?.1.clone(); Some(field_rev) } - pub async fn get_field_revs(&self, field_ids: Option>) -> FlowyResult> - where - T: Into, - { + pub async fn get_field_revs(&self, field_ids: Option>) -> FlowyResult>> { if field_ids.is_none() { let field_revs = self.grid_pad.read().await.get_field_revs(None)?; return Ok(field_revs); } - let to_field_orders = |item: Vec| item.into_iter().map(|data| data.into()).collect(); - let field_orders = field_ids.map_or(vec![], to_field_orders); - let expected_len = field_orders.len(); - let field_revs = self.grid_pad.read().await.get_field_revs(Some(field_orders))?; + let field_ids = field_ids.unwrap_or_default(); + let expected_len = field_ids.len(); + let field_revs = self.grid_pad.read().await.get_field_revs(Some(field_ids))?; if expected_len != 0 && field_revs.len() != expected_len { tracing::error!( "This is a bug. The len of the field_revs should equal to {}", @@ -269,14 +265,14 @@ impl GridRevisionEditor { Ok(()) } - pub async fn create_row(&self, start_row_id: Option) -> FlowyResult { + pub async fn create_row(&self, start_row_id: Option) -> FlowyResult { let field_revs = self.grid_pad.read().await.get_field_revs(None)?; let block_id = self.block_id().await?; // insert empty row below the row whose id is upper_row_id let row_rev_ctx = CreateRowRevisionBuilder::new(&field_revs).build(); let row_rev = make_row_rev_from_context(&block_id, row_rev_ctx); - let row_order = RowOrder::from(&row_rev); + let row_order = BlockRowInfo::from(&row_rev); // insert the row let row_count = self.block_manager.create_row(&block_id, row_rev, start_row_id).await?; @@ -287,13 +283,13 @@ impl GridRevisionEditor { Ok(row_order) } - pub async fn insert_rows(&self, contexts: Vec) -> FlowyResult> { + pub async fn insert_rows(&self, contexts: Vec) -> FlowyResult> { let block_id = self.block_id().await?; let mut rows_by_block_id: HashMap> = HashMap::new(); let mut row_orders = vec![]; for ctx in contexts { let row_rev = make_row_rev_from_context(&block_id, ctx); - row_orders.push(RowOrder::from(&row_rev)); + row_orders.push(BlockRowInfo::from(&row_rev)); rows_by_block_id .entry(block_id.clone()) .or_insert_with(Vec::new) @@ -307,7 +303,7 @@ impl GridRevisionEditor { } pub async fn update_row(&self, changeset: RowMetaChangeset) -> FlowyResult<()> { - let field_revs = self.get_field_revs::(None).await?; + let field_revs = self.get_field_revs(None).await?; self.block_manager .update_row(changeset, |row_rev| make_row_from_row_rev(&field_revs, row_rev)) .await @@ -322,7 +318,7 @@ impl GridRevisionEditor { debug_assert_eq!(grid_block_snapshot.len(), 1); if grid_block_snapshot.len() == 1 { let snapshot = grid_block_snapshot.pop().unwrap(); - let field_revs = self.get_field_revs::(None).await?; + let field_revs = self.get_field_revs(None).await?; let rows = make_rows_from_row_revs(&field_revs, &snapshot.row_revs); Ok(rows.into()) } else { @@ -334,7 +330,7 @@ impl GridRevisionEditor { match self.block_manager.get_row_rev(row_id).await? { None => Ok(None), Some(row_rev) => { - let field_revs = self.get_field_revs::(None).await?; + let field_revs = self.get_field_revs(None).await?; let row_revs = vec![row_rev]; let mut rows = make_rows_from_row_revs(&field_revs, &row_revs); debug_assert!(rows.len() == 1); @@ -399,7 +395,7 @@ impl GridRevisionEditor { cell_rev, field_rev, )?); - let field_revs = self.get_field_revs::(None).await?; + let field_revs = self.get_field_revs(None).await?; let cell_changeset = CellChangeset { grid_id, row_id, @@ -425,7 +421,7 @@ impl GridRevisionEditor { Ok(block_meta_revs) } - pub async fn delete_rows(&self, row_orders: Vec) -> FlowyResult<()> { + pub async fn delete_rows(&self, row_orders: Vec) -> FlowyResult<()> { let changesets = self.block_manager.delete_rows(row_orders).await?; for changeset in changesets { let _ = self.update_block(changeset).await?; @@ -435,13 +431,17 @@ impl GridRevisionEditor { pub async fn get_grid_data(&self) -> FlowyResult { let pad_read_guard = self.grid_pad.read().await; - let field_orders = pad_read_guard.get_field_orders(); + let field_orders = pad_read_guard + .get_field_revs(None)? + .iter() + .map(FieldOrder::from) + .collect(); let mut block_orders = vec![]; for block_rev in pad_read_guard.get_block_meta_revs() { let row_orders = self.block_manager.get_row_orders(&block_rev.block_id).await?; let block_order = GridBlock { id: block_rev.block_id.clone(), - row_orders, + row_infos: row_orders, }; block_orders.push(block_order); } @@ -454,29 +454,31 @@ impl GridRevisionEditor { } pub async fn get_grid_setting(&self) -> FlowyResult { - let read_guard = self.grid_pad.read().await; - let grid_setting_rev = read_guard.get_grid_setting_rev(); - Ok(grid_setting_rev.into()) + // let read_guard = self.grid_pad.read().await; + // let grid_setting_rev = read_guard.get_grid_setting_rev(); + // Ok(grid_setting_rev.into()) + todo!() } pub async fn get_grid_filter(&self, layout_type: &GridLayoutType) -> FlowyResult> { let read_guard = self.grid_pad.read().await; let layout_rev = layout_type.clone().into(); - match read_guard.get_filters(Some(&layout_rev)) { + match read_guard.get_filters(Some(&layout_rev), None) { Some(filter_revs) => Ok(filter_revs.iter().map(GridFilter::from).collect::>()), None => Ok(vec![]), } } pub async fn update_grid_setting(&self, params: GridSettingChangesetParams) -> FlowyResult<()> { - let is_filter_changed = params.is_filter_changed(); + let filter_changeset = GridFilterChangeset::from(¶ms); let _ = self .modify(|grid_pad| Ok(grid_pad.update_grid_setting_rev(params)?)) .await?; - if is_filter_changed { - self.filter_service.notify_changed().await; - } + let filter_service = self.filter_service.clone(); + tokio::spawn(async move { + filter_service.apply_changeset(filter_changeset).await; + }); Ok(()) } @@ -492,7 +494,7 @@ impl GridRevisionEditor { .collect::>(), Some(block_ids) => block_ids, }; - let snapshots = self.block_manager.make_block_snapshots(block_ids).await?; + let snapshots = self.block_manager.get_block_snapshots(Some(block_ids)).await?; Ok(snapshots) } diff --git a/frontend/rust-lib/flowy-grid/src/services/grid_editor_task.rs b/frontend/rust-lib/flowy-grid/src/services/grid_editor_task.rs index 965cc0839e..1b3a364833 100644 --- a/frontend/rust-lib/flowy-grid/src/services/grid_editor_task.rs +++ b/frontend/rust-lib/flowy-grid/src/services/grid_editor_task.rs @@ -1,9 +1,15 @@ +use crate::manager::GridTaskSchedulerRwLock; use crate::services::grid_editor::GridRevisionEditor; -use crate::services::tasks::{GridTaskHandler, Task, TaskContent, TaskHandlerId}; +use crate::services::tasks::{GridTaskHandler, Task, TaskContent, TaskHandlerId, TaskId}; use flowy_error::FlowyError; - +use futures::future::BoxFuture; use lib_infra::future::BoxResultFuture; +pub(crate) trait GridServiceTaskScheduler: Send + Sync + 'static { + fn gen_task_id(&self) -> BoxFuture; + fn register_task(&self, task: Task) -> BoxFuture<()>; +} + impl GridTaskHandler for GridRevisionEditor { fn handler_id(&self) -> &TaskHandlerId { &self.grid_id @@ -11,11 +17,25 @@ impl GridTaskHandler for GridRevisionEditor { fn process_task(&self, task: Task) -> BoxResultFuture<(), FlowyError> { Box::pin(async move { - match &task.content { - TaskContent::Snapshot { .. } => {} - TaskContent::Filter => self.filter_service.process_task(task).await?, + match task.content { + TaskContent::Snapshot => {} + TaskContent::Filter(context) => self.filter_service.process(context).await?, } Ok(()) }) } } + +impl GridServiceTaskScheduler for GridTaskSchedulerRwLock { + fn gen_task_id(&self) -> BoxFuture { + let this = self.clone(); + Box::pin(async move { this.read().await.next_task_id() }) + } + + fn register_task(&self, task: Task) -> BoxFuture<()> { + let this = self.clone(); + Box::pin(async move { + this.write().await.register_task(task); + }) + } +} diff --git a/frontend/rust-lib/flowy-grid/src/services/row/cell_data_operation.rs b/frontend/rust-lib/flowy-grid/src/services/row/cell_data_operation.rs index aaa7300046..99787f8550 100644 --- a/frontend/rust-lib/flowy-grid/src/services/row/cell_data_operation.rs +++ b/frontend/rust-lib/flowy-grid/src/services/row/cell_data_operation.rs @@ -1,13 +1,13 @@ +use crate::entities::FieldType; use crate::services::field::*; use bytes::Bytes; use flowy_error::{internal_error, ErrorCode, FlowyError, FlowyResult}; -use flowy_grid_data_model::entities::FieldType; use flowy_grid_data_model::revision::{CellRevision, FieldRevision}; use serde::{Deserialize, Serialize}; use std::fmt::Formatter; use std::str::FromStr; -pub trait CellDataOperation { +pub trait CellDataOperation { fn decode_cell_data( &self, encoded_data: T, @@ -15,9 +15,10 @@ pub trait CellDataOperation { field_rev: &FieldRevision, ) -> FlowyResult where - T: Into; + T: Into; + + fn apply_filter(&self, filter: F) -> bool; - // fn apply_changeset>( &self, changeset: C, @@ -115,12 +116,14 @@ impl TypeOptionCellData { /// The changeset will be deserialized into specific data base on the FieldType. /// For example, it's String on FieldType::RichText, and SelectOptionChangeset on FieldType::SingleSelect -pub fn apply_cell_data_changeset>( - changeset: T, +pub fn apply_cell_data_changeset, T: AsRef>( + changeset: C, cell_rev: Option, - field_rev: &FieldRevision, + field_rev: T, ) -> Result { - let s = match field_rev.field_type { + let field_rev = field_rev.as_ref(); + let field_type = field_rev.field_type_rev.into(); + let s = match field_type { FieldType::RichText => RichTextTypeOption::from(field_rev).apply_changeset(changeset, cell_rev), FieldType::Number => NumberTypeOption::from(field_rev).apply_changeset(changeset, cell_rev), FieldType::DateTime => DateTypeOption::from(field_rev).apply_changeset(changeset, cell_rev), @@ -130,14 +133,14 @@ pub fn apply_cell_data_changeset>( FieldType::URL => URLTypeOption::from(field_rev).apply_changeset(changeset, cell_rev), }?; - Ok(TypeOptionCellData::new(s, field_rev.field_type.clone()).json()) + Ok(TypeOptionCellData::new(s, field_type).json()) } pub fn decode_cell_data>(data: T, field_rev: &FieldRevision) -> DecodedCellData { if let Ok(type_option_cell_data) = data.try_into() { let TypeOptionCellData { data, field_type } = type_option_cell_data; - let to_field_type = &field_rev.field_type; - match try_decode_cell_data(data, field_rev, &field_type, to_field_type) { + let to_field_type = field_rev.field_type_rev.into(); + match try_decode_cell_data(data, field_rev, &field_type, &to_field_type) { Ok(cell_data) => cell_data, Err(e) => { tracing::error!("Decode cell data failed, {:?}", e); @@ -150,35 +153,34 @@ pub fn decode_cell_data>(data: T, field_rev: &Fie } } -pub fn try_decode_cell_data>( - encoded_data: T, +pub fn try_decode_cell_data( + encoded_data: String, field_rev: &FieldRevision, s_field_type: &FieldType, t_field_type: &FieldType, ) -> FlowyResult { - let encoded_data = encoded_data.into(); let get_cell_data = || { let data = match t_field_type { FieldType::RichText => field_rev - .get_type_option_entry::(t_field_type)? + .get_type_option_entry::(t_field_type)? .decode_cell_data(encoded_data, s_field_type, field_rev), FieldType::Number => field_rev - .get_type_option_entry::(t_field_type)? + .get_type_option_entry::(t_field_type)? .decode_cell_data(encoded_data, s_field_type, field_rev), FieldType::DateTime => field_rev - .get_type_option_entry::(t_field_type)? + .get_type_option_entry::(t_field_type)? .decode_cell_data(encoded_data, s_field_type, field_rev), FieldType::SingleSelect => field_rev - .get_type_option_entry::(t_field_type)? + .get_type_option_entry::(t_field_type)? .decode_cell_data(encoded_data, s_field_type, field_rev), FieldType::MultiSelect => field_rev - .get_type_option_entry::(t_field_type)? + .get_type_option_entry::(t_field_type)? .decode_cell_data(encoded_data, s_field_type, field_rev), FieldType::Checkbox => field_rev - .get_type_option_entry::(t_field_type)? + .get_type_option_entry::(t_field_type)? .decode_cell_data(encoded_data, s_field_type, field_rev), FieldType::URL => field_rev - .get_type_option_entry::(t_field_type)? + .get_type_option_entry::(t_field_type)? .decode_cell_data(encoded_data, s_field_type, field_rev), }; Some(data) diff --git a/frontend/rust-lib/flowy-grid/src/services/row/mod.rs b/frontend/rust-lib/flowy-grid/src/services/row/mod.rs index f9bf130e8b..e2727cdf34 100644 --- a/frontend/rust-lib/flowy-grid/src/services/row/mod.rs +++ b/frontend/rust-lib/flowy-grid/src/services/row/mod.rs @@ -1,6 +1,5 @@ mod cell_data_operation; mod row_builder; -pub mod row_entities; mod row_loader; pub use cell_data_operation::*; diff --git a/frontend/rust-lib/flowy-grid/src/services/row/row_builder.rs b/frontend/rust-lib/flowy-grid/src/services/row/row_builder.rs index 83301b3fb2..568c8ed12a 100644 --- a/frontend/rust-lib/flowy-grid/src/services/row/row_builder.rs +++ b/frontend/rust-lib/flowy-grid/src/services/row/row_builder.rs @@ -4,18 +4,19 @@ use flowy_error::{FlowyError, FlowyResult}; use flowy_grid_data_model::revision::{gen_row_id, CellRevision, FieldRevision, RowRevision, DEFAULT_ROW_HEIGHT}; use indexmap::IndexMap; use std::collections::HashMap; +use std::sync::Arc; pub struct CreateRowRevisionBuilder<'a> { - field_rev_map: HashMap<&'a String, &'a FieldRevision>, + field_rev_map: HashMap<&'a String, &'a Arc>, payload: CreateRowRevisionPayload, } impl<'a> CreateRowRevisionBuilder<'a> { - pub fn new(fields: &'a [FieldRevision]) -> Self { + pub fn new(fields: &'a [Arc]) -> Self { let field_rev_map = fields .iter() .map(|field| (&field.id, field)) - .collect::>(); + .collect::>>(); let payload = CreateRowRevisionPayload { row_id: gen_row_id(), diff --git a/frontend/rust-lib/flowy-grid/src/services/row/row_entities.rs b/frontend/rust-lib/flowy-grid/src/services/row/row_entities.rs deleted file mode 100644 index c97becbd34..0000000000 --- a/frontend/rust-lib/flowy-grid/src/services/row/row_entities.rs +++ /dev/null @@ -1,31 +0,0 @@ -use flowy_derive::ProtoBuf; -use flowy_error::ErrorCode; -use flowy_grid_data_model::parser::NotEmptyStr; - -#[derive(ProtoBuf, Default)] -pub struct RowIdentifierPayload { - #[pb(index = 1)] - pub grid_id: String, - - #[pb(index = 3)] - pub row_id: String, -} - -pub struct RowIdentifier { - pub grid_id: String, - pub row_id: String, -} - -impl TryInto for RowIdentifierPayload { - type Error = ErrorCode; - - fn try_into(self) -> Result { - let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?; - let row_id = NotEmptyStr::parse(self.row_id).map_err(|_| ErrorCode::RowIdIsEmpty)?; - - Ok(RowIdentifier { - grid_id: grid_id.0, - row_id: row_id.0, - }) - } -} diff --git a/frontend/rust-lib/flowy-grid/src/services/row/row_loader.rs b/frontend/rust-lib/flowy-grid/src/services/row/row_loader.rs index 1c88442aac..96da30e574 100644 --- a/frontend/rust-lib/flowy-grid/src/services/row/row_loader.rs +++ b/frontend/rust-lib/flowy-grid/src/services/row/row_loader.rs @@ -1,5 +1,5 @@ +use crate::entities::{BlockRowInfo, GridBlock, RepeatedGridBlock, Row}; use flowy_error::FlowyResult; -use flowy_grid_data_model::entities::{GridBlock, RepeatedGridBlock, Row, RowOrder}; use flowy_grid_data_model::revision::{FieldRevision, RowRevision}; use std::collections::HashMap; use std::sync::Arc; @@ -9,15 +9,16 @@ pub struct GridBlockSnapshot { pub row_revs: Vec>, } -pub(crate) fn block_from_row_orders(row_orders: Vec) -> Vec { +pub(crate) fn block_from_row_orders(row_orders: Vec) -> Vec { let mut map: HashMap = HashMap::new(); - row_orders.into_iter().for_each(|row_order| { + row_orders.into_iter().for_each(|row_info| { // Memory Optimization: escape clone block_id - let block_id = row_order.block_id.clone(); + let block_id = row_info.block_id().to_owned(); + let cloned_block_id = block_id.clone(); map.entry(block_id) - .or_insert_with(|| GridBlock::new(&row_order.block_id, vec![])) - .row_orders - .push(row_order); + .or_insert_with(|| GridBlock::new(&cloned_block_id, vec![])) + .row_infos + .push(row_info); }); map.into_values().collect::>() } @@ -34,15 +35,15 @@ pub(crate) fn block_from_row_orders(row_orders: Vec) -> Vec // Some((field_id, cell)) // } -pub(crate) fn make_row_orders_from_row_revs(row_revs: &[Arc]) -> Vec { - row_revs.iter().map(RowOrder::from).collect::>() +pub(crate) fn make_row_orders_from_row_revs(row_revs: &[Arc]) -> Vec { + row_revs.iter().map(BlockRowInfo::from).collect::>() } -pub(crate) fn make_row_from_row_rev(fields: &[FieldRevision], row_rev: Arc) -> Option { +pub(crate) fn make_row_from_row_rev(fields: &[Arc], row_rev: Arc) -> Option { make_rows_from_row_revs(fields, &[row_rev]).pop() } -pub(crate) fn make_rows_from_row_revs(_fields: &[FieldRevision], row_revs: &[Arc]) -> Vec { +pub(crate) fn make_rows_from_row_revs(_fields: &[Arc], row_revs: &[Arc]) -> Vec { // let field_rev_map = fields // .iter() // .map(|field_rev| (&field_rev.id, field_rev)) diff --git a/frontend/rust-lib/flowy-grid/src/services/setting/setting_builder.rs b/frontend/rust-lib/flowy-grid/src/services/setting/setting_builder.rs index 7edb779d15..866b0a51e6 100644 --- a/frontend/rust-lib/flowy-grid/src/services/setting/setting_builder.rs +++ b/frontend/rust-lib/flowy-grid/src/services/setting/setting_builder.rs @@ -1,4 +1,5 @@ -use flowy_grid_data_model::entities::{CreateGridFilterParams, GridLayoutType, GridSettingChangesetParams}; +use crate::entities::GridLayoutType; +use flowy_sync::entities::grid::{CreateGridFilterParams, DeleteFilterParams, GridSettingChangesetParams}; pub struct GridSettingChangesetBuilder { params: GridSettingChangesetParams, @@ -8,7 +9,7 @@ impl GridSettingChangesetBuilder { pub fn new(grid_id: &str, layout_type: &GridLayoutType) -> Self { let params = GridSettingChangesetParams { grid_id: grid_id.to_string(), - layout_type: layout_type.clone(), + layout_type: layout_type.clone().into(), insert_filter: None, delete_filter: None, insert_group: None, @@ -24,8 +25,8 @@ impl GridSettingChangesetBuilder { self } - pub fn delete_filter(mut self, filter_id: &str) -> Self { - self.params.delete_filter = Some(filter_id.to_string()); + pub fn delete_filter(mut self, params: DeleteFilterParams) -> Self { + self.params.delete_filter = Some(params); self } diff --git a/frontend/rust-lib/flowy-grid/src/services/tasks/queue.rs b/frontend/rust-lib/flowy-grid/src/services/tasks/queue.rs index 2c86d6606c..537f789f9b 100644 --- a/frontend/rust-lib/flowy-grid/src/services/tasks/queue.rs +++ b/frontend/rust-lib/flowy-grid/src/services/tasks/queue.rs @@ -21,8 +21,8 @@ impl GridTaskQueue { pub(crate) fn push(&mut self, task: &Task) { let task_type = match task.content { - TaskContent::Snapshot { .. } => TaskType::Snapshot, - TaskContent::Filter => TaskType::Filter, + TaskContent::Snapshot => TaskType::Snapshot, + TaskContent::Filter { .. } => TaskType::Filter, }; let pending_task = PendingTask { ty: task_type, diff --git a/frontend/rust-lib/flowy-grid/src/services/tasks/scheduler.rs b/frontend/rust-lib/flowy-grid/src/services/tasks/scheduler.rs index f4fb460eeb..14494842ec 100644 --- a/frontend/rust-lib/flowy-grid/src/services/tasks/scheduler.rs +++ b/frontend/rust-lib/flowy-grid/src/services/tasks/scheduler.rs @@ -3,6 +3,7 @@ use crate::services::tasks::runner::GridTaskRunner; use crate::services::tasks::store::GridTaskStore; use crate::services::tasks::task::Task; +use crate::services::tasks::TaskId; use flowy_error::{FlowyError, FlowyResult}; use lib_infra::future::BoxResultFuture; use std::collections::HashMap; @@ -10,7 +11,7 @@ use std::sync::Arc; use std::time::Duration; use tokio::sync::{watch, RwLock}; -pub trait GridTaskHandler: Send + Sync + 'static { +pub(crate) trait GridTaskHandler: Send + Sync + 'static { fn handler_id(&self) -> &TaskHandlerId; fn process_task(&self, task: Task) -> BoxResultFuture<(), FlowyError>; @@ -24,7 +25,7 @@ pub struct GridTaskScheduler { } impl GridTaskScheduler { - pub fn new() -> Arc> { + pub(crate) fn new() -> Arc> { let (notifier, rx) = watch::channel(()); let scheduler = Self { @@ -44,7 +45,7 @@ impl GridTaskScheduler { scheduler } - pub fn register_handler(&mut self, handler: Arc) + pub(crate) fn register_handler(&mut self, handler: Arc) where T: GridTaskHandler, { @@ -52,11 +53,11 @@ impl GridTaskScheduler { self.handlers.insert(handler_id, handler); } - pub fn unregister_handler>(&mut self, handler_id: T) { + pub(crate) fn unregister_handler>(&mut self, handler_id: T) { let _ = self.handlers.remove(handler_id.as_ref()); } - pub async fn process_next_task(&mut self) -> FlowyResult<()> { + pub(crate) async fn process_next_task(&mut self) -> FlowyResult<()> { let mut get_next_task = || { let pending_task = self.queue.mut_head(|list| list.pop())?; let task = self.store.remove_task(&pending_task.id)?; @@ -64,7 +65,7 @@ impl GridTaskScheduler { }; if let Some(task) = get_next_task() { - match self.handlers.get(&task.hid) { + match self.handlers.get(&task.handler_id) { None => {} Some(handler) => { let _ = handler.process_task(task).await; @@ -74,14 +75,18 @@ impl GridTaskScheduler { Ok(()) } - pub fn register_task(&mut self, task: Task) { + pub(crate) fn register_task(&mut self, task: Task) { assert!(!task.is_finished()); self.queue.push(&task); self.store.insert_task(task); self.notify(); } - pub fn notify(&self) { + pub(crate) fn next_task_id(&self) -> TaskId { + self.store.next_task_id() + } + + pub(crate) fn notify(&self) { let _ = self.notifier.send(()); } } diff --git a/frontend/rust-lib/flowy-grid/src/services/tasks/store.rs b/frontend/rust-lib/flowy-grid/src/services/tasks/store.rs index 7f2fc8d695..21aae60bc4 100644 --- a/frontend/rust-lib/flowy-grid/src/services/tasks/store.rs +++ b/frontend/rust-lib/flowy-grid/src/services/tasks/store.rs @@ -4,7 +4,7 @@ use std::collections::HashMap; use std::sync::atomic::AtomicU32; use std::sync::atomic::Ordering::SeqCst; -pub struct GridTaskStore { +pub(crate) struct GridTaskStore { tasks: HashMap, task_id_counter: AtomicU32, } @@ -17,15 +17,15 @@ impl GridTaskStore { } } - pub fn insert_task(&mut self, task: Task) { + pub(crate) fn insert_task(&mut self, task: Task) { self.tasks.insert(task.id, task); } - pub fn remove_task(&mut self, task_id: &TaskId) -> Option { + pub(crate) fn remove_task(&mut self, task_id: &TaskId) -> Option { self.tasks.remove(task_id) } - #[allow(dead_code)] - pub fn next_task_id(&self) -> TaskId { + + pub(crate) fn next_task_id(&self) -> TaskId { let _ = self.task_id_counter.fetch_add(1, SeqCst); self.task_id_counter.load(SeqCst) } diff --git a/frontend/rust-lib/flowy-grid/src/services/tasks/task.rs b/frontend/rust-lib/flowy-grid/src/services/tasks/task.rs index 00a6b158cc..92575dabdc 100644 --- a/frontend/rust-lib/flowy-grid/src/services/tasks/task.rs +++ b/frontend/rust-lib/flowy-grid/src/services/tasks/task.rs @@ -1,3 +1,4 @@ +use crate::services::row::GridBlockSnapshot; use crate::services::tasks::queue::TaskHandlerId; use std::cmp::Ordering; @@ -44,20 +45,23 @@ impl Ord for PendingTask { (TaskType::Snapshot, TaskType::Snapshot) => Ordering::Equal, (TaskType::Snapshot, _) => Ordering::Greater, (_, TaskType::Snapshot) => Ordering::Less, - (TaskType::Filter, TaskType::Filter) => self.id.cmp(&other.id), + (TaskType::Filter, TaskType::Filter) => self.id.cmp(&other.id).reverse(), } } } -pub type ContentId = String; - -pub enum TaskContent { - Snapshot { content_id: ContentId }, - Filter, +pub(crate) struct FilterTaskContext { + pub blocks: Vec, } -pub struct Task { - pub hid: TaskHandlerId, +pub(crate) enum TaskContent { + #[allow(dead_code)] + Snapshot, + Filter(FilterTaskContext), +} + +pub(crate) struct Task { + pub handler_id: TaskHandlerId, pub id: TaskId, pub content: TaskContent, } diff --git a/frontend/rust-lib/flowy-grid/src/util.rs b/frontend/rust-lib/flowy-grid/src/util.rs index 8f05b1a165..e0055d09b6 100644 --- a/frontend/rust-lib/flowy-grid/src/util.rs +++ b/frontend/rust-lib/flowy-grid/src/util.rs @@ -1,5 +1,5 @@ +use crate::entities::FieldType; use crate::services::field::*; -use flowy_grid_data_model::entities::FieldType; use flowy_grid_data_model::revision::BuildGridContext; use flowy_sync::client_grid::GridBuilder; diff --git a/frontend/rust-lib/flowy-grid/tests/grid/cell_test.rs b/frontend/rust-lib/flowy-grid/tests/grid/cell_test.rs index 225389bd6c..98b50436ab 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/cell_test.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/cell_test.rs @@ -1,8 +1,8 @@ use crate::grid::field_util::make_date_cell_string; use crate::grid::script::EditorScript::*; use crate::grid::script::*; +use flowy_grid::entities::{CellChangeset, FieldType}; use flowy_grid::services::field::{MultiSelectTypeOption, SelectOptionCellContentChangeset, SingleSelectTypeOption}; -use flowy_grid_data_model::entities::{CellChangeset, FieldType}; #[tokio::test] async fn grid_cell_update() { @@ -17,7 +17,8 @@ async fn grid_cell_update() { let mut scripts = vec![]; for (_, row_rev) in row_revs.iter().enumerate() { for field_rev in field_revs { - let data = match field_rev.field_type { + let field_type: FieldType = field_rev.field_type_rev.into(); + let data = match field_type { FieldType::RichText => "".to_string(), FieldType::Number => "123".to_string(), FieldType::DateTime => make_date_cell_string("123"), diff --git a/frontend/rust-lib/flowy-grid/tests/grid/field_test.rs b/frontend/rust-lib/flowy-grid/tests/grid/field_test.rs index cc2ee2ca87..c8eb1a541a 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/field_test.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/field_test.rs @@ -2,8 +2,8 @@ use crate::grid::field_util::*; use crate::grid::script::EditorScript::*; use crate::grid::script::*; use flowy_grid::services::field::{SelectOption, SingleSelectTypeOption}; -use flowy_grid_data_model::entities::FieldChangesetParams; use flowy_grid_data_model::revision::TypeOptionDataEntry; +use flowy_sync::entities::grid::FieldChangesetParams; #[tokio::test] async fn grid_create_field() { diff --git a/frontend/rust-lib/flowy-grid/tests/grid/field_util.rs b/frontend/rust-lib/flowy-grid/tests/grid/field_util.rs index 0217621acf..79b6b35ae3 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/field_util.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/field_util.rs @@ -1,6 +1,6 @@ use flowy_grid::services::field::*; -use flowy_grid_data_model::entities::*; +use flowy_grid::entities::*; use flowy_grid_data_model::revision::*; pub fn create_text_field(grid_id: &str) -> (InsertFieldParams, FieldRevision) { @@ -12,7 +12,7 @@ pub fn create_text_field(grid_id: &str) -> (InsertFieldParams, FieldRevision) { let cloned_field_rev = field_rev.clone(); let type_option_data = field_rev - .get_type_option_entry::(&field_rev.field_type) + .get_type_option_entry::(field_rev.field_type_rev) .unwrap() .protobuf_bytes() .to_vec(); @@ -21,7 +21,7 @@ pub fn create_text_field(grid_id: &str) -> (InsertFieldParams, FieldRevision) { id: field_rev.id, name: field_rev.name, desc: field_rev.desc, - field_type: field_rev.field_type, + field_type: field_rev.field_type_rev.into(), frozen: field_rev.frozen, visibility: field_rev.visibility, width: field_rev.width, @@ -44,8 +44,9 @@ pub fn create_single_select_field(grid_id: &str) -> (InsertFieldParams, FieldRev let field_rev = FieldBuilder::new(single_select).name("Name").visibility(true).build(); let cloned_field_rev = field_rev.clone(); + let field_type: FieldType = field_rev.field_type_rev.into(); let type_option_data = field_rev - .get_type_option_entry::(&field_rev.field_type) + .get_type_option_entry::(&field_type) .unwrap() .protobuf_bytes() .to_vec(); @@ -54,7 +55,7 @@ pub fn create_single_select_field(grid_id: &str) -> (InsertFieldParams, FieldRev id: field_rev.id, name: field_rev.name, desc: field_rev.desc, - field_type: field_rev.field_type, + field_type, frozen: field_rev.frozen, visibility: field_rev.visibility, width: field_rev.width, diff --git a/frontend/rust-lib/flowy-grid/tests/grid/filter_test.rs b/frontend/rust-lib/flowy-grid/tests/grid/filter_test.rs index cd47911f19..aad4cb1e7d 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/filter_test.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/filter_test.rs @@ -1,6 +1,6 @@ use crate::grid::script::EditorScript::*; use crate::grid::script::*; -use flowy_grid_data_model::entities::{CreateGridFilterPayload, TextFilterCondition}; +use flowy_grid::entities::CreateGridFilterPayload; #[tokio::test] async fn grid_filter_create_test() { @@ -26,14 +26,17 @@ async fn grid_filter_invalid_condition_panic_test() { #[tokio::test] async fn grid_filter_delete_test() { let mut test = GridEditorTest::new().await; - let field_rev = test.text_field(); - let payload = CreateGridFilterPayload::new(field_rev, TextFilterCondition::TextIsEmpty, Some("abc".to_owned())); + let field_rev = test.text_field().clone(); + let payload = CreateGridFilterPayload::new(&field_rev, TextFilterCondition::TextIsEmpty, Some("abc".to_owned())); let scripts = vec![InsertGridTableFilter { payload }, AssertTableFilterCount { count: 1 }]; test.run_scripts(scripts).await; let filter = test.grid_filters().await.pop().unwrap(); test.run_scripts(vec![ - DeleteGridTableFilter { filter_id: filter.id }, + DeleteGridTableFilter { + filter_id: filter.id, + field_type: field_rev.field_type.clone(), + }, AssertTableFilterCount { count: 0 }, ]) .await; diff --git a/frontend/rust-lib/flowy-grid/tests/grid/mod.rs b/frontend/rust-lib/flowy-grid/tests/grid/mod.rs index 4d746661eb..38cdb25b99 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/mod.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/mod.rs @@ -2,7 +2,7 @@ mod block_test; mod cell_test; mod field_test; mod field_util; -mod filter_test; +// mod filter_test; mod row_test; mod row_util; mod script; diff --git a/frontend/rust-lib/flowy-grid/tests/grid/row_test.rs b/frontend/rust-lib/flowy-grid/tests/grid/row_test.rs index 04cff420c5..f833dff8a6 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/row_test.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/row_test.rs @@ -3,11 +3,11 @@ use crate::grid::row_util::GridRowTestBuilder; use crate::grid::script::EditorScript::*; use crate::grid::script::*; use chrono::NaiveDateTime; +use flowy_grid::entities::FieldType; use flowy_grid::services::field::{ DateCellData, MultiSelectTypeOption, SingleSelectTypeOption, SELECTION_IDS_SEPARATOR, }; use flowy_grid::services::row::{decode_cell_data, CreateRowRevisionBuilder}; -use flowy_grid_data_model::entities::FieldType; use flowy_grid_data_model::revision::RowMetaChangeset; #[tokio::test] @@ -75,7 +75,8 @@ async fn grid_row_add_cells_test() { let mut test = GridEditorTest::new().await; let mut builder = CreateRowRevisionBuilder::new(&test.field_revs); for field in &test.field_revs { - match field.field_type { + let field_type: FieldType = field.field_type_rev.into(); + match field_type { FieldType::RichText => { builder.add_cell(&field.id, "hello world".to_owned()).unwrap(); } @@ -122,7 +123,8 @@ async fn grid_row_add_date_cell_test() { let mut date_field = None; let timestamp = 1647390674; for field in &test.field_revs { - if field.field_type == FieldType::DateTime { + let field_type: FieldType = field.field_type_rev.into(); + if field_type == FieldType::DateTime { date_field = Some(field.clone()); NaiveDateTime::from_timestamp(123, 0); // The data should not be empty diff --git a/frontend/rust-lib/flowy-grid/tests/grid/row_util.rs b/frontend/rust-lib/flowy-grid/tests/grid/row_util.rs index 7fd6f043ce..ee4750bd19 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/row_util.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/row_util.rs @@ -1,7 +1,7 @@ use crate::grid::script::GridEditorTest; +use flowy_grid::entities::FieldType; use flowy_grid::services::field::DateCellContentChangeset; use flowy_grid::services::row::{CreateRowRevisionBuilder, CreateRowRevisionPayload}; -use flowy_grid_data_model::entities::FieldType; use flowy_grid_data_model::revision::FieldRevision; use strum::EnumCount; @@ -61,8 +61,12 @@ impl<'a> GridRowTestBuilder<'a> { self.test .field_revs .iter() - .find(|field_rev| &field_rev.field_type == field_type) + .find(|field_rev| { + let t_field_type: FieldType = field_rev.field_type_rev.into(); + &t_field_type == field_type + }) .unwrap() + .as_ref() .clone() } diff --git a/frontend/rust-lib/flowy-grid/tests/grid/script.rs b/frontend/rust-lib/flowy-grid/tests/grid/script.rs index c2686974e8..0ca04024a6 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/script.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/script.rs @@ -1,10 +1,13 @@ #![cfg_attr(rustfmt, rustfmt::skip)] +#![allow(clippy::all)] +#![allow(dead_code)] +#![allow(unused_imports)] use bytes::Bytes; use flowy_grid::services::field::*; use flowy_grid::services::grid_editor::{GridPadBuilder, GridRevisionEditor}; use flowy_grid::services::row::CreateRowRevisionPayload; use flowy_grid::services::setting::GridSettingChangesetBuilder; -use flowy_grid_data_model::entities::*; +use flowy_grid::entities::*; use flowy_grid_data_model::revision::*; use flowy_revision::REVISION_WRITE_INTERVAL_IN_MILLIS; use flowy_sync::client_grid::GridBuilder; @@ -15,6 +18,7 @@ use std::sync::Arc; use std::time::Duration; use strum::EnumCount; use tokio::time::sleep; +use flowy_sync::entities::grid::{CreateGridFilterParams, DeleteFilterParams, FieldChangesetParams, GridSettingChangesetParams}; pub enum EditorScript { CreateField { @@ -77,6 +81,7 @@ pub enum EditorScript { }, DeleteGridTableFilter { filter_id: String, + field_type: FieldType, }, #[allow(dead_code)] AssertGridSetting { @@ -89,12 +94,12 @@ pub struct GridEditorTest { pub sdk: FlowySDKTest, pub grid_id: String, pub editor: Arc, - pub field_revs: Vec, + pub field_revs: Vec>, pub block_meta_revs: Vec>, pub row_revs: Vec>, pub field_count: usize, - pub row_order_by_row_id: HashMap, + pub row_order_by_row_id: HashMap, } impl GridEditorTest { @@ -105,7 +110,7 @@ impl GridEditorTest { let view_data: Bytes = build_context.into(); let test = ViewTest::new_grid_view(&sdk, view_data.to_vec()).await; let editor = sdk.grid_manager.open_grid(&test.view.id).await.unwrap(); - let field_revs = editor.get_field_revs::(None).await.unwrap(); + let field_revs = editor.get_field_revs(None).await.unwrap(); let block_meta_revs = editor.get_block_meta_revs().await.unwrap(); let row_revs = editor.grid_block_snapshots(None).await.unwrap().pop().unwrap().row_revs; assert_eq!(row_revs.len(), 3); @@ -147,12 +152,12 @@ impl GridEditorTest { } self.editor.insert_field(params).await.unwrap(); - self.field_revs = self.editor.get_field_revs::(None).await.unwrap(); + self.field_revs = self.editor.get_field_revs(None).await.unwrap(); assert_eq!(self.field_count, self.field_revs.len()); } EditorScript::UpdateField { changeset: change } => { self.editor.update_field(change).await.unwrap(); - self.field_revs = self.editor.get_field_revs::(None).await.unwrap(); + self.field_revs = self.editor.get_field_revs(None).await.unwrap(); } EditorScript::DeleteField { field_rev } => { if self.editor.contain_field(&field_rev.id).await { @@ -160,18 +165,18 @@ impl GridEditorTest { } self.editor.delete_field(&field_rev.id).await.unwrap(); - self.field_revs = self.editor.get_field_revs::(None).await.unwrap(); + self.field_revs = self.editor.get_field_revs(None).await.unwrap(); assert_eq!(self.field_count, self.field_revs.len()); } EditorScript::AssertFieldCount(count) => { assert_eq!( - self.editor.get_field_revs::(None).await.unwrap().len(), + self.editor.get_field_revs(None).await.unwrap().len(), count ); } EditorScript::AssertFieldEqual { field_index, field_rev } => { - let field_revs = self.editor.get_field_revs::(None).await.unwrap(); - assert_eq!(field_revs[field_index].clone(), field_rev); + let field_revs = self.editor.get_field_revs(None).await.unwrap(); + assert_eq!(field_revs[field_index].as_ref(), &field_rev); } EditorScript::CreateBlock { block } => { self.editor.create_block(block).await.unwrap(); @@ -198,14 +203,14 @@ impl GridEditorTest { } EditorScript::CreateEmptyRow => { let row_order = self.editor.create_row(None).await.unwrap(); - self.row_order_by_row_id.insert(row_order.row_id.clone(), row_order); + self.row_order_by_row_id.insert(row_order.row_id().to_owned(), row_order); self.row_revs = self.get_row_revs().await; self.block_meta_revs = self.editor.get_block_meta_revs().await.unwrap(); } EditorScript::CreateRow { payload: context } => { let row_orders = self.editor.insert_rows(vec![context]).await.unwrap(); for row_order in row_orders { - self.row_order_by_row_id.insert(row_order.row_id.clone(), row_order); + self.row_order_by_row_id.insert(row_order.row_id().to_owned(), row_order); } self.row_revs = self.get_row_revs().await; self.block_meta_revs = self.editor.get_block_meta_revs().await.unwrap(); @@ -215,7 +220,7 @@ impl GridEditorTest { let row_orders = row_ids .into_iter() .map(|row_id| self.row_order_by_row_id.get(&row_id).unwrap().clone()) - .collect::>(); + .collect::>(); self.editor.delete_rows(row_orders).await.unwrap(); self.row_revs = self.get_row_revs().await; @@ -265,10 +270,10 @@ impl GridEditorTest { let filters = self.editor.get_grid_filter(&layout_type).await.unwrap(); assert_eq!(count as usize, filters.len()); } - EditorScript::DeleteGridTableFilter { filter_id } => { + EditorScript::DeleteGridTableFilter { filter_id ,field_type} => { let layout_type = GridLayoutType::Table; let params = GridSettingChangesetBuilder::new(&self.grid_id, &layout_type) - .delete_filter(&filter_id) + .delete_filter(DeleteFilterParams { filter_id, field_type_rev: field_type.into() }) .build(); let _ = self.editor.update_grid_setting(params).await.unwrap(); } @@ -303,7 +308,10 @@ impl GridEditorTest { pub fn text_field(&self) -> &FieldRevision { self.field_revs .iter() - .filter(|field_rev| field_rev.field_type == FieldType::RichText) + .filter(|field_rev| { + let t_field_type: FieldType = field_rev.field_type_rev.into(); + t_field_type == FieldType::RichText + }) .collect::>() .pop() .unwrap() diff --git a/frontend/rust-lib/flowy-net/src/http_server/document.rs b/frontend/rust-lib/flowy-net/src/http_server/document.rs index f10c737a95..fe9f31f2ca 100644 --- a/frontend/rust-lib/flowy-net/src/http_server/document.rs +++ b/frontend/rust-lib/flowy-net/src/http_server/document.rs @@ -3,7 +3,7 @@ use crate::{ request::{HttpRequestBuilder, ResponseMiddleware}, }; use flowy_error::FlowyError; -use flowy_sync::entities::text_block_info::{CreateTextBlockParams, ResetTextBlockParams, TextBlockId, TextBlockInfo}; +use flowy_sync::entities::text_block::{CreateTextBlockParams, ResetTextBlockParams, TextBlockId, TextBlockInfo}; use flowy_text_block::BlockCloudService; use http_flowy::response::FlowyResponse; use lazy_static::lazy_static; diff --git a/frontend/rust-lib/flowy-net/src/local_server/persistence.rs b/frontend/rust-lib/flowy-net/src/local_server/persistence.rs index 6d7dd9c342..28151af2f4 100644 --- a/frontend/rust-lib/flowy-net/src/local_server/persistence.rs +++ b/frontend/rust-lib/flowy-net/src/local_server/persistence.rs @@ -1,5 +1,5 @@ use flowy_sync::{ - entities::{folder_info::FolderInfo, text_block_info::TextBlockInfo}, + entities::{folder::FolderInfo, text_block::TextBlockInfo}, errors::CollaborateError, protobuf::{RepeatedRevision as RepeatedRevisionPB, Revision as RevisionPB}, server_document::*, diff --git a/frontend/rust-lib/flowy-net/src/local_server/server.rs b/frontend/rust-lib/flowy-net/src/local_server/server.rs index 87f4f46f4e..905e2bccb4 100644 --- a/frontend/rust-lib/flowy-net/src/local_server/server.rs +++ b/frontend/rust-lib/flowy-net/src/local_server/server.rs @@ -6,7 +6,7 @@ use flowy_folder::event_map::FolderCouldServiceV1; use flowy_sync::{ client_document::default::initial_quill_delta_string, entities::{ - text_block_info::{CreateTextBlockParams, ResetTextBlockParams, TextBlockId, TextBlockInfo}, + text_block::{CreateTextBlockParams, ResetTextBlockParams, TextBlockId, TextBlockInfo}, ws_data::{ClientRevisionWSData, ClientRevisionWSDataType}, }, errors::CollaborateError, diff --git a/frontend/rust-lib/flowy-text-block/src/editor.rs b/frontend/rust-lib/flowy-text-block/src/editor.rs index 87b4416ef0..111808109d 100644 --- a/frontend/rust-lib/flowy-text-block/src/editor.rs +++ b/frontend/rust-lib/flowy-text-block/src/editor.rs @@ -9,7 +9,7 @@ use flowy_error::{internal_error, FlowyResult}; use flowy_revision::{RevisionCloudService, RevisionManager, RevisionObjectBuilder, RevisionWebSocket}; use flowy_sync::entities::ws_data::ServerRevisionWSData; use flowy_sync::{ - entities::{revision::Revision, text_block_info::TextBlockInfo}, + entities::{revision::Revision, text_block::TextBlockInfo}, errors::CollaborateResult, util::make_delta_from_revisions, }; diff --git a/frontend/rust-lib/flowy-text-block/src/event_handler.rs b/frontend/rust-lib/flowy-text-block/src/event_handler.rs index 183103b73e..0934d20a29 100644 --- a/frontend/rust-lib/flowy-text-block/src/event_handler.rs +++ b/frontend/rust-lib/flowy-text-block/src/event_handler.rs @@ -1,7 +1,7 @@ use crate::entities::{ExportData, ExportParams, ExportPayload}; use crate::TextBlockManager; use flowy_error::FlowyError; -use flowy_sync::entities::text_block_info::{TextBlockDelta, TextBlockId}; +use flowy_sync::entities::text_block::{TextBlockDelta, TextBlockId}; use lib_dispatch::prelude::{data_result, AppData, Data, DataResult}; use std::convert::TryInto; use std::sync::Arc; diff --git a/frontend/rust-lib/flowy-text-block/src/lib.rs b/frontend/rust-lib/flowy-text-block/src/lib.rs index 991fed8f38..f470739d85 100644 --- a/frontend/rust-lib/flowy-text-block/src/lib.rs +++ b/frontend/rust-lib/flowy-text-block/src/lib.rs @@ -15,7 +15,7 @@ pub mod errors { pub const TEXT_BLOCK_SYNC_INTERVAL_IN_MILLIS: u64 = 1000; use crate::errors::FlowyError; -use flowy_sync::entities::text_block_info::{CreateTextBlockParams, ResetTextBlockParams, TextBlockId, TextBlockInfo}; +use flowy_sync::entities::text_block::{CreateTextBlockParams, ResetTextBlockParams, TextBlockId, TextBlockInfo}; use lib_infra::future::FutureResult; pub trait BlockCloudService: Send + Sync { diff --git a/frontend/rust-lib/flowy-text-block/src/manager.rs b/frontend/rust-lib/flowy-text-block/src/manager.rs index 9325fe6001..ead24857be 100644 --- a/frontend/rust-lib/flowy-text-block/src/manager.rs +++ b/frontend/rust-lib/flowy-text-block/src/manager.rs @@ -7,7 +7,7 @@ use flowy_revision::disk::SQLiteTextBlockRevisionPersistence; use flowy_revision::{RevisionCloudService, RevisionManager, RevisionPersistence, RevisionWebSocket}; use flowy_sync::entities::{ revision::{md5, RepeatedRevision, Revision}, - text_block_info::{TextBlockDelta, TextBlockId}, + text_block::{TextBlockDelta, TextBlockId}, ws_data::ServerRevisionWSData, }; use lib_infra::future::FutureResult; diff --git a/shared-lib/Cargo.lock b/shared-lib/Cargo.lock index 2ae77e2bd3..04b92a09fb 100644 --- a/shared-lib/Cargo.lock +++ b/shared-lib/Cargo.lock @@ -447,17 +447,13 @@ name = "flowy-grid-data-model" version = "0.1.0" dependencies = [ "bytes", - "flowy-derive", "flowy-error-code", "indexmap", "lib-infra", "nanoid", - "protobuf", "serde", "serde_json", "serde_repr", - "strum", - "strum_macros", ] [[package]] diff --git a/shared-lib/flowy-grid-data-model/Cargo.toml b/shared-lib/flowy-grid-data-model/Cargo.toml index 12356183d0..b0162c82a8 100644 --- a/shared-lib/flowy-grid-data-model/Cargo.toml +++ b/shared-lib/flowy-grid-data-model/Cargo.toml @@ -6,17 +6,14 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -flowy-derive = { path = "../flowy-derive" } -protobuf = {version = "2.18.0"} bytes = "1.0" -strum = "0.21" -strum_macros = "0.21" serde = { version = "1.0", features = ["derive", "rc"] } serde_json = {version = "1.0"} serde_repr = "0.1" nanoid = "0.4.0" flowy-error-code = { path = "../flowy-error-code"} indexmap = {version = "1.8.1", features = ["serde"]} + [build-dependencies] lib-infra = { path = "../lib-infra", features = ["protobuf_file_gen"] } diff --git a/shared-lib/flowy-grid-data-model/Flowy.toml b/shared-lib/flowy-grid-data-model/Flowy.toml deleted file mode 100644 index 7e493fc841..0000000000 --- a/shared-lib/flowy-grid-data-model/Flowy.toml +++ /dev/null @@ -1,2 +0,0 @@ -# Check out the FlowyConfig (located in flowy_toml.rs) for more details. -proto_input = ["src/entities/",] diff --git a/shared-lib/flowy-grid-data-model/build.rs b/shared-lib/flowy-grid-data-model/build.rs deleted file mode 100644 index e897c3690d..0000000000 --- a/shared-lib/flowy-grid-data-model/build.rs +++ /dev/null @@ -1,5 +0,0 @@ -use lib_infra::code_gen; - -fn main() { - code_gen::protobuf_file::gen(env!("CARGO_PKG_NAME")); -} diff --git a/shared-lib/flowy-grid-data-model/src/entities/field.rs b/shared-lib/flowy-grid-data-model/src/entities/field.rs deleted file mode 100644 index cb886fcb61..0000000000 --- a/shared-lib/flowy-grid-data-model/src/entities/field.rs +++ /dev/null @@ -1,523 +0,0 @@ -use crate::parser::NotEmptyStr; -use crate::revision::FieldRevision; -use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; -use flowy_error_code::ErrorCode; -use serde_repr::*; -use strum_macros::{Display, EnumCount as EnumCountMacro, EnumIter, EnumString}; - -#[derive(Debug, Clone, Default, ProtoBuf)] -pub struct Field { - #[pb(index = 1)] - pub id: String, - - #[pb(index = 2)] - pub name: String, - - #[pb(index = 3)] - pub desc: String, - - #[pb(index = 4)] - pub field_type: FieldType, - - #[pb(index = 5)] - pub frozen: bool, - - #[pb(index = 6)] - pub visibility: bool, - - #[pb(index = 7)] - pub width: i32, - - #[pb(index = 8)] - pub is_primary: bool, -} - -#[derive(Debug, Clone, Default, ProtoBuf)] -pub struct FieldOrder { - #[pb(index = 1)] - pub field_id: String, -} - -impl std::convert::From<&str> for FieldOrder { - fn from(s: &str) -> Self { - FieldOrder { field_id: s.to_owned() } - } -} - -impl std::convert::From for FieldOrder { - fn from(s: String) -> Self { - FieldOrder { field_id: s } - } -} - -#[derive(Debug, Clone, Default, ProtoBuf)] -pub struct GridFieldChangeset { - #[pb(index = 1)] - pub grid_id: String, - - #[pb(index = 2)] - pub inserted_fields: Vec, - - #[pb(index = 3)] - pub deleted_fields: Vec, - - #[pb(index = 4)] - pub updated_fields: Vec, -} - -impl GridFieldChangeset { - pub fn insert(grid_id: &str, inserted_fields: Vec) -> Self { - Self { - grid_id: grid_id.to_owned(), - inserted_fields, - deleted_fields: vec![], - updated_fields: vec![], - } - } - - pub fn delete(grid_id: &str, deleted_fields: Vec) -> Self { - Self { - grid_id: grid_id.to_string(), - inserted_fields: vec![], - deleted_fields, - updated_fields: vec![], - } - } - - pub fn update(grid_id: &str, updated_fields: Vec) -> Self { - Self { - grid_id: grid_id.to_string(), - inserted_fields: vec![], - deleted_fields: vec![], - updated_fields, - } - } -} - -#[derive(Debug, Clone, Default, ProtoBuf)] -pub struct IndexField { - #[pb(index = 1)] - pub field: Field, - - #[pb(index = 2)] - pub index: i32, -} - -impl IndexField { - pub fn from_field_rev(field_rev: &FieldRevision, index: usize) -> Self { - Self { - field: Field::from(field_rev.clone()), - index: index as i32, - } - } -} - -#[derive(Debug, Default, ProtoBuf)] -pub struct GetEditFieldContextPayload { - #[pb(index = 1)] - pub grid_id: String, - - #[pb(index = 2, one_of)] - pub field_id: Option, - - #[pb(index = 3)] - pub field_type: FieldType, -} - -#[derive(Debug, Default, ProtoBuf)] -pub struct EditFieldPayload { - #[pb(index = 1)] - pub grid_id: String, - - #[pb(index = 2)] - pub field_id: String, - - #[pb(index = 3)] - pub field_type: FieldType, - - #[pb(index = 4)] - pub create_if_not_exist: bool, -} - -pub struct EditFieldParams { - pub grid_id: String, - pub field_id: String, - pub field_type: FieldType, -} - -impl TryInto for EditFieldPayload { - type Error = ErrorCode; - - fn try_into(self) -> Result { - let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?; - let field_id = NotEmptyStr::parse(self.field_id).map_err(|_| ErrorCode::FieldIdIsEmpty)?; - Ok(EditFieldParams { - grid_id: grid_id.0, - field_id: field_id.0, - field_type: self.field_type, - }) - } -} - -pub struct CreateFieldParams { - pub grid_id: String, - pub field_type: FieldType, -} - -impl TryInto for EditFieldPayload { - type Error = ErrorCode; - - fn try_into(self) -> Result { - let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?; - - Ok(CreateFieldParams { - grid_id: grid_id.0, - field_type: self.field_type, - }) - } -} - -#[derive(Debug, Default, ProtoBuf)] -pub struct FieldTypeOptionContext { - #[pb(index = 1)] - pub grid_id: String, - - #[pb(index = 2)] - pub grid_field: Field, - - #[pb(index = 3)] - pub type_option_data: Vec, -} - -#[derive(Debug, Default, ProtoBuf)] -pub struct FieldTypeOptionData { - #[pb(index = 1)] - pub grid_id: String, - - #[pb(index = 2)] - pub field: Field, - - #[pb(index = 3)] - pub type_option_data: Vec, -} - -#[derive(Debug, Default, ProtoBuf)] -pub struct RepeatedField { - #[pb(index = 1)] - pub items: Vec, -} -impl std::ops::Deref for RepeatedField { - type Target = Vec; - fn deref(&self) -> &Self::Target { - &self.items - } -} - -impl std::ops::DerefMut for RepeatedField { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.items - } -} - -impl std::convert::From> for RepeatedField { - fn from(items: Vec) -> Self { - Self { items } - } -} - -#[derive(Debug, Clone, Default, ProtoBuf)] -pub struct RepeatedFieldOrder { - #[pb(index = 1)] - pub items: Vec, -} - -impl std::ops::Deref for RepeatedFieldOrder { - type Target = Vec; - fn deref(&self) -> &Self::Target { - &self.items - } -} - -impl std::convert::From> for RepeatedFieldOrder { - fn from(field_orders: Vec) -> Self { - RepeatedFieldOrder { items: field_orders } - } -} - -impl std::convert::From for RepeatedFieldOrder { - fn from(s: String) -> Self { - RepeatedFieldOrder { - items: vec![FieldOrder::from(s)], - } - } -} - -#[derive(ProtoBuf, Default)] -pub struct InsertFieldPayload { - #[pb(index = 1)] - pub grid_id: String, - - #[pb(index = 2)] - pub field: Field, - - #[pb(index = 3)] - pub type_option_data: Vec, - - #[pb(index = 4, one_of)] - pub start_field_id: Option, -} - -#[derive(Clone)] -pub struct InsertFieldParams { - pub grid_id: String, - pub field: Field, - pub type_option_data: Vec, - pub start_field_id: Option, -} - -impl TryInto for InsertFieldPayload { - type Error = ErrorCode; - - fn try_into(self) -> Result { - let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?; - let _ = NotEmptyStr::parse(self.field.id.clone()).map_err(|_| ErrorCode::FieldIdIsEmpty)?; - - let start_field_id = match self.start_field_id { - None => None, - Some(id) => Some(NotEmptyStr::parse(id).map_err(|_| ErrorCode::FieldIdIsEmpty)?.0), - }; - - Ok(InsertFieldParams { - grid_id: grid_id.0, - field: self.field, - type_option_data: self.type_option_data, - start_field_id, - }) - } -} - -#[derive(ProtoBuf, Default)] -pub struct UpdateFieldTypeOptionPayload { - #[pb(index = 1)] - pub grid_id: String, - - #[pb(index = 2)] - pub field_id: String, - - #[pb(index = 3)] - pub type_option_data: Vec, -} - -#[derive(Clone)] -pub struct UpdateFieldTypeOptionParams { - pub grid_id: String, - pub field_id: String, - pub type_option_data: Vec, -} - -impl TryInto for UpdateFieldTypeOptionPayload { - type Error = ErrorCode; - - fn try_into(self) -> Result { - let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?; - let _ = NotEmptyStr::parse(self.field_id.clone()).map_err(|_| ErrorCode::FieldIdIsEmpty)?; - - Ok(UpdateFieldTypeOptionParams { - grid_id: grid_id.0, - field_id: self.field_id, - type_option_data: self.type_option_data, - }) - } -} - -#[derive(ProtoBuf, Default)] -pub struct QueryFieldPayload { - #[pb(index = 1)] - pub grid_id: String, - - #[pb(index = 2)] - pub field_orders: RepeatedFieldOrder, -} - -pub struct QueryFieldParams { - pub grid_id: String, - pub field_orders: RepeatedFieldOrder, -} - -impl TryInto for QueryFieldPayload { - type Error = ErrorCode; - - fn try_into(self) -> Result { - let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?; - Ok(QueryFieldParams { - grid_id: grid_id.0, - field_orders: self.field_orders, - }) - } -} - -#[derive(Debug, Clone, Default, ProtoBuf)] -pub struct FieldChangesetPayload { - #[pb(index = 1)] - pub field_id: String, - - #[pb(index = 2)] - pub grid_id: String, - - #[pb(index = 3, one_of)] - pub name: Option, - - #[pb(index = 4, one_of)] - pub desc: Option, - - #[pb(index = 5, one_of)] - pub field_type: Option, - - #[pb(index = 6, one_of)] - pub frozen: Option, - - #[pb(index = 7, one_of)] - pub visibility: Option, - - #[pb(index = 8, one_of)] - pub width: Option, - - #[pb(index = 9, one_of)] - pub type_option_data: Option>, -} - -#[derive(Debug, Clone, Default)] -pub struct FieldChangesetParams { - pub field_id: String, - - pub grid_id: String, - - pub name: Option, - - pub desc: Option, - - pub field_type: Option, - - pub frozen: Option, - - pub visibility: Option, - - pub width: Option, - - pub type_option_data: Option>, -} - -impl TryInto for FieldChangesetPayload { - type Error = ErrorCode; - - fn try_into(self) -> Result { - let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?; - let field_id = NotEmptyStr::parse(self.field_id).map_err(|_| ErrorCode::FieldIdIsEmpty)?; - - if let Some(type_option_data) = self.type_option_data.as_ref() { - if type_option_data.is_empty() { - return Err(ErrorCode::TypeOptionDataIsEmpty); - } - } - - Ok(FieldChangesetParams { - field_id: field_id.0, - grid_id: grid_id.0, - name: self.name, - desc: self.desc, - field_type: self.field_type, - frozen: self.frozen, - visibility: self.visibility, - width: self.width, - type_option_data: self.type_option_data, - }) - } -} - -#[derive( - Debug, - Clone, - PartialEq, - Eq, - ProtoBuf_Enum, - EnumCountMacro, - EnumString, - EnumIter, - Display, - Serialize_repr, - Deserialize_repr, -)] -#[repr(u8)] -pub enum FieldType { - RichText = 0, - Number = 1, - DateTime = 2, - SingleSelect = 3, - MultiSelect = 4, - Checkbox = 5, - URL = 6, -} - -impl std::default::Default for FieldType { - fn default() -> Self { - FieldType::RichText - } -} - -impl AsRef for FieldType { - fn as_ref(&self) -> &FieldType { - self - } -} - -impl From<&FieldType> for FieldType { - fn from(field_type: &FieldType) -> Self { - field_type.clone() - } -} - -impl FieldType { - pub fn type_id(&self) -> String { - let ty = self.clone() as u8; - ty.to_string() - } - - pub fn default_cell_width(&self) -> i32 { - match self { - FieldType::DateTime => 180, - _ => 150, - } - } - - pub fn is_number(&self) -> bool { - self == &FieldType::Number - } - - pub fn is_text(&self) -> bool { - self == &FieldType::RichText - } - - pub fn is_checkbox(&self) -> bool { - self == &FieldType::Checkbox - } - - pub fn is_date(&self) -> bool { - self == &FieldType::DateTime - } - - pub fn is_single_select(&self) -> bool { - self == &FieldType::SingleSelect - } - - pub fn is_multi_select(&self) -> bool { - self == &FieldType::MultiSelect - } - - pub fn is_url(&self) -> bool { - self == &FieldType::URL - } - - pub fn is_select_option(&self) -> bool { - self == &FieldType::MultiSelect || self == &FieldType::SingleSelect - } -} diff --git a/shared-lib/flowy-grid-data-model/src/entities/grid.rs b/shared-lib/flowy-grid-data-model/src/entities/grid.rs deleted file mode 100644 index 52a4be6e8f..0000000000 --- a/shared-lib/flowy-grid-data-model/src/entities/grid.rs +++ /dev/null @@ -1,379 +0,0 @@ -use crate::entities::FieldOrder; -use crate::parser::NotEmptyStr; -use crate::revision::RowRevision; -use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; -use flowy_error_code::ErrorCode; - -#[derive(Debug, Clone, Default, ProtoBuf)] -pub struct Grid { - #[pb(index = 1)] - pub id: String, - - #[pb(index = 2)] - pub field_orders: Vec, - - #[pb(index = 3)] - pub blocks: Vec, -} - -#[derive(Debug, Default, Clone, ProtoBuf)] -pub struct RowOrder { - #[pb(index = 1)] - pub row_id: String, - - #[pb(index = 2)] - pub block_id: String, - - #[pb(index = 3)] - pub height: i32, -} - -#[derive(Debug, Default, ProtoBuf)] -pub struct Row { - #[pb(index = 1)] - pub id: String, - - #[pb(index = 2)] - pub height: i32, -} - -#[derive(Debug, Default, ProtoBuf)] -pub struct OptionalRow { - #[pb(index = 1, one_of)] - pub row: Option, -} - -#[derive(Debug, Default, ProtoBuf)] -pub struct RepeatedRow { - #[pb(index = 1)] - pub items: Vec, -} - -impl std::convert::From> for RepeatedRow { - fn from(items: Vec) -> Self { - Self { items } - } -} - -#[derive(Debug, Default, ProtoBuf)] -pub struct RepeatedGridBlock { - #[pb(index = 1)] - pub items: Vec, -} - -impl std::convert::From> for RepeatedGridBlock { - fn from(items: Vec) -> Self { - Self { items } - } -} - -#[derive(Debug, Clone, Default, ProtoBuf)] -pub struct IndexRowOrder { - #[pb(index = 1)] - pub row_order: RowOrder, - - #[pb(index = 2, one_of)] - pub index: Option, -} - -#[derive(Debug, Default, ProtoBuf)] -pub struct UpdatedRowOrder { - #[pb(index = 1)] - pub row_order: RowOrder, - - #[pb(index = 2)] - pub row: Row, -} - -impl UpdatedRowOrder { - pub fn new(row_rev: &RowRevision, row: Row) -> Self { - Self { - row_order: RowOrder::from(row_rev), - row, - } - } -} - -#[derive(Debug, Default, ProtoBuf)] -pub struct GridRowsChangeset { - #[pb(index = 1)] - pub block_id: String, - - #[pb(index = 2)] - pub inserted_rows: Vec, - - #[pb(index = 3)] - pub deleted_rows: Vec, - - #[pb(index = 4)] - pub updated_rows: Vec, -} - -impl std::convert::From for IndexRowOrder { - fn from(row_order: RowOrder) -> Self { - Self { row_order, index: None } - } -} - -impl std::convert::From<&RowRevision> for IndexRowOrder { - fn from(row: &RowRevision) -> Self { - let row_order = RowOrder::from(row); - Self::from(row_order) - } -} - -impl GridRowsChangeset { - pub fn insert(block_id: &str, inserted_rows: Vec) -> Self { - Self { - block_id: block_id.to_owned(), - inserted_rows, - deleted_rows: vec![], - updated_rows: vec![], - } - } - - pub fn delete(block_id: &str, deleted_rows: Vec) -> Self { - Self { - block_id: block_id.to_owned(), - inserted_rows: vec![], - deleted_rows, - updated_rows: vec![], - } - } - - pub fn update(block_id: &str, updated_rows: Vec) -> Self { - Self { - block_id: block_id.to_owned(), - inserted_rows: vec![], - deleted_rows: vec![], - updated_rows, - } - } -} - -#[derive(Debug, Clone, Default, ProtoBuf)] -pub struct GridBlock { - #[pb(index = 1)] - pub id: String, - - #[pb(index = 2)] - pub row_orders: Vec, -} - -impl GridBlock { - pub fn new(block_id: &str, row_orders: Vec) -> Self { - Self { - id: block_id.to_owned(), - row_orders, - } - } -} - -#[derive(Debug, Default, ProtoBuf)] -pub struct Cell { - #[pb(index = 1)] - pub field_id: String, - - #[pb(index = 2)] - pub data: Vec, -} - -impl Cell { - pub fn new(field_id: &str, data: Vec) -> Self { - Self { - field_id: field_id.to_owned(), - data, - } - } - - pub fn empty(field_id: &str) -> Self { - Self { - field_id: field_id.to_owned(), - data: vec![], - } - } -} - -#[derive(Debug, Default, ProtoBuf)] -pub struct RepeatedCell { - #[pb(index = 1)] - pub items: Vec, -} - -impl std::ops::Deref for RepeatedCell { - type Target = Vec; - fn deref(&self) -> &Self::Target { - &self.items - } -} - -impl std::ops::DerefMut for RepeatedCell { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.items - } -} - -impl std::convert::From> for RepeatedCell { - fn from(items: Vec) -> Self { - Self { items } - } -} - -#[derive(ProtoBuf, Default)] -pub struct CreateGridPayload { - #[pb(index = 1)] - pub name: String, -} - -#[derive(Clone, ProtoBuf, Default, Debug)] -pub struct GridId { - #[pb(index = 1)] - pub value: String, -} - -impl AsRef for GridId { - fn as_ref(&self) -> &str { - &self.value - } -} - -#[derive(Clone, ProtoBuf, Default, Debug)] -pub struct GridBlockId { - #[pb(index = 1)] - pub value: String, -} - -impl AsRef for GridBlockId { - fn as_ref(&self) -> &str { - &self.value - } -} - -impl std::convert::From<&str> for GridBlockId { - fn from(s: &str) -> Self { - GridBlockId { value: s.to_owned() } - } -} - -#[derive(ProtoBuf, Default)] -pub struct CreateRowPayload { - #[pb(index = 1)] - pub grid_id: String, - - #[pb(index = 2, one_of)] - pub start_row_id: Option, -} - -#[derive(Default)] -pub struct CreateRowParams { - pub grid_id: String, - pub start_row_id: Option, -} - -impl TryInto for CreateRowPayload { - type Error = ErrorCode; - - fn try_into(self) -> Result { - let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?; - Ok(CreateRowParams { - grid_id: grid_id.0, - start_row_id: self.start_row_id, - }) - } -} - -#[derive(ProtoBuf, Default)] -pub struct QueryGridBlocksPayload { - #[pb(index = 1)] - pub grid_id: String, - - #[pb(index = 2)] - pub block_ids: Vec, -} - -pub struct QueryGridBlocksParams { - pub grid_id: String, - pub block_ids: Vec, -} - -impl TryInto for QueryGridBlocksPayload { - type Error = ErrorCode; - - fn try_into(self) -> Result { - let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?; - Ok(QueryGridBlocksParams { - grid_id: grid_id.0, - block_ids: self.block_ids, - }) - } -} - -#[derive(Debug, Clone, ProtoBuf_Enum)] -pub enum MoveItemType { - MoveField = 0, - MoveRow = 1, -} - -impl std::default::Default for MoveItemType { - fn default() -> Self { - MoveItemType::MoveField - } -} - -#[derive(Debug, Clone, Default, ProtoBuf)] -pub struct MoveItemPayload { - #[pb(index = 1)] - pub grid_id: String, - - #[pb(index = 2)] - pub item_id: String, - - #[pb(index = 3)] - pub from_index: i32, - - #[pb(index = 4)] - pub to_index: i32, - - #[pb(index = 5)] - pub ty: MoveItemType, -} - -#[derive(Clone)] -pub struct MoveItemParams { - pub grid_id: String, - pub item_id: String, - pub from_index: i32, - pub to_index: i32, - pub ty: MoveItemType, -} - -impl TryInto for MoveItemPayload { - type Error = ErrorCode; - - fn try_into(self) -> Result { - let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?; - let item_id = NotEmptyStr::parse(self.item_id).map_err(|_| ErrorCode::InvalidData)?; - Ok(MoveItemParams { - grid_id: grid_id.0, - item_id: item_id.0, - from_index: self.from_index, - to_index: self.to_index, - ty: self.ty, - }) - } -} - -#[derive(Debug, Clone, Default, ProtoBuf)] -pub struct CellChangeset { - #[pb(index = 1)] - pub grid_id: String, - - #[pb(index = 2)] - pub row_id: String, - - #[pb(index = 3)] - pub field_id: String, - - #[pb(index = 4, one_of)] - pub cell_content_changeset: Option, -} diff --git a/shared-lib/flowy-grid-data-model/src/entities/mod.rs b/shared-lib/flowy-grid-data-model/src/entities/mod.rs deleted file mode 100644 index e6a16d8026..0000000000 --- a/shared-lib/flowy-grid-data-model/src/entities/mod.rs +++ /dev/null @@ -1,13 +0,0 @@ -mod field; -mod grid; -mod grid_filter; -mod grid_group; -mod grid_setting; -mod grid_sort; - -pub use field::*; -pub use grid::*; -pub use grid_filter::*; -pub use grid_group::*; -pub use grid_setting::*; -pub use grid_sort::*; diff --git a/shared-lib/flowy-grid-data-model/src/lib.rs b/shared-lib/flowy-grid-data-model/src/lib.rs index 0e92bcfc71..c4306291e8 100644 --- a/shared-lib/flowy-grid-data-model/src/lib.rs +++ b/shared-lib/flowy-grid-data-model/src/lib.rs @@ -1,4 +1,2 @@ -pub mod entities; pub mod parser; -pub mod protobuf; pub mod revision; diff --git a/shared-lib/flowy-grid-data-model/src/revision/grid_rev.rs b/shared-lib/flowy-grid-data-model/src/revision/grid_rev.rs index f083e6fb49..a214fe9aa6 100644 --- a/shared-lib/flowy-grid-data-model/src/revision/grid_rev.rs +++ b/shared-lib/flowy-grid-data-model/src/revision/grid_rev.rs @@ -1,4 +1,3 @@ -use crate::entities::{CellChangeset, Field, FieldOrder, FieldType, RowOrder}; use crate::revision::GridSettingRevision; use bytes::Bytes; use indexmap::IndexMap; @@ -29,7 +28,7 @@ pub fn gen_field_id() -> String { #[derive(Debug, Clone, Default, Serialize, Deserialize)] pub struct GridRevision { pub grid_id: String, - pub fields: Vec, + pub fields: Vec>, pub blocks: Vec>, #[serde(default, skip)] @@ -49,7 +48,7 @@ impl GridRevision { pub fn from_build_context(grid_id: &str, context: BuildGridContext) -> Self { Self { grid_id: grid_id.to_owned(), - fields: context.field_revs, + fields: context.field_revs.into_iter().map(Arc::new).collect(), blocks: context.blocks.into_iter().map(Arc::new).collect(), setting: Default::default(), } @@ -112,7 +111,8 @@ pub struct FieldRevision { pub desc: String, - pub field_type: FieldType, + #[serde(rename = "field_type")] + pub field_type_rev: FieldTypeRevision, pub frozen: bool, @@ -131,16 +131,27 @@ pub struct FieldRevision { pub is_primary: bool, } +impl AsRef for FieldRevision { + fn as_ref(&self) -> &FieldRevision { + self + } +} + const DEFAULT_IS_PRIMARY: fn() -> bool = || false; impl FieldRevision { - pub fn new(name: &str, desc: &str, field_type: FieldType, is_primary: bool) -> Self { - let width = field_type.default_cell_width(); + pub fn new>( + name: &str, + desc: &str, + field_type: T, + width: i32, + is_primary: bool, + ) -> Self { Self { id: gen_field_id(), name: name.to_string(), desc: desc.to_string(), - field_type, + field_type_rev: field_type.into(), frozen: false, visibility: true, width, @@ -153,49 +164,32 @@ impl FieldRevision { where T: TypeOptionDataEntry + ?Sized, { - self.type_options.insert(entry.field_type().type_id(), entry.json_str()); + let id = self.field_type_rev.to_string(); + self.type_options.insert(id, entry.json_str()); } - pub fn get_type_option_entry(&self, field_type: &FieldType) -> Option { - self.type_options - .get(&field_type.type_id()) - .map(|s| T::from_json_str(s)) + pub fn get_type_option_entry>( + &self, + field_type: T2, + ) -> Option { + let field_type_rev = field_type.into(); + let id = field_type_rev.to_string(); + self.type_options.get(&id).map(|s| T1::from_json_str(s)) } - pub fn insert_type_option_str(&mut self, field_type: &FieldType, json_str: String) { - self.type_options.insert(field_type.type_id(), json_str); + pub fn insert_type_option_str(&mut self, field_type: &FieldTypeRevision, json_str: String) { + let id = field_type.to_string(); + self.type_options.insert(id, json_str); } - pub fn get_type_option_str(&self, field_type: &FieldType) -> Option { - self.type_options.get(&field_type.type_id()).map(|s| s.to_owned()) - } -} - -impl std::convert::From for Field { - fn from(field_rev: FieldRevision) -> Self { - Self { - id: field_rev.id, - name: field_rev.name, - desc: field_rev.desc, - field_type: field_rev.field_type, - frozen: field_rev.frozen, - visibility: field_rev.visibility, - width: field_rev.width, - is_primary: field_rev.is_primary, - } - } -} - -impl std::convert::From<&FieldRevision> for FieldOrder { - fn from(field_rev: &FieldRevision) -> Self { - Self { - field_id: field_rev.id.clone(), - } + pub fn get_type_option_str>(&self, field_type: T) -> Option { + let field_type_rev = field_type.into(); + let id = field_type_rev.to_string(); + self.type_options.get(&id).map(|s| s.to_owned()) } } pub trait TypeOptionDataEntry { - fn field_type(&self) -> FieldType; fn json_str(&self) -> String; fn protobuf_bytes(&self) -> Bytes; } @@ -204,7 +198,7 @@ pub trait TypeOptionDataDeserializer { fn from_json_str(s: &str) -> Self; fn from_protobuf_bytes(bytes: Bytes) -> Self; } - +pub type FieldId = String; #[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] pub struct RowRevision { pub id: String, @@ -213,7 +207,7 @@ pub struct RowRevision { /// key: field id, /// value: CellMeta #[serde(with = "indexmap::serde_seq")] - pub cells: IndexMap, + pub cells: IndexMap, pub height: i32, pub visibility: bool, } @@ -229,51 +223,12 @@ impl RowRevision { } } } - -impl std::convert::From<&RowRevision> for RowOrder { - fn from(row: &RowRevision) -> Self { - Self { - row_id: row.id.clone(), - block_id: row.block_id.clone(), - height: row.height, - } - } -} - -impl std::convert::From<&Arc> for RowOrder { - fn from(row: &Arc) -> Self { - Self { - row_id: row.id.clone(), - block_id: row.block_id.clone(), - height: row.height, - } - } -} - #[derive(Debug, Clone, Default)] pub struct RowMetaChangeset { pub row_id: String, pub height: Option, pub visibility: Option, - pub cell_by_field_id: HashMap, -} - -impl std::convert::From for RowMetaChangeset { - fn from(changeset: CellChangeset) -> Self { - let mut cell_by_field_id = HashMap::with_capacity(1); - let field_id = changeset.field_id; - let cell_rev = CellRevision { - data: changeset.cell_content_changeset.unwrap_or_else(|| "".to_owned()), - }; - cell_by_field_id.insert(field_id, cell_rev); - - RowMetaChangeset { - row_id: changeset.row_id, - height: None, - visibility: None, - cell_by_field_id, - } - } + pub cell_by_field_id: HashMap, } #[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize)] @@ -315,3 +270,5 @@ impl std::convert::TryFrom for BuildGridContext { Ok(ctx) } } + +pub type FieldTypeRevision = u8; diff --git a/shared-lib/flowy-grid-data-model/src/revision/grid_setting_rev.rs b/shared-lib/flowy-grid-data-model/src/revision/grid_setting_rev.rs index 146d15d069..3ffcedb1c4 100644 --- a/shared-lib/flowy-grid-data-model/src/revision/grid_setting_rev.rs +++ b/shared-lib/flowy-grid-data-model/src/revision/grid_setting_rev.rs @@ -1,7 +1,9 @@ +use crate::revision::FieldTypeRevision; use indexmap::IndexMap; use nanoid::nanoid; use serde::{Deserialize, Serialize}; use serde_repr::*; +use std::sync::Arc; pub fn gen_grid_filter_id() -> String { nanoid!(6) @@ -18,9 +20,17 @@ pub fn gen_grid_sort_id() -> String { #[derive(Debug, Clone, Serialize, Deserialize, Default, Eq, PartialEq)] pub struct GridSettingRevision { pub layout: GridLayoutRevision, - + // layout: + // field_id: + // FieldType: GridFilterRevision + // FieldType: GridFilterRevision + // layout: + // field_id: + // FieldType: GridFilterRevision + // field_id: + // FieldType: GridFilterRevision #[serde(with = "indexmap::serde_seq")] - pub filters: IndexMap>, + pub filters: IndexMap>, #[serde(skip, with = "indexmap::serde_seq")] pub groups: IndexMap>, @@ -29,6 +39,78 @@ pub struct GridSettingRevision { pub sorts: IndexMap>, } +impl GridSettingRevision { + pub fn get_mut_filters( + &mut self, + layout: &GridLayoutRevision, + field_id: &str, + field_type: &FieldTypeRevision, + ) -> Option<&mut Vec>> { + self.filters + .get_mut(layout) + .and_then(|filter_rev_map_by_field_id| filter_rev_map_by_field_id.get_mut(field_id)) + .and_then(|filter_rev_map| filter_rev_map.get_mut(field_type)) + } + + pub fn get_filters( + &self, + layout: &GridLayoutRevision, + field_id: &str, + field_type: &FieldTypeRevision, + ) -> Option>> { + self.filters + .get(layout) + .and_then(|filter_rev_map_by_field_id| filter_rev_map_by_field_id.get(field_id)) + .and_then(|filter_rev_map| filter_rev_map.get(field_type)) + .cloned() + } + + pub fn insert_filter( + &mut self, + layout: &GridLayoutRevision, + field_id: &str, + field_type: &FieldTypeRevision, + filter_rev: GridFilterRevision, + ) { + let filter_rev_map_by_field_id = self.filters.entry(layout.clone()).or_insert_with(IndexMap::new); + let filter_rev_map = filter_rev_map_by_field_id + .entry(field_id.to_string()) + .or_insert_with(GridFilterRevisionMap::new); + + filter_rev_map + .entry(field_type.to_owned()) + .or_insert_with(Vec::new) + .push(Arc::new(filter_rev)) + } +} + +#[derive(Debug, Clone, Serialize, Deserialize, Default, Eq, PartialEq)] +#[serde(transparent)] +pub struct GridFilterRevisionMap { + #[serde(with = "indexmap::serde_seq")] + pub filter_by_field_type: IndexMap>>, +} + +impl GridFilterRevisionMap { + pub fn new() -> Self { + GridFilterRevisionMap::default() + } +} + +impl std::ops::Deref for GridFilterRevisionMap { + type Target = IndexMap>>; + + fn deref(&self) -> &Self::Target { + &self.filter_by_field_type + } +} + +impl std::ops::DerefMut for GridFilterRevisionMap { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.filter_by_field_type + } +} + #[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize_repr, Deserialize_repr)] #[repr(u8)] pub enum GridLayoutRevision { @@ -49,7 +131,7 @@ impl std::default::Default for GridLayoutRevision { } } -#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)] +#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq, Hash)] pub struct GridFilterRevision { pub id: String, pub field_id: String, diff --git a/shared-lib/flowy-sync/src/client_folder/builder.rs b/shared-lib/flowy-sync/src/client_folder/builder.rs index 73d9aac24f..4c27f278f5 100644 --- a/shared-lib/flowy-sync/src/client_folder/builder.rs +++ b/shared-lib/flowy-sync/src/client_folder/builder.rs @@ -1,4 +1,4 @@ -use crate::entities::folder_info::FolderDelta; +use crate::entities::folder::FolderDelta; use crate::util::make_delta_from_revisions; use crate::{ client_folder::{default_folder_delta, FolderPad}, diff --git a/shared-lib/flowy-sync/src/client_folder/folder_pad.rs b/shared-lib/flowy-sync/src/client_folder/folder_pad.rs index ac5758e64c..5743bfdb84 100644 --- a/shared-lib/flowy-sync/src/client_folder/folder_pad.rs +++ b/shared-lib/flowy-sync/src/client_folder/folder_pad.rs @@ -3,7 +3,7 @@ use crate::util::cal_diff; use crate::{ client_folder::builder::FolderPadBuilder, entities::{ - folder_info::FolderDelta, + folder::FolderDelta, revision::{md5, Revision}, }, errors::{CollaborateError, CollaborateResult}, @@ -431,7 +431,7 @@ pub struct FolderChange { #[cfg(test)] mod tests { #![allow(clippy::all)] - use crate::{client_folder::folder_pad::FolderPad, entities::folder_info::FolderDelta}; + use crate::{client_folder::folder_pad::FolderPad, entities::folder::FolderDelta}; use chrono::Utc; use flowy_folder_data_model::revision::{AppRevision, TrashRevision, ViewRevision, WorkspaceRevision}; diff --git a/shared-lib/flowy-sync/src/client_grid/grid_builder.rs b/shared-lib/flowy-sync/src/client_grid/grid_builder.rs index d539335ee7..d1fbed3f53 100644 --- a/shared-lib/flowy-sync/src/client_grid/grid_builder.rs +++ b/shared-lib/flowy-sync/src/client_grid/grid_builder.rs @@ -57,36 +57,3 @@ fn check_rows(fields: &[FieldRevision], rows: &[RowRevision]) -> CollaborateResu } Ok(()) } - -#[cfg(test)] -mod tests { - use crate::client_grid::{make_block_meta_delta, make_grid_delta, GridBuilder}; - use flowy_grid_data_model::entities::FieldType; - use flowy_grid_data_model::revision::{FieldRevision, GridBlockRevision, GridRevision}; - use std::sync::Arc; - - #[test] - fn create_default_grid_test() { - let grid_id = "1".to_owned(); - let build_context = GridBuilder::default() - .add_field(FieldRevision::new("Name", "", FieldType::RichText, true)) - .add_field(FieldRevision::new("Tags", "", FieldType::SingleSelect, false)) - .add_empty_row() - .add_empty_row() - .add_empty_row() - .build(); - - let grid_rev = GridRevision { - grid_id, - fields: build_context.field_revs, - blocks: build_context.blocks.into_iter().map(Arc::new).collect(), - setting: Default::default(), - }; - - let grid_meta_delta = make_grid_delta(&grid_rev); - let _: GridRevision = serde_json::from_str(&grid_meta_delta.to_str().unwrap()).unwrap(); - - let grid_block_meta_delta = make_block_meta_delta(build_context.blocks_meta_data.first().unwrap()); - let _: GridBlockRevision = serde_json::from_str(&grid_block_meta_delta.to_str().unwrap()).unwrap(); - } -} diff --git a/shared-lib/flowy-sync/src/client_grid/grid_revision_pad.rs b/shared-lib/flowy-sync/src/client_grid/grid_revision_pad.rs index 2ff58582f4..8b724d8133 100644 --- a/shared-lib/flowy-sync/src/client_grid/grid_revision_pad.rs +++ b/shared-lib/flowy-sync/src/client_grid/grid_revision_pad.rs @@ -1,13 +1,12 @@ +use crate::entities::grid::{FieldChangesetParams, GridSettingChangesetParams}; use crate::entities::revision::{md5, RepeatedRevision, Revision}; use crate::errors::{internal_error, CollaborateError, CollaborateResult}; use crate::util::{cal_diff, make_delta_from_revisions}; use bytes::Bytes; -use flowy_grid_data_model::entities::{FieldChangesetParams, FieldOrder}; -use flowy_grid_data_model::entities::{FieldType, GridSettingChangesetParams}; use flowy_grid_data_model::revision::{ gen_block_id, gen_grid_filter_id, gen_grid_group_id, gen_grid_id, gen_grid_sort_id, FieldRevision, - GridBlockMetaRevision, GridBlockMetaRevisionChangeset, GridFilterRevision, GridGroupRevision, GridLayoutRevision, - GridRevision, GridSettingRevision, GridSortRevision, + FieldTypeRevision, GridBlockMetaRevision, GridBlockMetaRevisionChangeset, GridFilterRevision, GridGroupRevision, + GridLayoutRevision, GridRevision, GridSettingRevision, GridSortRevision, }; use lib_infra::util::move_vec_element; use lib_ot::core::{OperationTransformable, PlainTextAttributes, PlainTextDelta, PlainTextDeltaBuilder}; @@ -27,8 +26,16 @@ pub trait JsonDeserializer { } impl GridRevisionPad { + pub fn grid_id(&self) -> String { + self.grid_rev.grid_id.clone() + } pub async fn duplicate_grid_block_meta(&self) -> (Vec, Vec) { - let fields = self.grid_rev.fields.to_vec(); + let fields = self + .grid_rev + .fields + .iter() + .map(|field_rev| field_rev.as_ref().clone()) + .collect(); let blocks = self .grid_rev @@ -81,7 +88,7 @@ impl GridRevisionPad { None => None, Some(start_field_id) => grid_meta.fields.iter().position(|field| field.id == start_field_id), }; - + let new_field_rev = Arc::new(new_field_rev); match insert_index { None => grid_meta.fields.push(new_field_rev), Some(index) => grid_meta.fields.insert(index, new_field_rev), @@ -111,25 +118,27 @@ impl GridRevisionPad { |grid_meta| match grid_meta.fields.iter().position(|field| field.id == field_id) { None => Ok(None), Some(index) => { - let mut duplicate_field_rev = grid_meta.fields[index].clone(); + let mut duplicate_field_rev = grid_meta.fields[index].as_ref().clone(); duplicate_field_rev.id = duplicated_field_id.to_string(); duplicate_field_rev.name = format!("{} (copy)", duplicate_field_rev.name); - grid_meta.fields.insert(index + 1, duplicate_field_rev); + grid_meta.fields.insert(index + 1, Arc::new(duplicate_field_rev)); Ok(Some(())) } }, ) } - pub fn switch_to_field( + pub fn switch_to_field( &mut self, field_id: &str, - field_type: FieldType, + field_type: T, type_option_json_builder: B, ) -> CollaborateResult> where - B: FnOnce(&FieldType) -> String, + B: FnOnce(&FieldTypeRevision) -> String, + T: Into, { + let field_type = field_type.into(); self.modify_grid(|grid_meta| { // match grid_meta.fields.iter_mut().find(|field_rev| field_rev.id == field_id) { @@ -138,12 +147,13 @@ impl GridRevisionPad { Ok(None) } Some(field_rev) => { - if field_rev.get_type_option_str(&field_type).is_none() { + let mut_field_rev = Arc::make_mut(field_rev); + if mut_field_rev.get_type_option_str(field_type).is_none() { let type_option_json = type_option_json_builder(&field_type); - field_rev.insert_type_option_str(&field_type, type_option_json); + mut_field_rev.insert_type_option_str(&field_type, type_option_json); } - field_rev.field_type = field_type; + mut_field_rev.field_type_rev = field_type; Ok(Some(())) } } @@ -169,7 +179,7 @@ impl GridRevisionPad { } if let Some(field_type) = changeset.field_type { - field.field_type = field_type; + field.field_type_rev = field_type; is_changed = Some(()) } @@ -191,7 +201,7 @@ impl GridRevisionPad { if let Some(type_option_data) = changeset.type_option_data { match deserializer.deserialize(type_option_data) { Ok(json_str) => { - let field_type = field.field_type.clone(); + let field_type = field.field_type_rev; field.insert_type_option_str(&field_type, json_str); is_changed = Some(()) } @@ -205,7 +215,7 @@ impl GridRevisionPad { }) } - pub fn get_field_rev(&self, field_id: &str) -> Option<(usize, &FieldRevision)> { + pub fn get_field_rev(&self, field_id: &str) -> Option<(usize, &Arc)> { self.grid_rev .fields .iter() @@ -213,7 +223,7 @@ impl GridRevisionPad { .find(|(_, field)| field.id == field_id) } - pub fn replace_field_rev(&mut self, field_rev: FieldRevision) -> CollaborateResult> { + pub fn replace_field_rev(&mut self, field_rev: Arc) -> CollaborateResult> { self.modify_grid( |grid_meta| match grid_meta.fields.iter().position(|field| field.id == field_rev.id) { None => Ok(None), @@ -251,31 +261,27 @@ impl GridRevisionPad { self.grid_rev.fields.iter().any(|field| field.id == field_id) } - pub fn get_field_orders(&self) -> Vec { - self.grid_rev.fields.iter().map(FieldOrder::from).collect() - } - - pub fn get_field_revs(&self, field_orders: Option>) -> CollaborateResult> { - match field_orders { + pub fn get_field_revs(&self, field_ids: Option>) -> CollaborateResult>> { + match field_ids { None => Ok(self.grid_rev.fields.clone()), - Some(field_orders) => { + Some(field_ids) => { let field_by_field_id = self .grid_rev .fields .iter() .map(|field| (&field.id, field)) - .collect::>(); + .collect::>>(); - let fields = field_orders + let fields = field_ids .iter() - .flat_map(|field_order| match field_by_field_id.get(&field_order.field_id) { + .flat_map(|field_id| match field_by_field_id.get(&field_id) { None => { - tracing::error!("Can't find the field with id: {}", field_order.field_id); + tracing::error!("Can't find the field with id: {}", field_id); None } Some(field) => Some((*field).clone()), }) - .collect::>(); + .collect::>>(); Ok(fields) } } @@ -334,9 +340,35 @@ impl GridRevisionPad { &self.grid_rev.setting } - pub fn get_filters(&self, layout: Option<&GridLayoutRevision>) -> Option<&Vec> { + /// If layout is None, then the default layout will be the read from GridSettingRevision + pub fn get_filters( + &self, + layout: Option<&GridLayoutRevision>, + field_ids: Option>, + ) -> Option>> { + let mut filter_revs = vec![]; let layout_ty = layout.unwrap_or(&self.grid_rev.setting.layout); - self.grid_rev.setting.filters.get(layout_ty) + let field_revs = self.get_field_revs(None).ok()?; + + field_revs.iter().for_each(|field_rev| { + let mut is_contain = true; + if let Some(field_ids) = &field_ids { + is_contain = field_ids.contains(&field_rev.id); + } + + if is_contain { + // Only return the filters for the current fields' type. + if let Some(mut t_filter_revs) = + self.grid_rev + .setting + .get_filters(layout_ty, &field_rev.id, &field_rev.field_type_rev) + { + filter_revs.append(&mut t_filter_revs); + } + } + }); + + Some(filter_revs) } pub fn update_grid_setting_rev( @@ -345,28 +377,30 @@ impl GridRevisionPad { ) -> CollaborateResult> { self.modify_grid(|grid_rev| { let mut is_changed = None; - let layout_rev: GridLayoutRevision = changeset.layout_type.into(); + let layout_rev = changeset.layout_type; if let Some(params) = changeset.insert_filter { - let rev = GridFilterRevision { + let filter_rev = GridFilterRevision { id: gen_grid_filter_id(), - field_id: params.field_id, + field_id: params.field_id.clone(), condition: params.condition, content: params.content, }; grid_rev .setting - .filters - .entry(layout_rev.clone()) - .or_insert_with(std::vec::Vec::new) - .push(rev); + .insert_filter(&layout_rev, ¶ms.field_id, ¶ms.field_type_rev, filter_rev); is_changed = Some(()) } - if let Some(delete_filter_id) = changeset.delete_filter { - match grid_rev.setting.filters.get_mut(&layout_rev) { - Some(filters) => filters.retain(|filter| filter.id != delete_filter_id), + if let Some(params) = changeset.delete_filter { + match grid_rev + .setting + .get_mut_filters(&layout_rev, ¶ms.filter_id, ¶ms.field_type_rev) + { + Some(filters) => { + filters.retain(|filter| filter.id != params.filter_id); + } None => { tracing::warn!("Can't find the filter with {:?}", layout_rev); } @@ -435,7 +469,7 @@ impl GridRevisionPad { self.delta.to_delta_bytes() } - pub fn fields(&self) -> &[FieldRevision] { + pub fn fields(&self) -> &[Arc] { &self.grid_rev.fields } @@ -488,7 +522,10 @@ impl GridRevisionPad { tracing::warn!("[GridMetaPad]: Can't find any field with id: {}", field_id); Ok(None) } - Some(index) => f(&mut grid_rev.fields[index]), + Some(index) => { + let mut_field_rev = Arc::make_mut(&mut grid_rev.fields[index]); + f(mut_field_rev) + } }, ) } diff --git a/shared-lib/flowy-sync/src/entities/folder_info.rs b/shared-lib/flowy-sync/src/entities/folder.rs similarity index 100% rename from shared-lib/flowy-sync/src/entities/folder_info.rs rename to shared-lib/flowy-sync/src/entities/folder.rs diff --git a/shared-lib/flowy-sync/src/entities/grid.rs b/shared-lib/flowy-sync/src/entities/grid.rs new file mode 100644 index 0000000000..866562ccd6 --- /dev/null +++ b/shared-lib/flowy-sync/src/entities/grid.rs @@ -0,0 +1,57 @@ +use flowy_grid_data_model::revision::{FieldTypeRevision, GridLayoutRevision}; + +pub struct GridSettingChangesetParams { + pub grid_id: String, + pub layout_type: GridLayoutRevision, + pub insert_filter: Option, + pub delete_filter: Option, + pub insert_group: Option, + pub delete_group: Option, + pub insert_sort: Option, + pub delete_sort: Option, +} + +impl GridSettingChangesetParams { + pub fn is_filter_changed(&self) -> bool { + self.insert_filter.is_some() || self.delete_filter.is_some() + } +} +pub struct CreateGridFilterParams { + pub field_id: String, + pub field_type_rev: FieldTypeRevision, + pub condition: u8, + pub content: Option, +} + +pub struct DeleteFilterParams { + pub filter_id: String, + pub field_type_rev: FieldTypeRevision, +} +pub struct CreateGridGroupParams { + pub field_id: Option, + pub sub_field_id: Option, +} +pub struct CreateGridSortParams { + pub field_id: Option, +} + +#[derive(Debug, Clone, Default)] +pub struct FieldChangesetParams { + pub field_id: String, + + pub grid_id: String, + + pub name: Option, + + pub desc: Option, + + pub field_type: Option, + + pub frozen: Option, + + pub visibility: Option, + + pub width: Option, + + pub type_option_data: Option>, +} diff --git a/shared-lib/flowy-sync/src/entities/mod.rs b/shared-lib/flowy-sync/src/entities/mod.rs index 8989125677..768640454b 100644 --- a/shared-lib/flowy-sync/src/entities/mod.rs +++ b/shared-lib/flowy-sync/src/entities/mod.rs @@ -1,5 +1,6 @@ -pub mod folder_info; +pub mod folder; +pub mod grid; pub mod parser; pub mod revision; -pub mod text_block_info; +pub mod text_block; pub mod ws_data; diff --git a/shared-lib/flowy-sync/src/entities/text_block_info.rs b/shared-lib/flowy-sync/src/entities/text_block.rs similarity index 100% rename from shared-lib/flowy-sync/src/entities/text_block_info.rs rename to shared-lib/flowy-sync/src/entities/text_block.rs diff --git a/shared-lib/flowy-sync/src/server_document/document_manager.rs b/shared-lib/flowy-sync/src/server_document/document_manager.rs index 8ce136480e..8d547a9484 100644 --- a/shared-lib/flowy-sync/src/server_document/document_manager.rs +++ b/shared-lib/flowy-sync/src/server_document/document_manager.rs @@ -1,5 +1,5 @@ use crate::{ - entities::{text_block_info::TextBlockInfo, ws_data::ServerRevisionWSDataBuilder}, + entities::{text_block::TextBlockInfo, ws_data::ServerRevisionWSDataBuilder}, errors::{internal_error, CollaborateError, CollaborateResult}, protobuf::{ClientRevisionWSData, RepeatedRevision as RepeatedRevisionPB, Revision as RevisionPB}, server_document::document_pad::ServerDocument, diff --git a/shared-lib/flowy-sync/src/server_folder/folder_manager.rs b/shared-lib/flowy-sync/src/server_folder/folder_manager.rs index 96b7cb71cb..0a1a5e117a 100644 --- a/shared-lib/flowy-sync/src/server_folder/folder_manager.rs +++ b/shared-lib/flowy-sync/src/server_folder/folder_manager.rs @@ -1,6 +1,6 @@ use crate::{ entities::{ - folder_info::{FolderDelta, FolderInfo}, + folder::{FolderDelta, FolderInfo}, ws_data::ServerRevisionWSDataBuilder, }, errors::{internal_error, CollaborateError, CollaborateResult}, diff --git a/shared-lib/flowy-sync/src/server_folder/folder_pad.rs b/shared-lib/flowy-sync/src/server_folder/folder_pad.rs index 3b51e52ed7..09b4c9d048 100644 --- a/shared-lib/flowy-sync/src/server_folder/folder_pad.rs +++ b/shared-lib/flowy-sync/src/server_folder/folder_pad.rs @@ -1,4 +1,4 @@ -use crate::{entities::folder_info::FolderDelta, errors::CollaborateError, synchronizer::RevisionSyncObject}; +use crate::{entities::folder::FolderDelta, errors::CollaborateError, synchronizer::RevisionSyncObject}; use lib_ot::core::{OperationTransformable, PlainTextAttributes, PlainTextDelta}; pub struct ServerFolder { diff --git a/shared-lib/flowy-sync/src/util.rs b/shared-lib/flowy-sync/src/util.rs index a3ea7b136e..3fc09c5932 100644 --- a/shared-lib/flowy-sync/src/util.rs +++ b/shared-lib/flowy-sync/src/util.rs @@ -1,8 +1,8 @@ use crate::{ entities::{ - folder_info::{FolderDelta, FolderInfo}, + folder::{FolderDelta, FolderInfo}, revision::{RepeatedRevision, Revision}, - text_block_info::TextBlockInfo, + text_block::TextBlockInfo, }, errors::{CollaborateError, CollaborateResult}, protobuf::{