Kaynağa Gözat

chore: config grid row changeset

appflowy 3 yıl önce
ebeveyn
işleme
572e38ec1c
25 değiştirilmiş dosya ile 554 ekleme ve 463 silme
  1. 24 24
      frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pb.dart
  2. 5 5
      frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pbjson.dart
  3. 11 55
      frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/meta.pb.dart
  4. 3 6
      frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/meta.pbjson.dart
  5. 2 2
      frontend/rust-lib/flowy-grid/src/event_handler.rs
  6. 0 2
      frontend/rust-lib/flowy-grid/src/services/field/mod.rs
  7. 1 1
      frontend/rust-lib/flowy-grid/src/services/field/type_options.rs
  8. 43 96
      frontend/rust-lib/flowy-grid/src/services/grid_editor.rs
  9. 108 6
      frontend/rust-lib/flowy-grid/src/services/grid_meta_editor.rs
  10. 1 0
      frontend/rust-lib/flowy-grid/src/services/mod.rs
  11. 0 0
      frontend/rust-lib/flowy-grid/src/services/row/cell_stringify.rs
  12. 7 0
      frontend/rust-lib/flowy-grid/src/services/row/mod.rs
  13. 24 0
      frontend/rust-lib/flowy-grid/src/services/row/row_builder.rs
  14. 68 0
      frontend/rust-lib/flowy-grid/src/services/row/row_loader.rs
  15. 75 1
      frontend/rust-lib/flowy-grid/tests/grid/grid_test.rs
  16. 32 3
      frontend/rust-lib/flowy-grid/tests/grid/script.rs
  17. 4 0
      shared-lib/flowy-collaboration/src/client_grid/block_pad.rs
  18. 1 1
      shared-lib/flowy-collaboration/src/client_grid/grid_builder.rs
  19. 21 6
      shared-lib/flowy-collaboration/src/client_grid/grid_pad.rs
  20. 8 5
      shared-lib/flowy-grid-data-model/src/entities/grid.rs
  21. 25 20
      shared-lib/flowy-grid-data-model/src/entities/meta.rs
  22. 60 60
      shared-lib/flowy-grid-data-model/src/protobuf/model/grid.rs
  23. 26 162
      shared-lib/flowy-grid-data-model/src/protobuf/model/meta.rs
  24. 3 3
      shared-lib/flowy-grid-data-model/src/protobuf/proto/grid.proto
  25. 2 5
      shared-lib/flowy-grid-data-model/src/protobuf/proto/meta.proto

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

@@ -163,17 +163,22 @@ class RepeatedFieldOrder extends $pb.GeneratedMessage {
 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')
     ..hasRequiredFields = false
   ;
 
   RowOrder._() : super();
   factory RowOrder({
     $core.String? rowId,
+    $core.String? blockId,
   }) {
     final _result = create();
     if (rowId != null) {
       _result.rowId = rowId;
     }
+    if (blockId != null) {
+      _result.blockId = blockId;
+    }
     return _result;
   }
   factory RowOrder.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
@@ -205,6 +210,15 @@ class RowOrder extends $pb.GeneratedMessage {
   $core.bool hasRowId() => $_has(0);
   @$pb.TagNumber(1)
   void clearRowId() => clearField(1);
+
+  @$pb.TagNumber(2)
+  $core.String get blockId => $_getSZ(1);
+  @$pb.TagNumber(2)
+  set blockId($core.String v) { $_setString(1, v); }
+  @$pb.TagNumber(2)
+  $core.bool hasBlockId() => $_has(1);
+  @$pb.TagNumber(2)
+  void clearBlockId() => clearField(2);
 }
 
 class RepeatedRowOrder extends $pb.GeneratedMessage {
@@ -360,22 +374,17 @@ class RepeatedRow extends $pb.GeneratedMessage {
 
 class Cell extends $pb.GeneratedMessage {
   static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'Cell', createEmptyInstance: create)
-    ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'id')
-    ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'fieldId')
-    ..aOS(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'content')
+    ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'fieldId')
+    ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'content')
     ..hasRequiredFields = false
   ;
 
   Cell._() : super();
   factory Cell({
-    $core.String? id,
     $core.String? fieldId,
     $core.String? content,
   }) {
     final _result = create();
-    if (id != null) {
-      _result.id = id;
-    }
     if (fieldId != null) {
       _result.fieldId = fieldId;
     }
@@ -406,31 +415,22 @@ class Cell extends $pb.GeneratedMessage {
   static Cell? _defaultInstance;
 
   @$pb.TagNumber(1)
-  $core.String get id => $_getSZ(0);
+  $core.String get fieldId => $_getSZ(0);
   @$pb.TagNumber(1)
-  set id($core.String v) { $_setString(0, v); }
+  set fieldId($core.String v) { $_setString(0, v); }
   @$pb.TagNumber(1)
-  $core.bool hasId() => $_has(0);
+  $core.bool hasFieldId() => $_has(0);
   @$pb.TagNumber(1)
-  void clearId() => clearField(1);
+  void clearFieldId() => clearField(1);
 
   @$pb.TagNumber(2)
-  $core.String get fieldId => $_getSZ(1);
+  $core.String get content => $_getSZ(1);
   @$pb.TagNumber(2)
-  set fieldId($core.String v) { $_setString(1, v); }
+  set content($core.String v) { $_setString(1, v); }
   @$pb.TagNumber(2)
-  $core.bool hasFieldId() => $_has(1);
+  $core.bool hasContent() => $_has(1);
   @$pb.TagNumber(2)
-  void clearFieldId() => clearField(2);
-
-  @$pb.TagNumber(3)
-  $core.String get content => $_getSZ(2);
-  @$pb.TagNumber(3)
-  set content($core.String v) { $_setString(2, v); }
-  @$pb.TagNumber(3)
-  $core.bool hasContent() => $_has(2);
-  @$pb.TagNumber(3)
-  void clearContent() => clearField(3);
+  void clearContent() => clearField(2);
 }
 
 class CreateGridPayload extends $pb.GeneratedMessage {

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

@@ -45,11 +45,12 @@ const RowOrder$json = const {
   '1': 'RowOrder',
   '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'},
   ],
 };
 
 /// Descriptor for `RowOrder`. Decode as a `google.protobuf.DescriptorProto`.
-final $typed_data.Uint8List rowOrderDescriptor = $convert.base64Decode('CghSb3dPcmRlchIVCgZyb3dfaWQYASABKAlSBXJvd0lk');
+final $typed_data.Uint8List rowOrderDescriptor = $convert.base64Decode('CghSb3dPcmRlchIVCgZyb3dfaWQYASABKAlSBXJvd0lkEhkKCGJsb2NrX2lkGAIgASgJUgdibG9ja0lk');
 @$core.Deprecated('Use repeatedRowOrderDescriptor instead')
 const RepeatedRowOrder$json = const {
   '1': 'RepeatedRowOrder',
@@ -97,14 +98,13 @@ final $typed_data.Uint8List repeatedRowDescriptor = $convert.base64Decode('CgtSZ
 const Cell$json = const {
   '1': 'Cell',
   '2': const [
-    const {'1': 'id', '3': 1, '4': 1, '5': 9, '10': 'id'},
-    const {'1': 'field_id', '3': 2, '4': 1, '5': 9, '10': 'fieldId'},
-    const {'1': 'content', '3': 3, '4': 1, '5': 9, '10': 'content'},
+    const {'1': 'field_id', '3': 1, '4': 1, '5': 9, '10': 'fieldId'},
+    const {'1': 'content', '3': 2, '4': 1, '5': 9, '10': 'content'},
   ],
 };
 
 /// Descriptor for `Cell`. Decode as a `google.protobuf.DescriptorProto`.
-final $typed_data.Uint8List cellDescriptor = $convert.base64Decode('CgRDZWxsEg4KAmlkGAEgASgJUgJpZBIZCghmaWVsZF9pZBgCIAEoCVIHZmllbGRJZBIYCgdjb250ZW50GAMgASgJUgdjb250ZW50');
+final $typed_data.Uint8List cellDescriptor = $convert.base64Decode('CgRDZWxsEhkKCGZpZWxkX2lkGAEgASgJUgdmaWVsZElkEhgKB2NvbnRlbnQYAiABKAlSB2NvbnRlbnQ=');
 @$core.Deprecated('Use createGridPayloadDescriptor instead')
 const CreateGridPayload$json = const {
   '1': 'CreateGridPayload',

+ 11 - 55
frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/meta.pb.dart

@@ -897,38 +897,23 @@ class RowMetaChangeset extends $pb.GeneratedMessage {
 
 class CellMeta extends $pb.GeneratedMessage {
   static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'CellMeta', createEmptyInstance: create)
-    ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'id')
-    ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'rowId')
-    ..aOS(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'fieldId')
-    ..aOM<AnyData>(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'data', subBuilder: AnyData.create)
-    ..a<$core.int>(5, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'height', $pb.PbFieldType.O3)
+    ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'fieldId')
+    ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'data')
     ..hasRequiredFields = false
   ;
 
   CellMeta._() : super();
   factory CellMeta({
-    $core.String? id,
-    $core.String? rowId,
     $core.String? fieldId,
-    AnyData? data,
-    $core.int? height,
+    $core.String? data,
   }) {
     final _result = create();
-    if (id != null) {
-      _result.id = id;
-    }
-    if (rowId != null) {
-      _result.rowId = rowId;
-    }
     if (fieldId != null) {
       _result.fieldId = fieldId;
     }
     if (data != null) {
       _result.data = data;
     }
-    if (height != null) {
-      _result.height = height;
-    }
     return _result;
   }
   factory CellMeta.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
@@ -953,50 +938,21 @@ class CellMeta extends $pb.GeneratedMessage {
   static CellMeta? _defaultInstance;
 
   @$pb.TagNumber(1)
-  $core.String get id => $_getSZ(0);
+  $core.String get fieldId => $_getSZ(0);
   @$pb.TagNumber(1)
-  set id($core.String v) { $_setString(0, v); }
+  set fieldId($core.String v) { $_setString(0, v); }
   @$pb.TagNumber(1)
-  $core.bool hasId() => $_has(0);
+  $core.bool hasFieldId() => $_has(0);
   @$pb.TagNumber(1)
-  void clearId() => clearField(1);
+  void clearFieldId() => clearField(1);
 
   @$pb.TagNumber(2)
-  $core.String get rowId => $_getSZ(1);
+  $core.String get data => $_getSZ(1);
   @$pb.TagNumber(2)
-  set rowId($core.String v) { $_setString(1, v); }
+  set data($core.String v) { $_setString(1, v); }
   @$pb.TagNumber(2)
-  $core.bool hasRowId() => $_has(1);
+  $core.bool hasData() => $_has(1);
   @$pb.TagNumber(2)
-  void clearRowId() => clearField(2);
-
-  @$pb.TagNumber(3)
-  $core.String get fieldId => $_getSZ(2);
-  @$pb.TagNumber(3)
-  set fieldId($core.String v) { $_setString(2, v); }
-  @$pb.TagNumber(3)
-  $core.bool hasFieldId() => $_has(2);
-  @$pb.TagNumber(3)
-  void clearFieldId() => clearField(3);
-
-  @$pb.TagNumber(4)
-  AnyData get data => $_getN(3);
-  @$pb.TagNumber(4)
-  set data(AnyData v) { setField(4, v); }
-  @$pb.TagNumber(4)
-  $core.bool hasData() => $_has(3);
-  @$pb.TagNumber(4)
-  void clearData() => clearField(4);
-  @$pb.TagNumber(4)
-  AnyData ensureData() => $_ensure(3);
-
-  @$pb.TagNumber(5)
-  $core.int get height => $_getIZ(4);
-  @$pb.TagNumber(5)
-  set height($core.int v) { $_setSignedInt32(4, v); }
-  @$pb.TagNumber(5)
-  $core.bool hasHeight() => $_has(4);
-  @$pb.TagNumber(5)
-  void clearHeight() => clearField(5);
+  void clearData() => clearField(2);
 }
 

+ 3 - 6
frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/meta.pbjson.dart

@@ -179,13 +179,10 @@ final $typed_data.Uint8List rowMetaChangesetDescriptor = $convert.base64Decode('
 const CellMeta$json = const {
   '1': 'CellMeta',
   '2': const [
-    const {'1': 'id', '3': 1, '4': 1, '5': 9, '10': 'id'},
-    const {'1': 'row_id', '3': 2, '4': 1, '5': 9, '10': 'rowId'},
-    const {'1': 'field_id', '3': 3, '4': 1, '5': 9, '10': 'fieldId'},
-    const {'1': 'data', '3': 4, '4': 1, '5': 11, '6': '.AnyData', '10': 'data'},
-    const {'1': 'height', '3': 5, '4': 1, '5': 5, '10': 'height'},
+    const {'1': 'field_id', '3': 1, '4': 1, '5': 9, '10': 'fieldId'},
+    const {'1': 'data', '3': 2, '4': 1, '5': 9, '10': 'data'},
   ],
 };
 
 /// Descriptor for `CellMeta`. Decode as a `google.protobuf.DescriptorProto`.
-final $typed_data.Uint8List cellMetaDescriptor = $convert.base64Decode('CghDZWxsTWV0YRIOCgJpZBgBIAEoCVICaWQSFQoGcm93X2lkGAIgASgJUgVyb3dJZBIZCghmaWVsZF9pZBgDIAEoCVIHZmllbGRJZBIcCgRkYXRhGAQgASgLMgguQW55RGF0YVIEZGF0YRIWCgZoZWlnaHQYBSABKAVSBmhlaWdodA==');
+final $typed_data.Uint8List cellMetaDescriptor = $convert.base64Decode('CghDZWxsTWV0YRIZCghmaWVsZF9pZBgBIAEoCVIHZmllbGRJZBISCgRkYXRhGAIgASgJUgRkYXRh');

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

@@ -24,7 +24,7 @@ pub(crate) async fn get_rows_handler(
 ) -> DataResult<RepeatedRow, FlowyError> {
     let payload: QueryRowPayload = data.into_inner();
     let editor = manager.get_grid_editor(&payload.grid_id)?;
-    let repeated_row = editor.get_rows(payload.row_orders).await?;
+    let repeated_row: RepeatedRow = editor.get_rows(Some(payload.row_orders)).await?.into();
     data_result(repeated_row)
 }
 
@@ -35,7 +35,7 @@ pub(crate) async fn get_fields_handler(
 ) -> DataResult<RepeatedField, FlowyError> {
     let payload: QueryFieldPayload = data.into_inner();
     let editor = manager.get_grid_editor(&payload.grid_id)?;
-    let repeated_field = editor.get_fields(Some(payload.field_orders)).await?;
+    let repeated_field: RepeatedField = editor.get_fields(Some(payload.field_orders)).await?.into();
     data_result(repeated_field)
 }
 

+ 0 - 2
frontend/rust-lib/flowy-grid/src/services/field/mod.rs

@@ -1,7 +1,5 @@
-mod cell_stringify;
 mod field_builder;
 mod type_options;
 
-pub use cell_stringify::*;
 pub use field_builder::*;
 pub use type_options::*;

+ 1 - 1
frontend/rust-lib/flowy-grid/src/services/field/type_options.rs

@@ -1,6 +1,6 @@
 #![allow(clippy::upper_case_acronyms)]
 use crate::impl_from_and_to_type_option;
-use crate::services::field::StringifyCellData;
+use crate::services::row::StringifyCellData;
 use crate::services::util::*;
 use bytes::Bytes;
 use chrono::format::strftime::StrftimeItems;

+ 43 - 96
frontend/rust-lib/flowy-grid/src/services/grid_editor.rs

@@ -1,7 +1,7 @@
 use crate::manager::GridUser;
 use crate::services::kv_persistence::{GridKVPersistence, KVTransaction};
 
-use crate::services::grid_meta_editor::ClientGridBlockMetaEditor;
+use crate::services::grid_meta_editor::{ClientGridBlockMetaEditor, GridBlockMetaEditorManager};
 use bytes::Bytes;
 use dashmap::DashMap;
 use flowy_collaboration::client_grid::{GridChange, GridMetaPad};
@@ -9,7 +9,8 @@ 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::{
-    Field, FieldChangeset, Grid, GridBlock, RepeatedField, RepeatedFieldOrder, RepeatedRow, RepeatedRowOrder,
+    Field, FieldChangeset, Grid, GridBlock, GridBlockChangeset, RepeatedField, RepeatedFieldOrder, RepeatedRow,
+    RepeatedRowOrder, Row,
 };
 use flowy_sync::disk::SQLiteGridBlockMetaRevisionPersistence;
 use flowy_sync::{
@@ -43,7 +44,7 @@ impl ClientGridEditor {
         let grid_meta_pad = Arc::new(RwLock::new(grid_pad));
 
         let block_meta_manager =
-            Arc::new(GridBlockMetaEditorManager::new(&user, grid_meta_pad.read().await.get_blocks()).await?);
+            Arc::new(GridBlockMetaEditorManager::new(&user, grid_meta_pad.read().await.get_blocks().clone()).await?);
 
         Ok(Arc::new(Self {
             grid_id: grid_id.to_owned(),
@@ -70,27 +71,60 @@ impl ClientGridEditor {
         Ok(())
     }
 
+    pub async fn create_block(&self, grid_block: GridBlock) -> FlowyResult<()> {
+        let _ = self.modify(|grid| Ok(grid.create_block(grid_block)?)).await?;
+        Ok(())
+    }
+
+    pub async fn update_block(&self, change: GridBlockChangeset) -> FlowyResult<()> {
+        let _ = self.modify(|grid| Ok(grid.update_block(change)?)).await?;
+        Ok(())
+    }
+
     pub async fn create_row(&self) -> FlowyResult<()> {
-        todo!()
+        let fields = self.grid_meta_pad.read().await.get_fields(None)?;
+        match self.grid_meta_pad.read().await.get_blocks().last() {
+            None => Err(FlowyError::internal().context("There is no grid block in this grid")),
+            Some(grid_block) => {
+                let row_count = self.block_meta_manager.create_row(fields, grid_block).await?;
+                let change = GridBlockChangeset::from_row_count(&grid_block.id, row_count);
+                let _ = self.update_block(change).await?;
+                Ok(())
+            }
+        }
     }
 
-    pub async fn get_rows(&self, _row_orders: RepeatedRowOrder) -> FlowyResult<RepeatedRow> {
-        todo!()
+    pub async fn get_rows(&self, row_orders: Option<RepeatedRowOrder>) -> FlowyResult<Vec<Row>> {
+        let fields = self.grid_meta_pad.read().await.get_fields(None)?;
+        let rows = self.block_meta_manager.get_rows(fields, row_orders).await?;
+        Ok(rows)
     }
 
-    pub async fn delete_rows(&self, _ids: Vec<String>) -> FlowyResult<()> {
-        todo!()
+    pub async fn delete_rows(&self, row_orders: Option<RepeatedRowOrder>) -> FlowyResult<()> {
+        let row_counts = self.block_meta_manager.delete_rows(row_orders).await?;
+        for (block_id, row_count) in row_counts {
+            let _ = self
+                .update_block(GridBlockChangeset::from_row_count(&block_id, row_count))
+                .await?;
+        }
+
+        Ok(())
     }
 
     pub async fn grid_data(&self) -> Grid {
         todo!()
     }
 
-    pub async fn get_fields(&self, field_orders: Option<RepeatedFieldOrder>) -> FlowyResult<RepeatedField> {
+    pub async fn get_fields(&self, field_orders: Option<RepeatedFieldOrder>) -> FlowyResult<Vec<Field>> {
         let fields = self.grid_meta_pad.read().await.get_fields(field_orders)?;
         Ok(fields)
     }
 
+    pub async fn get_blocks(&self) -> FlowyResult<Vec<GridBlock>> {
+        let grid_blocks = self.grid_meta_pad.read().await.get_blocks();
+        Ok(grid_blocks)
+    }
+
     pub async fn delta_str(&self) -> String {
         self.grid_meta_pad.read().await.delta_str()
     }
@@ -184,90 +218,3 @@ impl RevisionCompactor for GridRevisionCompactor {
         Ok(delta.to_bytes())
     }
 }
-
-struct GridBlockMetaEditorManager {
-    editor_map: DashMap<String, Arc<ClientGridBlockMetaEditor>>,
-}
-
-impl GridBlockMetaEditorManager {
-    async fn new(user: &Arc<dyn GridUser>, blocks: Vec<GridBlock>) -> FlowyResult<Self> {
-        let editor_map = make_block_meta_editor_map(user, blocks).await?;
-        let manager = Self { editor_map };
-        Ok(manager)
-    }
-
-    async fn get_editor(&self, _block_id: &str) -> Arc<ClientGridBlockMetaEditor> {
-        todo!()
-    }
-
-    pub async fn get_rows(&self, _row_orders: RepeatedRowOrder) -> FlowyResult<RepeatedRow> {
-        // let ids = row_orders
-        //     .items
-        //     .into_iter()
-        //     .map(|row_order| row_order.row_id)
-        //     .collect::<Vec<_>>();
-        // let row_metas: Vec<RowMeta> = self.kv_persistence.batch_get(ids)?;
-        //
-        // let make_cell = |field_id: String, raw_cell: CellMeta| {
-        //     let some_field = self.field_map.get(&field_id);
-        //     if some_field.is_none() {
-        //         tracing::error!("Can't find the field with {}", field_id);
-        //         return None;
-        //     }
-        //     self.cell_map.insert(raw_cell.id.clone(), raw_cell.clone());
-        //
-        //     let field = some_field.unwrap();
-        //     match stringify_deserialize(raw_cell.data, field.value()) {
-        //         Ok(content) => {
-        //             let cell = Cell {
-        //                 id: raw_cell.id,
-        //                 field_id: field_id.clone(),
-        //                 content,
-        //             };
-        //             Some((field_id, cell))
-        //         }
-        //         Err(_) => None,
-        //     }
-        // };
-        //
-        // let rows = row_metas
-        //     .into_par_iter()
-        //     .map(|row_meta| {
-        //         let mut row = Row {
-        //             id: row_meta.id.clone(),
-        //             cell_by_field_id: Default::default(),
-        //             height: row_meta.height,
-        //         };
-        //         row.cell_by_field_id = row_meta
-        //             .cell_by_field_id
-        //             .into_par_iter()
-        //             .flat_map(|(field_id, raw_cell)| make_cell(field_id, raw_cell))
-        //             .collect::<HashMap<String, Cell>>();
-        //         row
-        //     })
-        //     .collect::<Vec<Row>>();
-        //
-        // Ok(rows.into())
-        todo!()
-    }
-}
-
-async fn make_block_meta_editor_map(
-    user: &Arc<dyn GridUser>,
-    blocks: Vec<GridBlock>,
-) -> FlowyResult<DashMap<String, Arc<ClientGridBlockMetaEditor>>> {
-    let token = user.token()?;
-    let user_id = user.user_id()?;
-    let pool = user.db_pool()?;
-
-    let editor_map = DashMap::new();
-    for block in blocks {
-        let disk_cache = Arc::new(SQLiteGridBlockMetaRevisionPersistence::new(&user_id, pool.clone()));
-        let rev_persistence = Arc::new(RevisionPersistence::new(&user_id, &block.id, disk_cache));
-        let rev_manager = RevisionManager::new(&user_id, &block.id, rev_persistence);
-        let editor = ClientGridBlockMetaEditor::new(&user_id, &token, &block.id, rev_manager).await?;
-        editor_map.insert(block.id, Arc::new(editor));
-    }
-
-    Ok(editor_map)
-}

+ 108 - 6
frontend/rust-lib/flowy-grid/src/services/grid_meta_editor.rs

@@ -1,15 +1,110 @@
+use crate::manager::GridUser;
+use crate::services::row::{make_row_ids_per_block, make_rows, sort_rows, RowBuilder};
 use bytes::Bytes;
+use dashmap::mapref::one::Ref;
+use dashmap::DashMap;
 use flowy_collaboration::client_grid::{GridBlockMetaChange, GridBlockMetaPad};
 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::{RowMeta, RowMetaChangeset};
-use flowy_sync::{RevisionCloudService, RevisionCompactor, RevisionManager, RevisionObjectBuilder};
+use flowy_grid_data_model::entities::{
+    Field, GridBlock, RepeatedRow, RepeatedRowOrder, Row, RowMeta, RowMetaChangeset,
+};
+use flowy_sync::disk::SQLiteGridBlockMetaRevisionPersistence;
+use flowy_sync::{
+    RevisionCloudService, RevisionCompactor, RevisionManager, RevisionObjectBuilder, RevisionPersistence,
+};
 use lib_infra::future::FutureResult;
 use lib_ot::core::PlainTextAttributes;
+use lib_sqlite::ConnectionPool;
+use std::collections::HashMap;
 use std::sync::Arc;
 use tokio::sync::RwLock;
 
+pub(crate) struct GridBlockMetaEditorManager {
+    user: Arc<dyn GridUser>,
+    editor_map: DashMap<String, Arc<ClientGridBlockMetaEditor>>,
+}
+
+impl GridBlockMetaEditorManager {
+    pub(crate) async fn new(user: &Arc<dyn GridUser>, blocks: Vec<GridBlock>) -> FlowyResult<Self> {
+        let editor_map = make_block_meta_editor_map(user, blocks).await?;
+        let user = user.clone();
+        let manager = Self { user, editor_map };
+        Ok(manager)
+    }
+
+    pub(crate) async fn get_editor(&self, block_id: &str) -> FlowyResult<Arc<ClientGridBlockMetaEditor>> {
+        match self.editor_map.get(block_id) {
+            None => {
+                tracing::error!("The is a fatal error, block is not exist");
+                let editor = Arc::new(make_block_meta_editor(&self.user, block_id).await?);
+                self.editor_map.insert(block_id.to_owned(), editor.clone());
+                Ok(editor)
+            }
+            Some(editor) => Ok(editor.clone()),
+        }
+    }
+
+    pub(crate) async fn create_row(&self, fields: Vec<Field>, grid_block: &GridBlock) -> FlowyResult<i32> {
+        let row = RowBuilder::new(&fields, &grid_block.id).build();
+        let editor = self.get_editor(&grid_block.id).await?;
+        editor.create_row(row).await
+    }
+
+    pub(crate) async fn delete_rows(&self, row_orders: Option<RepeatedRowOrder>) -> FlowyResult<Vec<(String, i32)>> {
+        Ok(vec![("".to_owned(), 2)])
+    }
+
+    pub(crate) async fn get_rows(
+        &self,
+        fields: Vec<Field>,
+        row_orders: Option<RepeatedRowOrder>,
+    ) -> FlowyResult<Vec<Row>> {
+        match row_orders {
+            None => {
+                let rows = vec![];
+                Ok(rows)
+            }
+            Some(row_orders) => {
+                let row_ids_per_blocks = make_row_ids_per_block(&row_orders);
+                let mut rows = vec![];
+                for row_ids_per_block in row_ids_per_blocks {
+                    let editor = self.get_editor(&row_ids_per_block.block_id).await?;
+                    let row_metas = editor.get_rows(row_ids_per_block.row_ids).await?;
+                    rows.extend(make_rows(&fields, row_metas));
+                }
+                sort_rows(&mut rows, row_orders);
+                Ok(rows)
+            }
+        }
+    }
+}
+
+async fn make_block_meta_editor_map(
+    user: &Arc<dyn GridUser>,
+    blocks: Vec<GridBlock>,
+) -> FlowyResult<DashMap<String, Arc<ClientGridBlockMetaEditor>>> {
+    let editor_map = DashMap::new();
+    for block in blocks {
+        let editor = make_block_meta_editor(user, &block.id).await?;
+        editor_map.insert(block.id, Arc::new(editor));
+    }
+
+    Ok(editor_map)
+}
+
+async fn make_block_meta_editor(user: &Arc<dyn GridUser>, block_id: &str) -> FlowyResult<ClientGridBlockMetaEditor> {
+    let token = user.token()?;
+    let user_id = user.user_id()?;
+    let pool = user.db_pool()?;
+
+    let disk_cache = Arc::new(SQLiteGridBlockMetaRevisionPersistence::new(&user_id, pool));
+    let rev_persistence = Arc::new(RevisionPersistence::new(&user_id, block_id, disk_cache));
+    let rev_manager = RevisionManager::new(&user_id, block_id, rev_persistence);
+    ClientGridBlockMetaEditor::new(&user_id, &token, block_id, rev_manager).await
+}
+
 pub struct ClientGridBlockMetaEditor {
     user_id: String,
     pub block_id: String,
@@ -40,10 +135,17 @@ impl ClientGridBlockMetaEditor {
         })
     }
 
-    async fn create_row(&self) -> FlowyResult<()> {
-        let row = RowMeta::new(&self.block_id, vec![]);
-        let _ = self.modify(|pad| Ok(pad.add_row(row)?)).await?;
-        Ok(())
+    async fn create_row(&self, row: RowMeta) -> FlowyResult<i32> {
+        let mut row_count = 0;
+        let _ = self
+            .modify(|pad| {
+                let change = pad.add_row(row)?;
+                row_count = pad.number_of_rows();
+                Ok(change)
+            })
+            .await?;
+
+        Ok(row_count)
     }
 
     pub async fn delete_rows(&self, ids: Vec<String>) -> FlowyResult<()> {

+ 1 - 0
frontend/rust-lib/flowy-grid/src/services/mod.rs

@@ -4,3 +4,4 @@ pub mod field;
 pub mod grid_editor;
 pub mod grid_meta_editor;
 pub mod kv_persistence;
+pub mod row;

+ 0 - 0
frontend/rust-lib/flowy-grid/src/services/field/cell_stringify.rs → frontend/rust-lib/flowy-grid/src/services/row/cell_stringify.rs


+ 7 - 0
frontend/rust-lib/flowy-grid/src/services/row/mod.rs

@@ -0,0 +1,7 @@
+mod cell_stringify;
+mod row_builder;
+mod row_loader;
+
+pub use cell_stringify::*;
+pub use row_builder::*;
+pub use row_loader::*;

+ 24 - 0
frontend/rust-lib/flowy-grid/src/services/row/row_builder.rs

@@ -0,0 +1,24 @@
+use flowy_grid_data_model::entities::{CellMeta, Field, RowMeta};
+
+pub struct RowBuilder<'a> {
+    fields: &'a Vec<Field>,
+    row: RowMeta,
+}
+
+impl<'a> RowBuilder<'a> {
+    pub fn new(fields: &'a Vec<Field>, block_id: &'a String) -> Self {
+        let row = RowMeta::new(block_id);
+        Self { fields, row }
+    }
+
+    #[allow(dead_code)]
+    pub fn add_cell(mut self, field_id: &str, data: String) -> Self {
+        let cell = CellMeta::new(field_id, data);
+        self.row.cell_by_field_id.insert(field_id.to_owned(), cell);
+        self
+    }
+
+    pub fn build(self) -> RowMeta {
+        self.row
+    }
+}

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

@@ -0,0 +1,68 @@
+use flowy_grid_data_model::entities::{Field, RepeatedRowOrder, Row, RowMeta};
+use std::collections::HashMap;
+
+pub(crate) struct RowIdsPerBlock {
+    pub(crate) block_id: String,
+    pub(crate) row_ids: Vec<String>,
+}
+
+pub(crate) fn make_row_ids_per_block(row_orders: &RepeatedRowOrder) -> Vec<RowIdsPerBlock> {
+    let mut map: HashMap<String, RowIdsPerBlock> = HashMap::new();
+    row_orders.iter().for_each(|row_order| {
+        let block_id = row_order.block_id.clone();
+        let entry = map.entry(block_id.clone()).or_insert(RowIdsPerBlock {
+            block_id,
+            row_ids: vec![],
+        });
+        entry.row_ids.push(row_order.row_id.clone());
+    });
+    map.into_values().collect::<Vec<_>>()
+}
+
+pub(crate) fn sort_rows(rows: &mut Vec<Row>, row_orders: RepeatedRowOrder) {
+    todo!()
+}
+
+pub(crate) fn make_rows(fields: &Vec<Field>, rows: Vec<RowMeta>) -> Vec<Row> {
+    // let make_cell = |field_id: String, raw_cell: CellMeta| {
+    //     let some_field = self.field_map.get(&field_id);
+    //     if some_field.is_none() {
+    //         tracing::error!("Can't find the field with {}", field_id);
+    //         return None;
+    //     }
+    //     self.cell_map.insert(raw_cell.id.clone(), raw_cell.clone());
+    //
+    //     let field = some_field.unwrap();
+    //     match stringify_deserialize(raw_cell.data, field.value()) {
+    //         Ok(content) => {
+    //             let cell = Cell {
+    //                 id: raw_cell.id,
+    //                 field_id: field_id.clone(),
+    //                 content,
+    //             };
+    //             Some((field_id, cell))
+    //         }
+    //         Err(_) => None,
+    //     }
+    // };
+    //
+    // let rows = row_metas
+    //     .into_par_iter()
+    //     .map(|row_meta| {
+    //         let mut row = Row {
+    //             id: row_meta.id.clone(),
+    //             cell_by_field_id: Default::default(),
+    //             height: row_meta.height,
+    //         };
+    //         row.cell_by_field_id = row_meta
+    //             .cell_by_field_id
+    //             .into_par_iter()
+    //             .flat_map(|(field_id, raw_cell)| make_cell(field_id, raw_cell))
+    //             .collect::<HashMap<String, Cell>>();
+    //         row
+    //     })
+    //     .collect::<Vec<Row>>();
+    //
+    // Ok(rows.into())
+    todo!()
+}

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

@@ -1,7 +1,7 @@
 use crate::grid::script::EditorScript::*;
 use crate::grid::script::*;
 use flowy_grid::services::field::{SelectOption, SingleSelectDescription};
-use flowy_grid_data_model::entities::FieldChangeset;
+use flowy_grid_data_model::entities::{FieldChangeset, GridBlock, GridBlockChangeset};
 
 #[tokio::test]
 async fn default_grid_test() {
@@ -35,6 +35,23 @@ async fn grid_create_field() {
     GridEditorTest::new().await.run_scripts(scripts).await;
 }
 
+#[tokio::test]
+async fn grid_create_duplicate_field() {
+    let text_field = create_text_field();
+    let scripts = vec![
+        AssertFieldCount(2),
+        CreateField {
+            field: text_field.clone(),
+        },
+        AssertFieldCount(3),
+        CreateField {
+            field: text_field.clone(),
+        },
+        AssertFieldCount(3),
+    ];
+    GridEditorTest::new().await.run_scripts(scripts).await;
+}
+
 #[tokio::test]
 async fn grid_update_field_with_empty_change() {
     let single_select_field = create_single_select_field();
@@ -98,3 +115,60 @@ async fn grid_update_field() {
     ];
     GridEditorTest::new().await.run_scripts(scripts).await;
 }
+
+#[tokio::test]
+async fn grid_delete_field() {
+    let text_field = create_text_field();
+    let scripts = vec![
+        CreateField {
+            field: text_field.clone(),
+        },
+        AssertFieldCount(3),
+        DeleteField { field: text_field },
+        AssertFieldCount(2),
+    ];
+    GridEditorTest::new().await.run_scripts(scripts).await;
+}
+
+#[tokio::test]
+async fn grid_create_block() {
+    let grid_block = GridBlock::new();
+    let scripts = vec![
+        AssertBlockCount(1),
+        CreateBlock { block: grid_block },
+        AssertBlockCount(2),
+    ];
+    GridEditorTest::new().await.run_scripts(scripts).await;
+}
+
+#[tokio::test]
+async fn grid_update_block() {
+    let grid_block = GridBlock::new();
+    let mut cloned_grid_block = grid_block.clone();
+    let change = GridBlockChangeset {
+        block_id: grid_block.id.clone(),
+        start_row_index: Some(2),
+        row_count: Some(10),
+    };
+
+    cloned_grid_block.start_row_index = 2;
+    cloned_grid_block.row_count = 10;
+
+    let scripts = vec![
+        AssertBlockCount(1),
+        CreateBlock { block: grid_block },
+        UpdateBlock { change },
+        AssertBlockCount(2),
+        AssertBlockEqual {
+            block_index: 1,
+            block: cloned_grid_block,
+        },
+    ];
+    GridEditorTest::new().await.run_scripts(scripts).await;
+}
+
+#[tokio::test]
+async fn grid_create_row() {
+    let scripts = vec![AssertRowCount(2), CreateRow, CreateRow, CreateRow, AssertRowCount(5)];
+    GridEditorTest::new().await.run_scripts(scripts).await;
+}

+ 32 - 3
frontend/rust-lib/flowy-grid/tests/grid/script.rs

@@ -1,6 +1,6 @@
 use flowy_grid::services::field::*;
 use flowy_grid::services::grid_editor::{ClientGridEditor, GridPadBuilder};
-use flowy_grid_data_model::entities::{AnyData, Field, FieldChangeset, FieldType};
+use flowy_grid_data_model::entities::{AnyData, Field, FieldChangeset, FieldType, GridBlock, GridBlockChangeset};
 use flowy_sync::REVISION_WRITE_INTERVAL_IN_MILLIS;
 use flowy_test::event_builder::FolderEventBuilder;
 use flowy_test::helper::ViewTest;
@@ -12,10 +12,17 @@ use tokio::time::sleep;
 pub enum EditorScript {
     CreateField { field: Field },
     UpdateField { change: FieldChangeset },
+    DeleteField { field: Field },
     AssertFieldCount(usize),
     AssertFieldEqual { field_index: usize, field: Field },
-    AssertGridMetaPad,
+    CreateBlock { block: GridBlock },
+    UpdateBlock { change: GridBlockChangeset },
+    AssertBlockCount(usize),
+    AssertBlockEqual { block_index: usize, block: GridBlock },
     CreateRow,
+    AssertRowCount(usize),
+    // AssertRowEqual{ row_index: usize, row: RowMeta},
+    AssertGridMetaPad,
 }
 
 pub struct GridEditorTest {
@@ -53,6 +60,9 @@ impl GridEditorTest {
             EditorScript::UpdateField { change } => {
                 self.editor.update_field(change).await.unwrap();
             }
+            EditorScript::DeleteField { field } => {
+                self.editor.delete_field(&field.id).await.unwrap();
+            }
             EditorScript::AssertFieldCount(count) => {
                 assert_eq!(self.editor.get_fields(None).await.unwrap().len(), count);
             }
@@ -61,13 +71,32 @@ impl GridEditorTest {
                 let compared_field = repeated_fields[field_index].clone();
                 assert_eq!(compared_field, field);
             }
+            EditorScript::CreateBlock { block } => {
+                self.editor.create_block(block).await.unwrap();
+            }
+            EditorScript::UpdateBlock { change } => {
+                self.editor.update_block(change).await.unwrap();
+            }
+            EditorScript::AssertBlockCount(count) => {
+                assert_eq!(self.editor.get_blocks().await.unwrap().len(), count);
+            }
+            EditorScript::AssertBlockEqual { block_index, block } => {
+                let blocks = self.editor.get_blocks().await.unwrap();
+                let compared_block = blocks[block_index].clone();
+                assert_eq!(compared_block, block);
+            }
+            EditorScript::CreateRow => {
+                self.editor.create_row().await.unwrap();
+            }
+            EditorScript::AssertRowCount(count) => {
+                assert_eq!(self.editor.get_rows(None).await.unwrap().len(), count);
+            }
             EditorScript::AssertGridMetaPad => {
                 sleep(Duration::from_millis(2 * REVISION_WRITE_INTERVAL_IN_MILLIS)).await;
                 let mut grid_rev_manager = grid_manager.make_grid_rev_manager(&self.grid_id, pool.clone()).unwrap();
                 let grid_pad = grid_rev_manager.load::<GridPadBuilder>(None).await.unwrap();
                 println!("{}", grid_pad.delta_str());
             }
-            EditorScript::CreateRow => {}
         }
     }
 }

+ 4 - 0
shared-lib/flowy-collaboration/src/client_grid/block_pad.rs

@@ -69,6 +69,10 @@ impl GridBlockMetaPad {
             .collect::<Vec<RowMeta>>())
     }
 
+    pub fn number_of_rows(&self) -> i32 {
+        self.rows.len() as i32
+    }
+
     pub fn update_row(&mut self, changeset: RowMetaChangeset) -> CollaborateResult<Option<GridBlockMetaChange>> {
         let row_id = changeset.row_id.clone();
         self.modify_row(&row_id, |row| {

+ 1 - 1
shared-lib/flowy-collaboration/src/client_grid/grid_builder.rs

@@ -31,7 +31,7 @@ impl GridBuilder {
     }
 
     pub fn add_empty_row(mut self) -> Self {
-        let row = RowMeta::new(&self.grid_block.id, vec![]);
+        let row = RowMeta::new(&self.grid_block.id);
         self.grid_block_meta.rows.push(row);
         self
     }

+ 21 - 6
shared-lib/flowy-collaboration/src/client_grid/grid_pad.rs

@@ -36,8 +36,13 @@ impl GridMetaPad {
 
     pub fn create_field(&mut self, field: Field) -> CollaborateResult<Option<GridChange>> {
         self.modify_grid(|grid| {
-            grid.fields.push(field);
-            Ok(Some(()))
+            if grid.fields.contains(&field) {
+                tracing::warn!("Duplicate grid field");
+                Ok(None)
+            } else {
+                grid.fields.push(field);
+                Ok(Some(()))
+            }
         })
     }
 
@@ -51,7 +56,7 @@ impl GridMetaPad {
         })
     }
 
-    pub fn get_fields(&self, field_orders: Option<RepeatedFieldOrder>) -> CollaborateResult<RepeatedField> {
+    pub fn get_fields(&self, field_orders: Option<RepeatedFieldOrder>) -> CollaborateResult<Vec<Field>> {
         match field_orders {
             None => Ok(self.grid_meta.fields.clone().into()),
             Some(field_orders) => {
@@ -72,7 +77,7 @@ impl GridMetaPad {
                         Some(field) => Some((*field).clone()),
                     })
                     .collect::<Vec<Field>>();
-                Ok(fields.into())
+                Ok(fields)
             }
         }
     }
@@ -122,8 +127,13 @@ impl GridMetaPad {
 
     pub fn create_block(&mut self, block: GridBlock) -> CollaborateResult<Option<GridChange>> {
         self.modify_grid(|grid| {
-            grid.blocks.push(block);
-            Ok(Some(()))
+            if grid.blocks.iter().find(|b| b.id == block.id).is_some() {
+                tracing::warn!("Duplicate grid block");
+                Ok(None)
+            } else {
+                grid.blocks.push(block);
+                Ok(Some(()))
+            }
         })
     }
 
@@ -141,6 +151,11 @@ impl GridMetaPad {
                 is_changed = Some(());
             }
 
+            if let Some(start_row_index) = change.start_row_index {
+                block.start_row_index = start_row_index;
+                is_changed = Some(());
+            }
+
             Ok(is_changed)
         })
     }

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

@@ -45,11 +45,17 @@ impl std::ops::Deref for RepeatedFieldOrder {
 pub struct RowOrder {
     #[pb(index = 1)]
     pub row_id: String,
+
+    #[pb(index = 2)]
+    pub block_id: String,
 }
 
 impl std::convert::From<&RowMeta> for RowOrder {
     fn from(row: &RowMeta) -> Self {
-        Self { row_id: row.id.clone() }
+        Self {
+            row_id: row.id.clone(),
+            block_id: row.block_id.clone(),
+        }
     }
 }
 
@@ -111,12 +117,9 @@ impl std::convert::From<Vec<Row>> for RepeatedRow {
 #[derive(Debug, Default, ProtoBuf)]
 pub struct Cell {
     #[pb(index = 1)]
-    pub id: String,
-
-    #[pb(index = 2)]
     pub field_id: String,
 
-    #[pb(index = 3)]
+    #[pb(index = 2)]
     pub content: String,
 }
 

+ 25 - 20
shared-lib/flowy-grid-data-model/src/entities/meta.rs

@@ -18,7 +18,7 @@ pub struct GridMeta {
     pub blocks: Vec<GridBlock>,
 }
 
-#[derive(Debug, Clone, Default, Serialize, Deserialize, ProtoBuf)]
+#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, ProtoBuf)]
 pub struct GridBlock {
     #[pb(index = 1)]
     pub id: String,
@@ -45,6 +45,16 @@ pub struct GridBlockChangeset {
     pub row_count: Option<i32>,
 }
 
+impl GridBlockChangeset {
+    pub fn from_row_count(block_id: &str, row_count: i32) -> Self {
+        Self {
+            block_id: block_id.to_string(),
+            start_row_index: None,
+            row_count: Some(row_count),
+        }
+    }
+}
+
 #[derive(Debug, Clone, Default, Serialize, Deserialize, ProtoBuf)]
 pub struct GridBlockMeta {
     #[pb(index = 1)]
@@ -225,7 +235,7 @@ impl ToString for AnyData {
     }
 }
 
-#[derive(Debug, Clone, Default, Serialize, Deserialize, ProtoBuf)]
+#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, ProtoBuf)]
 pub struct RowMeta {
     #[pb(index = 1)]
     pub id: String,
@@ -244,16 +254,11 @@ pub struct RowMeta {
 }
 
 impl RowMeta {
-    pub fn new(block_id: &str, cells: Vec<CellMeta>) -> Self {
-        let cell_by_field_id = cells
-            .into_iter()
-            .map(|cell| (cell.id.clone(), cell))
-            .collect::<HashMap<String, CellMeta>>();
-
+    pub fn new(block_id: &str) -> Self {
         Self {
             id: uuid::Uuid::new_v4().to_string(),
             block_id: block_id.to_owned(),
-            cell_by_field_id,
+            cell_by_field_id: Default::default(),
             height: DEFAULT_ROW_HEIGHT,
             visibility: true,
         }
@@ -275,20 +280,20 @@ pub struct RowMetaChangeset {
     pub cell_by_field_id: HashMap<String, CellMeta>,
 }
 
-#[derive(Debug, Clone, Default, Serialize, Deserialize, ProtoBuf)]
+#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize, ProtoBuf)]
 pub struct CellMeta {
     #[pb(index = 1)]
-    pub id: String,
-
-    #[pb(index = 2)]
-    pub row_id: String,
-
-    #[pb(index = 3)]
     pub field_id: String,
 
-    #[pb(index = 4)]
-    pub data: AnyData,
+    #[pb(index = 2)]
+    pub data: String,
+}
 
-    #[pb(index = 5)]
-    pub height: i32,
+impl CellMeta {
+    pub fn new(field_id: &str, data: String) -> Self {
+        Self {
+            field_id: field_id.to_string(),
+            data,
+        }
+    }
 }

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

@@ -609,6 +609,7 @@ impl ::protobuf::reflect::ProtobufValue for RepeatedFieldOrder {
 pub struct RowOrder {
     // message fields
     pub row_id: ::std::string::String,
+    pub block_id: ::std::string::String,
     // special fields
     pub unknown_fields: ::protobuf::UnknownFields,
     pub cached_size: ::protobuf::CachedSize,
@@ -650,6 +651,32 @@ impl RowOrder {
     pub fn take_row_id(&mut self) -> ::std::string::String {
         ::std::mem::replace(&mut self.row_id, ::std::string::String::new())
     }
+
+    // string block_id = 2;
+
+
+    pub fn get_block_id(&self) -> &str {
+        &self.block_id
+    }
+    pub fn clear_block_id(&mut self) {
+        self.block_id.clear();
+    }
+
+    // Param is passed by value, moved
+    pub fn set_block_id(&mut self, v: ::std::string::String) {
+        self.block_id = v;
+    }
+
+    // Mutable pointer to the field.
+    // If field is not initialized, it is initialized with default value first.
+    pub fn mut_block_id(&mut self) -> &mut ::std::string::String {
+        &mut self.block_id
+    }
+
+    // Take field
+    pub fn take_block_id(&mut self) -> ::std::string::String {
+        ::std::mem::replace(&mut self.block_id, ::std::string::String::new())
+    }
 }
 
 impl ::protobuf::Message for RowOrder {
@@ -664,6 +691,9 @@ impl ::protobuf::Message for RowOrder {
                 1 => {
                     ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.row_id)?;
                 },
+                2 => {
+                    ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.block_id)?;
+                },
                 _ => {
                     ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
                 },
@@ -679,6 +709,9 @@ impl ::protobuf::Message for RowOrder {
         if !self.row_id.is_empty() {
             my_size += ::protobuf::rt::string_size(1, &self.row_id);
         }
+        if !self.block_id.is_empty() {
+            my_size += ::protobuf::rt::string_size(2, &self.block_id);
+        }
         my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
         self.cached_size.set(my_size);
         my_size
@@ -688,6 +721,9 @@ impl ::protobuf::Message for RowOrder {
         if !self.row_id.is_empty() {
             os.write_string(1, &self.row_id)?;
         }
+        if !self.block_id.is_empty() {
+            os.write_string(2, &self.block_id)?;
+        }
         os.write_unknown_fields(self.get_unknown_fields())?;
         ::std::result::Result::Ok(())
     }
@@ -731,6 +767,11 @@ impl ::protobuf::Message for RowOrder {
                 |m: &RowOrder| { &m.row_id },
                 |m: &mut RowOrder| { &mut m.row_id },
             ));
+            fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
+                "block_id",
+                |m: &RowOrder| { &m.block_id },
+                |m: &mut RowOrder| { &mut m.block_id },
+            ));
             ::protobuf::reflect::MessageDescriptor::new_pb_name::<RowOrder>(
                 "RowOrder",
                 fields,
@@ -748,6 +789,7 @@ impl ::protobuf::Message for RowOrder {
 impl ::protobuf::Clear for RowOrder {
     fn clear(&mut self) {
         self.row_id.clear();
+        self.block_id.clear();
         self.unknown_fields.clear();
     }
 }
@@ -1330,7 +1372,6 @@ impl ::protobuf::reflect::ProtobufValue for RepeatedRow {
 #[derive(PartialEq,Clone,Default)]
 pub struct Cell {
     // message fields
-    pub id: ::std::string::String,
     pub field_id: ::std::string::String,
     pub content: ::std::string::String,
     // special fields
@@ -1349,33 +1390,7 @@ impl Cell {
         ::std::default::Default::default()
     }
 
-    // string id = 1;
-
-
-    pub fn get_id(&self) -> &str {
-        &self.id
-    }
-    pub fn clear_id(&mut self) {
-        self.id.clear();
-    }
-
-    // Param is passed by value, moved
-    pub fn set_id(&mut self, v: ::std::string::String) {
-        self.id = v;
-    }
-
-    // Mutable pointer to the field.
-    // If field is not initialized, it is initialized with default value first.
-    pub fn mut_id(&mut self) -> &mut ::std::string::String {
-        &mut self.id
-    }
-
-    // Take field
-    pub fn take_id(&mut self) -> ::std::string::String {
-        ::std::mem::replace(&mut self.id, ::std::string::String::new())
-    }
-
-    // string field_id = 2;
+    // string field_id = 1;
 
 
     pub fn get_field_id(&self) -> &str {
@@ -1401,7 +1416,7 @@ impl Cell {
         ::std::mem::replace(&mut self.field_id, ::std::string::String::new())
     }
 
-    // string content = 3;
+    // string content = 2;
 
 
     pub fn get_content(&self) -> &str {
@@ -1438,12 +1453,9 @@ impl ::protobuf::Message for Cell {
             let (field_number, wire_type) = is.read_tag_unpack()?;
             match field_number {
                 1 => {
-                    ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.id)?;
-                },
-                2 => {
                     ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.field_id)?;
                 },
-                3 => {
+                2 => {
                     ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.content)?;
                 },
                 _ => {
@@ -1458,14 +1470,11 @@ impl ::protobuf::Message for Cell {
     #[allow(unused_variables)]
     fn compute_size(&self) -> u32 {
         let mut my_size = 0;
-        if !self.id.is_empty() {
-            my_size += ::protobuf::rt::string_size(1, &self.id);
-        }
         if !self.field_id.is_empty() {
-            my_size += ::protobuf::rt::string_size(2, &self.field_id);
+            my_size += ::protobuf::rt::string_size(1, &self.field_id);
         }
         if !self.content.is_empty() {
-            my_size += ::protobuf::rt::string_size(3, &self.content);
+            my_size += ::protobuf::rt::string_size(2, &self.content);
         }
         my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
         self.cached_size.set(my_size);
@@ -1473,14 +1482,11 @@ impl ::protobuf::Message for Cell {
     }
 
     fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> {
-        if !self.id.is_empty() {
-            os.write_string(1, &self.id)?;
-        }
         if !self.field_id.is_empty() {
-            os.write_string(2, &self.field_id)?;
+            os.write_string(1, &self.field_id)?;
         }
         if !self.content.is_empty() {
-            os.write_string(3, &self.content)?;
+            os.write_string(2, &self.content)?;
         }
         os.write_unknown_fields(self.get_unknown_fields())?;
         ::std::result::Result::Ok(())
@@ -1520,11 +1526,6 @@ impl ::protobuf::Message for Cell {
         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_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
-                "id",
-                |m: &Cell| { &m.id },
-                |m: &mut Cell| { &mut m.id },
-            ));
             fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
                 "field_id",
                 |m: &Cell| { &m.field_id },
@@ -1551,7 +1552,6 @@ impl ::protobuf::Message for Cell {
 
 impl ::protobuf::Clear for Cell {
     fn clear(&mut self) {
-        self.id.clear();
         self.field_id.clear();
         self.content.clear();
         self.unknown_fields.clear();
@@ -2326,17 +2326,17 @@ static file_descriptor_proto_data: &'static [u8] = b"\
     ders\x12(\n\nrow_orders\x18\x03\x20\x03(\x0b2\t.RowOrderR\trowOrders\"'\
     \n\nFieldOrder\x12\x19\n\x08field_id\x18\x01\x20\x01(\tR\x07fieldId\"7\n\
     \x12RepeatedFieldOrder\x12!\n\x05items\x18\x01\x20\x03(\x0b2\x0b.FieldOr\
-    derR\x05items\"!\n\x08RowOrder\x12\x15\n\x06row_id\x18\x01\x20\x01(\tR\
-    \x05rowId\"3\n\x10RepeatedRowOrder\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\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\x03key\x18\
-    \x01\x20\x01(\tR\x03key\x12\x1b\n\x05value\x18\x02\x20\x01(\x0b2\x05.Cel\
-    lR\x05value:\x028\x01\")\n\x0bRepeatedRow\x12\x1a\n\x05items\x18\x01\x20\
-    \x03(\x0b2\x04.RowR\x05items\"K\n\x04Cell\x12\x0e\n\x02id\x18\x01\x20\
-    \x01(\tR\x02id\x12\x19\n\x08field_id\x18\x02\x20\x01(\tR\x07fieldId\x12\
-    \x18\n\x07content\x18\x03\x20\x01(\tR\x07content\"'\n\x11CreateGridPaylo\
+    derR\x05items\"<\n\x08RowOrder\x12\x15\n\x06row_id\x18\x01\x20\x01(\tR\
+    \x05rowId\x12\x19\n\x08block_id\x18\x02\x20\x01(\tR\x07blockId\"3\n\x10R\
+    epeatedRowOrder\x12\x1f\n\x05items\x18\x01\x20\x03(\x0b2\t.RowOrderR\x05\
+    items\"\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\x03key\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\x05ite\
+    ms\";\n\x04Cell\x12\x19\n\x08field_id\x18\x01\x20\x01(\tR\x07fieldId\x12\
+    \x18\n\x07content\x18\x02\x20\x01(\tR\x07content\"'\n\x11CreateGridPaylo\
     ad\x12\x12\n\x04name\x18\x01\x20\x01(\tR\x04name\"\x1e\n\x06GridId\x12\
     \x14\n\x05value\x18\x01\x20\x01(\tR\x05value\"d\n\x11QueryFieldPayload\
     \x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x126\n\x0cfield_orde\

+ 26 - 162
shared-lib/flowy-grid-data-model/src/protobuf/model/meta.rs

@@ -2758,11 +2758,8 @@ impl ::protobuf::reflect::ProtobufValue for RowMetaChangeset {
 #[derive(PartialEq,Clone,Default)]
 pub struct CellMeta {
     // message fields
-    pub id: ::std::string::String,
-    pub row_id: ::std::string::String,
     pub field_id: ::std::string::String,
-    pub data: ::protobuf::SingularPtrField<AnyData>,
-    pub height: i32,
+    pub data: ::std::string::String,
     // special fields
     pub unknown_fields: ::protobuf::UnknownFields,
     pub cached_size: ::protobuf::CachedSize,
@@ -2779,59 +2776,7 @@ impl CellMeta {
         ::std::default::Default::default()
     }
 
-    // string id = 1;
-
-
-    pub fn get_id(&self) -> &str {
-        &self.id
-    }
-    pub fn clear_id(&mut self) {
-        self.id.clear();
-    }
-
-    // Param is passed by value, moved
-    pub fn set_id(&mut self, v: ::std::string::String) {
-        self.id = v;
-    }
-
-    // Mutable pointer to the field.
-    // If field is not initialized, it is initialized with default value first.
-    pub fn mut_id(&mut self) -> &mut ::std::string::String {
-        &mut self.id
-    }
-
-    // Take field
-    pub fn take_id(&mut self) -> ::std::string::String {
-        ::std::mem::replace(&mut self.id, ::std::string::String::new())
-    }
-
-    // string row_id = 2;
-
-
-    pub fn get_row_id(&self) -> &str {
-        &self.row_id
-    }
-    pub fn clear_row_id(&mut self) {
-        self.row_id.clear();
-    }
-
-    // Param is passed by value, moved
-    pub fn set_row_id(&mut self, v: ::std::string::String) {
-        self.row_id = v;
-    }
-
-    // Mutable pointer to the field.
-    // If field is not initialized, it is initialized with default value first.
-    pub fn mut_row_id(&mut self) -> &mut ::std::string::String {
-        &mut self.row_id
-    }
-
-    // Take field
-    pub fn take_row_id(&mut self) -> ::std::string::String {
-        ::std::mem::replace(&mut self.row_id, ::std::string::String::new())
-    }
-
-    // string field_id = 3;
+    // string field_id = 1;
 
 
     pub fn get_field_id(&self) -> &str {
@@ -2857,62 +2802,35 @@ impl CellMeta {
         ::std::mem::replace(&mut self.field_id, ::std::string::String::new())
     }
 
-    // .AnyData data = 4;
+    // string data = 2;
 
 
-    pub fn get_data(&self) -> &AnyData {
-        self.data.as_ref().unwrap_or_else(|| <AnyData as ::protobuf::Message>::default_instance())
+    pub fn get_data(&self) -> &str {
+        &self.data
     }
     pub fn clear_data(&mut self) {
         self.data.clear();
     }
 
-    pub fn has_data(&self) -> bool {
-        self.data.is_some()
-    }
-
     // Param is passed by value, moved
-    pub fn set_data(&mut self, v: AnyData) {
-        self.data = ::protobuf::SingularPtrField::some(v);
+    pub fn set_data(&mut self, v: ::std::string::String) {
+        self.data = v;
     }
 
     // Mutable pointer to the field.
     // If field is not initialized, it is initialized with default value first.
-    pub fn mut_data(&mut self) -> &mut AnyData {
-        if self.data.is_none() {
-            self.data.set_default();
-        }
-        self.data.as_mut().unwrap()
+    pub fn mut_data(&mut self) -> &mut ::std::string::String {
+        &mut self.data
     }
 
     // Take field
-    pub fn take_data(&mut self) -> AnyData {
-        self.data.take().unwrap_or_else(|| AnyData::new())
-    }
-
-    // int32 height = 5;
-
-
-    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;
+    pub fn take_data(&mut self) -> ::std::string::String {
+        ::std::mem::replace(&mut self.data, ::std::string::String::new())
     }
 }
 
 impl ::protobuf::Message for CellMeta {
     fn is_initialized(&self) -> bool {
-        for v in &self.data {
-            if !v.is_initialized() {
-                return false;
-            }
-        };
         true
     }
 
@@ -2921,23 +2839,10 @@ impl ::protobuf::Message for CellMeta {
             let (field_number, wire_type) = is.read_tag_unpack()?;
             match field_number {
                 1 => {
-                    ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.id)?;
-                },
-                2 => {
-                    ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.row_id)?;
-                },
-                3 => {
                     ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.field_id)?;
                 },
-                4 => {
-                    ::protobuf::rt::read_singular_message_into(wire_type, is, &mut self.data)?;
-                },
-                5 => {
-                    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;
+                2 => {
+                    ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.data)?;
                 },
                 _ => {
                     ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
@@ -2951,21 +2856,11 @@ impl ::protobuf::Message for CellMeta {
     #[allow(unused_variables)]
     fn compute_size(&self) -> u32 {
         let mut my_size = 0;
-        if !self.id.is_empty() {
-            my_size += ::protobuf::rt::string_size(1, &self.id);
-        }
-        if !self.row_id.is_empty() {
-            my_size += ::protobuf::rt::string_size(2, &self.row_id);
-        }
         if !self.field_id.is_empty() {
-            my_size += ::protobuf::rt::string_size(3, &self.field_id);
-        }
-        if let Some(ref v) = self.data.as_ref() {
-            let len = v.compute_size();
-            my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len;
+            my_size += ::protobuf::rt::string_size(1, &self.field_id);
         }
-        if self.height != 0 {
-            my_size += ::protobuf::rt::value_size(5, self.height, ::protobuf::wire_format::WireTypeVarint);
+        if !self.data.is_empty() {
+            my_size += ::protobuf::rt::string_size(2, &self.data);
         }
         my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
         self.cached_size.set(my_size);
@@ -2973,22 +2868,11 @@ impl ::protobuf::Message for CellMeta {
     }
 
     fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> {
-        if !self.id.is_empty() {
-            os.write_string(1, &self.id)?;
-        }
-        if !self.row_id.is_empty() {
-            os.write_string(2, &self.row_id)?;
-        }
         if !self.field_id.is_empty() {
-            os.write_string(3, &self.field_id)?;
-        }
-        if let Some(ref v) = self.data.as_ref() {
-            os.write_tag(4, ::protobuf::wire_format::WireTypeLengthDelimited)?;
-            os.write_raw_varint32(v.get_cached_size())?;
-            v.write_to_with_cached_sizes(os)?;
+            os.write_string(1, &self.field_id)?;
         }
-        if self.height != 0 {
-            os.write_int32(5, self.height)?;
+        if !self.data.is_empty() {
+            os.write_string(2, &self.data)?;
         }
         os.write_unknown_fields(self.get_unknown_fields())?;
         ::std::result::Result::Ok(())
@@ -3028,31 +2912,16 @@ impl ::protobuf::Message for CellMeta {
         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_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
-                "id",
-                |m: &CellMeta| { &m.id },
-                |m: &mut CellMeta| { &mut m.id },
-            ));
-            fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
-                "row_id",
-                |m: &CellMeta| { &m.row_id },
-                |m: &mut CellMeta| { &mut m.row_id },
-            ));
             fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
                 "field_id",
                 |m: &CellMeta| { &m.field_id },
                 |m: &mut CellMeta| { &mut m.field_id },
             ));
-            fields.push(::protobuf::reflect::accessor::make_singular_ptr_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage<AnyData>>(
+            fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
                 "data",
                 |m: &CellMeta| { &m.data },
                 |m: &mut CellMeta| { &mut m.data },
             ));
-            fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeInt32>(
-                "height",
-                |m: &CellMeta| { &m.height },
-                |m: &mut CellMeta| { &mut m.height },
-            ));
             ::protobuf::reflect::MessageDescriptor::new_pb_name::<CellMeta>(
                 "CellMeta",
                 fields,
@@ -3069,11 +2938,8 @@ impl ::protobuf::Message for CellMeta {
 
 impl ::protobuf::Clear for CellMeta {
     fn clear(&mut self) {
-        self.id.clear();
-        self.row_id.clear();
         self.field_id.clear();
         self.data.clear();
-        self.height = 0;
         self.unknown_fields.clear();
     }
 }
@@ -3191,14 +3057,12 @@ static file_descriptor_proto_data: &'static [u8] = b"\
     field_id\x18\x04\x20\x03(\x0b2$.RowMetaChangeset.CellByFieldIdEntryR\rce\
     llByFieldId\x1aK\n\x12CellByFieldIdEntry\x12\x10\n\x03key\x18\x01\x20\
     \x01(\tR\x03key\x12\x1f\n\x05value\x18\x02\x20\x01(\x0b2\t.CellMetaR\x05\
-    value:\x028\x01B\x0f\n\rone_of_heightB\x13\n\x11one_of_visibility\"\x82\
-    \x01\n\x08CellMeta\x12\x0e\n\x02id\x18\x01\x20\x01(\tR\x02id\x12\x15\n\
-    \x06row_id\x18\x02\x20\x01(\tR\x05rowId\x12\x19\n\x08field_id\x18\x03\
-    \x20\x01(\tR\x07fieldId\x12\x1c\n\x04data\x18\x04\x20\x01(\x0b2\x08.AnyD\
-    ataR\x04data\x12\x16\n\x06height\x18\x05\x20\x01(\x05R\x06height*d\n\tFi\
-    eldType\x12\x0c\n\x08RichText\x10\0\x12\n\n\x06Number\x10\x01\x12\x0c\n\
-    \x08DateTime\x10\x02\x12\x10\n\x0cSingleSelect\x10\x03\x12\x0f\n\x0bMult\
-    iSelect\x10\x04\x12\x0c\n\x08Checkbox\x10\x05b\x06proto3\
+    value:\x028\x01B\x0f\n\rone_of_heightB\x13\n\x11one_of_visibility\"9\n\
+    \x08CellMeta\x12\x19\n\x08field_id\x18\x01\x20\x01(\tR\x07fieldId\x12\
+    \x12\n\x04data\x18\x02\x20\x01(\tR\x04data*d\n\tFieldType\x12\x0c\n\x08R\
+    ichText\x10\0\x12\n\n\x06Number\x10\x01\x12\x0c\n\x08DateTime\x10\x02\
+    \x12\x10\n\x0cSingleSelect\x10\x03\x12\x0f\n\x0bMultiSelect\x10\x04\x12\
+    \x0c\n\x08Checkbox\x10\x05b\x06proto3\
 ";
 
 static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;

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

@@ -13,6 +13,7 @@ message RepeatedFieldOrder {
 }
 message RowOrder {
     string row_id = 1;
+    string block_id = 2;
 }
 message RepeatedRowOrder {
     repeated RowOrder items = 1;
@@ -26,9 +27,8 @@ message RepeatedRow {
     repeated Row items = 1;
 }
 message Cell {
-    string id = 1;
-    string field_id = 2;
-    string content = 3;
+    string field_id = 1;
+    string content = 2;
 }
 message CreateGridPayload {
     string name = 1;

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

@@ -55,11 +55,8 @@ message RowMetaChangeset {
     map<string, CellMeta> cell_by_field_id = 4;
 }
 message CellMeta {
-    string id = 1;
-    string row_id = 2;
-    string field_id = 3;
-    AnyData data = 4;
-    int32 height = 5;
+    string field_id = 1;
+    string data = 2;
 }
 enum FieldType {
     RichText = 0;