Selaa lähdekoodia

refactor: remove FieldTypeOptionContext

appflowy 3 vuotta sitten
vanhempi
commit
a59a0af05b
33 muutettua tiedostoa jossa 401 lisäystä ja 320 poistoa
  1. 3 3
      frontend/app_flowy/lib/startup/deps_resolver.dart
  2. 2 2
      frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/context_builder.dart
  3. 5 5
      frontend/app_flowy/lib/workspace/application/grid/field/field_action_sheet_bloc.dart
  4. 6 6
      frontend/app_flowy/lib/workspace/application/grid/field/field_cell_bloc.dart
  5. 23 24
      frontend/app_flowy/lib/workspace/application/grid/field/field_editor_bloc.dart
  6. 5 5
      frontend/app_flowy/lib/workspace/application/grid/field/field_editor_pannel_bloc.dart
  7. 16 25
      frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart
  8. 17 16
      frontend/app_flowy/lib/workspace/application/grid/field/type_option/select_option_type_option_bloc.dart
  9. 47 1
      frontend/app_flowy/lib/workspace/application/grid/field/type_option/type_option_service.dart
  10. 1 1
      frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/date_editor.dart
  11. 4 4
      frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_cell.dart
  12. 14 13
      frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_editor.dart
  13. 7 7
      frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_editor_pannel.dart
  14. 1 1
      frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart
  15. 1 1
      frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/multi_select.dart
  16. 23 31
      frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/select_option.dart
  17. 1 1
      frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/single_select.dart
  18. 1 1
      frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/row_detail.dart
  19. 1 1
      frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_property.dart
  20. 2 19
      frontend/app_flowy/packages/flowy_sdk/lib/dispatch/dart_event/flowy-grid/dart_event.dart
  21. 42 26
      frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pb.dart
  22. 9 8
      frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pbjson.dart
  23. 2 4
      frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/event_map.pbenum.dart
  24. 3 4
      frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/event_map.pbjson.dart
  25. 12 23
      frontend/rust-lib/flowy-grid/src/event_handler.rs
  26. 3 7
      frontend/rust-lib/flowy-grid/src/event_map.rs
  27. 13 16
      frontend/rust-lib/flowy-grid/src/protobuf/model/event_map.rs
  28. 2 3
      frontend/rust-lib/flowy-grid/src/protobuf/proto/event_map.proto
  29. 5 2
      shared-lib/flowy-grid-data-model/src/entities/grid.rs
  30. 94 51
      shared-lib/flowy-grid-data-model/src/protobuf/model/grid.rs
  31. 4 3
      shared-lib/flowy-grid-data-model/src/protobuf/proto/grid.proto
  32. 1 0
      shared-lib/lib-infra/Cargo.toml
  33. 31 6
      shared-lib/lib-infra/src/code_gen/protobuf_file/mod.rs

+ 3 - 3
frontend/app_flowy/lib/startup/deps_resolver.dart

@@ -15,7 +15,7 @@ import 'package:app_flowy/workspace/presentation/home/home_stack.dart';
 import 'package:app_flowy/workspace/presentation/home/menu/menu.dart';
 import 'package:flowy_sdk/protobuf/flowy-folder-data-model/app.pb.dart';
 import 'package:flowy_sdk/protobuf/flowy-folder-data-model/view.pb.dart';
-import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show EditFieldContext;
+import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show FieldTypeOptionData;
 import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option.pb.dart';
 import 'package:flowy_sdk/protobuf/flowy-grid/number_type_option.pb.dart';
 import 'package:flowy_sdk/protobuf/flowy-user-data-model/user_profile.pb.dart';
@@ -157,7 +157,7 @@ void _resolveGridDeps(GetIt getIt) {
     ),
   );
 
-  getIt.registerFactoryParam<FieldEditorBloc, String, EditFieldContextLoader>(
+  getIt.registerFactoryParam<FieldEditorBloc, String, FieldContextLoader>(
     (gridId, fieldLoader) => FieldEditorBloc(
       gridId: gridId,
       fieldLoader: fieldLoader,
@@ -195,7 +195,7 @@ void _resolveGridDeps(GetIt getIt) {
     ),
   );
 
-  getIt.registerFactoryParam<FieldEditorPannelBloc, EditFieldContext, void>(
+  getIt.registerFactoryParam<FieldEditorPannelBloc, FieldTypeOptionData, void>(
     (context, _) => FieldEditorPannelBloc(context),
   );
 

+ 2 - 2
frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/context_builder.dart

@@ -150,8 +150,8 @@ class _GridCellContext<T, D> extends Equatable {
     return data;
   }
 
-  Future<Either<List<int>, FlowyError>> getTypeOptionData() {
-    return _fieldService.getTypeOptionData(fieldType: fieldType);
+  Future<Either<FieldTypeOptionData, FlowyError>> getTypeOptionData() {
+    return _fieldService.getFieldTypeOptionData(fieldType: fieldType);
   }
 
   Future<Option<FlowyError>> saveCellData(D data) {

+ 5 - 5
frontend/app_flowy/lib/workspace/application/grid/field/field_action_sheet_bloc.dart

@@ -11,7 +11,7 @@ class FieldActionSheetBloc extends Bloc<FieldActionSheetEvent, FieldActionSheetS
   final FieldService fieldService;
 
   FieldActionSheetBloc({required Field field, required this.fieldService})
-      : super(FieldActionSheetState.initial(EditFieldContext.create()..gridField = field)) {
+      : super(FieldActionSheetState.initial(FieldTypeOptionData.create()..field_2 = field)) {
     on<FieldActionSheetEvent>(
       (event, emit) async {
         await event.map(
@@ -67,14 +67,14 @@ class FieldActionSheetEvent with _$FieldActionSheetEvent {
 @freezed
 class FieldActionSheetState with _$FieldActionSheetState {
   const factory FieldActionSheetState({
-    required EditFieldContext editContext,
+    required FieldTypeOptionData fieldTypeOptionData,
     required String errorText,
     required String fieldName,
   }) = _FieldActionSheetState;
 
-  factory FieldActionSheetState.initial(EditFieldContext editContext) => FieldActionSheetState(
-        editContext: editContext,
+  factory FieldActionSheetState.initial(FieldTypeOptionData data) => FieldActionSheetState(
+        fieldTypeOptionData: data,
         errorText: '',
-        fieldName: editContext.gridField.name,
+        fieldName: data.field_2.name,
       );
 }

+ 6 - 6
frontend/app_flowy/lib/workspace/application/grid/field/field_cell_bloc.dart

@@ -19,16 +19,16 @@ class FieldCellBloc extends Bloc<FieldCellEvent, FieldCellState> {
         super(FieldCellState.initial(cellContext)) {
     on<FieldCellEvent>(
       (event, emit) async {
-        await event.map(
-          initial: (_InitialCell value) async {
+        event.when(
+          initial: () {
             _startListening();
           },
-          didReceiveFieldUpdate: (_DidReceiveFieldUpdate value) {
-            emit(state.copyWith(field: value.field));
+          didReceiveFieldUpdate: (field) {
+            emit(state.copyWith(field: field));
           },
-          updateWidth: (_UpdateWidth value) {
+          updateWidth: (offset) {
             final defaultWidth = state.field.width.toDouble();
-            final width = defaultWidth + value.offset;
+            final width = defaultWidth + offset;
             if (width > defaultWidth && width < 300) {
               _fieldService.updateField(width: width);
             }

+ 23 - 24
frontend/app_flowy/lib/workspace/application/grid/field/field_editor_bloc.dart

@@ -12,27 +12,26 @@ part 'field_editor_bloc.freezed.dart';
 
 class FieldEditorBloc extends Bloc<FieldEditorEvent, FieldEditorState> {
   final String gridId;
-  final EditFieldContextLoader _loader;
+  final FieldContextLoader _loader;
 
   FieldEditorBloc({
     required this.gridId,
-    required EditFieldContextLoader fieldLoader,
+    required FieldContextLoader fieldLoader,
   })  : _loader = fieldLoader,
         super(FieldEditorState.initial(gridId)) {
     on<FieldEditorEvent>(
       (event, emit) async {
         await event.map(
           initial: (_InitialField value) async {
-            await _getEditFieldContext(emit);
+            await _getFieldTypeOptionContext(emit);
           },
           updateName: (_UpdateName value) {
             final newContext = _updateEditContext(name: value.name);
-            emit(state.copyWith(editFieldContext: newContext));
+            emit(state.copyWith(fieldTypeOptionData: newContext));
           },
           updateField: (_UpdateField value) {
-            final newContext = _updateEditContext(field: value.field, typeOptionData: value.typeOptionData);
-
-            emit(state.copyWith(editFieldContext: newContext));
+            final data = _updateEditContext(field: value.field, typeOptionData: value.typeOptionData);
+            emit(state.copyWith(fieldTypeOptionData: data));
           },
           done: (_Done value) async {
             await _saveField(emit);
@@ -47,26 +46,26 @@ class FieldEditorBloc extends Bloc<FieldEditorEvent, FieldEditorState> {
     return super.close();
   }
 
-  Option<EditFieldContext> _updateEditContext({
+  Option<FieldTypeOptionData> _updateEditContext({
     String? name,
     Field? field,
     List<int>? typeOptionData,
   }) {
-    return state.editFieldContext.fold(
+    return state.fieldTypeOptionData.fold(
       () => none(),
       (context) {
         context.freeze();
-        final newContext = context.rebuild((newContext) {
-          newContext.gridField.rebuild((newField) {
+        final newFieldTypeOptionData = context.rebuild((newContext) {
+          newContext.field_2.rebuild((newField) {
             if (name != null) {
               newField.name = name;
             }
 
-            newContext.gridField = newField;
+            newContext.field_2 = newField;
           });
 
           if (field != null) {
-            newContext.gridField = field;
+            newContext.field_2 = field;
           }
 
           if (typeOptionData != null) {
@@ -76,35 +75,35 @@ class FieldEditorBloc extends Bloc<FieldEditorEvent, FieldEditorState> {
 
         FieldService.insertField(
           gridId: gridId,
-          field: newContext.gridField,
-          typeOptionData: newContext.typeOptionData,
+          field: newFieldTypeOptionData.field_2,
+          typeOptionData: newFieldTypeOptionData.typeOptionData,
         );
 
-        return Some(newContext);
+        return Some(newFieldTypeOptionData);
       },
     );
   }
 
   Future<void> _saveField(Emitter<FieldEditorState> emit) async {
-    await state.editFieldContext.fold(
+    await state.fieldTypeOptionData.fold(
       () async => null,
-      (context) async {
+      (data) async {
         final result = await FieldService.insertField(
           gridId: gridId,
-          field: context.gridField,
-          typeOptionData: context.typeOptionData,
+          field: data.field_2,
+          typeOptionData: data.typeOptionData,
         );
         result.fold((l) => null, (r) => null);
       },
     );
   }
 
-  Future<void> _getEditFieldContext(Emitter<FieldEditorState> emit) async {
+  Future<void> _getFieldTypeOptionContext(Emitter<FieldEditorState> emit) async {
     final result = await _loader.load();
     result.fold(
       (context) {
         emit(state.copyWith(
-          editFieldContext: Some(context),
+          fieldTypeOptionData: Some(context),
         ));
       },
       (err) => Log.error(err),
@@ -125,12 +124,12 @@ class FieldEditorState with _$FieldEditorState {
   const factory FieldEditorState({
     required String gridId,
     required String errorText,
-    required Option<EditFieldContext> editFieldContext,
+    required Option<FieldTypeOptionData> fieldTypeOptionData,
   }) = _FieldEditorState;
 
   factory FieldEditorState.initial(String gridId) => FieldEditorState(
         gridId: gridId,
-        editFieldContext: none(),
+        fieldTypeOptionData: none(),
         errorText: '',
       );
 }

+ 5 - 5
frontend/app_flowy/lib/workspace/application/grid/field/field_editor_pannel_bloc.dart

@@ -7,7 +7,7 @@ import 'dart:async';
 part 'field_editor_pannel_bloc.freezed.dart';
 
 class FieldEditorPannelBloc extends Bloc<FieldEditorPannelEvent, FieldEditorPannelState> {
-  FieldEditorPannelBloc(EditFieldContext editContext) : super(FieldEditorPannelState.initial(editContext)) {
+  FieldEditorPannelBloc(FieldTypeOptionData editContext) : super(FieldEditorPannelState.initial(editContext)) {
     on<FieldEditorPannelEvent>(
       (event, emit) async {
         await event.map(
@@ -45,9 +45,9 @@ class FieldEditorPannelState with _$FieldEditorPannelState {
     required Uint8List typeOptionData,
   }) = _FieldEditorPannelState;
 
-  factory FieldEditorPannelState.initial(EditFieldContext context) => FieldEditorPannelState(
-        gridId: context.gridId,
-        field: context.gridField,
-        typeOptionData: Uint8List.fromList(context.typeOptionData),
+  factory FieldEditorPannelState.initial(FieldTypeOptionData data) => FieldEditorPannelState(
+        gridId: data.gridId,
+        field: data.field_2,
+        typeOptionData: Uint8List.fromList(data.typeOptionData),
       );
 }

+ 16 - 25
frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart

@@ -12,7 +12,7 @@ class FieldService {
 
   FieldService({required this.gridId, required this.fieldId});
 
-  Future<Either<EditFieldContext, FlowyError>> switchToField(FieldType fieldType) {
+  Future<Either<FieldTypeOptionData, FlowyError>> switchToField(FieldType fieldType) {
     final payload = EditFieldPayload.create()
       ..gridId = gridId
       ..fieldId = fieldId
@@ -21,15 +21,6 @@ class FieldService {
     return GridEventSwitchToField(payload).send();
   }
 
-  Future<Either<EditFieldContext, FlowyError>> getEditFieldContext(FieldType fieldType) {
-    final payload = EditFieldPayload.create()
-      ..gridId = gridId
-      ..fieldId = fieldId
-      ..fieldType = fieldType;
-
-    return GridEventGetEditFieldContext(payload).send();
-  }
-
   Future<Either<Unit, FlowyError>> moveField(int fromIndex, int toIndex) {
     final payload = MoveItemPayload.create()
       ..gridId = gridId
@@ -128,7 +119,7 @@ class FieldService {
     return GridEventDuplicateField(payload).send();
   }
 
-  Future<Either<List<int>, FlowyError>> getTypeOptionData({
+  Future<Either<FieldTypeOptionData, FlowyError>> getFieldTypeOptionData({
     required FieldType fieldType,
   }) {
     final payload = EditFieldPayload.create()
@@ -137,7 +128,7 @@ class FieldService {
       ..fieldType = fieldType;
     return GridEventGetFieldTypeOption(payload).send().then((result) {
       return result.fold(
-        (data) => left(data.typeOptionData),
+        (data) => left(data),
         (err) => right(err),
       );
     });
@@ -152,58 +143,58 @@ class GridFieldCellContext with _$GridFieldCellContext {
   }) = _GridFieldCellContext;
 }
 
-abstract class EditFieldContextLoader {
-  Future<Either<EditFieldContext, FlowyError>> load();
+abstract class FieldContextLoader {
+  Future<Either<FieldTypeOptionData, FlowyError>> load();
 
-  Future<Either<EditFieldContext, FlowyError>> switchToField(String fieldId, FieldType fieldType);
+  Future<Either<FieldTypeOptionData, FlowyError>> switchToField(String fieldId, FieldType fieldType);
 }
 
-class NewFieldContextLoader extends EditFieldContextLoader {
+class NewFieldContextLoader extends FieldContextLoader {
   final String gridId;
   NewFieldContextLoader({
     required this.gridId,
   });
 
   @override
-  Future<Either<EditFieldContext, FlowyError>> load() {
+  Future<Either<FieldTypeOptionData, FlowyError>> load() {
     final payload = EditFieldPayload.create()
       ..gridId = gridId
       ..fieldType = FieldType.RichText;
 
-    return GridEventGetEditFieldContext(payload).send();
+    return GridEventGetFieldTypeOption(payload).send();
   }
 
   @override
-  Future<Either<EditFieldContext, FlowyError>> switchToField(String fieldId, FieldType fieldType) {
+  Future<Either<FieldTypeOptionData, FlowyError>> switchToField(String fieldId, FieldType fieldType) {
     final payload = EditFieldPayload.create()
       ..gridId = gridId
       ..fieldType = fieldType;
 
-    return GridEventGetEditFieldContext(payload).send();
+    return GridEventGetFieldTypeOption(payload).send();
   }
 }
 
-class FieldContextLoaderAdaptor extends EditFieldContextLoader {
+class DefaultFieldContextLoader extends FieldContextLoader {
   final String gridId;
   final Field field;
 
-  FieldContextLoaderAdaptor({
+  DefaultFieldContextLoader({
     required this.gridId,
     required this.field,
   });
 
   @override
-  Future<Either<EditFieldContext, FlowyError>> load() {
+  Future<Either<FieldTypeOptionData, FlowyError>> load() {
     final payload = EditFieldPayload.create()
       ..gridId = gridId
       ..fieldId = field.id
       ..fieldType = field.fieldType;
 
-    return GridEventGetEditFieldContext(payload).send();
+    return GridEventGetFieldTypeOption(payload).send();
   }
 
   @override
-  Future<Either<EditFieldContext, FlowyError>> switchToField(String fieldId, FieldType fieldType) async {
+  Future<Either<FieldTypeOptionData, FlowyError>> switchToField(String fieldId, FieldType fieldType) async {
     final fieldService = FieldService(gridId: gridId, fieldId: fieldId);
     return fieldService.switchToField(fieldType);
   }

+ 17 - 16
frontend/app_flowy/lib/workspace/application/grid/field/type_option/field_option_pannel_bloc.dart → frontend/app_flowy/lib/workspace/application/grid/field/type_option/select_option_type_option_bloc.dart

@@ -3,17 +3,18 @@ import 'package:flutter_bloc/flutter_bloc.dart';
 import 'package:freezed_annotation/freezed_annotation.dart';
 import 'dart:async';
 import 'package:dartz/dartz.dart';
-part 'field_option_pannel_bloc.freezed.dart';
+part 'select_option_type_option_bloc.freezed.dart';
 
-class FieldOptionPannelBloc extends Bloc<FieldOptionPannelEvent, FieldOptionPannelState> {
-  FieldOptionPannelBloc({required List<SelectOption> options}) : super(FieldOptionPannelState.initial(options)) {
-    on<FieldOptionPannelEvent>(
+class SelectOptionTypeOptionBloc extends Bloc<SelectOptionTypeOptionEvent, SelectOptionTyepOptionState> {
+  SelectOptionTypeOptionBloc({required List<SelectOption> options})
+      : super(SelectOptionTyepOptionState.initial(options)) {
+    on<SelectOptionTypeOptionEvent>(
       (event, emit) async {
         await event.map(
           createOption: (_CreateOption value) async {
-            emit(state.copyWith(isEditingOption: false, newOptionName: Some(value.optionName)));
+            emit(state.copyWith(isEditingOption: true, newOptionName: Some(value.optionName)));
           },
-          beginAddingOption: (_BeginAddingOption value) {
+          addingOption: (_AddingOption value) {
             emit(state.copyWith(isEditingOption: true, newOptionName: none()));
           },
           endAddingOption: (_EndAddingOption value) {
@@ -37,25 +38,25 @@ class FieldOptionPannelBloc extends Bloc<FieldOptionPannelEvent, FieldOptionPann
 }
 
 @freezed
-class FieldOptionPannelEvent with _$FieldOptionPannelEvent {
-  const factory FieldOptionPannelEvent.createOption(String optionName) = _CreateOption;
-  const factory FieldOptionPannelEvent.beginAddingOption() = _BeginAddingOption;
-  const factory FieldOptionPannelEvent.endAddingOption() = _EndAddingOption;
-  const factory FieldOptionPannelEvent.updateOption(SelectOption option) = _UpdateOption;
-  const factory FieldOptionPannelEvent.deleteOption(SelectOption option) = _DeleteOption;
+class SelectOptionTypeOptionEvent with _$SelectOptionTypeOptionEvent {
+  const factory SelectOptionTypeOptionEvent.createOption(String optionName) = _CreateOption;
+  const factory SelectOptionTypeOptionEvent.addingOption() = _AddingOption;
+  const factory SelectOptionTypeOptionEvent.endAddingOption() = _EndAddingOption;
+  const factory SelectOptionTypeOptionEvent.updateOption(SelectOption option) = _UpdateOption;
+  const factory SelectOptionTypeOptionEvent.deleteOption(SelectOption option) = _DeleteOption;
 }
 
 @freezed
-class FieldOptionPannelState with _$FieldOptionPannelState {
-  const factory FieldOptionPannelState({
+class SelectOptionTyepOptionState with _$SelectOptionTyepOptionState {
+  const factory SelectOptionTyepOptionState({
     required List<SelectOption> options,
     required bool isEditingOption,
     required Option<String> newOptionName,
     required Option<SelectOption> updateOption,
     required Option<SelectOption> deleteOption,
-  }) = _FieldOptionPannelState;
+  }) = _SelectOptionTyepOptionState;
 
-  factory FieldOptionPannelState.initial(List<SelectOption> options) => FieldOptionPannelState(
+  factory SelectOptionTyepOptionState.initial(List<SelectOption> options) => SelectOptionTyepOptionState(
         options: options,
         isEditingOption: false,
         newOptionName: none(),

+ 47 - 1
frontend/app_flowy/lib/workspace/application/grid/field/type_option/type_option_service.dart

@@ -1,5 +1,6 @@
 import 'dart:typed_data';
 
+import 'package:app_flowy/workspace/application/grid/field/field_service.dart';
 import 'package:dartz/dartz.dart';
 import 'package:flowy_sdk/dispatch/dispatch.dart';
 import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
@@ -32,13 +33,58 @@ class TypeOptionService {
   }
 }
 
+abstract class TypeOptionDataBuilder<T> {
+  T fromBuffer(List<int> buffer);
+}
+
 class TypeOptionContext {
   final String gridId;
   final Field field;
   final Uint8List data;
-  const TypeOptionContext({
+
+  TypeOptionContext({
     required this.gridId,
     required this.field,
     required this.data,
   });
 }
+
+abstract class TypeOptionFieldDelegate {
+  void onFieldChanged(void Function(String) callback);
+  void dispose();
+}
+
+class TypeOptionContext2<T> {
+  final String gridId;
+  final Field field;
+  final FieldService _fieldService;
+  T? _data;
+  final TypeOptionDataBuilder dataBuilder;
+
+  TypeOptionContext2({
+    required this.gridId,
+    required this.field,
+    required this.dataBuilder,
+    Uint8List? data,
+  }) : _fieldService = FieldService(gridId: gridId, fieldId: field.id) {
+    if (data != null) {
+      _data = dataBuilder.fromBuffer(data);
+    }
+  }
+
+  Future<Either<T, FlowyError>> typeOptionData() {
+    if (_data != null) {
+      return Future(() => left(_data!));
+    }
+
+    return _fieldService.getFieldTypeOptionData(fieldType: field.fieldType).then((result) {
+      return result.fold(
+        (data) {
+          _data = dataBuilder.fromBuffer(data.typeOptionData);
+          return left(_data!);
+        },
+        (err) => right(err),
+      );
+    });
+  }
+}

+ 1 - 1
frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/date_editor.dart

@@ -40,7 +40,7 @@ class DateCellEditor with FlowyOverlayDelegate {
       (data) {
         final calendar = _CellCalendarWidget(
           cellContext: cellContext,
-          dateTypeOption: DateTypeOption.fromBuffer(data),
+          dateTypeOption: DateTypeOption.fromBuffer(data.typeOptionData),
         );
 
         FlowyOverlay.of(context).insertWithAnchor(

+ 4 - 4
frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_cell.dart

@@ -37,7 +37,7 @@ class GridFieldCell extends StatelessWidget {
             child: _DragToExpandLine(),
           );
 
-          return _CellContainer(
+          return _GridHeaderCellContainer(
             width: state.field.width.toDouble(),
             child: Stack(
               alignment: Alignment.centerRight,
@@ -63,7 +63,7 @@ class GridFieldCell extends StatelessWidget {
 
     FieldEditor(
       gridId: state.gridId,
-      fieldContextLoader: FieldContextLoaderAdaptor(
+      contextLoader: DefaultFieldContextLoader(
         gridId: state.gridId,
         field: state.field,
       ),
@@ -71,10 +71,10 @@ class GridFieldCell extends StatelessWidget {
   }
 }
 
-class _CellContainer extends StatelessWidget {
+class _GridHeaderCellContainer extends StatelessWidget {
   final Widget child;
   final double width;
-  const _CellContainer({
+  const _GridHeaderCellContainer({
     required this.child,
     required this.width,
     Key? key,

+ 14 - 13
frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_editor.dart

@@ -14,12 +14,12 @@ import 'field_editor_pannel.dart';
 class FieldEditor extends FlowyOverlayDelegate {
   final String gridId;
   final FieldEditorBloc _fieldEditorBloc;
-  final EditFieldContextLoader fieldContextLoader;
+  final FieldContextLoader contextLoader;
   FieldEditor({
     required this.gridId,
-    required this.fieldContextLoader,
+    required this.contextLoader,
     Key? key,
-  }) : _fieldEditorBloc = getIt<FieldEditorBloc>(param1: gridId, param2: fieldContextLoader) {
+  }) : _fieldEditorBloc = getIt<FieldEditorBloc>(param1: gridId, param2: contextLoader) {
     _fieldEditorBloc.add(const FieldEditorEvent.initial());
   }
 
@@ -28,9 +28,10 @@ class FieldEditor extends FlowyOverlayDelegate {
     AnchorDirection anchorDirection = AnchorDirection.bottomWithLeftAligned,
   }) {
     FlowyOverlay.of(context).remove(identifier());
+    final child = _FieldEditorPage(_fieldEditorBloc, contextLoader);
     FlowyOverlay.of(context).insertWithAnchor(
       widget: OverlayContainer(
-        child: _FieldEditorWidget(_fieldEditorBloc, fieldContextLoader),
+        child: child,
         constraints: BoxConstraints.loose(const Size(280, 400)),
       ),
       identifier: identifier(),
@@ -54,10 +55,10 @@ class FieldEditor extends FlowyOverlayDelegate {
   bool asBarrier() => true;
 }
 
-class _FieldEditorWidget extends StatelessWidget {
+class _FieldEditorPage extends StatelessWidget {
   final FieldEditorBloc editorBloc;
-  final EditFieldContextLoader fieldContextLoader;
-  const _FieldEditorWidget(this.editorBloc, this.fieldContextLoader, {Key? key}) : super(key: key);
+  final FieldContextLoader contextLoader;
+  const _FieldEditorPage(this.editorBloc, this.contextLoader, {Key? key}) : super(key: key);
 
   @override
   Widget build(BuildContext context) {
@@ -65,9 +66,9 @@ class _FieldEditorWidget extends StatelessWidget {
       value: editorBloc,
       child: BlocBuilder<FieldEditorBloc, FieldEditorState>(
         builder: (context, state) {
-          return state.editFieldContext.fold(
+          return state.fieldTypeOptionData.fold(
             () => const SizedBox(),
-            (editFieldContext) => ListView(
+            (fieldTypeOptionContext) => ListView(
               shrinkWrap: true,
               children: [
                 FlowyText.medium(LocaleKeys.grid_field_editProperty.tr(), fontSize: 12),
@@ -75,9 +76,9 @@ class _FieldEditorWidget extends StatelessWidget {
                 const _FieldNameTextField(),
                 const VSpace(10),
                 FieldEditorPannel(
-                  editFieldContext: editFieldContext,
+                  fieldTypeOptionData: fieldTypeOptionContext,
                   onSwitchToField: (fieldId, fieldType) {
-                    return fieldContextLoader.switchToField(fieldId, fieldType);
+                    return contextLoader.switchToField(fieldId, fieldType);
                   },
                   onUpdated: (field, typeOptionData) {
                     context.read<FieldEditorBloc>().add(FieldEditorEvent.updateField(field, typeOptionData));
@@ -99,9 +100,9 @@ class _FieldNameTextField extends StatelessWidget {
   Widget build(BuildContext context) {
     return BlocSelector<FieldEditorBloc, FieldEditorState, String>(
       selector: (state) {
-        return state.editFieldContext.fold(
+        return state.fieldTypeOptionData.fold(
           () => "",
-          (editFieldContext) => editFieldContext.gridField.name,
+          (fieldTypeOptionContext) => fieldTypeOptionContext.field_2.name,
         );
       },
       builder: (context, name) {

+ 7 - 7
frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_editor_pannel.dart

@@ -25,18 +25,18 @@ import 'type_option/number.dart';
 import 'type_option/single_select.dart';
 
 typedef UpdateFieldCallback = void Function(Field, Uint8List);
-typedef SwitchToFieldCallback = Future<Either<EditFieldContext, FlowyError>> Function(
+typedef SwitchToFieldCallback = Future<Either<FieldTypeOptionData, FlowyError>> Function(
   String fieldId,
   FieldType fieldType,
 );
 
 class FieldEditorPannel extends StatefulWidget {
-  final EditFieldContext editFieldContext;
+  final FieldTypeOptionData fieldTypeOptionData;
   final UpdateFieldCallback onUpdated;
   final SwitchToFieldCallback onSwitchToField;
 
   const FieldEditorPannel({
-    required this.editFieldContext,
+    required this.fieldTypeOptionData,
     required this.onUpdated,
     required this.onSwitchToField,
     Key? key,
@@ -52,7 +52,7 @@ class _FieldEditorPannelState extends State<FieldEditorPannel> {
   @override
   Widget build(BuildContext context) {
     return BlocProvider(
-      create: (context) => getIt<FieldEditorPannelBloc>(param1: widget.editFieldContext),
+      create: (context) => getIt<FieldEditorPannelBloc>(param1: widget.fieldTypeOptionData),
       child: BlocConsumer<FieldEditorPannelBloc, FieldEditorPannelState>(
         listener: (context, state) {
           widget.onUpdated(state.field, state.typeOptionData);
@@ -86,11 +86,11 @@ class _FieldEditorPannelState extends State<FieldEditorPannel> {
           final list = FieldTypeList(onSelectField: (newFieldType) {
             widget.onSwitchToField(field.id, newFieldType).then((result) {
               result.fold(
-                (editFieldContext) {
+                (fieldTypeOptionContext) {
                   context.read<FieldEditorPannelBloc>().add(
                         FieldEditorPannelEvent.toFieldType(
-                          editFieldContext.gridField,
-                          editFieldContext.typeOptionData,
+                          fieldTypeOptionContext.field_2,
+                          fieldTypeOptionContext.typeOptionData,
                         ),
                       );
                 },

+ 1 - 1
frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart

@@ -150,7 +150,7 @@ class CreateFieldButton extends StatelessWidget {
       hoverColor: theme.hover,
       onTap: () => FieldEditor(
         gridId: gridId,
-        fieldContextLoader: NewFieldContextLoader(gridId: gridId),
+        contextLoader: NewFieldContextLoader(gridId: gridId),
       ).show(context),
       leftIcon: svgWidget("home/add"),
     );

+ 1 - 1
frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/multi_select.dart

@@ -58,7 +58,7 @@ class MultiSelectTypeOptionWidget extends TypeOptionWidget {
               context.read<MultiSelectTypeOptionBloc>().add(MultiSelectTypeOptionEvent.deleteOption(deleteOption));
             },
             overlayDelegate: overlayDelegate,
-            key: ValueKey(state.typeOption.hashCode),
+            // key: ValueKey(state.typeOption.hashCode),
           );
         },
       ),

+ 23 - 31
frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/select_option.dart

@@ -1,4 +1,4 @@
-import 'package:app_flowy/workspace/application/grid/field/type_option/field_option_pannel_bloc.dart';
+import 'package:app_flowy/workspace/application/grid/field/type_option/select_option_type_option_bloc.dart';
 import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart';
 import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/common/text_field.dart';
 import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/field_editor_pannel.dart';
@@ -36,8 +36,8 @@ class SelectOptionTypeOptionWidget extends StatelessWidget {
   @override
   Widget build(BuildContext context) {
     return BlocProvider(
-      create: (context) => FieldOptionPannelBloc(options: options),
-      child: BlocConsumer<FieldOptionPannelBloc, FieldOptionPannelState>(
+      create: (context) => SelectOptionTypeOptionBloc(options: options),
+      child: BlocConsumer<SelectOptionTypeOptionBloc, SelectOptionTyepOptionState>(
         listener: (context, state) {
           if (state.isEditingOption) {
             beginEdit();
@@ -61,18 +61,10 @@ class SelectOptionTypeOptionWidget extends StatelessWidget {
           List<Widget> children = [
             const TypeOptionSeparator(),
             const OptionTitle(),
+            if (state.isEditingOption) const _CreateOptionTextField(),
+            if (state.options.isEmpty && !state.isEditingOption) const _AddOptionButton(),
+            _OptionList(overlayDelegate)
           ];
-          if (state.isEditingOption) {
-            children.add(const _OptionNameTextField());
-          }
-
-          if (state.options.isEmpty && !state.isEditingOption) {
-            children.add(const _AddOptionButton());
-          }
-
-          if (state.options.isNotEmpty) {
-            children.add(_OptionList(overlayDelegate));
-          }
 
           return Column(children: children);
         },
@@ -86,12 +78,12 @@ class OptionTitle extends StatelessWidget {
 
   @override
   Widget build(BuildContext context) {
-    return BlocBuilder<FieldOptionPannelBloc, FieldOptionPannelState>(
+    return BlocBuilder<SelectOptionTypeOptionBloc, SelectOptionTyepOptionState>(
       builder: (context, state) {
         List<Widget> children = [FlowyText.medium(LocaleKeys.grid_field_optionTitle.tr(), fontSize: 12)];
         if (state.options.isNotEmpty) {
           children.add(const Spacer());
-          children.add(const _OptionTitleAddOptionButton());
+          children.add(const _OptionTitleButton());
         }
 
         return SizedBox(
@@ -103,8 +95,8 @@ class OptionTitle extends StatelessWidget {
   }
 }
 
-class _OptionTitleAddOptionButton extends StatelessWidget {
-  const _OptionTitleAddOptionButton({Key? key}) : super(key: key);
+class _OptionTitleButton extends StatelessWidget {
+  const _OptionTitleButton({Key? key}) : super(key: key);
 
   @override
   Widget build(BuildContext context) {
@@ -120,7 +112,7 @@ class _OptionTitleAddOptionButton extends StatelessWidget {
         ),
         hoverColor: theme.hover,
         onTap: () {
-          context.read<FieldOptionPannelBloc>().add(const FieldOptionPannelEvent.beginAddingOption());
+          context.read<SelectOptionTypeOptionBloc>().add(const SelectOptionTypeOptionEvent.addingOption());
         },
       ),
     );
@@ -133,7 +125,7 @@ class _OptionList extends StatelessWidget {
 
   @override
   Widget build(BuildContext context) {
-    return BlocBuilder<FieldOptionPannelBloc, FieldOptionPannelState>(
+    return BlocBuilder<SelectOptionTypeOptionBloc, SelectOptionTyepOptionState>(
       buildWhen: (previous, current) {
         return previous.options != current.options;
       },
@@ -160,16 +152,16 @@ class _OptionList extends StatelessWidget {
   _OptionCell _makeOptionCell(BuildContext context, SelectOption option) {
     return _OptionCell(
       option: option,
-      onEdited: (option) {
+      onSelected: (option) {
         final pannel = SelectOptionTypeOptionEditor(
           option: option,
           onDeleted: () {
             delegate.hideOverlay(context);
-            context.read<FieldOptionPannelBloc>().add(FieldOptionPannelEvent.deleteOption(option));
+            context.read<SelectOptionTypeOptionBloc>().add(SelectOptionTypeOptionEvent.deleteOption(option));
           },
           onUpdated: (updatedOption) {
             delegate.hideOverlay(context);
-            context.read<FieldOptionPannelBloc>().add(FieldOptionPannelEvent.updateOption(updatedOption));
+            context.read<SelectOptionTypeOptionBloc>().add(SelectOptionTypeOptionEvent.updateOption(updatedOption));
           },
           key: ValueKey(option.id),
         );
@@ -181,10 +173,10 @@ class _OptionList extends StatelessWidget {
 
 class _OptionCell extends StatelessWidget {
   final SelectOption option;
-  final Function(SelectOption) onEdited;
+  final Function(SelectOption) onSelected;
   const _OptionCell({
     required this.option,
-    required this.onEdited,
+    required this.onSelected,
     Key? key,
   }) : super(key: key);
 
@@ -196,7 +188,7 @@ class _OptionCell extends StatelessWidget {
       child: FlowyButton(
         text: FlowyText.medium(option.name, fontSize: 12),
         hoverColor: theme.hover,
-        onTap: () => onEdited(option),
+        onTap: () => onSelected(option),
         rightIcon: svgWidget("grid/details", color: theme.iconColor),
       ),
     );
@@ -215,7 +207,7 @@ class _AddOptionButton extends StatelessWidget {
         text: FlowyText.medium(LocaleKeys.grid_field_addSelectOption.tr(), fontSize: 12),
         hoverColor: theme.hover,
         onTap: () {
-          context.read<FieldOptionPannelBloc>().add(const FieldOptionPannelEvent.beginAddingOption());
+          context.read<SelectOptionTypeOptionBloc>().add(const SelectOptionTypeOptionEvent.addingOption());
         },
         leftIcon: svgWidget("home/add", color: theme.iconColor),
       ),
@@ -223,18 +215,18 @@ class _AddOptionButton extends StatelessWidget {
   }
 }
 
-class _OptionNameTextField extends StatelessWidget {
-  const _OptionNameTextField({Key? key}) : super(key: key);
+class _CreateOptionTextField extends StatelessWidget {
+  const _CreateOptionTextField({Key? key}) : super(key: key);
 
   @override
   Widget build(BuildContext context) {
     return InputTextField(
       text: "",
       onCanceled: () {
-        context.read<FieldOptionPannelBloc>().add(const FieldOptionPannelEvent.endAddingOption());
+        context.read<SelectOptionTypeOptionBloc>().add(const SelectOptionTypeOptionEvent.endAddingOption());
       },
       onDone: (optionName) {
-        context.read<FieldOptionPannelBloc>().add(FieldOptionPannelEvent.createOption(optionName));
+        context.read<SelectOptionTypeOptionBloc>().add(SelectOptionTypeOptionEvent.createOption(optionName));
       },
     );
   }

+ 1 - 1
frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/single_select.dart

@@ -57,7 +57,7 @@ class SingleSelectTypeOptionWidget extends TypeOptionWidget {
               context.read<SingleSelectTypeOptionBloc>().add(SingleSelectTypeOptionEvent.deleteOption(deleteOption));
             },
             overlayDelegate: overlayDelegate,
-            key: ValueKey(state.typeOption.hashCode),
+            // key: ValueKey(state.typeOption.hashCode),
           );
         },
       ),

+ 1 - 1
frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/row_detail.dart

@@ -178,7 +178,7 @@ class _RowDetailCell extends StatelessWidget {
   void _showFieldEditor(BuildContext context) {
     FieldEditor(
       gridId: gridCell.gridId,
-      fieldContextLoader: FieldContextLoaderAdaptor(
+      contextLoader: DefaultFieldContextLoader(
         gridId: gridCell.gridId,
         field: gridCell.field,
       ),

+ 1 - 1
frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_property.dart

@@ -115,7 +115,7 @@ class _GridPropertyCell extends StatelessWidget {
       onTap: () {
         FieldEditor(
           gridId: gridId,
-          fieldContextLoader: FieldContextLoaderAdaptor(gridId: gridId, field: field),
+          contextLoader: DefaultFieldContextLoader(gridId: gridId, field: field),
         ).show(context, anchorDirection: AnchorDirection.bottomRight);
       },
     );

+ 2 - 19
frontend/app_flowy/packages/flowy_sdk/lib/dispatch/dart_event/flowy-grid/dart_event.dart

@@ -124,14 +124,14 @@ class GridEventSwitchToField {
      EditFieldPayload request;
      GridEventSwitchToField(this.request);
 
-    Future<Either<EditFieldContext, FlowyError>> send() {
+    Future<Either<FieldTypeOptionData, FlowyError>> send() {
     final request = FFIRequest.create()
           ..event = GridEvent.SwitchToField.toString()
           ..payload = requestToBytes(this.request);
 
     return Dispatch.asyncRequest(request)
         .then((bytesResult) => bytesResult.fold(
-           (okBytes) => left(EditFieldContext.fromBuffer(okBytes)),
+           (okBytes) => left(FieldTypeOptionData.fromBuffer(okBytes)),
            (errBytes) => right(FlowyError.fromBuffer(errBytes)),
         ));
     }
@@ -154,23 +154,6 @@ class GridEventDuplicateField {
     }
 }
 
-class GridEventGetEditFieldContext {
-     EditFieldPayload request;
-     GridEventGetEditFieldContext(this.request);
-
-    Future<Either<EditFieldContext, FlowyError>> send() {
-    final request = FFIRequest.create()
-          ..event = GridEvent.GetEditFieldContext.toString()
-          ..payload = requestToBytes(this.request);
-
-    return Dispatch.asyncRequest(request)
-        .then((bytesResult) => bytesResult.fold(
-           (okBytes) => left(EditFieldContext.fromBuffer(okBytes)),
-           (errBytes) => right(FlowyError.fromBuffer(errBytes)),
-        ));
-    }
-}
-
 class GridEventMoveItem {
      MoveItemPayload request;
      GridEventMoveItem(this.request);

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

@@ -578,16 +578,16 @@ class EditFieldPayload extends $pb.GeneratedMessage {
   void clearFieldType() => clearField(3);
 }
 
-class EditFieldContext extends $pb.GeneratedMessage {
-  static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'EditFieldContext', createEmptyInstance: create)
+class FieldTypeOptionContext extends $pb.GeneratedMessage {
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'FieldTypeOptionContext', createEmptyInstance: create)
     ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'gridId')
     ..aOM<Field>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'gridField', subBuilder: Field.create)
     ..a<$core.List<$core.int>>(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'typeOptionData', $pb.PbFieldType.OY)
     ..hasRequiredFields = false
   ;
 
-  EditFieldContext._() : super();
-  factory EditFieldContext({
+  FieldTypeOptionContext._() : super();
+  factory FieldTypeOptionContext({
     $core.String? gridId,
     Field? gridField,
     $core.List<$core.int>? typeOptionData,
@@ -604,26 +604,26 @@ class EditFieldContext extends $pb.GeneratedMessage {
     }
     return _result;
   }
-  factory EditFieldContext.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
-  factory EditFieldContext.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+  factory FieldTypeOptionContext.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory FieldTypeOptionContext.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')
-  EditFieldContext clone() => EditFieldContext()..mergeFromMessage(this);
+  FieldTypeOptionContext clone() => FieldTypeOptionContext()..mergeFromMessage(this);
   @$core.Deprecated(
   'Using this can add significant overhead to your binary. '
   'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
   'Will be removed in next major version')
-  EditFieldContext copyWith(void Function(EditFieldContext) updates) => super.copyWith((message) => updates(message as EditFieldContext)) as EditFieldContext; // ignore: deprecated_member_use
+  FieldTypeOptionContext copyWith(void Function(FieldTypeOptionContext) updates) => super.copyWith((message) => updates(message as FieldTypeOptionContext)) as FieldTypeOptionContext; // ignore: deprecated_member_use
   $pb.BuilderInfo get info_ => _i;
   @$core.pragma('dart2js:noInline')
-  static EditFieldContext create() => EditFieldContext._();
-  EditFieldContext createEmptyInstance() => create();
-  static $pb.PbList<EditFieldContext> createRepeated() => $pb.PbList<EditFieldContext>();
+  static FieldTypeOptionContext create() => FieldTypeOptionContext._();
+  FieldTypeOptionContext createEmptyInstance() => create();
+  static $pb.PbList<FieldTypeOptionContext> createRepeated() => $pb.PbList<FieldTypeOptionContext>();
   @$core.pragma('dart2js:noInline')
-  static EditFieldContext getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<EditFieldContext>(create);
-  static EditFieldContext? _defaultInstance;
+  static FieldTypeOptionContext getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<FieldTypeOptionContext>(create);
+  static FieldTypeOptionContext? _defaultInstance;
 
   @$pb.TagNumber(1)
   $core.String get gridId => $_getSZ(0);
@@ -657,19 +657,24 @@ class EditFieldContext extends $pb.GeneratedMessage {
 
 class FieldTypeOptionData extends $pb.GeneratedMessage {
   static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'FieldTypeOptionData', createEmptyInstance: create)
-    ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'fieldId')
-    ..a<$core.List<$core.int>>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'typeOptionData', $pb.PbFieldType.OY)
+    ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'gridId')
+    ..aOM<Field>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'field', subBuilder: Field.create)
+    ..a<$core.List<$core.int>>(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'typeOptionData', $pb.PbFieldType.OY)
     ..hasRequiredFields = false
   ;
 
   FieldTypeOptionData._() : super();
   factory FieldTypeOptionData({
-    $core.String? fieldId,
+    $core.String? gridId,
+    Field? field_2,
     $core.List<$core.int>? typeOptionData,
   }) {
     final _result = create();
-    if (fieldId != null) {
-      _result.fieldId = fieldId;
+    if (gridId != null) {
+      _result.gridId = gridId;
+    }
+    if (field_2 != null) {
+      _result.field_2 = field_2;
     }
     if (typeOptionData != null) {
       _result.typeOptionData = typeOptionData;
@@ -698,22 +703,33 @@ class FieldTypeOptionData extends $pb.GeneratedMessage {
   static FieldTypeOptionData? _defaultInstance;
 
   @$pb.TagNumber(1)
-  $core.String get fieldId => $_getSZ(0);
+  $core.String get gridId => $_getSZ(0);
   @$pb.TagNumber(1)
-  set fieldId($core.String v) { $_setString(0, v); }
+  set gridId($core.String v) { $_setString(0, v); }
   @$pb.TagNumber(1)
-  $core.bool hasFieldId() => $_has(0);
+  $core.bool hasGridId() => $_has(0);
   @$pb.TagNumber(1)
-  void clearFieldId() => clearField(1);
+  void clearGridId() => clearField(1);
 
   @$pb.TagNumber(2)
-  $core.List<$core.int> get typeOptionData => $_getN(1);
+  Field get field_2 => $_getN(1);
   @$pb.TagNumber(2)
-  set typeOptionData($core.List<$core.int> v) { $_setBytes(1, v); }
+  set field_2(Field v) { setField(2, v); }
   @$pb.TagNumber(2)
-  $core.bool hasTypeOptionData() => $_has(1);
+  $core.bool hasField_2() => $_has(1);
+  @$pb.TagNumber(2)
+  void clearField_2() => clearField(2);
   @$pb.TagNumber(2)
-  void clearTypeOptionData() => clearField(2);
+  Field ensureField_2() => $_ensure(1);
+
+  @$pb.TagNumber(3)
+  $core.List<$core.int> get typeOptionData => $_getN(2);
+  @$pb.TagNumber(3)
+  set typeOptionData($core.List<$core.int> v) { $_setBytes(2, v); }
+  @$pb.TagNumber(3)
+  $core.bool hasTypeOptionData() => $_has(2);
+  @$pb.TagNumber(3)
+  void clearTypeOptionData() => clearField(3);
 }
 
 class RepeatedField extends $pb.GeneratedMessage {

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

@@ -127,9 +127,9 @@ const EditFieldPayload$json = const {
 
 /// Descriptor for `EditFieldPayload`. Decode as a `google.protobuf.DescriptorProto`.
 final $typed_data.Uint8List editFieldPayloadDescriptor = $convert.base64Decode('ChBFZGl0RmllbGRQYXlsb2FkEhcKB2dyaWRfaWQYASABKAlSBmdyaWRJZBIbCghmaWVsZF9pZBgCIAEoCUgAUgdmaWVsZElkEikKCmZpZWxkX3R5cGUYAyABKA4yCi5GaWVsZFR5cGVSCWZpZWxkVHlwZUIRCg9vbmVfb2ZfZmllbGRfaWQ=');
-@$core.Deprecated('Use editFieldContextDescriptor instead')
-const EditFieldContext$json = const {
-  '1': 'EditFieldContext',
+@$core.Deprecated('Use fieldTypeOptionContextDescriptor instead')
+const FieldTypeOptionContext$json = const {
+  '1': 'FieldTypeOptionContext',
   '2': const [
     const {'1': 'grid_id', '3': 1, '4': 1, '5': 9, '10': 'gridId'},
     const {'1': 'grid_field', '3': 2, '4': 1, '5': 11, '6': '.Field', '10': 'gridField'},
@@ -137,19 +137,20 @@ const EditFieldContext$json = const {
   ],
 };
 
-/// Descriptor for `EditFieldContext`. Decode as a `google.protobuf.DescriptorProto`.
-final $typed_data.Uint8List editFieldContextDescriptor = $convert.base64Decode('ChBFZGl0RmllbGRDb250ZXh0EhcKB2dyaWRfaWQYASABKAlSBmdyaWRJZBIlCgpncmlkX2ZpZWxkGAIgASgLMgYuRmllbGRSCWdyaWRGaWVsZBIoChB0eXBlX29wdGlvbl9kYXRhGAMgASgMUg50eXBlT3B0aW9uRGF0YQ==');
+/// Descriptor for `FieldTypeOptionContext`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List fieldTypeOptionContextDescriptor = $convert.base64Decode('ChZGaWVsZFR5cGVPcHRpb25Db250ZXh0EhcKB2dyaWRfaWQYASABKAlSBmdyaWRJZBIlCgpncmlkX2ZpZWxkGAIgASgLMgYuRmllbGRSCWdyaWRGaWVsZBIoChB0eXBlX29wdGlvbl9kYXRhGAMgASgMUg50eXBlT3B0aW9uRGF0YQ==');
 @$core.Deprecated('Use fieldTypeOptionDataDescriptor instead')
 const FieldTypeOptionData$json = const {
   '1': 'FieldTypeOptionData',
   '2': const [
-    const {'1': 'field_id', '3': 1, '4': 1, '5': 9, '10': 'fieldId'},
-    const {'1': 'type_option_data', '3': 2, '4': 1, '5': 12, '10': 'typeOptionData'},
+    const {'1': 'grid_id', '3': 1, '4': 1, '5': 9, '10': 'gridId'},
+    const {'1': 'field', '3': 2, '4': 1, '5': 11, '6': '.Field', '10': 'field'},
+    const {'1': 'type_option_data', '3': 3, '4': 1, '5': 12, '10': 'typeOptionData'},
   ],
 };
 
 /// Descriptor for `FieldTypeOptionData`. Decode as a `google.protobuf.DescriptorProto`.
-final $typed_data.Uint8List fieldTypeOptionDataDescriptor = $convert.base64Decode('ChNGaWVsZFR5cGVPcHRpb25EYXRhEhkKCGZpZWxkX2lkGAEgASgJUgdmaWVsZElkEigKEHR5cGVfb3B0aW9uX2RhdGEYAiABKAxSDnR5cGVPcHRpb25EYXRh');
+final $typed_data.Uint8List fieldTypeOptionDataDescriptor = $convert.base64Decode('ChNGaWVsZFR5cGVPcHRpb25EYXRhEhcKB2dyaWRfaWQYASABKAlSBmdyaWRJZBIcCgVmaWVsZBgCIAEoCzIGLkZpZWxkUgVmaWVsZBIoChB0eXBlX29wdGlvbl9kYXRhGAMgASgMUg50eXBlT3B0aW9uRGF0YQ==');
 @$core.Deprecated('Use repeatedFieldDescriptor instead')
 const RepeatedField$json = const {
   '1': 'RepeatedField',

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

@@ -19,9 +19,8 @@ class GridEvent extends $pb.ProtobufEnum {
   static const GridEvent DeleteField = GridEvent._(14, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DeleteField');
   static const GridEvent SwitchToField = GridEvent._(20, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'SwitchToField');
   static const GridEvent DuplicateField = GridEvent._(21, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DuplicateField');
-  static const GridEvent GetEditFieldContext = GridEvent._(22, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'GetEditFieldContext');
-  static const GridEvent MoveItem = GridEvent._(23, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'MoveItem');
-  static const GridEvent GetFieldTypeOption = GridEvent._(24, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'GetFieldTypeOption');
+  static const GridEvent MoveItem = GridEvent._(22, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'MoveItem');
+  static const GridEvent GetFieldTypeOption = GridEvent._(23, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'GetFieldTypeOption');
   static const GridEvent NewSelectOption = GridEvent._(30, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'NewSelectOption');
   static const GridEvent GetSelectOptionCellData = GridEvent._(31, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'GetSelectOptionCellData');
   static const GridEvent UpdateSelectOption = GridEvent._(32, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UpdateSelectOption');
@@ -45,7 +44,6 @@ class GridEvent extends $pb.ProtobufEnum {
     DeleteField,
     SwitchToField,
     DuplicateField,
-    GetEditFieldContext,
     MoveItem,
     GetFieldTypeOption,
     NewSelectOption,

+ 3 - 4
frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/event_map.pbjson.dart

@@ -21,9 +21,8 @@ const GridEvent$json = const {
     const {'1': 'DeleteField', '2': 14},
     const {'1': 'SwitchToField', '2': 20},
     const {'1': 'DuplicateField', '2': 21},
-    const {'1': 'GetEditFieldContext', '2': 22},
-    const {'1': 'MoveItem', '2': 23},
-    const {'1': 'GetFieldTypeOption', '2': 24},
+    const {'1': 'MoveItem', '2': 22},
+    const {'1': 'GetFieldTypeOption', '2': 23},
     const {'1': 'NewSelectOption', '2': 30},
     const {'1': 'GetSelectOptionCellData', '2': 31},
     const {'1': 'UpdateSelectOption', '2': 32},
@@ -40,4 +39,4 @@ const GridEvent$json = const {
 };
 
 /// Descriptor for `GridEvent`. Decode as a `google.protobuf.EnumDescriptorProto`.
-final $typed_data.Uint8List gridEventDescriptor = $convert.base64Decode('CglHcmlkRXZlbnQSDwoLR2V0R3JpZERhdGEQABIRCg1HZXRHcmlkQmxvY2tzEAESDQoJR2V0RmllbGRzEAoSDwoLVXBkYXRlRmllbGQQCxIZChVVcGRhdGVGaWVsZFR5cGVPcHRpb24QDBIPCgtJbnNlcnRGaWVsZBANEg8KC0RlbGV0ZUZpZWxkEA4SEQoNU3dpdGNoVG9GaWVsZBAUEhIKDkR1cGxpY2F0ZUZpZWxkEBUSFwoTR2V0RWRpdEZpZWxkQ29udGV4dBAWEgwKCE1vdmVJdGVtEBcSFgoSR2V0RmllbGRUeXBlT3B0aW9uEBgSEwoPTmV3U2VsZWN0T3B0aW9uEB4SGwoXR2V0U2VsZWN0T3B0aW9uQ2VsbERhdGEQHxIWChJVcGRhdGVTZWxlY3RPcHRpb24QIBINCglDcmVhdGVSb3cQMhIKCgZHZXRSb3cQMxINCglEZWxldGVSb3cQNBIQCgxEdXBsaWNhdGVSb3cQNRILCgdHZXRDZWxsEEYSDgoKVXBkYXRlQ2VsbBBHEhoKFlVwZGF0ZVNlbGVjdE9wdGlvbkNlbGwQSBISCg5VcGRhdGVEYXRlQ2VsbBBQEhMKD0dldERhdGVDZWxsRGF0YRBa');
+final $typed_data.Uint8List gridEventDescriptor = $convert.base64Decode('CglHcmlkRXZlbnQSDwoLR2V0R3JpZERhdGEQABIRCg1HZXRHcmlkQmxvY2tzEAESDQoJR2V0RmllbGRzEAoSDwoLVXBkYXRlRmllbGQQCxIZChVVcGRhdGVGaWVsZFR5cGVPcHRpb24QDBIPCgtJbnNlcnRGaWVsZBANEg8KC0RlbGV0ZUZpZWxkEA4SEQoNU3dpdGNoVG9GaWVsZBAUEhIKDkR1cGxpY2F0ZUZpZWxkEBUSDAoITW92ZUl0ZW0QFhIWChJHZXRGaWVsZFR5cGVPcHRpb24QFxITCg9OZXdTZWxlY3RPcHRpb24QHhIbChdHZXRTZWxlY3RPcHRpb25DZWxsRGF0YRAfEhYKElVwZGF0ZVNlbGVjdE9wdGlvbhAgEg0KCUNyZWF0ZVJvdxAyEgoKBkdldFJvdxAzEg0KCURlbGV0ZVJvdxA0EhAKDER1cGxpY2F0ZVJvdxA1EgsKB0dldENlbGwQRhIOCgpVcGRhdGVDZWxsEEcSGgoWVXBkYXRlU2VsZWN0T3B0aW9uQ2VsbBBIEhIKDlVwZGF0ZURhdGVDZWxsEFASEwoPR2V0RGF0ZUNlbGxEYXRhEFo=');

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

@@ -98,7 +98,7 @@ pub(crate) async fn delete_field_handler(
 pub(crate) async fn switch_to_field_handler(
     data: Data<EditFieldPayload>,
     manager: AppData<Arc<GridManager>>,
-) -> DataResult<EditFieldContext, FlowyError> {
+) -> DataResult<FieldTypeOptionData, FlowyError> {
     let params: EditFieldParams = data.into_inner().try_into()?;
     if params.field_id.is_none() {
         return Err(ErrorCode::FieldIdIsEmpty.into());
@@ -107,9 +107,9 @@ pub(crate) async fn switch_to_field_handler(
     let editor = manager.get_grid_editor(&params.grid_id)?;
     editor.switch_to_field_type(&field_id, &params.field_type).await?;
     let field_meta = editor.get_field_meta(&field_id).await;
-    let edit_context =
-        make_edit_field_context(&params.grid_id, Some(field_id), params.field_type, editor, field_meta).await?;
-    data_result(edit_context)
+    let data =
+        make_field_type_option_data(&params.grid_id, Some(field_id), params.field_type, editor, field_meta).await?;
+    data_result(data)
 }
 
 #[tracing::instrument(level = "debug", skip(data, manager), err)]
@@ -123,19 +123,6 @@ pub(crate) async fn duplicate_field_handler(
     Ok(())
 }
 
-#[tracing::instrument(level = "debug", skip(data, manager), err)]
-pub(crate) async fn get_field_context_handler(
-    data: Data<EditFieldPayload>,
-    manager: AppData<Arc<GridManager>>,
-) -> DataResult<EditFieldContext, FlowyError> {
-    let params: EditFieldParams = data.into_inner().try_into()?;
-    let editor = manager.get_grid_editor(&params.grid_id)?;
-    let edit_context =
-        make_edit_field_context(&params.grid_id, params.field_id, params.field_type, editor, None).await?;
-
-    data_result(edit_context)
-}
-
 #[tracing::instrument(level = "debug", skip(data, manager), err)]
 pub(crate) async fn get_field_type_option_data_handler(
     data: Data<EditFieldPayload>,
@@ -147,7 +134,8 @@ pub(crate) async fn get_field_type_option_data_handler(
     let type_option_data = get_type_option_data(&field_meta, &field_meta.field_type).await?;
 
     data_result(FieldTypeOptionData {
-        field_id: field_meta.id.clone(),
+        grid_id: params.grid_id,
+        field: field_meta.into(),
         type_option_data,
     })
 }
@@ -163,23 +151,24 @@ pub(crate) async fn move_item_handler(
     Ok(())
 }
 
-async fn make_edit_field_context(
+async fn make_field_type_option_data(
     grid_id: &str,
     field_id: Option<String>,
     field_type: FieldType,
     editor: Arc<ClientGridEditor>,
     field_meta: Option<FieldMeta>,
-) -> FlowyResult<EditFieldContext> {
+) -> FlowyResult<FieldTypeOptionData> {
     let field_meta = field_meta.unwrap_or(get_or_create_field_meta(field_id, &field_type, editor).await?);
     let type_option_data = get_type_option_data(&field_meta, &field_type).await?;
-    let field: Field = field_meta.into();
-    Ok(EditFieldContext {
+
+    Ok(FieldTypeOptionData {
         grid_id: grid_id.to_string(),
-        grid_field: field,
+        field: field_meta.into(),
         type_option_data,
     })
 }
 
+/// The FieldMeta contains multiple data, each of them belongs to a specific FieldType.
 async fn get_type_option_data(field_meta: &FieldMeta, field_type: &FieldType) -> FlowyResult<Vec<u8>> {
     let s = field_meta
         .get_type_option_str(field_type)

+ 3 - 7
frontend/rust-lib/flowy-grid/src/event_map.rs

@@ -18,7 +18,6 @@ pub fn create(grid_manager: Arc<GridManager>) -> Module {
         .event(GridEvent::DeleteField, delete_field_handler)
         .event(GridEvent::SwitchToField, switch_to_field_handler)
         .event(GridEvent::DuplicateField, duplicate_field_handler)
-        .event(GridEvent::GetEditFieldContext, get_field_context_handler)
         .event(GridEvent::MoveItem, move_item_handler)
         .event(GridEvent::GetFieldTypeOption, get_field_type_option_data_handler)
         // Row
@@ -65,20 +64,17 @@ pub enum GridEvent {
     #[event(input = "FieldIdentifierPayload")]
     DeleteField = 14,
 
-    #[event(input = "EditFieldPayload", output = "EditFieldContext")]
+    #[event(input = "EditFieldPayload", output = "FieldTypeOptionData")]
     SwitchToField = 20,
 
     #[event(input = "FieldIdentifierPayload")]
     DuplicateField = 21,
 
-    #[event(input = "EditFieldPayload", output = "EditFieldContext")]
-    GetEditFieldContext = 22,
-
     #[event(input = "MoveItemPayload")]
-    MoveItem = 23,
+    MoveItem = 22,
 
     #[event(input = "EditFieldPayload", output = "FieldTypeOptionData")]
-    GetFieldTypeOption = 24,
+    GetFieldTypeOption = 23,
 
     #[event(input = "CreateSelectOptionPayload", output = "SelectOption")]
     NewSelectOption = 30,

+ 13 - 16
frontend/rust-lib/flowy-grid/src/protobuf/model/event_map.rs

@@ -34,9 +34,8 @@ pub enum GridEvent {
     DeleteField = 14,
     SwitchToField = 20,
     DuplicateField = 21,
-    GetEditFieldContext = 22,
-    MoveItem = 23,
-    GetFieldTypeOption = 24,
+    MoveItem = 22,
+    GetFieldTypeOption = 23,
     NewSelectOption = 30,
     GetSelectOptionCellData = 31,
     UpdateSelectOption = 32,
@@ -67,9 +66,8 @@ impl ::protobuf::ProtobufEnum for GridEvent {
             14 => ::std::option::Option::Some(GridEvent::DeleteField),
             20 => ::std::option::Option::Some(GridEvent::SwitchToField),
             21 => ::std::option::Option::Some(GridEvent::DuplicateField),
-            22 => ::std::option::Option::Some(GridEvent::GetEditFieldContext),
-            23 => ::std::option::Option::Some(GridEvent::MoveItem),
-            24 => ::std::option::Option::Some(GridEvent::GetFieldTypeOption),
+            22 => ::std::option::Option::Some(GridEvent::MoveItem),
+            23 => ::std::option::Option::Some(GridEvent::GetFieldTypeOption),
             30 => ::std::option::Option::Some(GridEvent::NewSelectOption),
             31 => ::std::option::Option::Some(GridEvent::GetSelectOptionCellData),
             32 => ::std::option::Option::Some(GridEvent::UpdateSelectOption),
@@ -97,7 +95,6 @@ impl ::protobuf::ProtobufEnum for GridEvent {
             GridEvent::DeleteField,
             GridEvent::SwitchToField,
             GridEvent::DuplicateField,
-            GridEvent::GetEditFieldContext,
             GridEvent::MoveItem,
             GridEvent::GetFieldTypeOption,
             GridEvent::NewSelectOption,
@@ -140,18 +137,18 @@ impl ::protobuf::reflect::ProtobufValue for GridEvent {
 }
 
 static file_descriptor_proto_data: &'static [u8] = b"\
-    \n\x0fevent_map.proto*\xda\x03\n\tGridEvent\x12\x0f\n\x0bGetGridData\x10\
+    \n\x0fevent_map.proto*\xc1\x03\n\tGridEvent\x12\x0f\n\x0bGetGridData\x10\
     \0\x12\x11\n\rGetGridBlocks\x10\x01\x12\r\n\tGetFields\x10\n\x12\x0f\n\
     \x0bUpdateField\x10\x0b\x12\x19\n\x15UpdateFieldTypeOption\x10\x0c\x12\
     \x0f\n\x0bInsertField\x10\r\x12\x0f\n\x0bDeleteField\x10\x0e\x12\x11\n\r\
-    SwitchToField\x10\x14\x12\x12\n\x0eDuplicateField\x10\x15\x12\x17\n\x13G\
-    etEditFieldContext\x10\x16\x12\x0c\n\x08MoveItem\x10\x17\x12\x16\n\x12Ge\
-    tFieldTypeOption\x10\x18\x12\x13\n\x0fNewSelectOption\x10\x1e\x12\x1b\n\
-    \x17GetSelectOptionCellData\x10\x1f\x12\x16\n\x12UpdateSelectOption\x10\
-    \x20\x12\r\n\tCreateRow\x102\x12\n\n\x06GetRow\x103\x12\r\n\tDeleteRow\
-    \x104\x12\x10\n\x0cDuplicateRow\x105\x12\x0b\n\x07GetCell\x10F\x12\x0e\n\
-    \nUpdateCell\x10G\x12\x1a\n\x16UpdateSelectOptionCell\x10H\x12\x12\n\x0e\
-    UpdateDateCell\x10P\x12\x13\n\x0fGetDateCellData\x10Zb\x06proto3\
+    SwitchToField\x10\x14\x12\x12\n\x0eDuplicateField\x10\x15\x12\x0c\n\x08M\
+    oveItem\x10\x16\x12\x16\n\x12GetFieldTypeOption\x10\x17\x12\x13\n\x0fNew\
+    SelectOption\x10\x1e\x12\x1b\n\x17GetSelectOptionCellData\x10\x1f\x12\
+    \x16\n\x12UpdateSelectOption\x10\x20\x12\r\n\tCreateRow\x102\x12\n\n\x06\
+    GetRow\x103\x12\r\n\tDeleteRow\x104\x12\x10\n\x0cDuplicateRow\x105\x12\
+    \x0b\n\x07GetCell\x10F\x12\x0e\n\nUpdateCell\x10G\x12\x1a\n\x16UpdateSel\
+    ectOptionCell\x10H\x12\x12\n\x0eUpdateDateCell\x10P\x12\x13\n\x0fGetDate\
+    CellData\x10Zb\x06proto3\
 ";
 
 static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;

+ 2 - 3
frontend/rust-lib/flowy-grid/src/protobuf/proto/event_map.proto

@@ -10,9 +10,8 @@ enum GridEvent {
     DeleteField = 14;
     SwitchToField = 20;
     DuplicateField = 21;
-    GetEditFieldContext = 22;
-    MoveItem = 23;
-    GetFieldTypeOption = 24;
+    MoveItem = 22;
+    GetFieldTypeOption = 23;
     NewSelectOption = 30;
     GetSelectOptionCellData = 31;
     UpdateSelectOption = 32;

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

@@ -195,7 +195,7 @@ impl TryInto<EditFieldParams> for EditFieldPayload {
 }
 
 #[derive(Debug, Default, ProtoBuf)]
-pub struct EditFieldContext {
+pub struct FieldTypeOptionContext {
     #[pb(index = 1)]
     pub grid_id: String,
 
@@ -209,9 +209,12 @@ pub struct EditFieldContext {
 #[derive(Debug, Default, ProtoBuf)]
 pub struct FieldTypeOptionData {
     #[pb(index = 1)]
-    pub field_id: String,
+    pub grid_id: String,
 
     #[pb(index = 2)]
+    pub field_id: String,
+
+    #[pb(index = 3)]
     pub type_option_data: Vec<u8>,
 }
 

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

@@ -1913,7 +1913,7 @@ impl ::protobuf::reflect::ProtobufValue for EditFieldPayload {
 }
 
 #[derive(PartialEq,Clone,Default)]
-pub struct EditFieldContext {
+pub struct FieldTypeOptionContext {
     // message fields
     pub grid_id: ::std::string::String,
     pub grid_field: ::protobuf::SingularPtrField<Field>,
@@ -1923,14 +1923,14 @@ pub struct EditFieldContext {
     pub cached_size: ::protobuf::CachedSize,
 }
 
-impl<'a> ::std::default::Default for &'a EditFieldContext {
-    fn default() -> &'a EditFieldContext {
-        <EditFieldContext as ::protobuf::Message>::default_instance()
+impl<'a> ::std::default::Default for &'a FieldTypeOptionContext {
+    fn default() -> &'a FieldTypeOptionContext {
+        <FieldTypeOptionContext as ::protobuf::Message>::default_instance()
     }
 }
 
-impl EditFieldContext {
-    pub fn new() -> EditFieldContext {
+impl FieldTypeOptionContext {
+    pub fn new() -> FieldTypeOptionContext {
         ::std::default::Default::default()
     }
 
@@ -2020,7 +2020,7 @@ impl EditFieldContext {
     }
 }
 
-impl ::protobuf::Message for EditFieldContext {
+impl ::protobuf::Message for FieldTypeOptionContext {
     fn is_initialized(&self) -> bool {
         for v in &self.grid_field {
             if !v.is_initialized() {
@@ -2112,8 +2112,8 @@ impl ::protobuf::Message for EditFieldContext {
         Self::descriptor_static()
     }
 
-    fn new() -> EditFieldContext {
-        EditFieldContext::new()
+    fn new() -> FieldTypeOptionContext {
+        FieldTypeOptionContext::new()
     }
 
     fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor {
@@ -2122,34 +2122,34 @@ impl ::protobuf::Message for EditFieldContext {
             let mut fields = ::std::vec::Vec::new();
             fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
                 "grid_id",
-                |m: &EditFieldContext| { &m.grid_id },
-                |m: &mut EditFieldContext| { &mut m.grid_id },
+                |m: &FieldTypeOptionContext| { &m.grid_id },
+                |m: &mut FieldTypeOptionContext| { &mut m.grid_id },
             ));
             fields.push(::protobuf::reflect::accessor::make_singular_ptr_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage<Field>>(
                 "grid_field",
-                |m: &EditFieldContext| { &m.grid_field },
-                |m: &mut EditFieldContext| { &mut m.grid_field },
+                |m: &FieldTypeOptionContext| { &m.grid_field },
+                |m: &mut FieldTypeOptionContext| { &mut m.grid_field },
             ));
             fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBytes>(
                 "type_option_data",
-                |m: &EditFieldContext| { &m.type_option_data },
-                |m: &mut EditFieldContext| { &mut m.type_option_data },
+                |m: &FieldTypeOptionContext| { &m.type_option_data },
+                |m: &mut FieldTypeOptionContext| { &mut m.type_option_data },
             ));
-            ::protobuf::reflect::MessageDescriptor::new_pb_name::<EditFieldContext>(
-                "EditFieldContext",
+            ::protobuf::reflect::MessageDescriptor::new_pb_name::<FieldTypeOptionContext>(
+                "FieldTypeOptionContext",
                 fields,
                 file_descriptor_proto()
             )
         })
     }
 
-    fn default_instance() -> &'static EditFieldContext {
-        static instance: ::protobuf::rt::LazyV2<EditFieldContext> = ::protobuf::rt::LazyV2::INIT;
-        instance.get(EditFieldContext::new)
+    fn default_instance() -> &'static FieldTypeOptionContext {
+        static instance: ::protobuf::rt::LazyV2<FieldTypeOptionContext> = ::protobuf::rt::LazyV2::INIT;
+        instance.get(FieldTypeOptionContext::new)
     }
 }
 
-impl ::protobuf::Clear for EditFieldContext {
+impl ::protobuf::Clear for FieldTypeOptionContext {
     fn clear(&mut self) {
         self.grid_id.clear();
         self.grid_field.clear();
@@ -2158,13 +2158,13 @@ impl ::protobuf::Clear for EditFieldContext {
     }
 }
 
-impl ::std::fmt::Debug for EditFieldContext {
+impl ::std::fmt::Debug for FieldTypeOptionContext {
     fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
         ::protobuf::text_format::fmt(self, f)
     }
 }
 
-impl ::protobuf::reflect::ProtobufValue for EditFieldContext {
+impl ::protobuf::reflect::ProtobufValue for FieldTypeOptionContext {
     fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
         ::protobuf::reflect::ReflectValueRef::Message(self)
     }
@@ -2173,6 +2173,7 @@ impl ::protobuf::reflect::ProtobufValue for EditFieldContext {
 #[derive(PartialEq,Clone,Default)]
 pub struct FieldTypeOptionData {
     // message fields
+    pub grid_id: ::std::string::String,
     pub field_id: ::std::string::String,
     pub type_option_data: ::std::vec::Vec<u8>,
     // special fields
@@ -2191,7 +2192,33 @@ impl FieldTypeOptionData {
         ::std::default::Default::default()
     }
 
-    // string field_id = 1;
+    // string grid_id = 1;
+
+
+    pub fn get_grid_id(&self) -> &str {
+        &self.grid_id
+    }
+    pub fn clear_grid_id(&mut self) {
+        self.grid_id.clear();
+    }
+
+    // Param is passed by value, moved
+    pub fn set_grid_id(&mut self, v: ::std::string::String) {
+        self.grid_id = v;
+    }
+
+    // Mutable pointer to the field.
+    // If field is not initialized, it is initialized with default value first.
+    pub fn mut_grid_id(&mut self) -> &mut ::std::string::String {
+        &mut self.grid_id
+    }
+
+    // Take field
+    pub fn take_grid_id(&mut self) -> ::std::string::String {
+        ::std::mem::replace(&mut self.grid_id, ::std::string::String::new())
+    }
+
+    // string field_id = 2;
 
 
     pub fn get_field_id(&self) -> &str {
@@ -2217,7 +2244,7 @@ impl FieldTypeOptionData {
         ::std::mem::replace(&mut self.field_id, ::std::string::String::new())
     }
 
-    // bytes type_option_data = 2;
+    // bytes type_option_data = 3;
 
 
     pub fn get_type_option_data(&self) -> &[u8] {
@@ -2254,9 +2281,12 @@ impl ::protobuf::Message for FieldTypeOptionData {
             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.field_id)?;
+                    ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.grid_id)?;
                 },
                 2 => {
+                    ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.field_id)?;
+                },
+                3 => {
                     ::protobuf::rt::read_singular_proto3_bytes_into(wire_type, is, &mut self.type_option_data)?;
                 },
                 _ => {
@@ -2271,11 +2301,14 @@ impl ::protobuf::Message for FieldTypeOptionData {
     #[allow(unused_variables)]
     fn compute_size(&self) -> u32 {
         let mut my_size = 0;
+        if !self.grid_id.is_empty() {
+            my_size += ::protobuf::rt::string_size(1, &self.grid_id);
+        }
         if !self.field_id.is_empty() {
-            my_size += ::protobuf::rt::string_size(1, &self.field_id);
+            my_size += ::protobuf::rt::string_size(2, &self.field_id);
         }
         if !self.type_option_data.is_empty() {
-            my_size += ::protobuf::rt::bytes_size(2, &self.type_option_data);
+            my_size += ::protobuf::rt::bytes_size(3, &self.type_option_data);
         }
         my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
         self.cached_size.set(my_size);
@@ -2283,11 +2316,14 @@ impl ::protobuf::Message for FieldTypeOptionData {
     }
 
     fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> {
+        if !self.grid_id.is_empty() {
+            os.write_string(1, &self.grid_id)?;
+        }
         if !self.field_id.is_empty() {
-            os.write_string(1, &self.field_id)?;
+            os.write_string(2, &self.field_id)?;
         }
         if !self.type_option_data.is_empty() {
-            os.write_bytes(2, &self.type_option_data)?;
+            os.write_bytes(3, &self.type_option_data)?;
         }
         os.write_unknown_fields(self.get_unknown_fields())?;
         ::std::result::Result::Ok(())
@@ -2327,6 +2363,11 @@ impl ::protobuf::Message for FieldTypeOptionData {
         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>(
+                "grid_id",
+                |m: &FieldTypeOptionData| { &m.grid_id },
+                |m: &mut FieldTypeOptionData| { &mut m.grid_id },
+            ));
             fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
                 "field_id",
                 |m: &FieldTypeOptionData| { &m.field_id },
@@ -2353,6 +2394,7 @@ impl ::protobuf::Message for FieldTypeOptionData {
 
 impl ::protobuf::Clear for FieldTypeOptionData {
     fn clear(&mut self) {
+        self.grid_id.clear();
         self.field_id.clear();
         self.type_option_data.clear();
         self.unknown_fields.clear();
@@ -8257,27 +8299,28 @@ static file_descriptor_proto_data: &'static [u8] = b"\
     \x86\x01\n\x10EditFieldPayload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\
     \x06gridId\x12\x1b\n\x08field_id\x18\x02\x20\x01(\tH\0R\x07fieldId\x12)\
     \n\nfield_type\x18\x03\x20\x01(\x0e2\n.FieldTypeR\tfieldTypeB\x11\n\x0fo\
-    ne_of_field_id\"|\n\x10EditFieldContext\x12\x17\n\x07grid_id\x18\x01\x20\
-    \x01(\tR\x06gridId\x12%\n\ngrid_field\x18\x02\x20\x01(\x0b2\x06.FieldR\t\
-    gridField\x12(\n\x10type_option_data\x18\x03\x20\x01(\x0cR\x0etypeOption\
-    Data\"Z\n\x13FieldTypeOptionData\x12\x19\n\x08field_id\x18\x01\x20\x01(\
-    \tR\x07fieldId\x12(\n\x10type_option_data\x18\x02\x20\x01(\x0cR\x0etypeO\
-    ptionData\"-\n\rRepeatedField\x12\x1c\n\x05items\x18\x01\x20\x03(\x0b2\
-    \x06.FieldR\x05items\"7\n\x12RepeatedFieldOrder\x12!\n\x05items\x18\x01\
-    \x20\x03(\x0b2\x0b.FieldOrderR\x05items\"T\n\x08RowOrder\x12\x15\n\x06ro\
-    w_id\x18\x01\x20\x01(\tR\x05rowId\x12\x19\n\x08block_id\x18\x02\x20\x01(\
-    \tR\x07blockId\x12\x16\n\x06height\x18\x03\x20\x01(\x05R\x06height\"\xb8\
-    \x01\n\x03Row\x12\x0e\n\x02id\x18\x01\x20\x01(\tR\x02id\x12@\n\x10cell_b\
-    y_field_id\x18\x02\x20\x03(\x0b2\x17.Row.CellByFieldIdEntryR\rcellByFiel\
-    dId\x12\x16\n\x06height\x18\x03\x20\x01(\x05R\x06height\x1aG\n\x12CellBy\
-    FieldIdEntry\x12\x10\n\x03key\x18\x01\x20\x01(\tR\x03key\x12\x1b\n\x05va\
-    lue\x18\x02\x20\x01(\x0b2\x05.CellR\x05value:\x028\x01\")\n\x0bRepeatedR\
-    ow\x12\x1a\n\x05items\x18\x01\x20\x03(\x0b2\x04.RowR\x05items\"5\n\x11Re\
-    peatedGridBlock\x12\x20\n\x05items\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\trow\
-    Orders\"_\n\rIndexRowOrder\x12&\n\trow_order\x18\x01\x20\x01(\x0b2\t.Row\
-    OrderR\x08rowOrder\x12\x16\n\x05index\x18\x02\x20\x01(\x05H\0R\x05indexB\
+    ne_of_field_id\"\x82\x01\n\x16FieldTypeOptionContext\x12\x17\n\x07grid_i\
+    d\x18\x01\x20\x01(\tR\x06gridId\x12%\n\ngrid_field\x18\x02\x20\x01(\x0b2\
+    \x06.FieldR\tgridField\x12(\n\x10type_option_data\x18\x03\x20\x01(\x0cR\
+    \x0etypeOptionData\"s\n\x13FieldTypeOptionData\x12\x17\n\x07grid_id\x18\
+    \x01\x20\x01(\tR\x06gridId\x12\x19\n\x08field_id\x18\x02\x20\x01(\tR\x07\
+    fieldId\x12(\n\x10type_option_data\x18\x03\x20\x01(\x0cR\x0etypeOptionDa\
+    ta\"-\n\rRepeatedField\x12\x1c\n\x05items\x18\x01\x20\x03(\x0b2\x06.Fiel\
+    dR\x05items\"7\n\x12RepeatedFieldOrder\x12!\n\x05items\x18\x01\x20\x03(\
+    \x0b2\x0b.FieldOrderR\x05items\"T\n\x08RowOrder\x12\x15\n\x06row_id\x18\
+    \x01\x20\x01(\tR\x05rowId\x12\x19\n\x08block_id\x18\x02\x20\x01(\tR\x07b\
+    lockId\x12\x16\n\x06height\x18\x03\x20\x01(\x05R\x06height\"\xb8\x01\n\
+    \x03Row\x12\x0e\n\x02id\x18\x01\x20\x01(\tR\x02id\x12@\n\x10cell_by_fiel\
+    d_id\x18\x02\x20\x03(\x0b2\x17.Row.CellByFieldIdEntryR\rcellByFieldId\
+    \x12\x16\n\x06height\x18\x03\x20\x01(\x05R\x06height\x1aG\n\x12CellByFie\
+    ldIdEntry\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\x05items\"5\n\x11Repe\
+    atedGridBlock\x12\x20\n\x05items\x18\x01\x20\x03(\x0b2\n.GridBlockR\x05i\
+    tems\"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\trowOrd\
+    ers\"_\n\rIndexRowOrder\x12&\n\trow_order\x18\x01\x20\x01(\x0b2\t.RowOrd\
+    erR\x08rowOrder\x12\x16\n\x05index\x18\x02\x20\x01(\x05H\0R\x05indexB\
     \x0e\n\x0cone_of_index\"Q\n\x0fUpdatedRowOrder\x12&\n\trow_order\x18\x01\
     \x20\x01(\x0b2\t.RowOrderR\x08rowOrder\x12\x16\n\x03row\x18\x02\x20\x01(\
     \x0b2\x04.RowR\x03row\"\xc6\x01\n\x11GridRowsChangeset\x12\x19\n\x08bloc\

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

@@ -38,14 +38,15 @@ message EditFieldPayload {
     oneof one_of_field_id { string field_id = 2; };
     FieldType field_type = 3;
 }
-message EditFieldContext {
+message FieldTypeOptionContext {
     string grid_id = 1;
     Field grid_field = 2;
     bytes type_option_data = 3;
 }
 message FieldTypeOptionData {
-    string field_id = 1;
-    bytes type_option_data = 2;
+    string grid_id = 1;
+    string field_id = 2;
+    bytes type_option_data = 3;
 }
 message RepeatedField {
     repeated Field items = 1;

+ 1 - 0
shared-lib/lib-infra/Cargo.toml

@@ -16,6 +16,7 @@ rand = "0.8.5"
 serde = { version = "1.0", features = ["derive"]}
 serde_json = "1.0"
 
+
 cmd_lib = { version = "1", optional = true }
 protoc-rust = { version = "2", optional = true }
 walkdir = { version = "2", optional = true }

+ 31 - 6
shared-lib/lib-infra/src/code_gen/protobuf_file/mod.rs

@@ -7,6 +7,7 @@ mod proto_info;
 mod template;
 
 use crate::code_gen::util::path_string_with_component;
+use itertools::Itertools;
 use log::info;
 pub use proto_gen::*;
 pub use proto_info::*;
@@ -132,7 +133,7 @@ fn generate_dart_protobuf_files(
     }
 }
 
-fn check_pb_dart_plugin() {
+pub fn check_pb_dart_plugin() {
     if cfg!(target_os = "windows") {
         //Command::new("cmd")
         //    .arg("/C")
@@ -141,15 +142,39 @@ fn check_pb_dart_plugin() {
         //    .expect("failed to execute process");
         //panic!("{}", format!("\n❌ The protoc-gen-dart was not installed correctly."))
     } else {
-        let is_success = Command::new("sh")
+        let exit_result = Command::new("sh")
             .arg("-c")
             .arg("command -v protoc-gen-dart")
             .status()
-            .expect("failed to execute process")
-            .success();
+            .expect("failed to execute process");
+
+        if !exit_result.success() {
+            let mut msg = "\n❌ Can't find protoc-gen-dart in $PATH:\n".to_string();
+            let output = Command::new("sh").arg("-c").arg("echo $PATH").output();
+            let paths = String::from_utf8(output.unwrap().stdout)
+                .unwrap()
+                .split(":")
+                .map(|s| s.to_string())
+                .collect::<Vec<String>>();
+
+            paths.iter().for_each(|s| msg.push_str(&format!("{}\n", s)));
+
+            match Command::new("sh").arg("-c").arg("which protoc-gen-dart").output() {
+                Ok(output) => {
+                    msg.push_str(&format!(
+                        "Installed protoc-gen-dart path: {:?}\n",
+                        String::from_utf8(output.stdout).unwrap()
+                    ));
+                }
+                Err(_) => {}
+            }
 
-        if !is_success {
-            panic!("{}", format!("\n❌ The protoc-gen-dart was not installed correctly. \n✅ You can fix that by adding \"{}\" to your shell's config file.(.bashrc, .bash, etc.)", "dart pub global activate protoc_plugin"))
+            msg.push_str(&format!("✅ You can fix that by adding:"));
+            msg.push_str(&format!("\n\texport PATH=\"$PATH\":\"$HOME/.pub-cache/bin\"\n",));
+            msg.push_str(&format!(
+                "to your shell's config file.(.bashrc, .bash, .profile, .zshrc etc.)"
+            ));
+            panic!("{}", msg)
         }
     }
 }