ソースを参照

chore: fix deserialize GridBlockMetaPad error

appflowy 3 年 前
コミット
420b8ca05d
22 ファイル変更605 行追加231 行削除
  1. 10 3
      frontend/app_flowy/lib/workspace/application/grid/grid_bloc.dart
  2. 0 92
      frontend/app_flowy/lib/workspace/application/grid/grid_block_service.dart
  3. 4 3
      frontend/app_flowy/lib/workspace/application/grid/grid_listener.dart
  4. 71 0
      frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pb.dart
  5. 13 0
      frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pbjson.dart
  6. 9 9
      frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/meta.pb.dart
  7. 2 2
      frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/meta.pbjson.dart
  8. 2 2
      frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/dart_notification.pbenum.dart
  9. 2 2
      frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/dart_notification.pbjson.dart
  10. 1 1
      frontend/rust-lib/flowy-grid/src/dart_notification.rs
  11. 3 2
      frontend/rust-lib/flowy-grid/src/manager.rs
  12. 8 8
      frontend/rust-lib/flowy-grid/src/protobuf/model/dart_notification.rs
  13. 1 1
      frontend/rust-lib/flowy-grid/src/protobuf/proto/dart_notification.proto
  14. 30 11
      frontend/rust-lib/flowy-grid/src/services/block_meta_manager.rs
  15. 44 0
      shared-lib/flowy-grid-data-model/src/entities/grid.rs
  16. 6 6
      shared-lib/flowy-grid-data-model/src/entities/meta.rs
  17. 334 24
      shared-lib/flowy-grid-data-model/src/protobuf/model/grid.rs
  18. 31 32
      shared-lib/flowy-grid-data-model/src/protobuf/model/meta.rs
  19. 6 0
      shared-lib/flowy-grid-data-model/src/protobuf/proto/grid.proto
  20. 1 1
      shared-lib/flowy-grid-data-model/src/protobuf/proto/meta.proto
  21. 24 29
      shared-lib/flowy-sync/src/client_grid/grid_block_meta_pad.rs
  22. 3 3
      shared-lib/flowy-sync/src/client_grid/grid_builder.rs

+ 10 - 3
frontend/app_flowy/lib/workspace/application/grid/grid_bloc.dart

@@ -7,7 +7,6 @@ import 'package:flowy_sdk/protobuf/flowy-folder-data-model/view.pb.dart';
 import 'package:flowy_sdk/protobuf/flowy-grid-data-model/protobuf.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
 import 'package:freezed_annotation/freezed_annotation.dart';
-import 'grid_block_service.dart';
 import 'field/grid_listenr.dart';
 import 'grid_listener.dart';
 import 'grid_service.dart';
@@ -70,8 +69,16 @@ class GridBloc extends Bloc<GridEvent, GridState> {
 
   void _startListening() {
     _gridListener.rowsUpdateNotifier.addPublishListener((result) {
-      result.fold((blockOrders) {
-        add(GridEvent.didReceiveRowUpdate(_buildRows(blockOrders)));
+      result.fold((gridBlockChangeset) {
+        for (final changeset in gridBlockChangeset) {
+          if (changeset.insertedRows.isNotEmpty) {}
+
+          if (changeset.deletedRows.isNotEmpty) {}
+
+          if (changeset.updatedRows.isNotEmpty) {}
+        }
+
+        // add(GridEvent.didReceiveRowUpdate(_buildRows(blockOrders)));
       }, (err) => Log.error(err));
     });
     _gridListener.start();

+ 0 - 92
frontend/app_flowy/lib/workspace/application/grid/grid_block_service.dart

@@ -1,92 +0,0 @@
-import 'dart:collection';
-import 'package:dartz/dartz.dart';
-import 'package:flowy_sdk/dispatch/dispatch.dart';
-import 'package:flowy_sdk/log.dart';
-import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
-import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
-import 'package:flowy_sdk/protobuf/flowy-grid/dart_notification.pb.dart';
-import 'package:flowy_infra/notifier.dart';
-import 'dart:async';
-import 'dart:typed_data';
-import 'package:app_flowy/core/notification_helper.dart';
-
-typedef GridBlockMap = LinkedHashMap<String, GridBlock>;
-typedef BlocksUpdateNotifierValue = Either<GridBlockMap, FlowyError>;
-
-class GridBlockService {
-  String gridId;
-  GridBlockMap blockMap = GridBlockMap();
-  late GridBlockListener _blockListener;
-  PublishNotifier<BlocksUpdateNotifierValue>? blocksUpdateNotifier = PublishNotifier();
-
-  GridBlockService({required this.gridId, required List<GridBlockOrder> blockOrders}) {
-    _loadGridBlocks(blockOrders);
-
-    _blockListener = GridBlockListener(gridId: gridId);
-    _blockListener.blockUpdateNotifier.addPublishListener((result) {
-      result.fold(
-        (blockOrder) => _loadGridBlocks(blockOrder),
-        (err) => Log.error(err),
-      );
-    });
-    _blockListener.start();
-  }
-
-  Future<void> stop() async {
-    await _blockListener.stop();
-    blocksUpdateNotifier?.dispose();
-    blocksUpdateNotifier = null;
-  }
-
-  void _loadGridBlocks(List<GridBlockOrder> blockOrders) {
-    final payload = QueryGridBlocksPayload.create()
-      ..gridId = gridId
-      ..blockOrders.addAll(blockOrders);
-
-    GridEventGetGridBlocks(payload).send().then((result) {
-      result.fold(
-        (repeatedBlocks) {
-          for (final gridBlock in repeatedBlocks.items) {
-            blockMap[gridBlock.id] = gridBlock;
-          }
-          blocksUpdateNotifier?.value = left(blockMap);
-        },
-        (err) => blocksUpdateNotifier?.value = right(err),
-      );
-    });
-  }
-}
-
-class GridBlockListener {
-  final String gridId;
-  PublishNotifier<Either<List<GridBlockOrder>, FlowyError>> blockUpdateNotifier = PublishNotifier(comparable: null);
-  GridNotificationListener? _listener;
-
-  GridBlockListener({required this.gridId});
-
-  void start() {
-    _listener = GridNotificationListener(
-      objectId: gridId,
-      handler: _handler,
-    );
-  }
-
-  void _handler(GridNotification ty, Either<Uint8List, FlowyError> result) {
-    switch (ty) {
-      case GridNotification.DidUpdateBlock:
-        result.fold(
-          (payload) => blockUpdateNotifier.value = left([GridBlockOrder.fromBuffer(payload)]),
-          (error) => blockUpdateNotifier.value = right(error),
-        );
-        break;
-
-      default:
-        break;
-    }
-  }
-
-  Future<void> stop() async {
-    await _listener?.stop();
-    blockUpdateNotifier.dispose();
-  }
-}

+ 4 - 3
frontend/app_flowy/lib/workspace/application/grid/grid_listener.dart

@@ -9,7 +9,8 @@ import 'package:app_flowy/core/notification_helper.dart';
 
 class GridListener {
   final String gridId;
-  PublishNotifier<Either<List<GridBlockOrder>, FlowyError>> rowsUpdateNotifier = PublishNotifier(comparable: null);
+  PublishNotifier<Either<List<GridBlockOrderChangeset>, FlowyError>> rowsUpdateNotifier =
+      PublishNotifier(comparable: null);
   GridNotificationListener? _listener;
 
   GridListener({required this.gridId});
@@ -23,9 +24,9 @@ class GridListener {
 
   void _handler(GridNotification ty, Either<Uint8List, FlowyError> result) {
     switch (ty) {
-      case GridNotification.DidUpdateBlock:
+      case GridNotification.DidUpdateGridBlock:
         result.fold(
-          (payload) => rowsUpdateNotifier.value = left([GridBlockOrder.fromBuffer(payload)]),
+          (payload) => rowsUpdateNotifier.value = left([GridBlockOrderChangeset.fromBuffer(payload)]),
           (error) => rowsUpdateNotifier.value = right(error),
         );
         break;

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

@@ -855,6 +855,77 @@ class GridBlockOrder extends $pb.GeneratedMessage {
   $core.List<RowOrder> get rowOrders => $_getList(1);
 }
 
+class GridBlockOrderChangeset extends $pb.GeneratedMessage {
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'GridBlockOrderChangeset', createEmptyInstance: create)
+    ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'blockId')
+    ..pc<RowOrder>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'insertedRows', $pb.PbFieldType.PM, subBuilder: RowOrder.create)
+    ..pc<RowOrder>(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'deletedRows', $pb.PbFieldType.PM, subBuilder: RowOrder.create)
+    ..pc<RowOrder>(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'updatedRows', $pb.PbFieldType.PM, subBuilder: RowOrder.create)
+    ..hasRequiredFields = false
+  ;
+
+  GridBlockOrderChangeset._() : super();
+  factory GridBlockOrderChangeset({
+    $core.String? blockId,
+    $core.Iterable<RowOrder>? insertedRows,
+    $core.Iterable<RowOrder>? deletedRows,
+    $core.Iterable<RowOrder>? updatedRows,
+  }) {
+    final _result = create();
+    if (blockId != null) {
+      _result.blockId = blockId;
+    }
+    if (insertedRows != null) {
+      _result.insertedRows.addAll(insertedRows);
+    }
+    if (deletedRows != null) {
+      _result.deletedRows.addAll(deletedRows);
+    }
+    if (updatedRows != null) {
+      _result.updatedRows.addAll(updatedRows);
+    }
+    return _result;
+  }
+  factory GridBlockOrderChangeset.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory GridBlockOrderChangeset.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')
+  GridBlockOrderChangeset clone() => GridBlockOrderChangeset()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  GridBlockOrderChangeset copyWith(void Function(GridBlockOrderChangeset) updates) => super.copyWith((message) => updates(message as GridBlockOrderChangeset)) as GridBlockOrderChangeset; // ignore: deprecated_member_use
+  $pb.BuilderInfo get info_ => _i;
+  @$core.pragma('dart2js:noInline')
+  static GridBlockOrderChangeset create() => GridBlockOrderChangeset._();
+  GridBlockOrderChangeset createEmptyInstance() => create();
+  static $pb.PbList<GridBlockOrderChangeset> createRepeated() => $pb.PbList<GridBlockOrderChangeset>();
+  @$core.pragma('dart2js:noInline')
+  static GridBlockOrderChangeset getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<GridBlockOrderChangeset>(create);
+  static GridBlockOrderChangeset? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $core.String get blockId => $_getSZ(0);
+  @$pb.TagNumber(1)
+  set blockId($core.String v) { $_setString(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasBlockId() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearBlockId() => clearField(1);
+
+  @$pb.TagNumber(2)
+  $core.List<RowOrder> get insertedRows => $_getList(1);
+
+  @$pb.TagNumber(3)
+  $core.List<RowOrder> get deletedRows => $_getList(2);
+
+  @$pb.TagNumber(4)
+  $core.List<RowOrder> get updatedRows => $_getList(3);
+}
+
 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') ? '' : 'id')

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

@@ -171,6 +171,19 @@ const GridBlockOrder$json = const {
 
 /// Descriptor for `GridBlockOrder`. Decode as a `google.protobuf.DescriptorProto`.
 final $typed_data.Uint8List gridBlockOrderDescriptor = $convert.base64Decode('Cg5HcmlkQmxvY2tPcmRlchIZCghibG9ja19pZBgBIAEoCVIHYmxvY2tJZBIoCgpyb3dfb3JkZXJzGAIgAygLMgkuUm93T3JkZXJSCXJvd09yZGVycw==');
+@$core.Deprecated('Use gridBlockOrderChangesetDescriptor instead')
+const GridBlockOrderChangeset$json = const {
+  '1': 'GridBlockOrderChangeset',
+  '2': const [
+    const {'1': 'block_id', '3': 1, '4': 1, '5': 9, '10': 'blockId'},
+    const {'1': 'inserted_rows', '3': 2, '4': 3, '5': 11, '6': '.RowOrder', '10': 'insertedRows'},
+    const {'1': 'deleted_rows', '3': 3, '4': 3, '5': 11, '6': '.RowOrder', '10': 'deletedRows'},
+    const {'1': 'updated_rows', '3': 4, '4': 3, '5': 11, '6': '.RowOrder', '10': 'updatedRows'},
+  ],
+};
+
+/// Descriptor for `GridBlockOrderChangeset`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List gridBlockOrderChangesetDescriptor = $convert.base64Decode('ChdHcmlkQmxvY2tPcmRlckNoYW5nZXNldBIZCghibG9ja19pZBgBIAEoCVIHYmxvY2tJZBIuCg1pbnNlcnRlZF9yb3dzGAIgAygLMgkuUm93T3JkZXJSDGluc2VydGVkUm93cxIsCgxkZWxldGVkX3Jvd3MYAyADKAsyCS5Sb3dPcmRlclILZGVsZXRlZFJvd3MSLAoMdXBkYXRlZF9yb3dzGAQgAygLMgkuUm93T3JkZXJSC3VwZGF0ZWRSb3dz');
 @$core.Deprecated('Use gridBlockDescriptor instead')
 const GridBlock$json = const {
   '1': 'GridBlock',

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

@@ -1014,7 +1014,7 @@ class CellMetaChangeset extends $pb.GeneratedMessage {
 class BuildGridContext extends $pb.GeneratedMessage {
   static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'BuildGridContext', createEmptyInstance: create)
     ..pc<FieldMeta>(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'fieldMetas', $pb.PbFieldType.PM, subBuilder: FieldMeta.create)
-    ..aOM<GridBlockMeta>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'blockMetas', subBuilder: GridBlockMeta.create)
+    ..aOM<GridBlockMeta>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'blockMeta', subBuilder: GridBlockMeta.create)
     ..aOM<GridBlockMetaData>(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'blockMetaData', subBuilder: GridBlockMetaData.create)
     ..hasRequiredFields = false
   ;
@@ -1022,15 +1022,15 @@ class BuildGridContext extends $pb.GeneratedMessage {
   BuildGridContext._() : super();
   factory BuildGridContext({
     $core.Iterable<FieldMeta>? fieldMetas,
-    GridBlockMeta? blockMetas,
+    GridBlockMeta? blockMeta,
     GridBlockMetaData? blockMetaData,
   }) {
     final _result = create();
     if (fieldMetas != null) {
       _result.fieldMetas.addAll(fieldMetas);
     }
-    if (blockMetas != null) {
-      _result.blockMetas = blockMetas;
+    if (blockMeta != null) {
+      _result.blockMeta = blockMeta;
     }
     if (blockMetaData != null) {
       _result.blockMetaData = blockMetaData;
@@ -1062,15 +1062,15 @@ class BuildGridContext extends $pb.GeneratedMessage {
   $core.List<FieldMeta> get fieldMetas => $_getList(0);
 
   @$pb.TagNumber(2)
-  GridBlockMeta get blockMetas => $_getN(1);
+  GridBlockMeta get blockMeta => $_getN(1);
   @$pb.TagNumber(2)
-  set blockMetas(GridBlockMeta v) { setField(2, v); }
+  set blockMeta(GridBlockMeta v) { setField(2, v); }
   @$pb.TagNumber(2)
-  $core.bool hasBlockMetas() => $_has(1);
+  $core.bool hasBlockMeta() => $_has(1);
   @$pb.TagNumber(2)
-  void clearBlockMetas() => clearField(2);
+  void clearBlockMeta() => clearField(2);
   @$pb.TagNumber(2)
-  GridBlockMeta ensureBlockMetas() => $_ensure(1);
+  GridBlockMeta ensureBlockMeta() => $_ensure(1);
 
   @$pb.TagNumber(3)
   GridBlockMetaData get blockMetaData => $_getN(2);

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

@@ -208,10 +208,10 @@ const BuildGridContext$json = const {
   '1': 'BuildGridContext',
   '2': const [
     const {'1': 'field_metas', '3': 1, '4': 3, '5': 11, '6': '.FieldMeta', '10': 'fieldMetas'},
-    const {'1': 'block_metas', '3': 2, '4': 1, '5': 11, '6': '.GridBlockMeta', '10': 'blockMetas'},
+    const {'1': 'block_meta', '3': 2, '4': 1, '5': 11, '6': '.GridBlockMeta', '10': 'blockMeta'},
     const {'1': 'block_meta_data', '3': 3, '4': 1, '5': 11, '6': '.GridBlockMetaData', '10': 'blockMetaData'},
   ],
 };
 
 /// Descriptor for `BuildGridContext`. Decode as a `google.protobuf.DescriptorProto`.
-final $typed_data.Uint8List buildGridContextDescriptor = $convert.base64Decode('ChBCdWlsZEdyaWRDb250ZXh0EisKC2ZpZWxkX21ldGFzGAEgAygLMgouRmllbGRNZXRhUgpmaWVsZE1ldGFzEi8KC2Jsb2NrX21ldGFzGAIgASgLMg4uR3JpZEJsb2NrTWV0YVIKYmxvY2tNZXRhcxI6Cg9ibG9ja19tZXRhX2RhdGEYAyABKAsyEi5HcmlkQmxvY2tNZXRhRGF0YVINYmxvY2tNZXRhRGF0YQ==');
+final $typed_data.Uint8List buildGridContextDescriptor = $convert.base64Decode('ChBCdWlsZEdyaWRDb250ZXh0EisKC2ZpZWxkX21ldGFzGAEgAygLMgouRmllbGRNZXRhUgpmaWVsZE1ldGFzEi0KCmJsb2NrX21ldGEYAiABKAsyDi5HcmlkQmxvY2tNZXRhUglibG9ja01ldGESOgoPYmxvY2tfbWV0YV9kYXRhGAMgASgLMhIuR3JpZEJsb2NrTWV0YURhdGFSDWJsb2NrTWV0YURhdGE=');

+ 2 - 2
frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/dart_notification.pbenum.dart

@@ -12,7 +12,7 @@ import 'package:protobuf/protobuf.dart' as $pb;
 class GridNotification extends $pb.ProtobufEnum {
   static const GridNotification Unknown = GridNotification._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Unknown');
   static const GridNotification DidCreateBlock = GridNotification._(11, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DidCreateBlock');
-  static const GridNotification DidUpdateBlock = GridNotification._(20, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DidUpdateBlock');
+  static const GridNotification DidUpdateGridBlock = GridNotification._(20, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DidUpdateGridBlock');
   static const GridNotification DidUpdateRow = GridNotification._(30, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DidUpdateRow');
   static const GridNotification DidUpdateCell = GridNotification._(31, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DidUpdateCell');
   static const GridNotification DidUpdateGrid = GridNotification._(40, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DidUpdateGrid');
@@ -21,7 +21,7 @@ class GridNotification extends $pb.ProtobufEnum {
   static const $core.List<GridNotification> values = <GridNotification> [
     Unknown,
     DidCreateBlock,
-    DidUpdateBlock,
+    DidUpdateGridBlock,
     DidUpdateRow,
     DidUpdateCell,
     DidUpdateGrid,

+ 2 - 2
frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/dart_notification.pbjson.dart

@@ -14,7 +14,7 @@ const GridNotification$json = const {
   '2': const [
     const {'1': 'Unknown', '2': 0},
     const {'1': 'DidCreateBlock', '2': 11},
-    const {'1': 'DidUpdateBlock', '2': 20},
+    const {'1': 'DidUpdateGridBlock', '2': 20},
     const {'1': 'DidUpdateRow', '2': 30},
     const {'1': 'DidUpdateCell', '2': 31},
     const {'1': 'DidUpdateGrid', '2': 40},
@@ -23,4 +23,4 @@ const GridNotification$json = const {
 };
 
 /// Descriptor for `GridNotification`. Decode as a `google.protobuf.EnumDescriptorProto`.
-final $typed_data.Uint8List gridNotificationDescriptor = $convert.base64Decode('ChBHcmlkTm90aWZpY2F0aW9uEgsKB1Vua25vd24QABISCg5EaWRDcmVhdGVCbG9jaxALEhIKDkRpZFVwZGF0ZUJsb2NrEBQSEAoMRGlkVXBkYXRlUm93EB4SEQoNRGlkVXBkYXRlQ2VsbBAfEhEKDURpZFVwZGF0ZUdyaWQQKBISCg5EaWRVcGRhdGVGaWVsZBAp');
+final $typed_data.Uint8List gridNotificationDescriptor = $convert.base64Decode('ChBHcmlkTm90aWZpY2F0aW9uEgsKB1Vua25vd24QABISCg5EaWRDcmVhdGVCbG9jaxALEhYKEkRpZFVwZGF0ZUdyaWRCbG9jaxAUEhAKDERpZFVwZGF0ZVJvdxAeEhEKDURpZFVwZGF0ZUNlbGwQHxIRCg1EaWRVcGRhdGVHcmlkECgSEgoORGlkVXBkYXRlRmllbGQQKQ==');

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

@@ -6,7 +6,7 @@ const OBSERVABLE_CATEGORY: &str = "Grid";
 pub enum GridNotification {
     Unknown = 0,
     DidCreateBlock = 11,
-    DidUpdateBlock = 20,
+    DidUpdateGridBlock = 20,
     DidUpdateRow = 30,
     DidUpdateCell = 31,
     DidUpdateGrid = 40,

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

@@ -110,6 +110,7 @@ impl GridManager {
         }
     }
 
+    #[tracing::instrument(level = "trace", skip(self, pool), err)]
     async fn make_grid_editor(
         &self,
         grid_id: &str,
@@ -175,11 +176,11 @@ pub async fn make_grid_view_data(
     grid_manager: Arc<GridManager>,
     build_context: BuildGridContext,
 ) -> FlowyResult<Bytes> {
-    let block_id = build_context.block_metas.block_id.clone();
+    let block_id = build_context.block_meta.block_id.clone();
     let grid_meta = GridMeta {
         grid_id: view_id.to_string(),
         fields: build_context.field_metas,
-        blocks: vec![build_context.block_metas],
+        blocks: vec![build_context.block_meta],
     };
 
     // Create grid

+ 8 - 8
frontend/rust-lib/flowy-grid/src/protobuf/model/dart_notification.rs

@@ -27,7 +27,7 @@
 pub enum GridNotification {
     Unknown = 0,
     DidCreateBlock = 11,
-    DidUpdateBlock = 20,
+    DidUpdateGridBlock = 20,
     DidUpdateRow = 30,
     DidUpdateCell = 31,
     DidUpdateGrid = 40,
@@ -43,7 +43,7 @@ impl ::protobuf::ProtobufEnum for GridNotification {
         match value {
             0 => ::std::option::Option::Some(GridNotification::Unknown),
             11 => ::std::option::Option::Some(GridNotification::DidCreateBlock),
-            20 => ::std::option::Option::Some(GridNotification::DidUpdateBlock),
+            20 => ::std::option::Option::Some(GridNotification::DidUpdateGridBlock),
             30 => ::std::option::Option::Some(GridNotification::DidUpdateRow),
             31 => ::std::option::Option::Some(GridNotification::DidUpdateCell),
             40 => ::std::option::Option::Some(GridNotification::DidUpdateGrid),
@@ -56,7 +56,7 @@ impl ::protobuf::ProtobufEnum for GridNotification {
         static values: &'static [GridNotification] = &[
             GridNotification::Unknown,
             GridNotification::DidCreateBlock,
-            GridNotification::DidUpdateBlock,
+            GridNotification::DidUpdateGridBlock,
             GridNotification::DidUpdateRow,
             GridNotification::DidUpdateCell,
             GridNotification::DidUpdateGrid,
@@ -89,11 +89,11 @@ impl ::protobuf::reflect::ProtobufValue for GridNotification {
 }
 
 static file_descriptor_proto_data: &'static [u8] = b"\
-    \n\x17dart_notification.proto*\x93\x01\n\x10GridNotification\x12\x0b\n\
-    \x07Unknown\x10\0\x12\x12\n\x0eDidCreateBlock\x10\x0b\x12\x12\n\x0eDidUp\
-    dateBlock\x10\x14\x12\x10\n\x0cDidUpdateRow\x10\x1e\x12\x11\n\rDidUpdate\
-    Cell\x10\x1f\x12\x11\n\rDidUpdateGrid\x10(\x12\x12\n\x0eDidUpdateField\
-    \x10)b\x06proto3\
+    \n\x17dart_notification.proto*\x97\x01\n\x10GridNotification\x12\x0b\n\
+    \x07Unknown\x10\0\x12\x12\n\x0eDidCreateBlock\x10\x0b\x12\x16\n\x12DidUp\
+    dateGridBlock\x10\x14\x12\x10\n\x0cDidUpdateRow\x10\x1e\x12\x11\n\rDidUp\
+    dateCell\x10\x1f\x12\x11\n\rDidUpdateGrid\x10(\x12\x12\n\x0eDidUpdateFie\
+    ld\x10)b\x06proto3\
 ";
 
 static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;

+ 1 - 1
frontend/rust-lib/flowy-grid/src/protobuf/proto/dart_notification.proto

@@ -3,7 +3,7 @@ syntax = "proto3";
 enum GridNotification {
     Unknown = 0;
     DidCreateBlock = 11;
-    DidUpdateBlock = 20;
+    DidUpdateGridBlock = 20;
     DidUpdateRow = 30;
     DidUpdateCell = 31;
     DidUpdateGrid = 40;

+ 30 - 11
frontend/rust-lib/flowy-grid/src/services/block_meta_manager.rs

@@ -9,7 +9,7 @@ use dashmap::DashMap;
 use flowy_error::FlowyResult;
 use flowy_grid_data_model::entities::{
     CellMeta, CellMetaChangeset, CellNotificationData, FieldMeta, GridBlockMeta, GridBlockMetaChangeset,
-    GridBlockOrder, RowMeta, RowMetaChangeset, RowOrder,
+    GridBlockOrder, GridBlockOrderChangeset, RowMeta, RowMetaChangeset, RowOrder,
 };
 use flowy_revision::disk::SQLiteGridBlockMetaRevisionPersistence;
 use flowy_revision::{RevisionManager, RevisionPersistence};
@@ -70,8 +70,12 @@ impl GridBlockMetaEditorManager {
     ) -> FlowyResult<i32> {
         let _ = self.persistence.insert_or_update(&row_meta.block_id, &row_meta.id)?;
         let editor = self.get_editor(&row_meta.block_id).await?;
+        let row_order = RowOrder::from(&row_meta);
         let row_count = editor.create_row(row_meta, start_row_id).await?;
-        self.notify_block_did_update_row(block_id).await?;
+
+        let _ = self
+            .notify_block_did_update_row(GridBlockOrderChangeset::from_update(block_id, vec![row_order]))
+            .await?;
         Ok(row_count)
     }
 
@@ -81,14 +85,18 @@ impl GridBlockMetaEditorManager {
     ) -> FlowyResult<Vec<GridBlockMetaChangeset>> {
         let mut changesets = vec![];
         for (block_id, row_metas) in rows_by_block_id {
+            let mut inserted_row_orders = vec![];
             let editor = self.get_editor(&block_id).await?;
             let mut row_count = 0;
-            for row in &row_metas {
+            for row in row_metas {
                 let _ = self.persistence.insert_or_update(&row.block_id, &row.id)?;
-                row_count = editor.create_row(row.clone(), None).await?;
+                inserted_row_orders.push(RowOrder::from(&row));
+                row_count = editor.create_row(row, None).await?;
             }
             changesets.push(GridBlockMetaChangeset::from_row_count(&block_id, row_count));
-            let _ = self.notify_block_did_update_row(&block_id).await?;
+            let _ = self
+                .notify_block_did_update_row(GridBlockOrderChangeset::from_insert(&block_id, inserted_row_orders))
+                .await?;
         }
 
         Ok(changesets)
@@ -97,7 +105,19 @@ impl GridBlockMetaEditorManager {
     pub async fn update_row(&self, changeset: RowMetaChangeset) -> FlowyResult<()> {
         let editor = self.get_editor_from_row_id(&changeset.row_id).await?;
         let _ = editor.update_row(changeset.clone()).await?;
-        let _ = self.notify_block_did_update_row(&editor.block_id).await?;
+
+        match editor
+            .get_row_orders(Some(vec![Cow::Borrowed(&changeset.row_id)]))
+            .await?
+            .pop()
+        {
+            None => {}
+            Some(row_order) => {
+                let block_order_changeset = GridBlockOrderChangeset::from_update(&editor.block_id, vec![row_order]);
+                let _ = self.notify_block_did_update_row(block_order_changeset).await?;
+            }
+        }
+
         Ok(())
     }
 
@@ -177,11 +197,10 @@ impl GridBlockMetaEditorManager {
         Ok(block_cell_metas)
     }
 
-    async fn notify_block_did_update_row(&self, block_id: &str) -> FlowyResult<()> {
-        // let block_order: GridBlockOrder = block_id.into();
-        // send_dart_notification(&self.grid_id, GridNotification::DidUpdateBlock)
-        //     .payload(block_order)
-        //     .send();
+    async fn notify_block_did_update_row(&self, changeset: GridBlockOrderChangeset) -> FlowyResult<()> {
+        send_dart_notification(&self.grid_id, GridNotification::DidUpdateGridBlock)
+            .payload(changeset)
+            .send();
         Ok(())
     }
 

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

@@ -274,6 +274,50 @@ impl GridBlockOrder {
     }
 }
 
+#[derive(Debug, Clone, Default, ProtoBuf)]
+pub struct GridBlockOrderChangeset {
+    #[pb(index = 1)]
+    pub block_id: String,
+
+    #[pb(index = 2)]
+    pub inserted_rows: Vec<RowOrder>,
+
+    #[pb(index = 3)]
+    pub deleted_rows: Vec<RowOrder>,
+
+    #[pb(index = 4)]
+    pub updated_rows: Vec<RowOrder>,
+}
+
+impl GridBlockOrderChangeset {
+    pub fn from_insert(block_id: &str, inserted_rows: Vec<RowOrder>) -> Self {
+        Self {
+            block_id: block_id.to_owned(),
+            inserted_rows,
+            deleted_rows: vec![],
+            updated_rows: vec![],
+        }
+    }
+
+    pub fn from_delete(block_id: &str, deleted_rows: Vec<RowOrder>) -> Self {
+        Self {
+            block_id: block_id.to_owned(),
+            inserted_rows: vec![],
+            deleted_rows,
+            updated_rows: vec![],
+        }
+    }
+
+    pub fn from_update(block_id: &str, updated_rows: Vec<RowOrder>) -> Self {
+        Self {
+            block_id: block_id.to_owned(),
+            inserted_rows: vec![],
+            deleted_rows: vec![],
+            updated_rows,
+        }
+    }
+}
+
 #[derive(Debug, Default, ProtoBuf)]
 pub struct GridBlock {
     #[pb(index = 1)]

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

@@ -409,7 +409,7 @@ pub struct BuildGridContext {
     pub field_metas: Vec<FieldMeta>,
 
     #[pb(index = 2)]
-    pub block_metas: GridBlockMeta,
+    pub block_meta: GridBlockMeta,
 
     #[pb(index = 3)]
     pub block_meta_data: GridBlockMetaData,
@@ -417,16 +417,16 @@ pub struct BuildGridContext {
 
 impl std::default::Default for BuildGridContext {
     fn default() -> Self {
-        let grid_block = GridBlockMeta::new();
-        let grid_block_meta_data = GridBlockMetaData {
-            block_id: grid_block.block_id.clone(),
+        let block_meta = GridBlockMeta::new();
+        let block_meta_data = GridBlockMetaData {
+            block_id: block_meta.block_id.clone(),
             rows: vec![],
         };
 
         Self {
             field_metas: vec![],
-            block_metas: grid_block,
-            block_meta_data: grid_block_meta_data,
+            block_meta,
+            block_meta_data,
         }
     }
 }

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

@@ -2919,6 +2919,312 @@ impl ::protobuf::reflect::ProtobufValue for GridBlockOrder {
     }
 }
 
+#[derive(PartialEq,Clone,Default)]
+pub struct GridBlockOrderChangeset {
+    // message fields
+    pub block_id: ::std::string::String,
+    pub inserted_rows: ::protobuf::RepeatedField<RowOrder>,
+    pub deleted_rows: ::protobuf::RepeatedField<RowOrder>,
+    pub updated_rows: ::protobuf::RepeatedField<RowOrder>,
+    // special fields
+    pub unknown_fields: ::protobuf::UnknownFields,
+    pub cached_size: ::protobuf::CachedSize,
+}
+
+impl<'a> ::std::default::Default for &'a GridBlockOrderChangeset {
+    fn default() -> &'a GridBlockOrderChangeset {
+        <GridBlockOrderChangeset as ::protobuf::Message>::default_instance()
+    }
+}
+
+impl GridBlockOrderChangeset {
+    pub fn new() -> GridBlockOrderChangeset {
+        ::std::default::Default::default()
+    }
+
+    // string block_id = 1;
+
+
+    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())
+    }
+
+    // repeated .RowOrder inserted_rows = 2;
+
+
+    pub fn get_inserted_rows(&self) -> &[RowOrder] {
+        &self.inserted_rows
+    }
+    pub fn clear_inserted_rows(&mut self) {
+        self.inserted_rows.clear();
+    }
+
+    // Param is passed by value, moved
+    pub fn set_inserted_rows(&mut self, v: ::protobuf::RepeatedField<RowOrder>) {
+        self.inserted_rows = v;
+    }
+
+    // Mutable pointer to the field.
+    pub fn mut_inserted_rows(&mut self) -> &mut ::protobuf::RepeatedField<RowOrder> {
+        &mut self.inserted_rows
+    }
+
+    // Take field
+    pub fn take_inserted_rows(&mut self) -> ::protobuf::RepeatedField<RowOrder> {
+        ::std::mem::replace(&mut self.inserted_rows, ::protobuf::RepeatedField::new())
+    }
+
+    // repeated .RowOrder deleted_rows = 3;
+
+
+    pub fn get_deleted_rows(&self) -> &[RowOrder] {
+        &self.deleted_rows
+    }
+    pub fn clear_deleted_rows(&mut self) {
+        self.deleted_rows.clear();
+    }
+
+    // Param is passed by value, moved
+    pub fn set_deleted_rows(&mut self, v: ::protobuf::RepeatedField<RowOrder>) {
+        self.deleted_rows = v;
+    }
+
+    // Mutable pointer to the field.
+    pub fn mut_deleted_rows(&mut self) -> &mut ::protobuf::RepeatedField<RowOrder> {
+        &mut self.deleted_rows
+    }
+
+    // Take field
+    pub fn take_deleted_rows(&mut self) -> ::protobuf::RepeatedField<RowOrder> {
+        ::std::mem::replace(&mut self.deleted_rows, ::protobuf::RepeatedField::new())
+    }
+
+    // repeated .RowOrder updated_rows = 4;
+
+
+    pub fn get_updated_rows(&self) -> &[RowOrder] {
+        &self.updated_rows
+    }
+    pub fn clear_updated_rows(&mut self) {
+        self.updated_rows.clear();
+    }
+
+    // Param is passed by value, moved
+    pub fn set_updated_rows(&mut self, v: ::protobuf::RepeatedField<RowOrder>) {
+        self.updated_rows = v;
+    }
+
+    // Mutable pointer to the field.
+    pub fn mut_updated_rows(&mut self) -> &mut ::protobuf::RepeatedField<RowOrder> {
+        &mut self.updated_rows
+    }
+
+    // Take field
+    pub fn take_updated_rows(&mut self) -> ::protobuf::RepeatedField<RowOrder> {
+        ::std::mem::replace(&mut self.updated_rows, ::protobuf::RepeatedField::new())
+    }
+}
+
+impl ::protobuf::Message for GridBlockOrderChangeset {
+    fn is_initialized(&self) -> bool {
+        for v in &self.inserted_rows {
+            if !v.is_initialized() {
+                return false;
+            }
+        };
+        for v in &self.deleted_rows {
+            if !v.is_initialized() {
+                return false;
+            }
+        };
+        for v in &self.updated_rows {
+            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_singular_proto3_string_into(wire_type, is, &mut self.block_id)?;
+                },
+                2 => {
+                    ::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.inserted_rows)?;
+                },
+                3 => {
+                    ::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.deleted_rows)?;
+                },
+                4 => {
+                    ::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.updated_rows)?;
+                },
+                _ => {
+                    ::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;
+        if !self.block_id.is_empty() {
+            my_size += ::protobuf::rt::string_size(1, &self.block_id);
+        }
+        for value in &self.inserted_rows {
+            let len = value.compute_size();
+            my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len;
+        };
+        for value in &self.deleted_rows {
+            let len = value.compute_size();
+            my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len;
+        };
+        for value in &self.updated_rows {
+            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<()> {
+        if !self.block_id.is_empty() {
+            os.write_string(1, &self.block_id)?;
+        }
+        for v in &self.inserted_rows {
+            os.write_tag(2, ::protobuf::wire_format::WireTypeLengthDelimited)?;
+            os.write_raw_varint32(v.get_cached_size())?;
+            v.write_to_with_cached_sizes(os)?;
+        };
+        for v in &self.deleted_rows {
+            os.write_tag(3, ::protobuf::wire_format::WireTypeLengthDelimited)?;
+            os.write_raw_varint32(v.get_cached_size())?;
+            v.write_to_with_cached_sizes(os)?;
+        };
+        for v in &self.updated_rows {
+            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_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() -> GridBlockOrderChangeset {
+        GridBlockOrderChangeset::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_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
+                "block_id",
+                |m: &GridBlockOrderChangeset| { &m.block_id },
+                |m: &mut GridBlockOrderChangeset| { &mut m.block_id },
+            ));
+            fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage<RowOrder>>(
+                "inserted_rows",
+                |m: &GridBlockOrderChangeset| { &m.inserted_rows },
+                |m: &mut GridBlockOrderChangeset| { &mut m.inserted_rows },
+            ));
+            fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage<RowOrder>>(
+                "deleted_rows",
+                |m: &GridBlockOrderChangeset| { &m.deleted_rows },
+                |m: &mut GridBlockOrderChangeset| { &mut m.deleted_rows },
+            ));
+            fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage<RowOrder>>(
+                "updated_rows",
+                |m: &GridBlockOrderChangeset| { &m.updated_rows },
+                |m: &mut GridBlockOrderChangeset| { &mut m.updated_rows },
+            ));
+            ::protobuf::reflect::MessageDescriptor::new_pb_name::<GridBlockOrderChangeset>(
+                "GridBlockOrderChangeset",
+                fields,
+                file_descriptor_proto()
+            )
+        })
+    }
+
+    fn default_instance() -> &'static GridBlockOrderChangeset {
+        static instance: ::protobuf::rt::LazyV2<GridBlockOrderChangeset> = ::protobuf::rt::LazyV2::INIT;
+        instance.get(GridBlockOrderChangeset::new)
+    }
+}
+
+impl ::protobuf::Clear for GridBlockOrderChangeset {
+    fn clear(&mut self) {
+        self.block_id.clear();
+        self.inserted_rows.clear();
+        self.deleted_rows.clear();
+        self.updated_rows.clear();
+        self.unknown_fields.clear();
+    }
+}
+
+impl ::std::fmt::Debug for GridBlockOrderChangeset {
+    fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
+        ::protobuf::text_format::fmt(self, f)
+    }
+}
+
+impl ::protobuf::reflect::ProtobufValue for GridBlockOrderChangeset {
+    fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
+        ::protobuf::reflect::ReflectValueRef::Message(self)
+    }
+}
+
 #[derive(PartialEq,Clone,Default)]
 pub struct GridBlock {
     // message fields
@@ -5334,30 +5640,34 @@ static file_descriptor_proto_data: &'static [u8] = b"\
     \x20\x03(\x0b2\x04.RowR\x05items\"5\n\x11RepeatedGridBlock\x12\x20\n\x05\
     items\x18\x01\x20\x03(\x0b2\n.GridBlockR\x05items\"U\n\x0eGridBlockOrder\
     \x12\x19\n\x08block_id\x18\x01\x20\x01(\tR\x07blockId\x12(\n\nrow_orders\
-    \x18\x02\x20\x03(\x0b2\t.RowOrderR\trowOrders\"E\n\tGridBlock\x12\x0e\n\
-    \x02id\x18\x01\x20\x01(\tR\x02id\x12(\n\nrow_orders\x18\x02\x20\x03(\x0b\
-    2\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\
-    \"\x8f\x01\n\x14CellNotificationData\x12\x17\n\x07grid_id\x18\x01\x20\
-    \x01(\tR\x06gridId\x12\x19\n\x08field_id\x18\x02\x20\x01(\tR\x07fieldId\
-    \x12\x15\n\x06row_id\x18\x03\x20\x01(\tR\x05rowId\x12\x1a\n\x07content\
-    \x18\x04\x20\x01(\tH\0R\x07contentB\x10\n\x0eone_of_content\"+\n\x0cRepe\
-    atedCell\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\x05value\x18\x01\x20\x01(\tR\x05value\"#\n\
-    \x0bGridBlockId\x12\x14\n\x05value\x18\x01\x20\x01(\tR\x05value\"f\n\x10\
-    CreateRowPayload\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\"\xb6\x01\n\x12CreateFieldPayload\x12\x17\n\x07grid_id\x18\
-    \x01\x20\x01(\tR\x06gridId\x12\x1c\n\x05field\x18\x02\x20\x01(\x0b2\x06.\
-    FieldR\x05field\x12(\n\x10type_option_data\x18\x03\x20\x01(\x0cR\x0etype\
-    OptionData\x12&\n\x0estart_field_id\x18\x04\x20\x01(\tH\0R\x0cstartField\
-    IdB\x17\n\x15one_of_start_field_id\"d\n\x11QueryFieldPayload\x12\x17\n\
-    \x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x126\n\x0cfield_orders\x18\x02\
-    \x20\x01(\x0b2\x13.RepeatedFieldOrderR\x0bfieldOrders\"e\n\x16QueryGridB\
-    locksPayload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x122\n\
-    \x0cblock_orders\x18\x02\x20\x03(\x0b2\x0f.GridBlockOrderR\x0bblockOrder\
-    sb\x06proto3\
+    \x18\x02\x20\x03(\x0b2\t.RowOrderR\trowOrders\"\xc0\x01\n\x17GridBlockOr\
+    derChangeset\x12\x19\n\x08block_id\x18\x01\x20\x01(\tR\x07blockId\x12.\n\
+    \rinserted_rows\x18\x02\x20\x03(\x0b2\t.RowOrderR\x0cinsertedRows\x12,\n\
+    \x0cdeleted_rows\x18\x03\x20\x03(\x0b2\t.RowOrderR\x0bdeletedRows\x12,\n\
+    \x0cupdated_rows\x18\x04\x20\x03(\x0b2\t.RowOrderR\x0bupdatedRows\"E\n\t\
+    GridBlock\x12\x0e\n\x02id\x18\x01\x20\x01(\tR\x02id\x12(\n\nrow_orders\
+    \x18\x02\x20\x03(\x0b2\t.RowOrderR\trowOrders\";\n\x04Cell\x12\x19\n\x08\
+    field_id\x18\x01\x20\x01(\tR\x07fieldId\x12\x18\n\x07content\x18\x02\x20\
+    \x01(\tR\x07content\"\x8f\x01\n\x14CellNotificationData\x12\x17\n\x07gri\
+    d_id\x18\x01\x20\x01(\tR\x06gridId\x12\x19\n\x08field_id\x18\x02\x20\x01\
+    (\tR\x07fieldId\x12\x15\n\x06row_id\x18\x03\x20\x01(\tR\x05rowId\x12\x1a\
+    \n\x07content\x18\x04\x20\x01(\tH\0R\x07contentB\x10\n\x0eone_of_content\
+    \"+\n\x0cRepeatedCell\x12\x1b\n\x05items\x18\x01\x20\x03(\x0b2\x05.CellR\
+    \x05items\"'\n\x11CreateGridPayload\x12\x12\n\x04name\x18\x01\x20\x01(\t\
+    R\x04name\"\x1e\n\x06GridId\x12\x14\n\x05value\x18\x01\x20\x01(\tR\x05va\
+    lue\"#\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\x06gr\
+    idId\x12\"\n\x0cstart_row_id\x18\x02\x20\x01(\tH\0R\nstartRowIdB\x15\n\
+    \x13one_of_start_row_id\"\xb6\x01\n\x12CreateFieldPayload\x12\x17\n\x07g\
+    rid_id\x18\x01\x20\x01(\tR\x06gridId\x12\x1c\n\x05field\x18\x02\x20\x01(\
+    \x0b2\x06.FieldR\x05field\x12(\n\x10type_option_data\x18\x03\x20\x01(\
+    \x0cR\x0etypeOptionData\x12&\n\x0estart_field_id\x18\x04\x20\x01(\tH\0R\
+    \x0cstartFieldIdB\x17\n\x15one_of_start_field_id\"d\n\x11QueryFieldPaylo\
+    ad\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x126\n\x0cfield_or\
+    ders\x18\x02\x20\x01(\x0b2\x13.RepeatedFieldOrderR\x0bfieldOrders\"e\n\
+    \x16QueryGridBlocksPayload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06g\
+    ridId\x122\n\x0cblock_orders\x18\x02\x20\x03(\x0b2\x0f.GridBlockOrderR\
+    \x0bblockOrdersb\x06proto3\
 ";
 
 static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;

+ 31 - 32
shared-lib/flowy-grid-data-model/src/protobuf/model/meta.rs

@@ -3114,7 +3114,7 @@ impl ::protobuf::reflect::ProtobufValue for CellMetaChangeset {
 pub struct BuildGridContext {
     // message fields
     pub field_metas: ::protobuf::RepeatedField<FieldMeta>,
-    pub block_metas: ::protobuf::SingularPtrField<GridBlockMeta>,
+    pub block_meta: ::protobuf::SingularPtrField<GridBlockMeta>,
     pub block_meta_data: ::protobuf::SingularPtrField<GridBlockMetaData>,
     // special fields
     pub unknown_fields: ::protobuf::UnknownFields,
@@ -3157,37 +3157,37 @@ impl BuildGridContext {
         ::std::mem::replace(&mut self.field_metas, ::protobuf::RepeatedField::new())
     }
 
-    // .GridBlockMeta block_metas = 2;
+    // .GridBlockMeta block_meta = 2;
 
 
-    pub fn get_block_metas(&self) -> &GridBlockMeta {
-        self.block_metas.as_ref().unwrap_or_else(|| <GridBlockMeta as ::protobuf::Message>::default_instance())
+    pub fn get_block_meta(&self) -> &GridBlockMeta {
+        self.block_meta.as_ref().unwrap_or_else(|| <GridBlockMeta as ::protobuf::Message>::default_instance())
     }
-    pub fn clear_block_metas(&mut self) {
-        self.block_metas.clear();
+    pub fn clear_block_meta(&mut self) {
+        self.block_meta.clear();
     }
 
-    pub fn has_block_metas(&self) -> bool {
-        self.block_metas.is_some()
+    pub fn has_block_meta(&self) -> bool {
+        self.block_meta.is_some()
     }
 
     // Param is passed by value, moved
-    pub fn set_block_metas(&mut self, v: GridBlockMeta) {
-        self.block_metas = ::protobuf::SingularPtrField::some(v);
+    pub fn set_block_meta(&mut self, v: GridBlockMeta) {
+        self.block_meta = ::protobuf::SingularPtrField::some(v);
     }
 
     // Mutable pointer to the field.
     // If field is not initialized, it is initialized with default value first.
-    pub fn mut_block_metas(&mut self) -> &mut GridBlockMeta {
-        if self.block_metas.is_none() {
-            self.block_metas.set_default();
+    pub fn mut_block_meta(&mut self) -> &mut GridBlockMeta {
+        if self.block_meta.is_none() {
+            self.block_meta.set_default();
         }
-        self.block_metas.as_mut().unwrap()
+        self.block_meta.as_mut().unwrap()
     }
 
     // Take field
-    pub fn take_block_metas(&mut self) -> GridBlockMeta {
-        self.block_metas.take().unwrap_or_else(|| GridBlockMeta::new())
+    pub fn take_block_meta(&mut self) -> GridBlockMeta {
+        self.block_meta.take().unwrap_or_else(|| GridBlockMeta::new())
     }
 
     // .GridBlockMetaData block_meta_data = 3;
@@ -3231,7 +3231,7 @@ impl ::protobuf::Message for BuildGridContext {
                 return false;
             }
         };
-        for v in &self.block_metas {
+        for v in &self.block_meta {
             if !v.is_initialized() {
                 return false;
             }
@@ -3252,7 +3252,7 @@ impl ::protobuf::Message for BuildGridContext {
                     ::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.field_metas)?;
                 },
                 2 => {
-                    ::protobuf::rt::read_singular_message_into(wire_type, is, &mut self.block_metas)?;
+                    ::protobuf::rt::read_singular_message_into(wire_type, is, &mut self.block_meta)?;
                 },
                 3 => {
                     ::protobuf::rt::read_singular_message_into(wire_type, is, &mut self.block_meta_data)?;
@@ -3273,7 +3273,7 @@ impl ::protobuf::Message for BuildGridContext {
             let len = value.compute_size();
             my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len;
         };
-        if let Some(ref v) = self.block_metas.as_ref() {
+        if let Some(ref v) = self.block_meta.as_ref() {
             let len = v.compute_size();
             my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len;
         }
@@ -3292,7 +3292,7 @@ impl ::protobuf::Message for BuildGridContext {
             os.write_raw_varint32(v.get_cached_size())?;
             v.write_to_with_cached_sizes(os)?;
         };
-        if let Some(ref v) = self.block_metas.as_ref() {
+        if let Some(ref v) = self.block_meta.as_ref() {
             os.write_tag(2, ::protobuf::wire_format::WireTypeLengthDelimited)?;
             os.write_raw_varint32(v.get_cached_size())?;
             v.write_to_with_cached_sizes(os)?;
@@ -3346,9 +3346,9 @@ impl ::protobuf::Message for BuildGridContext {
                 |m: &mut BuildGridContext| { &mut m.field_metas },
             ));
             fields.push(::protobuf::reflect::accessor::make_singular_ptr_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage<GridBlockMeta>>(
-                "block_metas",
-                |m: &BuildGridContext| { &m.block_metas },
-                |m: &mut BuildGridContext| { &mut m.block_metas },
+                "block_meta",
+                |m: &BuildGridContext| { &m.block_meta },
+                |m: &mut BuildGridContext| { &mut m.block_meta },
             ));
             fields.push(::protobuf::reflect::accessor::make_singular_ptr_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage<GridBlockMetaData>>(
                 "block_meta_data",
@@ -3372,7 +3372,7 @@ impl ::protobuf::Message for BuildGridContext {
 impl ::protobuf::Clear for BuildGridContext {
     fn clear(&mut self) {
         self.field_metas.clear();
-        self.block_metas.clear();
+        self.block_meta.clear();
         self.block_meta_data.clear();
         self.unknown_fields.clear();
     }
@@ -3498,14 +3498,13 @@ static file_descriptor_proto_data: &'static [u8] = b"\
     \x01\n\x11CellMetaChangeset\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06\
     gridId\x12\x15\n\x06row_id\x18\x02\x20\x01(\tR\x05rowId\x12\x19\n\x08fie\
     ld_id\x18\x03\x20\x01(\tR\x07fieldId\x12\x14\n\x04data\x18\x04\x20\x01(\
-    \tH\0R\x04dataB\r\n\x0bone_of_data\"\xac\x01\n\x10BuildGridContext\x12+\
-    \n\x0bfield_metas\x18\x01\x20\x03(\x0b2\n.FieldMetaR\nfieldMetas\x12/\n\
-    \x0bblock_metas\x18\x02\x20\x01(\x0b2\x0e.GridBlockMetaR\nblockMetas\x12\
-    :\n\x0fblock_meta_data\x18\x03\x20\x01(\x0b2\x12.GridBlockMetaDataR\rblo\
-    ckMetaData*d\n\tFieldType\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\x0bMultiSelect\x10\x04\x12\x0c\n\x08Checkbox\x10\x05b\x06prot\
-    o3\
+    \tH\0R\x04dataB\r\n\x0bone_of_data\"\xaa\x01\n\x10BuildGridContext\x12+\
+    \n\x0bfield_metas\x18\x01\x20\x03(\x0b2\n.FieldMetaR\nfieldMetas\x12-\n\
+    \nblock_meta\x18\x02\x20\x01(\x0b2\x0e.GridBlockMetaR\tblockMeta\x12:\n\
+    \x0fblock_meta_data\x18\x03\x20\x01(\x0b2\x12.GridBlockMetaDataR\rblockM\
+    etaData*d\n\tFieldType\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\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;

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

@@ -59,6 +59,12 @@ message GridBlockOrder {
     string block_id = 1;
     repeated RowOrder row_orders = 2;
 }
+message GridBlockOrderChangeset {
+    string block_id = 1;
+    repeated RowOrder inserted_rows = 2;
+    repeated RowOrder deleted_rows = 3;
+    repeated RowOrder updated_rows = 4;
+}
 message GridBlock {
     string id = 1;
     repeated RowOrder row_orders = 2;

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

@@ -63,7 +63,7 @@ message CellMetaChangeset {
 }
 message BuildGridContext {
     repeated FieldMeta field_metas = 1;
-    GridBlockMeta block_metas = 2;
+    GridBlockMeta block_meta = 2;
     GridBlockMetaData block_meta_data = 3;
 }
 enum FieldType {

+ 24 - 29
shared-lib/flowy-sync/src/client_grid/grid_block_meta_pad.rs

@@ -16,7 +16,7 @@ pub type GridBlockMetaDeltaBuilder = PlainTextDeltaBuilder;
 #[derive(Debug, Deserialize, Serialize, Clone)]
 pub struct GridBlockMetaPad {
     block_id: String,
-    row_metas: Vec<Arc<RowMeta>>,
+    rows: Vec<Arc<RowMeta>>,
 
     #[serde(skip)]
     pub(crate) delta: GridBlockMetaDelta,
@@ -32,11 +32,7 @@ impl GridBlockMetaPad {
         })?;
         let block_id = meta_data.block_id;
         let rows = meta_data.rows.into_iter().map(Arc::new).collect::<Vec<Arc<RowMeta>>>();
-        Ok(Self {
-            block_id,
-            row_metas: rows,
-            delta,
-        })
+        Ok(Self { block_id, rows, delta })
     }
 
     pub fn from_revisions(_grid_id: &str, revisions: Vec<Revision>) -> CollaborateResult<Self> {
@@ -80,10 +76,10 @@ impl GridBlockMetaPad {
         T: AsRef<str> + ToOwned + ?Sized,
     {
         match row_ids {
-            None => Ok(self.row_metas.to_vec()),
+            None => Ok(self.rows.to_vec()),
             Some(row_ids) => {
                 let row_map = self
-                    .row_metas
+                    .rows
                     .iter()
                     .map(|row| (row.id.as_str(), row.clone()))
                     .collect::<HashMap<&str, Arc<RowMeta>>>();
@@ -122,7 +118,7 @@ impl GridBlockMetaPad {
     }
 
     pub fn number_of_rows(&self) -> i32 {
-        self.row_metas.len() as i32
+        self.rows.len() as i32
     }
 
     pub fn update_row(&mut self, changeset: RowMetaChangeset) -> CollaborateResult<Option<GridBlockMetaChange>> {
@@ -155,7 +151,7 @@ impl GridBlockMetaPad {
         F: for<'a> FnOnce(&'a mut Vec<Arc<RowMeta>>) -> CollaborateResult<Option<()>>,
     {
         let cloned_self = self.clone();
-        match f(&mut self.row_metas)? {
+        match f(&mut self.rows)? {
             None => Ok(None),
             Some(_) => {
                 let old = cloned_self.to_json()?;
@@ -228,7 +224,7 @@ impl std::default::Default for GridBlockMetaPad {
         let delta = make_block_meta_delta(&block_meta_data);
         GridBlockMetaPad {
             block_id: block_meta_data.block_id,
-            row_metas: block_meta_data.rows.into_iter().map(Arc::new).collect::<Vec<_>>(),
+            rows: block_meta_data.rows.into_iter().map(Arc::new).collect::<Vec<_>>(),
             delta,
         }
     }
@@ -254,7 +250,7 @@ mod tests {
         let change = pad.add_row_meta(row, None).unwrap().unwrap();
         assert_eq!(
             change.delta.to_delta_str(),
-            r#"[{"retain":29},{"insert":"{\"id\":\"1\",\"block_id\":\"1\",\"cell_by_field_id\":{},\"height\":0,\"visibility\":false}"},{"retain":2}]"#
+            r#"[{"retain":24},{"insert":"{\"id\":\"1\",\"block_id\":\"1\",\"cells\":{},\"height\":0,\"visibility\":false}"},{"retain":2}]"#
         );
     }
 
@@ -268,24 +264,24 @@ mod tests {
         let change = pad.add_row_meta(row_1.clone(), None).unwrap().unwrap();
         assert_eq!(
             change.delta.to_delta_str(),
-            r#"[{"retain":29},{"insert":"{\"id\":\"1\",\"block_id\":\"1\",\"cell_by_field_id\":{},\"height\":0,\"visibility\":false}"},{"retain":2}]"#
+            r#"[{"retain":24},{"insert":"{\"id\":\"1\",\"block_id\":\"1\",\"cells\":{},\"height\":0,\"visibility\":false}"},{"retain":2}]"#
         );
 
         let change = pad.add_row_meta(row_2.clone(), None).unwrap().unwrap();
         assert_eq!(
             change.delta.to_delta_str(),
-            r#"[{"retain":106},{"insert":",{\"id\":\"2\",\"block_id\":\"1\",\"cell_by_field_id\":{},\"height\":0,\"visibility\":false}"},{"retain":2}]"#
+            r#"[{"retain":90},{"insert":",{\"id\":\"2\",\"block_id\":\"1\",\"cells\":{},\"height\":0,\"visibility\":false}"},{"retain":2}]"#
         );
 
         let change = pad.add_row_meta(row_3.clone(), Some("2".to_string())).unwrap().unwrap();
         assert_eq!(
             change.delta.to_delta_str(),
-            r#"[{"retain":114},{"insert":"3\",\"block_id\":\"1\",\"cell_by_field_id\":{},\"height\":0,\"visibility\":false},{\"id\":\""},{"retain":72}]"#
+            r#"[{"retain":157},{"insert":",{\"id\":\"3\",\"block_id\":\"1\",\"cells\":{},\"height\":0,\"visibility\":false}"},{"retain":2}]"#
         );
 
-        assert_eq!(*pad.row_metas[0], row_1);
-        assert_eq!(*pad.row_metas[1], row_3);
-        assert_eq!(*pad.row_metas[2], row_2);
+        assert_eq!(*pad.rows[0], row_1);
+        assert_eq!(*pad.rows[1], row_2);
+        assert_eq!(*pad.rows[2], row_3);
     }
 
     fn test_row_meta(id: &str, pad: &GridBlockMetaPad) -> RowMeta {
@@ -309,9 +305,9 @@ mod tests {
         let _ = pad.add_row_meta(row_2.clone(), None).unwrap().unwrap();
         let _ = pad.add_row_meta(row_3.clone(), Some("1".to_string())).unwrap().unwrap();
 
-        assert_eq!(*pad.row_metas[0], row_3);
-        assert_eq!(*pad.row_metas[1], row_1);
-        assert_eq!(*pad.row_metas[2], row_2);
+        assert_eq!(*pad.rows[0], row_3);
+        assert_eq!(*pad.rows[1], row_1);
+        assert_eq!(*pad.rows[2], row_2);
     }
 
     #[test]
@@ -325,9 +321,9 @@ mod tests {
         let _ = pad.add_row_meta(row_2.clone(), None).unwrap().unwrap();
         let _ = pad.add_row_meta(row_3.clone(), Some("".to_string())).unwrap().unwrap();
 
-        assert_eq!(*pad.row_metas[0], row_3);
-        assert_eq!(*pad.row_metas[1], row_1);
-        assert_eq!(*pad.row_metas[2], row_2);
+        assert_eq!(*pad.rows[0], row_3);
+        assert_eq!(*pad.rows[1], row_1);
+        assert_eq!(*pad.rows[2], row_2);
     }
 
     #[test]
@@ -346,7 +342,7 @@ mod tests {
         let change = pad.delete_rows(vec![Cow::Borrowed(&row.id)]).unwrap().unwrap();
         assert_eq!(
             change.delta.to_delta_str(),
-            r#"[{"retain":29},{"delete":77},{"retain":2}]"#
+            r#"[{"retain":24},{"delete":66},{"retain":2}]"#
         );
 
         assert_eq!(pad.delta_str(), pre_delta_str);
@@ -375,18 +371,17 @@ mod tests {
 
         assert_eq!(
             change.delta.to_delta_str(),
-            r#"[{"retain":85},{"insert":"10"},{"retain":15},{"insert":"tru"},{"delete":4},{"retain":4}]"#
+            r#"[{"retain":69},{"insert":"10"},{"retain":15},{"insert":"tru"},{"delete":4},{"retain":4}]"#
         );
 
         assert_eq!(
             pad.to_json().unwrap(),
-            r#"{"block_id":"1","row_metas":[{"id":"1","block_id":"1","cell_by_field_id":{},"height":100,"visibility":true}]}"#
+            r#"{"block_id":"1","rows":[{"id":"1","block_id":"1","cells":{},"height":100,"visibility":true}]}"#
         );
     }
 
     fn test_pad() -> GridBlockMetaPad {
-        let delta =
-            GridBlockMetaDelta::from_delta_str(r#"[{"insert":"{\"block_id\":\"1\",\"row_metas\":[]}"}]"#).unwrap();
+        let delta = GridBlockMetaDelta::from_delta_str(r#"[{"insert":"{\"block_id\":\"1\",\"rows\":[]}"}]"#).unwrap();
         GridBlockMetaPad::from_delta(delta).unwrap()
     }
 }

+ 3 - 3
shared-lib/flowy-sync/src/client_grid/grid_builder.rs

@@ -13,9 +13,9 @@ impl GridBuilder {
     }
 
     pub fn add_empty_row(mut self) -> Self {
-        let row = RowMeta::new(&self.build_context.block_metas.block_id);
+        let row = RowMeta::new(&self.build_context.block_meta.block_id);
         self.build_context.block_meta_data.rows.push(row);
-        self.build_context.block_metas.row_count += 1;
+        self.build_context.block_meta.row_count += 1;
         self
     }
 
@@ -57,7 +57,7 @@ mod tests {
         let grid_meta = GridMeta {
             grid_id,
             fields: build_context.field_metas,
-            blocks: vec![build_context.block_metas],
+            blocks: vec![build_context.block_meta],
         };
 
         let grid_meta_delta = make_grid_delta(&grid_meta);