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, ¶ms.view_id).await?; + let view_data = processor + .create_default_view(&user_id, ¶ms.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 {