Преглед на файлове

docs: update code documentation (#1804)

* docs: update code documentation

* chore: fix bloc test

* chore: reduce lock granularity

* chore: fix bloc test
Nathan.fooo преди 2 години
родител
ревизия
1df2619c9f
променени са 29 файла, в които са добавени 198 реда и са изтрити 212 реда
  1. 1 1
      frontend/.vscode/tasks.json
  2. 1 1
      frontend/app_flowy/lib/plugins/document/document.dart
  3. 8 3
      frontend/app_flowy/lib/plugins/grid/application/cell/select_option_editor_bloc.dart
  4. 8 8
      frontend/app_flowy/lib/plugins/grid/application/field/type_option/type_option_data_controller.dart
  5. 1 1
      frontend/app_flowy/lib/startup/plugin/plugin.dart
  6. 1 1
      frontend/app_flowy/lib/workspace/application/app/app_service.dart
  7. 1 1
      frontend/app_flowy/lib/workspace/application/workspace/workspace_service.dart
  8. 1 1
      frontend/app_flowy/test/bloc_test/board_test/group_by_checkbox_field_test.dart
  9. 7 3
      frontend/app_flowy/test/bloc_test/board_test/group_by_multi_select_field_test.dart
  10. 35 3
      frontend/app_flowy/test/bloc_test/grid_test/cell/select_option_cell_test.dart
  11. 54 61
      frontend/app_flowy/test/bloc_test/grid_test/field/edit_field_test.dart
  12. 1 1
      frontend/app_flowy/test/bloc_test/grid_test/util.dart
  13. 2 2
      frontend/app_flowy/test/bloc_test/home_test/view_bloc_test.dart
  14. 1 1
      frontend/rust-lib/flowy-core/src/deps_resolve/folder_deps.rs
  15. 1 1
      frontend/rust-lib/flowy-core/src/lib.rs
  16. 15 14
      frontend/rust-lib/flowy-database/src/services/filter/controller.rs
  17. 2 5
      frontend/rust-lib/flowy-database/src/services/filter/task.rs
  18. 16 19
      frontend/rust-lib/flowy-database/src/services/view_editor/editor.rs
  19. 2 2
      frontend/rust-lib/flowy-database/src/services/view_editor/trait_impl.rs
  20. 0 2
      frontend/rust-lib/flowy-folder/src/entities/mod.rs
  21. 7 3
      frontend/rust-lib/flowy-folder/src/entities/view.rs
  22. 0 26
      frontend/rust-lib/flowy-folder/src/entities/view_info.rs
  23. 26 6
      frontend/rust-lib/flowy-folder/src/event_map.rs
  24. 2 2
      frontend/rust-lib/flowy-folder/src/services/persistence/version_1/view_sql.rs
  25. 2 31
      frontend/rust-lib/flowy-folder/src/services/view/controller.rs
  26. 0 10
      frontend/rust-lib/flowy-folder/src/services/view/event_handler.rs
  27. 1 1
      frontend/rust-lib/flowy-folder/tests/workspace/script.rs
  28. 1 1
      frontend/rust-lib/flowy-test/src/helper.rs
  29. 1 1
      shared-lib/folder-model/src/view_rev.rs

+ 1 - 1
frontend/.vscode/tasks.json

@@ -58,7 +58,7 @@
 			"label": "AF: Build Appflowy Core",
 			"type": "shell",
 			"windows": {
-				"command": "cargo make --profile development-windows appflowy-core-dev"
+				"command": "cargo make --profile development-windows-x86 appflowy-core-dev"
 			},
 			"linux": {
 				"command": "cargo make --profile \"development-linux-$(uname -m)\" appflowy-core-dev"

+ 1 - 1
frontend/app_flowy/lib/plugins/document/document.dart

@@ -34,7 +34,7 @@ class DocumentPluginBuilder extends PluginBuilder {
   PluginType get pluginType => PluginType.editor;
 
   @override
-  ViewDataFormatPB get dataFormatType => ViewDataFormatPB.TreeFormat;
+  ViewDataFormatPB get dataFormatType => ViewDataFormatPB.NodeFormat;
 }
 
 class DocumentPlugin extends Plugin<int> {

+ 8 - 3
frontend/app_flowy/lib/plugins/grid/application/cell/select_option_editor_bloc.dart

@@ -147,8 +147,10 @@ class SelectOptionCellEditorBloc
   }
 
   void _filterOption(String optionName, Emitter<SelectOptionEditorState> emit) {
-    final _MakeOptionResult result =
-        _makeOptions(Some(optionName), state.allOptions);
+    final _MakeOptionResult result = _makeOptions(
+      Some(optionName),
+      state.allOptions,
+    );
     emit(state.copyWith(
       filter: Some(optionName),
       options: result.options,
@@ -159,6 +161,7 @@ class SelectOptionCellEditorBloc
   Future<void> _loadOptions() async {
     final result = await _selectOptionService.getOptionContext();
     if (isClosed) {
+      Log.warn("Unexpected closing the bloc");
       return;
     }
 
@@ -177,7 +180,9 @@ class SelectOptionCellEditorBloc
   }
 
   _MakeOptionResult _makeOptions(
-      Option<String> filter, List<SelectOptionPB> allOptions) {
+    Option<String> filter,
+    List<SelectOptionPB> allOptions,
+  ) {
     final List<SelectOptionPB> options = List.from(allOptions);
     Option<String> createOption = filter;
 

+ 8 - 8
frontend/app_flowy/lib/plugins/grid/application/field/type_option/type_option_data_controller.dart

@@ -12,7 +12,7 @@ import 'type_option_context.dart';
 class TypeOptionDataController {
   final String databaseId;
   final IFieldTypeOptionLoader loader;
-  late TypeOptionPB _data;
+  late TypeOptionPB _typeOptiondata;
   final PublishNotifier<FieldPB> _fieldNotifier = PublishNotifier();
 
   /// Returns a [TypeOptionDataController] used to modify the specified
@@ -27,7 +27,7 @@ class TypeOptionDataController {
     FieldInfo? fieldInfo,
   }) {
     if (fieldInfo != null) {
-      _data = TypeOptionPB.create()
+      _typeOptiondata = TypeOptionPB.create()
         ..databaseId = databaseId
         ..field_2 = fieldInfo.field;
     }
@@ -38,7 +38,7 @@ class TypeOptionDataController {
     return result.fold(
       (data) {
         data.freeze();
-        _data = data;
+        _typeOptiondata = data;
         _fieldNotifier.value = data.field_2;
         return left(data);
       },
@@ -50,28 +50,28 @@ class TypeOptionDataController {
   }
 
   FieldPB get field {
-    return _data.field_2;
+    return _typeOptiondata.field_2;
   }
 
   T getTypeOption<T>(TypeOptionDataParser<T> parser) {
-    return parser.fromBuffer(_data.typeOptionData);
+    return parser.fromBuffer(_typeOptiondata.typeOptionData);
   }
 
   set fieldName(String name) {
-    _data = _data.rebuild((rebuildData) {
+    _typeOptiondata = _typeOptiondata.rebuild((rebuildData) {
       rebuildData.field_2 = rebuildData.field_2.rebuild((rebuildField) {
         rebuildField.name = name;
       });
     });
 
-    _fieldNotifier.value = _data.field_2;
+    _fieldNotifier.value = _typeOptiondata.field_2;
 
     FieldService(databaseId: databaseId, fieldId: field.id)
         .updateField(name: name);
   }
 
   set typeOptionData(List<int> typeOptionData) {
-    _data = _data.rebuild((rebuildData) {
+    _typeOptiondata = _typeOptiondata.rebuild((rebuildData) {
       if (typeOptionData.isNotEmpty) {
         rebuildData.typeOptionData = typeOptionData;
       }

+ 1 - 1
frontend/app_flowy/lib/startup/plugin/plugin.dart

@@ -52,7 +52,7 @@ abstract class PluginBuilder {
 
   PluginType get pluginType;
 
-  ViewDataFormatPB get dataFormatType => ViewDataFormatPB.TreeFormat;
+  ViewDataFormatPB get dataFormatType => ViewDataFormatPB.NodeFormat;
 
   ViewLayoutTypePB? get layoutType => ViewLayoutTypePB.Document;
 }

+ 1 - 1
frontend/app_flowy/lib/workspace/application/app/app_service.dart

@@ -76,7 +76,7 @@ class AppService {
       ..to = toIndex
       ..ty = MoveFolderItemType.MoveView;
 
-    return FolderEventMoveFolderItem(payload).send();
+    return FolderEventMoveItem(payload).send();
   }
 
   Future<List<Tuple2<AppPB, List<ViewPB>>>> fetchViews(

+ 1 - 1
frontend/app_flowy/lib/workspace/application/workspace/workspace_service.dart

@@ -65,6 +65,6 @@ class WorkspaceService {
       ..to = toIndex
       ..ty = MoveFolderItemType.MoveApp;
 
-    return FolderEventMoveFolderItem(payload).send();
+    return FolderEventMoveItem(payload).send();
   }
 }

+ 1 - 1
frontend/app_flowy/test/bloc_test/board_test/group_by_checkbox_field_test.dart

@@ -33,7 +33,7 @@ void main() {
     final gridGroupBloc = GridGroupBloc(
       viewId: context.gridView.id,
       fieldController: context.fieldController,
-    );
+    )..add(const GridGroupEvent.initial());
     gridGroupBloc.add(GridGroupEvent.setGroupByField(
       checkboxField.id,
       checkboxField.fieldType,

+ 7 - 3
frontend/app_flowy/test/bloc_test/board_test/group_by_multi_select_field_test.dart

@@ -14,7 +14,7 @@ void main() {
     boardTest = await AppFlowyBoardTest.ensureInitialized();
   });
 
-  test('group by multi select with no options test', () async {
+  test('no status group name test', () async {
     final context = await boardTest.createTestBoard();
 
     // create multi-select field
@@ -27,7 +27,9 @@ void main() {
     final gridGroupBloc = GridGroupBloc(
       viewId: context.gridView.id,
       fieldController: context.fieldController,
-    );
+    )..add(const GridGroupEvent.initial());
+    await boardResponseFuture();
+
     gridGroupBloc.add(GridGroupEvent.setGroupByField(
       multiSelectField.id,
       multiSelectField.fieldType,
@@ -72,7 +74,9 @@ void main() {
     final gridGroupBloc = GridGroupBloc(
       viewId: context.gridView.id,
       fieldController: context.fieldController,
-    );
+    )..add(const GridGroupEvent.initial());
+    await boardResponseFuture();
+
     gridGroupBloc.add(GridGroupEvent.setGroupByField(
       multiSelectField.id,
       multiSelectField.fieldType,

+ 35 - 3
frontend/app_flowy/test/bloc_test/grid_test/cell/select_option_cell_test.dart

@@ -64,15 +64,24 @@ void main() {
 
       bloc.add(const SelectOptionEditorEvent.newOption("A"));
       await gridResponseFuture();
+      assert(bloc.state.options.length == 1,
+          "Expect 1 but receive ${bloc.state.options.length}, Options: ${bloc.state.options}");
+
       bloc.add(const SelectOptionEditorEvent.newOption("B"));
       await gridResponseFuture();
+      assert(bloc.state.options.length == 2,
+          "Expect 2 but receive ${bloc.state.options.length}, Options: ${bloc.state.options}");
+
       bloc.add(const SelectOptionEditorEvent.newOption("C"));
       await gridResponseFuture();
+      assert(bloc.state.options.length == 3,
+          "Expect 3 but receive ${bloc.state.options.length}. Options: ${bloc.state.options}");
 
       bloc.add(const SelectOptionEditorEvent.deleteAllOptions());
       await gridResponseFuture();
 
-      assert(bloc.state.options.isEmpty);
+      assert(bloc.state.options.isEmpty,
+          "Expect empty but receive ${bloc.state.options.length}");
     });
 
     test('select/unselect option', () async {
@@ -161,18 +170,41 @@ void main() {
 
       bloc.add(const SelectOptionEditorEvent.newOption("abcd"));
       await gridResponseFuture();
+      expect(
+        bloc.state.options.length,
+        1,
+        reason: "Options: ${bloc.state.options}",
+      );
 
       bloc.add(const SelectOptionEditorEvent.newOption("aaaa"));
       await gridResponseFuture();
+      expect(
+        bloc.state.options.length,
+        2,
+        reason: "Options: ${bloc.state.options}",
+      );
 
       bloc.add(const SelectOptionEditorEvent.newOption("defg"));
       await gridResponseFuture();
+      expect(
+        bloc.state.options.length,
+        3,
+        reason: "Options: ${bloc.state.options}",
+      );
 
       bloc.add(const SelectOptionEditorEvent.filterOption("a"));
       await gridResponseFuture();
 
-      expect(bloc.state.options.length, 2);
-      expect(bloc.state.allOptions.length, 3);
+      expect(
+        bloc.state.options.length,
+        2,
+        reason: "Options: ${bloc.state.options}",
+      );
+      expect(
+        bloc.state.allOptions.length,
+        3,
+        reason: "Options: ${bloc.state.options}",
+      );
       expect(bloc.state.createOption, const Some("a"));
       expect(bloc.state.filter, const Some("a"));
     });

+ 54 - 61
frontend/app_flowy/test/bloc_test/grid_test/field/edit_field_test.dart

@@ -1,6 +1,5 @@
 import 'package:app_flowy/plugins/grid/application/field/type_option/type_option_context.dart';
 import 'package:app_flowy/plugins/grid/application/prelude.dart';
-import 'package:bloc_test/bloc_test.dart';
 import 'package:appflowy_backend/protobuf/flowy-database/field_entities.pb.dart';
 import 'package:flutter_test/flutter_test.dart';
 import '../util.dart';
@@ -28,75 +27,69 @@ void main() {
     gridTest = await AppFlowyGridTest.ensureInitialized();
   });
 
-  group('$FieldEditorBloc', () {
-    late FieldEditorBloc editorBloc;
+  test('rename field', () async {
+    final editorBloc = await makeEditorBloc(gridTest);
+    editorBloc.add(const FieldEditorEvent.updateName('Hello world'));
+    await gridResponseFuture();
 
-    setUp(() async {
-      final context = await gridTest.createTestGrid();
-      final fieldInfo = context.singleSelectFieldContext();
-      final loader = FieldTypeOptionLoader(
-        databaseId: context.gridView.id,
-        field: fieldInfo.field,
-      );
+    editorBloc.state.field.fold(
+      () => throw Exception("The field should not be none"),
+      (field) {
+        assert(field.name == 'Hello world');
+      },
+    );
+  });
 
-      editorBloc = FieldEditorBloc(
-        databaseId: context.gridView.id,
-        fieldName: fieldInfo.name,
-        isGroupField: fieldInfo.isGroupField,
-        loader: loader,
-      )..add(const FieldEditorEvent.initial());
+  test('switch to text field', () async {
+    final editorBloc = await makeEditorBloc(gridTest);
 
-      await gridResponseFuture();
-    });
+    editorBloc.add(const FieldEditorEvent.switchToField(FieldType.RichText));
+    await gridResponseFuture();
 
-    blocTest<FieldEditorBloc, FieldEditorState>(
-      "rename field",
-      build: () => editorBloc,
-      act: (bloc) async {
-        editorBloc.add(const FieldEditorEvent.updateName('Hello world'));
-      },
-      wait: gridResponseDuration(),
-      verify: (bloc) {
-        bloc.state.field.fold(
-          () => throw Exception("The field should not be none"),
-          (field) {
-            assert(field.name == 'Hello world');
-          },
-        );
+    editorBloc.state.field.fold(
+      () => throw Exception("The field should not be none"),
+      (field) {
+        // The default length of the fields is 3. The length of the fields
+        // should not change after switching to other field type
+        // assert(gridTest.fieldContexts.length == 3);
+        assert(field.fieldType == FieldType.RichText);
       },
     );
+  });
 
-    blocTest<FieldEditorBloc, FieldEditorState>(
-      "switch to text field",
-      build: () => editorBloc,
-      act: (bloc) async {
-        editorBloc
-            .add(const FieldEditorEvent.switchToField(FieldType.RichText));
-      },
-      wait: gridResponseDuration(),
-      verify: (bloc) {
-        bloc.state.field.fold(
-          () => throw Exception("The field should not be none"),
-          (field) {
-            // The default length of the fields is 3. The length of the fields
-            // should not change after switching to other field type
-            // assert(gridTest.fieldContexts.length == 3);
-            assert(field.fieldType == FieldType.RichText);
-          },
-        );
-      },
-    );
+  test('delete field', () async {
+    final editorBloc = await makeEditorBloc(gridTest);
+    editorBloc.add(const FieldEditorEvent.switchToField(FieldType.RichText));
+    await gridResponseFuture();
 
-    blocTest<FieldEditorBloc, FieldEditorState>(
-      "delete field",
-      build: () => editorBloc,
-      act: (bloc) async {
-        editorBloc.add(const FieldEditorEvent.deleteField());
-      },
-      wait: gridResponseDuration(),
-      verify: (bloc) {
-        // assert(gridTest.fieldContexts.length == 2);
+    editorBloc.state.field.fold(
+      () => throw Exception("The field should not be none"),
+      (field) {
+        // The default length of the fields is 3. The length of the fields
+        // should not change after switching to other field type
+        // assert(gridTest.fieldContexts.length == 3);
+        assert(field.fieldType == FieldType.RichText);
       },
     );
   });
 }
+
+Future<FieldEditorBloc> makeEditorBloc(AppFlowyGridTest gridTest) async {
+  final context = await gridTest.createTestGrid();
+  final fieldInfo = context.singleSelectFieldContext();
+  final loader = FieldTypeOptionLoader(
+    databaseId: context.gridView.id,
+    field: fieldInfo.field,
+  );
+
+  final editorBloc = FieldEditorBloc(
+    databaseId: context.gridView.id,
+    fieldName: fieldInfo.name,
+    isGroupField: fieldInfo.isGroupField,
+    loader: loader,
+  )..add(const FieldEditorEvent.initial());
+
+  await gridResponseFuture();
+
+  return editorBloc;
+}

+ 1 - 1
frontend/app_flowy/test/bloc_test/grid_test/util.dart

@@ -210,7 +210,7 @@ class AppFlowyGridCellTest {
 
   Future<GridSelectOptionCellController> makeSelectOptionCellController(
       FieldType fieldType, int rowIndex) async {
-    return context.makeSelectOptionCellController(fieldType, rowIndex);
+    return await context.makeSelectOptionCellController(fieldType, rowIndex);
   }
 }
 

+ 2 - 2
frontend/app_flowy/test/bloc_test/home_test/view_bloc_test.dart

@@ -46,7 +46,7 @@ void main() {
     viewBloc.add(const ViewEvent.duplicate());
     await blocResponseFuture();
 
-    assert(appBloc.state.views.length == 2);
+    expect(appBloc.state.views.length, 2);
   });
 
   test('delete view test', () async {
@@ -59,7 +59,7 @@ void main() {
       DocumentPluginBuilder(),
     ));
     await blocResponseFuture();
-    assert(appBloc.state.views.length == 1);
+    expect(appBloc.state.views.length, 1);
 
     final viewBloc = ViewBloc(view: appBloc.state.views.first)
       ..add(const ViewEvent.initial());

+ 1 - 1
frontend/rust-lib/flowy-core/src/deps_resolve/folder_deps.rs

@@ -211,7 +211,7 @@ impl ViewDataProcessor for DocumentViewDataProcessor {
     }
 
     fn data_types(&self) -> Vec<ViewDataFormatPB> {
-        vec![ViewDataFormatPB::DeltaFormat, ViewDataFormatPB::TreeFormat]
+        vec![ViewDataFormatPB::DeltaFormat, ViewDataFormatPB::NodeFormat]
     }
 }
 

+ 1 - 1
frontend/rust-lib/flowy-core/src/lib.rs

@@ -297,7 +297,7 @@ impl UserStatusListener {
     async fn did_sign_up(&self, user_profile: &UserProfile) -> FlowyResult<()> {
         let view_data_type = match self.config.document.version {
             DocumentVersionPB::V0 => ViewDataFormatPB::DeltaFormat,
-            DocumentVersionPB::V1 => ViewDataFormatPB::TreeFormat,
+            DocumentVersionPB::V1 => ViewDataFormatPB::NodeFormat,
         };
         self.folder_manager
             .initialize_with_new_user(&user_profile.id, &user_profile.token, view_data_type)

+ 15 - 14
frontend/rust-lib/flowy-database/src/services/filter/controller.rs

@@ -5,6 +5,7 @@ use crate::services::field::*;
 use crate::services::filter::{FilterChangeset, FilterResult, FilterResultNotification, FilterType};
 use crate::services::row::DatabaseBlockRowRevision;
 use crate::services::view_editor::{GridViewChanged, GridViewChangedNotifier};
+use dashmap::DashMap;
 use flowy_error::FlowyResult;
 use flowy_task::{QualityOfService, Task, TaskContent, TaskDispatcher};
 use grid_model::{CellRevision, FieldId, FieldRevision, FilterRevision, RowRevision};
@@ -34,7 +35,7 @@ pub struct FilterController {
     view_id: String,
     handler_id: String,
     delegate: Box<dyn FilterDelegate>,
-    result_by_row_id: HashMap<RowId, FilterResult>,
+    result_by_row_id: DashMap<RowId, FilterResult>,
     cell_data_cache: AtomicCellDataCache,
     cell_filter_cache: AtomicCellFilterCache,
     task_scheduler: Arc<RwLock<TaskDispatcher>>,
@@ -54,11 +55,11 @@ impl FilterController {
     where
         T: FilterDelegate + 'static,
     {
-        let mut this = Self {
+        let this = Self {
             view_id: view_id.to_string(),
             handler_id: handler_id.to_string(),
             delegate: Box::new(delegate),
-            result_by_row_id: HashMap::default(),
+            result_by_row_id: DashMap::default(),
             cell_data_cache,
             cell_filter_cache: AnyTypeCache::<FilterType>::new(),
             task_scheduler,
@@ -83,7 +84,7 @@ impl FilterController {
         self.task_scheduler.write().await.add_task(task);
     }
 
-    pub async fn filter_row_revs(&mut self, row_revs: &mut Vec<Arc<RowRevision>>) {
+    pub async fn filter_row_revs(&self, row_revs: &mut Vec<Arc<RowRevision>>) {
         if self.cell_filter_cache.read().is_empty() {
             return;
         }
@@ -91,7 +92,7 @@ impl FilterController {
         row_revs.iter().for_each(|row_rev| {
             let _ = filter_row(
                 row_rev,
-                &mut self.result_by_row_id,
+                &self.result_by_row_id,
                 &field_rev_by_field_id,
                 &self.cell_data_cache,
                 &self.cell_filter_cache,
@@ -116,7 +117,7 @@ impl FilterController {
     }
 
     #[tracing::instrument(name = "process_filter_task", level = "trace", skip_all, fields(filter_result), err)]
-    pub async fn process(&mut self, predicate: &str) -> FlowyResult<()> {
+    pub async fn process(&self, predicate: &str) -> FlowyResult<()> {
         let event_type = FilterEvent::from_str(predicate).unwrap();
         match event_type {
             FilterEvent::FilterDidChanged => self.filter_all_rows().await?,
@@ -125,13 +126,13 @@ impl FilterController {
         Ok(())
     }
 
-    async fn filter_row(&mut self, row_id: String) -> FlowyResult<()> {
+    async fn filter_row(&self, row_id: String) -> FlowyResult<()> {
         if let Some((_, row_rev)) = self.delegate.get_row_rev(&row_id).await {
             let field_rev_by_field_id = self.get_filter_revs_map().await;
             let mut notification = FilterResultNotification::new(self.view_id.clone(), row_rev.block_id.clone());
             if let Some((row_id, is_visible)) = filter_row(
                 &row_rev,
-                &mut self.result_by_row_id,
+                &self.result_by_row_id,
                 &field_rev_by_field_id,
                 &self.cell_data_cache,
                 &self.cell_filter_cache,
@@ -153,7 +154,7 @@ impl FilterController {
         Ok(())
     }
 
-    async fn filter_all_rows(&mut self) -> FlowyResult<()> {
+    async fn filter_all_rows(&self) -> FlowyResult<()> {
         let field_rev_by_field_id = self.get_filter_revs_map().await;
         for block in self.delegate.get_blocks().await.into_iter() {
             // The row_ids contains the row that its visibility was changed.
@@ -163,7 +164,7 @@ impl FilterController {
             for (index, row_rev) in block.row_revs.iter().enumerate() {
                 if let Some((row_id, is_visible)) = filter_row(
                     row_rev,
-                    &mut self.result_by_row_id,
+                    &self.result_by_row_id,
                     &field_rev_by_field_id,
                     &self.cell_data_cache,
                     &self.cell_filter_cache,
@@ -198,7 +199,7 @@ impl FilterController {
     }
 
     #[tracing::instrument(level = "trace", skip(self))]
-    pub async fn did_receive_changes(&mut self, changeset: FilterChangeset) -> Option<FilterChangesetNotificationPB> {
+    pub async fn did_receive_changes(&self, changeset: FilterChangeset) -> Option<FilterChangesetNotificationPB> {
         let mut notification: Option<FilterChangesetNotificationPB> = None;
         if let Some(filter_type) = &changeset.insert_filter {
             if let Some(filter) = self.filter_from_filter_type(filter_type).await {
@@ -258,7 +259,7 @@ impl FilterController {
     }
 
     #[tracing::instrument(level = "trace", skip_all)]
-    async fn refresh_filters(&mut self, filter_revs: Vec<Arc<FilterRevision>>) {
+    async fn refresh_filters(&self, filter_revs: Vec<Arc<FilterRevision>>) {
         for filter_rev in filter_revs {
             if let Some(field_rev) = self.delegate.get_field_rev(&filter_rev.field_id).await {
                 let filter_type = FilterType::from(&field_rev);
@@ -309,13 +310,13 @@ impl FilterController {
 #[tracing::instrument(level = "trace", skip_all)]
 fn filter_row(
     row_rev: &Arc<RowRevision>,
-    result_by_row_id: &mut HashMap<RowId, FilterResult>,
+    result_by_row_id: &DashMap<RowId, FilterResult>,
     field_rev_by_field_id: &HashMap<FieldId, Arc<FieldRevision>>,
     cell_data_cache: &AtomicCellDataCache,
     cell_filter_cache: &AtomicCellFilterCache,
 ) -> Option<(String, bool)> {
     // Create a filter result cache if it's not exist
-    let filter_result = result_by_row_id
+    let mut filter_result = result_by_row_id
         .entry(row_rev.id.clone())
         .or_insert_with(FilterResult::default);
     let old_is_visible = filter_result.is_visible();

+ 2 - 5
frontend/rust-lib/flowy-database/src/services/filter/task.rs

@@ -3,15 +3,14 @@ use flowy_task::{TaskContent, TaskHandler};
 use lib_infra::future::BoxResultFuture;
 use std::collections::HashMap;
 use std::sync::Arc;
-use tokio::sync::RwLock;
 
 pub struct FilterTaskHandler {
     handler_id: String,
-    filter_controller: Arc<RwLock<FilterController>>,
+    filter_controller: Arc<FilterController>,
 }
 
 impl FilterTaskHandler {
-    pub fn new(handler_id: String, filter_controller: Arc<RwLock<FilterController>>) -> Self {
+    pub fn new(handler_id: String, filter_controller: Arc<FilterController>) -> Self {
         Self {
             handler_id,
             filter_controller,
@@ -33,8 +32,6 @@ impl TaskHandler for FilterTaskHandler {
         Box::pin(async move {
             if let TaskContent::Text(predicate) = content {
                 filter_controller
-                    .write()
-                    .await
                     .process(&predicate)
                     .await
                     .map_err(anyhow::Error::from)?;

+ 16 - 19
frontend/rust-lib/flowy-database/src/services/view_editor/editor.rs

@@ -74,7 +74,7 @@ pub struct DatabaseViewRevisionEditor {
     rev_manager: Arc<RevisionManager<Arc<ConnectionPool>>>,
     delegate: Arc<dyn DatabaseViewEditorDelegate>,
     group_controller: Arc<RwLock<Box<dyn GroupController>>>,
-    filter_controller: Arc<RwLock<FilterController>>,
+    filter_controller: Arc<FilterController>,
     sort_controller: Arc<RwLock<SortController>>,
     pub notifier: GridViewChangedNotifier,
 }
@@ -156,7 +156,7 @@ impl DatabaseViewRevisionEditor {
     pub async fn close(&self) {
         self.rev_manager.generate_snapshot().await;
         self.rev_manager.close().await;
-        self.filter_controller.read().await.close().await;
+        self.filter_controller.close().await;
         self.sort_controller.read().await.close().await;
     }
 
@@ -194,7 +194,7 @@ impl DatabaseViewRevisionEditor {
     }
 
     pub async fn filter_rows(&self, _block_id: &str, rows: &mut Vec<Arc<RowRevision>>) {
-        self.filter_controller.write().await.filter_row_revs(rows).await;
+        self.filter_controller.filter_row_revs(rows).await;
     }
 
     pub async fn duplicate_view_data(&self) -> FlowyResult<String> {
@@ -286,7 +286,7 @@ impl DatabaseViewRevisionEditor {
         let sort_controller = self.sort_controller.clone();
         let row_id = row_rev.id.clone();
         tokio::spawn(async move {
-            filter_controller.read().await.did_receive_row_changed(&row_id).await;
+            filter_controller.did_receive_row_changed(&row_id).await;
             sort_controller.read().await.did_receive_row_changed(&row_id).await;
         });
     }
@@ -514,7 +514,7 @@ impl DatabaseViewRevisionEditor {
             condition: params.condition,
             content: params.content,
         };
-        let mut filter_controller = self.filter_controller.write().await;
+        let filter_controller = self.filter_controller.clone();
         let changeset = if is_exist {
             let old_filter_type = self
                 .delegate
@@ -555,8 +555,6 @@ impl DatabaseViewRevisionEditor {
         let filter_type = params.filter_type;
         let changeset = self
             .filter_controller
-            .write()
-            .await
             .did_receive_changes(FilterChangeset::from_delete(filter_type.clone()))
             .await;
 
@@ -590,15 +588,14 @@ impl DatabaseViewRevisionEditor {
                 .did_update_view_field_type_option(&field_rev)
                 .await;
 
-            if let Some(changeset) = self
-                .filter_controller
-                .write()
-                .await
-                .did_receive_changes(filter_changeset)
-                .await
-            {
-                self.notify_did_update_filter(changeset).await;
-            }
+            let filter_controller = self.filter_controller.clone();
+            let _ = tokio::spawn(async move {
+                if let Some(notification) = filter_controller.did_receive_changes(filter_changeset).await {
+                    send_notification(&notification.view_id, DatabaseNotification::DidUpdateFilter)
+                        .payload(notification)
+                        .send();
+                }
+            });
         }
         Ok(())
     }
@@ -830,7 +827,7 @@ async fn make_filter_controller(
     notifier: GridViewChangedNotifier,
     cell_data_cache: AtomicCellDataCache,
     pad: Arc<RwLock<GridViewRevisionPad>>,
-) -> Arc<RwLock<FilterController>> {
+) -> Arc<FilterController> {
     let field_revs = delegate.get_field_revs(None).await;
     let filter_revs = pad.read().await.get_all_filters(&field_revs);
     let task_scheduler = delegate.get_task_scheduler();
@@ -849,7 +846,7 @@ async fn make_filter_controller(
         notifier,
     )
     .await;
-    let filter_controller = Arc::new(RwLock::new(filter_controller));
+    let filter_controller = Arc::new(filter_controller);
     task_scheduler
         .write()
         .await
@@ -861,7 +858,7 @@ async fn make_sort_controller(
     view_id: &str,
     delegate: Arc<dyn DatabaseViewEditorDelegate>,
     notifier: GridViewChangedNotifier,
-    filter_controller: Arc<RwLock<FilterController>>,
+    filter_controller: Arc<FilterController>,
     pad: Arc<RwLock<GridViewRevisionPad>>,
     cell_data_cache: AtomicCellDataCache,
 ) -> Arc<RwLock<SortController>> {

+ 2 - 2
frontend/rust-lib/flowy-database/src/services/view_editor/trait_impl.rs

@@ -185,7 +185,7 @@ impl FilterDelegate for GridViewFilterDelegateImpl {
 pub(crate) struct GridViewSortDelegateImpl {
     pub(crate) editor_delegate: Arc<dyn DatabaseViewEditorDelegate>,
     pub(crate) view_revision_pad: Arc<RwLock<GridViewRevisionPad>>,
-    pub(crate) filter_controller: Arc<RwLock<FilterController>>,
+    pub(crate) filter_controller: Arc<FilterController>,
 }
 
 impl SortDelegate for GridViewSortDelegateImpl {
@@ -209,7 +209,7 @@ impl SortDelegate for GridViewSortDelegateImpl {
         let editor_delegate = self.editor_delegate.clone();
         to_fut(async move {
             let mut row_revs = editor_delegate.get_row_revs(None).await;
-            filter_controller.write().await.filter_row_revs(&mut row_revs).await;
+            filter_controller.filter_row_revs(&mut row_revs).await;
             row_revs
         })
     }

+ 0 - 2
frontend/rust-lib/flowy-folder/src/entities/mod.rs

@@ -2,11 +2,9 @@ pub mod app;
 mod parser;
 pub mod trash;
 pub mod view;
-mod view_info;
 pub mod workspace;
 
 pub use app::*;
 pub use trash::*;
 pub use view::*;
-pub use view_info::*;
 pub use workspace::*;

+ 7 - 3
frontend/rust-lib/flowy-folder/src/entities/view.rs

@@ -50,9 +50,13 @@ impl std::convert::From<ViewRevision> for ViewPB {
 
 #[derive(Eq, PartialEq, Hash, Debug, ProtoBuf_Enum, Clone)]
 pub enum ViewDataFormatPB {
+    /// Indicate this view is using `Delta` for the persistence data format, it's deprecated.
     DeltaFormat = 0,
+    /// Indicate this view is using `Database` for the persistence data format. It is used in AppFlowy database
+    /// views including Grid,Board, and Calendar.
     DatabaseFormat = 1,
-    TreeFormat = 2,
+    /// Indicate this view is using `Node` for the persistence data format. It is used in AppFlowy document
+    NodeFormat = 2,
 }
 
 impl std::default::Default for ViewDataFormatPB {
@@ -66,7 +70,7 @@ impl std::convert::From<ViewDataFormatRevision> for ViewDataFormatPB {
         match rev {
             ViewDataFormatRevision::DeltaFormat => ViewDataFormatPB::DeltaFormat,
             ViewDataFormatRevision::DatabaseFormat => ViewDataFormatPB::DatabaseFormat,
-            ViewDataFormatRevision::TreeFormat => ViewDataFormatPB::TreeFormat,
+            ViewDataFormatRevision::NodeFormat => ViewDataFormatPB::NodeFormat,
         }
     }
 }
@@ -76,7 +80,7 @@ impl std::convert::From<ViewDataFormatPB> for ViewDataFormatRevision {
         match ty {
             ViewDataFormatPB::DeltaFormat => ViewDataFormatRevision::DeltaFormat,
             ViewDataFormatPB::DatabaseFormat => ViewDataFormatRevision::DatabaseFormat,
-            ViewDataFormatPB::TreeFormat => ViewDataFormatRevision::TreeFormat,
+            ViewDataFormatPB::NodeFormat => ViewDataFormatRevision::NodeFormat,
         }
     }
 }

+ 0 - 26
frontend/rust-lib/flowy-folder/src/entities/view_info.rs

@@ -1,26 +0,0 @@
-use crate::entities::{RepeatedViewPB, ViewDataFormatPB};
-use flowy_derive::ProtoBuf;
-
-#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
-pub struct ViewInfoPB {
-    #[pb(index = 1)]
-    pub id: String,
-
-    #[pb(index = 2)]
-    pub belong_to_id: String,
-
-    #[pb(index = 3)]
-    pub name: String,
-
-    #[pb(index = 4)]
-    pub desc: String,
-
-    #[pb(index = 5)]
-    pub data_type: ViewDataFormatPB,
-
-    #[pb(index = 6)]
-    pub belongings: RepeatedViewPB,
-
-    #[pb(index = 7)]
-    pub ext_data: String,
-}

+ 26 - 6
frontend/rust-lib/flowy-folder/src/event_map.rs

@@ -63,12 +63,11 @@ pub fn init(folder: Arc<FolderManager>) -> AFPlugin {
         .event(FolderEvent::CreateView, create_view_handler)
         .event(FolderEvent::ReadView, read_view_handler)
         .event(FolderEvent::UpdateView, update_view_handler)
-        .event(FolderEvent::ReadViewInfo, read_view_info_handler)
         .event(FolderEvent::DeleteView, delete_view_handler)
         .event(FolderEvent::DuplicateView, duplicate_view_handler)
         .event(FolderEvent::SetLatestView, set_latest_view_handler)
         .event(FolderEvent::CloseView, close_view_handler)
-        .event(FolderEvent::MoveFolderItem, move_item_handler);
+        .event(FolderEvent::MoveItem, move_item_handler);
 
     // Trash
     plugin = plugin
@@ -84,78 +83,99 @@ pub fn init(folder: Arc<FolderManager>) -> AFPlugin {
 #[derive(Clone, Copy, PartialEq, Eq, Debug, Display, Hash, ProtoBuf_Enum, Flowy_Event)]
 #[event_err = "FlowyError"]
 pub enum FolderEvent {
+    /// Create a new workspace
     #[event(input = "CreateWorkspacePayloadPB", output = "WorkspacePB")]
     CreateWorkspace = 0,
 
+    /// Read the current opening workspace
     #[event(output = "WorkspaceSettingPB")]
     ReadCurrentWorkspace = 1,
 
+    /// Open the workspace and mark it as the current workspace
     #[event(input = "WorkspaceIdPB", output = "RepeatedWorkspacePB")]
     ReadWorkspaces = 2,
 
+    /// Delete the workspace
     #[event(input = "WorkspaceIdPB")]
     DeleteWorkspace = 3,
 
+    /// Open the workspace and mark it as the current workspace
     #[event(input = "WorkspaceIdPB", output = "WorkspacePB")]
     OpenWorkspace = 4,
 
+    /// Return a list of apps that belong to this workspace
     #[event(input = "WorkspaceIdPB", output = "RepeatedAppPB")]
     ReadWorkspaceApps = 5,
 
+    /// Create a new app
     #[event(input = "CreateAppPayloadPB", output = "AppPB")]
     CreateApp = 101,
 
+    /// Delete the app
     #[event(input = "AppIdPB")]
     DeleteApp = 102,
 
+    /// Read the app
     #[event(input = "AppIdPB", output = "AppPB")]
     ReadApp = 103,
 
+    /// Update the app's properties including the name,description, etc.
     #[event(input = "UpdateAppPayloadPB")]
     UpdateApp = 104,
 
+    /// Create a new view in the corresponding app
     #[event(input = "CreateViewPayloadPB", output = "ViewPB")]
     CreateView = 201,
 
+    /// Return the view info
     #[event(input = "ViewIdPB", output = "ViewPB")]
     ReadView = 202,
 
+    /// Update the view's properties including the name,description, etc.
     #[event(input = "UpdateViewPayloadPB", output = "ViewPB")]
     UpdateView = 203,
 
+    /// Move the view to the trash folder
     #[event(input = "RepeatedViewIdPB")]
     DeleteView = 204,
 
+    /// Duplicate the view
     #[event(input = "ViewPB")]
     DuplicateView = 205,
 
+    /// Close and release the resources that are used by this view.
+    /// It should get called when the 'View' page get destroy
     #[event(input = "ViewIdPB")]
     CloseView = 206,
 
-    #[event(input = "ViewIdPB", output = "ViewInfoPB")]
-    ReadViewInfo = 207,
-
     #[event()]
     CopyLink = 220,
 
+    /// Set the current visiting view
     #[event(input = "ViewIdPB")]
     SetLatestView = 221,
 
+    /// Move the view or app to another place
     #[event(input = "MoveFolderItemPayloadPB")]
-    MoveFolderItem = 230,
+    MoveItem = 230,
 
+    /// Read the trash that was deleted by the user
     #[event(output = "RepeatedTrashPB")]
     ReadTrash = 300,
 
+    /// Put back the trash to the origin folder
     #[event(input = "TrashIdPB")]
     PutbackTrash = 301,
 
+    /// Delete the trash from the disk
     #[event(input = "RepeatedTrashIdPB")]
     DeleteTrash = 302,
 
+    /// Put back all the trash to its original folder
     #[event()]
     RestoreAllTrash = 303,
 
+    /// Delete all the trash from the disk
     #[event()]
     DeleteAllTrash = 304,
 }

+ 2 - 2
frontend/rust-lib/flowy-folder/src/services/persistence/version_1/view_sql.rs

@@ -89,7 +89,7 @@ impl ViewTable {
         let data_type = match view_rev.data_format {
             ViewDataFormatRevision::DeltaFormat => SqlViewDataFormat::Delta,
             ViewDataFormatRevision::DatabaseFormat => SqlViewDataFormat::Database,
-            ViewDataFormatRevision::TreeFormat => SqlViewDataFormat::Tree,
+            ViewDataFormatRevision::NodeFormat => SqlViewDataFormat::Tree,
         };
 
         ViewTable {
@@ -113,7 +113,7 @@ impl std::convert::From<ViewTable> for ViewRevision {
         let data_type = match table.view_type {
             SqlViewDataFormat::Delta => ViewDataFormatRevision::DeltaFormat,
             SqlViewDataFormat::Database => ViewDataFormatRevision::DatabaseFormat,
-            SqlViewDataFormat::Tree => ViewDataFormatRevision::TreeFormat,
+            SqlViewDataFormat::Tree => ViewDataFormatRevision::NodeFormat,
         };
 
         ViewRevision {

+ 2 - 31
frontend/rust-lib/flowy-folder/src/services/view/controller.rs

@@ -1,10 +1,10 @@
 pub use crate::entities::view::ViewDataFormatPB;
-use crate::entities::{AppPB, DeletedViewPB, ViewInfoPB, ViewLayoutTypePB};
+use crate::entities::{AppPB, DeletedViewPB, ViewLayoutTypePB};
 use crate::manager::{ViewDataProcessor, ViewDataProcessorMap};
 use crate::{
     entities::{
         trash::{RepeatedTrashIdPB, TrashType},
-        view::{CreateViewParams, RepeatedViewPB, UpdateViewParams, ViewIdPB, ViewPB},
+        view::{CreateViewParams, UpdateViewParams, ViewIdPB, ViewPB},
     },
     errors::{FlowyError, FlowyResult},
     event_map::{FolderCouldServiceV1, WorkspaceUser},
@@ -139,35 +139,6 @@ impl ViewController {
         Ok(view_rev)
     }
 
-    #[tracing::instrument(level = "debug", skip(self, view_id), fields(view_id = %view_id.value), err)]
-    pub(crate) async fn read_view_pb(&self, view_id: ViewIdPB) -> Result<ViewInfoPB, FlowyError> {
-        let view_info = self
-            .persistence
-            .begin_transaction(|transaction| {
-                let view_rev = transaction.read_view(&view_id.value)?;
-
-                let items: Vec<ViewPB> = view_rev
-                    .belongings
-                    .into_iter()
-                    .map(|view_rev| view_rev.into())
-                    .collect();
-
-                let view_info = ViewInfoPB {
-                    id: view_rev.id,
-                    belong_to_id: view_rev.app_id,
-                    name: view_rev.name,
-                    desc: view_rev.desc,
-                    data_type: view_rev.data_format.into(),
-                    belongings: RepeatedViewPB { items },
-                    ext_data: view_rev.ext_data,
-                };
-                Ok(view_info)
-            })
-            .await?;
-
-        Ok(view_info)
-    }
-
     pub(crate) async fn read_local_views(&self, ids: Vec<String>) -> Result<Vec<ViewRevision>, FlowyError> {
         self.persistence
             .begin_transaction(|transaction| {

+ 0 - 10
frontend/rust-lib/flowy-folder/src/services/view/event_handler.rs

@@ -1,5 +1,4 @@
 use crate::entities::view::{MoveFolderItemParams, MoveFolderItemPayloadPB, MoveFolderItemType};
-use crate::entities::ViewInfoPB;
 use crate::manager::FolderManager;
 use crate::services::{notify_workspace_setting_did_change, AppController};
 use crate::{
@@ -35,15 +34,6 @@ pub(crate) async fn read_view_handler(
     data_result(view_rev.into())
 }
 
-pub(crate) async fn read_view_info_handler(
-    data: AFPluginData<ViewIdPB>,
-    controller: AFPluginState<Arc<ViewController>>,
-) -> DataResult<ViewInfoPB, FlowyError> {
-    let view_id: ViewIdPB = data.into_inner();
-    let view_info = controller.read_view_pb(view_id.clone()).await?;
-    data_result(view_info)
-}
-
 #[tracing::instrument(level = "debug", skip(data, controller), err)]
 pub(crate) async fn update_view_handler(
     data: AFPluginData<UpdateViewPayloadPB>,

+ 1 - 1
frontend/rust-lib/flowy-folder/tests/workspace/script.rs

@@ -182,7 +182,7 @@ impl FolderTest {
             FolderScript::CreateView { name, desc, data_type } => {
                 let layout = match data_type {
                     ViewDataFormatPB::DeltaFormat => ViewLayoutTypePB::Document,
-                    ViewDataFormatPB::TreeFormat => ViewLayoutTypePB::Document,
+                    ViewDataFormatPB::NodeFormat => ViewLayoutTypePB::Document,
                     ViewDataFormatPB::DatabaseFormat => ViewLayoutTypePB::Grid,
                 };
                 let view = create_view(sdk, &self.app.id, &name, &desc, data_type, layout).await;

+ 1 - 1
frontend/rust-lib/flowy-test/src/helper.rs

@@ -58,7 +58,7 @@ impl ViewTest {
     pub async fn new_document_view(sdk: &FlowySDKTest) -> Self {
         let view_data_format = match sdk.document_version() {
             DocumentVersionPB::V0 => ViewDataFormatPB::DeltaFormat,
-            DocumentVersionPB::V1 => ViewDataFormatPB::TreeFormat,
+            DocumentVersionPB::V1 => ViewDataFormatPB::NodeFormat,
         };
         Self::new(sdk, view_data_format, ViewLayoutTypePB::Document, vec![]).await
     }

+ 1 - 1
shared-lib/folder-model/src/view_rev.rs

@@ -59,7 +59,7 @@ impl std::convert::From<ViewRevision> for TrashRevision {
 pub enum ViewDataFormatRevision {
     DeltaFormat = 0,
     DatabaseFormat = 1,
-    TreeFormat = 2,
+    NodeFormat = 2,
 }
 
 impl std::default::Default for ViewDataFormatRevision {