Browse Source

chore: fix warnings

appflowy 3 years ago
parent
commit
318d7e6456
23 changed files with 253 additions and 457 deletions
  1. 5 4
      frontend/app_flowy/lib/workspace/application/grid/grid_block_service.dart
  2. 3 0
      frontend/app_flowy/lib/workspace/application/grid/grid_service.dart
  3. 21 11
      frontend/app_flowy/lib/workspace/application/grid/row_bloc.dart
  4. 2 0
      frontend/app_flowy/lib/workspace/application/grid/row_service.dart
  5. 1 1
      frontend/app_flowy/lib/workspace/presentation/plugins/grid/grid.dart
  6. 0 1
      frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/content/cell_builder.dart
  7. 15 10
      frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/content/grid_row.dart
  8. 18 45
      frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pb.dart
  9. 4 13
      frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pbjson.dart
  10. 2 2
      frontend/rust-lib/dart-ffi/Cargo.toml
  11. 1 1
      frontend/rust-lib/flowy-grid/src/event_handler.rs
  12. 5 25
      frontend/rust-lib/flowy-grid/src/services/block_meta_editor.rs
  13. 16 14
      frontend/rust-lib/flowy-grid/src/services/grid_editor.rs
  14. 19 16
      frontend/rust-lib/flowy-grid/src/services/row/row_builder.rs
  15. 11 11
      frontend/rust-lib/flowy-grid/src/services/row/row_loader.rs
  16. 0 33
      frontend/rust-lib/flowy-grid/src/services/util.rs
  17. 8 8
      frontend/rust-lib/flowy-grid/tests/grid/grid_test.rs
  18. 19 6
      frontend/rust-lib/flowy-grid/tests/grid/script.rs
  19. 8 31
      shared-lib/flowy-grid-data-model/src/entities/grid.rs
  20. 0 2
      shared-lib/flowy-grid-data-model/src/entities/meta.rs
  21. 0 2
      shared-lib/flowy-grid-data-model/src/parser/id.rs
  22. 93 217
      shared-lib/flowy-grid-data-model/src/protobuf/model/grid.rs
  23. 2 4
      shared-lib/flowy-grid-data-model/src/protobuf/proto/grid.proto

+ 5 - 4
frontend/app_flowy/lib/workspace/application/grid/grid_block_service.dart

@@ -37,13 +37,14 @@ class GridBlockService {
 
   List<GridRowData> rows() {
     List<GridRowData> rows = [];
-    blockMap.forEach((_, gridBlock) {
-      rows.addAll(gridBlock.rowIds.map(
-        (rowId) => GridRowData(
+    blockMap.forEach((_, GridBlock gridBlock) {
+      rows.addAll(gridBlock.rowOrders.map(
+        (rowOrder) => GridRowData(
           gridId: gridId,
           fields: fields,
           blockId: gridBlock.blockId,
-          rowId: rowId,
+          rowId: rowOrder.rowId,
+          height: rowOrder.height.toDouble(),
         ),
       ));
     });

+ 3 - 0
frontend/app_flowy/lib/workspace/application/grid/grid_service.dart

@@ -40,11 +40,14 @@ class GridRowData extends Equatable {
   final String rowId;
   final String blockId;
   final List<Field> fields;
+  final double height;
+
   const GridRowData({
     required this.gridId,
     required this.rowId,
     required this.blockId,
     required this.fields,
+    required this.height,
   });
 
   @override

+ 21 - 11
frontend/app_flowy/lib/workspace/application/grid/row_bloc.dart

@@ -1,4 +1,5 @@
 import 'package:flowy_sdk/log.dart';
+import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
 import 'package:freezed_annotation/freezed_annotation.dart';
 import 'dart:async';
@@ -61,20 +62,29 @@ class RowBloc extends Bloc<RowEvent, RowState> {
     final result = await rowService.getRow();
     result.fold(
       (row) {
-        final cellDatas = rowService.rowData.fields.map((field) {
-          final cell = row.cellByFieldId[field.id];
-          return GridCellData(
-            rowId: row.id,
-            gridId: rowService.rowData.gridId,
-            cell: cell,
-            field: field,
-          );
-        }).toList();
-        emit(state.copyWith(cellDatas: cellDatas, rowHeight: row.height.toDouble()));
+        emit(state.copyWith(
+          cellDatas: makeGridCellDatas(row),
+          rowHeight: row.height.toDouble(),
+        ));
       },
       (e) => Log.error(e),
     );
   }
+
+  List<GridCellData> makeGridCellDatas(Row row) {
+    return rowService.rowData.fields.map((field) {
+      final cell = row.cellByFieldId[field.id];
+      final rowData = rowService.rowData;
+
+      return GridCellData(
+        rowId: row.id,
+        gridId: rowData.gridId,
+        blockId: rowData.blockId,
+        cell: cell,
+        field: field,
+      );
+    }).toList();
+  }
 }
 
 @freezed
@@ -97,7 +107,7 @@ abstract class RowState with _$RowState {
   factory RowState.initial(GridRowData data) => RowState(
         rowId: data.rowId,
         active: false,
-        rowHeight: 0,
+        rowHeight: data.height,
         cellDatas: [],
       );
 }

+ 2 - 0
frontend/app_flowy/lib/workspace/application/grid/row_service.dart

@@ -31,12 +31,14 @@ class RowService {
 class GridCellData {
   final String gridId;
   final String rowId;
+  final String blockId;
   final Field field;
   final Cell? cell;
 
   GridCellData({
     required this.rowId,
     required this.gridId,
+    required this.blockId,
     required this.field,
     required this.cell,
   });

+ 1 - 1
frontend/app_flowy/lib/workspace/presentation/plugins/grid/grid.dart

@@ -28,7 +28,7 @@ class GridPluginBuilder implements PluginBuilder {
 
 class GridPluginConfig implements PluginConfig {
   @override
-  bool get creatable => true;
+  bool get creatable => false;
 }
 
 class GridPlugin extends Plugin {

+ 0 - 1
frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/content/cell_builder.dart

@@ -1,4 +1,3 @@
-import 'package:app_flowy/workspace/application/grid/cell_bloc/cell_service.dart';
 import 'package:app_flowy/workspace/application/grid/row_service.dart';
 import 'package:flowy_sdk/protobuf/flowy-grid-data-model/meta.pb.dart';
 import 'package:flutter/widgets.dart';

+ 15 - 10
frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/content/grid_row.dart

@@ -36,16 +36,21 @@ class _GridRowWidgetState extends State<GridRowWidget> {
           cursor: SystemMouseCursors.click,
           onEnter: (p) => _rowBloc.add(const RowEvent.activeRow()),
           onExit: (p) => _rowBloc.add(const RowEvent.disactiveRow()),
-          child: SizedBox(
-            height: _rowBloc.state.rowHeight,
-            child: Row(
-              crossAxisAlignment: CrossAxisAlignment.stretch,
-              children: [
-                const LeadingRow(),
-                _buildCells(),
-                const TrailingRow(),
-              ],
-            ),
+          child: BlocBuilder<RowBloc, RowState>(
+            buildWhen: (p, c) => p.rowHeight != c.rowHeight,
+            builder: (context, state) {
+              return SizedBox(
+                height: _rowBloc.state.rowHeight,
+                child: Row(
+                  crossAxisAlignment: CrossAxisAlignment.stretch,
+                  children: [
+                    const LeadingRow(),
+                    _buildCells(),
+                    const TrailingRow(),
+                  ],
+                ),
+              );
+            },
           ),
         ),
       ),

+ 18 - 45
frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pb.dart

@@ -338,6 +338,7 @@ class RowOrder extends $pb.GeneratedMessage {
   static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'RowOrder', createEmptyInstance: create)
     ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'rowId')
     ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'blockId')
+    ..a<$core.int>(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'height', $pb.PbFieldType.O3)
     ..hasRequiredFields = false
   ;
 
@@ -345,6 +346,7 @@ class RowOrder extends $pb.GeneratedMessage {
   factory RowOrder({
     $core.String? rowId,
     $core.String? blockId,
+    $core.int? height,
   }) {
     final _result = create();
     if (rowId != null) {
@@ -353,6 +355,9 @@ class RowOrder extends $pb.GeneratedMessage {
     if (blockId != null) {
       _result.blockId = blockId;
     }
+    if (height != null) {
+      _result.height = height;
+    }
     return _result;
   }
   factory RowOrder.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
@@ -393,47 +398,15 @@ class RowOrder extends $pb.GeneratedMessage {
   $core.bool hasBlockId() => $_has(1);
   @$pb.TagNumber(2)
   void clearBlockId() => clearField(2);
-}
 
-class RepeatedRowOrder extends $pb.GeneratedMessage {
-  static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'RepeatedRowOrder', createEmptyInstance: create)
-    ..pc<RowOrder>(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'items', $pb.PbFieldType.PM, subBuilder: RowOrder.create)
-    ..hasRequiredFields = false
-  ;
-
-  RepeatedRowOrder._() : super();
-  factory RepeatedRowOrder({
-    $core.Iterable<RowOrder>? items,
-  }) {
-    final _result = create();
-    if (items != null) {
-      _result.items.addAll(items);
-    }
-    return _result;
-  }
-  factory RepeatedRowOrder.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
-  factory RepeatedRowOrder.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
-  @$core.Deprecated(
-  'Using this can add significant overhead to your binary. '
-  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
-  'Will be removed in next major version')
-  RepeatedRowOrder clone() => RepeatedRowOrder()..mergeFromMessage(this);
-  @$core.Deprecated(
-  'Using this can add significant overhead to your binary. '
-  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
-  'Will be removed in next major version')
-  RepeatedRowOrder copyWith(void Function(RepeatedRowOrder) updates) => super.copyWith((message) => updates(message as RepeatedRowOrder)) as RepeatedRowOrder; // ignore: deprecated_member_use
-  $pb.BuilderInfo get info_ => _i;
-  @$core.pragma('dart2js:noInline')
-  static RepeatedRowOrder create() => RepeatedRowOrder._();
-  RepeatedRowOrder createEmptyInstance() => create();
-  static $pb.PbList<RepeatedRowOrder> createRepeated() => $pb.PbList<RepeatedRowOrder>();
-  @$core.pragma('dart2js:noInline')
-  static RepeatedRowOrder getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<RepeatedRowOrder>(create);
-  static RepeatedRowOrder? _defaultInstance;
-
-  @$pb.TagNumber(1)
-  $core.List<RowOrder> get items => $_getList(0);
+  @$pb.TagNumber(3)
+  $core.int get height => $_getIZ(2);
+  @$pb.TagNumber(3)
+  set height($core.int v) { $_setSignedInt32(2, v); }
+  @$pb.TagNumber(3)
+  $core.bool hasHeight() => $_has(2);
+  @$pb.TagNumber(3)
+  void clearHeight() => clearField(3);
 }
 
 class Row extends $pb.GeneratedMessage {
@@ -637,21 +610,21 @@ class GridBlockOrder extends $pb.GeneratedMessage {
 class GridBlock extends $pb.GeneratedMessage {
   static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'GridBlock', createEmptyInstance: create)
     ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'blockId')
-    ..pPS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'rowIds')
+    ..pc<RowOrder>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'rowOrders', $pb.PbFieldType.PM, subBuilder: RowOrder.create)
     ..hasRequiredFields = false
   ;
 
   GridBlock._() : super();
   factory GridBlock({
     $core.String? blockId,
-    $core.Iterable<$core.String>? rowIds,
+    $core.Iterable<RowOrder>? rowOrders,
   }) {
     final _result = create();
     if (blockId != null) {
       _result.blockId = blockId;
     }
-    if (rowIds != null) {
-      _result.rowIds.addAll(rowIds);
+    if (rowOrders != null) {
+      _result.rowOrders.addAll(rowOrders);
     }
     return _result;
   }
@@ -686,7 +659,7 @@ class GridBlock extends $pb.GeneratedMessage {
   void clearBlockId() => clearField(1);
 
   @$pb.TagNumber(2)
-  $core.List<$core.String> get rowIds => $_getList(1);
+  $core.List<RowOrder> get rowOrders => $_getList(1);
 }
 
 class Cell extends $pb.GeneratedMessage {

+ 4 - 13
frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pbjson.dart

@@ -72,21 +72,12 @@ const RowOrder$json = const {
   '2': const [
     const {'1': 'row_id', '3': 1, '4': 1, '5': 9, '10': 'rowId'},
     const {'1': 'block_id', '3': 2, '4': 1, '5': 9, '10': 'blockId'},
+    const {'1': 'height', '3': 3, '4': 1, '5': 5, '10': 'height'},
   ],
 };
 
 /// Descriptor for `RowOrder`. Decode as a `google.protobuf.DescriptorProto`.
-final $typed_data.Uint8List rowOrderDescriptor = $convert.base64Decode('CghSb3dPcmRlchIVCgZyb3dfaWQYASABKAlSBXJvd0lkEhkKCGJsb2NrX2lkGAIgASgJUgdibG9ja0lk');
-@$core.Deprecated('Use repeatedRowOrderDescriptor instead')
-const RepeatedRowOrder$json = const {
-  '1': 'RepeatedRowOrder',
-  '2': const [
-    const {'1': 'items', '3': 1, '4': 3, '5': 11, '6': '.RowOrder', '10': 'items'},
-  ],
-};
-
-/// Descriptor for `RepeatedRowOrder`. Decode as a `google.protobuf.DescriptorProto`.
-final $typed_data.Uint8List repeatedRowOrderDescriptor = $convert.base64Decode('ChBSZXBlYXRlZFJvd09yZGVyEh8KBWl0ZW1zGAEgAygLMgkuUm93T3JkZXJSBWl0ZW1z');
+final $typed_data.Uint8List rowOrderDescriptor = $convert.base64Decode('CghSb3dPcmRlchIVCgZyb3dfaWQYASABKAlSBXJvd0lkEhkKCGJsb2NrX2lkGAIgASgJUgdibG9ja0lkEhYKBmhlaWdodBgDIAEoBVIGaGVpZ2h0');
 @$core.Deprecated('Use rowDescriptor instead')
 const Row$json = const {
   '1': 'Row',
@@ -145,12 +136,12 @@ const GridBlock$json = const {
   '1': 'GridBlock',
   '2': const [
     const {'1': 'block_id', '3': 1, '4': 1, '5': 9, '10': 'blockId'},
-    const {'1': 'row_ids', '3': 2, '4': 3, '5': 9, '10': 'rowIds'},
+    const {'1': 'row_orders', '3': 2, '4': 3, '5': 11, '6': '.RowOrder', '10': 'rowOrders'},
   ],
 };
 
 /// Descriptor for `GridBlock`. Decode as a `google.protobuf.DescriptorProto`.
-final $typed_data.Uint8List gridBlockDescriptor = $convert.base64Decode('CglHcmlkQmxvY2sSGQoIYmxvY2tfaWQYASABKAlSB2Jsb2NrSWQSFwoHcm93X2lkcxgCIAMoCVIGcm93SWRz');
+final $typed_data.Uint8List gridBlockDescriptor = $convert.base64Decode('CglHcmlkQmxvY2sSGQoIYmxvY2tfaWQYASABKAlSB2Jsb2NrSWQSKAoKcm93X29yZGVycxgCIAMoCzIJLlJvd09yZGVyUglyb3dPcmRlcnM=');
 @$core.Deprecated('Use cellDescriptor instead')
 const Cell$json = const {
   '1': 'Cell',

+ 2 - 2
frontend/rust-lib/dart-ffi/Cargo.toml

@@ -7,8 +7,8 @@ edition = "2018"
 [lib]
 name = "dart_ffi"
 # this value will change depending on the target os
-# default cdylib
-crate-type = ["cdylib"]
+# default staticlib
+crate-type = ["staticlib"]
 
 
 [dependencies]

+ 1 - 1
frontend/rust-lib/flowy-grid/src/event_handler.rs

@@ -2,7 +2,7 @@ use crate::manager::GridManager;
 use flowy_error::FlowyError;
 use flowy_grid_data_model::entities::{
     CellMetaChangeset, CreateRowPayload, Field, Grid, GridId, QueryFieldPayload, QueryGridBlocksPayload,
-    QueryRowPayload, RepeatedField, RepeatedGridBlock, RepeatedRow, Row,
+    QueryRowPayload, RepeatedField, RepeatedGridBlock, Row,
 };
 use flowy_grid_data_model::parser::{CreateRowParams, QueryFieldParams, QueryGridBlocksParams, QueryRowParams};
 use lib_dispatch::prelude::{data_result, AppData, Data, DataResult};

+ 5 - 25
frontend/rust-lib/flowy-grid/src/services/block_meta_editor.rs

@@ -9,8 +9,7 @@ use flowy_collaboration::entities::revision::Revision;
 use flowy_collaboration::util::make_delta_from_revisions;
 use flowy_error::{FlowyError, FlowyResult};
 use flowy_grid_data_model::entities::{
-    FieldMeta, GridBlockId, GridBlockMeta, GridBlockMetaChangeset, RepeatedCell, RepeatedRowOrder, RowMeta,
-    RowMetaChangeset, RowOrder,
+    FieldMeta, GridBlockId, GridBlockMeta, GridBlockMetaChangeset, RepeatedCell, RowMeta, RowMetaChangeset, RowOrder,
 };
 use flowy_sync::disk::SQLiteGridBlockMetaRevisionPersistence;
 use flowy_sync::{
@@ -92,16 +91,7 @@ impl GridBlockMetaEditorManager {
         Ok(changesets)
     }
 
-    pub(crate) async fn delete_rows(&self, row_ids: Vec<String>) -> FlowyResult<Vec<GridBlockMetaChangeset>> {
-        let row_orders = row_ids
-            .into_iter()
-            .flat_map(|row_id| {
-                self.block_id_by_row_id.get(&row_id).map(|block_id| RowOrder {
-                    row_id,
-                    block_id: block_id.clone(),
-                })
-            })
-            .collect::<Vec<RowOrder>>();
+    pub(crate) async fn delete_rows(&self, row_orders: Vec<RowOrder>) -> FlowyResult<Vec<GridBlockMetaChangeset>> {
         let mut changesets = vec![];
         let row_ids_per_blocks = make_row_ids_per_block(&row_orders);
         for row_ids_per_block in row_ids_per_blocks {
@@ -163,7 +153,7 @@ impl GridBlockMetaEditorManager {
     pub(crate) async fn get_block_meta_data(&self, block_ids: &[String]) -> FlowyResult<Vec<GridBlockMetaData>> {
         let mut snapshots = vec![];
         for block_id in block_ids {
-            let editor = self.get_editor(&block_id).await?;
+            let editor = self.get_editor(block_id).await?;
             let row_metas = editor.get_row_metas(None).await?;
             row_metas.iter().for_each(|row_meta| {
                 self.block_id_by_row_id
@@ -177,16 +167,6 @@ impl GridBlockMetaEditorManager {
         Ok(snapshots)
     }
 
-    pub(crate) async fn get_row_orders(&self, grid_block_ids: Vec<String>) -> FlowyResult<Vec<RowOrder>> {
-        let mut row_orders = vec![];
-        for grid_block_id in grid_block_ids {
-            let editor = self.get_editor(&grid_block_id).await?;
-            let new_row_order = editor.get_row_orders().await?;
-            row_orders.extend(new_row_order);
-        }
-        Ok(row_orders)
-    }
-
     async fn get_editor_from_row_id(&self, row_id: &str) -> FlowyResult<Arc<ClientGridBlockMetaEditor>> {
         match self.block_id_by_row_id.get(row_id) {
             None => {
@@ -328,12 +308,12 @@ impl ClientGridBlockMetaEditor {
         Ok(row_metas)
     }
 
-    pub async fn get_row_orders(&self) -> FlowyResult<Vec<RowOrder>> {
+    pub async fn get_row_orders(&self, row_ids: Option<Vec<String>>) -> FlowyResult<Vec<RowOrder>> {
         let row_orders = self
             .pad
             .read()
             .await
-            .get_rows(None)?
+            .get_rows(row_ids)?
             .iter()
             .map(RowOrder::from)
             .collect::<Vec<RowOrder>>();

+ 16 - 14
frontend/rust-lib/flowy-grid/src/services/grid_editor.rs

@@ -6,16 +6,15 @@ use flowy_collaboration::entities::revision::Revision;
 use flowy_collaboration::util::make_delta_from_revisions;
 use flowy_error::{FlowyError, FlowyResult};
 use flowy_grid_data_model::entities::{
-    Cell, CellMetaChangeset, Field, FieldChangeset, FieldMeta, Grid, GridBlockMeta, GridBlockMetaChangeset,
-    GridBlockOrder, RepeatedField, RepeatedFieldOrder, RepeatedGridBlock, RepeatedRow, RepeatedRowOrder, Row, RowMeta,
-    RowMetaChangeset,
+    CellMetaChangeset, Field, FieldChangeset, FieldMeta, Grid, GridBlockMeta, GridBlockMetaChangeset, GridBlockOrder,
+    RepeatedField, RepeatedFieldOrder, RepeatedGridBlock, RepeatedRow, Row, RowMeta, RowMetaChangeset, RowOrder,
 };
 use std::collections::HashMap;
 
 use crate::dart_notification::{send_dart_notification, GridNotification};
 use crate::services::row::{
-    make_grid_block_from_block_metas, make_grid_blocks, make_row_ids_per_block, make_rows_from_row_metas,
-    row_meta_from_context, serialize_cell_data, GridBlockMetaData, RowMetaContext, RowMetaContextBuilder,
+    make_grid_block_from_block_metas, make_grid_blocks, make_row_meta_from_context, make_rows_from_row_metas,
+    serialize_cell_data, CreateRowMetaBuilder, CreateRowMetaPayload, GridBlockMetaData,
 };
 use flowy_sync::{RevisionCloudService, RevisionCompactor, RevisionManager, RevisionObjectBuilder};
 use lib_infra::future::FutureResult;
@@ -85,13 +84,14 @@ impl ClientGridEditor {
         Ok(())
     }
 
-    pub async fn create_row(&self, start_row_id: Option<String>) -> FlowyResult<()> {
+    pub async fn create_row(&self, start_row_id: Option<String>) -> FlowyResult<RowOrder> {
         let field_metas = self.pad.read().await.get_field_metas(None)?;
         let block_id = self.block_id().await?;
 
         // insert empty row below the row whose id is upper_row_id
-        let row_meta_ctx = RowMetaContextBuilder::new(&field_metas).build();
-        let row_meta = row_meta_from_context(&block_id, row_meta_ctx);
+        let row_meta_ctx = CreateRowMetaBuilder::new(&field_metas).build();
+        let row_meta = make_row_meta_from_context(&block_id, row_meta_ctx);
+        let row_order = RowOrder::from(&row_meta);
 
         // insert the row
         let row_count = self
@@ -102,14 +102,16 @@ impl ClientGridEditor {
         // update block row count
         let changeset = GridBlockMetaChangeset::from_row_count(&block_id, row_count);
         let _ = self.update_block(changeset).await?;
-        Ok(())
+        Ok(row_order)
     }
 
-    pub async fn insert_rows(&self, contexts: Vec<RowMetaContext>) -> FlowyResult<()> {
+    pub async fn insert_rows(&self, contexts: Vec<CreateRowMetaPayload>) -> FlowyResult<Vec<RowOrder>> {
         let block_id = self.block_id().await?;
         let mut rows_by_block_id: HashMap<String, Vec<RowMeta>> = HashMap::new();
+        let mut row_orders = vec![];
         for ctx in contexts {
-            let row_meta = row_meta_from_context(&block_id, ctx);
+            let row_meta = make_row_meta_from_context(&block_id, ctx);
+            row_orders.push(RowOrder::from(&row_meta));
             rows_by_block_id
                 .entry(block_id.clone())
                 .or_insert_with(Vec::new)
@@ -119,7 +121,7 @@ impl ClientGridEditor {
         for changeset in changesets {
             let _ = self.update_block(changeset).await?;
         }
-        Ok(())
+        Ok(row_orders)
     }
 
     pub async fn update_row(&self, changeset: RowMetaChangeset) -> FlowyResult<()> {
@@ -188,8 +190,8 @@ impl ClientGridEditor {
         Ok(grid_blocks)
     }
 
-    pub async fn delete_rows(&self, row_ids: Vec<String>) -> FlowyResult<()> {
-        let changesets = self.block_meta_manager.delete_rows(row_ids).await?;
+    pub async fn delete_rows(&self, row_orders: Vec<RowOrder>) -> FlowyResult<()> {
+        let changesets = self.block_meta_manager.delete_rows(row_orders).await?;
         for changeset in changesets {
             let _ = self.update_block(changeset).await?;
         }

+ 19 - 16
frontend/rust-lib/flowy-grid/src/services/row/row_builder.rs

@@ -3,26 +3,29 @@ use flowy_error::{FlowyError, FlowyResult};
 use flowy_grid_data_model::entities::{CellMeta, FieldMeta, RowMeta, DEFAULT_ROW_HEIGHT};
 use std::collections::HashMap;
 
-pub struct RowMetaContextBuilder<'a> {
+pub struct CreateRowMetaBuilder<'a> {
     field_meta_map: HashMap<&'a String, &'a FieldMeta>,
-    ctx: RowMetaContext,
+    payload: CreateRowMetaPayload,
 }
 
-impl<'a> RowMetaContextBuilder<'a> {
+impl<'a> CreateRowMetaBuilder<'a> {
     pub fn new(fields: &'a [FieldMeta]) -> Self {
         let field_meta_map = fields
             .iter()
             .map(|field| (&field.id, field))
             .collect::<HashMap<&String, &FieldMeta>>();
 
-        let ctx = RowMetaContext {
+        let payload = CreateRowMetaPayload {
             row_id: uuid::Uuid::new_v4().to_string(),
             cell_by_field_id: Default::default(),
             height: DEFAULT_ROW_HEIGHT,
             visibility: true,
         };
 
-        Self { field_meta_map, ctx }
+        Self {
+            field_meta_map,
+            payload,
+        }
     }
 
     pub fn add_cell(&mut self, field_id: &str, data: String) -> FlowyResult<()> {
@@ -34,7 +37,7 @@ impl<'a> RowMetaContextBuilder<'a> {
             Some(field_meta) => {
                 let data = serialize_cell_data(&data, field_meta)?;
                 let cell = CellMeta::new(field_id, data);
-                self.ctx.cell_by_field_id.insert(field_id.to_owned(), cell);
+                self.payload.cell_by_field_id.insert(field_id.to_owned(), cell);
                 Ok(())
             }
         }
@@ -42,32 +45,32 @@ impl<'a> RowMetaContextBuilder<'a> {
 
     #[allow(dead_code)]
     pub fn height(mut self, height: i32) -> Self {
-        self.ctx.height = height;
+        self.payload.height = height;
         self
     }
 
     #[allow(dead_code)]
     pub fn visibility(mut self, visibility: bool) -> Self {
-        self.ctx.visibility = visibility;
+        self.payload.visibility = visibility;
         self
     }
 
-    pub fn build(self) -> RowMetaContext {
-        self.ctx
+    pub fn build(self) -> CreateRowMetaPayload {
+        self.payload
     }
 }
 
-pub fn row_meta_from_context(block_id: &str, ctx: RowMetaContext) -> RowMeta {
+pub fn make_row_meta_from_context(block_id: &str, payload: CreateRowMetaPayload) -> RowMeta {
     RowMeta {
-        id: ctx.row_id,
+        id: payload.row_id,
         block_id: block_id.to_owned(),
-        cell_by_field_id: ctx.cell_by_field_id,
-        height: ctx.height,
-        visibility: ctx.visibility,
+        cell_by_field_id: payload.cell_by_field_id,
+        height: payload.height,
+        visibility: payload.visibility,
     }
 }
 
-pub struct RowMetaContext {
+pub struct CreateRowMetaPayload {
     pub row_id: String,
     pub cell_by_field_id: HashMap<String, CellMeta>,
     pub height: i32,

+ 11 - 11
frontend/rust-lib/flowy-grid/src/services/row/row_loader.rs

@@ -1,7 +1,7 @@
 use crate::services::row::deserialize_cell_data;
 use flowy_error::FlowyResult;
 use flowy_grid_data_model::entities::{
-    Cell, CellMeta, FieldMeta, GridBlock, RepeatedGridBlock, RepeatedRowOrder, Row, RowMeta, RowOrder,
+    Cell, CellMeta, FieldMeta, GridBlock, RepeatedGridBlock, Row, RowMeta, RowOrder,
 };
 use rayon::iter::{IntoParallelIterator, ParallelIterator};
 use std::collections::HashMap;
@@ -32,8 +32,8 @@ pub(crate) fn make_row_ids_per_block(row_orders: &[RowOrder]) -> Vec<RowIdsPerBl
     row_orders.iter().for_each(|row_order| {
         let block_id = &row_order.block_id;
         let row_id = row_order.row_id.clone();
-        map.entry(&block_id)
-            .or_insert_with(|| RowIdsPerBlock::new(&block_id))
+        map.entry(block_id)
+            .or_insert_with(|| RowIdsPerBlock::new(block_id))
             .row_ids
             .push(row_id);
     });
@@ -44,10 +44,10 @@ pub(crate) fn make_grid_blocks(block_meta_snapshots: Vec<GridBlockMetaData>) ->
     Ok(block_meta_snapshots
         .into_iter()
         .map(|row_metas_per_block| {
-            let row_ids = make_row_ids_from_row_metas(&row_metas_per_block.row_metas);
+            let row_orders = make_row_orders_from_row_metas(&row_metas_per_block.row_metas);
             GridBlock {
                 block_id: row_metas_per_block.block_id,
-                row_ids,
+                row_orders,
             }
         })
         .collect::<Vec<GridBlock>>()
@@ -73,11 +73,11 @@ pub fn make_cell(
     }
 }
 
-pub(crate) fn make_row_ids_from_row_metas(row_metas: &Vec<Arc<RowMeta>>) -> Vec<String> {
-    row_metas.iter().map(|row_meta| row_meta.id.clone()).collect::<Vec<_>>()
+pub(crate) fn make_row_orders_from_row_metas(row_metas: &[Arc<RowMeta>]) -> Vec<RowOrder> {
+    row_metas.iter().map(RowOrder::from).collect::<Vec<_>>()
 }
 
-pub(crate) fn make_rows_from_row_metas(fields: &[FieldMeta], row_metas: &Vec<Arc<RowMeta>>) -> Vec<Row> {
+pub(crate) fn make_rows_from_row_metas(fields: &[FieldMeta], row_metas: &[Arc<RowMeta>]) -> Vec<Row> {
     let field_meta_map = fields
         .iter()
         .map(|field_meta| (&field_meta.id, field_meta))
@@ -98,7 +98,7 @@ pub(crate) fn make_rows_from_row_metas(fields: &[FieldMeta], row_metas: &Vec<Arc
         }
     };
 
-    row_metas.into_iter().map(make_row).collect::<Vec<_>>()
+    row_metas.iter().map(make_row).collect::<Vec<_>>()
 }
 
 pub(crate) fn make_grid_block_from_block_metas(
@@ -115,8 +115,8 @@ pub(crate) fn make_grid_block_from_block_metas(
         match block_meta_data_map.get(&block_id) {
             None => {}
             Some(row_metas) => {
-                let row_ids = make_row_ids_from_row_metas(row_metas);
-                grid_blocks.push(GridBlock::new(block_id, row_ids));
+                let row_orders = make_row_orders_from_row_metas(row_metas);
+                grid_blocks.push(GridBlock::new(block_id, row_orders));
             }
         }
     }

+ 0 - 33
frontend/rust-lib/flowy-grid/src/services/util.rs

@@ -1,36 +1,3 @@
-//
-// #[allow(dead_code)]
-// pub fn string_to_money(money_str: &str) -> Option<Money<Currency>> {
-//     let mut process_money_str = String::from(money_str);
-//     let default_currency = MoneySymbol::from_symbol_str("CNY").currency();
-//
-//     if process_money_str.is_empty() {
-//         return None;
-//     }
-//
-//     return if process_money_str.chars().all(char::is_numeric) {
-//         match Money::from_str(&process_money_str, default_currency) {
-//             Ok(money) => Some(money),
-//             Err(_) => None,
-//         }
-//     } else {
-//         let symbol = process_money_str.chars().next().unwrap().to_string();
-//         let mut currency = default_currency;
-//
-//         for key in CURRENCIES_BY_SYMBOL.keys() {
-//             if symbol.eq(key) {
-//                 currency = CURRENCIES_BY_SYMBOL.get(key).unwrap();
-//                 crop_letters(&mut process_money_str, 1);
-//             }
-//         }
-//
-//         match Money::from_str(&process_money_str, currency) {
-//             Ok(money) => Some(money),
-//             Err(_) => None,
-//         }
-//     };
-// }
-
 pub fn uuid() -> String {
     uuid::Uuid::new_v4().to_string()
 }

+ 8 - 8
frontend/rust-lib/flowy-grid/tests/grid/grid_test.rs

@@ -2,7 +2,7 @@ use crate::grid::script::EditorScript::*;
 use crate::grid::script::*;
 use chrono::NaiveDateTime;
 use flowy_grid::services::cell::*;
-use flowy_grid::services::row::{deserialize_cell_data, serialize_cell_data, CellDataSerde, RowMetaContextBuilder};
+use flowy_grid::services::row::{deserialize_cell_data, serialize_cell_data, CellDataSerde, CreateRowMetaBuilder};
 use flowy_grid_data_model::entities::{
     CellMetaChangeset, FieldChangeset, FieldType, GridBlockMeta, GridBlockMetaChangeset, RowMetaChangeset,
 };
@@ -179,7 +179,7 @@ async fn grid_create_row() {
 #[tokio::test]
 async fn grid_create_row2() {
     let mut test = GridEditorTest::new().await;
-    let create_row_context = RowMetaContextBuilder::new(&test.field_metas).build();
+    let create_row_context = CreateRowMetaBuilder::new(&test.field_metas).build();
     let scripts = vec![
         AssertRowCount(3),
         CreateRow {
@@ -193,7 +193,7 @@ async fn grid_create_row2() {
 #[tokio::test]
 async fn grid_update_row() {
     let mut test = GridEditorTest::new().await;
-    let context = RowMetaContextBuilder::new(&test.field_metas).build();
+    let context = CreateRowMetaBuilder::new(&test.field_metas).build();
     let changeset = RowMetaChangeset {
         row_id: context.row_id.clone(),
         height: None,
@@ -216,8 +216,8 @@ async fn grid_update_row() {
 #[tokio::test]
 async fn grid_delete_row() {
     let mut test = GridEditorTest::new().await;
-    let context_1 = RowMetaContextBuilder::new(&test.field_metas).build();
-    let context_2 = RowMetaContextBuilder::new(&test.field_metas).build();
+    let context_1 = CreateRowMetaBuilder::new(&test.field_metas).build();
+    let context_2 = CreateRowMetaBuilder::new(&test.field_metas).build();
     let row_ids = vec![context_1.row_id.clone(), context_2.row_id.clone()];
     let scripts = vec![
         AssertRowCount(3),
@@ -242,7 +242,7 @@ async fn grid_delete_row() {
 #[tokio::test]
 async fn grid_row_add_cells_test() {
     let mut test = GridEditorTest::new().await;
-    let mut builder = RowMetaContextBuilder::new(&test.field_metas);
+    let mut builder = CreateRowMetaBuilder::new(&test.field_metas);
     for field in &test.field_metas {
         match field.field_type {
             FieldType::RichText => {
@@ -288,7 +288,7 @@ async fn grid_row_add_cells_test() {
 #[tokio::test]
 async fn grid_row_add_selection_cell_test() {
     let mut test = GridEditorTest::new().await;
-    let mut builder = RowMetaContextBuilder::new(&test.field_metas);
+    let mut builder = CreateRowMetaBuilder::new(&test.field_metas);
     let uuid = uuid::Uuid::new_v4().to_string();
     let mut single_select_field_id = "".to_string();
     let mut multi_select_field_id = "".to_string();
@@ -343,7 +343,7 @@ async fn grid_row_add_selection_cell_test() {
 #[tokio::test]
 async fn grid_row_add_date_cell_test() {
     let mut test = GridEditorTest::new().await;
-    let mut builder = RowMetaContextBuilder::new(&test.field_metas);
+    let mut builder = CreateRowMetaBuilder::new(&test.field_metas);
     let mut date_field = None;
     let timestamp = 1647390674;
     for field in &test.field_metas {

+ 19 - 6
frontend/rust-lib/flowy-grid/tests/grid/script.rs

@@ -1,13 +1,14 @@
 use bytes::Bytes;
 use flowy_collaboration::client_grid::GridBuilder;
+use std::collections::HashMap;
 
 use flowy_grid::services::cell::*;
 use flowy_grid::services::field::*;
 use flowy_grid::services::grid_editor::{ClientGridEditor, GridPadBuilder};
-use flowy_grid::services::row::RowMetaContext;
+use flowy_grid::services::row::CreateRowMetaPayload;
 use flowy_grid_data_model::entities::{
     BuildGridContext, CellMetaChangeset, FieldChangeset, FieldMeta, FieldType, GridBlockMeta, GridBlockMetaChangeset,
-    RowMeta, RowMetaChangeset,
+    RowMeta, RowMetaChangeset, RowOrder,
 };
 use flowy_sync::REVISION_WRITE_INTERVAL_IN_MILLIS;
 use flowy_test::helper::ViewTest;
@@ -50,7 +51,7 @@ pub enum EditorScript {
     },
     CreateEmptyRow,
     CreateRow {
-        context: RowMetaContext,
+        context: CreateRowMetaPayload,
     },
     UpdateRow {
         changeset: RowMetaChangeset,
@@ -78,6 +79,8 @@ pub struct GridEditorTest {
     pub grid_blocks: Vec<GridBlockMeta>,
     pub row_metas: Vec<Arc<RowMeta>>,
     pub field_count: usize,
+
+    pub row_order_by_row_id: HashMap<String, RowOrder>,
 }
 
 impl GridEditorTest {
@@ -101,6 +104,7 @@ impl GridEditorTest {
             grid_blocks,
             row_metas,
             field_count: FieldType::COUNT,
+            row_order_by_row_id: HashMap::default(),
         }
     }
 
@@ -172,18 +176,27 @@ impl GridEditorTest {
                 assert_eq!(compared_block, block);
             }
             EditorScript::CreateEmptyRow => {
-                self.editor.create_row(None).await.unwrap();
+                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_metas = self.get_row_metas().await;
                 self.grid_blocks = self.editor.get_block_metas().await.unwrap();
             }
             EditorScript::CreateRow { context } => {
-                self.editor.insert_rows(vec![context]).await.unwrap();
+                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_metas = self.get_row_metas().await;
                 self.grid_blocks = self.editor.get_block_metas().await.unwrap();
             }
             EditorScript::UpdateRow { changeset: change } => self.editor.update_row(change).await.unwrap(),
             EditorScript::DeleteRow { row_ids } => {
-                self.editor.delete_rows(row_ids).await.unwrap();
+                let row_orders = row_ids
+                    .into_iter()
+                    .map(|row_id| self.row_order_by_row_id.get(&row_id).unwrap().clone())
+                    .collect::<Vec<RowOrder>>();
+
+                self.editor.delete_rows(row_orders).await.unwrap();
                 self.row_metas = self.get_row_metas().await;
                 self.grid_blocks = self.editor.get_block_metas().await.unwrap();
             }

+ 8 - 31
shared-lib/flowy-grid-data-model/src/entities/grid.rs

@@ -1,9 +1,6 @@
 use crate::entities::{FieldMeta, FieldType, RowMeta};
 use flowy_derive::ProtoBuf;
 use std::collections::HashMap;
-
-use crate::parser::NonEmptyId;
-use flowy_error_code::ErrorCode;
 use std::sync::Arc;
 
 #[derive(Debug, Clone, Default, ProtoBuf)]
@@ -114,6 +111,9 @@ pub struct RowOrder {
 
     #[pb(index = 2)]
     pub block_id: String,
+
+    #[pb(index = 3)]
+    pub height: i32,
 }
 
 impl std::convert::From<&RowMeta> for RowOrder {
@@ -121,6 +121,7 @@ impl std::convert::From<&RowMeta> for RowOrder {
         Self {
             row_id: row.id.clone(),
             block_id: row.block_id.clone(),
+            height: row.height,
         }
     }
 }
@@ -130,35 +131,11 @@ impl std::convert::From<&Arc<RowMeta>> for RowOrder {
         Self {
             row_id: row.id.clone(),
             block_id: row.block_id.clone(),
+            height: row.height,
         }
     }
 }
 
-#[derive(Debug, Clone, Default, ProtoBuf)]
-pub struct RepeatedRowOrder {
-    #[pb(index = 1)]
-    pub items: Vec<RowOrder>,
-}
-
-impl std::ops::Deref for RepeatedRowOrder {
-    type Target = Vec<RowOrder>;
-    fn deref(&self) -> &Self::Target {
-        &self.items
-    }
-}
-
-impl std::ops::DerefMut for RepeatedRowOrder {
-    fn deref_mut(&mut self) -> &mut Self::Target {
-        &mut self.items
-    }
-}
-
-impl std::convert::From<Vec<RowOrder>> for RepeatedRowOrder {
-    fn from(items: Vec<RowOrder>) -> Self {
-        Self { items }
-    }
-}
-
 #[derive(Debug, Default, ProtoBuf)]
 pub struct Row {
     #[pb(index = 1)]
@@ -207,14 +184,14 @@ pub struct GridBlock {
     pub block_id: String,
 
     #[pb(index = 2)]
-    pub row_ids: Vec<String>,
+    pub row_orders: Vec<RowOrder>,
 }
 
 impl GridBlock {
-    pub fn new(block_id: &str, row_ids: Vec<String>) -> Self {
+    pub fn new(block_id: &str, row_orders: Vec<RowOrder>) -> Self {
         Self {
             block_id: block_id.to_owned(),
-            row_ids,
+            row_orders,
         }
     }
 }

+ 0 - 2
shared-lib/flowy-grid-data-model/src/entities/meta.rs

@@ -1,8 +1,6 @@
 use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
 use serde::{Deserialize, Serialize};
 use std::collections::HashMap;
-
-use crate::entities::GridBlockOrder;
 use strum_macros::{Display, EnumCount as EnumCountMacro, EnumIter, EnumString};
 
 pub const DEFAULT_ROW_HEIGHT: i32 = 36;

+ 0 - 2
shared-lib/flowy-grid-data-model/src/parser/id.rs

@@ -1,5 +1,3 @@
-use flowy_error_code::ErrorCode;
-
 #[derive(Debug)]
 pub struct NonEmptyId(pub String);
 

+ 93 - 217
shared-lib/flowy-grid-data-model/src/protobuf/model/grid.rs

@@ -1155,6 +1155,7 @@ pub struct RowOrder {
     // message fields
     pub row_id: ::std::string::String,
     pub block_id: ::std::string::String,
+    pub height: i32,
     // special fields
     pub unknown_fields: ::protobuf::UnknownFields,
     pub cached_size: ::protobuf::CachedSize,
@@ -1222,6 +1223,21 @@ impl RowOrder {
     pub fn take_block_id(&mut self) -> ::std::string::String {
         ::std::mem::replace(&mut self.block_id, ::std::string::String::new())
     }
+
+    // int32 height = 3;
+
+
+    pub fn get_height(&self) -> i32 {
+        self.height
+    }
+    pub fn clear_height(&mut self) {
+        self.height = 0;
+    }
+
+    // Param is passed by value, moved
+    pub fn set_height(&mut self, v: i32) {
+        self.height = v;
+    }
 }
 
 impl ::protobuf::Message for RowOrder {
@@ -1239,6 +1255,13 @@ impl ::protobuf::Message for RowOrder {
                 2 => {
                     ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.block_id)?;
                 },
+                3 => {
+                    if wire_type != ::protobuf::wire_format::WireTypeVarint {
+                        return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
+                    }
+                    let tmp = is.read_int32()?;
+                    self.height = tmp;
+                },
                 _ => {
                     ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
                 },
@@ -1257,6 +1280,9 @@ impl ::protobuf::Message for RowOrder {
         if !self.block_id.is_empty() {
             my_size += ::protobuf::rt::string_size(2, &self.block_id);
         }
+        if self.height != 0 {
+            my_size += ::protobuf::rt::value_size(3, self.height, ::protobuf::wire_format::WireTypeVarint);
+        }
         my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
         self.cached_size.set(my_size);
         my_size
@@ -1269,6 +1295,9 @@ impl ::protobuf::Message for RowOrder {
         if !self.block_id.is_empty() {
             os.write_string(2, &self.block_id)?;
         }
+        if self.height != 0 {
+            os.write_int32(3, self.height)?;
+        }
         os.write_unknown_fields(self.get_unknown_fields())?;
         ::std::result::Result::Ok(())
     }
@@ -1317,6 +1346,11 @@ impl ::protobuf::Message for RowOrder {
                 |m: &RowOrder| { &m.block_id },
                 |m: &mut RowOrder| { &mut m.block_id },
             ));
+            fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeInt32>(
+                "height",
+                |m: &RowOrder| { &m.height },
+                |m: &mut RowOrder| { &mut m.height },
+            ));
             ::protobuf::reflect::MessageDescriptor::new_pb_name::<RowOrder>(
                 "RowOrder",
                 fields,
@@ -1335,6 +1369,7 @@ impl ::protobuf::Clear for RowOrder {
     fn clear(&mut self) {
         self.row_id.clear();
         self.block_id.clear();
+        self.height = 0;
         self.unknown_fields.clear();
     }
 }
@@ -1351,172 +1386,6 @@ impl ::protobuf::reflect::ProtobufValue for RowOrder {
     }
 }
 
-#[derive(PartialEq,Clone,Default)]
-pub struct RepeatedRowOrder {
-    // message fields
-    pub items: ::protobuf::RepeatedField<RowOrder>,
-    // special fields
-    pub unknown_fields: ::protobuf::UnknownFields,
-    pub cached_size: ::protobuf::CachedSize,
-}
-
-impl<'a> ::std::default::Default for &'a RepeatedRowOrder {
-    fn default() -> &'a RepeatedRowOrder {
-        <RepeatedRowOrder as ::protobuf::Message>::default_instance()
-    }
-}
-
-impl RepeatedRowOrder {
-    pub fn new() -> RepeatedRowOrder {
-        ::std::default::Default::default()
-    }
-
-    // repeated .RowOrder items = 1;
-
-
-    pub fn get_items(&self) -> &[RowOrder] {
-        &self.items
-    }
-    pub fn clear_items(&mut self) {
-        self.items.clear();
-    }
-
-    // Param is passed by value, moved
-    pub fn set_items(&mut self, v: ::protobuf::RepeatedField<RowOrder>) {
-        self.items = v;
-    }
-
-    // Mutable pointer to the field.
-    pub fn mut_items(&mut self) -> &mut ::protobuf::RepeatedField<RowOrder> {
-        &mut self.items
-    }
-
-    // Take field
-    pub fn take_items(&mut self) -> ::protobuf::RepeatedField<RowOrder> {
-        ::std::mem::replace(&mut self.items, ::protobuf::RepeatedField::new())
-    }
-}
-
-impl ::protobuf::Message for RepeatedRowOrder {
-    fn is_initialized(&self) -> bool {
-        for v in &self.items {
-            if !v.is_initialized() {
-                return false;
-            }
-        };
-        true
-    }
-
-    fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> {
-        while !is.eof()? {
-            let (field_number, wire_type) = is.read_tag_unpack()?;
-            match field_number {
-                1 => {
-                    ::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.items)?;
-                },
-                _ => {
-                    ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
-                },
-            };
-        }
-        ::std::result::Result::Ok(())
-    }
-
-    // Compute sizes of nested messages
-    #[allow(unused_variables)]
-    fn compute_size(&self) -> u32 {
-        let mut my_size = 0;
-        for value in &self.items {
-            let len = value.compute_size();
-            my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len;
-        };
-        my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
-        self.cached_size.set(my_size);
-        my_size
-    }
-
-    fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> {
-        for v in &self.items {
-            os.write_tag(1, ::protobuf::wire_format::WireTypeLengthDelimited)?;
-            os.write_raw_varint32(v.get_cached_size())?;
-            v.write_to_with_cached_sizes(os)?;
-        };
-        os.write_unknown_fields(self.get_unknown_fields())?;
-        ::std::result::Result::Ok(())
-    }
-
-    fn get_cached_size(&self) -> u32 {
-        self.cached_size.get()
-    }
-
-    fn get_unknown_fields(&self) -> &::protobuf::UnknownFields {
-        &self.unknown_fields
-    }
-
-    fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields {
-        &mut self.unknown_fields
-    }
-
-    fn as_any(&self) -> &dyn (::std::any::Any) {
-        self as &dyn (::std::any::Any)
-    }
-    fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) {
-        self as &mut dyn (::std::any::Any)
-    }
-    fn into_any(self: ::std::boxed::Box<Self>) -> ::std::boxed::Box<dyn (::std::any::Any)> {
-        self
-    }
-
-    fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor {
-        Self::descriptor_static()
-    }
-
-    fn new() -> RepeatedRowOrder {
-        RepeatedRowOrder::new()
-    }
-
-    fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor {
-        static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT;
-        descriptor.get(|| {
-            let mut fields = ::std::vec::Vec::new();
-            fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage<RowOrder>>(
-                "items",
-                |m: &RepeatedRowOrder| { &m.items },
-                |m: &mut RepeatedRowOrder| { &mut m.items },
-            ));
-            ::protobuf::reflect::MessageDescriptor::new_pb_name::<RepeatedRowOrder>(
-                "RepeatedRowOrder",
-                fields,
-                file_descriptor_proto()
-            )
-        })
-    }
-
-    fn default_instance() -> &'static RepeatedRowOrder {
-        static instance: ::protobuf::rt::LazyV2<RepeatedRowOrder> = ::protobuf::rt::LazyV2::INIT;
-        instance.get(RepeatedRowOrder::new)
-    }
-}
-
-impl ::protobuf::Clear for RepeatedRowOrder {
-    fn clear(&mut self) {
-        self.items.clear();
-        self.unknown_fields.clear();
-    }
-}
-
-impl ::std::fmt::Debug for RepeatedRowOrder {
-    fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
-        ::protobuf::text_format::fmt(self, f)
-    }
-}
-
-impl ::protobuf::reflect::ProtobufValue for RepeatedRowOrder {
-    fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
-        ::protobuf::reflect::ReflectValueRef::Message(self)
-    }
-}
-
 #[derive(PartialEq,Clone,Default)]
 pub struct Row {
     // message fields
@@ -2243,7 +2112,7 @@ impl ::protobuf::reflect::ProtobufValue for GridBlockOrder {
 pub struct GridBlock {
     // message fields
     pub block_id: ::std::string::String,
-    pub row_ids: ::protobuf::RepeatedField<::std::string::String>,
+    pub row_orders: ::protobuf::RepeatedField<RowOrder>,
     // special fields
     pub unknown_fields: ::protobuf::UnknownFields,
     pub cached_size: ::protobuf::CachedSize,
@@ -2286,34 +2155,39 @@ impl GridBlock {
         ::std::mem::replace(&mut self.block_id, ::std::string::String::new())
     }
 
-    // repeated string row_ids = 2;
+    // repeated .RowOrder row_orders = 2;
 
 
-    pub fn get_row_ids(&self) -> &[::std::string::String] {
-        &self.row_ids
+    pub fn get_row_orders(&self) -> &[RowOrder] {
+        &self.row_orders
     }
-    pub fn clear_row_ids(&mut self) {
-        self.row_ids.clear();
+    pub fn clear_row_orders(&mut self) {
+        self.row_orders.clear();
     }
 
     // Param is passed by value, moved
-    pub fn set_row_ids(&mut self, v: ::protobuf::RepeatedField<::std::string::String>) {
-        self.row_ids = v;
+    pub fn set_row_orders(&mut self, v: ::protobuf::RepeatedField<RowOrder>) {
+        self.row_orders = v;
     }
 
     // Mutable pointer to the field.
-    pub fn mut_row_ids(&mut self) -> &mut ::protobuf::RepeatedField<::std::string::String> {
-        &mut self.row_ids
+    pub fn mut_row_orders(&mut self) -> &mut ::protobuf::RepeatedField<RowOrder> {
+        &mut self.row_orders
     }
 
     // Take field
-    pub fn take_row_ids(&mut self) -> ::protobuf::RepeatedField<::std::string::String> {
-        ::std::mem::replace(&mut self.row_ids, ::protobuf::RepeatedField::new())
+    pub fn take_row_orders(&mut self) -> ::protobuf::RepeatedField<RowOrder> {
+        ::std::mem::replace(&mut self.row_orders, ::protobuf::RepeatedField::new())
     }
 }
 
 impl ::protobuf::Message for GridBlock {
     fn is_initialized(&self) -> bool {
+        for v in &self.row_orders {
+            if !v.is_initialized() {
+                return false;
+            }
+        };
         true
     }
 
@@ -2325,7 +2199,7 @@ impl ::protobuf::Message for GridBlock {
                     ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.block_id)?;
                 },
                 2 => {
-                    ::protobuf::rt::read_repeated_string_into(wire_type, is, &mut self.row_ids)?;
+                    ::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.row_orders)?;
                 },
                 _ => {
                     ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
@@ -2342,8 +2216,9 @@ impl ::protobuf::Message for GridBlock {
         if !self.block_id.is_empty() {
             my_size += ::protobuf::rt::string_size(1, &self.block_id);
         }
-        for value in &self.row_ids {
-            my_size += ::protobuf::rt::string_size(2, &value);
+        for value in &self.row_orders {
+            let len = value.compute_size();
+            my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len;
         };
         my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
         self.cached_size.set(my_size);
@@ -2354,8 +2229,10 @@ impl ::protobuf::Message for GridBlock {
         if !self.block_id.is_empty() {
             os.write_string(1, &self.block_id)?;
         }
-        for v in &self.row_ids {
-            os.write_string(2, &v)?;
+        for v in &self.row_orders {
+            os.write_tag(2, ::protobuf::wire_format::WireTypeLengthDelimited)?;
+            os.write_raw_varint32(v.get_cached_size())?;
+            v.write_to_with_cached_sizes(os)?;
         };
         os.write_unknown_fields(self.get_unknown_fields())?;
         ::std::result::Result::Ok(())
@@ -2400,10 +2277,10 @@ impl ::protobuf::Message for GridBlock {
                 |m: &GridBlock| { &m.block_id },
                 |m: &mut GridBlock| { &mut m.block_id },
             ));
-            fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
-                "row_ids",
-                |m: &GridBlock| { &m.row_ids },
-                |m: &mut GridBlock| { &mut m.row_ids },
+            fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage<RowOrder>>(
+                "row_orders",
+                |m: &GridBlock| { &m.row_orders },
+                |m: &mut GridBlock| { &mut m.row_orders },
             ));
             ::protobuf::reflect::MessageDescriptor::new_pb_name::<GridBlock>(
                 "GridBlock",
@@ -2422,7 +2299,7 @@ impl ::protobuf::Message for GridBlock {
 impl ::protobuf::Clear for GridBlock {
     fn clear(&mut self) {
         self.block_id.clear();
-        self.row_ids.clear();
+        self.row_orders.clear();
         self.unknown_fields.clear();
     }
 }
@@ -4204,35 +4081,34 @@ static file_descriptor_proto_data: &'static [u8] = b"\
     \x19\n\x08field_id\x18\x01\x20\x01(\tR\x07fieldId\"-\n\rRepeatedField\
     \x12\x1c\n\x05items\x18\x01\x20\x03(\x0b2\x06.FieldR\x05items\"7\n\x12Re\
     peatedFieldOrder\x12!\n\x05items\x18\x01\x20\x03(\x0b2\x0b.FieldOrderR\
-    \x05items\"<\n\x08RowOrder\x12\x15\n\x06row_id\x18\x01\x20\x01(\tR\x05ro\
-    wId\x12\x19\n\x08block_id\x18\x02\x20\x01(\tR\x07blockId\"3\n\x10Repeate\
-    dRowOrder\x12\x1f\n\x05items\x18\x01\x20\x03(\x0b2\t.RowOrderR\x05items\
-    \"\xb8\x01\n\x03Row\x12\x0e\n\x02id\x18\x01\x20\x01(\tR\x02id\x12@\n\x10\
-    cell_by_field_id\x18\x02\x20\x03(\x0b2\x17.Row.CellByFieldIdEntryR\rcell\
-    ByFieldId\x12\x16\n\x06height\x18\x03\x20\x01(\x05R\x06height\x1aG\n\x12\
-    CellByFieldIdEntry\x12\x10\n\x03key\x18\x01\x20\x01(\tR\x03key\x12\x1b\n\
-    \x05value\x18\x02\x20\x01(\x0b2\x05.CellR\x05value:\x028\x01\")\n\x0bRep\
-    eatedRow\x12\x1a\n\x05items\x18\x01\x20\x03(\x0b2\x04.RowR\x05items\"5\n\
-    \x11RepeatedGridBlock\x12\x20\n\x05items\x18\x01\x20\x03(\x0b2\n.GridBlo\
-    ckR\x05items\"+\n\x0eGridBlockOrder\x12\x19\n\x08block_id\x18\x01\x20\
-    \x01(\tR\x07blockId\"?\n\tGridBlock\x12\x19\n\x08block_id\x18\x01\x20\
-    \x01(\tR\x07blockId\x12\x17\n\x07row_ids\x18\x02\x20\x03(\tR\x06rowIds\"\
-    ;\n\x04Cell\x12\x19\n\x08field_id\x18\x01\x20\x01(\tR\x07fieldId\x12\x18\
-    \n\x07content\x18\x02\x20\x01(\tR\x07content\"+\n\x0cRepeatedCell\x12\
-    \x1b\n\x05items\x18\x01\x20\x03(\x0b2\x05.CellR\x05items\"'\n\x11CreateG\
-    ridPayload\x12\x12\n\x04name\x18\x01\x20\x01(\tR\x04name\"\x1e\n\x06Grid\
-    Id\x12\x14\n\x05value\x18\x01\x20\x01(\tR\x05value\"#\n\x0bGridBlockId\
-    \x12\x14\n\x05value\x18\x01\x20\x01(\tR\x05value\"f\n\x10CreateRowPayloa\
-    d\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x12\"\n\x0cstart_ro\
-    w_id\x18\x02\x20\x01(\tH\0R\nstartRowIdB\x15\n\x13one_of_start_row_id\"d\
-    \n\x11QueryFieldPayload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06grid\
-    Id\x126\n\x0cfield_orders\x18\x02\x20\x01(\x0b2\x13.RepeatedFieldOrderR\
-    \x0bfieldOrders\"e\n\x16QueryGridBlocksPayload\x12\x17\n\x07grid_id\x18\
-    \x01\x20\x01(\tR\x06gridId\x122\n\x0cblock_orders\x18\x02\x20\x03(\x0b2\
-    \x0f.GridBlockOrderR\x0bblockOrders\"\\\n\x0fQueryRowPayload\x12\x17\n\
-    \x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x12\x19\n\x08block_id\x18\x02\
-    \x20\x01(\tR\x07blockId\x12\x15\n\x06row_id\x18\x03\x20\x01(\tR\x05rowId\
-    b\x06proto3\
+    \x05items\"T\n\x08RowOrder\x12\x15\n\x06row_id\x18\x01\x20\x01(\tR\x05ro\
+    wId\x12\x19\n\x08block_id\x18\x02\x20\x01(\tR\x07blockId\x12\x16\n\x06he\
+    ight\x18\x03\x20\x01(\x05R\x06height\"\xb8\x01\n\x03Row\x12\x0e\n\x02id\
+    \x18\x01\x20\x01(\tR\x02id\x12@\n\x10cell_by_field_id\x18\x02\x20\x03(\
+    \x0b2\x17.Row.CellByFieldIdEntryR\rcellByFieldId\x12\x16\n\x06height\x18\
+    \x03\x20\x01(\x05R\x06height\x1aG\n\x12CellByFieldIdEntry\x12\x10\n\x03k\
+    ey\x18\x01\x20\x01(\tR\x03key\x12\x1b\n\x05value\x18\x02\x20\x01(\x0b2\
+    \x05.CellR\x05value:\x028\x01\")\n\x0bRepeatedRow\x12\x1a\n\x05items\x18\
+    \x01\x20\x03(\x0b2\x04.RowR\x05items\"5\n\x11RepeatedGridBlock\x12\x20\n\
+    \x05items\x18\x01\x20\x03(\x0b2\n.GridBlockR\x05items\"+\n\x0eGridBlockO\
+    rder\x12\x19\n\x08block_id\x18\x01\x20\x01(\tR\x07blockId\"P\n\tGridBloc\
+    k\x12\x19\n\x08block_id\x18\x01\x20\x01(\tR\x07blockId\x12(\n\nrow_order\
+    s\x18\x02\x20\x03(\x0b2\t.RowOrderR\trowOrders\";\n\x04Cell\x12\x19\n\
+    \x08field_id\x18\x01\x20\x01(\tR\x07fieldId\x12\x18\n\x07content\x18\x02\
+    \x20\x01(\tR\x07content\"+\n\x0cRepeatedCell\x12\x1b\n\x05items\x18\x01\
+    \x20\x03(\x0b2\x05.CellR\x05items\"'\n\x11CreateGridPayload\x12\x12\n\
+    \x04name\x18\x01\x20\x01(\tR\x04name\"\x1e\n\x06GridId\x12\x14\n\x05valu\
+    e\x18\x01\x20\x01(\tR\x05value\"#\n\x0bGridBlockId\x12\x14\n\x05value\
+    \x18\x01\x20\x01(\tR\x05value\"f\n\x10CreateRowPayload\x12\x17\n\x07grid\
+    _id\x18\x01\x20\x01(\tR\x06gridId\x12\"\n\x0cstart_row_id\x18\x02\x20\
+    \x01(\tH\0R\nstartRowIdB\x15\n\x13one_of_start_row_id\"d\n\x11QueryField\
+    Payload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x126\n\x0cfie\
+    ld_orders\x18\x02\x20\x01(\x0b2\x13.RepeatedFieldOrderR\x0bfieldOrders\"\
+    e\n\x16QueryGridBlocksPayload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\
+    \x06gridId\x122\n\x0cblock_orders\x18\x02\x20\x03(\x0b2\x0f.GridBlockOrd\
+    erR\x0bblockOrders\"\\\n\x0fQueryRowPayload\x12\x17\n\x07grid_id\x18\x01\
+    \x20\x01(\tR\x06gridId\x12\x19\n\x08block_id\x18\x02\x20\x01(\tR\x07bloc\
+    kId\x12\x15\n\x06row_id\x18\x03\x20\x01(\tR\x05rowIdb\x06proto3\
 ";
 
 static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;

+ 2 - 4
shared-lib/flowy-grid-data-model/src/protobuf/proto/grid.proto

@@ -27,9 +27,7 @@ message RepeatedFieldOrder {
 message RowOrder {
     string row_id = 1;
     string block_id = 2;
-}
-message RepeatedRowOrder {
-    repeated RowOrder items = 1;
+    int32 height = 3;
 }
 message Row {
     string id = 1;
@@ -47,7 +45,7 @@ message GridBlockOrder {
 }
 message GridBlock {
     string block_id = 1;
-    repeated string row_ids = 2;
+    repeated RowOrder row_orders = 2;
 }
 message Cell {
     string field_id = 1;