appflowy 3 rokov pred
rodič
commit
c8664c8a28
34 zmenil súbory, kde vykonal 2249 pridanie a 135 odobranie
  1. 103 0
      app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/view_create.pb.dart
  2. 14 0
      app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/view_create.pbjson.dart
  3. 47 0
      app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/view_delete.pb.dart
  4. 10 0
      app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/view_delete.pbjson.dart
  5. 75 0
      app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/view_query.pb.dart
  6. 12 0
      app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/view_query.pbjson.dart
  7. 155 0
      app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/view_update.pb.dart
  8. 20 0
      app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/view_update.pbjson.dart
  9. 4 4
      backend/src/application.rs
  10. 2 1
      backend/src/workspace_service/app/app.rs
  11. 3 0
      backend/src/workspace_service/view/mod.rs
  12. 26 12
      backend/src/workspace_service/view/router.rs
  13. 230 0
      backend/src/workspace_service/view/view.rs
  14. 22 0
      backend/tests/api/helper.rs
  15. 66 0
      backend/tests/api/workspace.rs
  16. 4 0
      rust-lib/flowy-derive/src/derive_cache/derive_cache.rs
  17. 1 1
      rust-lib/flowy-workspace/src/entities/view/mod.rs
  18. 0 2
      rust-lib/flowy-workspace/src/entities/view/parser/mod.rs
  19. 4 0
      rust-lib/flowy-workspace/src/entities/view/parser/view_id.rs
  20. 0 15
      rust-lib/flowy-workspace/src/entities/view/parser/view_type.rs
  21. 25 3
      rust-lib/flowy-workspace/src/entities/view/view_create.rs
  22. 3 1
      rust-lib/flowy-workspace/src/entities/view/view_delete.rs
  23. 6 0
      rust-lib/flowy-workspace/src/entities/view/view_query.rs
  24. 10 0
      rust-lib/flowy-workspace/src/entities/view/view_update.rs
  25. 391 56
      rust-lib/flowy-workspace/src/protobuf/model/view_create.rs
  26. 169 5
      rust-lib/flowy-workspace/src/protobuf/model/view_delete.rs
  27. 252 11
      rust-lib/flowy-workspace/src/protobuf/model/view_query.rs
  28. 507 22
      rust-lib/flowy-workspace/src/protobuf/model/view_update.rs
  29. 7 0
      rust-lib/flowy-workspace/src/protobuf/proto/view_create.proto
  30. 3 0
      rust-lib/flowy-workspace/src/protobuf/proto/view_delete.proto
  31. 5 0
      rust-lib/flowy-workspace/src/protobuf/proto/view_query.proto
  32. 7 0
      rust-lib/flowy-workspace/src/protobuf/proto/view_update.proto
  33. 60 1
      rust-lib/flowy-workspace/src/services/view_controller.rs
  34. 6 1
      rust-lib/flowy-workspace/src/sql_tables/view/view_table.rs

+ 103 - 0
app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/view_create.pb.dart

@@ -130,6 +130,109 @@ class CreateViewRequest extends $pb.GeneratedMessage {
   void clearViewType() => clearField(5);
 }
 
+class CreateViewParams extends $pb.GeneratedMessage {
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'CreateViewParams', createEmptyInstance: create)
+    ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'belongToId')
+    ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'name')
+    ..aOS(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'desc')
+    ..aOS(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'thumbnail')
+    ..e<ViewType>(5, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'viewType', $pb.PbFieldType.OE, defaultOrMaker: ViewType.Blank, valueOf: ViewType.valueOf, enumValues: ViewType.values)
+    ..hasRequiredFields = false
+  ;
+
+  CreateViewParams._() : super();
+  factory CreateViewParams({
+    $core.String? belongToId,
+    $core.String? name,
+    $core.String? desc,
+    $core.String? thumbnail,
+    ViewType? viewType,
+  }) {
+    final _result = create();
+    if (belongToId != null) {
+      _result.belongToId = belongToId;
+    }
+    if (name != null) {
+      _result.name = name;
+    }
+    if (desc != null) {
+      _result.desc = desc;
+    }
+    if (thumbnail != null) {
+      _result.thumbnail = thumbnail;
+    }
+    if (viewType != null) {
+      _result.viewType = viewType;
+    }
+    return _result;
+  }
+  factory CreateViewParams.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory CreateViewParams.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')
+  CreateViewParams clone() => CreateViewParams()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  CreateViewParams copyWith(void Function(CreateViewParams) updates) => super.copyWith((message) => updates(message as CreateViewParams)) as CreateViewParams; // ignore: deprecated_member_use
+  $pb.BuilderInfo get info_ => _i;
+  @$core.pragma('dart2js:noInline')
+  static CreateViewParams create() => CreateViewParams._();
+  CreateViewParams createEmptyInstance() => create();
+  static $pb.PbList<CreateViewParams> createRepeated() => $pb.PbList<CreateViewParams>();
+  @$core.pragma('dart2js:noInline')
+  static CreateViewParams getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<CreateViewParams>(create);
+  static CreateViewParams? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $core.String get belongToId => $_getSZ(0);
+  @$pb.TagNumber(1)
+  set belongToId($core.String v) { $_setString(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasBelongToId() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearBelongToId() => clearField(1);
+
+  @$pb.TagNumber(2)
+  $core.String get name => $_getSZ(1);
+  @$pb.TagNumber(2)
+  set name($core.String v) { $_setString(1, v); }
+  @$pb.TagNumber(2)
+  $core.bool hasName() => $_has(1);
+  @$pb.TagNumber(2)
+  void clearName() => clearField(2);
+
+  @$pb.TagNumber(3)
+  $core.String get desc => $_getSZ(2);
+  @$pb.TagNumber(3)
+  set desc($core.String v) { $_setString(2, v); }
+  @$pb.TagNumber(3)
+  $core.bool hasDesc() => $_has(2);
+  @$pb.TagNumber(3)
+  void clearDesc() => clearField(3);
+
+  @$pb.TagNumber(4)
+  $core.String get thumbnail => $_getSZ(3);
+  @$pb.TagNumber(4)
+  set thumbnail($core.String v) { $_setString(3, v); }
+  @$pb.TagNumber(4)
+  $core.bool hasThumbnail() => $_has(3);
+  @$pb.TagNumber(4)
+  void clearThumbnail() => clearField(4);
+
+  @$pb.TagNumber(5)
+  ViewType get viewType => $_getN(4);
+  @$pb.TagNumber(5)
+  set viewType(ViewType v) { setField(5, v); }
+  @$pb.TagNumber(5)
+  $core.bool hasViewType() => $_has(4);
+  @$pb.TagNumber(5)
+  void clearViewType() => clearField(5);
+}
+
 class View extends $pb.GeneratedMessage {
   static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'View', createEmptyInstance: create)
     ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'id')

+ 14 - 0
app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/view_create.pbjson.dart

@@ -36,6 +36,20 @@ const CreateViewRequest$json = const {
 
 /// Descriptor for `CreateViewRequest`. Decode as a `google.protobuf.DescriptorProto`.
 final $typed_data.Uint8List createViewRequestDescriptor = $convert.base64Decode('ChFDcmVhdGVWaWV3UmVxdWVzdBIgCgxiZWxvbmdfdG9faWQYASABKAlSCmJlbG9uZ1RvSWQSEgoEbmFtZRgCIAEoCVIEbmFtZRISCgRkZXNjGAMgASgJUgRkZXNjEh4KCXRodW1ibmFpbBgEIAEoCUgAUgl0aHVtYm5haWwSJgoJdmlld190eXBlGAUgASgOMgkuVmlld1R5cGVSCHZpZXdUeXBlQhIKEG9uZV9vZl90aHVtYm5haWw=');
+@$core.Deprecated('Use createViewParamsDescriptor instead')
+const CreateViewParams$json = const {
+  '1': 'CreateViewParams',
+  '2': const [
+    const {'1': 'belong_to_id', '3': 1, '4': 1, '5': 9, '10': 'belongToId'},
+    const {'1': 'name', '3': 2, '4': 1, '5': 9, '10': 'name'},
+    const {'1': 'desc', '3': 3, '4': 1, '5': 9, '10': 'desc'},
+    const {'1': 'thumbnail', '3': 4, '4': 1, '5': 9, '10': 'thumbnail'},
+    const {'1': 'view_type', '3': 5, '4': 1, '5': 14, '6': '.ViewType', '10': 'viewType'},
+  ],
+};
+
+/// Descriptor for `CreateViewParams`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List createViewParamsDescriptor = $convert.base64Decode('ChBDcmVhdGVWaWV3UGFyYW1zEiAKDGJlbG9uZ190b19pZBgBIAEoCVIKYmVsb25nVG9JZBISCgRuYW1lGAIgASgJUgRuYW1lEhIKBGRlc2MYAyABKAlSBGRlc2MSHAoJdGh1bWJuYWlsGAQgASgJUgl0aHVtYm5haWwSJgoJdmlld190eXBlGAUgASgOMgkuVmlld1R5cGVSCHZpZXdUeXBl');
 @$core.Deprecated('Use viewDescriptor instead')
 const View$json = const {
   '1': 'View',

+ 47 - 0
app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/view_delete.pb.dart

@@ -56,3 +56,50 @@ class DeleteViewRequest extends $pb.GeneratedMessage {
   void clearViewId() => clearField(1);
 }
 
+class DeleteViewParams extends $pb.GeneratedMessage {
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'DeleteViewParams', createEmptyInstance: create)
+    ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'viewId')
+    ..hasRequiredFields = false
+  ;
+
+  DeleteViewParams._() : super();
+  factory DeleteViewParams({
+    $core.String? viewId,
+  }) {
+    final _result = create();
+    if (viewId != null) {
+      _result.viewId = viewId;
+    }
+    return _result;
+  }
+  factory DeleteViewParams.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory DeleteViewParams.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')
+  DeleteViewParams clone() => DeleteViewParams()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  DeleteViewParams copyWith(void Function(DeleteViewParams) updates) => super.copyWith((message) => updates(message as DeleteViewParams)) as DeleteViewParams; // ignore: deprecated_member_use
+  $pb.BuilderInfo get info_ => _i;
+  @$core.pragma('dart2js:noInline')
+  static DeleteViewParams create() => DeleteViewParams._();
+  DeleteViewParams createEmptyInstance() => create();
+  static $pb.PbList<DeleteViewParams> createRepeated() => $pb.PbList<DeleteViewParams>();
+  @$core.pragma('dart2js:noInline')
+  static DeleteViewParams getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<DeleteViewParams>(create);
+  static DeleteViewParams? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $core.String get viewId => $_getSZ(0);
+  @$pb.TagNumber(1)
+  set viewId($core.String v) { $_setString(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasViewId() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearViewId() => clearField(1);
+}
+

+ 10 - 0
app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/view_delete.pbjson.dart

@@ -18,3 +18,13 @@ const DeleteViewRequest$json = const {
 
 /// Descriptor for `DeleteViewRequest`. Decode as a `google.protobuf.DescriptorProto`.
 final $typed_data.Uint8List deleteViewRequestDescriptor = $convert.base64Decode('ChFEZWxldGVWaWV3UmVxdWVzdBIXCgd2aWV3X2lkGAEgASgJUgZ2aWV3SWQ=');
+@$core.Deprecated('Use deleteViewParamsDescriptor instead')
+const DeleteViewParams$json = const {
+  '1': 'DeleteViewParams',
+  '2': const [
+    const {'1': 'view_id', '3': 1, '4': 1, '5': 9, '10': 'viewId'},
+  ],
+};
+
+/// Descriptor for `DeleteViewParams`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List deleteViewParamsDescriptor = $convert.base64Decode('ChBEZWxldGVWaWV3UGFyYW1zEhcKB3ZpZXdfaWQYASABKAlSBnZpZXdJZA==');

+ 75 - 0
app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/view_query.pb.dart

@@ -84,3 +84,78 @@ class QueryViewRequest extends $pb.GeneratedMessage {
   void clearReadBelongings() => clearField(3);
 }
 
+class QueryViewParams extends $pb.GeneratedMessage {
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'QueryViewParams', createEmptyInstance: create)
+    ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'viewId')
+    ..aOB(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'isTrash')
+    ..aOB(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'readBelongings')
+    ..hasRequiredFields = false
+  ;
+
+  QueryViewParams._() : super();
+  factory QueryViewParams({
+    $core.String? viewId,
+    $core.bool? isTrash,
+    $core.bool? readBelongings,
+  }) {
+    final _result = create();
+    if (viewId != null) {
+      _result.viewId = viewId;
+    }
+    if (isTrash != null) {
+      _result.isTrash = isTrash;
+    }
+    if (readBelongings != null) {
+      _result.readBelongings = readBelongings;
+    }
+    return _result;
+  }
+  factory QueryViewParams.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory QueryViewParams.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')
+  QueryViewParams clone() => QueryViewParams()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  QueryViewParams copyWith(void Function(QueryViewParams) updates) => super.copyWith((message) => updates(message as QueryViewParams)) as QueryViewParams; // ignore: deprecated_member_use
+  $pb.BuilderInfo get info_ => _i;
+  @$core.pragma('dart2js:noInline')
+  static QueryViewParams create() => QueryViewParams._();
+  QueryViewParams createEmptyInstance() => create();
+  static $pb.PbList<QueryViewParams> createRepeated() => $pb.PbList<QueryViewParams>();
+  @$core.pragma('dart2js:noInline')
+  static QueryViewParams getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<QueryViewParams>(create);
+  static QueryViewParams? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $core.String get viewId => $_getSZ(0);
+  @$pb.TagNumber(1)
+  set viewId($core.String v) { $_setString(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasViewId() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearViewId() => clearField(1);
+
+  @$pb.TagNumber(2)
+  $core.bool get isTrash => $_getBF(1);
+  @$pb.TagNumber(2)
+  set isTrash($core.bool v) { $_setBool(1, v); }
+  @$pb.TagNumber(2)
+  $core.bool hasIsTrash() => $_has(1);
+  @$pb.TagNumber(2)
+  void clearIsTrash() => clearField(2);
+
+  @$pb.TagNumber(3)
+  $core.bool get readBelongings => $_getBF(2);
+  @$pb.TagNumber(3)
+  set readBelongings($core.bool v) { $_setBool(2, v); }
+  @$pb.TagNumber(3)
+  $core.bool hasReadBelongings() => $_has(2);
+  @$pb.TagNumber(3)
+  void clearReadBelongings() => clearField(3);
+}
+

+ 12 - 0
app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/view_query.pbjson.dart

@@ -20,3 +20,15 @@ const QueryViewRequest$json = const {
 
 /// Descriptor for `QueryViewRequest`. Decode as a `google.protobuf.DescriptorProto`.
 final $typed_data.Uint8List queryViewRequestDescriptor = $convert.base64Decode('ChBRdWVyeVZpZXdSZXF1ZXN0EhcKB3ZpZXdfaWQYASABKAlSBnZpZXdJZBIZCghpc190cmFzaBgCIAEoCFIHaXNUcmFzaBInCg9yZWFkX2JlbG9uZ2luZ3MYAyABKAhSDnJlYWRCZWxvbmdpbmdz');
+@$core.Deprecated('Use queryViewParamsDescriptor instead')
+const QueryViewParams$json = const {
+  '1': 'QueryViewParams',
+  '2': const [
+    const {'1': 'view_id', '3': 1, '4': 1, '5': 9, '10': 'viewId'},
+    const {'1': 'is_trash', '3': 2, '4': 1, '5': 8, '10': 'isTrash'},
+    const {'1': 'read_belongings', '3': 3, '4': 1, '5': 8, '10': 'readBelongings'},
+  ],
+};
+
+/// Descriptor for `QueryViewParams`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List queryViewParamsDescriptor = $convert.base64Decode('Cg9RdWVyeVZpZXdQYXJhbXMSFwoHdmlld19pZBgBIAEoCVIGdmlld0lkEhkKCGlzX3RyYXNoGAIgASgIUgdpc1RyYXNoEicKD3JlYWRfYmVsb25naW5ncxgDIAEoCFIOcmVhZEJlbG9uZ2luZ3M=');

+ 155 - 0
app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/view_update.pb.dart

@@ -164,3 +164,158 @@ class UpdateViewRequest extends $pb.GeneratedMessage {
   void clearIsTrash() => clearField(5);
 }
 
+enum UpdateViewParams_OneOfName {
+  name, 
+  notSet
+}
+
+enum UpdateViewParams_OneOfDesc {
+  desc, 
+  notSet
+}
+
+enum UpdateViewParams_OneOfThumbnail {
+  thumbnail, 
+  notSet
+}
+
+enum UpdateViewParams_OneOfIsTrash {
+  isTrash, 
+  notSet
+}
+
+class UpdateViewParams extends $pb.GeneratedMessage {
+  static const $core.Map<$core.int, UpdateViewParams_OneOfName> _UpdateViewParams_OneOfNameByTag = {
+    2 : UpdateViewParams_OneOfName.name,
+    0 : UpdateViewParams_OneOfName.notSet
+  };
+  static const $core.Map<$core.int, UpdateViewParams_OneOfDesc> _UpdateViewParams_OneOfDescByTag = {
+    3 : UpdateViewParams_OneOfDesc.desc,
+    0 : UpdateViewParams_OneOfDesc.notSet
+  };
+  static const $core.Map<$core.int, UpdateViewParams_OneOfThumbnail> _UpdateViewParams_OneOfThumbnailByTag = {
+    4 : UpdateViewParams_OneOfThumbnail.thumbnail,
+    0 : UpdateViewParams_OneOfThumbnail.notSet
+  };
+  static const $core.Map<$core.int, UpdateViewParams_OneOfIsTrash> _UpdateViewParams_OneOfIsTrashByTag = {
+    5 : UpdateViewParams_OneOfIsTrash.isTrash,
+    0 : UpdateViewParams_OneOfIsTrash.notSet
+  };
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'UpdateViewParams', createEmptyInstance: create)
+    ..oo(0, [2])
+    ..oo(1, [3])
+    ..oo(2, [4])
+    ..oo(3, [5])
+    ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'viewId')
+    ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'name')
+    ..aOS(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'desc')
+    ..aOS(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'thumbnail')
+    ..aOB(5, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'isTrash')
+    ..hasRequiredFields = false
+  ;
+
+  UpdateViewParams._() : super();
+  factory UpdateViewParams({
+    $core.String? viewId,
+    $core.String? name,
+    $core.String? desc,
+    $core.String? thumbnail,
+    $core.bool? isTrash,
+  }) {
+    final _result = create();
+    if (viewId != null) {
+      _result.viewId = viewId;
+    }
+    if (name != null) {
+      _result.name = name;
+    }
+    if (desc != null) {
+      _result.desc = desc;
+    }
+    if (thumbnail != null) {
+      _result.thumbnail = thumbnail;
+    }
+    if (isTrash != null) {
+      _result.isTrash = isTrash;
+    }
+    return _result;
+  }
+  factory UpdateViewParams.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory UpdateViewParams.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')
+  UpdateViewParams clone() => UpdateViewParams()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  UpdateViewParams copyWith(void Function(UpdateViewParams) updates) => super.copyWith((message) => updates(message as UpdateViewParams)) as UpdateViewParams; // ignore: deprecated_member_use
+  $pb.BuilderInfo get info_ => _i;
+  @$core.pragma('dart2js:noInline')
+  static UpdateViewParams create() => UpdateViewParams._();
+  UpdateViewParams createEmptyInstance() => create();
+  static $pb.PbList<UpdateViewParams> createRepeated() => $pb.PbList<UpdateViewParams>();
+  @$core.pragma('dart2js:noInline')
+  static UpdateViewParams getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<UpdateViewParams>(create);
+  static UpdateViewParams? _defaultInstance;
+
+  UpdateViewParams_OneOfName whichOneOfName() => _UpdateViewParams_OneOfNameByTag[$_whichOneof(0)]!;
+  void clearOneOfName() => clearField($_whichOneof(0));
+
+  UpdateViewParams_OneOfDesc whichOneOfDesc() => _UpdateViewParams_OneOfDescByTag[$_whichOneof(1)]!;
+  void clearOneOfDesc() => clearField($_whichOneof(1));
+
+  UpdateViewParams_OneOfThumbnail whichOneOfThumbnail() => _UpdateViewParams_OneOfThumbnailByTag[$_whichOneof(2)]!;
+  void clearOneOfThumbnail() => clearField($_whichOneof(2));
+
+  UpdateViewParams_OneOfIsTrash whichOneOfIsTrash() => _UpdateViewParams_OneOfIsTrashByTag[$_whichOneof(3)]!;
+  void clearOneOfIsTrash() => clearField($_whichOneof(3));
+
+  @$pb.TagNumber(1)
+  $core.String get viewId => $_getSZ(0);
+  @$pb.TagNumber(1)
+  set viewId($core.String v) { $_setString(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasViewId() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearViewId() => clearField(1);
+
+  @$pb.TagNumber(2)
+  $core.String get name => $_getSZ(1);
+  @$pb.TagNumber(2)
+  set name($core.String v) { $_setString(1, v); }
+  @$pb.TagNumber(2)
+  $core.bool hasName() => $_has(1);
+  @$pb.TagNumber(2)
+  void clearName() => clearField(2);
+
+  @$pb.TagNumber(3)
+  $core.String get desc => $_getSZ(2);
+  @$pb.TagNumber(3)
+  set desc($core.String v) { $_setString(2, v); }
+  @$pb.TagNumber(3)
+  $core.bool hasDesc() => $_has(2);
+  @$pb.TagNumber(3)
+  void clearDesc() => clearField(3);
+
+  @$pb.TagNumber(4)
+  $core.String get thumbnail => $_getSZ(3);
+  @$pb.TagNumber(4)
+  set thumbnail($core.String v) { $_setString(3, v); }
+  @$pb.TagNumber(4)
+  $core.bool hasThumbnail() => $_has(3);
+  @$pb.TagNumber(4)
+  void clearThumbnail() => clearField(4);
+
+  @$pb.TagNumber(5)
+  $core.bool get isTrash => $_getBF(4);
+  @$pb.TagNumber(5)
+  set isTrash($core.bool v) { $_setBool(4, v); }
+  @$pb.TagNumber(5)
+  $core.bool hasIsTrash() => $_has(4);
+  @$pb.TagNumber(5)
+  void clearIsTrash() => clearField(5);
+}
+

+ 20 - 0
app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/view_update.pbjson.dart

@@ -28,3 +28,23 @@ const UpdateViewRequest$json = const {
 
 /// Descriptor for `UpdateViewRequest`. Decode as a `google.protobuf.DescriptorProto`.
 final $typed_data.Uint8List updateViewRequestDescriptor = $convert.base64Decode('ChFVcGRhdGVWaWV3UmVxdWVzdBIXCgd2aWV3X2lkGAEgASgJUgZ2aWV3SWQSFAoEbmFtZRgCIAEoCUgAUgRuYW1lEhQKBGRlc2MYAyABKAlIAVIEZGVzYxIeCgl0aHVtYm5haWwYBCABKAlIAlIJdGh1bWJuYWlsEhsKCGlzX3RyYXNoGAUgASgISANSB2lzVHJhc2hCDQoLb25lX29mX25hbWVCDQoLb25lX29mX2Rlc2NCEgoQb25lX29mX3RodW1ibmFpbEIRCg9vbmVfb2ZfaXNfdHJhc2g=');
+@$core.Deprecated('Use updateViewParamsDescriptor instead')
+const UpdateViewParams$json = const {
+  '1': 'UpdateViewParams',
+  '2': const [
+    const {'1': 'view_id', '3': 1, '4': 1, '5': 9, '10': 'viewId'},
+    const {'1': 'name', '3': 2, '4': 1, '5': 9, '9': 0, '10': 'name'},
+    const {'1': 'desc', '3': 3, '4': 1, '5': 9, '9': 1, '10': 'desc'},
+    const {'1': 'thumbnail', '3': 4, '4': 1, '5': 9, '9': 2, '10': 'thumbnail'},
+    const {'1': 'is_trash', '3': 5, '4': 1, '5': 8, '9': 3, '10': 'isTrash'},
+  ],
+  '8': const [
+    const {'1': 'one_of_name'},
+    const {'1': 'one_of_desc'},
+    const {'1': 'one_of_thumbnail'},
+    const {'1': 'one_of_is_trash'},
+  ],
+};
+
+/// Descriptor for `UpdateViewParams`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List updateViewParamsDescriptor = $convert.base64Decode('ChBVcGRhdGVWaWV3UGFyYW1zEhcKB3ZpZXdfaWQYASABKAlSBnZpZXdJZBIUCgRuYW1lGAIgASgJSABSBG5hbWUSFAoEZGVzYxgDIAEoCUgBUgRkZXNjEh4KCXRodW1ibmFpbBgEIAEoCUgCUgl0aHVtYm5haWwSGwoIaXNfdHJhc2gYBSABKAhIA1IHaXNUcmFzaEINCgtvbmVfb2ZfbmFtZUINCgtvbmVfb2ZfZGVzY0ISChBvbmVfb2ZfdGh1bWJuYWlsQhEKD29uZV9vZl9pc190cmFzaA==');

+ 4 - 4
backend/src/application.rs

@@ -86,10 +86,10 @@ fn user_scope() -> Scope {
             .route(web::patch().to(app::update_handler))
         )
         .service(web::resource("/view")
-            .route(web::post().to(view::create_view))
-            .route(web::delete().to(view::delete_view))
-            .route(web::get().to(view::read_view))
-            .route(web::patch().to(view::update_view))
+            .route(web::post().to(view::create_handler))
+            .route(web::delete().to(view::delete_handler))
+            .route(web::get().to(view::read_handler))
+            .route(web::patch().to(view::update_handler))
         )
         // password
         .service(web::resource("/password_change")

+ 2 - 1
backend/src/workspace_service/app/app.rs

@@ -110,7 +110,7 @@ pub(crate) async fn read_app(
     };
 
     if params.read_belongings {
-        // app.belongings
+        // TODO: read belongings
     }
 
     FlowyResponse::success().data(app)
@@ -166,6 +166,7 @@ pub(crate) async fn update_app(
         .add_some_arg("workspace_id", workspace_id)
         .add_some_arg("color_style", color_style)
         .add_some_arg("description", desc)
+        .add_some_arg("modified_time", Some(Utc::now()))
         .add_arg_if(params.has_is_trash(), "is_trash", params.get_is_trash())
         .and_where_eq("id", app_id)
         .build()?;

+ 3 - 0
backend/src/workspace_service/view/mod.rs

@@ -1 +1,4 @@
 pub mod router;
+mod view;
+
+pub use view::*;

+ 26 - 12
backend/src/workspace_service/view/router.rs

@@ -1,3 +1,7 @@
+use crate::{
+    routers::utils::parse_from_payload,
+    workspace_service::view::{create_view, delete_view, read_view, update_view},
+};
 use actix_identity::Identity;
 use actix_web::{
     web::{Data, Payload},
@@ -6,36 +10,46 @@ use actix_web::{
     HttpResponse,
 };
 use flowy_net::errors::ServerError;
+use flowy_workspace::protobuf::{
+    CreateViewParams,
+    DeleteViewParams,
+    QueryViewParams,
+    UpdateViewParams,
+};
 use sqlx::PgPool;
 
-pub async fn create_view(
+pub async fn create_handler(
     payload: Payload,
-    id: Identity,
     pool: Data<PgPool>,
 ) -> Result<HttpResponse, ServerError> {
-    unimplemented!()
+    let params: CreateViewParams = parse_from_payload(payload).await?;
+    let resp = create_view(pool.get_ref(), params).await?;
+    Ok(resp.into())
 }
 
-pub async fn read_view(
+pub async fn read_handler(
     payload: Payload,
-    id: Identity,
     pool: Data<PgPool>,
 ) -> Result<HttpResponse, ServerError> {
-    unimplemented!()
+    let params: QueryViewParams = parse_from_payload(payload).await?;
+    let resp = read_view(pool.get_ref(), params).await?;
+    Ok(resp.into())
 }
 
-pub async fn update_view(
+pub async fn update_handler(
     payload: Payload,
-    id: Identity,
     pool: Data<PgPool>,
 ) -> Result<HttpResponse, ServerError> {
-    unimplemented!()
+    let params: UpdateViewParams = parse_from_payload(payload).await?;
+    let resp = update_view(pool.get_ref(), params).await?;
+    Ok(resp.into())
 }
 
-pub async fn delete_view(
+pub async fn delete_handler(
     payload: Payload,
-    id: Identity,
     pool: Data<PgPool>,
 ) -> Result<HttpResponse, ServerError> {
-    unimplemented!()
+    let params: DeleteViewParams = parse_from_payload(payload).await?;
+    let resp = delete_view(pool.get_ref(), &params.view_id).await?;
+    Ok(resp.into())
 }

+ 230 - 0
backend/src/workspace_service/view/view.rs

@@ -0,0 +1,230 @@
+use crate::{
+    entities::workspace::ViewTable,
+    sqlx_ext::{map_sqlx_error, SqlBuilder},
+};
+use anyhow::Context;
+use chrono::Utc;
+use flowy_net::{
+    errors::{invalid_params, ServerError},
+    response::FlowyResponse,
+};
+use flowy_workspace::{
+    entities::{
+        app::parser::AppId,
+        view::{
+            parser::{ViewDesc, ViewId, ViewName, ViewThumbnail},
+            RepeatedView,
+            View,
+            ViewType,
+        },
+    },
+    protobuf::{CreateViewParams, QueryViewParams, UpdateViewParams},
+};
+use protobuf::ProtobufEnum;
+use sqlx::{postgres::PgArguments, PgPool, Postgres};
+use uuid::Uuid;
+
+pub(crate) async fn create_view(
+    pool: &PgPool,
+    params: CreateViewParams,
+) -> Result<FlowyResponse, ServerError> {
+    let name = ViewName::parse(params.name).map_err(invalid_params)?;
+    let belong_to_id = AppId::parse(params.belong_to_id).map_err(invalid_params)?;
+    let thumbnail = ViewThumbnail::parse(params.thumbnail).map_err(invalid_params)?;
+    let desc = ViewDesc::parse(params.desc).map_err(invalid_params)?;
+
+    let mut transaction = pool
+        .begin()
+        .await
+        .context("Failed to acquire a Postgres connection to create view")?;
+
+    let uuid = uuid::Uuid::new_v4();
+    let time = Utc::now();
+
+    let (sql, args) = SqlBuilder::create("view_table")
+        .add_arg("id", uuid)
+        .add_arg("belong_to_id", belong_to_id.as_ref())
+        .add_arg("name", name.as_ref())
+        .add_arg("description", desc.as_ref())
+        .add_arg("modified_time", &time)
+        .add_arg("create_time", &time)
+        .add_arg("thumbnail", thumbnail.as_ref())
+        .add_arg("view_type", params.view_type.value())
+        .build()?;
+
+    let _ = sqlx::query_with(&sql, args)
+        .execute(&mut transaction)
+        .await
+        .map_err(map_sqlx_error)?;
+
+    transaction
+        .commit()
+        .await
+        .context("Failed to commit SQL transaction to create view.")?;
+
+    // a little confused here, different type with the same name in different crate
+    // let view_type = match params.view_type {
+    //     flowy_workspace::protobuf::ViewType::Blank => ViewType::Doc,
+    //     flowy_workspace::protobuf::ViewType::Doc => ViewType::Doc,
+    // };
+
+    let view = View {
+        id: uuid.to_string(),
+        belong_to_id: belong_to_id.as_ref().to_owned(),
+        name: name.as_ref().to_owned(),
+        desc: desc.as_ref().to_owned(),
+        view_type: params.view_type.value().into(),
+        version: 0,
+        belongings: RepeatedView::default(),
+    };
+
+    FlowyResponse::success().data(view)
+}
+
+pub(crate) async fn read_view(
+    pool: &PgPool,
+    params: QueryViewParams,
+) -> Result<FlowyResponse, ServerError> {
+    let view_id = check_view_id(params.view_id)?;
+    let mut transaction = pool
+        .begin()
+        .await
+        .context("Failed to acquire a Postgres connection to read view")?;
+
+    let (sql, args) = SqlBuilder::select("view_table")
+        .add_field("*")
+        .and_where_eq("id", view_id)
+        .build()?;
+
+    let table = sqlx::query_as_with::<Postgres, ViewTable, PgArguments>(&sql, args)
+        .fetch_one(&mut transaction)
+        .await
+        .map_err(map_sqlx_error)?;
+
+    transaction
+        .commit()
+        .await
+        .context("Failed to commit SQL transaction to read view.")?;
+
+    let view = View {
+        id: table.id.to_string(),
+        belong_to_id: table.belong_to_id,
+        name: table.name,
+        desc: table.description,
+        view_type: ViewType::from(table.view_type),
+        version: 0,
+        belongings: RepeatedView::default(),
+    };
+
+    if params.read_belongings {
+        // TODO: read belongings
+    }
+    FlowyResponse::success().data(view)
+}
+
+pub(crate) async fn update_view(
+    pool: &PgPool,
+    params: UpdateViewParams,
+) -> Result<FlowyResponse, ServerError> {
+    let view_id = check_view_id(params.view_id.clone())?;
+    // #[pb(index = 1)]
+    // pub view_id: String,
+    //
+    // #[pb(index = 2, one_of)]
+    // pub name: Option<String>,
+    //
+    // #[pb(index = 3, one_of)]
+    // pub desc: Option<String>,
+    //
+    // #[pb(index = 4, one_of)]
+    // pub thumbnail: Option<String>,
+    //
+    // #[pb(index = 5, one_of)]
+    // pub is_trash: Option<bool>,
+
+    let name = match params.has_name() {
+        false => None,
+        true => Some(
+            ViewName::parse(params.get_name().to_owned())
+                .map_err(invalid_params)?
+                .0,
+        ),
+    };
+
+    let desc = match params.has_desc() {
+        false => None,
+        true => Some(
+            ViewDesc::parse(params.get_desc().to_owned())
+                .map_err(invalid_params)?
+                .0,
+        ),
+    };
+
+    let thumbnail = match params.has_thumbnail() {
+        false => None,
+        true => Some(
+            ViewThumbnail::parse(params.get_thumbnail().to_owned())
+                .map_err(invalid_params)?
+                .0,
+        ),
+    };
+
+    let mut transaction = pool
+        .begin()
+        .await
+        .context("Failed to acquire a Postgres connection to update app")?;
+
+    let (sql, args) = SqlBuilder::update("view_table")
+        .add_some_arg("name", name)
+        .add_some_arg("description", desc)
+        .add_some_arg("thumbnail", thumbnail)
+        .add_some_arg("modified_time", Some(Utc::now()))
+        .add_arg_if(params.has_is_trash(), "is_trash", params.get_is_trash())
+        .and_where_eq("id", view_id)
+        .build()?;
+
+    sqlx::query_with(&sql, args)
+        .execute(&mut transaction)
+        .await
+        .map_err(map_sqlx_error)?;
+
+    transaction
+        .commit()
+        .await
+        .context("Failed to commit SQL transaction to update view.")?;
+
+    Ok(FlowyResponse::success())
+}
+
+pub(crate) async fn delete_view(
+    pool: &PgPool,
+    view_id: &str,
+) -> Result<FlowyResponse, ServerError> {
+    let view_id = check_view_id(view_id.to_owned())?;
+    let mut transaction = pool
+        .begin()
+        .await
+        .context("Failed to acquire a Postgres connection to delete view")?;
+
+    let (sql, args) = SqlBuilder::delete("view_table")
+        .and_where_eq("id", view_id)
+        .build()?;
+
+    let _ = sqlx::query_with(&sql, args)
+        .execute(&mut transaction)
+        .await
+        .map_err(map_sqlx_error)?;
+
+    transaction
+        .commit()
+        .await
+        .context("Failed to commit SQL transaction to delete view.")?;
+
+    Ok(FlowyResponse::success())
+}
+
+fn check_view_id(id: String) -> Result<Uuid, ServerError> {
+    let view_id = ViewId::parse(id).map_err(invalid_params)?;
+    let view_id = Uuid::parse_str(view_id.as_ref())?;
+    Ok(view_id)
+}

+ 22 - 0
backend/tests/api/helper.rs

@@ -71,6 +71,28 @@ impl TestApp {
         delete_app_request(params, &url).await.unwrap();
     }
 
+    pub async fn create_view(&self, params: CreateViewParams) -> View {
+        let url = format!("{}/api/view", self.address);
+        let view = create_view_request(params, &url).await.unwrap();
+        view
+    }
+
+    pub async fn read_view(&self, params: QueryViewParams) -> Option<View> {
+        let url = format!("{}/api/view", self.address);
+        let view = read_view_request(params, &url).await.unwrap();
+        view
+    }
+
+    pub async fn update_view(&self, params: UpdateViewParams) {
+        let url = format!("{}/api/view", self.address);
+        update_view_request(params, &url).await.unwrap();
+    }
+
+    pub async fn delete_view(&self, params: DeleteViewParams) {
+        let url = format!("{}/api/view", self.address);
+        delete_view_request(params, &url).await.unwrap();
+    }
+
     pub(crate) async fn register_test_user(&self) -> SignUpResponse {
         let params = SignUpParams {
             email: "[email protected]".to_string(),

+ 66 - 0
backend/tests/api/workspace.rs

@@ -1,6 +1,7 @@
 use crate::helper::{spawn_app, TestApp};
 use flowy_workspace::entities::{
     app::{App, ColorStyle, CreateAppParams, DeleteAppParams, QueryAppParams, UpdateAppParams},
+    view::{CreateViewParams, DeleteViewParams, QueryViewParams, UpdateViewParams, View, ViewType},
     workspace::{
         CreateWorkspaceParams,
         DeleteWorkspaceParams,
@@ -156,3 +157,68 @@ async fn create_test_app(app: &TestApp) -> App {
     let app = app.create_app(params).await;
     app
 }
+
+#[actix_rt::test]
+async fn view_create() {
+    let application = spawn_app().await;
+    let view = create_test_view(&application).await;
+    log::info!("{:?}", view);
+}
+
+#[actix_rt::test]
+async fn view_update() {
+    let application = spawn_app().await;
+    let view = create_test_view(&application).await;
+
+    // update
+    let update_params = UpdateViewParams {
+        view_id: view.id.clone(),
+        name: Some("new view name".to_string()),
+        desc: None,
+        thumbnail: None,
+        is_trash: Some(true),
+    };
+    application.update_view(update_params).await;
+
+    // read
+    let read_params = QueryViewParams {
+        view_id: view.id.clone(),
+        is_trash: true,
+        read_belongings: false,
+    };
+    let view = application.read_view(read_params).await;
+    log::info!("{:?}", view);
+}
+
+#[actix_rt::test]
+async fn view_delete() {
+    let application = spawn_app().await;
+    let view = create_test_view(&application).await;
+
+    // delete
+    let delete_params = DeleteViewParams {
+        view_id: view.id.clone(),
+    };
+    application.delete_view(delete_params).await;
+
+    // read
+    let read_params = QueryViewParams {
+        view_id: view.id.clone(),
+        is_trash: true,
+        read_belongings: false,
+    };
+    assert_eq!(application.read_view(read_params).await.is_none(), true);
+}
+
+async fn create_test_view(application: &TestApp) -> View {
+    let app = create_test_app(&application).await;
+    let params = CreateViewParams {
+        belong_to_id: app.id.clone(),
+        name: "My first view".to_string(),
+        desc: "This is my first view".to_string(),
+        thumbnail: "http://1.png".to_string(),
+        view_type: ViewType::Doc,
+    };
+    let app = application.create_view(params).await;
+    app
+}

+ 4 - 0
rust-lib/flowy-derive/src/derive_cache/derive_cache.rs

@@ -40,9 +40,13 @@ pub fn category_from_str(type_str: &str) -> TypeCategory {
         | "QueryWorkspaceParams"
         | "CurrentWorkspace"
         | "UpdateViewRequest"
+        | "UpdateViewParams"
         | "DeleteViewRequest"
+        | "DeleteViewParams"
         | "QueryViewRequest"
+        | "QueryViewParams"
         | "CreateViewRequest"
+        | "CreateViewParams"
         | "View"
         | "RepeatedView"
         | "WorkspaceError"

+ 1 - 1
rust-lib/flowy-workspace/src/entities/view/mod.rs

@@ -1,4 +1,4 @@
-mod parser;
+pub mod parser;
 mod view_create;
 mod view_delete;
 mod view_query;

+ 0 - 2
rust-lib/flowy-workspace/src/entities/view/parser/mod.rs

@@ -2,10 +2,8 @@ mod view_desc;
 mod view_id;
 mod view_name;
 mod view_thumbnail;
-mod view_type;
 
 pub use view_desc::*;
 pub use view_id::*;
 pub use view_name::*;
 pub use view_thumbnail::*;
-pub use view_type::*;

+ 4 - 0
rust-lib/flowy-workspace/src/entities/view/parser/view_id.rs

@@ -10,3 +10,7 @@ impl ViewId {
         Ok(Self(s))
     }
 }
+
+impl AsRef<str> for ViewId {
+    fn as_ref(&self) -> &str { &self.0 }
+}

+ 0 - 15
rust-lib/flowy-workspace/src/entities/view/parser/view_type.rs

@@ -1,15 +0,0 @@
-use crate::{entities::view::ViewType, sql_tables::view::ViewTableType};
-
-#[derive(Debug)]
-pub struct ViewTypeCheck(pub ViewTableType);
-
-impl ViewTypeCheck {
-    pub fn parse(s: ViewType) -> Result<ViewTypeCheck, String> {
-        match s {
-            ViewType::Blank => {
-                Err("Impossible to here, because you can create blank view".to_owned())
-            },
-            ViewType::Doc => Ok(Self(ViewTableType::Docs)),
-        }
-    }
-}

+ 25 - 3
rust-lib/flowy-workspace/src/entities/view/view_create.rs

@@ -17,6 +17,19 @@ impl std::default::Default for ViewType {
     fn default() -> Self { ViewType::Blank }
 }
 
+impl std::convert::From<i32> for ViewType {
+    fn from(val: i32) -> Self {
+        match val {
+            1 => ViewType::Doc,
+            0 => ViewType::Blank,
+            _ => {
+                log::error!("Invalid view type: {}", val);
+                ViewType::Blank
+            },
+        }
+    }
+}
+
 #[derive(Default, ProtoBuf)]
 pub struct CreateViewRequest {
     #[pb(index = 1)]
@@ -35,12 +48,22 @@ pub struct CreateViewRequest {
     pub view_type: ViewType,
 }
 
+#[derive(Default, ProtoBuf)]
 pub struct CreateViewParams {
+    #[pb(index = 1)]
     pub belong_to_id: String,
+
+    #[pb(index = 2)]
     pub name: String,
+
+    #[pb(index = 3)]
     pub desc: String,
+
+    #[pb(index = 4)]
     pub thumbnail: String,
-    pub view_type: ViewTableType,
+
+    #[pb(index = 5)]
+    pub view_type: ViewType,
 }
 
 impl TryInto<CreateViewParams> for CreateViewRequest {
@@ -68,13 +91,12 @@ impl TryInto<CreateViewParams> for CreateViewRequest {
             },
         };
 
-        let view_type = ViewTypeCheck::parse(self.view_type).unwrap().0;
         Ok(CreateViewParams {
             belong_to_id,
             name,
             desc: self.desc,
             thumbnail,
-            view_type,
+            view_type: self.view_type,
         })
     }
 }

+ 3 - 1
rust-lib/flowy-workspace/src/entities/view/view_delete.rs

@@ -11,8 +11,10 @@ pub struct DeleteViewRequest {
     view_id: String,
 }
 
+#[derive(Default, ProtoBuf)]
 pub struct DeleteViewParams {
-    pub(crate) view_id: String,
+    #[pb(index = 1)]
+    pub view_id: String,
 }
 
 impl TryInto<DeleteViewParams> for DeleteViewRequest {

+ 6 - 0
rust-lib/flowy-workspace/src/entities/view/view_query.rs

@@ -32,9 +32,15 @@ impl QueryViewRequest {
     }
 }
 
+#[derive(Default, ProtoBuf)]
 pub struct QueryViewParams {
+    #[pb(index = 1)]
     pub view_id: String,
+
+    #[pb(index = 2)]
     pub is_trash: bool,
+
+    #[pb(index = 3)]
     pub read_belongings: bool,
 }
 

+ 10 - 0
rust-lib/flowy-workspace/src/entities/view/view_update.rs

@@ -23,11 +23,21 @@ pub struct UpdateViewRequest {
     pub is_trash: Option<bool>,
 }
 
+#[derive(Default, ProtoBuf)]
 pub struct UpdateViewParams {
+    #[pb(index = 1)]
     pub view_id: String,
+
+    #[pb(index = 2, one_of)]
     pub name: Option<String>,
+
+    #[pb(index = 3, one_of)]
     pub desc: Option<String>,
+
+    #[pb(index = 4, one_of)]
     pub thumbnail: Option<String>,
+
+    #[pb(index = 5, one_of)]
     pub is_trash: Option<bool>,
 }
 

+ 391 - 56
rust-lib/flowy-workspace/src/protobuf/model/view_create.rs

@@ -379,6 +379,322 @@ impl ::protobuf::reflect::ProtobufValue for CreateViewRequest {
     }
 }
 
+#[derive(PartialEq,Clone,Default)]
+pub struct CreateViewParams {
+    // message fields
+    pub belong_to_id: ::std::string::String,
+    pub name: ::std::string::String,
+    pub desc: ::std::string::String,
+    pub thumbnail: ::std::string::String,
+    pub view_type: ViewType,
+    // special fields
+    pub unknown_fields: ::protobuf::UnknownFields,
+    pub cached_size: ::protobuf::CachedSize,
+}
+
+impl<'a> ::std::default::Default for &'a CreateViewParams {
+    fn default() -> &'a CreateViewParams {
+        <CreateViewParams as ::protobuf::Message>::default_instance()
+    }
+}
+
+impl CreateViewParams {
+    pub fn new() -> CreateViewParams {
+        ::std::default::Default::default()
+    }
+
+    // string belong_to_id = 1;
+
+
+    pub fn get_belong_to_id(&self) -> &str {
+        &self.belong_to_id
+    }
+    pub fn clear_belong_to_id(&mut self) {
+        self.belong_to_id.clear();
+    }
+
+    // Param is passed by value, moved
+    pub fn set_belong_to_id(&mut self, v: ::std::string::String) {
+        self.belong_to_id = v;
+    }
+
+    // Mutable pointer to the field.
+    // If field is not initialized, it is initialized with default value first.
+    pub fn mut_belong_to_id(&mut self) -> &mut ::std::string::String {
+        &mut self.belong_to_id
+    }
+
+    // Take field
+    pub fn take_belong_to_id(&mut self) -> ::std::string::String {
+        ::std::mem::replace(&mut self.belong_to_id, ::std::string::String::new())
+    }
+
+    // string name = 2;
+
+
+    pub fn get_name(&self) -> &str {
+        &self.name
+    }
+    pub fn clear_name(&mut self) {
+        self.name.clear();
+    }
+
+    // Param is passed by value, moved
+    pub fn set_name(&mut self, v: ::std::string::String) {
+        self.name = v;
+    }
+
+    // Mutable pointer to the field.
+    // If field is not initialized, it is initialized with default value first.
+    pub fn mut_name(&mut self) -> &mut ::std::string::String {
+        &mut self.name
+    }
+
+    // Take field
+    pub fn take_name(&mut self) -> ::std::string::String {
+        ::std::mem::replace(&mut self.name, ::std::string::String::new())
+    }
+
+    // string desc = 3;
+
+
+    pub fn get_desc(&self) -> &str {
+        &self.desc
+    }
+    pub fn clear_desc(&mut self) {
+        self.desc.clear();
+    }
+
+    // Param is passed by value, moved
+    pub fn set_desc(&mut self, v: ::std::string::String) {
+        self.desc = v;
+    }
+
+    // Mutable pointer to the field.
+    // If field is not initialized, it is initialized with default value first.
+    pub fn mut_desc(&mut self) -> &mut ::std::string::String {
+        &mut self.desc
+    }
+
+    // Take field
+    pub fn take_desc(&mut self) -> ::std::string::String {
+        ::std::mem::replace(&mut self.desc, ::std::string::String::new())
+    }
+
+    // string thumbnail = 4;
+
+
+    pub fn get_thumbnail(&self) -> &str {
+        &self.thumbnail
+    }
+    pub fn clear_thumbnail(&mut self) {
+        self.thumbnail.clear();
+    }
+
+    // Param is passed by value, moved
+    pub fn set_thumbnail(&mut self, v: ::std::string::String) {
+        self.thumbnail = v;
+    }
+
+    // Mutable pointer to the field.
+    // If field is not initialized, it is initialized with default value first.
+    pub fn mut_thumbnail(&mut self) -> &mut ::std::string::String {
+        &mut self.thumbnail
+    }
+
+    // Take field
+    pub fn take_thumbnail(&mut self) -> ::std::string::String {
+        ::std::mem::replace(&mut self.thumbnail, ::std::string::String::new())
+    }
+
+    // .ViewType view_type = 5;
+
+
+    pub fn get_view_type(&self) -> ViewType {
+        self.view_type
+    }
+    pub fn clear_view_type(&mut self) {
+        self.view_type = ViewType::Blank;
+    }
+
+    // Param is passed by value, moved
+    pub fn set_view_type(&mut self, v: ViewType) {
+        self.view_type = v;
+    }
+}
+
+impl ::protobuf::Message for CreateViewParams {
+    fn is_initialized(&self) -> bool {
+        true
+    }
+
+    fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> {
+        while !is.eof()? {
+            let (field_number, wire_type) = is.read_tag_unpack()?;
+            match field_number {
+                1 => {
+                    ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.belong_to_id)?;
+                },
+                2 => {
+                    ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.name)?;
+                },
+                3 => {
+                    ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.desc)?;
+                },
+                4 => {
+                    ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.thumbnail)?;
+                },
+                5 => {
+                    ::protobuf::rt::read_proto3_enum_with_unknown_fields_into(wire_type, is, &mut self.view_type, 5, &mut self.unknown_fields)?
+                },
+                _ => {
+                    ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
+                },
+            };
+        }
+        ::std::result::Result::Ok(())
+    }
+
+    // Compute sizes of nested messages
+    #[allow(unused_variables)]
+    fn compute_size(&self) -> u32 {
+        let mut my_size = 0;
+        if !self.belong_to_id.is_empty() {
+            my_size += ::protobuf::rt::string_size(1, &self.belong_to_id);
+        }
+        if !self.name.is_empty() {
+            my_size += ::protobuf::rt::string_size(2, &self.name);
+        }
+        if !self.desc.is_empty() {
+            my_size += ::protobuf::rt::string_size(3, &self.desc);
+        }
+        if !self.thumbnail.is_empty() {
+            my_size += ::protobuf::rt::string_size(4, &self.thumbnail);
+        }
+        if self.view_type != ViewType::Blank {
+            my_size += ::protobuf::rt::enum_size(5, self.view_type);
+        }
+        my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
+        self.cached_size.set(my_size);
+        my_size
+    }
+
+    fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> {
+        if !self.belong_to_id.is_empty() {
+            os.write_string(1, &self.belong_to_id)?;
+        }
+        if !self.name.is_empty() {
+            os.write_string(2, &self.name)?;
+        }
+        if !self.desc.is_empty() {
+            os.write_string(3, &self.desc)?;
+        }
+        if !self.thumbnail.is_empty() {
+            os.write_string(4, &self.thumbnail)?;
+        }
+        if self.view_type != ViewType::Blank {
+            os.write_enum(5, ::protobuf::ProtobufEnum::value(&self.view_type))?;
+        }
+        os.write_unknown_fields(self.get_unknown_fields())?;
+        ::std::result::Result::Ok(())
+    }
+
+    fn get_cached_size(&self) -> u32 {
+        self.cached_size.get()
+    }
+
+    fn get_unknown_fields(&self) -> &::protobuf::UnknownFields {
+        &self.unknown_fields
+    }
+
+    fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields {
+        &mut self.unknown_fields
+    }
+
+    fn as_any(&self) -> &dyn (::std::any::Any) {
+        self as &dyn (::std::any::Any)
+    }
+    fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) {
+        self as &mut dyn (::std::any::Any)
+    }
+    fn into_any(self: ::std::boxed::Box<Self>) -> ::std::boxed::Box<dyn (::std::any::Any)> {
+        self
+    }
+
+    fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor {
+        Self::descriptor_static()
+    }
+
+    fn new() -> CreateViewParams {
+        CreateViewParams::new()
+    }
+
+    fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor {
+        static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT;
+        descriptor.get(|| {
+            let mut fields = ::std::vec::Vec::new();
+            fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
+                "belong_to_id",
+                |m: &CreateViewParams| { &m.belong_to_id },
+                |m: &mut CreateViewParams| { &mut m.belong_to_id },
+            ));
+            fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
+                "name",
+                |m: &CreateViewParams| { &m.name },
+                |m: &mut CreateViewParams| { &mut m.name },
+            ));
+            fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
+                "desc",
+                |m: &CreateViewParams| { &m.desc },
+                |m: &mut CreateViewParams| { &mut m.desc },
+            ));
+            fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
+                "thumbnail",
+                |m: &CreateViewParams| { &m.thumbnail },
+                |m: &mut CreateViewParams| { &mut m.thumbnail },
+            ));
+            fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeEnum<ViewType>>(
+                "view_type",
+                |m: &CreateViewParams| { &m.view_type },
+                |m: &mut CreateViewParams| { &mut m.view_type },
+            ));
+            ::protobuf::reflect::MessageDescriptor::new_pb_name::<CreateViewParams>(
+                "CreateViewParams",
+                fields,
+                file_descriptor_proto()
+            )
+        })
+    }
+
+    fn default_instance() -> &'static CreateViewParams {
+        static instance: ::protobuf::rt::LazyV2<CreateViewParams> = ::protobuf::rt::LazyV2::INIT;
+        instance.get(CreateViewParams::new)
+    }
+}
+
+impl ::protobuf::Clear for CreateViewParams {
+    fn clear(&mut self) {
+        self.belong_to_id.clear();
+        self.name.clear();
+        self.desc.clear();
+        self.thumbnail.clear();
+        self.view_type = ViewType::Blank;
+        self.unknown_fields.clear();
+    }
+}
+
+impl ::std::fmt::Debug for CreateViewParams {
+    fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
+        ::protobuf::text_format::fmt(self, f)
+    }
+}
+
+impl ::protobuf::reflect::ProtobufValue for CreateViewParams {
+    fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
+        ::protobuf::reflect::ReflectValueRef::Message(self)
+    }
+}
+
 #[derive(PartialEq,Clone,Default)]
 pub struct View {
     // message fields
@@ -1008,62 +1324,81 @@ static file_descriptor_proto_data: &'static [u8] = b"\
     long_to_id\x18\x01\x20\x01(\tR\nbelongToId\x12\x12\n\x04name\x18\x02\x20\
     \x01(\tR\x04name\x12\x12\n\x04desc\x18\x03\x20\x01(\tR\x04desc\x12\x1e\n\
     \tthumbnail\x18\x04\x20\x01(\tH\0R\tthumbnail\x12&\n\tview_type\x18\x05\
-    \x20\x01(\x0e2\t.ViewTypeR\x08viewTypeB\x12\n\x10one_of_thumbnail\"\xd1\
-    \x01\n\x04View\x12\x0e\n\x02id\x18\x01\x20\x01(\tR\x02id\x12\x20\n\x0cbe\
-    long_to_id\x18\x02\x20\x01(\tR\nbelongToId\x12\x12\n\x04name\x18\x03\x20\
-    \x01(\tR\x04name\x12\x12\n\x04desc\x18\x04\x20\x01(\tR\x04desc\x12&\n\tv\
-    iew_type\x18\x05\x20\x01(\x0e2\t.ViewTypeR\x08viewType\x12\x18\n\x07vers\
-    ion\x18\x06\x20\x01(\x03R\x07version\x12-\n\nbelongings\x18\x07\x20\x01(\
-    \x0b2\r.RepeatedViewR\nbelongings\"+\n\x0cRepeatedView\x12\x1b\n\x05item\
-    s\x18\x01\x20\x03(\x0b2\x05.ViewR\x05items*\x1e\n\x08ViewType\x12\t\n\
-    \x05Blank\x10\0\x12\x07\n\x03Doc\x10\x01J\xb8\x07\n\x06\x12\x04\0\0\x18\
-    \x01\n\x08\n\x01\x0c\x12\x03\0\0\x12\n\n\n\x02\x04\0\x12\x04\x02\0\x08\
-    \x01\n\n\n\x03\x04\0\x01\x12\x03\x02\x08\x19\n\x0b\n\x04\x04\0\x02\0\x12\
-    \x03\x03\x04\x1c\n\x0c\n\x05\x04\0\x02\0\x05\x12\x03\x03\x04\n\n\x0c\n\
-    \x05\x04\0\x02\0\x01\x12\x03\x03\x0b\x17\n\x0c\n\x05\x04\0\x02\0\x03\x12\
-    \x03\x03\x1a\x1b\n\x0b\n\x04\x04\0\x02\x01\x12\x03\x04\x04\x14\n\x0c\n\
-    \x05\x04\0\x02\x01\x05\x12\x03\x04\x04\n\n\x0c\n\x05\x04\0\x02\x01\x01\
-    \x12\x03\x04\x0b\x0f\n\x0c\n\x05\x04\0\x02\x01\x03\x12\x03\x04\x12\x13\n\
-    \x0b\n\x04\x04\0\x02\x02\x12\x03\x05\x04\x14\n\x0c\n\x05\x04\0\x02\x02\
-    \x05\x12\x03\x05\x04\n\n\x0c\n\x05\x04\0\x02\x02\x01\x12\x03\x05\x0b\x0f\
-    \n\x0c\n\x05\x04\0\x02\x02\x03\x12\x03\x05\x12\x13\n\x0b\n\x04\x04\0\x08\
-    \0\x12\x03\x06\x044\n\x0c\n\x05\x04\0\x08\0\x01\x12\x03\x06\n\x1a\n\x0b\
-    \n\x04\x04\0\x02\x03\x12\x03\x06\x1d2\n\x0c\n\x05\x04\0\x02\x03\x05\x12\
-    \x03\x06\x1d#\n\x0c\n\x05\x04\0\x02\x03\x01\x12\x03\x06$-\n\x0c\n\x05\
-    \x04\0\x02\x03\x03\x12\x03\x0601\n\x0b\n\x04\x04\0\x02\x04\x12\x03\x07\
-    \x04\x1b\n\x0c\n\x05\x04\0\x02\x04\x06\x12\x03\x07\x04\x0c\n\x0c\n\x05\
-    \x04\0\x02\x04\x01\x12\x03\x07\r\x16\n\x0c\n\x05\x04\0\x02\x04\x03\x12\
-    \x03\x07\x19\x1a\n\n\n\x02\x04\x01\x12\x04\t\0\x11\x01\n\n\n\x03\x04\x01\
-    \x01\x12\x03\t\x08\x0c\n\x0b\n\x04\x04\x01\x02\0\x12\x03\n\x04\x12\n\x0c\
-    \n\x05\x04\x01\x02\0\x05\x12\x03\n\x04\n\n\x0c\n\x05\x04\x01\x02\0\x01\
-    \x12\x03\n\x0b\r\n\x0c\n\x05\x04\x01\x02\0\x03\x12\x03\n\x10\x11\n\x0b\n\
-    \x04\x04\x01\x02\x01\x12\x03\x0b\x04\x1c\n\x0c\n\x05\x04\x01\x02\x01\x05\
-    \x12\x03\x0b\x04\n\n\x0c\n\x05\x04\x01\x02\x01\x01\x12\x03\x0b\x0b\x17\n\
-    \x0c\n\x05\x04\x01\x02\x01\x03\x12\x03\x0b\x1a\x1b\n\x0b\n\x04\x04\x01\
-    \x02\x02\x12\x03\x0c\x04\x14\n\x0c\n\x05\x04\x01\x02\x02\x05\x12\x03\x0c\
-    \x04\n\n\x0c\n\x05\x04\x01\x02\x02\x01\x12\x03\x0c\x0b\x0f\n\x0c\n\x05\
-    \x04\x01\x02\x02\x03\x12\x03\x0c\x12\x13\n\x0b\n\x04\x04\x01\x02\x03\x12\
-    \x03\r\x04\x14\n\x0c\n\x05\x04\x01\x02\x03\x05\x12\x03\r\x04\n\n\x0c\n\
-    \x05\x04\x01\x02\x03\x01\x12\x03\r\x0b\x0f\n\x0c\n\x05\x04\x01\x02\x03\
-    \x03\x12\x03\r\x12\x13\n\x0b\n\x04\x04\x01\x02\x04\x12\x03\x0e\x04\x1b\n\
-    \x0c\n\x05\x04\x01\x02\x04\x06\x12\x03\x0e\x04\x0c\n\x0c\n\x05\x04\x01\
-    \x02\x04\x01\x12\x03\x0e\r\x16\n\x0c\n\x05\x04\x01\x02\x04\x03\x12\x03\
-    \x0e\x19\x1a\n\x0b\n\x04\x04\x01\x02\x05\x12\x03\x0f\x04\x16\n\x0c\n\x05\
-    \x04\x01\x02\x05\x05\x12\x03\x0f\x04\t\n\x0c\n\x05\x04\x01\x02\x05\x01\
-    \x12\x03\x0f\n\x11\n\x0c\n\x05\x04\x01\x02\x05\x03\x12\x03\x0f\x14\x15\n\
-    \x0b\n\x04\x04\x01\x02\x06\x12\x03\x10\x04\x20\n\x0c\n\x05\x04\x01\x02\
-    \x06\x06\x12\x03\x10\x04\x10\n\x0c\n\x05\x04\x01\x02\x06\x01\x12\x03\x10\
-    \x11\x1b\n\x0c\n\x05\x04\x01\x02\x06\x03\x12\x03\x10\x1e\x1f\n\n\n\x02\
-    \x04\x02\x12\x04\x12\0\x14\x01\n\n\n\x03\x04\x02\x01\x12\x03\x12\x08\x14\
-    \n\x0b\n\x04\x04\x02\x02\0\x12\x03\x13\x04\x1c\n\x0c\n\x05\x04\x02\x02\0\
-    \x04\x12\x03\x13\x04\x0c\n\x0c\n\x05\x04\x02\x02\0\x06\x12\x03\x13\r\x11\
-    \n\x0c\n\x05\x04\x02\x02\0\x01\x12\x03\x13\x12\x17\n\x0c\n\x05\x04\x02\
-    \x02\0\x03\x12\x03\x13\x1a\x1b\n\n\n\x02\x05\0\x12\x04\x15\0\x18\x01\n\n\
-    \n\x03\x05\0\x01\x12\x03\x15\x05\r\n\x0b\n\x04\x05\0\x02\0\x12\x03\x16\
-    \x04\x0e\n\x0c\n\x05\x05\0\x02\0\x01\x12\x03\x16\x04\t\n\x0c\n\x05\x05\0\
-    \x02\0\x02\x12\x03\x16\x0c\r\n\x0b\n\x04\x05\0\x02\x01\x12\x03\x17\x04\
-    \x0c\n\x0c\n\x05\x05\0\x02\x01\x01\x12\x03\x17\x04\x07\n\x0c\n\x05\x05\0\
-    \x02\x01\x02\x12\x03\x17\n\x0bb\x06proto3\
+    \x20\x01(\x0e2\t.ViewTypeR\x08viewTypeB\x12\n\x10one_of_thumbnail\"\xa2\
+    \x01\n\x10CreateViewParams\x12\x20\n\x0cbelong_to_id\x18\x01\x20\x01(\tR\
+    \nbelongToId\x12\x12\n\x04name\x18\x02\x20\x01(\tR\x04name\x12\x12\n\x04\
+    desc\x18\x03\x20\x01(\tR\x04desc\x12\x1c\n\tthumbnail\x18\x04\x20\x01(\t\
+    R\tthumbnail\x12&\n\tview_type\x18\x05\x20\x01(\x0e2\t.ViewTypeR\x08view\
+    Type\"\xd1\x01\n\x04View\x12\x0e\n\x02id\x18\x01\x20\x01(\tR\x02id\x12\
+    \x20\n\x0cbelong_to_id\x18\x02\x20\x01(\tR\nbelongToId\x12\x12\n\x04name\
+    \x18\x03\x20\x01(\tR\x04name\x12\x12\n\x04desc\x18\x04\x20\x01(\tR\x04de\
+    sc\x12&\n\tview_type\x18\x05\x20\x01(\x0e2\t.ViewTypeR\x08viewType\x12\
+    \x18\n\x07version\x18\x06\x20\x01(\x03R\x07version\x12-\n\nbelongings\
+    \x18\x07\x20\x01(\x0b2\r.RepeatedViewR\nbelongings\"+\n\x0cRepeatedView\
+    \x12\x1b\n\x05items\x18\x01\x20\x03(\x0b2\x05.ViewR\x05items*\x1e\n\x08V\
+    iewType\x12\t\n\x05Blank\x10\0\x12\x07\n\x03Doc\x10\x01J\xe3\t\n\x06\x12\
+    \x04\0\0\x1f\x01\n\x08\n\x01\x0c\x12\x03\0\0\x12\n\n\n\x02\x04\0\x12\x04\
+    \x02\0\x08\x01\n\n\n\x03\x04\0\x01\x12\x03\x02\x08\x19\n\x0b\n\x04\x04\0\
+    \x02\0\x12\x03\x03\x04\x1c\n\x0c\n\x05\x04\0\x02\0\x05\x12\x03\x03\x04\n\
+    \n\x0c\n\x05\x04\0\x02\0\x01\x12\x03\x03\x0b\x17\n\x0c\n\x05\x04\0\x02\0\
+    \x03\x12\x03\x03\x1a\x1b\n\x0b\n\x04\x04\0\x02\x01\x12\x03\x04\x04\x14\n\
+    \x0c\n\x05\x04\0\x02\x01\x05\x12\x03\x04\x04\n\n\x0c\n\x05\x04\0\x02\x01\
+    \x01\x12\x03\x04\x0b\x0f\n\x0c\n\x05\x04\0\x02\x01\x03\x12\x03\x04\x12\
+    \x13\n\x0b\n\x04\x04\0\x02\x02\x12\x03\x05\x04\x14\n\x0c\n\x05\x04\0\x02\
+    \x02\x05\x12\x03\x05\x04\n\n\x0c\n\x05\x04\0\x02\x02\x01\x12\x03\x05\x0b\
+    \x0f\n\x0c\n\x05\x04\0\x02\x02\x03\x12\x03\x05\x12\x13\n\x0b\n\x04\x04\0\
+    \x08\0\x12\x03\x06\x044\n\x0c\n\x05\x04\0\x08\0\x01\x12\x03\x06\n\x1a\n\
+    \x0b\n\x04\x04\0\x02\x03\x12\x03\x06\x1d2\n\x0c\n\x05\x04\0\x02\x03\x05\
+    \x12\x03\x06\x1d#\n\x0c\n\x05\x04\0\x02\x03\x01\x12\x03\x06$-\n\x0c\n\
+    \x05\x04\0\x02\x03\x03\x12\x03\x0601\n\x0b\n\x04\x04\0\x02\x04\x12\x03\
+    \x07\x04\x1b\n\x0c\n\x05\x04\0\x02\x04\x06\x12\x03\x07\x04\x0c\n\x0c\n\
+    \x05\x04\0\x02\x04\x01\x12\x03\x07\r\x16\n\x0c\n\x05\x04\0\x02\x04\x03\
+    \x12\x03\x07\x19\x1a\n\n\n\x02\x04\x01\x12\x04\t\0\x0f\x01\n\n\n\x03\x04\
+    \x01\x01\x12\x03\t\x08\x18\n\x0b\n\x04\x04\x01\x02\0\x12\x03\n\x04\x1c\n\
+    \x0c\n\x05\x04\x01\x02\0\x05\x12\x03\n\x04\n\n\x0c\n\x05\x04\x01\x02\0\
+    \x01\x12\x03\n\x0b\x17\n\x0c\n\x05\x04\x01\x02\0\x03\x12\x03\n\x1a\x1b\n\
+    \x0b\n\x04\x04\x01\x02\x01\x12\x03\x0b\x04\x14\n\x0c\n\x05\x04\x01\x02\
+    \x01\x05\x12\x03\x0b\x04\n\n\x0c\n\x05\x04\x01\x02\x01\x01\x12\x03\x0b\
+    \x0b\x0f\n\x0c\n\x05\x04\x01\x02\x01\x03\x12\x03\x0b\x12\x13\n\x0b\n\x04\
+    \x04\x01\x02\x02\x12\x03\x0c\x04\x14\n\x0c\n\x05\x04\x01\x02\x02\x05\x12\
+    \x03\x0c\x04\n\n\x0c\n\x05\x04\x01\x02\x02\x01\x12\x03\x0c\x0b\x0f\n\x0c\
+    \n\x05\x04\x01\x02\x02\x03\x12\x03\x0c\x12\x13\n\x0b\n\x04\x04\x01\x02\
+    \x03\x12\x03\r\x04\x19\n\x0c\n\x05\x04\x01\x02\x03\x05\x12\x03\r\x04\n\n\
+    \x0c\n\x05\x04\x01\x02\x03\x01\x12\x03\r\x0b\x14\n\x0c\n\x05\x04\x01\x02\
+    \x03\x03\x12\x03\r\x17\x18\n\x0b\n\x04\x04\x01\x02\x04\x12\x03\x0e\x04\
+    \x1b\n\x0c\n\x05\x04\x01\x02\x04\x06\x12\x03\x0e\x04\x0c\n\x0c\n\x05\x04\
+    \x01\x02\x04\x01\x12\x03\x0e\r\x16\n\x0c\n\x05\x04\x01\x02\x04\x03\x12\
+    \x03\x0e\x19\x1a\n\n\n\x02\x04\x02\x12\x04\x10\0\x18\x01\n\n\n\x03\x04\
+    \x02\x01\x12\x03\x10\x08\x0c\n\x0b\n\x04\x04\x02\x02\0\x12\x03\x11\x04\
+    \x12\n\x0c\n\x05\x04\x02\x02\0\x05\x12\x03\x11\x04\n\n\x0c\n\x05\x04\x02\
+    \x02\0\x01\x12\x03\x11\x0b\r\n\x0c\n\x05\x04\x02\x02\0\x03\x12\x03\x11\
+    \x10\x11\n\x0b\n\x04\x04\x02\x02\x01\x12\x03\x12\x04\x1c\n\x0c\n\x05\x04\
+    \x02\x02\x01\x05\x12\x03\x12\x04\n\n\x0c\n\x05\x04\x02\x02\x01\x01\x12\
+    \x03\x12\x0b\x17\n\x0c\n\x05\x04\x02\x02\x01\x03\x12\x03\x12\x1a\x1b\n\
+    \x0b\n\x04\x04\x02\x02\x02\x12\x03\x13\x04\x14\n\x0c\n\x05\x04\x02\x02\
+    \x02\x05\x12\x03\x13\x04\n\n\x0c\n\x05\x04\x02\x02\x02\x01\x12\x03\x13\
+    \x0b\x0f\n\x0c\n\x05\x04\x02\x02\x02\x03\x12\x03\x13\x12\x13\n\x0b\n\x04\
+    \x04\x02\x02\x03\x12\x03\x14\x04\x14\n\x0c\n\x05\x04\x02\x02\x03\x05\x12\
+    \x03\x14\x04\n\n\x0c\n\x05\x04\x02\x02\x03\x01\x12\x03\x14\x0b\x0f\n\x0c\
+    \n\x05\x04\x02\x02\x03\x03\x12\x03\x14\x12\x13\n\x0b\n\x04\x04\x02\x02\
+    \x04\x12\x03\x15\x04\x1b\n\x0c\n\x05\x04\x02\x02\x04\x06\x12\x03\x15\x04\
+    \x0c\n\x0c\n\x05\x04\x02\x02\x04\x01\x12\x03\x15\r\x16\n\x0c\n\x05\x04\
+    \x02\x02\x04\x03\x12\x03\x15\x19\x1a\n\x0b\n\x04\x04\x02\x02\x05\x12\x03\
+    \x16\x04\x16\n\x0c\n\x05\x04\x02\x02\x05\x05\x12\x03\x16\x04\t\n\x0c\n\
+    \x05\x04\x02\x02\x05\x01\x12\x03\x16\n\x11\n\x0c\n\x05\x04\x02\x02\x05\
+    \x03\x12\x03\x16\x14\x15\n\x0b\n\x04\x04\x02\x02\x06\x12\x03\x17\x04\x20\
+    \n\x0c\n\x05\x04\x02\x02\x06\x06\x12\x03\x17\x04\x10\n\x0c\n\x05\x04\x02\
+    \x02\x06\x01\x12\x03\x17\x11\x1b\n\x0c\n\x05\x04\x02\x02\x06\x03\x12\x03\
+    \x17\x1e\x1f\n\n\n\x02\x04\x03\x12\x04\x19\0\x1b\x01\n\n\n\x03\x04\x03\
+    \x01\x12\x03\x19\x08\x14\n\x0b\n\x04\x04\x03\x02\0\x12\x03\x1a\x04\x1c\n\
+    \x0c\n\x05\x04\x03\x02\0\x04\x12\x03\x1a\x04\x0c\n\x0c\n\x05\x04\x03\x02\
+    \0\x06\x12\x03\x1a\r\x11\n\x0c\n\x05\x04\x03\x02\0\x01\x12\x03\x1a\x12\
+    \x17\n\x0c\n\x05\x04\x03\x02\0\x03\x12\x03\x1a\x1a\x1b\n\n\n\x02\x05\0\
+    \x12\x04\x1c\0\x1f\x01\n\n\n\x03\x05\0\x01\x12\x03\x1c\x05\r\n\x0b\n\x04\
+    \x05\0\x02\0\x12\x03\x1d\x04\x0e\n\x0c\n\x05\x05\0\x02\0\x01\x12\x03\x1d\
+    \x04\t\n\x0c\n\x05\x05\0\x02\0\x02\x12\x03\x1d\x0c\r\n\x0b\n\x04\x05\0\
+    \x02\x01\x12\x03\x1e\x04\x0c\n\x0c\n\x05\x05\0\x02\x01\x01\x12\x03\x1e\
+    \x04\x07\n\x0c\n\x05\x05\0\x02\x01\x02\x12\x03\x1e\n\x0bb\x06proto3\
 ";
 
 static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;

+ 169 - 5
rust-lib/flowy-workspace/src/protobuf/model/view_delete.rs

@@ -182,13 +182,177 @@ impl ::protobuf::reflect::ProtobufValue for DeleteViewRequest {
     }
 }
 
+#[derive(PartialEq,Clone,Default)]
+pub struct DeleteViewParams {
+    // message fields
+    pub view_id: ::std::string::String,
+    // special fields
+    pub unknown_fields: ::protobuf::UnknownFields,
+    pub cached_size: ::protobuf::CachedSize,
+}
+
+impl<'a> ::std::default::Default for &'a DeleteViewParams {
+    fn default() -> &'a DeleteViewParams {
+        <DeleteViewParams as ::protobuf::Message>::default_instance()
+    }
+}
+
+impl DeleteViewParams {
+    pub fn new() -> DeleteViewParams {
+        ::std::default::Default::default()
+    }
+
+    // string view_id = 1;
+
+
+    pub fn get_view_id(&self) -> &str {
+        &self.view_id
+    }
+    pub fn clear_view_id(&mut self) {
+        self.view_id.clear();
+    }
+
+    // Param is passed by value, moved
+    pub fn set_view_id(&mut self, v: ::std::string::String) {
+        self.view_id = v;
+    }
+
+    // Mutable pointer to the field.
+    // If field is not initialized, it is initialized with default value first.
+    pub fn mut_view_id(&mut self) -> &mut ::std::string::String {
+        &mut self.view_id
+    }
+
+    // Take field
+    pub fn take_view_id(&mut self) -> ::std::string::String {
+        ::std::mem::replace(&mut self.view_id, ::std::string::String::new())
+    }
+}
+
+impl ::protobuf::Message for DeleteViewParams {
+    fn is_initialized(&self) -> bool {
+        true
+    }
+
+    fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> {
+        while !is.eof()? {
+            let (field_number, wire_type) = is.read_tag_unpack()?;
+            match field_number {
+                1 => {
+                    ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.view_id)?;
+                },
+                _ => {
+                    ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
+                },
+            };
+        }
+        ::std::result::Result::Ok(())
+    }
+
+    // Compute sizes of nested messages
+    #[allow(unused_variables)]
+    fn compute_size(&self) -> u32 {
+        let mut my_size = 0;
+        if !self.view_id.is_empty() {
+            my_size += ::protobuf::rt::string_size(1, &self.view_id);
+        }
+        my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
+        self.cached_size.set(my_size);
+        my_size
+    }
+
+    fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> {
+        if !self.view_id.is_empty() {
+            os.write_string(1, &self.view_id)?;
+        }
+        os.write_unknown_fields(self.get_unknown_fields())?;
+        ::std::result::Result::Ok(())
+    }
+
+    fn get_cached_size(&self) -> u32 {
+        self.cached_size.get()
+    }
+
+    fn get_unknown_fields(&self) -> &::protobuf::UnknownFields {
+        &self.unknown_fields
+    }
+
+    fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields {
+        &mut self.unknown_fields
+    }
+
+    fn as_any(&self) -> &dyn (::std::any::Any) {
+        self as &dyn (::std::any::Any)
+    }
+    fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) {
+        self as &mut dyn (::std::any::Any)
+    }
+    fn into_any(self: ::std::boxed::Box<Self>) -> ::std::boxed::Box<dyn (::std::any::Any)> {
+        self
+    }
+
+    fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor {
+        Self::descriptor_static()
+    }
+
+    fn new() -> DeleteViewParams {
+        DeleteViewParams::new()
+    }
+
+    fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor {
+        static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT;
+        descriptor.get(|| {
+            let mut fields = ::std::vec::Vec::new();
+            fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
+                "view_id",
+                |m: &DeleteViewParams| { &m.view_id },
+                |m: &mut DeleteViewParams| { &mut m.view_id },
+            ));
+            ::protobuf::reflect::MessageDescriptor::new_pb_name::<DeleteViewParams>(
+                "DeleteViewParams",
+                fields,
+                file_descriptor_proto()
+            )
+        })
+    }
+
+    fn default_instance() -> &'static DeleteViewParams {
+        static instance: ::protobuf::rt::LazyV2<DeleteViewParams> = ::protobuf::rt::LazyV2::INIT;
+        instance.get(DeleteViewParams::new)
+    }
+}
+
+impl ::protobuf::Clear for DeleteViewParams {
+    fn clear(&mut self) {
+        self.view_id.clear();
+        self.unknown_fields.clear();
+    }
+}
+
+impl ::std::fmt::Debug for DeleteViewParams {
+    fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
+        ::protobuf::text_format::fmt(self, f)
+    }
+}
+
+impl ::protobuf::reflect::ProtobufValue for DeleteViewParams {
+    fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
+        ::protobuf::reflect::ReflectValueRef::Message(self)
+    }
+}
+
 static file_descriptor_proto_data: &'static [u8] = b"\
     \n\x11view_delete.proto\",\n\x11DeleteViewRequest\x12\x17\n\x07view_id\
-    \x18\x01\x20\x01(\tR\x06viewIdJa\n\x06\x12\x04\0\0\x04\x01\n\x08\n\x01\
-    \x0c\x12\x03\0\0\x12\n\n\n\x02\x04\0\x12\x04\x02\0\x04\x01\n\n\n\x03\x04\
-    \0\x01\x12\x03\x02\x08\x19\n\x0b\n\x04\x04\0\x02\0\x12\x03\x03\x04\x17\n\
-    \x0c\n\x05\x04\0\x02\0\x05\x12\x03\x03\x04\n\n\x0c\n\x05\x04\0\x02\0\x01\
-    \x12\x03\x03\x0b\x12\n\x0c\n\x05\x04\0\x02\0\x03\x12\x03\x03\x15\x16b\
+    \x18\x01\x20\x01(\tR\x06viewId\"+\n\x10DeleteViewParams\x12\x17\n\x07vie\
+    w_id\x18\x01\x20\x01(\tR\x06viewIdJ\xb0\x01\n\x06\x12\x04\0\0\x07\x01\n\
+    \x08\n\x01\x0c\x12\x03\0\0\x12\n\n\n\x02\x04\0\x12\x04\x02\0\x04\x01\n\n\
+    \n\x03\x04\0\x01\x12\x03\x02\x08\x19\n\x0b\n\x04\x04\0\x02\0\x12\x03\x03\
+    \x04\x17\n\x0c\n\x05\x04\0\x02\0\x05\x12\x03\x03\x04\n\n\x0c\n\x05\x04\0\
+    \x02\0\x01\x12\x03\x03\x0b\x12\n\x0c\n\x05\x04\0\x02\0\x03\x12\x03\x03\
+    \x15\x16\n\n\n\x02\x04\x01\x12\x04\x05\0\x07\x01\n\n\n\x03\x04\x01\x01\
+    \x12\x03\x05\x08\x18\n\x0b\n\x04\x04\x01\x02\0\x12\x03\x06\x04\x17\n\x0c\
+    \n\x05\x04\x01\x02\0\x05\x12\x03\x06\x04\n\n\x0c\n\x05\x04\x01\x02\0\x01\
+    \x12\x03\x06\x0b\x12\n\x0c\n\x05\x04\x01\x02\0\x03\x12\x03\x06\x15\x16b\
     \x06proto3\
 ";
 

+ 252 - 11
rust-lib/flowy-workspace/src/protobuf/model/view_query.rs

@@ -252,21 +252,262 @@ impl ::protobuf::reflect::ProtobufValue for QueryViewRequest {
     }
 }
 
+#[derive(PartialEq,Clone,Default)]
+pub struct QueryViewParams {
+    // message fields
+    pub view_id: ::std::string::String,
+    pub is_trash: bool,
+    pub read_belongings: bool,
+    // special fields
+    pub unknown_fields: ::protobuf::UnknownFields,
+    pub cached_size: ::protobuf::CachedSize,
+}
+
+impl<'a> ::std::default::Default for &'a QueryViewParams {
+    fn default() -> &'a QueryViewParams {
+        <QueryViewParams as ::protobuf::Message>::default_instance()
+    }
+}
+
+impl QueryViewParams {
+    pub fn new() -> QueryViewParams {
+        ::std::default::Default::default()
+    }
+
+    // string view_id = 1;
+
+
+    pub fn get_view_id(&self) -> &str {
+        &self.view_id
+    }
+    pub fn clear_view_id(&mut self) {
+        self.view_id.clear();
+    }
+
+    // Param is passed by value, moved
+    pub fn set_view_id(&mut self, v: ::std::string::String) {
+        self.view_id = v;
+    }
+
+    // Mutable pointer to the field.
+    // If field is not initialized, it is initialized with default value first.
+    pub fn mut_view_id(&mut self) -> &mut ::std::string::String {
+        &mut self.view_id
+    }
+
+    // Take field
+    pub fn take_view_id(&mut self) -> ::std::string::String {
+        ::std::mem::replace(&mut self.view_id, ::std::string::String::new())
+    }
+
+    // bool is_trash = 2;
+
+
+    pub fn get_is_trash(&self) -> bool {
+        self.is_trash
+    }
+    pub fn clear_is_trash(&mut self) {
+        self.is_trash = false;
+    }
+
+    // Param is passed by value, moved
+    pub fn set_is_trash(&mut self, v: bool) {
+        self.is_trash = v;
+    }
+
+    // bool read_belongings = 3;
+
+
+    pub fn get_read_belongings(&self) -> bool {
+        self.read_belongings
+    }
+    pub fn clear_read_belongings(&mut self) {
+        self.read_belongings = false;
+    }
+
+    // Param is passed by value, moved
+    pub fn set_read_belongings(&mut self, v: bool) {
+        self.read_belongings = v;
+    }
+}
+
+impl ::protobuf::Message for QueryViewParams {
+    fn is_initialized(&self) -> bool {
+        true
+    }
+
+    fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> {
+        while !is.eof()? {
+            let (field_number, wire_type) = is.read_tag_unpack()?;
+            match field_number {
+                1 => {
+                    ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.view_id)?;
+                },
+                2 => {
+                    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.is_trash = tmp;
+                },
+                3 => {
+                    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.read_belongings = tmp;
+                },
+                _ => {
+                    ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
+                },
+            };
+        }
+        ::std::result::Result::Ok(())
+    }
+
+    // Compute sizes of nested messages
+    #[allow(unused_variables)]
+    fn compute_size(&self) -> u32 {
+        let mut my_size = 0;
+        if !self.view_id.is_empty() {
+            my_size += ::protobuf::rt::string_size(1, &self.view_id);
+        }
+        if self.is_trash != false {
+            my_size += 2;
+        }
+        if self.read_belongings != false {
+            my_size += 2;
+        }
+        my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
+        self.cached_size.set(my_size);
+        my_size
+    }
+
+    fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> {
+        if !self.view_id.is_empty() {
+            os.write_string(1, &self.view_id)?;
+        }
+        if self.is_trash != false {
+            os.write_bool(2, self.is_trash)?;
+        }
+        if self.read_belongings != false {
+            os.write_bool(3, self.read_belongings)?;
+        }
+        os.write_unknown_fields(self.get_unknown_fields())?;
+        ::std::result::Result::Ok(())
+    }
+
+    fn get_cached_size(&self) -> u32 {
+        self.cached_size.get()
+    }
+
+    fn get_unknown_fields(&self) -> &::protobuf::UnknownFields {
+        &self.unknown_fields
+    }
+
+    fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields {
+        &mut self.unknown_fields
+    }
+
+    fn as_any(&self) -> &dyn (::std::any::Any) {
+        self as &dyn (::std::any::Any)
+    }
+    fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) {
+        self as &mut dyn (::std::any::Any)
+    }
+    fn into_any(self: ::std::boxed::Box<Self>) -> ::std::boxed::Box<dyn (::std::any::Any)> {
+        self
+    }
+
+    fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor {
+        Self::descriptor_static()
+    }
+
+    fn new() -> QueryViewParams {
+        QueryViewParams::new()
+    }
+
+    fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor {
+        static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT;
+        descriptor.get(|| {
+            let mut fields = ::std::vec::Vec::new();
+            fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
+                "view_id",
+                |m: &QueryViewParams| { &m.view_id },
+                |m: &mut QueryViewParams| { &mut m.view_id },
+            ));
+            fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBool>(
+                "is_trash",
+                |m: &QueryViewParams| { &m.is_trash },
+                |m: &mut QueryViewParams| { &mut m.is_trash },
+            ));
+            fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBool>(
+                "read_belongings",
+                |m: &QueryViewParams| { &m.read_belongings },
+                |m: &mut QueryViewParams| { &mut m.read_belongings },
+            ));
+            ::protobuf::reflect::MessageDescriptor::new_pb_name::<QueryViewParams>(
+                "QueryViewParams",
+                fields,
+                file_descriptor_proto()
+            )
+        })
+    }
+
+    fn default_instance() -> &'static QueryViewParams {
+        static instance: ::protobuf::rt::LazyV2<QueryViewParams> = ::protobuf::rt::LazyV2::INIT;
+        instance.get(QueryViewParams::new)
+    }
+}
+
+impl ::protobuf::Clear for QueryViewParams {
+    fn clear(&mut self) {
+        self.view_id.clear();
+        self.is_trash = false;
+        self.read_belongings = false;
+        self.unknown_fields.clear();
+    }
+}
+
+impl ::std::fmt::Debug for QueryViewParams {
+    fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
+        ::protobuf::text_format::fmt(self, f)
+    }
+}
+
+impl ::protobuf::reflect::ProtobufValue for QueryViewParams {
+    fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
+        ::protobuf::reflect::ReflectValueRef::Message(self)
+    }
+}
+
 static file_descriptor_proto_data: &'static [u8] = b"\
     \n\x10view_query.proto\"o\n\x10QueryViewRequest\x12\x17\n\x07view_id\x18\
     \x01\x20\x01(\tR\x06viewId\x12\x19\n\x08is_trash\x18\x02\x20\x01(\x08R\
     \x07isTrash\x12'\n\x0fread_belongings\x18\x03\x20\x01(\x08R\x0ereadBelon\
-    gingsJ\xcf\x01\n\x06\x12\x04\0\0\x06\x01\n\x08\n\x01\x0c\x12\x03\0\0\x12\
-    \n\n\n\x02\x04\0\x12\x04\x02\0\x06\x01\n\n\n\x03\x04\0\x01\x12\x03\x02\
-    \x08\x18\n\x0b\n\x04\x04\0\x02\0\x12\x03\x03\x04\x17\n\x0c\n\x05\x04\0\
-    \x02\0\x05\x12\x03\x03\x04\n\n\x0c\n\x05\x04\0\x02\0\x01\x12\x03\x03\x0b\
-    \x12\n\x0c\n\x05\x04\0\x02\0\x03\x12\x03\x03\x15\x16\n\x0b\n\x04\x04\0\
-    \x02\x01\x12\x03\x04\x04\x16\n\x0c\n\x05\x04\0\x02\x01\x05\x12\x03\x04\
-    \x04\x08\n\x0c\n\x05\x04\0\x02\x01\x01\x12\x03\x04\t\x11\n\x0c\n\x05\x04\
-    \0\x02\x01\x03\x12\x03\x04\x14\x15\n\x0b\n\x04\x04\0\x02\x02\x12\x03\x05\
-    \x04\x1d\n\x0c\n\x05\x04\0\x02\x02\x05\x12\x03\x05\x04\x08\n\x0c\n\x05\
-    \x04\0\x02\x02\x01\x12\x03\x05\t\x18\n\x0c\n\x05\x04\0\x02\x02\x03\x12\
-    \x03\x05\x1b\x1cb\x06proto3\
+    gings\"n\n\x0fQueryViewParams\x12\x17\n\x07view_id\x18\x01\x20\x01(\tR\
+    \x06viewId\x12\x19\n\x08is_trash\x18\x02\x20\x01(\x08R\x07isTrash\x12'\n\
+    \x0fread_belongings\x18\x03\x20\x01(\x08R\x0ereadBelongingsJ\x8c\x03\n\
+    \x06\x12\x04\0\0\x0b\x01\n\x08\n\x01\x0c\x12\x03\0\0\x12\n\n\n\x02\x04\0\
+    \x12\x04\x02\0\x06\x01\n\n\n\x03\x04\0\x01\x12\x03\x02\x08\x18\n\x0b\n\
+    \x04\x04\0\x02\0\x12\x03\x03\x04\x17\n\x0c\n\x05\x04\0\x02\0\x05\x12\x03\
+    \x03\x04\n\n\x0c\n\x05\x04\0\x02\0\x01\x12\x03\x03\x0b\x12\n\x0c\n\x05\
+    \x04\0\x02\0\x03\x12\x03\x03\x15\x16\n\x0b\n\x04\x04\0\x02\x01\x12\x03\
+    \x04\x04\x16\n\x0c\n\x05\x04\0\x02\x01\x05\x12\x03\x04\x04\x08\n\x0c\n\
+    \x05\x04\0\x02\x01\x01\x12\x03\x04\t\x11\n\x0c\n\x05\x04\0\x02\x01\x03\
+    \x12\x03\x04\x14\x15\n\x0b\n\x04\x04\0\x02\x02\x12\x03\x05\x04\x1d\n\x0c\
+    \n\x05\x04\0\x02\x02\x05\x12\x03\x05\x04\x08\n\x0c\n\x05\x04\0\x02\x02\
+    \x01\x12\x03\x05\t\x18\n\x0c\n\x05\x04\0\x02\x02\x03\x12\x03\x05\x1b\x1c\
+    \n\n\n\x02\x04\x01\x12\x04\x07\0\x0b\x01\n\n\n\x03\x04\x01\x01\x12\x03\
+    \x07\x08\x17\n\x0b\n\x04\x04\x01\x02\0\x12\x03\x08\x04\x17\n\x0c\n\x05\
+    \x04\x01\x02\0\x05\x12\x03\x08\x04\n\n\x0c\n\x05\x04\x01\x02\0\x01\x12\
+    \x03\x08\x0b\x12\n\x0c\n\x05\x04\x01\x02\0\x03\x12\x03\x08\x15\x16\n\x0b\
+    \n\x04\x04\x01\x02\x01\x12\x03\t\x04\x16\n\x0c\n\x05\x04\x01\x02\x01\x05\
+    \x12\x03\t\x04\x08\n\x0c\n\x05\x04\x01\x02\x01\x01\x12\x03\t\t\x11\n\x0c\
+    \n\x05\x04\x01\x02\x01\x03\x12\x03\t\x14\x15\n\x0b\n\x04\x04\x01\x02\x02\
+    \x12\x03\n\x04\x1d\n\x0c\n\x05\x04\x01\x02\x02\x05\x12\x03\n\x04\x08\n\
+    \x0c\n\x05\x04\x01\x02\x02\x01\x12\x03\n\t\x18\n\x0c\n\x05\x04\x01\x02\
+    \x02\x03\x12\x03\n\x1b\x1cb\x06proto3\
 ";
 
 static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;

+ 507 - 22
rust-lib/flowy-workspace/src/protobuf/model/view_update.rs

@@ -483,34 +483,519 @@ impl ::protobuf::reflect::ProtobufValue for UpdateViewRequest {
     }
 }
 
+#[derive(PartialEq,Clone,Default)]
+pub struct UpdateViewParams {
+    // message fields
+    pub view_id: ::std::string::String,
+    // message oneof groups
+    pub one_of_name: ::std::option::Option<UpdateViewParams_oneof_one_of_name>,
+    pub one_of_desc: ::std::option::Option<UpdateViewParams_oneof_one_of_desc>,
+    pub one_of_thumbnail: ::std::option::Option<UpdateViewParams_oneof_one_of_thumbnail>,
+    pub one_of_is_trash: ::std::option::Option<UpdateViewParams_oneof_one_of_is_trash>,
+    // special fields
+    pub unknown_fields: ::protobuf::UnknownFields,
+    pub cached_size: ::protobuf::CachedSize,
+}
+
+impl<'a> ::std::default::Default for &'a UpdateViewParams {
+    fn default() -> &'a UpdateViewParams {
+        <UpdateViewParams as ::protobuf::Message>::default_instance()
+    }
+}
+
+#[derive(Clone,PartialEq,Debug)]
+pub enum UpdateViewParams_oneof_one_of_name {
+    name(::std::string::String),
+}
+
+#[derive(Clone,PartialEq,Debug)]
+pub enum UpdateViewParams_oneof_one_of_desc {
+    desc(::std::string::String),
+}
+
+#[derive(Clone,PartialEq,Debug)]
+pub enum UpdateViewParams_oneof_one_of_thumbnail {
+    thumbnail(::std::string::String),
+}
+
+#[derive(Clone,PartialEq,Debug)]
+pub enum UpdateViewParams_oneof_one_of_is_trash {
+    is_trash(bool),
+}
+
+impl UpdateViewParams {
+    pub fn new() -> UpdateViewParams {
+        ::std::default::Default::default()
+    }
+
+    // string view_id = 1;
+
+
+    pub fn get_view_id(&self) -> &str {
+        &self.view_id
+    }
+    pub fn clear_view_id(&mut self) {
+        self.view_id.clear();
+    }
+
+    // Param is passed by value, moved
+    pub fn set_view_id(&mut self, v: ::std::string::String) {
+        self.view_id = v;
+    }
+
+    // Mutable pointer to the field.
+    // If field is not initialized, it is initialized with default value first.
+    pub fn mut_view_id(&mut self) -> &mut ::std::string::String {
+        &mut self.view_id
+    }
+
+    // Take field
+    pub fn take_view_id(&mut self) -> ::std::string::String {
+        ::std::mem::replace(&mut self.view_id, ::std::string::String::new())
+    }
+
+    // string name = 2;
+
+
+    pub fn get_name(&self) -> &str {
+        match self.one_of_name {
+            ::std::option::Option::Some(UpdateViewParams_oneof_one_of_name::name(ref v)) => v,
+            _ => "",
+        }
+    }
+    pub fn clear_name(&mut self) {
+        self.one_of_name = ::std::option::Option::None;
+    }
+
+    pub fn has_name(&self) -> bool {
+        match self.one_of_name {
+            ::std::option::Option::Some(UpdateViewParams_oneof_one_of_name::name(..)) => true,
+            _ => false,
+        }
+    }
+
+    // Param is passed by value, moved
+    pub fn set_name(&mut self, v: ::std::string::String) {
+        self.one_of_name = ::std::option::Option::Some(UpdateViewParams_oneof_one_of_name::name(v))
+    }
+
+    // Mutable pointer to the field.
+    pub fn mut_name(&mut self) -> &mut ::std::string::String {
+        if let ::std::option::Option::Some(UpdateViewParams_oneof_one_of_name::name(_)) = self.one_of_name {
+        } else {
+            self.one_of_name = ::std::option::Option::Some(UpdateViewParams_oneof_one_of_name::name(::std::string::String::new()));
+        }
+        match self.one_of_name {
+            ::std::option::Option::Some(UpdateViewParams_oneof_one_of_name::name(ref mut v)) => v,
+            _ => panic!(),
+        }
+    }
+
+    // Take field
+    pub fn take_name(&mut self) -> ::std::string::String {
+        if self.has_name() {
+            match self.one_of_name.take() {
+                ::std::option::Option::Some(UpdateViewParams_oneof_one_of_name::name(v)) => v,
+                _ => panic!(),
+            }
+        } else {
+            ::std::string::String::new()
+        }
+    }
+
+    // string desc = 3;
+
+
+    pub fn get_desc(&self) -> &str {
+        match self.one_of_desc {
+            ::std::option::Option::Some(UpdateViewParams_oneof_one_of_desc::desc(ref v)) => v,
+            _ => "",
+        }
+    }
+    pub fn clear_desc(&mut self) {
+        self.one_of_desc = ::std::option::Option::None;
+    }
+
+    pub fn has_desc(&self) -> bool {
+        match self.one_of_desc {
+            ::std::option::Option::Some(UpdateViewParams_oneof_one_of_desc::desc(..)) => true,
+            _ => false,
+        }
+    }
+
+    // Param is passed by value, moved
+    pub fn set_desc(&mut self, v: ::std::string::String) {
+        self.one_of_desc = ::std::option::Option::Some(UpdateViewParams_oneof_one_of_desc::desc(v))
+    }
+
+    // Mutable pointer to the field.
+    pub fn mut_desc(&mut self) -> &mut ::std::string::String {
+        if let ::std::option::Option::Some(UpdateViewParams_oneof_one_of_desc::desc(_)) = self.one_of_desc {
+        } else {
+            self.one_of_desc = ::std::option::Option::Some(UpdateViewParams_oneof_one_of_desc::desc(::std::string::String::new()));
+        }
+        match self.one_of_desc {
+            ::std::option::Option::Some(UpdateViewParams_oneof_one_of_desc::desc(ref mut v)) => v,
+            _ => panic!(),
+        }
+    }
+
+    // Take field
+    pub fn take_desc(&mut self) -> ::std::string::String {
+        if self.has_desc() {
+            match self.one_of_desc.take() {
+                ::std::option::Option::Some(UpdateViewParams_oneof_one_of_desc::desc(v)) => v,
+                _ => panic!(),
+            }
+        } else {
+            ::std::string::String::new()
+        }
+    }
+
+    // string thumbnail = 4;
+
+
+    pub fn get_thumbnail(&self) -> &str {
+        match self.one_of_thumbnail {
+            ::std::option::Option::Some(UpdateViewParams_oneof_one_of_thumbnail::thumbnail(ref v)) => v,
+            _ => "",
+        }
+    }
+    pub fn clear_thumbnail(&mut self) {
+        self.one_of_thumbnail = ::std::option::Option::None;
+    }
+
+    pub fn has_thumbnail(&self) -> bool {
+        match self.one_of_thumbnail {
+            ::std::option::Option::Some(UpdateViewParams_oneof_one_of_thumbnail::thumbnail(..)) => true,
+            _ => false,
+        }
+    }
+
+    // Param is passed by value, moved
+    pub fn set_thumbnail(&mut self, v: ::std::string::String) {
+        self.one_of_thumbnail = ::std::option::Option::Some(UpdateViewParams_oneof_one_of_thumbnail::thumbnail(v))
+    }
+
+    // Mutable pointer to the field.
+    pub fn mut_thumbnail(&mut self) -> &mut ::std::string::String {
+        if let ::std::option::Option::Some(UpdateViewParams_oneof_one_of_thumbnail::thumbnail(_)) = self.one_of_thumbnail {
+        } else {
+            self.one_of_thumbnail = ::std::option::Option::Some(UpdateViewParams_oneof_one_of_thumbnail::thumbnail(::std::string::String::new()));
+        }
+        match self.one_of_thumbnail {
+            ::std::option::Option::Some(UpdateViewParams_oneof_one_of_thumbnail::thumbnail(ref mut v)) => v,
+            _ => panic!(),
+        }
+    }
+
+    // Take field
+    pub fn take_thumbnail(&mut self) -> ::std::string::String {
+        if self.has_thumbnail() {
+            match self.one_of_thumbnail.take() {
+                ::std::option::Option::Some(UpdateViewParams_oneof_one_of_thumbnail::thumbnail(v)) => v,
+                _ => panic!(),
+            }
+        } else {
+            ::std::string::String::new()
+        }
+    }
+
+    // bool is_trash = 5;
+
+
+    pub fn get_is_trash(&self) -> bool {
+        match self.one_of_is_trash {
+            ::std::option::Option::Some(UpdateViewParams_oneof_one_of_is_trash::is_trash(v)) => v,
+            _ => false,
+        }
+    }
+    pub fn clear_is_trash(&mut self) {
+        self.one_of_is_trash = ::std::option::Option::None;
+    }
+
+    pub fn has_is_trash(&self) -> bool {
+        match self.one_of_is_trash {
+            ::std::option::Option::Some(UpdateViewParams_oneof_one_of_is_trash::is_trash(..)) => true,
+            _ => false,
+        }
+    }
+
+    // Param is passed by value, moved
+    pub fn set_is_trash(&mut self, v: bool) {
+        self.one_of_is_trash = ::std::option::Option::Some(UpdateViewParams_oneof_one_of_is_trash::is_trash(v))
+    }
+}
+
+impl ::protobuf::Message for UpdateViewParams {
+    fn is_initialized(&self) -> bool {
+        true
+    }
+
+    fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> {
+        while !is.eof()? {
+            let (field_number, wire_type) = is.read_tag_unpack()?;
+            match field_number {
+                1 => {
+                    ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.view_id)?;
+                },
+                2 => {
+                    if wire_type != ::protobuf::wire_format::WireTypeLengthDelimited {
+                        return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
+                    }
+                    self.one_of_name = ::std::option::Option::Some(UpdateViewParams_oneof_one_of_name::name(is.read_string()?));
+                },
+                3 => {
+                    if wire_type != ::protobuf::wire_format::WireTypeLengthDelimited {
+                        return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
+                    }
+                    self.one_of_desc = ::std::option::Option::Some(UpdateViewParams_oneof_one_of_desc::desc(is.read_string()?));
+                },
+                4 => {
+                    if wire_type != ::protobuf::wire_format::WireTypeLengthDelimited {
+                        return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
+                    }
+                    self.one_of_thumbnail = ::std::option::Option::Some(UpdateViewParams_oneof_one_of_thumbnail::thumbnail(is.read_string()?));
+                },
+                5 => {
+                    if wire_type != ::protobuf::wire_format::WireTypeVarint {
+                        return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
+                    }
+                    self.one_of_is_trash = ::std::option::Option::Some(UpdateViewParams_oneof_one_of_is_trash::is_trash(is.read_bool()?));
+                },
+                _ => {
+                    ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
+                },
+            };
+        }
+        ::std::result::Result::Ok(())
+    }
+
+    // Compute sizes of nested messages
+    #[allow(unused_variables)]
+    fn compute_size(&self) -> u32 {
+        let mut my_size = 0;
+        if !self.view_id.is_empty() {
+            my_size += ::protobuf::rt::string_size(1, &self.view_id);
+        }
+        if let ::std::option::Option::Some(ref v) = self.one_of_name {
+            match v {
+                &UpdateViewParams_oneof_one_of_name::name(ref v) => {
+                    my_size += ::protobuf::rt::string_size(2, &v);
+                },
+            };
+        }
+        if let ::std::option::Option::Some(ref v) = self.one_of_desc {
+            match v {
+                &UpdateViewParams_oneof_one_of_desc::desc(ref v) => {
+                    my_size += ::protobuf::rt::string_size(3, &v);
+                },
+            };
+        }
+        if let ::std::option::Option::Some(ref v) = self.one_of_thumbnail {
+            match v {
+                &UpdateViewParams_oneof_one_of_thumbnail::thumbnail(ref v) => {
+                    my_size += ::protobuf::rt::string_size(4, &v);
+                },
+            };
+        }
+        if let ::std::option::Option::Some(ref v) = self.one_of_is_trash {
+            match v {
+                &UpdateViewParams_oneof_one_of_is_trash::is_trash(v) => {
+                    my_size += 2;
+                },
+            };
+        }
+        my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
+        self.cached_size.set(my_size);
+        my_size
+    }
+
+    fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> {
+        if !self.view_id.is_empty() {
+            os.write_string(1, &self.view_id)?;
+        }
+        if let ::std::option::Option::Some(ref v) = self.one_of_name {
+            match v {
+                &UpdateViewParams_oneof_one_of_name::name(ref v) => {
+                    os.write_string(2, v)?;
+                },
+            };
+        }
+        if let ::std::option::Option::Some(ref v) = self.one_of_desc {
+            match v {
+                &UpdateViewParams_oneof_one_of_desc::desc(ref v) => {
+                    os.write_string(3, v)?;
+                },
+            };
+        }
+        if let ::std::option::Option::Some(ref v) = self.one_of_thumbnail {
+            match v {
+                &UpdateViewParams_oneof_one_of_thumbnail::thumbnail(ref v) => {
+                    os.write_string(4, v)?;
+                },
+            };
+        }
+        if let ::std::option::Option::Some(ref v) = self.one_of_is_trash {
+            match v {
+                &UpdateViewParams_oneof_one_of_is_trash::is_trash(v) => {
+                    os.write_bool(5, v)?;
+                },
+            };
+        }
+        os.write_unknown_fields(self.get_unknown_fields())?;
+        ::std::result::Result::Ok(())
+    }
+
+    fn get_cached_size(&self) -> u32 {
+        self.cached_size.get()
+    }
+
+    fn get_unknown_fields(&self) -> &::protobuf::UnknownFields {
+        &self.unknown_fields
+    }
+
+    fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields {
+        &mut self.unknown_fields
+    }
+
+    fn as_any(&self) -> &dyn (::std::any::Any) {
+        self as &dyn (::std::any::Any)
+    }
+    fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) {
+        self as &mut dyn (::std::any::Any)
+    }
+    fn into_any(self: ::std::boxed::Box<Self>) -> ::std::boxed::Box<dyn (::std::any::Any)> {
+        self
+    }
+
+    fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor {
+        Self::descriptor_static()
+    }
+
+    fn new() -> UpdateViewParams {
+        UpdateViewParams::new()
+    }
+
+    fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor {
+        static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT;
+        descriptor.get(|| {
+            let mut fields = ::std::vec::Vec::new();
+            fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
+                "view_id",
+                |m: &UpdateViewParams| { &m.view_id },
+                |m: &mut UpdateViewParams| { &mut m.view_id },
+            ));
+            fields.push(::protobuf::reflect::accessor::make_singular_string_accessor::<_>(
+                "name",
+                UpdateViewParams::has_name,
+                UpdateViewParams::get_name,
+            ));
+            fields.push(::protobuf::reflect::accessor::make_singular_string_accessor::<_>(
+                "desc",
+                UpdateViewParams::has_desc,
+                UpdateViewParams::get_desc,
+            ));
+            fields.push(::protobuf::reflect::accessor::make_singular_string_accessor::<_>(
+                "thumbnail",
+                UpdateViewParams::has_thumbnail,
+                UpdateViewParams::get_thumbnail,
+            ));
+            fields.push(::protobuf::reflect::accessor::make_singular_bool_accessor::<_>(
+                "is_trash",
+                UpdateViewParams::has_is_trash,
+                UpdateViewParams::get_is_trash,
+            ));
+            ::protobuf::reflect::MessageDescriptor::new_pb_name::<UpdateViewParams>(
+                "UpdateViewParams",
+                fields,
+                file_descriptor_proto()
+            )
+        })
+    }
+
+    fn default_instance() -> &'static UpdateViewParams {
+        static instance: ::protobuf::rt::LazyV2<UpdateViewParams> = ::protobuf::rt::LazyV2::INIT;
+        instance.get(UpdateViewParams::new)
+    }
+}
+
+impl ::protobuf::Clear for UpdateViewParams {
+    fn clear(&mut self) {
+        self.view_id.clear();
+        self.one_of_name = ::std::option::Option::None;
+        self.one_of_desc = ::std::option::Option::None;
+        self.one_of_thumbnail = ::std::option::Option::None;
+        self.one_of_is_trash = ::std::option::Option::None;
+        self.unknown_fields.clear();
+    }
+}
+
+impl ::std::fmt::Debug for UpdateViewParams {
+    fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
+        ::protobuf::text_format::fmt(self, f)
+    }
+}
+
+impl ::protobuf::reflect::ProtobufValue for UpdateViewParams {
+    fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
+        ::protobuf::reflect::ReflectValueRef::Message(self)
+    }
+}
+
 static file_descriptor_proto_data: &'static [u8] = b"\
     \n\x11view_update.proto\"\xda\x01\n\x11UpdateViewRequest\x12\x17\n\x07vi\
     ew_id\x18\x01\x20\x01(\tR\x06viewId\x12\x14\n\x04name\x18\x02\x20\x01(\t\
     H\0R\x04name\x12\x14\n\x04desc\x18\x03\x20\x01(\tH\x01R\x04desc\x12\x1e\
     \n\tthumbnail\x18\x04\x20\x01(\tH\x02R\tthumbnail\x12\x1b\n\x08is_trash\
     \x18\x05\x20\x01(\x08H\x03R\x07isTrashB\r\n\x0bone_of_nameB\r\n\x0bone_o\
-    f_descB\x12\n\x10one_of_thumbnailB\x11\n\x0fone_of_is_trashJ\xa9\x03\n\
-    \x06\x12\x04\0\0\x08\x01\n\x08\n\x01\x0c\x12\x03\0\0\x12\n\n\n\x02\x04\0\
-    \x12\x04\x02\0\x08\x01\n\n\n\x03\x04\0\x01\x12\x03\x02\x08\x19\n\x0b\n\
-    \x04\x04\0\x02\0\x12\x03\x03\x04\x17\n\x0c\n\x05\x04\0\x02\0\x05\x12\x03\
-    \x03\x04\n\n\x0c\n\x05\x04\0\x02\0\x01\x12\x03\x03\x0b\x12\n\x0c\n\x05\
-    \x04\0\x02\0\x03\x12\x03\x03\x15\x16\n\x0b\n\x04\x04\0\x08\0\x12\x03\x04\
-    \x04*\n\x0c\n\x05\x04\0\x08\0\x01\x12\x03\x04\n\x15\n\x0b\n\x04\x04\0\
-    \x02\x01\x12\x03\x04\x18(\n\x0c\n\x05\x04\0\x02\x01\x05\x12\x03\x04\x18\
-    \x1e\n\x0c\n\x05\x04\0\x02\x01\x01\x12\x03\x04\x1f#\n\x0c\n\x05\x04\0\
-    \x02\x01\x03\x12\x03\x04&'\n\x0b\n\x04\x04\0\x08\x01\x12\x03\x05\x04*\n\
-    \x0c\n\x05\x04\0\x08\x01\x01\x12\x03\x05\n\x15\n\x0b\n\x04\x04\0\x02\x02\
-    \x12\x03\x05\x18(\n\x0c\n\x05\x04\0\x02\x02\x05\x12\x03\x05\x18\x1e\n\
-    \x0c\n\x05\x04\0\x02\x02\x01\x12\x03\x05\x1f#\n\x0c\n\x05\x04\0\x02\x02\
-    \x03\x12\x03\x05&'\n\x0b\n\x04\x04\0\x08\x02\x12\x03\x06\x044\n\x0c\n\
-    \x05\x04\0\x08\x02\x01\x12\x03\x06\n\x1a\n\x0b\n\x04\x04\0\x02\x03\x12\
-    \x03\x06\x1d2\n\x0c\n\x05\x04\0\x02\x03\x05\x12\x03\x06\x1d#\n\x0c\n\x05\
-    \x04\0\x02\x03\x01\x12\x03\x06$-\n\x0c\n\x05\x04\0\x02\x03\x03\x12\x03\
-    \x0601\n\x0b\n\x04\x04\0\x08\x03\x12\x03\x07\x040\n\x0c\n\x05\x04\0\x08\
-    \x03\x01\x12\x03\x07\n\x19\n\x0b\n\x04\x04\0\x02\x04\x12\x03\x07\x1c.\n\
-    \x0c\n\x05\x04\0\x02\x04\x05\x12\x03\x07\x1c\x20\n\x0c\n\x05\x04\0\x02\
-    \x04\x01\x12\x03\x07!)\n\x0c\n\x05\x04\0\x02\x04\x03\x12\x03\x07,-b\x06p\
-    roto3\
+    f_descB\x12\n\x10one_of_thumbnailB\x11\n\x0fone_of_is_trash\"\xd9\x01\n\
+    \x10UpdateViewParams\x12\x17\n\x07view_id\x18\x01\x20\x01(\tR\x06viewId\
+    \x12\x14\n\x04name\x18\x02\x20\x01(\tH\0R\x04name\x12\x14\n\x04desc\x18\
+    \x03\x20\x01(\tH\x01R\x04desc\x12\x1e\n\tthumbnail\x18\x04\x20\x01(\tH\
+    \x02R\tthumbnail\x12\x1b\n\x08is_trash\x18\x05\x20\x01(\x08H\x03R\x07isT\
+    rashB\r\n\x0bone_of_nameB\r\n\x0bone_of_descB\x12\n\x10one_of_thumbnailB\
+    \x11\n\x0fone_of_is_trashJ\xc0\x06\n\x06\x12\x04\0\0\x0f\x01\n\x08\n\x01\
+    \x0c\x12\x03\0\0\x12\n\n\n\x02\x04\0\x12\x04\x02\0\x08\x01\n\n\n\x03\x04\
+    \0\x01\x12\x03\x02\x08\x19\n\x0b\n\x04\x04\0\x02\0\x12\x03\x03\x04\x17\n\
+    \x0c\n\x05\x04\0\x02\0\x05\x12\x03\x03\x04\n\n\x0c\n\x05\x04\0\x02\0\x01\
+    \x12\x03\x03\x0b\x12\n\x0c\n\x05\x04\0\x02\0\x03\x12\x03\x03\x15\x16\n\
+    \x0b\n\x04\x04\0\x08\0\x12\x03\x04\x04*\n\x0c\n\x05\x04\0\x08\0\x01\x12\
+    \x03\x04\n\x15\n\x0b\n\x04\x04\0\x02\x01\x12\x03\x04\x18(\n\x0c\n\x05\
+    \x04\0\x02\x01\x05\x12\x03\x04\x18\x1e\n\x0c\n\x05\x04\0\x02\x01\x01\x12\
+    \x03\x04\x1f#\n\x0c\n\x05\x04\0\x02\x01\x03\x12\x03\x04&'\n\x0b\n\x04\
+    \x04\0\x08\x01\x12\x03\x05\x04*\n\x0c\n\x05\x04\0\x08\x01\x01\x12\x03\
+    \x05\n\x15\n\x0b\n\x04\x04\0\x02\x02\x12\x03\x05\x18(\n\x0c\n\x05\x04\0\
+    \x02\x02\x05\x12\x03\x05\x18\x1e\n\x0c\n\x05\x04\0\x02\x02\x01\x12\x03\
+    \x05\x1f#\n\x0c\n\x05\x04\0\x02\x02\x03\x12\x03\x05&'\n\x0b\n\x04\x04\0\
+    \x08\x02\x12\x03\x06\x044\n\x0c\n\x05\x04\0\x08\x02\x01\x12\x03\x06\n\
+    \x1a\n\x0b\n\x04\x04\0\x02\x03\x12\x03\x06\x1d2\n\x0c\n\x05\x04\0\x02\
+    \x03\x05\x12\x03\x06\x1d#\n\x0c\n\x05\x04\0\x02\x03\x01\x12\x03\x06$-\n\
+    \x0c\n\x05\x04\0\x02\x03\x03\x12\x03\x0601\n\x0b\n\x04\x04\0\x08\x03\x12\
+    \x03\x07\x040\n\x0c\n\x05\x04\0\x08\x03\x01\x12\x03\x07\n\x19\n\x0b\n\
+    \x04\x04\0\x02\x04\x12\x03\x07\x1c.\n\x0c\n\x05\x04\0\x02\x04\x05\x12\
+    \x03\x07\x1c\x20\n\x0c\n\x05\x04\0\x02\x04\x01\x12\x03\x07!)\n\x0c\n\x05\
+    \x04\0\x02\x04\x03\x12\x03\x07,-\n\n\n\x02\x04\x01\x12\x04\t\0\x0f\x01\n\
+    \n\n\x03\x04\x01\x01\x12\x03\t\x08\x18\n\x0b\n\x04\x04\x01\x02\0\x12\x03\
+    \n\x04\x17\n\x0c\n\x05\x04\x01\x02\0\x05\x12\x03\n\x04\n\n\x0c\n\x05\x04\
+    \x01\x02\0\x01\x12\x03\n\x0b\x12\n\x0c\n\x05\x04\x01\x02\0\x03\x12\x03\n\
+    \x15\x16\n\x0b\n\x04\x04\x01\x08\0\x12\x03\x0b\x04*\n\x0c\n\x05\x04\x01\
+    \x08\0\x01\x12\x03\x0b\n\x15\n\x0b\n\x04\x04\x01\x02\x01\x12\x03\x0b\x18\
+    (\n\x0c\n\x05\x04\x01\x02\x01\x05\x12\x03\x0b\x18\x1e\n\x0c\n\x05\x04\
+    \x01\x02\x01\x01\x12\x03\x0b\x1f#\n\x0c\n\x05\x04\x01\x02\x01\x03\x12\
+    \x03\x0b&'\n\x0b\n\x04\x04\x01\x08\x01\x12\x03\x0c\x04*\n\x0c\n\x05\x04\
+    \x01\x08\x01\x01\x12\x03\x0c\n\x15\n\x0b\n\x04\x04\x01\x02\x02\x12\x03\
+    \x0c\x18(\n\x0c\n\x05\x04\x01\x02\x02\x05\x12\x03\x0c\x18\x1e\n\x0c\n\
+    \x05\x04\x01\x02\x02\x01\x12\x03\x0c\x1f#\n\x0c\n\x05\x04\x01\x02\x02\
+    \x03\x12\x03\x0c&'\n\x0b\n\x04\x04\x01\x08\x02\x12\x03\r\x044\n\x0c\n\
+    \x05\x04\x01\x08\x02\x01\x12\x03\r\n\x1a\n\x0b\n\x04\x04\x01\x02\x03\x12\
+    \x03\r\x1d2\n\x0c\n\x05\x04\x01\x02\x03\x05\x12\x03\r\x1d#\n\x0c\n\x05\
+    \x04\x01\x02\x03\x01\x12\x03\r$-\n\x0c\n\x05\x04\x01\x02\x03\x03\x12\x03\
+    \r01\n\x0b\n\x04\x04\x01\x08\x03\x12\x03\x0e\x040\n\x0c\n\x05\x04\x01\
+    \x08\x03\x01\x12\x03\x0e\n\x19\n\x0b\n\x04\x04\x01\x02\x04\x12\x03\x0e\
+    \x1c.\n\x0c\n\x05\x04\x01\x02\x04\x05\x12\x03\x0e\x1c\x20\n\x0c\n\x05\
+    \x04\x01\x02\x04\x01\x12\x03\x0e!)\n\x0c\n\x05\x04\x01\x02\x04\x03\x12\
+    \x03\x0e,-b\x06proto3\
 ";
 
 static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;

+ 7 - 0
rust-lib/flowy-workspace/src/protobuf/proto/view_create.proto

@@ -7,6 +7,13 @@ message CreateViewRequest {
     oneof one_of_thumbnail { string thumbnail = 4; };
     ViewType view_type = 5;
 }
+message CreateViewParams {
+    string belong_to_id = 1;
+    string name = 2;
+    string desc = 3;
+    string thumbnail = 4;
+    ViewType view_type = 5;
+}
 message View {
     string id = 1;
     string belong_to_id = 2;

+ 3 - 0
rust-lib/flowy-workspace/src/protobuf/proto/view_delete.proto

@@ -3,3 +3,6 @@ syntax = "proto3";
 message DeleteViewRequest {
     string view_id = 1;
 }
+message DeleteViewParams {
+    string view_id = 1;
+}

+ 5 - 0
rust-lib/flowy-workspace/src/protobuf/proto/view_query.proto

@@ -5,3 +5,8 @@ message QueryViewRequest {
     bool is_trash = 2;
     bool read_belongings = 3;
 }
+message QueryViewParams {
+    string view_id = 1;
+    bool is_trash = 2;
+    bool read_belongings = 3;
+}

+ 7 - 0
rust-lib/flowy-workspace/src/protobuf/proto/view_update.proto

@@ -7,3 +7,10 @@ message UpdateViewRequest {
     oneof one_of_thumbnail { string thumbnail = 4; };
     oneof one_of_is_trash { bool is_trash = 5; };
 }
+message UpdateViewParams {
+    string view_id = 1;
+    oneof one_of_name { string name = 2; };
+    oneof one_of_desc { string desc = 3; };
+    oneof one_of_thumbnail { string thumbnail = 4; };
+    oneof one_of_is_trash { bool is_trash = 5; };
+}

+ 60 - 1
rust-lib/flowy-workspace/src/services/view_controller.rs

@@ -1,10 +1,11 @@
 use crate::{
-    entities::view::{CreateViewParams, UpdateViewParams, View},
+    entities::view::{CreateViewParams, DeleteViewParams, QueryViewParams, UpdateViewParams, View},
     errors::WorkspaceError,
     module::WorkspaceDatabase,
     observable::{send_observable, WorkspaceObservable},
     sql_tables::view::{ViewTable, ViewTableChangeset, ViewTableSql},
 };
+use flowy_net::request::HttpRequestBuilder;
 use std::sync::Arc;
 
 pub struct ViewController {
@@ -61,3 +62,61 @@ impl ViewController {
         Ok(())
     }
 }
+
+pub async fn create_view_request(
+    params: CreateViewParams,
+    url: &str,
+) -> Result<View, WorkspaceError> {
+    let view = HttpRequestBuilder::post(&url.to_owned())
+        .protobuf(params)?
+        .send()
+        .await?
+        .response()
+        .await?;
+    Ok(view)
+}
+
+pub async fn read_view_request(
+    params: QueryViewParams,
+    url: &str,
+) -> Result<Option<View>, WorkspaceError> {
+    let result = HttpRequestBuilder::get(&url.to_owned())
+        .protobuf(params)?
+        .send()
+        .await?
+        .response::<View>()
+        .await;
+
+    match result {
+        Ok(view) => Ok(Some(view)),
+        Err(e) => {
+            if e.is_not_found() {
+                Ok(None)
+            } else {
+                Err(e.into())
+            }
+        },
+    }
+}
+
+pub async fn update_view_request(
+    params: UpdateViewParams,
+    url: &str,
+) -> Result<(), WorkspaceError> {
+    let _ = HttpRequestBuilder::patch(&url.to_owned())
+        .protobuf(params)?
+        .send()
+        .await?;
+    Ok(())
+}
+
+pub async fn delete_view_request(
+    params: DeleteViewParams,
+    url: &str,
+) -> Result<(), WorkspaceError> {
+    let _ = HttpRequestBuilder::delete(&url.to_owned())
+        .protobuf(params)?
+        .send()
+        .await?;
+    Ok(())
+}

+ 6 - 1
rust-lib/flowy-workspace/src/sql_tables/view/view_table.rs

@@ -27,6 +27,11 @@ impl ViewTable {
     pub fn new(params: CreateViewParams) -> Self {
         let view_id = uuid();
         let time = timestamp();
+        let view_type = match params.view_type {
+            ViewType::Blank => ViewTableType::Docs,
+            ViewType::Doc => ViewTableType::Docs,
+        };
+
         ViewTable {
             id: view_id,
             belong_to_id: params.belong_to_id,
@@ -35,7 +40,7 @@ impl ViewTable {
             modified_time: time,
             create_time: time,
             thumbnail: params.thumbnail,
-            view_type: params.view_type,
+            view_type,
             version: 0,
             is_trash: false,
         }