From ad3e2f57253f45f7bb7ecee006c932f9f5f2878c Mon Sep 17 00:00:00 2001
From: appflowy <annie@appflowy.io>
Date: Wed, 10 Aug 2022 17:59:28 +0800
Subject: [PATCH] chore: add sub data type

---
 .../plugins/board/application/board_bloc.dart | 34 ++++--------
 .../board/application/field_group.dart        |  0
 .../app_flowy/lib/plugins/board/board.dart    |  5 +-
 .../board/presentation/board_page.dart        | 53 ++++---------------
 .../lib/plugins/board/presentation/card.dart  | 13 +++++
 .../app_flowy/lib/plugins/doc/document.dart   |  6 +--
 frontend/app_flowy/lib/plugins/grid/grid.dart |  5 +-
 .../app_flowy/lib/startup/plugin/plugin.dart  |  9 ++--
 .../workspace/application/app/app_bloc.dart   |  4 +-
 .../application/app/app_service.dart          |  9 +++-
 .../home/menu/app/header/header.dart          | 18 +++++--
 .../flowy-folder/src/entities/view.rs         | 41 ++++++++------
 .../flowy-folder/src/entities/view_info.rs    |  4 +-
 frontend/rust-lib/flowy-folder/src/manager.rs | 16 ++++--
 .../persistence/version_1/view_sql.rs         |  4 +-
 .../src/services/view/controller.rs           | 15 +++---
 .../tests/workspace/folder_test.rs            | 14 ++---
 .../flowy-folder/tests/workspace/script.rs    | 14 +++--
 .../single_select_type_option.rs              |  8 +--
 .../text_type_option/text_type_option.rs      |  2 +-
 .../flowy-grid/src/services/grid_editor.rs    |  2 +-
 .../src/services/row/row_builder.rs           | 25 +++++----
 frontend/rust-lib/flowy-grid/src/util.rs      | 45 ++++++++++++++++
 .../flowy-grid/tests/grid/block_test/util.rs  | 10 ++--
 .../flowy-grid/tests/grid/field_test/util.rs  |  4 +-
 .../flowy-grid/tests/grid/grid_editor.rs      |  6 +--
 .../flowy-sdk/src/deps_resolve/folder_deps.rs | 33 ++++++++----
 frontend/rust-lib/flowy-test/src/helper.rs    |  8 +--
 .../src/revision/view_rev.rs                  |  2 +-
 29 files changed, 243 insertions(+), 166 deletions(-)
 create mode 100644 frontend/app_flowy/lib/plugins/board/application/field_group.dart
 create mode 100644 frontend/app_flowy/lib/plugins/board/presentation/card.dart

diff --git a/frontend/app_flowy/lib/plugins/board/application/board_bloc.dart b/frontend/app_flowy/lib/plugins/board/application/board_bloc.dart
index a2ce5e043f..2cb03a6c64 100644
--- a/frontend/app_flowy/lib/plugins/board/application/board_bloc.dart
+++ b/frontend/app_flowy/lib/plugins/board/application/board_bloc.dart
@@ -6,6 +6,7 @@ import 'package:app_flowy/plugins/grid/presentation/widgets/header/type_option/b
 import 'package:appflowy_board/appflowy_board.dart';
 import 'package:dartz/dartz.dart';
 import 'package:equatable/equatable.dart';
+import 'package:flowy_sdk/log.dart';
 import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
 import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart';
 import 'package:flowy_sdk/protobuf/flowy-grid/protobuf.dart';
@@ -55,15 +56,6 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
           didReceiveGridUpdate: (GridPB grid) {
             emit(state.copyWith(grid: Some(grid)));
           },
-          didReceiveFieldUpdate: (UnmodifiableListView<GridFieldPB> fields) {
-            emit(state.copyWith(fields: GridFieldEquatable(fields)));
-          },
-          didReceiveRowUpdate: (
-            List<GridRowInfo> newRowInfos,
-            GridRowChangeReason reason,
-          ) {
-            emit(state.copyWith(rowInfos: newRowInfos, reason: reason));
-          },
         );
       },
     );
@@ -89,18 +81,21 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
       },
       onRowsChanged: (rowInfos, reason) {
         if (!isClosed) {
-          add(BoardEvent.didReceiveRowUpdate(rowInfos, reason));
+          _buildColumnItems(rowInfos);
         }
       },
       onFieldsChanged: (fields) {
         if (!isClosed) {
           _buildColumns(fields);
-          add(BoardEvent.didReceiveFieldUpdate(fields));
         }
       },
     );
   }
 
+  void _buildColumnItems(List<GridRowInfo> rowInfos) {
+    for (final rowInfo in rowInfos) {}
+  }
+
   void _buildColumns(UnmodifiableListView<GridFieldPB> fields) {
     for (final field in fields) {
       if (field.fieldType == FieldType.SingleSelect) {
@@ -127,7 +122,7 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
 
         boardDataController.addColumns(columns);
       },
-      onError: (err) {},
+      onError: (err) => Log.error(err),
     );
   }
 
@@ -148,14 +143,7 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
 class BoardEvent with _$BoardEvent {
   const factory BoardEvent.initial() = InitialGrid;
   const factory BoardEvent.createRow() = _CreateRow;
-  const factory BoardEvent.didReceiveRowUpdate(
-    List<GridRowInfo> rows,
-    GridRowChangeReason listState,
-  ) = _DidReceiveRowUpdate;
-  const factory BoardEvent.didReceiveFieldUpdate(
-    UnmodifiableListView<GridFieldPB> fields,
-  ) = _DidReceiveFieldUpdate;
-
+  const factory BoardEvent.groupByField(GridFieldPB field) = _GroupByField;
   const factory BoardEvent.didReceiveGridUpdate(
     GridPB grid,
   ) = _DidReceiveGridUpdate;
@@ -166,19 +154,17 @@ class BoardState with _$BoardState {
   const factory BoardState({
     required String gridId,
     required Option<GridPB> grid,
-    required GridFieldEquatable fields,
+    required Option<GridFieldPB> groupField,
     required List<GridRowInfo> rowInfos,
     required GridLoadingState loadingState,
-    required GridRowChangeReason reason,
   }) = _BoardState;
 
   factory BoardState.initial(String gridId) => BoardState(
-        fields: GridFieldEquatable(UnmodifiableListView([])),
         rowInfos: [],
+        groupField: none(),
         grid: none(),
         gridId: gridId,
         loadingState: const _Loading(),
-        reason: const InitialListState(),
       );
 }
 
diff --git a/frontend/app_flowy/lib/plugins/board/application/field_group.dart b/frontend/app_flowy/lib/plugins/board/application/field_group.dart
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/frontend/app_flowy/lib/plugins/board/board.dart b/frontend/app_flowy/lib/plugins/board/board.dart
index 11a6d415eb..36d181ae3e 100644
--- a/frontend/app_flowy/lib/plugins/board/board.dart
+++ b/frontend/app_flowy/lib/plugins/board/board.dart
@@ -23,7 +23,10 @@ class BoardPluginBuilder implements PluginBuilder {
   PluginType get pluginType => DefaultPlugin.board.type();
 
   @override
-  ViewDataType get dataType => ViewDataType.Grid;
+  ViewDataTypePB get dataType => ViewDataTypePB.Database;
+
+  @override
+  SubViewDataTypePB get subDataType => SubViewDataTypePB.Board;
 }
 
 class BoardPluginConfig implements PluginConfig {
diff --git a/frontend/app_flowy/lib/plugins/board/presentation/board_page.dart b/frontend/app_flowy/lib/plugins/board/presentation/board_page.dart
index f961eeaf42..1155168e70 100644
--- a/frontend/app_flowy/lib/plugins/board/presentation/board_page.dart
+++ b/frontend/app_flowy/lib/plugins/board/presentation/board_page.dart
@@ -1,15 +1,17 @@
 // ignore_for_file: unused_field
 
+import 'package:app_flowy/plugins/grid/application/row/row_cache.dart';
 import 'package:appflowy_board/appflowy_board.dart';
 import 'package:flowy_infra_ui/widget/error_page.dart';
 import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
 import '../application/board_bloc.dart';
+import 'card.dart';
 
 class BoardPage extends StatelessWidget {
   final ViewPB view;
-  const BoardPage({required this.view, Key? key}) : super(key: key);
+  BoardPage({required this.view, Key? key}) : super(key: ValueKey(view.id));
 
   @override
   Widget build(BuildContext context) {
@@ -53,12 +55,7 @@ class BoardContent extends StatelessWidget {
               dataController: context.read<BoardBloc>().boardDataController,
               headerBuilder: _buildHeader,
               footBuilder: _buildFooter,
-              cardBuilder: (context, item) {
-                return AppFlowyColumnItemCard(
-                  key: ObjectKey(item),
-                  child: _buildCard(item),
-                );
-              },
+              cardBuilder: _buildCard,
               columnConstraints: const BoxConstraints.tightFor(width: 240),
               config: BoardConfig(
                 columnBackgroundColor: HexColor.fromHex('#F7F8FC'),
@@ -90,42 +87,12 @@ class BoardContent extends StatelessWidget {
     );
   }
 
-  Widget _buildCard(ColumnItem item) {
-    if (item is TextItem) {
-      return Align(
-        alignment: Alignment.centerLeft,
-        child: Padding(
-          padding: const EdgeInsets.symmetric(horizontal: 20),
-          child: Text(item.s),
-        ),
-      );
-    }
-
-    if (item is RichTextItem) {
-      return Align(
-        alignment: Alignment.centerLeft,
-        child: Padding(
-          padding: const EdgeInsets.all(20),
-          child: Column(
-            crossAxisAlignment: CrossAxisAlignment.start,
-            children: [
-              Text(
-                item.title,
-                style: const TextStyle(fontSize: 14),
-                textAlign: TextAlign.left,
-              ),
-              const SizedBox(height: 10),
-              Text(
-                item.subtitle,
-                style: const TextStyle(fontSize: 12, color: Colors.grey),
-              )
-            ],
-          ),
-        ),
-      );
-    }
-
-    throw UnimplementedError();
+  Widget _buildCard(BuildContext context, ColumnItem item) {
+    final rowInfo = item as GridRowInfo;
+    return AppFlowyColumnItemCard(
+      key: ObjectKey(item),
+      child: BoardCard(rowInfo: rowInfo),
+    );
   }
 }
 
diff --git a/frontend/app_flowy/lib/plugins/board/presentation/card.dart b/frontend/app_flowy/lib/plugins/board/presentation/card.dart
new file mode 100644
index 0000000000..b98739eea8
--- /dev/null
+++ b/frontend/app_flowy/lib/plugins/board/presentation/card.dart
@@ -0,0 +1,13 @@
+import 'package:app_flowy/plugins/grid/application/row/row_cache.dart';
+import 'package:flutter/material.dart';
+
+class BoardCard extends StatelessWidget {
+  final GridRowInfo rowInfo;
+
+  const BoardCard({required this.rowInfo, Key? key}) : super(key: key);
+
+  @override
+  Widget build(BuildContext context) {
+    return Container(child: Text('1234'));
+  }
+}
diff --git a/frontend/app_flowy/lib/plugins/doc/document.dart b/frontend/app_flowy/lib/plugins/doc/document.dart
index 91bae222c1..0deaedbb75 100644
--- a/frontend/app_flowy/lib/plugins/doc/document.dart
+++ b/frontend/app_flowy/lib/plugins/doc/document.dart
@@ -1,4 +1,4 @@
-library docuemnt_plugin;
+library document_plugin;
 
 import 'package:app_flowy/generated/locale_keys.g.dart';
 import 'package:app_flowy/startup/plugin/plugin.dart';
@@ -42,10 +42,10 @@ class DocumentPluginBuilder extends PluginBuilder {
   String get menuName => LocaleKeys.document_menuName.tr();
 
   @override
-  PluginType get pluginType => DefaultPlugin.quill.type();
+  PluginType get pluginType => DefaultPlugin.editor.type();
 
   @override
-  ViewDataType get dataType => ViewDataType.TextBlock;
+  ViewDataTypePB get dataType => ViewDataTypePB.TextBlock;
 }
 
 class DocumentPlugin implements Plugin {
diff --git a/frontend/app_flowy/lib/plugins/grid/grid.dart b/frontend/app_flowy/lib/plugins/grid/grid.dart
index c0c6d78642..9ac539929a 100644
--- a/frontend/app_flowy/lib/plugins/grid/grid.dart
+++ b/frontend/app_flowy/lib/plugins/grid/grid.dart
@@ -25,7 +25,10 @@ class GridPluginBuilder implements PluginBuilder {
   PluginType get pluginType => DefaultPlugin.grid.type();
 
   @override
-  ViewDataType get dataType => ViewDataType.Grid;
+  ViewDataTypePB get dataType => ViewDataTypePB.Database;
+
+  @override
+  SubViewDataTypePB? get subDataType => SubViewDataTypePB.Grid;
 }
 
 class GridPluginConfig implements PluginConfig {
diff --git a/frontend/app_flowy/lib/startup/plugin/plugin.dart b/frontend/app_flowy/lib/startup/plugin/plugin.dart
index a02a8cfb83..2879af42cb 100644
--- a/frontend/app_flowy/lib/startup/plugin/plugin.dart
+++ b/frontend/app_flowy/lib/startup/plugin/plugin.dart
@@ -10,7 +10,7 @@ import 'package:flutter/widgets.dart';
 export "./src/sandbox.dart";
 
 enum DefaultPlugin {
-  quill,
+  editor,
   blank,
   trash,
   grid,
@@ -20,7 +20,7 @@ enum DefaultPlugin {
 extension FlowyDefaultPluginExt on DefaultPlugin {
   int type() {
     switch (this) {
-      case DefaultPlugin.quill:
+      case DefaultPlugin.editor:
         return 0;
       case DefaultPlugin.blank:
         return 1;
@@ -35,7 +35,6 @@ extension FlowyDefaultPluginExt on DefaultPlugin {
 }
 
 typedef PluginType = int;
-typedef PluginDataType = ViewDataType;
 typedef PluginId = String;
 
 abstract class Plugin {
@@ -55,7 +54,9 @@ abstract class PluginBuilder {
 
   PluginType get pluginType;
 
-  ViewDataType get dataType => ViewDataType.TextBlock;
+  ViewDataTypePB get dataType => ViewDataTypePB.TextBlock;
+
+  SubViewDataTypePB? get subDataType => null;
 }
 
 abstract class PluginConfig {
diff --git a/frontend/app_flowy/lib/workspace/application/app/app_bloc.dart b/frontend/app_flowy/lib/workspace/application/app/app_bloc.dart
index f86bb5855b..c593c52679 100644
--- a/frontend/app_flowy/lib/workspace/application/app/app_bloc.dart
+++ b/frontend/app_flowy/lib/workspace/application/app/app_bloc.dart
@@ -86,6 +86,7 @@ class AppBloc extends Bloc<AppEvent, AppState> {
       desc: value.desc,
       dataType: value.dataType,
       pluginType: value.pluginType,
+      subDataType: value.subDataType,
     );
     viewOrFailed.fold(
       (view) => emit(state.copyWith(
@@ -138,7 +139,8 @@ class AppEvent with _$AppEvent {
   const factory AppEvent.createView(
     String name,
     String desc,
-    PluginDataType dataType,
+    ViewDataTypePB dataType,
+    SubViewDataTypePB? subDataType,
     PluginType pluginType,
   ) = CreateView;
   const factory AppEvent.delete() = Delete;
diff --git a/frontend/app_flowy/lib/workspace/application/app/app_service.dart b/frontend/app_flowy/lib/workspace/application/app/app_service.dart
index 695f2f4b6b..b05c64dd23 100644
--- a/frontend/app_flowy/lib/workspace/application/app/app_service.dart
+++ b/frontend/app_flowy/lib/workspace/application/app/app_service.dart
@@ -24,16 +24,21 @@ class AppService {
     required String appId,
     required String name,
     required String desc,
-    required PluginDataType dataType,
+    required ViewDataTypePB dataType,
     required PluginType pluginType,
+    SubViewDataTypePB? subDataType,
   }) {
-    final payload = CreateViewPayloadPB.create()
+    var payload = CreateViewPayloadPB.create()
       ..belongToId = appId
       ..name = name
       ..desc = desc
       ..dataType = dataType
       ..pluginType = pluginType;
 
+    if (subDataType != null) {
+      payload.subDataType = subDataType;
+    }
+
     return FolderEventCreateView(payload).send();
   }
 
diff --git a/frontend/app_flowy/lib/workspace/presentation/home/menu/app/header/header.dart b/frontend/app_flowy/lib/workspace/presentation/home/menu/app/header/header.dart
index dbeb2248cc..0cfac08628 100644
--- a/frontend/app_flowy/lib/workspace/presentation/home/menu/app/header/header.dart
+++ b/frontend/app_flowy/lib/workspace/presentation/home/menu/app/header/header.dart
@@ -49,7 +49,9 @@ class MenuAppHeader extends StatelessWidget {
       height: MenuAppSizes.headerHeight,
       child: InkWell(
         onTap: () {
-          ExpandableController.of(context, rebuildOnChange: false, required: true)?.toggle();
+          ExpandableController.of(context,
+                  rebuildOnChange: false, required: true)
+              ?.toggle();
         },
         child: ExpandableIcon(
           theme: ExpandableThemeData(
@@ -68,18 +70,23 @@ class MenuAppHeader extends StatelessWidget {
   Widget _renderTitle(BuildContext context, AppTheme theme) {
     return Expanded(
       child: BlocListener<AppBloc, AppState>(
-        listenWhen: (p, c) => (p.latestCreatedView == null && c.latestCreatedView != null),
+        listenWhen: (p, c) =>
+            (p.latestCreatedView == null && c.latestCreatedView != null),
         listener: (context, state) {
-          final expandableController = ExpandableController.of(context, rebuildOnChange: false, required: true)!;
+          final expandableController = ExpandableController.of(context,
+              rebuildOnChange: false, required: true)!;
           if (!expandableController.expanded) {
             expandableController.toggle();
           }
         },
         child: GestureDetector(
           behavior: HitTestBehavior.opaque,
-          onTap: () => ExpandableController.of(context, rebuildOnChange: false, required: true)?.toggle(),
+          onTap: () => ExpandableController.of(context,
+                  rebuildOnChange: false, required: true)
+              ?.toggle(),
           onSecondaryTap: () {
-            final actionList = AppDisclosureActionSheet(onSelected: (action) => _handleAction(context, action));
+            final actionList = AppDisclosureActionSheet(
+                onSelected: (action) => _handleAction(context, action));
             actionList.show(
               context,
               anchorDirection: AnchorDirection.bottomWithCenterAligned,
@@ -107,6 +114,7 @@ class MenuAppHeader extends StatelessWidget {
                 LocaleKeys.menuAppHeader_defaultNewPageName.tr(),
                 "",
                 pluginBuilder.dataType,
+                pluginBuilder.subDataType,
                 pluginBuilder.pluginType,
               ));
         },
diff --git a/frontend/rust-lib/flowy-folder/src/entities/view.rs b/frontend/rust-lib/flowy-folder/src/entities/view.rs
index 8f3a26c8fd..ae77017947 100644
--- a/frontend/rust-lib/flowy-folder/src/entities/view.rs
+++ b/frontend/rust-lib/flowy-folder/src/entities/view.rs
@@ -22,7 +22,7 @@ pub struct ViewPB {
     pub name: String,
 
     #[pb(index = 4)]
-    pub data_type: ViewDataType,
+    pub data_type: ViewDataTypePB,
 
     #[pb(index = 5)]
     pub modified_time: i64,
@@ -49,31 +49,37 @@ impl std::convert::From<ViewRevision> for ViewPB {
 }
 
 #[derive(Eq, PartialEq, Hash, Debug, ProtoBuf_Enum, Clone)]
-pub enum ViewDataType {
+pub enum ViewDataTypePB {
     TextBlock = 0,
-    Grid = 1,
+    Database = 1,
 }
 
-impl std::default::Default for ViewDataType {
+#[derive(Eq, PartialEq, Hash, Debug, ProtoBuf_Enum, Clone)]
+pub enum SubViewDataTypePB {
+    Grid = 0,
+    Board = 1,
+}
+
+impl std::default::Default for ViewDataTypePB {
     fn default() -> Self {
         ViewDataTypeRevision::default().into()
     }
 }
 
-impl std::convert::From<ViewDataTypeRevision> for ViewDataType {
+impl std::convert::From<ViewDataTypeRevision> for ViewDataTypePB {
     fn from(rev: ViewDataTypeRevision) -> Self {
         match rev {
-            ViewDataTypeRevision::TextBlock => ViewDataType::TextBlock,
-            ViewDataTypeRevision::Grid => ViewDataType::Grid,
+            ViewDataTypeRevision::TextBlock => ViewDataTypePB::TextBlock,
+            ViewDataTypeRevision::Database => ViewDataTypePB::Database,
         }
     }
 }
 
-impl std::convert::From<ViewDataType> for ViewDataTypeRevision {
-    fn from(ty: ViewDataType) -> Self {
+impl std::convert::From<ViewDataTypePB> for ViewDataTypeRevision {
+    fn from(ty: ViewDataTypePB) -> Self {
         match ty {
-            ViewDataType::TextBlock => ViewDataTypeRevision::TextBlock,
-            ViewDataType::Grid => ViewDataTypeRevision::Grid,
+            ViewDataTypePB::TextBlock => ViewDataTypeRevision::TextBlock,
+            ViewDataTypePB::Database => ViewDataTypeRevision::Database,
         }
     }
 }
@@ -113,12 +119,15 @@ pub struct CreateViewPayloadPB {
     pub thumbnail: Option<String>,
 
     #[pb(index = 5)]
-    pub data_type: ViewDataType,
+    pub data_type: ViewDataTypePB,
 
-    #[pb(index = 6)]
-    pub plugin_type: i32,
+    #[pb(index = 6, one_of)]
+    pub sub_data_type: Option<SubViewDataTypePB>,
 
     #[pb(index = 7)]
+    pub plugin_type: i32,
+
+    #[pb(index = 8)]
     pub data: Vec<u8>,
 }
 
@@ -128,7 +137,8 @@ pub struct CreateViewParams {
     pub name: String,
     pub desc: String,
     pub thumbnail: String,
-    pub data_type: ViewDataType,
+    pub data_type: ViewDataTypePB,
+    pub sub_data_type: Option<SubViewDataTypePB>,
     pub view_id: String,
     pub data: Vec<u8>,
     pub plugin_type: i32,
@@ -151,6 +161,7 @@ impl TryInto<CreateViewParams> for CreateViewPayloadPB {
             name,
             desc: self.desc,
             data_type: self.data_type,
+            sub_data_type: self.sub_data_type,
             thumbnail,
             view_id,
             data: self.data,
diff --git a/frontend/rust-lib/flowy-folder/src/entities/view_info.rs b/frontend/rust-lib/flowy-folder/src/entities/view_info.rs
index 92ec785821..42dbc42517 100644
--- a/frontend/rust-lib/flowy-folder/src/entities/view_info.rs
+++ b/frontend/rust-lib/flowy-folder/src/entities/view_info.rs
@@ -1,4 +1,4 @@
-use crate::entities::{RepeatedViewPB, ViewDataType};
+use crate::entities::{RepeatedViewPB, ViewDataTypePB};
 use flowy_derive::ProtoBuf;
 
 #[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
@@ -16,7 +16,7 @@ pub struct ViewInfoPB {
     pub desc: String,
 
     #[pb(index = 5)]
-    pub data_type: ViewDataType,
+    pub data_type: ViewDataTypePB,
 
     #[pb(index = 6)]
     pub belongings: RepeatedViewPB,
diff --git a/frontend/rust-lib/flowy-folder/src/manager.rs b/frontend/rust-lib/flowy-folder/src/manager.rs
index df070d90f3..96e35ba547 100644
--- a/frontend/rust-lib/flowy-folder/src/manager.rs
+++ b/frontend/rust-lib/flowy-folder/src/manager.rs
@@ -1,4 +1,5 @@
-use crate::entities::view::ViewDataType;
+use crate::entities::view::ViewDataTypePB;
+use crate::entities::SubViewDataTypePB;
 use crate::services::folder_editor::FolderRevisionCompactor;
 use crate::{
     dart_notification::{send_dart_notification, FolderNotification},
@@ -221,7 +222,7 @@ impl DefaultFolderBuilder {
                 };
                 let _ = view_controller.set_latest_view(&view.id);
                 let _ = view_controller
-                    .create_view(&view.id, ViewDataType::TextBlock, Bytes::from(view_data))
+                    .create_view(&view.id, ViewDataTypePB::TextBlock, Bytes::from(view_data))
                     .await?;
             }
         }
@@ -256,7 +257,12 @@ pub trait ViewDataProcessor {
 
     fn get_delta_data(&self, view_id: &str) -> FutureResult<Bytes, FlowyError>;
 
-    fn create_default_view(&self, user_id: &str, view_id: &str) -> FutureResult<Bytes, FlowyError>;
+    fn create_default_view(
+        &self,
+        user_id: &str,
+        view_id: &str,
+        sub_data_type: Option<SubViewDataTypePB>,
+    ) -> FutureResult<Bytes, FlowyError>;
 
     fn create_view_from_delta_data(
         &self,
@@ -265,7 +271,7 @@ pub trait ViewDataProcessor {
         data: Vec<u8>,
     ) -> FutureResult<Bytes, FlowyError>;
 
-    fn data_type(&self) -> ViewDataType;
+    fn data_type(&self) -> ViewDataTypePB;
 }
 
-pub type ViewDataProcessorMap = Arc<HashMap<ViewDataType, Arc<dyn ViewDataProcessor + Send + Sync>>>;
+pub type ViewDataProcessorMap = Arc<HashMap<ViewDataTypePB, Arc<dyn ViewDataProcessor + Send + Sync>>>;
diff --git a/frontend/rust-lib/flowy-folder/src/services/persistence/version_1/view_sql.rs b/frontend/rust-lib/flowy-folder/src/services/persistence/version_1/view_sql.rs
index 6223cd3366..245bd32f83 100644
--- a/frontend/rust-lib/flowy-folder/src/services/persistence/version_1/view_sql.rs
+++ b/frontend/rust-lib/flowy-folder/src/services/persistence/version_1/view_sql.rs
@@ -88,7 +88,7 @@ impl ViewTable {
     pub fn new(view_rev: ViewRevision) -> Self {
         let data_type = match view_rev.data_type {
             ViewDataTypeRevision::TextBlock => SqlViewDataType::Block,
-            ViewDataTypeRevision::Grid => SqlViewDataType::Grid,
+            ViewDataTypeRevision::Database => SqlViewDataType::Grid,
         };
 
         ViewTable {
@@ -111,7 +111,7 @@ impl std::convert::From<ViewTable> for ViewRevision {
     fn from(table: ViewTable) -> Self {
         let data_type = match table.view_type {
             SqlViewDataType::Block => ViewDataTypeRevision::TextBlock,
-            SqlViewDataType::Grid => ViewDataTypeRevision::Grid,
+            SqlViewDataType::Grid => ViewDataTypeRevision::Database,
         };
 
         ViewRevision {
diff --git a/frontend/rust-lib/flowy-folder/src/services/view/controller.rs b/frontend/rust-lib/flowy-folder/src/services/view/controller.rs
index df1f668941..defbe664db 100644
--- a/frontend/rust-lib/flowy-folder/src/services/view/controller.rs
+++ b/frontend/rust-lib/flowy-folder/src/services/view/controller.rs
@@ -1,5 +1,5 @@
-pub use crate::entities::view::ViewDataType;
-use crate::entities::ViewInfoPB;
+pub use crate::entities::view::ViewDataTypePB;
+use crate::entities::{SubViewDataTypePB, ViewInfoPB};
 use crate::manager::{ViewDataProcessor, ViewDataProcessorMap};
 use crate::{
     dart_notification::{send_dart_notification, FolderNotification},
@@ -61,7 +61,9 @@ impl ViewController {
         let processor = self.get_data_processor(params.data_type.clone())?;
         let user_id = self.user.user_id()?;
         if params.data.is_empty() {
-            let view_data = processor.create_default_view(&user_id, &params.view_id).await?;
+            let view_data = processor
+                .create_default_view(&user_id, &params.view_id, params.sub_data_type.clone())
+                .await?;
             params.data = view_data.to_vec();
         } else {
             let delta_data = processor
@@ -81,7 +83,7 @@ impl ViewController {
     pub(crate) async fn create_view(
         &self,
         view_id: &str,
-        data_type: ViewDataType,
+        data_type: ViewDataTypePB,
         delta_data: Bytes,
     ) -> Result<(), FlowyError> {
         if delta_data.is_empty() {
@@ -217,6 +219,7 @@ impl ViewController {
             desc: view_rev.desc,
             thumbnail: view_rev.thumbnail,
             data_type: view_rev.data_type.into(),
+            sub_data_type: None,
             data: delta_bytes.to_vec(),
             view_id: gen_view_id(),
             plugin_type: view_rev.plugin_type,
@@ -364,7 +367,7 @@ impl ViewController {
     }
 
     #[inline]
-    fn get_data_processor<T: Into<ViewDataType>>(
+    fn get_data_processor<T: Into<ViewDataTypePB>>(
         &self,
         data_type: T,
     ) -> FlowyResult<Arc<dyn ViewDataProcessor + Send + Sync>> {
@@ -452,7 +455,7 @@ async fn handle_trash_event(
 
 fn get_data_processor(
     data_processors: ViewDataProcessorMap,
-    data_type: &ViewDataType,
+    data_type: &ViewDataTypePB,
 ) -> FlowyResult<Arc<dyn ViewDataProcessor + Send + Sync>> {
     match data_processors.get(data_type) {
         None => Err(FlowyError::internal().context(format!(
diff --git a/frontend/rust-lib/flowy-folder/tests/workspace/folder_test.rs b/frontend/rust-lib/flowy-folder/tests/workspace/folder_test.rs
index f17986b484..15af0cb8d9 100644
--- a/frontend/rust-lib/flowy-folder/tests/workspace/folder_test.rs
+++ b/frontend/rust-lib/flowy-folder/tests/workspace/folder_test.rs
@@ -1,5 +1,5 @@
 use crate::script::{invalid_workspace_name_test_case, FolderScript::*, FolderTest};
-use flowy_folder::entities::view::ViewDataType;
+use flowy_folder::entities::view::ViewDataTypePB;
 use flowy_folder::entities::workspace::CreateWorkspacePayloadPB;
 
 use flowy_revision::disk::RevisionState;
@@ -134,12 +134,12 @@ async fn app_create_with_view() {
         CreateView {
             name: "View A".to_owned(),
             desc: "View A description".to_owned(),
-            data_type: ViewDataType::TextBlock,
+            data_type: ViewDataTypePB::TextBlock,
         },
         CreateView {
             name: "Grid".to_owned(),
             desc: "Grid description".to_owned(),
-            data_type: ViewDataType::Grid,
+            data_type: ViewDataTypePB::Database,
         },
         ReadApp(app.id),
     ])
@@ -198,12 +198,12 @@ async fn view_delete_all() {
         CreateView {
             name: "View A".to_owned(),
             desc: "View A description".to_owned(),
-            data_type: ViewDataType::TextBlock,
+            data_type: ViewDataTypePB::TextBlock,
         },
         CreateView {
             name: "Grid".to_owned(),
             desc: "Grid description".to_owned(),
-            data_type: ViewDataType::Grid,
+            data_type: ViewDataTypePB::Database,
         },
         ReadApp(app.id.clone()),
     ])
@@ -231,7 +231,7 @@ async fn view_delete_all_permanent() {
         CreateView {
             name: "View A".to_owned(),
             desc: "View A description".to_owned(),
-            data_type: ViewDataType::TextBlock,
+            data_type: ViewDataTypePB::TextBlock,
         },
         ReadApp(app.id.clone()),
     ])
@@ -330,7 +330,7 @@ async fn folder_sync_revision_with_new_view() {
         CreateView {
             name: view_name.clone(),
             desc: view_desc.clone(),
-            data_type: ViewDataType::TextBlock,
+            data_type: ViewDataTypePB::TextBlock,
         },
         AssertCurrentRevId(3),
         AssertNextSyncRevId(Some(3)),
diff --git a/frontend/rust-lib/flowy-folder/tests/workspace/script.rs b/frontend/rust-lib/flowy-folder/tests/workspace/script.rs
index ed16664d90..91fac9869e 100644
--- a/frontend/rust-lib/flowy-folder/tests/workspace/script.rs
+++ b/frontend/rust-lib/flowy-folder/tests/workspace/script.rs
@@ -9,7 +9,7 @@ use flowy_folder::entities::{
 use flowy_folder::entities::{
     app::{AppPB, RepeatedAppPB},
     trash::TrashPB,
-    view::{RepeatedViewPB, ViewDataType, ViewPB},
+    view::{RepeatedViewPB, ViewDataTypePB, ViewPB},
     workspace::WorkspacePB,
 };
 use flowy_folder::event_map::FolderEvent::*;
@@ -51,7 +51,7 @@ pub enum FolderScript {
     CreateView {
         name: String,
         desc: String,
-        data_type: ViewDataType,
+        data_type: ViewDataTypePB,
     },
     AssertView(ViewPB),
     ReadView(String),
@@ -98,7 +98,7 @@ impl FolderTest {
             &app.id,
             "Folder View",
             "Folder test view",
-            ViewDataType::TextBlock,
+            ViewDataTypePB::TextBlock,
         )
         .await;
         app.belongings = RepeatedViewPB {
@@ -346,7 +346,13 @@ pub async fn delete_app(sdk: &FlowySDKTest, app_id: &str) {
         .await;
 }
 
-pub async fn create_view(sdk: &FlowySDKTest, app_id: &str, name: &str, desc: &str, data_type: ViewDataType) -> ViewPB {
+pub async fn create_view(
+    sdk: &FlowySDKTest,
+    app_id: &str,
+    name: &str,
+    desc: &str,
+    data_type: ViewDataTypePB,
+) -> ViewPB {
     let request = CreateViewPayloadPB {
         belong_to_id: app_id.to_string(),
         name: name.to_string(),
diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/single_select_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/single_select_type_option.rs
index 553425222e..8722b3a479 100644
--- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/single_select_type_option.rs
+++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/single_select_type_option.rs
@@ -82,7 +82,7 @@ impl_into_box_type_option_builder!(SingleSelectTypeOptionBuilder);
 impl_builder_from_json_str_and_from_bytes!(SingleSelectTypeOptionBuilder, SingleSelectTypeOptionPB);
 
 impl SingleSelectTypeOptionBuilder {
-    pub fn option(mut self, opt: SelectOptionPB) -> Self {
+    pub fn add_option(mut self, opt: SelectOptionPB) -> Self {
         self.0.options.push(opt);
         self
     }
@@ -113,9 +113,9 @@ mod tests {
         let facebook_option = SelectOptionPB::new("Facebook");
         let twitter_option = SelectOptionPB::new("Twitter");
         let single_select = SingleSelectTypeOptionBuilder::default()
-            .option(google_option.clone())
-            .option(facebook_option.clone())
-            .option(twitter_option);
+            .add_option(google_option.clone())
+            .add_option(facebook_option.clone())
+            .add_option(twitter_option);
 
         let field_rev = FieldBuilder::new(single_select)
             .name("Platform")
diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option/text_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option/text_type_option.rs
index b11bd026d2..43e2b009d0 100644
--- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option/text_type_option.rs
+++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option/text_type_option.rs
@@ -133,7 +133,7 @@ mod tests {
         // Single select
         let done_option = SelectOptionPB::new("Done");
         let done_option_id = done_option.id.clone();
-        let single_select = SingleSelectTypeOptionBuilder::default().option(done_option.clone());
+        let single_select = SingleSelectTypeOptionBuilder::default().add_option(done_option.clone());
         let single_select_field_rev = FieldBuilder::new(single_select).build();
 
         assert_eq!(
diff --git a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs
index 44626b96fd..08c7284b74 100644
--- a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs
+++ b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs
@@ -272,7 +272,7 @@ impl GridRevisionEditor {
         let block_id = self.block_id().await?;
 
         // insert empty row below the row whose id is upper_row_id
-        let row_rev = RowRevisionBuilder::new(&field_revs).build(&block_id);
+        let row_rev = RowRevisionBuilder::new(&block_id, &field_revs).build();
         let row_order = GridRowPB::from(&row_rev);
 
         // insert the row
diff --git a/frontend/rust-lib/flowy-grid/src/services/row/row_builder.rs b/frontend/rust-lib/flowy-grid/src/services/row/row_builder.rs
index 43153f1311..3973dd4aed 100644
--- a/frontend/rust-lib/flowy-grid/src/services/row/row_builder.rs
+++ b/frontend/rust-lib/flowy-grid/src/services/row/row_builder.rs
@@ -7,12 +7,13 @@ use std::collections::HashMap;
 use std::sync::Arc;
 
 pub struct RowRevisionBuilder<'a> {
+    block_id: String,
     field_rev_map: HashMap<&'a String, Arc<FieldRevision>>,
     payload: CreateRowRevisionPayload,
 }
 
 impl<'a> RowRevisionBuilder<'a> {
-    pub fn new(fields: &'a [Arc<FieldRevision>]) -> Self {
+    pub fn new(block_id: &str, fields: &'a [Arc<FieldRevision>]) -> Self {
         let field_rev_map = fields
             .iter()
             .map(|field| (&field.id, field.clone()))
@@ -25,7 +26,13 @@ impl<'a> RowRevisionBuilder<'a> {
             visibility: true,
         };
 
-        Self { field_rev_map, payload }
+        let block_id = block_id.to_string();
+
+        Self {
+            block_id,
+            field_rev_map,
+            payload,
+        }
     }
 
     pub fn insert_cell(&mut self, field_id: &str, data: String) -> FlowyResult<()> {
@@ -43,18 +50,18 @@ impl<'a> RowRevisionBuilder<'a> {
         }
     }
 
-    pub fn insert_select_option_cell(&mut self, field_id: &str, data: String) -> FlowyResult<()> {
+    pub fn insert_select_option_cell(mut self, field_id: &str, data: String) -> Self {
         match self.field_rev_map.get(&field_id.to_owned()) {
             None => {
-                let msg = format!("Invalid field_id: {}", field_id);
-                Err(FlowyError::internal().context(msg))
+                tracing::warn!("Invalid field_id: {}", field_id);
+                self
             }
             Some(field_rev) => {
                 let cell_data = SelectOptionCellChangeset::from_insert(&data).to_str();
-                let data = apply_cell_data_changeset(cell_data, None, field_rev)?;
+                let data = apply_cell_data_changeset(cell_data, None, field_rev).unwrap();
                 let cell = CellRevision::new(data);
                 self.payload.cell_by_field_id.insert(field_id.to_owned(), cell);
-                Ok(())
+                self
             }
         }
     }
@@ -71,10 +78,10 @@ impl<'a> RowRevisionBuilder<'a> {
         self
     }
 
-    pub fn build(self, block_id: &str) -> RowRevision {
+    pub fn build(self) -> RowRevision {
         RowRevision {
             id: self.payload.row_id,
-            block_id: block_id.to_owned(),
+            block_id: self.block_id,
             cells: self.payload.cell_by_field_id,
             height: self.payload.height,
             visibility: self.payload.visibility,
diff --git a/frontend/rust-lib/flowy-grid/src/util.rs b/frontend/rust-lib/flowy-grid/src/util.rs
index 3b48e313a9..a53314a812 100644
--- a/frontend/rust-lib/flowy-grid/src/util.rs
+++ b/frontend/rust-lib/flowy-grid/src/util.rs
@@ -1,5 +1,6 @@
 use crate::entities::FieldType;
 use crate::services::field::*;
+use crate::services::row::RowRevisionBuilder;
 use flowy_grid_data_model::revision::BuildGridContext;
 use flowy_sync::client_grid::GridBuilder;
 
@@ -30,3 +31,47 @@ pub fn make_default_grid() -> BuildGridContext {
     grid_builder.add_empty_row();
     grid_builder.build()
 }
+
+pub fn make_default_board() -> BuildGridContext {
+    let mut grid_builder = GridBuilder::new();
+    // text
+    let text_field = FieldBuilder::new(RichTextTypeOptionBuilder::default())
+        .name("Name")
+        .visibility(true)
+        .primary(true)
+        .build();
+    grid_builder.add_field(text_field);
+
+    // single select
+    let in_progress_option = SelectOptionPB::new("In progress");
+    let not_started_option = SelectOptionPB::new("Not started");
+    let done_option = SelectOptionPB::new("Done");
+    let single_select = SingleSelectTypeOptionBuilder::default()
+        .add_option(not_started_option.clone())
+        .add_option(in_progress_option.clone())
+        .add_option(done_option.clone());
+    let single_select_field = FieldBuilder::new(single_select).name("Status").visibility(true).build();
+    let single_select_field_id = single_select_field.id.clone();
+    grid_builder.add_field(single_select_field);
+
+    let field_revs = grid_builder.field_revs();
+    let block_id = grid_builder.block_id();
+
+    // rows
+    let row_1 = RowRevisionBuilder::new(block_id, field_revs)
+        .insert_select_option_cell(&single_select_field_id, not_started_option.id.clone())
+        .build();
+    grid_builder.add_row(row_1);
+
+    let row_2 = RowRevisionBuilder::new(block_id, field_revs)
+        .insert_select_option_cell(&single_select_field_id, not_started_option.id.clone())
+        .build();
+    grid_builder.add_row(row_2);
+
+    let row_3 = RowRevisionBuilder::new(block_id, field_revs)
+        .insert_select_option_cell(&single_select_field_id, not_started_option.id.clone())
+        .build();
+    grid_builder.add_row(row_3);
+
+    grid_builder.build()
+}
diff --git a/frontend/rust-lib/flowy-grid/tests/grid/block_test/util.rs b/frontend/rust-lib/flowy-grid/tests/grid/block_test/util.rs
index 216a4d4acd..d2a430f591 100644
--- a/frontend/rust-lib/flowy-grid/tests/grid/block_test/util.rs
+++ b/frontend/rust-lib/flowy-grid/tests/grid/block_test/util.rs
@@ -18,7 +18,7 @@ pub struct GridRowTestBuilder<'a> {
 impl<'a> GridRowTestBuilder<'a> {
     pub fn new(block_id: &str, field_revs: &'a [Arc<FieldRevision>]) -> Self {
         assert_eq!(field_revs.len(), FieldType::COUNT);
-        let inner_builder = RowRevisionBuilder::new(field_revs);
+        let inner_builder = RowRevisionBuilder::new(block_id, field_revs);
         Self {
             block_id: block_id.to_owned(),
             field_revs,
@@ -77,8 +77,7 @@ impl<'a> GridRowTestBuilder<'a> {
         let type_option = SingleSelectTypeOptionPB::from(&single_select_field);
         let option = f(type_option.options);
         self.inner_builder
-            .insert_select_option_cell(&single_select_field.id, option.id)
-            .unwrap();
+            .insert_select_option_cell(&single_select_field.id, option.id);
 
         single_select_field.id.clone()
     }
@@ -96,8 +95,7 @@ impl<'a> GridRowTestBuilder<'a> {
             .collect::<Vec<_>>()
             .join(SELECTION_IDS_SEPARATOR);
         self.inner_builder
-            .insert_select_option_cell(&multi_select_field.id, ops_ids)
-            .unwrap();
+            .insert_select_option_cell(&multi_select_field.id, ops_ids);
 
         multi_select_field.id.clone()
     }
@@ -115,7 +113,7 @@ impl<'a> GridRowTestBuilder<'a> {
     }
 
     pub fn build(self) -> RowRevision {
-        self.inner_builder.build(&self.block_id)
+        self.inner_builder.build()
     }
 }
 
diff --git a/frontend/rust-lib/flowy-grid/tests/grid/field_test/util.rs b/frontend/rust-lib/flowy-grid/tests/grid/field_test/util.rs
index 01424cef74..9987b60671 100644
--- a/frontend/rust-lib/flowy-grid/tests/grid/field_test/util.rs
+++ b/frontend/rust-lib/flowy-grid/tests/grid/field_test/util.rs
@@ -39,8 +39,8 @@ pub fn create_text_field(grid_id: &str) -> (InsertFieldParams, FieldRevision) {
 
 pub fn create_single_select_field(grid_id: &str) -> (InsertFieldParams, FieldRevision) {
     let single_select = SingleSelectTypeOptionBuilder::default()
-        .option(SelectOptionPB::new("Done"))
-        .option(SelectOptionPB::new("Progress"));
+        .add_option(SelectOptionPB::new("Done"))
+        .add_option(SelectOptionPB::new("Progress"));
 
     let field_rev = FieldBuilder::new(single_select).name("Name").visibility(true).build();
     let cloned_field_rev = field_rev.clone();
diff --git a/frontend/rust-lib/flowy-grid/tests/grid/grid_editor.rs b/frontend/rust-lib/flowy-grid/tests/grid/grid_editor.rs
index f924b3e803..09f52ddb15 100644
--- a/frontend/rust-lib/flowy-grid/tests/grid/grid_editor.rs
+++ b/frontend/rust-lib/flowy-grid/tests/grid/grid_editor.rs
@@ -138,9 +138,9 @@ fn make_test_grid() -> BuildGridContext {
             FieldType::SingleSelect => {
                 // Single Select
                 let single_select = SingleSelectTypeOptionBuilder::default()
-                    .option(SelectOptionPB::new(COMPLETED))
-                    .option(SelectOptionPB::new(PLANNED))
-                    .option(SelectOptionPB::new(PAUSED));
+                    .add_option(SelectOptionPB::new(COMPLETED))
+                    .add_option(SelectOptionPB::new(PLANNED))
+                    .add_option(SelectOptionPB::new(PAUSED));
                 let single_select_field = FieldBuilder::new(single_select).name("Status").visibility(true).build();
                 grid_builder.add_field(single_select_field);
             }
diff --git a/frontend/rust-lib/flowy-sdk/src/deps_resolve/folder_deps.rs b/frontend/rust-lib/flowy-sdk/src/deps_resolve/folder_deps.rs
index 24bb71d89c..cb1d90409e 100644
--- a/frontend/rust-lib/flowy-sdk/src/deps_resolve/folder_deps.rs
+++ b/frontend/rust-lib/flowy-sdk/src/deps_resolve/folder_deps.rs
@@ -1,6 +1,6 @@
 use bytes::Bytes;
 use flowy_database::ConnectionPool;
-use flowy_folder::entities::ViewDataType;
+use flowy_folder::entities::{SubViewDataTypePB, ViewDataTypePB};
 use flowy_folder::manager::{ViewDataProcessor, ViewDataProcessorMap};
 use flowy_folder::{
     errors::{internal_error, FlowyError},
@@ -8,7 +8,7 @@ use flowy_folder::{
     manager::FolderManager,
 };
 use flowy_grid::manager::{make_grid_view_data, GridManager};
-use flowy_grid::util::make_default_grid;
+use flowy_grid::util::{make_default_board, make_default_grid};
 use flowy_grid_data_model::revision::BuildGridContext;
 use flowy_net::ClientServerConfiguration;
 use flowy_net::{
@@ -66,7 +66,7 @@ fn make_view_data_processor(
     text_block_manager: Arc<TextBlockManager>,
     grid_manager: Arc<GridManager>,
 ) -> ViewDataProcessorMap {
-    let mut map: HashMap<ViewDataType, Arc<dyn ViewDataProcessor + Send + Sync>> = HashMap::new();
+    let mut map: HashMap<ViewDataTypePB, Arc<dyn ViewDataProcessor + Send + Sync>> = HashMap::new();
 
     let block_data_impl = TextBlockViewDataProcessor(text_block_manager);
     map.insert(block_data_impl.data_type(), Arc::new(block_data_impl));
@@ -180,7 +180,12 @@ impl ViewDataProcessor for TextBlockViewDataProcessor {
         })
     }
 
-    fn create_default_view(&self, user_id: &str, view_id: &str) -> FutureResult<Bytes, FlowyError> {
+    fn create_default_view(
+        &self,
+        user_id: &str,
+        view_id: &str,
+        _sub_data_type: Option<SubViewDataTypePB>,
+    ) -> FutureResult<Bytes, FlowyError> {
         let user_id = user_id.to_string();
         let view_id = view_id.to_string();
         let manager = self.0.clone();
@@ -203,8 +208,8 @@ impl ViewDataProcessor for TextBlockViewDataProcessor {
         FutureResult::new(async move { Ok(Bytes::from(data)) })
     }
 
-    fn data_type(&self) -> ViewDataType {
-        ViewDataType::TextBlock
+    fn data_type(&self) -> ViewDataTypePB {
+        ViewDataTypePB::TextBlock
     }
 }
 
@@ -252,8 +257,16 @@ impl ViewDataProcessor for GridViewDataProcessor {
         })
     }
 
-    fn create_default_view(&self, user_id: &str, view_id: &str) -> FutureResult<Bytes, FlowyError> {
-        let build_context = make_default_grid();
+    fn create_default_view(
+        &self,
+        user_id: &str,
+        view_id: &str,
+        sub_data_type: Option<SubViewDataTypePB>,
+    ) -> FutureResult<Bytes, FlowyError> {
+        let build_context = match sub_data_type.unwrap() {
+            SubViewDataTypePB::Grid => make_default_grid(),
+            SubViewDataTypePB::Board => make_default_board(),
+        };
         let user_id = user_id.to_string();
         let view_id = view_id.to_string();
         let grid_manager = self.0.clone();
@@ -278,7 +291,7 @@ impl ViewDataProcessor for GridViewDataProcessor {
         })
     }
 
-    fn data_type(&self) -> ViewDataType {
-        ViewDataType::Grid
+    fn data_type(&self) -> ViewDataTypePB {
+        ViewDataTypePB::Database
     }
 }
diff --git a/frontend/rust-lib/flowy-test/src/helper.rs b/frontend/rust-lib/flowy-test/src/helper.rs
index 1265bd695c..6254955ceb 100644
--- a/frontend/rust-lib/flowy-test/src/helper.rs
+++ b/frontend/rust-lib/flowy-test/src/helper.rs
@@ -25,7 +25,7 @@ pub struct ViewTest {
 
 impl ViewTest {
     #[allow(dead_code)]
-    pub async fn new(sdk: &FlowySDKTest, data_type: ViewDataType, data: Vec<u8>) -> Self {
+    pub async fn new(sdk: &FlowySDKTest, data_type: ViewDataTypePB, data: Vec<u8>) -> Self {
         let workspace = create_workspace(sdk, "Workspace", "").await;
         open_workspace(sdk, &workspace.id).await;
         let app = create_app(sdk, "App", "AppFlowy GitHub Project", &workspace.id).await;
@@ -39,11 +39,11 @@ impl ViewTest {
     }
 
     pub async fn new_grid_view(sdk: &FlowySDKTest, data: Vec<u8>) -> Self {
-        Self::new(sdk, ViewDataType::Grid, data).await
+        Self::new(sdk, ViewDataTypePB::Database, data).await
     }
 
     pub async fn new_text_block_view(sdk: &FlowySDKTest) -> Self {
-        Self::new(sdk, ViewDataType::TextBlock, vec![]).await
+        Self::new(sdk, ViewDataTypePB::TextBlock, vec![]).await
     }
 }
 
@@ -90,7 +90,7 @@ async fn create_app(sdk: &FlowySDKTest, name: &str, desc: &str, workspace_id: &s
     app
 }
 
-async fn create_view(sdk: &FlowySDKTest, app_id: &str, data_type: ViewDataType, data: Vec<u8>) -> ViewPB {
+async fn create_view(sdk: &FlowySDKTest, app_id: &str, data_type: ViewDataTypePB, data: Vec<u8>) -> ViewPB {
     let request = CreateViewPayloadPB {
         belong_to_id: app_id.to_string(),
         name: "View A".to_string(),
diff --git a/shared-lib/flowy-folder-data-model/src/revision/view_rev.rs b/shared-lib/flowy-folder-data-model/src/revision/view_rev.rs
index 7a81bbb191..e542fb9bbd 100644
--- a/shared-lib/flowy-folder-data-model/src/revision/view_rev.rs
+++ b/shared-lib/flowy-folder-data-model/src/revision/view_rev.rs
@@ -53,7 +53,7 @@ impl std::convert::From<ViewRevision> for TrashRevision {
 #[repr(u8)]
 pub enum ViewDataTypeRevision {
     TextBlock = 0,
-    Grid = 1,
+    Database = 1,
 }
 
 impl std::default::Default for ViewDataTypeRevision {