Browse Source

chore: fix bugs

appflowy 3 years ago
parent
commit
23900b49f5
20 changed files with 322 additions and 260 deletions
  1. 3 3
      frontend/app_flowy/lib/workspace/application/grid/field/field_editor_bloc.dart
  2. 26 40
      frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart
  3. 1 1
      frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_cell.dart
  4. 1 2
      frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_editor.dart
  5. 26 4
      frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_name_input.dart
  6. 1 1
      frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/row_detail.dart
  7. 1 1
      frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_property.dart
  8. 17 0
      frontend/app_flowy/packages/flowy_sdk/lib/dispatch/dart_event/flowy-grid/dart_event.dart
  9. 14 13
      frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pb.dart
  10. 3 5
      frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pbjson.dart
  11. 2 0
      frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/event_map.pbenum.dart
  12. 2 1
      frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/event_map.pbjson.dart
  13. 41 41
      frontend/rust-lib/flowy-grid/src/event_handler.rs
  14. 4 0
      frontend/rust-lib/flowy-grid/src/event_map.rs
  15. 11 8
      frontend/rust-lib/flowy-grid/src/protobuf/model/event_map.rs
  16. 1 0
      frontend/rust-lib/flowy-grid/src/protobuf/proto/event_map.proto
  17. 11 1
      frontend/rust-lib/flowy-grid/src/services/grid_editor.rs
  18. 26 5
      shared-lib/flowy-grid-data-model/src/entities/grid.rs
  19. 129 133
      shared-lib/flowy-grid-data-model/src/protobuf/model/grid.rs
  20. 2 1
      shared-lib/flowy-grid-data-model/src/protobuf/proto/grid.proto

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

@@ -9,7 +9,7 @@ class FieldEditorBloc extends Bloc<FieldEditorEvent, FieldEditorState> {
   FieldEditorBloc({
   FieldEditorBloc({
     required String gridId,
     required String gridId,
     required String fieldName,
     required String fieldName,
-    required FieldContextLoader fieldContextLoader,
+    required IFieldContextLoader fieldContextLoader,
   }) : super(FieldEditorState.initial(gridId, fieldName, fieldContextLoader)) {
   }) : super(FieldEditorState.initial(gridId, fieldName, fieldContextLoader)) {
     on<FieldEditorEvent>(
     on<FieldEditorEvent>(
       (event, emit) async {
       (event, emit) async {
@@ -18,7 +18,7 @@ class FieldEditorBloc extends Bloc<FieldEditorEvent, FieldEditorState> {
             final fieldContext = GridFieldContext(gridId: gridId, loader: fieldContextLoader);
             final fieldContext = GridFieldContext(gridId: gridId, loader: fieldContextLoader);
             await fieldContext.loadData().then((result) {
             await fieldContext.loadData().then((result) {
               result.fold(
               result.fold(
-                (l) => emit(state.copyWith(fieldContext: Some(fieldContext))),
+                (l) => emit(state.copyWith(fieldContext: Some(fieldContext), name: fieldContext.field.name)),
                 (r) => null,
                 (r) => null,
               );
               );
             });
             });
@@ -53,7 +53,7 @@ class FieldEditorState with _$FieldEditorState {
     required Option<GridFieldContext> fieldContext,
     required Option<GridFieldContext> fieldContext,
   }) = _FieldEditorState;
   }) = _FieldEditorState;
 
 
-  factory FieldEditorState.initial(String gridId, String fieldName, FieldContextLoader loader) => FieldEditorState(
+  factory FieldEditorState.initial(String gridId, String fieldName, IFieldContextLoader loader) => FieldEditorState(
         gridId: gridId,
         gridId: gridId,
         fieldContext: none(),
         fieldContext: none(),
         errorText: '',
         errorText: '',

+ 26 - 40
frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart

@@ -15,15 +15,6 @@ class FieldService {
 
 
   FieldService({required this.gridId, required this.fieldId});
   FieldService({required this.gridId, required this.fieldId});
 
 
-  Future<Either<FieldTypeOptionData, FlowyError>> switchToField(FieldType fieldType) {
-    final payload = EditFieldPayload.create()
-      ..gridId = gridId
-      ..fieldId = fieldId
-      ..fieldType = fieldType;
-
-    return GridEventSwitchToField(payload).send();
-  }
-
   Future<Either<Unit, FlowyError>> moveField(int fromIndex, int toIndex) {
   Future<Either<Unit, FlowyError>> moveField(int fromIndex, int toIndex) {
     final payload = MoveItemPayload.create()
     final payload = MoveItemPayload.create()
       ..gridId = gridId
       ..gridId = gridId
@@ -146,13 +137,22 @@ class GridFieldCellContext with _$GridFieldCellContext {
   }) = _GridFieldCellContext;
   }) = _GridFieldCellContext;
 }
 }
 
 
-abstract class FieldContextLoader {
+abstract class IFieldContextLoader {
+  String get gridId;
   Future<Either<FieldTypeOptionData, FlowyError>> load();
   Future<Either<FieldTypeOptionData, FlowyError>> load();
 
 
-  Future<Either<FieldTypeOptionData, FlowyError>> switchToField(String fieldId, FieldType fieldType);
+  Future<Either<FieldTypeOptionData, FlowyError>> switchToField(String fieldId, FieldType fieldType) {
+    final payload = EditFieldPayload.create()
+      ..gridId = gridId
+      ..fieldId = fieldId
+      ..fieldType = fieldType;
+
+    return GridEventSwitchToField(payload).send();
+  }
 }
 }
 
 
-class NewFieldContextLoader extends FieldContextLoader {
+class NewFieldContextLoader extends IFieldContextLoader {
+  @override
   final String gridId;
   final String gridId;
   NewFieldContextLoader({
   NewFieldContextLoader({
     required this.gridId,
     required this.gridId,
@@ -164,24 +164,16 @@ class NewFieldContextLoader extends FieldContextLoader {
       ..gridId = gridId
       ..gridId = gridId
       ..fieldType = FieldType.RichText;
       ..fieldType = FieldType.RichText;
 
 
-    return GridEventGetFieldTypeOption(payload).send();
-  }
-
-  @override
-  Future<Either<FieldTypeOptionData, FlowyError>> switchToField(String fieldId, FieldType fieldType) {
-    final payload = EditFieldPayload.create()
-      ..gridId = gridId
-      ..fieldType = fieldType;
-
-    return GridEventGetFieldTypeOption(payload).send();
+    return GridEventCreateFieldTypeOption(payload).send();
   }
   }
 }
 }
 
 
-class DefaultFieldContextLoader extends FieldContextLoader {
+class FieldContextLoader extends IFieldContextLoader {
+  @override
   final String gridId;
   final String gridId;
   final Field field;
   final Field field;
 
 
-  DefaultFieldContextLoader({
+  FieldContextLoader({
     required this.gridId,
     required this.gridId,
     required this.field,
     required this.field,
   });
   });
@@ -195,24 +187,18 @@ class DefaultFieldContextLoader extends FieldContextLoader {
 
 
     return GridEventGetFieldTypeOption(payload).send();
     return GridEventGetFieldTypeOption(payload).send();
   }
   }
-
-  @override
-  Future<Either<FieldTypeOptionData, FlowyError>> switchToField(String fieldId, FieldType fieldType) async {
-    final fieldService = FieldService(gridId: gridId, fieldId: fieldId);
-    return fieldService.switchToField(fieldType);
-  }
 }
 }
 
 
 class GridFieldContext {
 class GridFieldContext {
   final String gridId;
   final String gridId;
-  final FieldContextLoader _loader;
+  final IFieldContextLoader _loader;
 
 
   late FieldTypeOptionData _data;
   late FieldTypeOptionData _data;
   ValueNotifier<Field>? _fieldNotifier;
   ValueNotifier<Field>? _fieldNotifier;
 
 
   GridFieldContext({
   GridFieldContext({
     required this.gridId,
     required this.gridId,
-    required FieldContextLoader loader,
+    required IFieldContextLoader loader,
   }) : _loader = loader;
   }) : _loader = loader;
 
 
   Future<Either<Unit, FlowyError>> loadData() async {
   Future<Either<Unit, FlowyError>> loadData() async {
@@ -246,18 +232,18 @@ class GridFieldContext {
   List<int> get typeOptionData => _data.typeOptionData;
   List<int> get typeOptionData => _data.typeOptionData;
 
 
   set fieldName(String name) {
   set fieldName(String name) {
-    _updateData(name: name);
+    _updateData(newName: name);
   }
   }
 
 
   set typeOptionData(List<int> typeOptionData) {
   set typeOptionData(List<int> typeOptionData) {
-    _updateData(typeOptionData: typeOptionData);
+    _updateData(newTypeOptionData: typeOptionData);
   }
   }
 
 
-  void _updateData({String? name, Field? newField, List<int>? typeOptionData}) {
+  void _updateData({String? newName, Field? newField, List<int>? newTypeOptionData}) {
     _data = _data.rebuild((rebuildData) {
     _data = _data.rebuild((rebuildData) {
-      if (name != null) {
+      if (newName != null) {
         rebuildData.field_2 = rebuildData.field_2.rebuild((rebuildField) {
         rebuildData.field_2 = rebuildData.field_2.rebuild((rebuildField) {
-          rebuildField.name = name;
+          rebuildField.name = newName;
         });
         });
       }
       }
 
 
@@ -265,8 +251,8 @@ class GridFieldContext {
         rebuildData.field_2 = newField;
         rebuildData.field_2 = newField;
       }
       }
 
 
-      if (typeOptionData != null) {
-        rebuildData.typeOptionData = typeOptionData;
+      if (newTypeOptionData != null) {
+        rebuildData.typeOptionData = newTypeOptionData;
       }
       }
     });
     });
 
 
@@ -287,7 +273,7 @@ class GridFieldContext {
         (fieldTypeOptionData) {
         (fieldTypeOptionData) {
           _updateData(
           _updateData(
             newField: fieldTypeOptionData.field_2,
             newField: fieldTypeOptionData.field_2,
-            typeOptionData: fieldTypeOptionData.typeOptionData,
+            newTypeOptionData: fieldTypeOptionData.typeOptionData,
           );
           );
         },
         },
         (err) {
         (err) {

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

@@ -64,7 +64,7 @@ class GridFieldCell extends StatelessWidget {
     FieldEditor(
     FieldEditor(
       gridId: state.gridId,
       gridId: state.gridId,
       fieldName: state.field.name,
       fieldName: state.field.name,
-      contextLoader: DefaultFieldContextLoader(
+      contextLoader: FieldContextLoader(
         gridId: state.gridId,
         gridId: state.gridId,
         field: state.field,
         field: state.field,
       ),
       ),

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

@@ -14,7 +14,7 @@ class FieldEditor extends StatelessWidget with FlowyOverlayDelegate {
   final String gridId;
   final String gridId;
   final String fieldName;
   final String fieldName;
 
 
-  final FieldContextLoader contextLoader;
+  final IFieldContextLoader contextLoader;
   const FieldEditor({
   const FieldEditor({
     required this.gridId,
     required this.gridId,
     required this.fieldName,
     required this.fieldName,
@@ -97,7 +97,6 @@ class _FieldNameTextField extends StatelessWidget {
   @override
   @override
   Widget build(BuildContext context) {
   Widget build(BuildContext context) {
     return BlocBuilder<FieldEditorBloc, FieldEditorState>(
     return BlocBuilder<FieldEditorBloc, FieldEditorState>(
-      buildWhen: (p, c) => p.name != c.name,
       builder: (context, state) {
       builder: (context, state) {
         return FieldNameTextField(
         return FieldNameTextField(
           name: state.name,
           name: state.name,

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

@@ -3,7 +3,7 @@ import 'package:flowy_infra_ui/widget/rounded_input_field.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
 
 
-class FieldNameTextField extends StatelessWidget {
+class FieldNameTextField extends StatefulWidget {
   final void Function(String) onNameChanged;
   final void Function(String) onNameChanged;
   final String name;
   final String name;
   final String errorText;
   final String errorText;
@@ -14,19 +14,41 @@ class FieldNameTextField extends StatelessWidget {
     Key? key,
     Key? key,
   }) : super(key: key);
   }) : super(key: key);
 
 
+  @override
+  State<FieldNameTextField> createState() => _FieldNameTextFieldState();
+}
+
+class _FieldNameTextFieldState extends State<FieldNameTextField> {
+  late String name;
+  TextEditingController controller = TextEditingController();
+
+  @override
+  void initState() {
+    controller.text = widget.name;
+    super.initState();
+  }
+
   @override
   @override
   Widget build(BuildContext context) {
   Widget build(BuildContext context) {
     final theme = context.watch<AppTheme>();
     final theme = context.watch<AppTheme>();
     return RoundedInputField(
     return RoundedInputField(
       height: 36,
       height: 36,
       style: const TextStyle(fontSize: 13, fontWeight: FontWeight.w500),
       style: const TextStyle(fontSize: 13, fontWeight: FontWeight.w500),
-      initialValue: name,
+      controller: controller,
       normalBorderColor: theme.shader4,
       normalBorderColor: theme.shader4,
       errorBorderColor: theme.red,
       errorBorderColor: theme.red,
       focusBorderColor: theme.main1,
       focusBorderColor: theme.main1,
       cursorColor: theme.main1,
       cursorColor: theme.main1,
-      errorText: errorText,
-      onChanged: onNameChanged,
+      errorText: widget.errorText,
+      onChanged: widget.onNameChanged,
     );
     );
   }
   }
+
+  @override
+  void didUpdateWidget(covariant FieldNameTextField oldWidget) {
+    controller.text = widget.name;
+    controller.selection = TextSelection.fromPosition(TextPosition(offset: controller.text.length));
+
+    super.didUpdateWidget(oldWidget);
+  }
 }
 }

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

@@ -179,7 +179,7 @@ class _RowDetailCell extends StatelessWidget {
     FieldEditor(
     FieldEditor(
       gridId: gridCell.gridId,
       gridId: gridCell.gridId,
       fieldName: gridCell.field.name,
       fieldName: gridCell.field.name,
-      contextLoader: DefaultFieldContextLoader(
+      contextLoader: FieldContextLoader(
         gridId: gridCell.gridId,
         gridId: gridCell.gridId,
         field: gridCell.field,
         field: gridCell.field,
       ),
       ),

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

@@ -116,7 +116,7 @@ class _GridPropertyCell extends StatelessWidget {
         FieldEditor(
         FieldEditor(
           gridId: gridId,
           gridId: gridId,
           fieldName: field.name,
           fieldName: field.name,
-          contextLoader: DefaultFieldContextLoader(gridId: gridId, field: field),
+          contextLoader: FieldContextLoader(gridId: gridId, field: field),
         ).show(context, anchorDirection: AnchorDirection.bottomRight);
         ).show(context, anchorDirection: AnchorDirection.bottomRight);
       },
       },
     );
     );

+ 17 - 0
frontend/app_flowy/packages/flowy_sdk/lib/dispatch/dart_event/flowy-grid/dart_event.dart

@@ -188,6 +188,23 @@ class GridEventGetFieldTypeOption {
     }
     }
 }
 }
 
 
+class GridEventCreateFieldTypeOption {
+     EditFieldPayload request;
+     GridEventCreateFieldTypeOption(this.request);
+
+    Future<Either<FieldTypeOptionData, FlowyError>> send() {
+    final request = FFIRequest.create()
+          ..event = GridEvent.CreateFieldTypeOption.toString()
+          ..payload = requestToBytes(this.request);
+
+    return Dispatch.asyncRequest(request)
+        .then((bytesResult) => bytesResult.fold(
+           (okBytes) => left(FieldTypeOptionData.fromBuffer(okBytes)),
+           (errBytes) => right(FlowyError.fromBuffer(errBytes)),
+        ));
+    }
+}
+
 class GridEventNewSelectOption {
 class GridEventNewSelectOption {
      CreateSelectOptionPayload request;
      CreateSelectOptionPayload request;
      GridEventNewSelectOption(this.request);
      GridEventNewSelectOption(this.request);

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

@@ -490,21 +490,12 @@ class GetEditFieldContextPayload extends $pb.GeneratedMessage {
   void clearFieldType() => clearField(3);
   void clearFieldType() => clearField(3);
 }
 }
 
 
-enum EditFieldPayload_OneOfFieldId {
-  fieldId, 
-  notSet
-}
-
 class EditFieldPayload extends $pb.GeneratedMessage {
 class EditFieldPayload extends $pb.GeneratedMessage {
-  static const $core.Map<$core.int, EditFieldPayload_OneOfFieldId> _EditFieldPayload_OneOfFieldIdByTag = {
-    2 : EditFieldPayload_OneOfFieldId.fieldId,
-    0 : EditFieldPayload_OneOfFieldId.notSet
-  };
   static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'EditFieldPayload', createEmptyInstance: create)
   static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'EditFieldPayload', createEmptyInstance: create)
-    ..oo(0, [2])
     ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'gridId')
     ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'gridId')
     ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'fieldId')
     ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'fieldId')
     ..e<FieldType>(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'fieldType', $pb.PbFieldType.OE, defaultOrMaker: FieldType.RichText, valueOf: FieldType.valueOf, enumValues: FieldType.values)
     ..e<FieldType>(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'fieldType', $pb.PbFieldType.OE, defaultOrMaker: FieldType.RichText, valueOf: FieldType.valueOf, enumValues: FieldType.values)
+    ..aOB(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'createIfNotExist')
     ..hasRequiredFields = false
     ..hasRequiredFields = false
   ;
   ;
 
 
@@ -513,6 +504,7 @@ class EditFieldPayload extends $pb.GeneratedMessage {
     $core.String? gridId,
     $core.String? gridId,
     $core.String? fieldId,
     $core.String? fieldId,
     FieldType? fieldType,
     FieldType? fieldType,
+    $core.bool? createIfNotExist,
   }) {
   }) {
     final _result = create();
     final _result = create();
     if (gridId != null) {
     if (gridId != null) {
@@ -524,6 +516,9 @@ class EditFieldPayload extends $pb.GeneratedMessage {
     if (fieldType != null) {
     if (fieldType != null) {
       _result.fieldType = fieldType;
       _result.fieldType = fieldType;
     }
     }
+    if (createIfNotExist != null) {
+      _result.createIfNotExist = createIfNotExist;
+    }
     return _result;
     return _result;
   }
   }
   factory EditFieldPayload.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
   factory EditFieldPayload.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
@@ -547,9 +542,6 @@ class EditFieldPayload extends $pb.GeneratedMessage {
   static EditFieldPayload getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<EditFieldPayload>(create);
   static EditFieldPayload getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<EditFieldPayload>(create);
   static EditFieldPayload? _defaultInstance;
   static EditFieldPayload? _defaultInstance;
 
 
-  EditFieldPayload_OneOfFieldId whichOneOfFieldId() => _EditFieldPayload_OneOfFieldIdByTag[$_whichOneof(0)]!;
-  void clearOneOfFieldId() => clearField($_whichOneof(0));
-
   @$pb.TagNumber(1)
   @$pb.TagNumber(1)
   $core.String get gridId => $_getSZ(0);
   $core.String get gridId => $_getSZ(0);
   @$pb.TagNumber(1)
   @$pb.TagNumber(1)
@@ -576,6 +568,15 @@ class EditFieldPayload extends $pb.GeneratedMessage {
   $core.bool hasFieldType() => $_has(2);
   $core.bool hasFieldType() => $_has(2);
   @$pb.TagNumber(3)
   @$pb.TagNumber(3)
   void clearFieldType() => clearField(3);
   void clearFieldType() => clearField(3);
+
+  @$pb.TagNumber(4)
+  $core.bool get createIfNotExist => $_getBF(3);
+  @$pb.TagNumber(4)
+  set createIfNotExist($core.bool v) { $_setBool(3, v); }
+  @$pb.TagNumber(4)
+  $core.bool hasCreateIfNotExist() => $_has(3);
+  @$pb.TagNumber(4)
+  void clearCreateIfNotExist() => clearField(4);
 }
 }
 
 
 class FieldTypeOptionContext extends $pb.GeneratedMessage {
 class FieldTypeOptionContext extends $pb.GeneratedMessage {

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

@@ -117,16 +117,14 @@ const EditFieldPayload$json = const {
   '1': 'EditFieldPayload',
   '1': 'EditFieldPayload',
   '2': const [
   '2': const [
     const {'1': 'grid_id', '3': 1, '4': 1, '5': 9, '10': 'gridId'},
     const {'1': 'grid_id', '3': 1, '4': 1, '5': 9, '10': 'gridId'},
-    const {'1': 'field_id', '3': 2, '4': 1, '5': 9, '9': 0, '10': 'fieldId'},
+    const {'1': 'field_id', '3': 2, '4': 1, '5': 9, '10': 'fieldId'},
     const {'1': 'field_type', '3': 3, '4': 1, '5': 14, '6': '.FieldType', '10': 'fieldType'},
     const {'1': 'field_type', '3': 3, '4': 1, '5': 14, '6': '.FieldType', '10': 'fieldType'},
-  ],
-  '8': const [
-    const {'1': 'one_of_field_id'},
+    const {'1': 'create_if_not_exist', '3': 4, '4': 1, '5': 8, '10': 'createIfNotExist'},
   ],
   ],
 };
 };
 
 
 /// Descriptor for `EditFieldPayload`. Decode as a `google.protobuf.DescriptorProto`.
 /// Descriptor for `EditFieldPayload`. Decode as a `google.protobuf.DescriptorProto`.
-final $typed_data.Uint8List editFieldPayloadDescriptor = $convert.base64Decode('ChBFZGl0RmllbGRQYXlsb2FkEhcKB2dyaWRfaWQYASABKAlSBmdyaWRJZBIbCghmaWVsZF9pZBgCIAEoCUgAUgdmaWVsZElkEikKCmZpZWxkX3R5cGUYAyABKA4yCi5GaWVsZFR5cGVSCWZpZWxkVHlwZUIRCg9vbmVfb2ZfZmllbGRfaWQ=');
+final $typed_data.Uint8List editFieldPayloadDescriptor = $convert.base64Decode('ChBFZGl0RmllbGRQYXlsb2FkEhcKB2dyaWRfaWQYASABKAlSBmdyaWRJZBIZCghmaWVsZF9pZBgCIAEoCVIHZmllbGRJZBIpCgpmaWVsZF90eXBlGAMgASgOMgouRmllbGRUeXBlUglmaWVsZFR5cGUSLQoTY3JlYXRlX2lmX25vdF9leGlzdBgEIAEoCFIQY3JlYXRlSWZOb3RFeGlzdA==');
 @$core.Deprecated('Use fieldTypeOptionContextDescriptor instead')
 @$core.Deprecated('Use fieldTypeOptionContextDescriptor instead')
 const FieldTypeOptionContext$json = const {
 const FieldTypeOptionContext$json = const {
   '1': 'FieldTypeOptionContext',
   '1': 'FieldTypeOptionContext',

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

@@ -21,6 +21,7 @@ class GridEvent extends $pb.ProtobufEnum {
   static const GridEvent DuplicateField = GridEvent._(21, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DuplicateField');
   static const GridEvent DuplicateField = GridEvent._(21, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DuplicateField');
   static const GridEvent MoveItem = GridEvent._(22, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'MoveItem');
   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 GetFieldTypeOption = GridEvent._(23, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'GetFieldTypeOption');
+  static const GridEvent CreateFieldTypeOption = GridEvent._(24, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'CreateFieldTypeOption');
   static const GridEvent NewSelectOption = GridEvent._(30, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'NewSelectOption');
   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 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');
   static const GridEvent UpdateSelectOption = GridEvent._(32, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UpdateSelectOption');
@@ -46,6 +47,7 @@ class GridEvent extends $pb.ProtobufEnum {
     DuplicateField,
     DuplicateField,
     MoveItem,
     MoveItem,
     GetFieldTypeOption,
     GetFieldTypeOption,
+    CreateFieldTypeOption,
     NewSelectOption,
     NewSelectOption,
     GetSelectOptionCellData,
     GetSelectOptionCellData,
     UpdateSelectOption,
     UpdateSelectOption,

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

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

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

@@ -2,7 +2,6 @@ use crate::manager::GridManager;
 use crate::services::entities::*;
 use crate::services::entities::*;
 use crate::services::field::type_options::*;
 use crate::services::field::type_options::*;
 use crate::services::field::{default_type_option_builder_from_type, type_option_builder_from_json_str};
 use crate::services::field::{default_type_option_builder_from_type, type_option_builder_from_json_str};
-use crate::services::grid_editor::ClientGridEditor;
 use flowy_error::{ErrorCode, FlowyError, FlowyResult};
 use flowy_error::{ErrorCode, FlowyError, FlowyResult};
 use flowy_grid_data_model::entities::*;
 use flowy_grid_data_model::entities::*;
 use lib_dispatch::prelude::{data_result, AppData, Data, DataResult};
 use lib_dispatch::prelude::{data_result, AppData, Data, DataResult};
@@ -100,15 +99,24 @@ pub(crate) async fn switch_to_field_handler(
     manager: AppData<Arc<GridManager>>,
     manager: AppData<Arc<GridManager>>,
 ) -> DataResult<FieldTypeOptionData, FlowyError> {
 ) -> DataResult<FieldTypeOptionData, FlowyError> {
     let params: EditFieldParams = data.into_inner().try_into()?;
     let params: EditFieldParams = data.into_inner().try_into()?;
-    if params.field_id.is_none() {
-        return Err(ErrorCode::FieldIdIsEmpty.into());
-    }
-    let field_id = params.field_id.unwrap();
     let editor = manager.get_grid_editor(&params.grid_id)?;
     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 data =
-        make_field_type_option_data(&params.grid_id, Some(field_id), params.field_type, editor, field_meta).await?;
+    editor
+        .switch_to_field_type(&params.field_id, &params.field_type)
+        .await?;
+
+    // Get the FieldMeta with field_id, if it doesn't exist, we create the default FieldMeta from the FieldType.
+    let field_meta = editor
+        .get_field_meta(&params.field_id)
+        .await
+        .unwrap_or(editor.next_field_meta(&params.field_type).await?);
+
+    let type_option_data = get_type_option_data(&field_meta, &params.field_type).await?;
+    let data = FieldTypeOptionData {
+        grid_id: params.grid_id,
+        field: field_meta.into(),
+        type_option_data,
+    };
+
     data_result(data)
     data_result(data)
 }
 }
 
 
@@ -123,6 +131,7 @@ pub(crate) async fn duplicate_field_handler(
     Ok(())
     Ok(())
 }
 }
 
 
+/// Return the FieldTypeOptionData if the Field exists otherwise return record not found error.
 #[tracing::instrument(level = "debug", skip(data, manager), err)]
 #[tracing::instrument(level = "debug", skip(data, manager), err)]
 pub(crate) async fn get_field_type_option_data_handler(
 pub(crate) async fn get_field_type_option_data_handler(
     data: Data<EditFieldPayload>,
     data: Data<EditFieldPayload>,
@@ -130,7 +139,29 @@ pub(crate) async fn get_field_type_option_data_handler(
 ) -> DataResult<FieldTypeOptionData, FlowyError> {
 ) -> DataResult<FieldTypeOptionData, FlowyError> {
     let params: EditFieldParams = data.into_inner().try_into()?;
     let params: EditFieldParams = data.into_inner().try_into()?;
     let editor = manager.get_grid_editor(&params.grid_id)?;
     let editor = manager.get_grid_editor(&params.grid_id)?;
-    let field_meta = get_or_create_field_meta(params.field_id, &params.field_type, editor).await?;
+    match editor.get_field_meta(&params.field_id).await {
+        None => Err(FlowyError::record_not_found()),
+        Some(field_meta) => {
+            let type_option_data = get_type_option_data(&field_meta, &field_meta.field_type).await?;
+            let data = FieldTypeOptionData {
+                grid_id: params.grid_id,
+                field: field_meta.into(),
+                type_option_data,
+            };
+            data_result(data)
+        }
+    }
+}
+
+/// Create FieldMeta and save it. Return the FieldTypeOptionData.
+#[tracing::instrument(level = "debug", skip(data, manager), err)]
+pub(crate) async fn create_field_type_option_data_handler(
+    data: Data<EditFieldPayload>,
+    manager: AppData<Arc<GridManager>>,
+) -> DataResult<FieldTypeOptionData, FlowyError> {
+    let params: CreateFieldParams = data.into_inner().try_into()?;
+    let editor = manager.get_grid_editor(&params.grid_id)?;
+    let field_meta = editor.create_next_field_meta(&params.field_type).await?;
     let type_option_data = get_type_option_data(&field_meta, &field_meta.field_type).await?;
     let type_option_data = get_type_option_data(&field_meta, &field_meta.field_type).await?;
 
 
     data_result(FieldTypeOptionData {
     data_result(FieldTypeOptionData {
@@ -151,23 +182,6 @@ pub(crate) async fn move_item_handler(
     Ok(())
     Ok(())
 }
 }
 
 
-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<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?;
-
-    Ok(FieldTypeOptionData {
-        grid_id: grid_id.to_string(),
-        field: field_meta.into(),
-        type_option_data,
-    })
-}
-
 /// The FieldMeta contains multiple data, each of them belongs to a specific FieldType.
 /// 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>> {
 async fn get_type_option_data(field_meta: &FieldMeta, field_type: &FieldType) -> FlowyResult<Vec<u8>> {
     let s = field_meta
     let s = field_meta
@@ -179,20 +193,6 @@ async fn get_type_option_data(field_meta: &FieldMeta, field_type: &FieldType) ->
     Ok(type_option_data)
     Ok(type_option_data)
 }
 }
 
 
-async fn get_or_create_field_meta(
-    field_id: Option<String>,
-    field_type: &FieldType,
-    editor: Arc<ClientGridEditor>,
-) -> FlowyResult<FieldMeta> {
-    match field_id {
-        None => editor.create_next_field_meta(field_type).await,
-        Some(field_id) => match editor.get_field_meta(&field_id).await {
-            None => editor.create_next_field_meta(field_type).await,
-            Some(field_meta) => Ok(field_meta),
-        },
-    }
-}
-
 #[tracing::instrument(level = "debug", skip(data, manager), err)]
 #[tracing::instrument(level = "debug", skip(data, manager), err)]
 pub(crate) async fn get_row_handler(
 pub(crate) async fn get_row_handler(
     data: Data<RowIdentifierPayload>,
     data: Data<RowIdentifierPayload>,

+ 4 - 0
frontend/rust-lib/flowy-grid/src/event_map.rs

@@ -20,6 +20,7 @@ pub fn create(grid_manager: Arc<GridManager>) -> Module {
         .event(GridEvent::DuplicateField, duplicate_field_handler)
         .event(GridEvent::DuplicateField, duplicate_field_handler)
         .event(GridEvent::MoveItem, move_item_handler)
         .event(GridEvent::MoveItem, move_item_handler)
         .event(GridEvent::GetFieldTypeOption, get_field_type_option_data_handler)
         .event(GridEvent::GetFieldTypeOption, get_field_type_option_data_handler)
+        .event(GridEvent::CreateFieldTypeOption, create_field_type_option_data_handler)
         // Row
         // Row
         .event(GridEvent::CreateRow, create_row_handler)
         .event(GridEvent::CreateRow, create_row_handler)
         .event(GridEvent::GetRow, get_row_handler)
         .event(GridEvent::GetRow, get_row_handler)
@@ -76,6 +77,9 @@ pub enum GridEvent {
     #[event(input = "EditFieldPayload", output = "FieldTypeOptionData")]
     #[event(input = "EditFieldPayload", output = "FieldTypeOptionData")]
     GetFieldTypeOption = 23,
     GetFieldTypeOption = 23,
 
 
+    #[event(input = "EditFieldPayload", output = "FieldTypeOptionData")]
+    CreateFieldTypeOption = 24,
+
     #[event(input = "CreateSelectOptionPayload", output = "SelectOption")]
     #[event(input = "CreateSelectOptionPayload", output = "SelectOption")]
     NewSelectOption = 30,
     NewSelectOption = 30,
 
 

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

@@ -36,6 +36,7 @@ pub enum GridEvent {
     DuplicateField = 21,
     DuplicateField = 21,
     MoveItem = 22,
     MoveItem = 22,
     GetFieldTypeOption = 23,
     GetFieldTypeOption = 23,
+    CreateFieldTypeOption = 24,
     NewSelectOption = 30,
     NewSelectOption = 30,
     GetSelectOptionCellData = 31,
     GetSelectOptionCellData = 31,
     UpdateSelectOption = 32,
     UpdateSelectOption = 32,
@@ -68,6 +69,7 @@ impl ::protobuf::ProtobufEnum for GridEvent {
             21 => ::std::option::Option::Some(GridEvent::DuplicateField),
             21 => ::std::option::Option::Some(GridEvent::DuplicateField),
             22 => ::std::option::Option::Some(GridEvent::MoveItem),
             22 => ::std::option::Option::Some(GridEvent::MoveItem),
             23 => ::std::option::Option::Some(GridEvent::GetFieldTypeOption),
             23 => ::std::option::Option::Some(GridEvent::GetFieldTypeOption),
+            24 => ::std::option::Option::Some(GridEvent::CreateFieldTypeOption),
             30 => ::std::option::Option::Some(GridEvent::NewSelectOption),
             30 => ::std::option::Option::Some(GridEvent::NewSelectOption),
             31 => ::std::option::Option::Some(GridEvent::GetSelectOptionCellData),
             31 => ::std::option::Option::Some(GridEvent::GetSelectOptionCellData),
             32 => ::std::option::Option::Some(GridEvent::UpdateSelectOption),
             32 => ::std::option::Option::Some(GridEvent::UpdateSelectOption),
@@ -97,6 +99,7 @@ impl ::protobuf::ProtobufEnum for GridEvent {
             GridEvent::DuplicateField,
             GridEvent::DuplicateField,
             GridEvent::MoveItem,
             GridEvent::MoveItem,
             GridEvent::GetFieldTypeOption,
             GridEvent::GetFieldTypeOption,
+            GridEvent::CreateFieldTypeOption,
             GridEvent::NewSelectOption,
             GridEvent::NewSelectOption,
             GridEvent::GetSelectOptionCellData,
             GridEvent::GetSelectOptionCellData,
             GridEvent::UpdateSelectOption,
             GridEvent::UpdateSelectOption,
@@ -137,18 +140,18 @@ impl ::protobuf::reflect::ProtobufValue for GridEvent {
 }
 }
 
 
 static file_descriptor_proto_data: &'static [u8] = b"\
 static file_descriptor_proto_data: &'static [u8] = b"\
-    \n\x0fevent_map.proto*\xc1\x03\n\tGridEvent\x12\x0f\n\x0bGetGridData\x10\
+    \n\x0fevent_map.proto*\xdc\x03\n\tGridEvent\x12\x0f\n\x0bGetGridData\x10\
     \0\x12\x11\n\rGetGridBlocks\x10\x01\x12\r\n\tGetFields\x10\n\x12\x0f\n\
     \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\
     \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\
     \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\x0c\n\x08M\
     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\
+    oveItem\x10\x16\x12\x16\n\x12GetFieldTypeOption\x10\x17\x12\x19\n\x15Cre\
+    ateFieldTypeOption\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\tDeleteR\
+    ow\x104\x12\x10\n\x0cDuplicateRow\x105\x12\x0b\n\x07GetCell\x10F\x12\x0e\
+    \n\nUpdateCell\x10G\x12\x1a\n\x16UpdateSelectOptionCell\x10H\x12\x12\n\
+    \x0eUpdateDateCell\x10P\x12\x13\n\x0fGetDateCellData\x10Zb\x06proto3\
 ";
 ";
 
 
 static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;
 static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;

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

@@ -12,6 +12,7 @@ enum GridEvent {
     DuplicateField = 21;
     DuplicateField = 21;
     MoveItem = 22;
     MoveItem = 22;
     GetFieldTypeOption = 23;
     GetFieldTypeOption = 23;
+    CreateFieldTypeOption = 24;
     NewSelectOption = 30;
     NewSelectOption = 30;
     GetSelectOptionCellData = 31;
     GetSelectOptionCellData = 31;
     UpdateSelectOption = 32;
     UpdateSelectOption = 32;

+ 11 - 1
frontend/rust-lib/flowy-grid/src/services/grid_editor.rs

@@ -121,12 +121,22 @@ impl ClientGridEditor {
         Ok(())
         Ok(())
     }
     }
 
 
-    pub async fn create_next_field_meta(&self, field_type: &FieldType) -> FlowyResult<FieldMeta> {
+    pub async fn next_field_meta(&self, field_type: &FieldType) -> FlowyResult<FieldMeta> {
         let name = format!("Property {}", self.grid_pad.read().await.fields().len() + 1);
         let name = format!("Property {}", self.grid_pad.read().await.fields().len() + 1);
         let field_meta = FieldBuilder::from_field_type(field_type).name(&name).build();
         let field_meta = FieldBuilder::from_field_type(field_type).name(&name).build();
         Ok(field_meta)
         Ok(field_meta)
     }
     }
 
 
+    pub async fn create_next_field_meta(&self, field_type: &FieldType) -> FlowyResult<FieldMeta> {
+        let field_meta = self.next_field_meta(field_type).await?;
+        let _ = self
+            .modify(|grid| Ok(grid.create_field_meta(field_meta.clone(), None)?))
+            .await?;
+        let _ = self.notify_did_insert_grid_field(&field_meta.id).await?;
+
+        Ok(field_meta)
+    }
+
     pub async fn contain_field(&self, field_id: &str) -> bool {
     pub async fn contain_field(&self, field_id: &str) -> bool {
         self.grid_pad.read().await.contain_field(field_id)
         self.grid_pad.read().await.contain_field(field_id)
     }
     }

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

@@ -167,16 +167,19 @@ pub struct EditFieldPayload {
     #[pb(index = 1)]
     #[pb(index = 1)]
     pub grid_id: String,
     pub grid_id: String,
 
 
-    #[pb(index = 2, one_of)]
-    pub field_id: Option<String>,
+    #[pb(index = 2)]
+    pub field_id: String,
 
 
     #[pb(index = 3)]
     #[pb(index = 3)]
     pub field_type: FieldType,
     pub field_type: FieldType,
+
+    #[pb(index = 4)]
+    pub create_if_not_exist: bool,
 }
 }
 
 
 pub struct EditFieldParams {
 pub struct EditFieldParams {
     pub grid_id: String,
     pub grid_id: String,
-    pub field_id: Option<String>,
+    pub field_id: String,
     pub field_type: FieldType,
     pub field_type: FieldType,
 }
 }
 
 
@@ -185,10 +188,28 @@ impl TryInto<EditFieldParams> for EditFieldPayload {
 
 
     fn try_into(self) -> Result<EditFieldParams, Self::Error> {
     fn try_into(self) -> Result<EditFieldParams, Self::Error> {
         let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?;
         let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?;
-        // let field_id = NotEmptyStr::parse(self.field_id).map_err(|_| ErrorCode::FieldIdIsEmpty)?;
+        let field_id = NotEmptyStr::parse(self.field_id).map_err(|_| ErrorCode::FieldIdIsEmpty)?;
         Ok(EditFieldParams {
         Ok(EditFieldParams {
             grid_id: grid_id.0,
             grid_id: grid_id.0,
-            field_id: self.field_id,
+            field_id: field_id.0,
+            field_type: self.field_type,
+        })
+    }
+}
+
+pub struct CreateFieldParams {
+    pub grid_id: String,
+    pub field_type: FieldType,
+}
+
+impl TryInto<CreateFieldParams> for EditFieldPayload {
+    type Error = ErrorCode;
+
+    fn try_into(self) -> Result<CreateFieldParams, Self::Error> {
+        let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?;
+
+        Ok(CreateFieldParams {
+            grid_id: grid_id.0,
             field_type: self.field_type,
             field_type: self.field_type,
         })
         })
     }
     }

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

@@ -1644,9 +1644,9 @@ impl ::protobuf::reflect::ProtobufValue for GetEditFieldContextPayload {
 pub struct EditFieldPayload {
 pub struct EditFieldPayload {
     // message fields
     // message fields
     pub grid_id: ::std::string::String,
     pub grid_id: ::std::string::String,
+    pub field_id: ::std::string::String,
     pub field_type: FieldType,
     pub field_type: FieldType,
-    // message oneof groups
-    pub one_of_field_id: ::std::option::Option<EditFieldPayload_oneof_one_of_field_id>,
+    pub create_if_not_exist: bool,
     // special fields
     // special fields
     pub unknown_fields: ::protobuf::UnknownFields,
     pub unknown_fields: ::protobuf::UnknownFields,
     pub cached_size: ::protobuf::CachedSize,
     pub cached_size: ::protobuf::CachedSize,
@@ -1658,11 +1658,6 @@ impl<'a> ::std::default::Default for &'a EditFieldPayload {
     }
     }
 }
 }
 
 
-#[derive(Clone,PartialEq,Debug)]
-pub enum EditFieldPayload_oneof_one_of_field_id {
-    field_id(::std::string::String),
-}
-
 impl EditFieldPayload {
 impl EditFieldPayload {
     pub fn new() -> EditFieldPayload {
     pub fn new() -> EditFieldPayload {
         ::std::default::Default::default()
         ::std::default::Default::default()
@@ -1698,49 +1693,26 @@ impl EditFieldPayload {
 
 
 
 
     pub fn get_field_id(&self) -> &str {
     pub fn get_field_id(&self) -> &str {
-        match self.one_of_field_id {
-            ::std::option::Option::Some(EditFieldPayload_oneof_one_of_field_id::field_id(ref v)) => v,
-            _ => "",
-        }
+        &self.field_id
     }
     }
     pub fn clear_field_id(&mut self) {
     pub fn clear_field_id(&mut self) {
-        self.one_of_field_id = ::std::option::Option::None;
-    }
-
-    pub fn has_field_id(&self) -> bool {
-        match self.one_of_field_id {
-            ::std::option::Option::Some(EditFieldPayload_oneof_one_of_field_id::field_id(..)) => true,
-            _ => false,
-        }
+        self.field_id.clear();
     }
     }
 
 
     // Param is passed by value, moved
     // Param is passed by value, moved
     pub fn set_field_id(&mut self, v: ::std::string::String) {
     pub fn set_field_id(&mut self, v: ::std::string::String) {
-        self.one_of_field_id = ::std::option::Option::Some(EditFieldPayload_oneof_one_of_field_id::field_id(v))
+        self.field_id = v;
     }
     }
 
 
     // Mutable pointer to the field.
     // Mutable pointer to the field.
+    // If field is not initialized, it is initialized with default value first.
     pub fn mut_field_id(&mut self) -> &mut ::std::string::String {
     pub fn mut_field_id(&mut self) -> &mut ::std::string::String {
-        if let ::std::option::Option::Some(EditFieldPayload_oneof_one_of_field_id::field_id(_)) = self.one_of_field_id {
-        } else {
-            self.one_of_field_id = ::std::option::Option::Some(EditFieldPayload_oneof_one_of_field_id::field_id(::std::string::String::new()));
-        }
-        match self.one_of_field_id {
-            ::std::option::Option::Some(EditFieldPayload_oneof_one_of_field_id::field_id(ref mut v)) => v,
-            _ => panic!(),
-        }
+        &mut self.field_id
     }
     }
 
 
     // Take field
     // Take field
     pub fn take_field_id(&mut self) -> ::std::string::String {
     pub fn take_field_id(&mut self) -> ::std::string::String {
-        if self.has_field_id() {
-            match self.one_of_field_id.take() {
-                ::std::option::Option::Some(EditFieldPayload_oneof_one_of_field_id::field_id(v)) => v,
-                _ => panic!(),
-            }
-        } else {
-            ::std::string::String::new()
-        }
+        ::std::mem::replace(&mut self.field_id, ::std::string::String::new())
     }
     }
 
 
     // .FieldType field_type = 3;
     // .FieldType field_type = 3;
@@ -1757,6 +1729,21 @@ impl EditFieldPayload {
     pub fn set_field_type(&mut self, v: FieldType) {
     pub fn set_field_type(&mut self, v: FieldType) {
         self.field_type = v;
         self.field_type = v;
     }
     }
+
+    // bool create_if_not_exist = 4;
+
+
+    pub fn get_create_if_not_exist(&self) -> bool {
+        self.create_if_not_exist
+    }
+    pub fn clear_create_if_not_exist(&mut self) {
+        self.create_if_not_exist = false;
+    }
+
+    // Param is passed by value, moved
+    pub fn set_create_if_not_exist(&mut self, v: bool) {
+        self.create_if_not_exist = v;
+    }
 }
 }
 
 
 impl ::protobuf::Message for EditFieldPayload {
 impl ::protobuf::Message for EditFieldPayload {
@@ -1772,14 +1759,18 @@ impl ::protobuf::Message for EditFieldPayload {
                     ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.grid_id)?;
                     ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.grid_id)?;
                 },
                 },
                 2 => {
                 2 => {
-                    if wire_type != ::protobuf::wire_format::WireTypeLengthDelimited {
-                        return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
-                    }
-                    self.one_of_field_id = ::std::option::Option::Some(EditFieldPayload_oneof_one_of_field_id::field_id(is.read_string()?));
+                    ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.field_id)?;
                 },
                 },
                 3 => {
                 3 => {
                     ::protobuf::rt::read_proto3_enum_with_unknown_fields_into(wire_type, is, &mut self.field_type, 3, &mut self.unknown_fields)?
                     ::protobuf::rt::read_proto3_enum_with_unknown_fields_into(wire_type, is, &mut self.field_type, 3, &mut self.unknown_fields)?
                 },
                 },
+                4 => {
+                    if wire_type != ::protobuf::wire_format::WireTypeVarint {
+                        return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
+                    }
+                    let tmp = is.read_bool()?;
+                    self.create_if_not_exist = tmp;
+                },
                 _ => {
                 _ => {
                     ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
                     ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
                 },
                 },
@@ -1795,15 +1786,14 @@ impl ::protobuf::Message for EditFieldPayload {
         if !self.grid_id.is_empty() {
         if !self.grid_id.is_empty() {
             my_size += ::protobuf::rt::string_size(1, &self.grid_id);
             my_size += ::protobuf::rt::string_size(1, &self.grid_id);
         }
         }
+        if !self.field_id.is_empty() {
+            my_size += ::protobuf::rt::string_size(2, &self.field_id);
+        }
         if self.field_type != FieldType::RichText {
         if self.field_type != FieldType::RichText {
             my_size += ::protobuf::rt::enum_size(3, self.field_type);
             my_size += ::protobuf::rt::enum_size(3, self.field_type);
         }
         }
-        if let ::std::option::Option::Some(ref v) = self.one_of_field_id {
-            match v {
-                &EditFieldPayload_oneof_one_of_field_id::field_id(ref v) => {
-                    my_size += ::protobuf::rt::string_size(2, &v);
-                },
-            };
+        if self.create_if_not_exist != false {
+            my_size += 2;
         }
         }
         my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
         my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
         self.cached_size.set(my_size);
         self.cached_size.set(my_size);
@@ -1814,15 +1804,14 @@ impl ::protobuf::Message for EditFieldPayload {
         if !self.grid_id.is_empty() {
         if !self.grid_id.is_empty() {
             os.write_string(1, &self.grid_id)?;
             os.write_string(1, &self.grid_id)?;
         }
         }
+        if !self.field_id.is_empty() {
+            os.write_string(2, &self.field_id)?;
+        }
         if self.field_type != FieldType::RichText {
         if self.field_type != FieldType::RichText {
             os.write_enum(3, ::protobuf::ProtobufEnum::value(&self.field_type))?;
             os.write_enum(3, ::protobuf::ProtobufEnum::value(&self.field_type))?;
         }
         }
-        if let ::std::option::Option::Some(ref v) = self.one_of_field_id {
-            match v {
-                &EditFieldPayload_oneof_one_of_field_id::field_id(ref v) => {
-                    os.write_string(2, v)?;
-                },
-            };
+        if self.create_if_not_exist != false {
+            os.write_bool(4, self.create_if_not_exist)?;
         }
         }
         os.write_unknown_fields(self.get_unknown_fields())?;
         os.write_unknown_fields(self.get_unknown_fields())?;
         ::std::result::Result::Ok(())
         ::std::result::Result::Ok(())
@@ -1867,16 +1856,21 @@ impl ::protobuf::Message for EditFieldPayload {
                 |m: &EditFieldPayload| { &m.grid_id },
                 |m: &EditFieldPayload| { &m.grid_id },
                 |m: &mut EditFieldPayload| { &mut m.grid_id },
                 |m: &mut EditFieldPayload| { &mut m.grid_id },
             ));
             ));
-            fields.push(::protobuf::reflect::accessor::make_singular_string_accessor::<_>(
+            fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
                 "field_id",
                 "field_id",
-                EditFieldPayload::has_field_id,
-                EditFieldPayload::get_field_id,
+                |m: &EditFieldPayload| { &m.field_id },
+                |m: &mut EditFieldPayload| { &mut m.field_id },
             ));
             ));
             fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeEnum<FieldType>>(
             fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeEnum<FieldType>>(
                 "field_type",
                 "field_type",
                 |m: &EditFieldPayload| { &m.field_type },
                 |m: &EditFieldPayload| { &m.field_type },
                 |m: &mut EditFieldPayload| { &mut m.field_type },
                 |m: &mut EditFieldPayload| { &mut m.field_type },
             ));
             ));
+            fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBool>(
+                "create_if_not_exist",
+                |m: &EditFieldPayload| { &m.create_if_not_exist },
+                |m: &mut EditFieldPayload| { &mut m.create_if_not_exist },
+            ));
             ::protobuf::reflect::MessageDescriptor::new_pb_name::<EditFieldPayload>(
             ::protobuf::reflect::MessageDescriptor::new_pb_name::<EditFieldPayload>(
                 "EditFieldPayload",
                 "EditFieldPayload",
                 fields,
                 fields,
@@ -1894,8 +1888,9 @@ impl ::protobuf::Message for EditFieldPayload {
 impl ::protobuf::Clear for EditFieldPayload {
 impl ::protobuf::Clear for EditFieldPayload {
     fn clear(&mut self) {
     fn clear(&mut self) {
         self.grid_id.clear();
         self.grid_id.clear();
-        self.one_of_field_id = ::std::option::Option::None;
+        self.field_id.clear();
         self.field_type = FieldType::RichText;
         self.field_type = FieldType::RichText;
+        self.create_if_not_exist = false;
         self.unknown_fields.clear();
         self.unknown_fields.clear();
     }
     }
 }
 }
@@ -8311,83 +8306,84 @@ static file_descriptor_proto_data: &'static [u8] = b"\
     extPayload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x12\x1b\n\
     extPayload\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\
     \x08field_id\x18\x02\x20\x01(\tH\0R\x07fieldId\x12)\n\nfield_type\x18\
     \x03\x20\x01(\x0e2\n.FieldTypeR\tfieldTypeB\x11\n\x0fone_of_field_id\"\
     \x03\x20\x01(\x0e2\n.FieldTypeR\tfieldTypeB\x11\n\x0fone_of_field_id\"\
-    \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\"\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\"v\n\x13FieldTypeOptionData\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\"-\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\
-    \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\
-    k_id\x18\x01\x20\x01(\tR\x07blockId\x123\n\rinserted_rows\x18\x02\x20\
-    \x03(\x0b2\x0e.IndexRowOrderR\x0cinsertedRows\x12,\n\x0cdeleted_rows\x18\
-    \x03\x20\x03(\x0b2\t.RowOrderR\x0bdeletedRows\x123\n\x0cupdated_rows\x18\
-    \x04\x20\x03(\x0b2\x10.UpdatedRowOrderR\x0bupdatedRows\"E\n\tGridBlock\
-    \x12\x0e\n\x02id\x18\x01\x20\x01(\tR\x02id\x12(\n\nrow_orders\x18\x02\
-    \x20\x03(\x0b2\t.RowOrderR\trowOrders\"O\n\x04Cell\x12\x19\n\x08field_id\
-    \x18\x01\x20\x01(\tR\x07fieldId\x12\x18\n\x07content\x18\x02\x20\x01(\tR\
-    \x07content\x12\x12\n\x04data\x18\x03\x20\x01(\tR\x04data\"+\n\x0cRepeat\
-    edCell\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\x12InsertFieldPayload\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\"|\n\x1cUpdateFieldTypeOptionPayload\
-    \x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x12\x19\n\x08field_i\
-    d\x18\x02\x20\x01(\tR\x07fieldId\x12(\n\x10type_option_data\x18\x03\x20\
-    \x01(\x0cR\x0etypeOptionData\"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\x16QueryGridBlocksPay\
-    load\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x122\n\x0cblock_\
-    orders\x18\x02\x20\x03(\x0b2\x0f.GridBlockOrderR\x0bblockOrders\"\xa8\
-    \x03\n\x15FieldChangesetPayload\x12\x19\n\x08field_id\x18\x01\x20\x01(\t\
-    R\x07fieldId\x12\x17\n\x07grid_id\x18\x02\x20\x01(\tR\x06gridId\x12\x14\
-    \n\x04name\x18\x03\x20\x01(\tH\0R\x04name\x12\x14\n\x04desc\x18\x04\x20\
-    \x01(\tH\x01R\x04desc\x12+\n\nfield_type\x18\x05\x20\x01(\x0e2\n.FieldTy\
-    peH\x02R\tfieldType\x12\x18\n\x06frozen\x18\x06\x20\x01(\x08H\x03R\x06fr\
-    ozen\x12\x20\n\nvisibility\x18\x07\x20\x01(\x08H\x04R\nvisibility\x12\
-    \x16\n\x05width\x18\x08\x20\x01(\x05H\x05R\x05width\x12*\n\x10type_optio\
-    n_data\x18\t\x20\x01(\x0cH\x06R\x0etypeOptionDataB\r\n\x0bone_of_nameB\r\
-    \n\x0bone_of_descB\x13\n\x11one_of_field_typeB\x0f\n\rone_of_frozenB\x13\
-    \n\x11one_of_visibilityB\x0e\n\x0cone_of_widthB\x19\n\x17one_of_type_opt\
-    ion_data\"\x9c\x01\n\x0fMoveItemPayload\x12\x17\n\x07grid_id\x18\x01\x20\
-    \x01(\tR\x06gridId\x12\x17\n\x07item_id\x18\x02\x20\x01(\tR\x06itemId\
-    \x12\x1d\n\nfrom_index\x18\x03\x20\x01(\x05R\tfromIndex\x12\x19\n\x08to_\
-    index\x18\x04\x20\x01(\x05R\x07toIndex\x12\x1d\n\x02ty\x18\x05\x20\x01(\
-    \x0e2\r.MoveItemTypeR\x02ty\"\xb3\x01\n\rCellChangeset\x12\x17\n\x07grid\
-    _id\x18\x01\x20\x01(\tR\x06gridId\x12\x15\n\x06row_id\x18\x02\x20\x01(\t\
-    R\x05rowId\x12\x19\n\x08field_id\x18\x03\x20\x01(\tR\x07fieldId\x126\n\
-    \x16cell_content_changeset\x18\x04\x20\x01(\tH\0R\x14cellContentChangese\
-    tB\x1f\n\x1done_of_cell_content_changeset**\n\x0cMoveItemType\x12\r\n\tM\
-    oveField\x10\0\x12\x0b\n\x07MoveRow\x10\x01*d\n\tFieldType\x12\x0c\n\x08\
-    RichText\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\
+    \xa0\x01\n\x10EditFieldPayload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\
+    \x06gridId\x12\x19\n\x08field_id\x18\x02\x20\x01(\tR\x07fieldId\x12)\n\n\
+    field_type\x18\x03\x20\x01(\x0e2\n.FieldTypeR\tfieldType\x12-\n\x13creat\
+    e_if_not_exist\x18\x04\x20\x01(\x08R\x10createIfNotExist\"\x82\x01\n\x16\
+    FieldTypeOptionContext\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridI\
+    d\x12%\n\ngrid_field\x18\x02\x20\x01(\x0b2\x06.FieldR\tgridField\x12(\n\
+    \x10type_option_data\x18\x03\x20\x01(\x0cR\x0etypeOptionData\"v\n\x13Fie\
+    ldTypeOptionData\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\x0etypeOptionData\"-\n\rRepeatedField\
+    \x12\x1c\n\x05items\x18\x01\x20\x03(\x0b2\x06.FieldR\x05items\"7\n\x12Re\
+    peatedFieldOrder\x12!\n\x05items\x18\x01\x20\x03(\x0b2\x0b.FieldOrderR\
+    \x05items\"T\n\x08RowOrder\x12\x15\n\x06row_id\x18\x01\x20\x01(\tR\x05ro\
+    wId\x12\x19\n\x08block_id\x18\x02\x20\x01(\tR\x07blockId\x12\x16\n\x06he\
+    ight\x18\x03\x20\x01(\x05R\x06height\"\xb8\x01\n\x03Row\x12\x0e\n\x02id\
+    \x18\x01\x20\x01(\tR\x02id\x12@\n\x10cell_by_field_id\x18\x02\x20\x03(\
+    \x0b2\x17.Row.CellByFieldIdEntryR\rcellByFieldId\x12\x16\n\x06height\x18\
+    \x03\x20\x01(\x05R\x06height\x1aG\n\x12CellByFieldIdEntry\x12\x10\n\x03k\
+    ey\x18\x01\x20\x01(\tR\x03key\x12\x1b\n\x05value\x18\x02\x20\x01(\x0b2\
+    \x05.CellR\x05value:\x028\x01\")\n\x0bRepeatedRow\x12\x1a\n\x05items\x18\
+    \x01\x20\x03(\x0b2\x04.RowR\x05items\"5\n\x11RepeatedGridBlock\x12\x20\n\
+    \x05items\x18\x01\x20\x03(\x0b2\n.GridBlockR\x05items\"U\n\x0eGridBlockO\
+    rder\x12\x19\n\x08block_id\x18\x01\x20\x01(\tR\x07blockId\x12(\n\nrow_or\
+    ders\x18\x02\x20\x03(\x0b2\t.RowOrderR\trowOrders\"_\n\rIndexRowOrder\
+    \x12&\n\trow_order\x18\x01\x20\x01(\x0b2\t.RowOrderR\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.RowOrder\
+    R\x08rowOrder\x12\x16\n\x03row\x18\x02\x20\x01(\x0b2\x04.RowR\x03row\"\
+    \xc6\x01\n\x11GridRowsChangeset\x12\x19\n\x08block_id\x18\x01\x20\x01(\t\
+    R\x07blockId\x123\n\rinserted_rows\x18\x02\x20\x03(\x0b2\x0e.IndexRowOrd\
+    erR\x0cinsertedRows\x12,\n\x0cdeleted_rows\x18\x03\x20\x03(\x0b2\t.RowOr\
+    derR\x0bdeletedRows\x123\n\x0cupdated_rows\x18\x04\x20\x03(\x0b2\x10.Upd\
+    atedRowOrderR\x0bupdatedRows\"E\n\tGridBlock\x12\x0e\n\x02id\x18\x01\x20\
+    \x01(\tR\x02id\x12(\n\nrow_orders\x18\x02\x20\x03(\x0b2\t.RowOrderR\trow\
+    Orders\"O\n\x04Cell\x12\x19\n\x08field_id\x18\x01\x20\x01(\tR\x07fieldId\
+    \x12\x18\n\x07content\x18\x02\x20\x01(\tR\x07content\x12\x12\n\x04data\
+    \x18\x03\x20\x01(\tR\x04data\"+\n\x0cRepeatedCell\x12\x1b\n\x05items\x18\
+    \x01\x20\x03(\x0b2\x05.CellR\x05items\"'\n\x11CreateGridPayload\x12\x12\
+    \n\x04name\x18\x01\x20\x01(\tR\x04name\"\x1e\n\x06GridId\x12\x14\n\x05va\
+    lue\x18\x01\x20\x01(\tR\x05value\"#\n\x0bGridBlockId\x12\x14\n\x05value\
+    \x18\x01\x20\x01(\tR\x05value\"f\n\x10CreateRowPayload\x12\x17\n\x07grid\
+    _id\x18\x01\x20\x01(\tR\x06gridId\x12\"\n\x0cstart_row_id\x18\x02\x20\
+    \x01(\tH\0R\nstartRowIdB\x15\n\x13one_of_start_row_id\"\xb6\x01\n\x12Ins\
+    ertFieldPayload\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\x0etypeOptionData\x12&\n\x0estart_fie\
+    ld_id\x18\x04\x20\x01(\tH\0R\x0cstartFieldIdB\x17\n\x15one_of_start_fiel\
+    d_id\"|\n\x1cUpdateFieldTypeOptionPayload\x12\x17\n\x07grid_id\x18\x01\
+    \x20\x01(\tR\x06gridId\x12\x19\n\x08field_id\x18\x02\x20\x01(\tR\x07fiel\
+    dId\x12(\n\x10type_option_data\x18\x03\x20\x01(\x0cR\x0etypeOptionData\"\
+    d\n\x11QueryFieldPayload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gri\
+    dId\x126\n\x0cfield_orders\x18\x02\x20\x01(\x0b2\x13.RepeatedFieldOrderR\
+    \x0bfieldOrders\"e\n\x16QueryGridBlocksPayload\x12\x17\n\x07grid_id\x18\
+    \x01\x20\x01(\tR\x06gridId\x122\n\x0cblock_orders\x18\x02\x20\x03(\x0b2\
+    \x0f.GridBlockOrderR\x0bblockOrders\"\xa8\x03\n\x15FieldChangesetPayload\
+    \x12\x19\n\x08field_id\x18\x01\x20\x01(\tR\x07fieldId\x12\x17\n\x07grid_\
+    id\x18\x02\x20\x01(\tR\x06gridId\x12\x14\n\x04name\x18\x03\x20\x01(\tH\0\
+    R\x04name\x12\x14\n\x04desc\x18\x04\x20\x01(\tH\x01R\x04desc\x12+\n\nfie\
+    ld_type\x18\x05\x20\x01(\x0e2\n.FieldTypeH\x02R\tfieldType\x12\x18\n\x06\
+    frozen\x18\x06\x20\x01(\x08H\x03R\x06frozen\x12\x20\n\nvisibility\x18\
+    \x07\x20\x01(\x08H\x04R\nvisibility\x12\x16\n\x05width\x18\x08\x20\x01(\
+    \x05H\x05R\x05width\x12*\n\x10type_option_data\x18\t\x20\x01(\x0cH\x06R\
+    \x0etypeOptionDataB\r\n\x0bone_of_nameB\r\n\x0bone_of_descB\x13\n\x11one\
+    _of_field_typeB\x0f\n\rone_of_frozenB\x13\n\x11one_of_visibilityB\x0e\n\
+    \x0cone_of_widthB\x19\n\x17one_of_type_option_data\"\x9c\x01\n\x0fMoveIt\
+    emPayload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x12\x17\n\
+    \x07item_id\x18\x02\x20\x01(\tR\x06itemId\x12\x1d\n\nfrom_index\x18\x03\
+    \x20\x01(\x05R\tfromIndex\x12\x19\n\x08to_index\x18\x04\x20\x01(\x05R\
+    \x07toIndex\x12\x1d\n\x02ty\x18\x05\x20\x01(\x0e2\r.MoveItemTypeR\x02ty\
+    \"\xb3\x01\n\rCellChangeset\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\x126\n\x16cell_content_changeset\
+    \x18\x04\x20\x01(\tH\0R\x14cellContentChangesetB\x1f\n\x1done_of_cell_co\
+    ntent_changeset**\n\x0cMoveItemType\x12\r\n\tMoveField\x10\0\x12\x0b\n\
+    \x07MoveRow\x10\x01*d\n\tFieldType\x12\x0c\n\x08RichText\x10\0\x12\n\n\
+    \x06Number\x10\x01\x12\x0c\n\x08DateTime\x10\x02\x12\x10\n\x0cSingleSele\
+    ct\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;
 static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;

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

@@ -35,8 +35,9 @@ message GetEditFieldContextPayload {
 }
 }
 message EditFieldPayload {
 message EditFieldPayload {
     string grid_id = 1;
     string grid_id = 1;
-    oneof one_of_field_id { string field_id = 2; };
+    string field_id = 2;
     FieldType field_type = 3;
     FieldType field_type = 3;
+    bool create_if_not_exist = 4;
 }
 }
 message FieldTypeOptionContext {
 message FieldTypeOptionContext {
     string grid_id = 1;
     string grid_id = 1;