瀏覽代碼

feat: config grid filter in backend & add tests

* chore: add search crate

* chore: add task order test

* chore: enable timeout

* add task crate

* chore: run filter task

* chore: run filter task

* chore: filter rows

* chore: cache filter result

* chore: filter rows when open a grid

* chore: add tests

* test: add number filter test

* test: add checkbox fitler test

* chore: fix test

Co-authored-by: nathan <[email protected]>
Nathan.fooo 2 年之前
父節點
當前提交
a0a16cc493
共有 83 個文件被更改,包括 2267 次插入1609 次删除
  1. 16 0
      frontend/rust-lib/Cargo.lock
  2. 1 0
      frontend/rust-lib/Cargo.toml
  3. 2 2
      frontend/rust-lib/dart-ffi/src/lib.rs
  4. 2 0
      frontend/rust-lib/flowy-error/src/errors.rs
  5. 2 0
      frontend/rust-lib/flowy-grid/Cargo.toml
  6. 1 0
      frontend/rust-lib/flowy-grid/src/entities/field_entities.rs
  7. 16 16
      frontend/rust-lib/flowy-grid/src/entities/filter_entities/checkbox_filter.rs
  8. 11 10
      frontend/rust-lib/flowy-grid/src/entities/filter_entities/date_filter.rs
  9. 9 9
      frontend/rust-lib/flowy-grid/src/entities/filter_entities/number_filter.rs
  10. 7 7
      frontend/rust-lib/flowy-grid/src/entities/filter_entities/select_option_filter.rs
  11. 9 9
      frontend/rust-lib/flowy-grid/src/entities/filter_entities/text_filter.rs
  12. 33 30
      frontend/rust-lib/flowy-grid/src/entities/filter_entities/util.rs
  13. 3 3
      frontend/rust-lib/flowy-grid/src/entities/mod.rs
  14. 4 4
      frontend/rust-lib/flowy-grid/src/entities/setting_entities.rs
  15. 5 5
      frontend/rust-lib/flowy-grid/src/event_handler.rs
  16. 5 7
      frontend/rust-lib/flowy-grid/src/manager.rs
  17. 2 2
      frontend/rust-lib/flowy-grid/src/services/block_editor.rs
  18. 8 11
      frontend/rust-lib/flowy-grid/src/services/block_manager.rs
  19. 0 37
      frontend/rust-lib/flowy-grid/src/services/block_manager_trait_impl.rs
  20. 11 11
      frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_filter.rs
  21. 1 0
      frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/mod.rs
  22. 10 10
      frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_filter.rs
  23. 1 0
      frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/mod.rs
  24. 1 0
      frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/mod.rs
  25. 36 30
      frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_filter.rs
  26. 1 0
      frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/mod.rs
  27. 8 16
      frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/select_filter.rs
  28. 1 0
      frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option/mod.rs
  29. 26 30
      frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option/text_filter.rs
  30. 1 0
      frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/mod.rs
  31. 3 3
      frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_filter.rs
  32. 94 0
      frontend/rust-lib/flowy-grid/src/services/filter/cache.rs
  33. 405 0
      frontend/rust-lib/flowy-grid/src/services/filter/controller.rs
  34. 0 171
      frontend/rust-lib/flowy-grid/src/services/filter/filter_cache.rs
  35. 0 294
      frontend/rust-lib/flowy-grid/src/services/filter/filter_service.rs
  36. 0 13
      frontend/rust-lib/flowy-grid/src/services/filter/impls/mod.rs
  37. 6 4
      frontend/rust-lib/flowy-grid/src/services/filter/mod.rs
  38. 35 0
      frontend/rust-lib/flowy-grid/src/services/filter/task.rs
  39. 71 80
      frontend/rust-lib/flowy-grid/src/services/grid_editor.rs
  40. 0 42
      frontend/rust-lib/flowy-grid/src/services/grid_editor_task.rs
  41. 57 15
      frontend/rust-lib/flowy-grid/src/services/grid_editor_trait_impl.rs
  42. 183 112
      frontend/rust-lib/flowy-grid/src/services/grid_view_editor.rs
  43. 41 66
      frontend/rust-lib/flowy-grid/src/services/grid_view_manager.rs
  44. 1 1
      frontend/rust-lib/flowy-grid/src/services/group/action.rs
  45. 3 3
      frontend/rust-lib/flowy-grid/src/services/group/configuration.rs
  46. 2 2
      frontend/rust-lib/flowy-grid/src/services/group/controller.rs
  47. 2 2
      frontend/rust-lib/flowy-grid/src/services/group/controller_impls/default_controller.rs
  48. 1 5
      frontend/rust-lib/flowy-grid/src/services/mod.rs
  49. 12 35
      frontend/rust-lib/flowy-grid/src/services/row/row_loader.rs
  50. 2 2
      frontend/rust-lib/flowy-grid/src/services/setting/setting_builder.rs
  51. 0 3
      frontend/rust-lib/flowy-grid/src/services/snapshot/mod.rs
  52. 0 7
      frontend/rust-lib/flowy-grid/src/services/snapshot/snapshot_service.rs
  53. 0 47
      frontend/rust-lib/flowy-grid/src/services/tasks/runner.rs
  54. 0 199
      frontend/rust-lib/flowy-grid/src/services/tasks/scheduler.rs
  55. 0 129
      frontend/rust-lib/flowy-grid/src/services/tasks/task.rs
  56. 27 0
      frontend/rust-lib/flowy-grid/tests/grid/filter_test/checkbox_filter_test.rs
  57. 17 0
      frontend/rust-lib/flowy-grid/tests/grid/filter_test/date_filter_test.rs
  58. 3 0
      frontend/rust-lib/flowy-grid/tests/grid/filter_test/mod.rs
  59. 82 0
      frontend/rust-lib/flowy-grid/tests/grid/filter_test/number_filter_test.rs
  60. 80 15
      frontend/rust-lib/flowy-grid/tests/grid/filter_test/script.rs
  61. 67 24
      frontend/rust-lib/flowy-grid/tests/grid/filter_test/text_filter_test.rs
  62. 8 13
      frontend/rust-lib/flowy-grid/tests/grid/grid_editor.rs
  63. 1 0
      frontend/rust-lib/flowy-sdk/Cargo.toml
  64. 8 1
      frontend/rust-lib/flowy-sdk/src/deps_resolve/grid_deps.rs
  65. 19 10
      frontend/rust-lib/flowy-sdk/src/lib.rs
  66. 3 9
      frontend/rust-lib/flowy-sdk/src/module.rs
  67. 17 0
      frontend/rust-lib/flowy-task/Cargo.toml
  68. 0 1
      frontend/rust-lib/flowy-task/src/lib.rs
  69. 5 11
      frontend/rust-lib/flowy-task/src/queue.rs
  70. 187 0
      frontend/rust-lib/flowy-task/src/scheduler.rs
  71. 12 6
      frontend/rust-lib/flowy-task/src/store.rs
  72. 142 0
      frontend/rust-lib/flowy-task/src/task.rs
  73. 1 0
      frontend/rust-lib/flowy-task/tests/main.rs
  74. 3 0
      frontend/rust-lib/flowy-task/tests/task_test/mod.rs
  75. 196 0
      frontend/rust-lib/flowy-task/tests/task_test/script.rs
  76. 88 0
      frontend/rust-lib/flowy-task/tests/task_test/task_cancel_test.rs
  77. 111 0
      frontend/rust-lib/flowy-task/tests/task_test/task_order_test.rs
  78. 8 8
      shared-lib/flowy-sync/src/client_grid/grid_revision_pad.rs
  79. 18 15
      shared-lib/flowy-sync/src/client_grid/view_revision_pad.rs
  80. 3 2
      shared-lib/grid-rev-model/src/filter_rev.rs
  81. 5 5
      shared-lib/grid-rev-model/src/grid_setting_rev.rs
  82. 4 4
      shared-lib/lib-infra/src/future.rs
  83. 1 1
      shared-lib/lib-infra/src/ref_map.rs

+ 16 - 0
frontend/rust-lib/Cargo.lock

@@ -955,6 +955,7 @@ dependencies = [
 name = "flowy-grid"
 name = "flowy-grid"
 version = "0.1.0"
 version = "0.1.0"
 dependencies = [
 dependencies = [
+ "anyhow",
  "atomic_refcell",
  "atomic_refcell",
  "bytes",
  "bytes",
  "chrono",
  "chrono",
@@ -970,6 +971,7 @@ dependencies = [
  "flowy-http-model",
  "flowy-http-model",
  "flowy-revision",
  "flowy-revision",
  "flowy-sync",
  "flowy-sync",
+ "flowy-task",
  "flowy-test",
  "flowy-test",
  "futures",
  "futures",
  "grid-rev-model",
  "grid-rev-model",
@@ -1078,6 +1080,7 @@ dependencies = [
  "flowy-http-model",
  "flowy-http-model",
  "flowy-net",
  "flowy-net",
  "flowy-revision",
  "flowy-revision",
+ "flowy-task",
  "flowy-user",
  "flowy-user",
  "futures-core",
  "futures-core",
  "grid-rev-model",
  "grid-rev-model",
@@ -1118,6 +1121,19 @@ dependencies = [
  "url",
  "url",
 ]
 ]
 
 
+[[package]]
+name = "flowy-task"
+version = "0.1.0"
+dependencies = [
+ "anyhow",
+ "atomic_refcell",
+ "futures",
+ "lib-infra",
+ "rand 0.8.5",
+ "tokio",
+ "tracing",
+]
+
 [[package]]
 [[package]]
 name = "flowy-test"
 name = "flowy-test"
 version = "0.1.0"
 version = "0.1.0"

+ 1 - 0
frontend/rust-lib/Cargo.toml

@@ -15,6 +15,7 @@ members = [
   "flowy-error",
   "flowy-error",
   "flowy-revision",
   "flowy-revision",
   "flowy-grid",
   "flowy-grid",
+  "flowy-task",
 ]
 ]
 
 
 [profile.dev]
 [profile.dev]

+ 2 - 2
frontend/rust-lib/dart-ffi/src/lib.rs

@@ -44,7 +44,7 @@ pub extern "C" fn async_event(port: i64, input: *const u8, len: usize) {
             log::error!("sdk not init yet.");
             log::error!("sdk not init yet.");
             return;
             return;
         }
         }
-        Some(e) => e.dispatcher.clone(),
+        Some(e) => e.event_dispatcher.clone(),
     };
     };
     let _ = EventDispatcher::async_send_with_callback(dispatcher, request, move |resp: EventResponse| {
     let _ = EventDispatcher::async_send_with_callback(dispatcher, request, move |resp: EventResponse| {
         log::trace!("[FFI]: Post data to dart through {} port", port);
         log::trace!("[FFI]: Post data to dart through {} port", port);
@@ -62,7 +62,7 @@ pub extern "C" fn sync_event(input: *const u8, len: usize) -> *const u8 {
             log::error!("sdk not init yet.");
             log::error!("sdk not init yet.");
             return forget_rust(Vec::default());
             return forget_rust(Vec::default());
         }
         }
-        Some(e) => e.dispatcher.clone(),
+        Some(e) => e.event_dispatcher.clone(),
     };
     };
     let _response = EventDispatcher::sync_send(dispatcher, request);
     let _response = EventDispatcher::sync_send(dispatcher, request);
 
 

+ 2 - 0
frontend/rust-lib/flowy-error/src/errors.rs

@@ -112,3 +112,5 @@ impl std::convert::From<protobuf::ProtobufError> for FlowyError {
         FlowyError::internal().context(e)
         FlowyError::internal().context(e)
     }
     }
 }
 }
+
+impl std::error::Error for FlowyError {}

+ 2 - 0
frontend/rust-lib/flowy-grid/Cargo.toml

@@ -9,6 +9,7 @@ edition = "2021"
 lib-dispatch = { path = "../lib-dispatch" }
 lib-dispatch = { path = "../lib-dispatch" }
 dart-notify = { path = "../dart-notify" }
 dart-notify = { path = "../dart-notify" }
 flowy-revision = { path = "../flowy-revision" }
 flowy-revision = { path = "../flowy-revision" }
+flowy-task= { path = "../flowy-task" }
 flowy-error = { path = "../flowy-error", features = ["db"]}
 flowy-error = { path = "../flowy-error", features = ["db"]}
 flowy-derive = { path = "../../../shared-lib/flowy-derive" }
 flowy-derive = { path = "../../../shared-lib/flowy-derive" }
 lib-ot = { path = "../../../shared-lib/lib-ot" }
 lib-ot = { path = "../../../shared-lib/lib-ot" }
@@ -17,6 +18,7 @@ grid-rev-model = { path = "../../../shared-lib/grid-rev-model" }
 flowy-sync = { path = "../../../shared-lib/flowy-sync" }
 flowy-sync = { path = "../../../shared-lib/flowy-sync" }
 flowy-http-model = { path = "../../../shared-lib/flowy-http-model" }
 flowy-http-model = { path = "../../../shared-lib/flowy-http-model" }
 flowy-database = { path = "../flowy-database" }
 flowy-database = { path = "../flowy-database" }
+anyhow = "1.0"
 
 
 strum = "0.21"
 strum = "0.21"
 strum_macros = "0.21"
 strum_macros = "0.21"

+ 1 - 0
frontend/rust-lib/flowy-grid/src/entities/field_entities.rs

@@ -591,6 +591,7 @@ impl std::convert::From<&FieldTypeRevision> for FieldType {
         FieldType::from(*ty)
         FieldType::from(*ty)
     }
     }
 }
 }
+
 impl std::convert::From<FieldTypeRevision> for FieldType {
 impl std::convert::From<FieldTypeRevision> for FieldType {
     fn from(ty: FieldTypeRevision) -> Self {
     fn from(ty: FieldTypeRevision) -> Self {
         match ty {
         match ty {

+ 16 - 16
frontend/rust-lib/flowy-grid/src/entities/filter_entities/checkbox_filter.rs

@@ -1,49 +1,49 @@
 use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
 use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
 use flowy_error::ErrorCode;
 use flowy_error::ErrorCode;
-use grid_rev_model::FilterConfigurationRevision;
+use grid_rev_model::FilterRevision;
 use std::sync::Arc;
 use std::sync::Arc;
 
 
 #[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
 #[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
-pub struct CheckboxFilterConfigurationPB {
+pub struct CheckboxFilterPB {
     #[pb(index = 1)]
     #[pb(index = 1)]
-    pub condition: CheckboxCondition,
+    pub condition: CheckboxFilterCondition,
 }
 }
 
 
 #[derive(Debug, Clone, PartialEq, Eq, ProtoBuf_Enum)]
 #[derive(Debug, Clone, PartialEq, Eq, ProtoBuf_Enum)]
 #[repr(u8)]
 #[repr(u8)]
-pub enum CheckboxCondition {
+pub enum CheckboxFilterCondition {
     IsChecked = 0,
     IsChecked = 0,
     IsUnChecked = 1,
     IsUnChecked = 1,
 }
 }
 
 
-impl std::convert::From<CheckboxCondition> for i32 {
-    fn from(value: CheckboxCondition) -> Self {
-        value as i32
+impl std::convert::From<CheckboxFilterCondition> for u32 {
+    fn from(value: CheckboxFilterCondition) -> Self {
+        value as u32
     }
     }
 }
 }
 
 
-impl std::default::Default for CheckboxCondition {
+impl std::default::Default for CheckboxFilterCondition {
     fn default() -> Self {
     fn default() -> Self {
-        CheckboxCondition::IsChecked
+        CheckboxFilterCondition::IsChecked
     }
     }
 }
 }
 
 
-impl std::convert::TryFrom<u8> for CheckboxCondition {
+impl std::convert::TryFrom<u8> for CheckboxFilterCondition {
     type Error = ErrorCode;
     type Error = ErrorCode;
 
 
     fn try_from(value: u8) -> Result<Self, Self::Error> {
     fn try_from(value: u8) -> Result<Self, Self::Error> {
         match value {
         match value {
-            0 => Ok(CheckboxCondition::IsChecked),
-            1 => Ok(CheckboxCondition::IsUnChecked),
+            0 => Ok(CheckboxFilterCondition::IsChecked),
+            1 => Ok(CheckboxFilterCondition::IsUnChecked),
             _ => Err(ErrorCode::InvalidData),
             _ => Err(ErrorCode::InvalidData),
         }
         }
     }
     }
 }
 }
 
 
-impl std::convert::From<Arc<FilterConfigurationRevision>> for CheckboxFilterConfigurationPB {
-    fn from(rev: Arc<FilterConfigurationRevision>) -> Self {
-        CheckboxFilterConfigurationPB {
-            condition: CheckboxCondition::try_from(rev.condition).unwrap_or(CheckboxCondition::IsChecked),
+impl std::convert::From<Arc<FilterRevision>> for CheckboxFilterPB {
+    fn from(rev: Arc<FilterRevision>) -> Self {
+        CheckboxFilterPB {
+            condition: CheckboxFilterCondition::try_from(rev.condition).unwrap_or(CheckboxFilterCondition::IsChecked),
         }
         }
     }
     }
 }
 }

+ 11 - 10
frontend/rust-lib/flowy-grid/src/entities/filter_entities/date_filter.rs

@@ -2,13 +2,13 @@ use crate::entities::parser::NotEmptyStr;
 use crate::entities::FieldType;
 use crate::entities::FieldType;
 use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
 use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
 use flowy_error::ErrorCode;
 use flowy_error::ErrorCode;
-use grid_rev_model::FilterConfigurationRevision;
+use grid_rev_model::FilterRevision;
 use serde::{Deserialize, Serialize};
 use serde::{Deserialize, Serialize};
 use std::str::FromStr;
 use std::str::FromStr;
 use std::sync::Arc;
 use std::sync::Arc;
 
 
 #[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
 #[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
-pub struct DateFilterConfigurationPB {
+pub struct DateFilterPB {
     #[pb(index = 1)]
     #[pb(index = 1)]
     pub condition: DateFilterCondition,
     pub condition: DateFilterCondition,
 
 
@@ -98,6 +98,11 @@ pub enum DateFilterCondition {
     DateIsEmpty = 6,
     DateIsEmpty = 6,
 }
 }
 
 
+impl std::convert::From<DateFilterCondition> for u32 {
+    fn from(value: DateFilterCondition) -> Self {
+        value as u32
+    }
+}
 impl std::default::Default for DateFilterCondition {
 impl std::default::Default for DateFilterCondition {
     fn default() -> Self {
     fn default() -> Self {
         DateFilterCondition::DateIs
         DateFilterCondition::DateIs
@@ -120,19 +125,15 @@ impl std::convert::TryFrom<u8> for DateFilterCondition {
         }
         }
     }
     }
 }
 }
-impl std::convert::From<Arc<FilterConfigurationRevision>> for DateFilterConfigurationPB {
-    fn from(rev: Arc<FilterConfigurationRevision>) -> Self {
+impl std::convert::From<Arc<FilterRevision>> for DateFilterPB {
+    fn from(rev: Arc<FilterRevision>) -> Self {
         let condition = DateFilterCondition::try_from(rev.condition).unwrap_or(DateFilterCondition::DateIs);
         let condition = DateFilterCondition::try_from(rev.condition).unwrap_or(DateFilterCondition::DateIs);
-        let mut filter = DateFilterConfigurationPB {
+        let mut filter = DateFilterPB {
             condition,
             condition,
             ..Default::default()
             ..Default::default()
         };
         };
 
 
-        if let Some(range) = rev
-            .content
-            .as_ref()
-            .and_then(|content| DateRange::from_str(content).ok())
-        {
+        if let Ok(range) = DateRange::from_str(&rev.content) {
             filter.start = range.start;
             filter.start = range.start;
             filter.end = range.end;
             filter.end = range.end;
         };
         };

+ 9 - 9
frontend/rust-lib/flowy-grid/src/entities/filter_entities/number_filter.rs

@@ -1,16 +1,16 @@
 use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
 use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
 use flowy_error::ErrorCode;
 use flowy_error::ErrorCode;
-use grid_rev_model::FilterConfigurationRevision;
+use grid_rev_model::FilterRevision;
 
 
 use std::sync::Arc;
 use std::sync::Arc;
 
 
 #[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
 #[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
-pub struct NumberFilterConfigurationPB {
+pub struct NumberFilterPB {
     #[pb(index = 1)]
     #[pb(index = 1)]
     pub condition: NumberFilterCondition,
     pub condition: NumberFilterCondition,
 
 
-    #[pb(index = 2, one_of)]
-    pub content: Option<String>,
+    #[pb(index = 2)]
+    pub content: String,
 }
 }
 
 
 #[derive(Debug, Clone, PartialEq, Eq, ProtoBuf_Enum)]
 #[derive(Debug, Clone, PartialEq, Eq, ProtoBuf_Enum)]
@@ -32,9 +32,9 @@ impl std::default::Default for NumberFilterCondition {
     }
     }
 }
 }
 
 
-impl std::convert::From<NumberFilterCondition> for i32 {
+impl std::convert::From<NumberFilterCondition> for u32 {
     fn from(value: NumberFilterCondition) -> Self {
     fn from(value: NumberFilterCondition) -> Self {
-        value as i32
+        value as u32
     }
     }
 }
 }
 impl std::convert::TryFrom<u8> for NumberFilterCondition {
 impl std::convert::TryFrom<u8> for NumberFilterCondition {
@@ -55,9 +55,9 @@ impl std::convert::TryFrom<u8> for NumberFilterCondition {
     }
     }
 }
 }
 
 
-impl std::convert::From<Arc<FilterConfigurationRevision>> for NumberFilterConfigurationPB {
-    fn from(rev: Arc<FilterConfigurationRevision>) -> Self {
-        NumberFilterConfigurationPB {
+impl std::convert::From<Arc<FilterRevision>> for NumberFilterPB {
+    fn from(rev: Arc<FilterRevision>) -> Self {
+        NumberFilterPB {
             condition: NumberFilterCondition::try_from(rev.condition).unwrap_or(NumberFilterCondition::Equal),
             condition: NumberFilterCondition::try_from(rev.condition).unwrap_or(NumberFilterCondition::Equal),
             content: rev.content.clone(),
             content: rev.content.clone(),
         }
         }

+ 7 - 7
frontend/rust-lib/flowy-grid/src/entities/filter_entities/select_option_filter.rs

@@ -1,11 +1,11 @@
 use crate::services::field::SelectOptionIds;
 use crate::services::field::SelectOptionIds;
 use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
 use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
 use flowy_error::ErrorCode;
 use flowy_error::ErrorCode;
-use grid_rev_model::FilterConfigurationRevision;
+use grid_rev_model::FilterRevision;
 use std::sync::Arc;
 use std::sync::Arc;
 
 
 #[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
 #[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
-pub struct SelectOptionFilterConfigurationPB {
+pub struct SelectOptionFilterPB {
     #[pb(index = 1)]
     #[pb(index = 1)]
     pub condition: SelectOptionCondition,
     pub condition: SelectOptionCondition,
 
 
@@ -21,9 +21,9 @@ pub enum SelectOptionCondition {
     OptionIsNotEmpty = 3,
     OptionIsNotEmpty = 3,
 }
 }
 
 
-impl std::convert::From<SelectOptionCondition> for i32 {
+impl std::convert::From<SelectOptionCondition> for u32 {
     fn from(value: SelectOptionCondition) -> Self {
     fn from(value: SelectOptionCondition) -> Self {
-        value as i32
+        value as u32
     }
     }
 }
 }
 
 
@@ -47,10 +47,10 @@ impl std::convert::TryFrom<u8> for SelectOptionCondition {
     }
     }
 }
 }
 
 
-impl std::convert::From<Arc<FilterConfigurationRevision>> for SelectOptionFilterConfigurationPB {
-    fn from(rev: Arc<FilterConfigurationRevision>) -> Self {
+impl std::convert::From<Arc<FilterRevision>> for SelectOptionFilterPB {
+    fn from(rev: Arc<FilterRevision>) -> Self {
         let ids = SelectOptionIds::from(rev.content.clone());
         let ids = SelectOptionIds::from(rev.content.clone());
-        SelectOptionFilterConfigurationPB {
+        SelectOptionFilterPB {
             condition: SelectOptionCondition::try_from(rev.condition).unwrap_or(SelectOptionCondition::OptionIs),
             condition: SelectOptionCondition::try_from(rev.condition).unwrap_or(SelectOptionCondition::OptionIs),
             option_ids: ids.into_inner(),
             option_ids: ids.into_inner(),
         }
         }

+ 9 - 9
frontend/rust-lib/flowy-grid/src/entities/filter_entities/text_filter.rs

@@ -1,15 +1,15 @@
 use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
 use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
 use flowy_error::ErrorCode;
 use flowy_error::ErrorCode;
-use grid_rev_model::FilterConfigurationRevision;
+use grid_rev_model::FilterRevision;
 use std::sync::Arc;
 use std::sync::Arc;
 
 
 #[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
 #[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
-pub struct TextFilterConfigurationPB {
+pub struct TextFilterPB {
     #[pb(index = 1)]
     #[pb(index = 1)]
     pub condition: TextFilterCondition,
     pub condition: TextFilterCondition,
 
 
-    #[pb(index = 2, one_of)]
-    pub content: Option<String>,
+    #[pb(index = 2)]
+    pub content: String,
 }
 }
 
 
 #[derive(Debug, Clone, PartialEq, Eq, ProtoBuf_Enum)]
 #[derive(Debug, Clone, PartialEq, Eq, ProtoBuf_Enum)]
@@ -25,9 +25,9 @@ pub enum TextFilterCondition {
     TextIsNotEmpty = 7,
     TextIsNotEmpty = 7,
 }
 }
 
 
-impl std::convert::From<TextFilterCondition> for i32 {
+impl std::convert::From<TextFilterCondition> for u32 {
     fn from(value: TextFilterCondition) -> Self {
     fn from(value: TextFilterCondition) -> Self {
-        value as i32
+        value as u32
     }
     }
 }
 }
 
 
@@ -54,9 +54,9 @@ impl std::convert::TryFrom<u8> for TextFilterCondition {
     }
     }
 }
 }
 
 
-impl std::convert::From<Arc<FilterConfigurationRevision>> for TextFilterConfigurationPB {
-    fn from(rev: Arc<FilterConfigurationRevision>) -> Self {
-        TextFilterConfigurationPB {
+impl std::convert::From<Arc<FilterRevision>> for TextFilterPB {
+    fn from(rev: Arc<FilterRevision>) -> Self {
+        TextFilterPB {
             condition: TextFilterCondition::try_from(rev.condition).unwrap_or(TextFilterCondition::Is),
             condition: TextFilterCondition::try_from(rev.condition).unwrap_or(TextFilterCondition::Is),
             content: rev.content.clone(),
             content: rev.content.clone(),
         }
         }

+ 33 - 30
frontend/rust-lib/flowy-grid/src/entities/filter_entities/util.rs

@@ -1,16 +1,17 @@
 use crate::entities::parser::NotEmptyStr;
 use crate::entities::parser::NotEmptyStr;
 use crate::entities::{
 use crate::entities::{
-    CheckboxCondition, DateFilterCondition, FieldType, NumberFilterCondition, SelectOptionCondition,
+    CheckboxFilterCondition, DateFilterCondition, FieldType, NumberFilterCondition, SelectOptionCondition,
     TextFilterCondition,
     TextFilterCondition,
 };
 };
+use crate::services::filter::FilterType;
 use flowy_derive::ProtoBuf;
 use flowy_derive::ProtoBuf;
 use flowy_error::ErrorCode;
 use flowy_error::ErrorCode;
-use grid_rev_model::{FieldRevision, FieldTypeRevision, FilterConfigurationRevision};
+use grid_rev_model::{FieldRevision, FieldTypeRevision, FilterRevision};
 use std::convert::TryInto;
 use std::convert::TryInto;
 use std::sync::Arc;
 use std::sync::Arc;
 
 
 #[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
 #[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
-pub struct GridFilterConfigurationPB {
+pub struct FilterPB {
     #[pb(index = 1)]
     #[pb(index = 1)]
     pub id: String,
     pub id: String,
 }
 }
@@ -18,25 +19,25 @@ pub struct GridFilterConfigurationPB {
 #[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
 #[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
 pub struct RepeatedGridFilterConfigurationPB {
 pub struct RepeatedGridFilterConfigurationPB {
     #[pb(index = 1)]
     #[pb(index = 1)]
-    pub items: Vec<GridFilterConfigurationPB>,
+    pub items: Vec<FilterPB>,
 }
 }
 
 
-impl std::convert::From<&FilterConfigurationRevision> for GridFilterConfigurationPB {
-    fn from(rev: &FilterConfigurationRevision) -> Self {
+impl std::convert::From<&FilterRevision> for FilterPB {
+    fn from(rev: &FilterRevision) -> Self {
         Self { id: rev.id.clone() }
         Self { id: rev.id.clone() }
     }
     }
 }
 }
 
 
-impl std::convert::From<Vec<Arc<FilterConfigurationRevision>>> for RepeatedGridFilterConfigurationPB {
-    fn from(revs: Vec<Arc<FilterConfigurationRevision>>) -> Self {
+impl std::convert::From<Vec<Arc<FilterRevision>>> for RepeatedGridFilterConfigurationPB {
+    fn from(revs: Vec<Arc<FilterRevision>>) -> Self {
         RepeatedGridFilterConfigurationPB {
         RepeatedGridFilterConfigurationPB {
             items: revs.into_iter().map(|rev| rev.as_ref().into()).collect(),
             items: revs.into_iter().map(|rev| rev.as_ref().into()).collect(),
         }
         }
     }
     }
 }
 }
 
 
-impl std::convert::From<Vec<GridFilterConfigurationPB>> for RepeatedGridFilterConfigurationPB {
-    fn from(items: Vec<GridFilterConfigurationPB>) -> Self {
+impl std::convert::From<Vec<FilterPB>> for RepeatedGridFilterConfigurationPB {
+    fn from(items: Vec<FilterPB>) -> Self {
         Self { items }
         Self { items }
     }
     }
 }
 }
@@ -47,10 +48,10 @@ pub struct DeleteFilterPayloadPB {
     pub field_id: String,
     pub field_id: String,
 
 
     #[pb(index = 2)]
     #[pb(index = 2)]
-    pub filter_id: String,
+    pub field_type: FieldType,
 
 
     #[pb(index = 3)]
     #[pb(index = 3)]
-    pub field_type: FieldType,
+    pub filter_id: String,
 }
 }
 
 
 impl TryInto<DeleteFilterParams> for DeleteFilterPayloadPB {
 impl TryInto<DeleteFilterParams> for DeleteFilterPayloadPB {
@@ -60,25 +61,27 @@ impl TryInto<DeleteFilterParams> for DeleteFilterPayloadPB {
         let field_id = NotEmptyStr::parse(self.field_id)
         let field_id = NotEmptyStr::parse(self.field_id)
             .map_err(|_| ErrorCode::FieldIdIsEmpty)?
             .map_err(|_| ErrorCode::FieldIdIsEmpty)?
             .0;
             .0;
+
         let filter_id = NotEmptyStr::parse(self.filter_id)
         let filter_id = NotEmptyStr::parse(self.filter_id)
             .map_err(|_| ErrorCode::UnexpectedEmptyString)?
             .map_err(|_| ErrorCode::UnexpectedEmptyString)?
             .0;
             .0;
-        Ok(DeleteFilterParams {
+
+        let filter_type = FilterType {
             field_id,
             field_id,
-            filter_id,
-            field_type_rev: self.field_type.into(),
-        })
+            field_type: self.field_type,
+        };
+
+        Ok(DeleteFilterParams { filter_id, filter_type })
     }
     }
 }
 }
 
 
 pub struct DeleteFilterParams {
 pub struct DeleteFilterParams {
-    pub field_id: String,
+    pub filter_type: FilterType,
     pub filter_id: String,
     pub filter_id: String,
-    pub field_type_rev: FieldTypeRevision,
 }
 }
 
 
 #[derive(ProtoBuf, Debug, Default, Clone)]
 #[derive(ProtoBuf, Debug, Default, Clone)]
-pub struct InsertFilterPayloadPB {
+pub struct CreateFilterPayloadPB {
     #[pb(index = 1)]
     #[pb(index = 1)]
     pub field_id: String,
     pub field_id: String,
 
 
@@ -86,15 +89,15 @@ pub struct InsertFilterPayloadPB {
     pub field_type: FieldType,
     pub field_type: FieldType,
 
 
     #[pb(index = 3)]
     #[pb(index = 3)]
-    pub condition: i32,
+    pub condition: u32,
 
 
-    #[pb(index = 4, one_of)]
-    pub content: Option<String>,
+    #[pb(index = 4)]
+    pub content: String,
 }
 }
 
 
-impl InsertFilterPayloadPB {
+impl CreateFilterPayloadPB {
     #[allow(dead_code)]
     #[allow(dead_code)]
-    pub fn new<T: Into<i32>>(field_rev: &FieldRevision, condition: T, content: Option<String>) -> Self {
+    pub fn new<T: Into<u32>>(field_rev: &FieldRevision, condition: T, content: String) -> Self {
         Self {
         Self {
             field_id: field_rev.id.clone(),
             field_id: field_rev.id.clone(),
             field_type: field_rev.ty.into(),
             field_type: field_rev.ty.into(),
@@ -104,10 +107,10 @@ impl InsertFilterPayloadPB {
     }
     }
 }
 }
 
 
-impl TryInto<InsertFilterParams> for InsertFilterPayloadPB {
+impl TryInto<CreateFilterParams> for CreateFilterPayloadPB {
     type Error = ErrorCode;
     type Error = ErrorCode;
 
 
-    fn try_into(self) -> Result<InsertFilterParams, Self::Error> {
+    fn try_into(self) -> Result<CreateFilterParams, Self::Error> {
         let field_id = NotEmptyStr::parse(self.field_id)
         let field_id = NotEmptyStr::parse(self.field_id)
             .map_err(|_| ErrorCode::FieldIdIsEmpty)?
             .map_err(|_| ErrorCode::FieldIdIsEmpty)?
             .0;
             .0;
@@ -117,7 +120,7 @@ impl TryInto<InsertFilterParams> for InsertFilterPayloadPB {
                 let _ = TextFilterCondition::try_from(condition)?;
                 let _ = TextFilterCondition::try_from(condition)?;
             }
             }
             FieldType::Checkbox => {
             FieldType::Checkbox => {
-                let _ = CheckboxCondition::try_from(condition)?;
+                let _ = CheckboxFilterCondition::try_from(condition)?;
             }
             }
             FieldType::Number => {
             FieldType::Number => {
                 let _ = NumberFilterCondition::try_from(condition)?;
                 let _ = NumberFilterCondition::try_from(condition)?;
@@ -130,7 +133,7 @@ impl TryInto<InsertFilterParams> for InsertFilterPayloadPB {
             }
             }
         }
         }
 
 
-        Ok(InsertFilterParams {
+        Ok(CreateFilterParams {
             field_id,
             field_id,
             field_type_rev: self.field_type.into(),
             field_type_rev: self.field_type.into(),
             condition,
             condition,
@@ -139,9 +142,9 @@ impl TryInto<InsertFilterParams> for InsertFilterPayloadPB {
     }
     }
 }
 }
 
 
-pub struct InsertFilterParams {
+pub struct CreateFilterParams {
     pub field_id: String,
     pub field_id: String,
     pub field_type_rev: FieldTypeRevision,
     pub field_type_rev: FieldTypeRevision,
     pub condition: u8,
     pub condition: u8,
-    pub content: Option<String>,
+    pub content: String,
 }
 }

+ 3 - 3
frontend/rust-lib/flowy-grid/src/entities/mod.rs

@@ -1,12 +1,12 @@
-mod block_entities;
+pub mod block_entities;
 mod cell_entities;
 mod cell_entities;
 mod field_entities;
 mod field_entities;
-mod filter_entities;
+pub mod filter_entities;
 mod grid_entities;
 mod grid_entities;
 mod group_entities;
 mod group_entities;
 pub mod parser;
 pub mod parser;
 mod row_entities;
 mod row_entities;
-mod setting_entities;
+pub mod setting_entities;
 
 
 pub use block_entities::*;
 pub use block_entities::*;
 pub use cell_entities::*;
 pub use cell_entities::*;

+ 4 - 4
frontend/rust-lib/flowy-grid/src/entities/setting_entities.rs

@@ -1,7 +1,7 @@
 use crate::entities::parser::NotEmptyStr;
 use crate::entities::parser::NotEmptyStr;
 use crate::entities::{
 use crate::entities::{
-    DeleteFilterParams, DeleteFilterPayloadPB, DeleteGroupParams, DeleteGroupPayloadPB, InsertFilterParams,
-    InsertFilterPayloadPB, InsertGroupParams, InsertGroupPayloadPB, RepeatedGridFilterConfigurationPB,
+    CreateFilterParams, CreateFilterPayloadPB, DeleteFilterParams, DeleteFilterPayloadPB, DeleteGroupParams,
+    DeleteGroupPayloadPB, InsertGroupParams, InsertGroupPayloadPB, RepeatedGridFilterConfigurationPB,
     RepeatedGridGroupConfigurationPB,
     RepeatedGridGroupConfigurationPB,
 };
 };
 use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
 use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
@@ -84,7 +84,7 @@ pub struct GridSettingChangesetPayloadPB {
     pub layout_type: GridLayout,
     pub layout_type: GridLayout,
 
 
     #[pb(index = 3, one_of)]
     #[pb(index = 3, one_of)]
-    pub insert_filter: Option<InsertFilterPayloadPB>,
+    pub insert_filter: Option<CreateFilterPayloadPB>,
 
 
     #[pb(index = 4, one_of)]
     #[pb(index = 4, one_of)]
     pub delete_filter: Option<DeleteFilterPayloadPB>,
     pub delete_filter: Option<DeleteFilterPayloadPB>,
@@ -138,7 +138,7 @@ impl TryInto<GridSettingChangesetParams> for GridSettingChangesetPayloadPB {
 pub struct GridSettingChangesetParams {
 pub struct GridSettingChangesetParams {
     pub grid_id: String,
     pub grid_id: String,
     pub layout_type: LayoutRevision,
     pub layout_type: LayoutRevision,
-    pub insert_filter: Option<InsertFilterParams>,
+    pub insert_filter: Option<CreateFilterParams>,
     pub delete_filter: Option<DeleteFilterParams>,
     pub delete_filter: Option<DeleteFilterParams>,
     pub insert_group: Option<InsertGroupParams>,
     pub insert_group: Option<InsertGroupParams>,
     pub delete_group: Option<DeleteGroupParams>,
     pub delete_group: Option<DeleteGroupParams>,

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

@@ -7,7 +7,7 @@ use crate::services::field::{
     SelectOptionCellChangesetPayloadPB, SelectOptionCellDataPB, SelectOptionChangeset, SelectOptionChangesetPayloadPB,
     SelectOptionCellChangesetPayloadPB, SelectOptionCellDataPB, SelectOptionChangeset, SelectOptionChangesetPayloadPB,
     SelectOptionPB,
     SelectOptionPB,
 };
 };
-use crate::services::row::make_row_from_row_rev;
+use crate::services::row::{make_block_pbs, make_row_from_row_rev};
 use flowy_error::{ErrorCode, FlowyError, FlowyResult};
 use flowy_error::{ErrorCode, FlowyError, FlowyResult};
 use grid_rev_model::FieldRevision;
 use grid_rev_model::FieldRevision;
 use lib_dispatch::prelude::{data_result, AppData, Data, DataResult};
 use lib_dispatch::prelude::{data_result, AppData, Data, DataResult};
@@ -20,7 +20,7 @@ pub(crate) async fn get_grid_handler(
 ) -> DataResult<GridPB, FlowyError> {
 ) -> DataResult<GridPB, FlowyError> {
     let grid_id: GridIdPB = data.into_inner();
     let grid_id: GridIdPB = data.into_inner();
     let editor = manager.open_grid(grid_id).await?;
     let editor = manager.open_grid(grid_id).await?;
-    let grid = editor.get_grid_data().await?;
+    let grid = editor.get_grid().await?;
     data_result(grid)
     data_result(grid)
 }
 }
 
 
@@ -31,7 +31,7 @@ pub(crate) async fn get_grid_setting_handler(
 ) -> DataResult<GridSettingPB, FlowyError> {
 ) -> DataResult<GridSettingPB, FlowyError> {
     let grid_id: GridIdPB = data.into_inner();
     let grid_id: GridIdPB = data.into_inner();
     let editor = manager.open_grid(grid_id).await?;
     let editor = manager.open_grid(grid_id).await?;
-    let grid_setting = editor.get_grid_setting().await?;
+    let grid_setting = editor.get_setting().await?;
     data_result(grid_setting)
     data_result(grid_setting)
 }
 }
 
 
@@ -68,8 +68,8 @@ pub(crate) async fn get_grid_blocks_handler(
 ) -> DataResult<RepeatedBlockPB, FlowyError> {
 ) -> DataResult<RepeatedBlockPB, FlowyError> {
     let params: QueryGridBlocksParams = data.into_inner().try_into()?;
     let params: QueryGridBlocksParams = data.into_inner().try_into()?;
     let editor = manager.get_grid_editor(&params.grid_id).await?;
     let editor = manager.get_grid_editor(&params.grid_id).await?;
-    let repeated_grid_block = editor.get_blocks(Some(params.block_ids)).await?;
-    data_result(repeated_grid_block)
+    let blocks = editor.get_blocks(Some(params.block_ids)).await?;
+    data_result(make_block_pbs(blocks))
 }
 }
 
 
 #[tracing::instrument(level = "trace", skip(data, manager), err)]
 #[tracing::instrument(level = "trace", skip(data, manager), err)]

+ 5 - 7
frontend/rust-lib/flowy-grid/src/manager.rs

@@ -7,7 +7,6 @@ use crate::services::persistence::kv::GridKVPersistence;
 use crate::services::persistence::migration::GridMigration;
 use crate::services::persistence::migration::GridMigration;
 use crate::services::persistence::rev_sqlite::SQLiteGridRevisionPersistence;
 use crate::services::persistence::rev_sqlite::SQLiteGridRevisionPersistence;
 use crate::services::persistence::GridDatabase;
 use crate::services::persistence::GridDatabase;
-use crate::services::tasks::GridTaskScheduler;
 use bytes::Bytes;
 use bytes::Bytes;
 
 
 use flowy_database::ConnectionPool;
 use flowy_database::ConnectionPool;
@@ -22,6 +21,7 @@ use grid_rev_model::{BuildGridContext, GridRevision, GridViewRevision};
 use lib_infra::ref_map::{RefCountHashMap, RefCountValue};
 use lib_infra::ref_map::{RefCountHashMap, RefCountValue};
 
 
 use crate::services::block_manager::make_grid_block_rev_manager;
 use crate::services::block_manager::make_grid_block_rev_manager;
+use flowy_task::TaskDispatcher;
 use std::sync::Arc;
 use std::sync::Arc;
 use tokio::sync::RwLock;
 use tokio::sync::RwLock;
 
 
@@ -31,15 +31,13 @@ pub trait GridUser: Send + Sync {
     fn db_pool(&self) -> Result<Arc<ConnectionPool>, FlowyError>;
     fn db_pool(&self) -> Result<Arc<ConnectionPool>, FlowyError>;
 }
 }
 
 
-pub type GridTaskSchedulerRwLock = Arc<RwLock<GridTaskScheduler>>;
-
 pub struct GridManager {
 pub struct GridManager {
     grid_editors: RwLock<RefCountHashMap<Arc<GridRevisionEditor>>>,
     grid_editors: RwLock<RefCountHashMap<Arc<GridRevisionEditor>>>,
     grid_user: Arc<dyn GridUser>,
     grid_user: Arc<dyn GridUser>,
     block_index_cache: Arc<BlockIndexCache>,
     block_index_cache: Arc<BlockIndexCache>,
     #[allow(dead_code)]
     #[allow(dead_code)]
     kv_persistence: Arc<GridKVPersistence>,
     kv_persistence: Arc<GridKVPersistence>,
-    task_scheduler: GridTaskSchedulerRwLock,
+    task_scheduler: Arc<RwLock<TaskDispatcher>>,
     migration: GridMigration,
     migration: GridMigration,
 }
 }
 
 
@@ -47,12 +45,12 @@ impl GridManager {
     pub fn new(
     pub fn new(
         grid_user: Arc<dyn GridUser>,
         grid_user: Arc<dyn GridUser>,
         _rev_web_socket: Arc<dyn RevisionWebSocket>,
         _rev_web_socket: Arc<dyn RevisionWebSocket>,
+        task_scheduler: Arc<RwLock<TaskDispatcher>>,
         database: Arc<dyn GridDatabase>,
         database: Arc<dyn GridDatabase>,
     ) -> Self {
     ) -> Self {
         let grid_editors = RwLock::new(RefCountHashMap::new());
         let grid_editors = RwLock::new(RefCountHashMap::new());
         let kv_persistence = Arc::new(GridKVPersistence::new(database.clone()));
         let kv_persistence = Arc::new(GridKVPersistence::new(database.clone()));
         let block_index_cache = Arc::new(BlockIndexCache::new(database.clone()));
         let block_index_cache = Arc::new(BlockIndexCache::new(database.clone()));
-        let task_scheduler = GridTaskScheduler::new();
         let migration = GridMigration::new(grid_user.clone(), database);
         let migration = GridMigration::new(grid_user.clone(), database);
         Self {
         Self {
             grid_editors,
             grid_editors,
@@ -111,7 +109,7 @@ impl GridManager {
         tracing::Span::current().record("grid_id", &grid_id);
         tracing::Span::current().record("grid_id", &grid_id);
 
 
         self.grid_editors.write().await.remove(grid_id);
         self.grid_editors.write().await.remove(grid_id);
-        self.task_scheduler.write().await.unregister_handler(grid_id);
+        // self.task_scheduler.write().await.unregister_handler(grid_id);
         Ok(())
         Ok(())
     }
     }
 
 
@@ -134,7 +132,7 @@ impl GridManager {
             .write()
             .write()
             .await
             .await
             .insert(grid_id.to_string(), editor.clone());
             .insert(grid_id.to_string(), editor.clone());
-        self.task_scheduler.write().await.register_handler(editor.clone());
+        // self.task_scheduler.write().await.register_handler(editor.clone());
         Ok(editor)
         Ok(editor)
     }
     }
 
 

+ 2 - 2
frontend/rust-lib/flowy-grid/src/services/block_editor.rs

@@ -134,10 +134,10 @@ impl GridBlockRevisionEditor {
 
 
     pub async fn get_row_pb(&self, row_id: &str) -> FlowyResult<Option<RowPB>> {
     pub async fn get_row_pb(&self, row_id: &str) -> FlowyResult<Option<RowPB>> {
         let row_ids = Some(vec![Cow::Borrowed(row_id)]);
         let row_ids = Some(vec![Cow::Borrowed(row_id)]);
-        Ok(self.get_row_infos(row_ids).await?.pop())
+        Ok(self.get_row_pbs(row_ids).await?.pop())
     }
     }
 
 
-    pub async fn get_row_infos<T>(&self, row_ids: Option<Vec<Cow<'_, T>>>) -> FlowyResult<Vec<RowPB>>
+    pub async fn get_row_pbs<T>(&self, row_ids: Option<Vec<Cow<'_, T>>>) -> FlowyResult<Vec<RowPB>>
     where
     where
         T: AsRef<str> + ToOwned + ?Sized,
         T: AsRef<str> + ToOwned + ?Sized,
     {
     {

+ 8 - 11
frontend/rust-lib/flowy-grid/src/services/block_manager.rs

@@ -4,7 +4,7 @@ use crate::manager::GridUser;
 use crate::services::block_editor::{GridBlockRevisionCompress, GridBlockRevisionEditor};
 use crate::services::block_editor::{GridBlockRevisionCompress, GridBlockRevisionEditor};
 use crate::services::persistence::block_index::BlockIndexCache;
 use crate::services::persistence::block_index::BlockIndexCache;
 use crate::services::persistence::rev_sqlite::SQLiteGridBlockRevisionPersistence;
 use crate::services::persistence::rev_sqlite::SQLiteGridBlockRevisionPersistence;
-use crate::services::row::{block_from_row_orders, make_row_from_row_rev, GridBlockSnapshot};
+use crate::services::row::{block_from_row_orders, make_row_from_row_rev, GridBlock};
 use dashmap::DashMap;
 use dashmap::DashMap;
 use flowy_database::ConnectionPool;
 use flowy_database::ConnectionPool;
 use flowy_error::FlowyResult;
 use flowy_error::FlowyResult;
@@ -209,34 +209,31 @@ impl GridBlockManager {
         }
         }
     }
     }
 
 
-    pub async fn get_row_orders(&self, block_id: &str) -> FlowyResult<Vec<RowPB>> {
+    pub async fn get_row_revs(&self, block_id: &str) -> FlowyResult<Vec<Arc<RowRevision>>> {
         let editor = self.get_block_editor(block_id).await?;
         let editor = self.get_block_editor(block_id).await?;
-        editor.get_row_infos::<&str>(None).await
+        editor.get_row_revs::<&str>(None).await
     }
     }
 
 
-    pub(crate) async fn get_block_snapshots(
-        &self,
-        block_ids: Option<Vec<String>>,
-    ) -> FlowyResult<Vec<GridBlockSnapshot>> {
-        let mut snapshots = vec![];
+    pub(crate) async fn get_blocks(&self, block_ids: Option<Vec<String>>) -> FlowyResult<Vec<GridBlock>> {
+        let mut blocks = vec![];
         match block_ids {
         match block_ids {
             None => {
             None => {
                 for iter in self.block_editors.iter() {
                 for iter in self.block_editors.iter() {
                     let editor = iter.value();
                     let editor = iter.value();
                     let block_id = editor.block_id.clone();
                     let block_id = editor.block_id.clone();
                     let row_revs = editor.get_row_revs::<&str>(None).await?;
                     let row_revs = editor.get_row_revs::<&str>(None).await?;
-                    snapshots.push(GridBlockSnapshot { block_id, row_revs });
+                    blocks.push(GridBlock { block_id, row_revs });
                 }
                 }
             }
             }
             Some(block_ids) => {
             Some(block_ids) => {
                 for block_id in block_ids {
                 for block_id in block_ids {
                     let editor = self.get_block_editor(&block_id).await?;
                     let editor = self.get_block_editor(&block_id).await?;
                     let row_revs = editor.get_row_revs::<&str>(None).await?;
                     let row_revs = editor.get_row_revs::<&str>(None).await?;
-                    snapshots.push(GridBlockSnapshot { block_id, row_revs });
+                    blocks.push(GridBlock { block_id, row_revs });
                 }
                 }
             }
             }
         }
         }
-        Ok(snapshots)
+        Ok(blocks)
     }
     }
 
 
     async fn notify_did_update_block(&self, block_id: &str, changeset: GridBlockChangesetPB) -> FlowyResult<()> {
     async fn notify_did_update_block(&self, block_id: &str, changeset: GridBlockChangesetPB) -> FlowyResult<()> {

+ 0 - 37
frontend/rust-lib/flowy-grid/src/services/block_manager_trait_impl.rs

@@ -1,37 +0,0 @@
-use crate::services::block_manager::GridBlockManager;
-use crate::services::grid_view_manager::GridViewRowDelegate;
-
-use grid_rev_model::RowRevision;
-use lib_infra::future::{wrap_future, AFFuture};
-use std::sync::Arc;
-
-impl GridViewRowDelegate for Arc<GridBlockManager> {
-    fn gv_index_of_row(&self, row_id: &str) -> AFFuture<Option<usize>> {
-        let block_manager = self.clone();
-        let row_id = row_id.to_owned();
-        wrap_future(async move { block_manager.index_of_row(&row_id).await })
-    }
-
-    fn gv_get_row_rev(&self, row_id: &str) -> AFFuture<Option<Arc<RowRevision>>> {
-        let block_manager = self.clone();
-        let row_id = row_id.to_owned();
-        wrap_future(async move {
-            match block_manager.get_row_rev(&row_id).await {
-                Ok(row_rev) => row_rev,
-                Err(_) => None,
-            }
-        })
-    }
-
-    fn gv_row_revs(&self) -> AFFuture<Vec<Arc<RowRevision>>> {
-        let block_manager = self.clone();
-
-        wrap_future(async move {
-            let blocks = block_manager.get_block_snapshots(None).await.unwrap();
-            blocks
-                .into_iter()
-                .flat_map(|block| block.row_revs)
-                .collect::<Vec<Arc<RowRevision>>>()
-        })
-    }
-}

+ 11 - 11
frontend/rust-lib/flowy-grid/src/services/filter/impls/checkbox_filter.rs → frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_filter.rs

@@ -1,20 +1,20 @@
-use crate::entities::{CheckboxCondition, CheckboxFilterConfigurationPB};
+use crate::entities::{CheckboxFilterCondition, CheckboxFilterPB};
 use crate::services::cell::{AnyCellData, CellData, CellFilterOperation};
 use crate::services::cell::{AnyCellData, CellData, CellFilterOperation};
 use crate::services::field::{CheckboxCellData, CheckboxTypeOptionPB};
 use crate::services::field::{CheckboxCellData, CheckboxTypeOptionPB};
 use flowy_error::FlowyResult;
 use flowy_error::FlowyResult;
 
 
-impl CheckboxFilterConfigurationPB {
+impl CheckboxFilterPB {
     pub fn is_visible(&self, cell_data: &CheckboxCellData) -> bool {
     pub fn is_visible(&self, cell_data: &CheckboxCellData) -> bool {
         let is_check = cell_data.is_check();
         let is_check = cell_data.is_check();
         match self.condition {
         match self.condition {
-            CheckboxCondition::IsChecked => is_check,
-            CheckboxCondition::IsUnChecked => !is_check,
+            CheckboxFilterCondition::IsChecked => is_check,
+            CheckboxFilterCondition::IsUnChecked => !is_check,
         }
         }
     }
     }
 }
 }
 
 
-impl CellFilterOperation<CheckboxFilterConfigurationPB> for CheckboxTypeOptionPB {
-    fn apply_filter(&self, any_cell_data: AnyCellData, filter: &CheckboxFilterConfigurationPB) -> FlowyResult<bool> {
+impl CellFilterOperation<CheckboxFilterPB> for CheckboxTypeOptionPB {
+    fn apply_filter(&self, any_cell_data: AnyCellData, filter: &CheckboxFilterPB) -> FlowyResult<bool> {
         if !any_cell_data.is_checkbox() {
         if !any_cell_data.is_checkbox() {
             return Ok(true);
             return Ok(true);
         }
         }
@@ -26,14 +26,14 @@ impl CellFilterOperation<CheckboxFilterConfigurationPB> for CheckboxTypeOptionPB
 
 
 #[cfg(test)]
 #[cfg(test)]
 mod tests {
 mod tests {
-    use crate::entities::{CheckboxCondition, CheckboxFilterConfigurationPB};
+    use crate::entities::{CheckboxFilterCondition, CheckboxFilterPB};
     use crate::services::field::CheckboxCellData;
     use crate::services::field::CheckboxCellData;
     use std::str::FromStr;
     use std::str::FromStr;
 
 
     #[test]
     #[test]
     fn checkbox_filter_is_check_test() {
     fn checkbox_filter_is_check_test() {
-        let checkbox_filter = CheckboxFilterConfigurationPB {
-            condition: CheckboxCondition::IsChecked,
+        let checkbox_filter = CheckboxFilterPB {
+            condition: CheckboxFilterCondition::IsChecked,
         };
         };
         for (value, visible) in [("true", true), ("yes", true), ("false", false), ("no", false)] {
         for (value, visible) in [("true", true), ("yes", true), ("false", false), ("no", false)] {
             let data = CheckboxCellData::from_str(value).unwrap();
             let data = CheckboxCellData::from_str(value).unwrap();
@@ -43,8 +43,8 @@ mod tests {
 
 
     #[test]
     #[test]
     fn checkbox_filter_is_uncheck_test() {
     fn checkbox_filter_is_uncheck_test() {
-        let checkbox_filter = CheckboxFilterConfigurationPB {
-            condition: CheckboxCondition::IsUnChecked,
+        let checkbox_filter = CheckboxFilterPB {
+            condition: CheckboxFilterCondition::IsUnChecked,
         };
         };
         for (value, visible) in [("false", true), ("no", true), ("true", false), ("yes", false)] {
         for (value, visible) in [("false", true), ("no", true), ("true", false), ("yes", false)] {
             let data = CheckboxCellData::from_str(value).unwrap();
             let data = CheckboxCellData::from_str(value).unwrap();

+ 1 - 0
frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/mod.rs

@@ -1,4 +1,5 @@
 #![allow(clippy::module_inception)]
 #![allow(clippy::module_inception)]
+mod checkbox_filter;
 mod checkbox_tests;
 mod checkbox_tests;
 mod checkbox_type_option;
 mod checkbox_type_option;
 mod checkbox_type_option_entities;
 mod checkbox_type_option_entities;

+ 10 - 10
frontend/rust-lib/flowy-grid/src/services/filter/impls/date_filter.rs → frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_filter.rs

@@ -1,9 +1,9 @@
-use crate::entities::{DateFilterCondition, DateFilterConfigurationPB};
+use crate::entities::{DateFilterCondition, DateFilterPB};
 use crate::services::cell::{AnyCellData, CellData, CellFilterOperation};
 use crate::services::cell::{AnyCellData, CellData, CellFilterOperation};
 use crate::services::field::{DateTimestamp, DateTypeOptionPB};
 use crate::services::field::{DateTimestamp, DateTypeOptionPB};
 use flowy_error::FlowyResult;
 use flowy_error::FlowyResult;
 
 
-impl DateFilterConfigurationPB {
+impl DateFilterPB {
     pub fn is_visible<T: Into<i64>>(&self, cell_timestamp: T) -> bool {
     pub fn is_visible<T: Into<i64>>(&self, cell_timestamp: T) -> bool {
         if self.start.is_none() {
         if self.start.is_none() {
             return false;
             return false;
@@ -29,8 +29,8 @@ impl DateFilterConfigurationPB {
     }
     }
 }
 }
 
 
-impl CellFilterOperation<DateFilterConfigurationPB> for DateTypeOptionPB {
-    fn apply_filter(&self, any_cell_data: AnyCellData, filter: &DateFilterConfigurationPB) -> FlowyResult<bool> {
+impl CellFilterOperation<DateFilterPB> for DateTypeOptionPB {
+    fn apply_filter(&self, any_cell_data: AnyCellData, filter: &DateFilterPB) -> FlowyResult<bool> {
         if !any_cell_data.is_date() {
         if !any_cell_data.is_date() {
             return Ok(true);
             return Ok(true);
         }
         }
@@ -43,11 +43,11 @@ impl CellFilterOperation<DateFilterConfigurationPB> for DateTypeOptionPB {
 #[cfg(test)]
 #[cfg(test)]
 mod tests {
 mod tests {
     #![allow(clippy::all)]
     #![allow(clippy::all)]
-    use crate::entities::{DateFilterCondition, DateFilterConfigurationPB};
+    use crate::entities::{DateFilterCondition, DateFilterPB};
 
 
     #[test]
     #[test]
     fn date_filter_is_test() {
     fn date_filter_is_test() {
-        let filter = DateFilterConfigurationPB {
+        let filter = DateFilterPB {
             condition: DateFilterCondition::DateIs,
             condition: DateFilterCondition::DateIs,
             start: Some(123),
             start: Some(123),
             end: None,
             end: None,
@@ -59,7 +59,7 @@ mod tests {
     }
     }
     #[test]
     #[test]
     fn date_filter_before_test() {
     fn date_filter_before_test() {
-        let filter = DateFilterConfigurationPB {
+        let filter = DateFilterPB {
             condition: DateFilterCondition::DateBefore,
             condition: DateFilterCondition::DateBefore,
             start: Some(123),
             start: Some(123),
             end: None,
             end: None,
@@ -71,7 +71,7 @@ mod tests {
     }
     }
     #[test]
     #[test]
     fn date_filter_before_or_on_test() {
     fn date_filter_before_or_on_test() {
-        let filter = DateFilterConfigurationPB {
+        let filter = DateFilterPB {
             condition: DateFilterCondition::DateOnOrBefore,
             condition: DateFilterCondition::DateOnOrBefore,
             start: Some(123),
             start: Some(123),
             end: None,
             end: None,
@@ -83,7 +83,7 @@ mod tests {
     }
     }
     #[test]
     #[test]
     fn date_filter_after_test() {
     fn date_filter_after_test() {
-        let filter = DateFilterConfigurationPB {
+        let filter = DateFilterPB {
             condition: DateFilterCondition::DateAfter,
             condition: DateFilterCondition::DateAfter,
             start: Some(123),
             start: Some(123),
             end: None,
             end: None,
@@ -95,7 +95,7 @@ mod tests {
     }
     }
     #[test]
     #[test]
     fn date_filter_within_test() {
     fn date_filter_within_test() {
-        let filter = DateFilterConfigurationPB {
+        let filter = DateFilterPB {
             condition: DateFilterCondition::DateWithIn,
             condition: DateFilterCondition::DateWithIn,
             start: Some(123),
             start: Some(123),
             end: Some(130),
             end: Some(130),

+ 1 - 0
frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/mod.rs

@@ -1,4 +1,5 @@
 #![allow(clippy::module_inception)]
 #![allow(clippy::module_inception)]
+mod date_filter;
 mod date_tests;
 mod date_tests;
 mod date_type_option;
 mod date_type_option;
 mod date_type_option_entities;
 mod date_type_option_entities;

+ 1 - 0
frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/mod.rs

@@ -1,5 +1,6 @@
 #![allow(clippy::module_inception)]
 #![allow(clippy::module_inception)]
 mod format;
 mod format;
+mod number_filter;
 mod number_tests;
 mod number_tests;
 mod number_type_option;
 mod number_type_option;
 mod number_type_option_entities;
 mod number_type_option_entities;

+ 36 - 30
frontend/rust-lib/flowy-grid/src/services/filter/impls/number_filter.rs → frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_filter.rs

@@ -1,4 +1,4 @@
-use crate::entities::{NumberFilterCondition, NumberFilterConfigurationPB};
+use crate::entities::{NumberFilterCondition, NumberFilterPB};
 use crate::services::cell::{AnyCellData, CellFilterOperation};
 use crate::services::cell::{AnyCellData, CellFilterOperation};
 use crate::services::field::{NumberCellData, NumberTypeOptionPB};
 use crate::services::field::{NumberCellData, NumberTypeOptionPB};
 use flowy_error::FlowyResult;
 use flowy_error::FlowyResult;
@@ -6,33 +6,39 @@ use rust_decimal::prelude::Zero;
 use rust_decimal::Decimal;
 use rust_decimal::Decimal;
 use std::str::FromStr;
 use std::str::FromStr;
 
 
-impl NumberFilterConfigurationPB {
+impl NumberFilterPB {
     pub fn is_visible(&self, num_cell_data: &NumberCellData) -> bool {
     pub fn is_visible(&self, num_cell_data: &NumberCellData) -> bool {
-        if self.content.is_none() {
-            return false;
+        if self.content.is_empty() {
+            match self.condition {
+                NumberFilterCondition::NumberIsEmpty => {
+                    return num_cell_data.is_empty();
+                }
+                NumberFilterCondition::NumberIsNotEmpty => {
+                    return !num_cell_data.is_empty();
+                }
+                _ => {}
+            }
         }
         }
-
-        let content = self.content.as_ref().unwrap();
-        let zero_decimal = Decimal::zero();
-        let cell_decimal = num_cell_data.decimal().as_ref().unwrap_or(&zero_decimal);
-        match Decimal::from_str(content) {
-            Ok(decimal) => match self.condition {
-                NumberFilterCondition::Equal => cell_decimal == &decimal,
-                NumberFilterCondition::NotEqual => cell_decimal != &decimal,
-                NumberFilterCondition::GreaterThan => cell_decimal > &decimal,
-                NumberFilterCondition::LessThan => cell_decimal < &decimal,
-                NumberFilterCondition::GreaterThanOrEqualTo => cell_decimal >= &decimal,
-                NumberFilterCondition::LessThanOrEqualTo => cell_decimal <= &decimal,
-                NumberFilterCondition::NumberIsEmpty => num_cell_data.is_empty(),
-                NumberFilterCondition::NumberIsNotEmpty => !num_cell_data.is_empty(),
-            },
-            Err(_) => false,
+        match num_cell_data.decimal().as_ref() {
+            None => false,
+            Some(cell_decimal) => {
+                let decimal = Decimal::from_str(&self.content).unwrap_or_else(|_| Decimal::zero());
+                match self.condition {
+                    NumberFilterCondition::Equal => cell_decimal == &decimal,
+                    NumberFilterCondition::NotEqual => cell_decimal != &decimal,
+                    NumberFilterCondition::GreaterThan => cell_decimal > &decimal,
+                    NumberFilterCondition::LessThan => cell_decimal < &decimal,
+                    NumberFilterCondition::GreaterThanOrEqualTo => cell_decimal >= &decimal,
+                    NumberFilterCondition::LessThanOrEqualTo => cell_decimal <= &decimal,
+                    _ => true,
+                }
+            }
         }
         }
     }
     }
 }
 }
 
 
-impl CellFilterOperation<NumberFilterConfigurationPB> for NumberTypeOptionPB {
-    fn apply_filter(&self, any_cell_data: AnyCellData, filter: &NumberFilterConfigurationPB) -> FlowyResult<bool> {
+impl CellFilterOperation<NumberFilterPB> for NumberTypeOptionPB {
+    fn apply_filter(&self, any_cell_data: AnyCellData, filter: &NumberFilterPB) -> FlowyResult<bool> {
         if !any_cell_data.is_number() {
         if !any_cell_data.is_number() {
             return Ok(true);
             return Ok(true);
         }
         }
@@ -46,13 +52,13 @@ impl CellFilterOperation<NumberFilterConfigurationPB> for NumberTypeOptionPB {
 
 
 #[cfg(test)]
 #[cfg(test)]
 mod tests {
 mod tests {
-    use crate::entities::{NumberFilterCondition, NumberFilterConfigurationPB};
+    use crate::entities::{NumberFilterCondition, NumberFilterPB};
     use crate::services::field::{NumberCellData, NumberFormat};
     use crate::services::field::{NumberCellData, NumberFormat};
     #[test]
     #[test]
     fn number_filter_equal_test() {
     fn number_filter_equal_test() {
-        let number_filter = NumberFilterConfigurationPB {
+        let number_filter = NumberFilterPB {
             condition: NumberFilterCondition::Equal,
             condition: NumberFilterCondition::Equal,
-            content: Some("123".to_owned()),
+            content: "123".to_owned(),
         };
         };
 
 
         for (num_str, visible) in [("123", true), ("1234", false), ("", false)] {
         for (num_str, visible) in [("123", true), ("1234", false), ("", false)] {
@@ -68,9 +74,9 @@ mod tests {
     }
     }
     #[test]
     #[test]
     fn number_filter_greater_than_test() {
     fn number_filter_greater_than_test() {
-        let number_filter = NumberFilterConfigurationPB {
+        let number_filter = NumberFilterPB {
             condition: NumberFilterCondition::GreaterThan,
             condition: NumberFilterCondition::GreaterThan,
-            content: Some("12".to_owned()),
+            content: "12".to_owned(),
         };
         };
         for (num_str, visible) in [("123", true), ("10", false), ("30", true), ("", false)] {
         for (num_str, visible) in [("123", true), ("10", false), ("30", true), ("", false)] {
             let data = NumberCellData::from_format_str(num_str, true, &NumberFormat::Num).unwrap();
             let data = NumberCellData::from_format_str(num_str, true, &NumberFormat::Num).unwrap();
@@ -80,11 +86,11 @@ mod tests {
 
 
     #[test]
     #[test]
     fn number_filter_less_than_test() {
     fn number_filter_less_than_test() {
-        let number_filter = NumberFilterConfigurationPB {
+        let number_filter = NumberFilterPB {
             condition: NumberFilterCondition::LessThan,
             condition: NumberFilterCondition::LessThan,
-            content: Some("100".to_owned()),
+            content: "100".to_owned(),
         };
         };
-        for (num_str, visible) in [("12", true), ("1234", false), ("30", true), ("", true)] {
+        for (num_str, visible) in [("12", true), ("1234", false), ("30", true), ("", false)] {
             let data = NumberCellData::from_format_str(num_str, true, &NumberFormat::Num).unwrap();
             let data = NumberCellData::from_format_str(num_str, true, &NumberFormat::Num).unwrap();
             assert_eq!(number_filter.is_visible(&data), visible);
             assert_eq!(number_filter.is_visible(&data), visible);
         }
         }

+ 1 - 0
frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/mod.rs

@@ -1,4 +1,5 @@
 mod multi_select_type_option;
 mod multi_select_type_option;
+mod select_filter;
 mod select_type_option;
 mod select_type_option;
 mod single_select_type_option;
 mod single_select_type_option;
 mod type_option_transform;
 mod type_option_transform;

+ 8 - 16
frontend/rust-lib/flowy-grid/src/services/filter/impls/select_option_filter.rs → frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/select_filter.rs

@@ -1,12 +1,12 @@
 #![allow(clippy::needless_collect)]
 #![allow(clippy::needless_collect)]
 
 
-use crate::entities::{SelectOptionCondition, SelectOptionFilterConfigurationPB};
+use crate::entities::{SelectOptionCondition, SelectOptionFilterPB};
 use crate::services::cell::{AnyCellData, CellFilterOperation};
 use crate::services::cell::{AnyCellData, CellFilterOperation};
 use crate::services::field::{MultiSelectTypeOptionPB, SingleSelectTypeOptionPB};
 use crate::services::field::{MultiSelectTypeOptionPB, SingleSelectTypeOptionPB};
 use crate::services::field::{SelectTypeOptionSharedAction, SelectedSelectOptions};
 use crate::services::field::{SelectTypeOptionSharedAction, SelectedSelectOptions};
 use flowy_error::FlowyResult;
 use flowy_error::FlowyResult;
 
 
-impl SelectOptionFilterConfigurationPB {
+impl SelectOptionFilterPB {
     pub fn is_visible(&self, selected_options: &SelectedSelectOptions) -> bool {
     pub fn is_visible(&self, selected_options: &SelectedSelectOptions) -> bool {
         let selected_option_ids: Vec<&String> = selected_options.options.iter().map(|option| &option.id).collect();
         let selected_option_ids: Vec<&String> = selected_options.options.iter().map(|option| &option.id).collect();
         match self.condition {
         match self.condition {
@@ -39,12 +39,8 @@ impl SelectOptionFilterConfigurationPB {
     }
     }
 }
 }
 
 
-impl CellFilterOperation<SelectOptionFilterConfigurationPB> for MultiSelectTypeOptionPB {
-    fn apply_filter(
-        &self,
-        any_cell_data: AnyCellData,
-        filter: &SelectOptionFilterConfigurationPB,
-    ) -> FlowyResult<bool> {
+impl CellFilterOperation<SelectOptionFilterPB> for MultiSelectTypeOptionPB {
+    fn apply_filter(&self, any_cell_data: AnyCellData, filter: &SelectOptionFilterPB) -> FlowyResult<bool> {
         if !any_cell_data.is_multi_select() {
         if !any_cell_data.is_multi_select() {
             return Ok(true);
             return Ok(true);
         }
         }
@@ -54,12 +50,8 @@ impl CellFilterOperation<SelectOptionFilterConfigurationPB> for MultiSelectTypeO
     }
     }
 }
 }
 
 
-impl CellFilterOperation<SelectOptionFilterConfigurationPB> for SingleSelectTypeOptionPB {
-    fn apply_filter(
-        &self,
-        any_cell_data: AnyCellData,
-        filter: &SelectOptionFilterConfigurationPB,
-    ) -> FlowyResult<bool> {
+impl CellFilterOperation<SelectOptionFilterPB> for SingleSelectTypeOptionPB {
+    fn apply_filter(&self, any_cell_data: AnyCellData, filter: &SelectOptionFilterPB) -> FlowyResult<bool> {
         if !any_cell_data.is_single_select() {
         if !any_cell_data.is_single_select() {
             return Ok(true);
             return Ok(true);
         }
         }
@@ -71,7 +63,7 @@ impl CellFilterOperation<SelectOptionFilterConfigurationPB> for SingleSelectType
 #[cfg(test)]
 #[cfg(test)]
 mod tests {
 mod tests {
     #![allow(clippy::all)]
     #![allow(clippy::all)]
-    use crate::entities::{SelectOptionCondition, SelectOptionFilterConfigurationPB};
+    use crate::entities::{SelectOptionCondition, SelectOptionFilterPB};
     use crate::services::field::selection_type_option::{SelectOptionPB, SelectedSelectOptions};
     use crate::services::field::selection_type_option::{SelectOptionPB, SelectedSelectOptions};
 
 
     #[test]
     #[test]
@@ -80,7 +72,7 @@ mod tests {
         let option_2 = SelectOptionPB::new("B");
         let option_2 = SelectOptionPB::new("B");
         let option_3 = SelectOptionPB::new("C");
         let option_3 = SelectOptionPB::new("C");
 
 
-        let filter_1 = SelectOptionFilterConfigurationPB {
+        let filter_1 = SelectOptionFilterPB {
             condition: SelectOptionCondition::OptionIs,
             condition: SelectOptionCondition::OptionIs,
             option_ids: vec![option_1.id.clone(), option_2.id.clone()],
             option_ids: vec![option_1.id.clone(), option_2.id.clone()],
         };
         };

+ 1 - 0
frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option/mod.rs

@@ -1,4 +1,5 @@
 #![allow(clippy::module_inception)]
 #![allow(clippy::module_inception)]
+mod text_filter;
 mod text_tests;
 mod text_tests;
 mod text_type_option;
 mod text_type_option;
 
 

+ 26 - 30
frontend/rust-lib/flowy-grid/src/services/filter/impls/text_filter.rs → frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option/text_filter.rs

@@ -1,31 +1,27 @@
-use crate::entities::{TextFilterCondition, TextFilterConfigurationPB};
+use crate::entities::{TextFilterCondition, TextFilterPB};
 use crate::services::cell::{AnyCellData, CellData, CellFilterOperation};
 use crate::services::cell::{AnyCellData, CellData, CellFilterOperation};
 use crate::services::field::{RichTextTypeOptionPB, TextCellData};
 use crate::services::field::{RichTextTypeOptionPB, TextCellData};
 use flowy_error::FlowyResult;
 use flowy_error::FlowyResult;
 
 
-impl TextFilterConfigurationPB {
+impl TextFilterPB {
     pub fn is_visible<T: AsRef<str>>(&self, cell_data: T) -> bool {
     pub fn is_visible<T: AsRef<str>>(&self, cell_data: T) -> bool {
-        let cell_data = cell_data.as_ref();
-        let s = cell_data.to_lowercase();
-        if let Some(content) = self.content.as_ref() {
-            match self.condition {
-                TextFilterCondition::Is => &s == content,
-                TextFilterCondition::IsNot => &s != content,
-                TextFilterCondition::Contains => s.contains(content),
-                TextFilterCondition::DoesNotContain => !s.contains(content),
-                TextFilterCondition::StartsWith => s.starts_with(content),
-                TextFilterCondition::EndsWith => s.ends_with(content),
-                TextFilterCondition::TextIsEmpty => s.is_empty(),
-                TextFilterCondition::TextIsNotEmpty => !s.is_empty(),
-            }
-        } else {
-            false
+        let cell_data = cell_data.as_ref().to_lowercase();
+        let content = &self.content.to_lowercase();
+        match self.condition {
+            TextFilterCondition::Is => &cell_data == content,
+            TextFilterCondition::IsNot => &cell_data != content,
+            TextFilterCondition::Contains => cell_data.contains(content),
+            TextFilterCondition::DoesNotContain => !cell_data.contains(content),
+            TextFilterCondition::StartsWith => cell_data.starts_with(content),
+            TextFilterCondition::EndsWith => cell_data.ends_with(content),
+            TextFilterCondition::TextIsEmpty => cell_data.is_empty(),
+            TextFilterCondition::TextIsNotEmpty => !cell_data.is_empty(),
         }
         }
     }
     }
 }
 }
 
 
-impl CellFilterOperation<TextFilterConfigurationPB> for RichTextTypeOptionPB {
-    fn apply_filter(&self, any_cell_data: AnyCellData, filter: &TextFilterConfigurationPB) -> FlowyResult<bool> {
+impl CellFilterOperation<TextFilterPB> for RichTextTypeOptionPB {
+    fn apply_filter(&self, any_cell_data: AnyCellData, filter: &TextFilterPB) -> FlowyResult<bool> {
         if !any_cell_data.is_text() {
         if !any_cell_data.is_text() {
             return Ok(true);
             return Ok(true);
         }
         }
@@ -38,13 +34,13 @@ impl CellFilterOperation<TextFilterConfigurationPB> for RichTextTypeOptionPB {
 #[cfg(test)]
 #[cfg(test)]
 mod tests {
 mod tests {
     #![allow(clippy::all)]
     #![allow(clippy::all)]
-    use crate::entities::{TextFilterCondition, TextFilterConfigurationPB};
+    use crate::entities::{TextFilterCondition, TextFilterPB};
 
 
     #[test]
     #[test]
     fn text_filter_equal_test() {
     fn text_filter_equal_test() {
-        let text_filter = TextFilterConfigurationPB {
+        let text_filter = TextFilterPB {
             condition: TextFilterCondition::Is,
             condition: TextFilterCondition::Is,
-            content: Some("appflowy".to_owned()),
+            content: "appflowy".to_owned(),
         };
         };
 
 
         assert!(text_filter.is_visible("AppFlowy"));
         assert!(text_filter.is_visible("AppFlowy"));
@@ -54,9 +50,9 @@ mod tests {
     }
     }
     #[test]
     #[test]
     fn text_filter_start_with_test() {
     fn text_filter_start_with_test() {
-        let text_filter = TextFilterConfigurationPB {
+        let text_filter = TextFilterPB {
             condition: TextFilterCondition::StartsWith,
             condition: TextFilterCondition::StartsWith,
-            content: Some("appflowy".to_owned()),
+            content: "appflowy".to_owned(),
         };
         };
 
 
         assert_eq!(text_filter.is_visible("AppFlowy.io"), true);
         assert_eq!(text_filter.is_visible("AppFlowy.io"), true);
@@ -66,9 +62,9 @@ mod tests {
 
 
     #[test]
     #[test]
     fn text_filter_end_with_test() {
     fn text_filter_end_with_test() {
-        let text_filter = TextFilterConfigurationPB {
+        let text_filter = TextFilterPB {
             condition: TextFilterCondition::EndsWith,
             condition: TextFilterCondition::EndsWith,
-            content: Some("appflowy".to_owned()),
+            content: "appflowy".to_owned(),
         };
         };
 
 
         assert_eq!(text_filter.is_visible("https://github.com/appflowy"), true);
         assert_eq!(text_filter.is_visible("https://github.com/appflowy"), true);
@@ -77,9 +73,9 @@ mod tests {
     }
     }
     #[test]
     #[test]
     fn text_filter_empty_test() {
     fn text_filter_empty_test() {
-        let text_filter = TextFilterConfigurationPB {
+        let text_filter = TextFilterPB {
             condition: TextFilterCondition::TextIsEmpty,
             condition: TextFilterCondition::TextIsEmpty,
-            content: Some("appflowy".to_owned()),
+            content: "appflowy".to_owned(),
         };
         };
 
 
         assert_eq!(text_filter.is_visible(""), true);
         assert_eq!(text_filter.is_visible(""), true);
@@ -87,9 +83,9 @@ mod tests {
     }
     }
     #[test]
     #[test]
     fn text_filter_contain_test() {
     fn text_filter_contain_test() {
-        let text_filter = TextFilterConfigurationPB {
+        let text_filter = TextFilterPB {
             condition: TextFilterCondition::Contains,
             condition: TextFilterCondition::Contains,
-            content: Some("appflowy".to_owned()),
+            content: "appflowy".to_owned(),
         };
         };
 
 
         assert_eq!(text_filter.is_visible("https://github.com/appflowy"), true);
         assert_eq!(text_filter.is_visible("https://github.com/appflowy"), true);

+ 1 - 0
frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/mod.rs

@@ -1,4 +1,5 @@
 #![allow(clippy::module_inception)]
 #![allow(clippy::module_inception)]
+mod url_filter;
 mod url_tests;
 mod url_tests;
 mod url_type_option;
 mod url_type_option;
 mod url_type_option_entities;
 mod url_type_option_entities;

+ 3 - 3
frontend/rust-lib/flowy-grid/src/services/filter/impls/url_filter.rs → frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_filter.rs

@@ -1,10 +1,10 @@
-use crate::entities::TextFilterConfigurationPB;
+use crate::entities::TextFilterPB;
 use crate::services::cell::{AnyCellData, CellData, CellFilterOperation};
 use crate::services::cell::{AnyCellData, CellData, CellFilterOperation};
 use crate::services::field::{TextCellData, URLTypeOptionPB};
 use crate::services::field::{TextCellData, URLTypeOptionPB};
 use flowy_error::FlowyResult;
 use flowy_error::FlowyResult;
 
 
-impl CellFilterOperation<TextFilterConfigurationPB> for URLTypeOptionPB {
-    fn apply_filter(&self, any_cell_data: AnyCellData, filter: &TextFilterConfigurationPB) -> FlowyResult<bool> {
+impl CellFilterOperation<TextFilterPB> for URLTypeOptionPB {
+    fn apply_filter(&self, any_cell_data: AnyCellData, filter: &TextFilterPB) -> FlowyResult<bool> {
         if !any_cell_data.is_url() {
         if !any_cell_data.is_url() {
             return Ok(true);
             return Ok(true);
         }
         }

+ 94 - 0
frontend/rust-lib/flowy-grid/src/services/filter/cache.rs

@@ -0,0 +1,94 @@
+use crate::entities::{CheckboxFilterPB, DateFilterPB, FieldType, NumberFilterPB, SelectOptionFilterPB, TextFilterPB};
+use crate::services::filter::FilterType;
+
+use std::collections::HashMap;
+
+#[derive(Default)]
+pub(crate) struct FilterMap {
+    pub(crate) text_filter: HashMap<FilterType, TextFilterPB>,
+    pub(crate) url_filter: HashMap<FilterType, TextFilterPB>,
+    pub(crate) number_filter: HashMap<FilterType, NumberFilterPB>,
+    pub(crate) date_filter: HashMap<FilterType, DateFilterPB>,
+    pub(crate) select_option_filter: HashMap<FilterType, SelectOptionFilterPB>,
+    pub(crate) checkbox_filter: HashMap<FilterType, CheckboxFilterPB>,
+}
+
+impl FilterMap {
+    pub(crate) fn new() -> Self {
+        Self::default()
+    }
+
+    pub(crate) fn is_empty(&self) -> bool {
+        if !self.text_filter.is_empty() {
+            return false;
+        }
+
+        if !self.url_filter.is_empty() {
+            return false;
+        }
+
+        if !self.number_filter.is_empty() {
+            return false;
+        }
+
+        if !self.number_filter.is_empty() {
+            return false;
+        }
+
+        if !self.date_filter.is_empty() {
+            return false;
+        }
+
+        if !self.select_option_filter.is_empty() {
+            return false;
+        }
+
+        if !self.checkbox_filter.is_empty() {
+            return false;
+        }
+        true
+    }
+
+    pub(crate) fn remove(&mut self, filter_id: &FilterType) {
+        let _ = match filter_id.field_type {
+            FieldType::RichText => {
+                let _ = self.text_filter.remove(filter_id);
+            }
+            FieldType::Number => {
+                let _ = self.number_filter.remove(filter_id);
+            }
+            FieldType::DateTime => {
+                let _ = self.date_filter.remove(filter_id);
+            }
+            FieldType::SingleSelect => {
+                let _ = self.select_option_filter.remove(filter_id);
+            }
+            FieldType::MultiSelect => {
+                let _ = self.select_option_filter.remove(filter_id);
+            }
+            FieldType::Checkbox => {
+                let _ = self.checkbox_filter.remove(filter_id);
+            }
+            FieldType::URL => {
+                let _ = self.url_filter.remove(filter_id);
+            }
+        };
+    }
+}
+
+/// Refresh the filter according to the field id.
+#[derive(Default)]
+pub(crate) struct FilterResult {
+    pub(crate) visible_by_filter_id: HashMap<FilterType, bool>,
+}
+
+impl FilterResult {
+    pub(crate) fn is_visible(&self) -> bool {
+        for visible in self.visible_by_filter_id.values() {
+            if visible == &false {
+                return false;
+            }
+        }
+        true
+    }
+}

+ 405 - 0
frontend/rust-lib/flowy-grid/src/services/filter/controller.rs

@@ -0,0 +1,405 @@
+use crate::dart_notification::{send_dart_notification, GridNotification};
+use crate::entities::filter_entities::*;
+use crate::entities::setting_entities::*;
+use crate::entities::{FieldType, GridBlockChangesetPB};
+use crate::services::cell::{AnyCellData, CellFilterOperation};
+use crate::services::field::*;
+use crate::services::filter::{FilterMap, FilterResult, FILTER_HANDLER_ID};
+use crate::services::row::GridBlock;
+use flowy_error::FlowyResult;
+use flowy_task::{QualityOfService, Task, TaskContent, TaskDispatcher};
+use grid_rev_model::{CellRevision, FieldId, FieldRevision, FieldTypeRevision, FilterRevision, RowRevision};
+use lib_infra::future::Fut;
+use std::collections::HashMap;
+use std::sync::Arc;
+use tokio::sync::RwLock;
+
+type RowId = String;
+pub trait GridViewFilterDelegate: Send + Sync + 'static {
+    fn get_filter_rev(&self, filter_id: FilterType) -> Fut<Vec<Arc<FilterRevision>>>;
+    fn get_field_rev(&self, field_id: &str) -> Fut<Option<Arc<FieldRevision>>>;
+    fn get_field_revs(&self, field_ids: Option<Vec<String>>) -> Fut<Vec<Arc<FieldRevision>>>;
+    fn get_blocks(&self) -> Fut<Vec<GridBlock>>;
+}
+
+pub struct FilterController {
+    view_id: String,
+    delegate: Box<dyn GridViewFilterDelegate>,
+    filter_map: FilterMap,
+    result_by_row_id: HashMap<RowId, FilterResult>,
+    task_scheduler: Arc<RwLock<TaskDispatcher>>,
+}
+impl FilterController {
+    pub async fn new<T>(
+        view_id: &str,
+        delegate: T,
+        task_scheduler: Arc<RwLock<TaskDispatcher>>,
+        filter_revs: Vec<Arc<FilterRevision>>,
+    ) -> Self
+    where
+        T: GridViewFilterDelegate,
+    {
+        let mut this = Self {
+            view_id: view_id.to_string(),
+            delegate: Box::new(delegate),
+            filter_map: FilterMap::new(),
+            result_by_row_id: HashMap::default(),
+            task_scheduler,
+        };
+        this.load_filters(filter_revs).await;
+        this
+    }
+
+    pub async fn close(&self) {
+        self.task_scheduler.write().await.unregister_handler(FILTER_HANDLER_ID);
+    }
+
+    #[tracing::instrument(name = "schedule_filter_task", level = "trace", skip(self))]
+    async fn gen_task(&mut self, predicate: &str) {
+        let task_id = self.task_scheduler.read().await.next_task_id();
+        let task = Task::new(
+            FILTER_HANDLER_ID,
+            task_id,
+            TaskContent::Text(predicate.to_owned()),
+            QualityOfService::UserInteractive,
+        );
+        self.task_scheduler.write().await.add_task(task);
+    }
+
+    pub async fn filter_row_revs(&mut self, row_revs: &mut Vec<Arc<RowRevision>>) {
+        if self.filter_map.is_empty() {
+            return;
+        }
+        let field_rev_by_field_id = self.get_filter_revs_map().await;
+        let _ = row_revs
+            .iter()
+            .flat_map(|row_rev| {
+                filter_row(
+                    row_rev,
+                    &self.filter_map,
+                    &mut self.result_by_row_id,
+                    &field_rev_by_field_id,
+                )
+            })
+            .collect::<Vec<String>>();
+
+        row_revs.retain(|row_rev| {
+            self.result_by_row_id
+                .get(&row_rev.id)
+                .map(|result| result.is_visible())
+                .unwrap_or(false)
+        });
+    }
+
+    async fn get_filter_revs_map(&self) -> HashMap<String, Arc<FieldRevision>> {
+        self.delegate
+            .get_field_revs(None)
+            .await
+            .into_iter()
+            .map(|field_rev| (field_rev.id.clone(), field_rev))
+            .collect::<HashMap<String, Arc<FieldRevision>>>()
+    }
+
+    pub async fn process(&mut self, _predicate: &str) -> FlowyResult<()> {
+        let field_rev_by_field_id = self.get_filter_revs_map().await;
+        let mut changesets = vec![];
+        for block in self.delegate.get_blocks().await.into_iter() {
+            // The row_ids contains the row that its visibility was changed.
+            let row_ids = block
+                .row_revs
+                .iter()
+                .flat_map(|row_rev| {
+                    filter_row(
+                        row_rev,
+                        &self.filter_map,
+                        &mut self.result_by_row_id,
+                        &field_rev_by_field_id,
+                    )
+                })
+                .collect::<Vec<String>>();
+
+            let mut visible_rows = vec![];
+            let mut hide_rows = vec![];
+
+            // Query the filter result from the cache
+            for row_id in row_ids {
+                if self
+                    .result_by_row_id
+                    .get(&row_id)
+                    .map(|result| result.is_visible())
+                    .unwrap_or(false)
+                {
+                    visible_rows.push(row_id);
+                } else {
+                    hide_rows.push(row_id);
+                }
+            }
+
+            let changeset = GridBlockChangesetPB {
+                block_id: block.block_id,
+                hide_rows,
+                visible_rows,
+                ..Default::default()
+            };
+
+            // Save the changeset for each block
+            changesets.push(changeset);
+        }
+
+        self.notify(changesets).await;
+        Ok(())
+    }
+
+    pub async fn apply_changeset(&mut self, changeset: FilterChangeset) {
+        if let Some(filter_id) = &changeset.insert_filter {
+            let filter_revs = self.delegate.get_filter_rev(filter_id.clone()).await;
+            let _ = self.load_filters(filter_revs).await;
+        }
+
+        if let Some(filter_id) = &changeset.delete_filter {
+            self.filter_map.remove(filter_id);
+        }
+
+        self.gen_task("").await;
+    }
+
+    async fn notify(&self, changesets: Vec<GridBlockChangesetPB>) {
+        for changeset in changesets {
+            send_dart_notification(&self.view_id, GridNotification::DidUpdateGridBlock)
+                .payload(changeset)
+                .send();
+        }
+    }
+
+    async fn load_filters(&mut 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);
+                let field_type: FieldType = field_rev.ty.into();
+                match &field_type {
+                    FieldType::RichText => {
+                        let _ = self
+                            .filter_map
+                            .text_filter
+                            .insert(filter_type, TextFilterPB::from(filter_rev));
+                    }
+                    FieldType::Number => {
+                        let _ = self
+                            .filter_map
+                            .number_filter
+                            .insert(filter_type, NumberFilterPB::from(filter_rev));
+                    }
+                    FieldType::DateTime => {
+                        let _ = self
+                            .filter_map
+                            .date_filter
+                            .insert(filter_type, DateFilterPB::from(filter_rev));
+                    }
+                    FieldType::SingleSelect | FieldType::MultiSelect => {
+                        let _ = self
+                            .filter_map
+                            .select_option_filter
+                            .insert(filter_type, SelectOptionFilterPB::from(filter_rev));
+                    }
+                    FieldType::Checkbox => {
+                        let _ = self
+                            .filter_map
+                            .checkbox_filter
+                            .insert(filter_type, CheckboxFilterPB::from(filter_rev));
+                    }
+                    FieldType::URL => {
+                        let _ = self
+                            .filter_map
+                            .url_filter
+                            .insert(filter_type, TextFilterPB::from(filter_rev));
+                    }
+                }
+            }
+        }
+    }
+}
+
+/// Returns None if there is no change in this row after applying the filter
+fn filter_row(
+    row_rev: &Arc<RowRevision>,
+    filter_map: &FilterMap,
+    result_by_row_id: &mut HashMap<RowId, FilterResult>,
+    field_rev_by_field_id: &HashMap<FieldId, Arc<FieldRevision>>,
+) -> Option<String> {
+    // Create a filter result cache if it's not exist
+    let filter_result = result_by_row_id
+        .entry(row_rev.id.clone())
+        .or_insert_with(FilterResult::default);
+
+    // Iterate each cell of the row to check its visibility
+    for (field_id, cell_rev) in row_rev.cells.iter() {
+        let field_rev = field_rev_by_field_id.get(field_id)?;
+        let filter_type = FilterType::from(field_rev);
+
+        // if the visibility of the cell_rew is changed, which means the visibility of the
+        // row is changed too.
+        if let Some(is_visible) = filter_cell(&filter_type, field_rev, filter_map, cell_rev) {
+            let prev_is_visible = filter_result.visible_by_filter_id.get(&filter_type).cloned();
+            filter_result.visible_by_filter_id.insert(filter_type, is_visible);
+            match prev_is_visible {
+                None => {
+                    if !is_visible {
+                        return Some(row_rev.id.clone());
+                    }
+                }
+                Some(prev_is_visible) => {
+                    if prev_is_visible != is_visible {
+                        return Some(row_rev.id.clone());
+                    }
+                }
+            }
+        }
+    }
+    None
+}
+
+// Return None if there is no change in this cell after applying the filter
+fn filter_cell(
+    filter_id: &FilterType,
+    field_rev: &Arc<FieldRevision>,
+    filter_map: &FilterMap,
+    cell_rev: &CellRevision,
+) -> Option<bool> {
+    let any_cell_data = AnyCellData::try_from(cell_rev).ok()?;
+    let is_visible = match &filter_id.field_type {
+        FieldType::RichText => filter_map.text_filter.get(filter_id).and_then(|filter| {
+            Some(
+                field_rev
+                    .get_type_option::<RichTextTypeOptionPB>(field_rev.ty)?
+                    .apply_filter(any_cell_data, filter)
+                    .ok(),
+            )
+        }),
+        FieldType::Number => filter_map.number_filter.get(filter_id).and_then(|filter| {
+            Some(
+                field_rev
+                    .get_type_option::<NumberTypeOptionPB>(field_rev.ty)?
+                    .apply_filter(any_cell_data, filter)
+                    .ok(),
+            )
+        }),
+        FieldType::DateTime => filter_map.date_filter.get(filter_id).and_then(|filter| {
+            Some(
+                field_rev
+                    .get_type_option::<DateTypeOptionPB>(field_rev.ty)?
+                    .apply_filter(any_cell_data, filter)
+                    .ok(),
+            )
+        }),
+        FieldType::SingleSelect => filter_map.select_option_filter.get(filter_id).and_then(|filter| {
+            Some(
+                field_rev
+                    .get_type_option::<SingleSelectTypeOptionPB>(field_rev.ty)?
+                    .apply_filter(any_cell_data, filter)
+                    .ok(),
+            )
+        }),
+        FieldType::MultiSelect => filter_map.select_option_filter.get(filter_id).and_then(|filter| {
+            Some(
+                field_rev
+                    .get_type_option::<MultiSelectTypeOptionPB>(field_rev.ty)?
+                    .apply_filter(any_cell_data, filter)
+                    .ok(),
+            )
+        }),
+        FieldType::Checkbox => filter_map.checkbox_filter.get(filter_id).and_then(|filter| {
+            Some(
+                field_rev
+                    .get_type_option::<CheckboxTypeOptionPB>(field_rev.ty)?
+                    .apply_filter(any_cell_data, filter)
+                    .ok(),
+            )
+        }),
+        FieldType::URL => filter_map.url_filter.get(filter_id).and_then(|filter| {
+            Some(
+                field_rev
+                    .get_type_option::<URLTypeOptionPB>(field_rev.ty)?
+                    .apply_filter(any_cell_data, filter)
+                    .ok(),
+            )
+        }),
+    }?;
+
+    is_visible
+}
+
+pub struct FilterChangeset {
+    insert_filter: Option<FilterType>,
+    delete_filter: Option<FilterType>,
+}
+
+impl FilterChangeset {
+    pub fn from_insert(filter_id: FilterType) -> Self {
+        Self {
+            insert_filter: Some(filter_id),
+            delete_filter: None,
+        }
+    }
+
+    pub fn from_delete(filter_id: FilterType) -> Self {
+        Self {
+            insert_filter: None,
+            delete_filter: Some(filter_id),
+        }
+    }
+}
+
+impl std::convert::From<&GridSettingChangesetParams> for FilterChangeset {
+    fn from(params: &GridSettingChangesetParams) -> Self {
+        let insert_filter = params.insert_filter.as_ref().map(|insert_filter_params| FilterType {
+            field_id: insert_filter_params.field_id.clone(),
+            field_type: insert_filter_params.field_type_rev.into(),
+        });
+
+        let delete_filter = params
+            .delete_filter
+            .as_ref()
+            .map(|delete_filter_params| delete_filter_params.filter_type.clone());
+        FilterChangeset {
+            insert_filter,
+            delete_filter,
+        }
+    }
+}
+
+#[derive(Hash, Eq, PartialEq, Clone)]
+pub struct FilterType {
+    pub field_id: String,
+    pub field_type: FieldType,
+}
+
+impl FilterType {
+    pub fn field_type_rev(&self) -> FieldTypeRevision {
+        self.field_type.clone().into()
+    }
+}
+
+impl std::convert::From<&Arc<FieldRevision>> for FilterType {
+    fn from(rev: &Arc<FieldRevision>) -> Self {
+        Self {
+            field_id: rev.id.clone(),
+            field_type: rev.ty.into(),
+        }
+    }
+}
+
+impl std::convert::From<&CreateFilterParams> for FilterType {
+    fn from(params: &CreateFilterParams) -> Self {
+        let field_type: FieldType = params.field_type_rev.into();
+        Self {
+            field_id: params.field_id.clone(),
+            field_type,
+        }
+    }
+}
+
+impl std::convert::From<&DeleteFilterParams> for FilterType {
+    fn from(params: &DeleteFilterParams) -> Self {
+        params.filter_type.clone()
+    }
+}

+ 0 - 171
frontend/rust-lib/flowy-grid/src/services/filter/filter_cache.rs

@@ -1,171 +0,0 @@
-use crate::entities::{
-    CheckboxFilterConfigurationPB, DateFilterConfigurationPB, FieldType, NumberFilterConfigurationPB,
-    SelectOptionFilterConfigurationPB, TextFilterConfigurationPB,
-};
-use dashmap::DashMap;
-use flowy_sync::client_grid::GridRevisionPad;
-use grid_rev_model::{FieldRevision, FilterConfigurationRevision, RowRevision};
-use std::collections::HashMap;
-use std::sync::Arc;
-use tokio::sync::RwLock;
-
-type RowId = String;
-
-#[derive(Default)]
-pub(crate) struct FilterResultCache {
-    // key: row id
-    inner: DashMap<RowId, FilterResult>,
-}
-
-impl FilterResultCache {
-    pub fn new() -> Arc<Self> {
-        let this = Self::default();
-        Arc::new(this)
-    }
-}
-
-impl std::ops::Deref for FilterResultCache {
-    type Target = DashMap<String, FilterResult>;
-
-    fn deref(&self) -> &Self::Target {
-        &self.inner
-    }
-}
-
-#[derive(Default)]
-pub(crate) struct FilterResult {
-    #[allow(dead_code)]
-    pub(crate) row_index: i32,
-    pub(crate) visible_by_field_id: HashMap<FilterId, bool>,
-}
-
-impl FilterResult {
-    pub(crate) fn new(index: i32, _row_rev: &RowRevision) -> Self {
-        Self {
-            row_index: index,
-            visible_by_field_id: HashMap::new(),
-        }
-    }
-
-    pub(crate) fn is_visible(&self) -> bool {
-        for visible in self.visible_by_field_id.values() {
-            if visible == &false {
-                return false;
-            }
-        }
-        true
-    }
-}
-
-#[derive(Default)]
-pub(crate) struct FilterCache {
-    pub(crate) text_filter: DashMap<FilterId, TextFilterConfigurationPB>,
-    pub(crate) url_filter: DashMap<FilterId, TextFilterConfigurationPB>,
-    pub(crate) number_filter: DashMap<FilterId, NumberFilterConfigurationPB>,
-    pub(crate) date_filter: DashMap<FilterId, DateFilterConfigurationPB>,
-    pub(crate) select_option_filter: DashMap<FilterId, SelectOptionFilterConfigurationPB>,
-    pub(crate) checkbox_filter: DashMap<FilterId, CheckboxFilterConfigurationPB>,
-}
-
-impl FilterCache {
-    pub(crate) async fn from_grid_pad(grid_pad: &Arc<RwLock<GridRevisionPad>>) -> Arc<Self> {
-        let this = Arc::new(Self::default());
-        let _ = refresh_filter_cache(this.clone(), None, grid_pad).await;
-        this
-    }
-
-    #[allow(dead_code)]
-    pub(crate) fn remove(&self, filter_id: &FilterId) {
-        let _ = match filter_id.field_type {
-            FieldType::RichText => {
-                let _ = self.text_filter.remove(filter_id);
-            }
-            FieldType::Number => {
-                let _ = self.number_filter.remove(filter_id);
-            }
-            FieldType::DateTime => {
-                let _ = self.date_filter.remove(filter_id);
-            }
-            FieldType::SingleSelect => {
-                let _ = self.select_option_filter.remove(filter_id);
-            }
-            FieldType::MultiSelect => {
-                let _ = self.select_option_filter.remove(filter_id);
-            }
-            FieldType::Checkbox => {
-                let _ = self.checkbox_filter.remove(filter_id);
-            }
-            FieldType::URL => {
-                let _ = self.url_filter.remove(filter_id);
-            }
-        };
-    }
-}
-
-/// Refresh the filter according to the field id.
-pub(crate) async fn refresh_filter_cache(
-    cache: Arc<FilterCache>,
-    _field_ids: Option<Vec<String>>,
-    grid_pad: &Arc<RwLock<GridRevisionPad>>,
-) {
-    let grid_pad = grid_pad.read().await;
-    // let filters_revs = grid_pad.get_filters(field_ids).unwrap_or_default();
-    // TODO nathan
-    let filter_revs: Vec<Arc<FilterConfigurationRevision>> = vec![];
-
-    for filter_rev in filter_revs {
-        match grid_pad.get_field_rev(&filter_rev.field_id) {
-            None => {}
-            Some((_, field_rev)) => {
-                let filter_id = FilterId::from(field_rev);
-                let field_type: FieldType = field_rev.ty.into();
-                match &field_type {
-                    FieldType::RichText => {
-                        let _ = cache
-                            .text_filter
-                            .insert(filter_id, TextFilterConfigurationPB::from(filter_rev));
-                    }
-                    FieldType::Number => {
-                        let _ = cache
-                            .number_filter
-                            .insert(filter_id, NumberFilterConfigurationPB::from(filter_rev));
-                    }
-                    FieldType::DateTime => {
-                        let _ = cache
-                            .date_filter
-                            .insert(filter_id, DateFilterConfigurationPB::from(filter_rev));
-                    }
-                    FieldType::SingleSelect | FieldType::MultiSelect => {
-                        let _ = cache
-                            .select_option_filter
-                            .insert(filter_id, SelectOptionFilterConfigurationPB::from(filter_rev));
-                    }
-                    FieldType::Checkbox => {
-                        let _ = cache
-                            .checkbox_filter
-                            .insert(filter_id, CheckboxFilterConfigurationPB::from(filter_rev));
-                    }
-                    FieldType::URL => {
-                        let _ = cache
-                            .url_filter
-                            .insert(filter_id, TextFilterConfigurationPB::from(filter_rev));
-                    }
-                }
-            }
-        }
-    }
-}
-#[derive(Hash, Eq, PartialEq)]
-pub(crate) struct FilterId {
-    pub(crate) field_id: String,
-    pub(crate) field_type: FieldType,
-}
-
-impl std::convert::From<&Arc<FieldRevision>> for FilterId {
-    fn from(rev: &Arc<FieldRevision>) -> Self {
-        Self {
-            field_id: rev.id.clone(),
-            field_type: rev.ty.into(),
-        }
-    }
-}

+ 0 - 294
frontend/rust-lib/flowy-grid/src/services/filter/filter_service.rs

@@ -1,294 +0,0 @@
-#![allow(clippy::all)]
-#![allow(unused_attributes)]
-#![allow(dead_code)]
-#![allow(unused_imports)]
-#![allow(unused_results)]
-use crate::dart_notification::{send_dart_notification, GridNotification};
-use crate::entities::{FieldType, GridBlockChangesetPB, GridSettingChangesetParams};
-use crate::services::block_manager::GridBlockManager;
-use crate::services::cell::{AnyCellData, CellFilterOperation};
-use crate::services::field::{
-    CheckboxTypeOptionPB, DateTypeOptionPB, MultiSelectTypeOptionPB, NumberTypeOptionPB, RichTextTypeOptionPB,
-    SingleSelectTypeOptionPB, URLTypeOptionPB,
-};
-use crate::services::filter::filter_cache::{
-    refresh_filter_cache, FilterCache, FilterId, FilterResult, FilterResultCache,
-};
-use crate::services::grid_editor_task::GridServiceTaskScheduler;
-use crate::services::row::GridBlockSnapshot;
-use crate::services::tasks::{FilterTaskContext, Task, TaskContent};
-use flowy_error::FlowyResult;
-use flowy_sync::client_grid::GridRevisionPad;
-use grid_rev_model::{CellRevision, FieldId, FieldRevision, RowRevision};
-use rayon::prelude::*;
-use std::collections::HashMap;
-use std::sync::Arc;
-use tokio::sync::RwLock;
-
-pub(crate) struct GridFilterService {
-    #[allow(dead_code)]
-    scheduler: Arc<dyn GridServiceTaskScheduler>,
-    grid_pad: Arc<RwLock<GridRevisionPad>>,
-    #[allow(dead_code)]
-    block_manager: Arc<GridBlockManager>,
-    filter_cache: Arc<FilterCache>,
-    filter_result_cache: Arc<FilterResultCache>,
-}
-impl GridFilterService {
-    pub async fn new<S: GridServiceTaskScheduler>(
-        grid_pad: Arc<RwLock<GridRevisionPad>>,
-        block_manager: Arc<GridBlockManager>,
-        scheduler: S,
-    ) -> Self {
-        let scheduler = Arc::new(scheduler);
-        let filter_cache = FilterCache::from_grid_pad(&grid_pad).await;
-        let filter_result_cache = FilterResultCache::new();
-        Self {
-            grid_pad,
-            block_manager,
-            scheduler,
-            filter_cache,
-            filter_result_cache,
-        }
-    }
-
-    pub async fn process(&self, task_context: FilterTaskContext) -> FlowyResult<()> {
-        let field_revs = self
-            .grid_pad
-            .read()
-            .await
-            .get_field_revs(None)?
-            .into_iter()
-            .map(|field_rev| (field_rev.id.clone(), field_rev))
-            .collect::<HashMap<String, Arc<FieldRevision>>>();
-
-        let mut changesets = vec![];
-        for (index, block) in task_context.blocks.into_iter().enumerate() {
-            // The row_ids contains the row that its visibility was changed.
-            let row_ids = block
-                .row_revs
-                .par_iter()
-                .flat_map(|row_rev| {
-                    let filter_result_cache = self.filter_result_cache.clone();
-                    let filter_cache = self.filter_cache.clone();
-                    filter_row(index, row_rev, filter_cache, filter_result_cache, &field_revs)
-                })
-                .collect::<Vec<String>>();
-
-            let mut visible_rows = vec![];
-            let mut hide_rows = vec![];
-
-            // Query the filter result from the cache
-            for row_id in row_ids {
-                if self
-                    .filter_result_cache
-                    .get(&row_id)
-                    .map(|result| result.is_visible())
-                    .unwrap_or(false)
-                {
-                    visible_rows.push(row_id);
-                } else {
-                    hide_rows.push(row_id);
-                }
-            }
-
-            let changeset = GridBlockChangesetPB {
-                block_id: block.block_id,
-                hide_rows,
-                visible_rows,
-                ..Default::default()
-            };
-
-            // Save the changeset for each block
-            changesets.push(changeset);
-        }
-
-        self.notify(changesets).await;
-        Ok(())
-    }
-
-    pub async fn apply_changeset(&self, changeset: GridFilterChangeset) {
-        if !changeset.is_changed() {
-            return;
-        }
-
-        if let Some(filter_id) = &changeset.insert_filter {
-            let field_ids = Some(vec![filter_id.field_id.clone()]);
-            refresh_filter_cache(self.filter_cache.clone(), field_ids, &self.grid_pad).await;
-        }
-
-        if let Some(filter_id) = &changeset.delete_filter {
-            self.filter_cache.remove(filter_id);
-        }
-
-        if let Ok(blocks) = self.block_manager.get_block_snapshots(None).await {
-            let _task = self.gen_task(blocks).await;
-            // let _ = self.scheduler.register_task(task).await;
-        }
-    }
-
-    async fn gen_task(&self, blocks: Vec<GridBlockSnapshot>) -> Task {
-        let task_id = self.scheduler.gen_task_id().await;
-        let handler_id = self.grid_pad.read().await.grid_id();
-
-        let context = FilterTaskContext { blocks };
-        Task::new(&handler_id, task_id, TaskContent::Filter(context))
-    }
-
-    async fn notify(&self, changesets: Vec<GridBlockChangesetPB>) {
-        let grid_id = self.grid_pad.read().await.grid_id();
-        for changeset in changesets {
-            send_dart_notification(&grid_id, GridNotification::DidUpdateGridBlock)
-                .payload(changeset)
-                .send();
-        }
-    }
-}
-
-// Return None if there is no change in this row after applying the filter
-fn filter_row(
-    index: usize,
-    row_rev: &Arc<RowRevision>,
-    filter_cache: Arc<FilterCache>,
-    filter_result_cache: Arc<FilterResultCache>,
-    field_revs: &HashMap<FieldId, Arc<FieldRevision>>,
-) -> Option<String> {
-    let mut result = filter_result_cache
-        .entry(row_rev.id.clone())
-        .or_insert(FilterResult::new(index as i32, row_rev));
-
-    for (field_id, cell_rev) in row_rev.cells.iter() {
-        match filter_cell(field_revs, result.value_mut(), &filter_cache, field_id, cell_rev) {
-            None => {}
-            Some(_) => {
-                return Some(row_rev.id.clone());
-            }
-        }
-    }
-    None
-}
-
-// Return None if there is no change in this cell after applying the filter
-fn filter_cell(
-    field_revs: &HashMap<FieldId, Arc<FieldRevision>>,
-    filter_result: &mut FilterResult,
-    filter_cache: &Arc<FilterCache>,
-    field_id: &str,
-    cell_rev: &CellRevision,
-) -> Option<()> {
-    let field_rev = field_revs.get(field_id)?;
-    let field_type = FieldType::from(field_rev.ty);
-    let field_type_rev = field_type.clone().into();
-    let filter_id = FilterId {
-        field_id: field_id.to_owned(),
-        field_type,
-    };
-    let any_cell_data = AnyCellData::try_from(cell_rev).ok()?;
-    let is_visible = match &filter_id.field_type {
-        FieldType::RichText => filter_cache.text_filter.get(&filter_id).and_then(|filter| {
-            Some(
-                field_rev
-                    .get_type_option::<RichTextTypeOptionPB>(field_type_rev)?
-                    .apply_filter(any_cell_data, filter.value())
-                    .ok(),
-            )
-        }),
-        FieldType::Number => filter_cache.number_filter.get(&filter_id).and_then(|filter| {
-            Some(
-                field_rev
-                    .get_type_option::<NumberTypeOptionPB>(field_type_rev)?
-                    .apply_filter(any_cell_data, filter.value())
-                    .ok(),
-            )
-        }),
-        FieldType::DateTime => filter_cache.date_filter.get(&filter_id).and_then(|filter| {
-            Some(
-                field_rev
-                    .get_type_option::<DateTypeOptionPB>(field_type_rev)?
-                    .apply_filter(any_cell_data, filter.value())
-                    .ok(),
-            )
-        }),
-        FieldType::SingleSelect => filter_cache.select_option_filter.get(&filter_id).and_then(|filter| {
-            Some(
-                field_rev
-                    .get_type_option::<SingleSelectTypeOptionPB>(field_type_rev)?
-                    .apply_filter(any_cell_data, filter.value())
-                    .ok(),
-            )
-        }),
-        FieldType::MultiSelect => filter_cache.select_option_filter.get(&filter_id).and_then(|filter| {
-            Some(
-                field_rev
-                    .get_type_option::<MultiSelectTypeOptionPB>(field_type_rev)?
-                    .apply_filter(any_cell_data, filter.value())
-                    .ok(),
-            )
-        }),
-        FieldType::Checkbox => filter_cache.checkbox_filter.get(&filter_id).and_then(|filter| {
-            Some(
-                field_rev
-                    .get_type_option::<CheckboxTypeOptionPB>(field_type_rev)?
-                    .apply_filter(any_cell_data, filter.value())
-                    .ok(),
-            )
-        }),
-        FieldType::URL => filter_cache.url_filter.get(&filter_id).and_then(|filter| {
-            Some(
-                field_rev
-                    .get_type_option::<URLTypeOptionPB>(field_type_rev)?
-                    .apply_filter(any_cell_data, filter.value())
-                    .ok(),
-            )
-        }),
-    }?;
-
-    let is_visible = !is_visible.unwrap_or(true);
-    match filter_result.visible_by_field_id.get(&filter_id) {
-        None => {
-            if is_visible {
-                None
-            } else {
-                filter_result.visible_by_field_id.insert(filter_id, is_visible);
-                Some(())
-            }
-        }
-        Some(old_is_visible) => {
-            if old_is_visible != &is_visible {
-                filter_result.visible_by_field_id.insert(filter_id, is_visible);
-                Some(())
-            } else {
-                None
-            }
-        }
-    }
-}
-
-pub struct GridFilterChangeset {
-    insert_filter: Option<FilterId>,
-    delete_filter: Option<FilterId>,
-}
-
-impl GridFilterChangeset {
-    fn is_changed(&self) -> bool {
-        self.insert_filter.is_some() || self.delete_filter.is_some()
-    }
-}
-
-impl std::convert::From<&GridSettingChangesetParams> for GridFilterChangeset {
-    fn from(params: &GridSettingChangesetParams) -> Self {
-        let insert_filter = params.insert_filter.as_ref().map(|insert_filter_params| FilterId {
-            field_id: insert_filter_params.field_id.clone(),
-            field_type: insert_filter_params.field_type_rev.into(),
-        });
-
-        let delete_filter = params.delete_filter.as_ref().map(|delete_filter_params| FilterId {
-            field_id: delete_filter_params.filter_id.clone(),
-            field_type: delete_filter_params.field_type_rev.into(),
-        });
-        GridFilterChangeset {
-            insert_filter,
-            delete_filter,
-        }
-    }
-}

+ 0 - 13
frontend/rust-lib/flowy-grid/src/services/filter/impls/mod.rs

@@ -1,13 +0,0 @@
-mod checkbox_filter;
-mod date_filter;
-mod number_filter;
-mod select_option_filter;
-mod text_filter;
-mod url_filter;
-
-pub use checkbox_filter::*;
-pub use date_filter::*;
-pub use number_filter::*;
-pub use select_option_filter::*;
-pub use text_filter::*;
-pub use url_filter::*;

+ 6 - 4
frontend/rust-lib/flowy-grid/src/services/filter/mod.rs

@@ -1,5 +1,7 @@
-mod filter_cache;
-mod filter_service;
-mod impls;
+mod cache;
+mod controller;
+mod task;
 
 
-pub(crate) use filter_service::*;
+pub(crate) use cache::*;
+pub use controller::*;
+pub(crate) use task::*;

+ 35 - 0
frontend/rust-lib/flowy-grid/src/services/filter/task.rs

@@ -0,0 +1,35 @@
+use crate::services::filter::FilterController;
+use flowy_task::{TaskContent, TaskHandler};
+use lib_infra::future::BoxResultFuture;
+use std::sync::Arc;
+use tokio::sync::RwLock;
+
+pub const FILTER_HANDLER_ID: &str = "grid_filter";
+
+pub struct FilterTaskHandler(Arc<RwLock<FilterController>>);
+impl FilterTaskHandler {
+    pub fn new(filter_controller: Arc<RwLock<FilterController>>) -> Self {
+        Self(filter_controller)
+    }
+}
+
+impl TaskHandler for FilterTaskHandler {
+    fn handler_id(&self) -> &str {
+        FILTER_HANDLER_ID
+    }
+
+    fn run(&self, content: TaskContent) -> BoxResultFuture<(), anyhow::Error> {
+        let filter_controller = self.0.clone();
+        Box::pin(async move {
+            if let TaskContent::Text(predicate) = content {
+                let _ = filter_controller
+                    .write()
+                    .await
+                    .process(&predicate)
+                    .await
+                    .map_err(anyhow::Error::from);
+            }
+            Ok(())
+        })
+    }
+}

+ 71 - 80
frontend/rust-lib/flowy-grid/src/services/grid_editor.rs

@@ -1,19 +1,21 @@
 use crate::dart_notification::{send_dart_notification, GridNotification};
 use crate::dart_notification::{send_dart_notification, GridNotification};
 use crate::entities::GridCellIdParams;
 use crate::entities::GridCellIdParams;
 use crate::entities::*;
 use crate::entities::*;
-use crate::manager::{GridTaskSchedulerRwLock, GridUser};
+use crate::manager::GridUser;
 use crate::services::block_manager::GridBlockManager;
 use crate::services::block_manager::GridBlockManager;
-
 use crate::services::cell::{apply_cell_data_changeset, decode_any_cell_data, CellBytes};
 use crate::services::cell::{apply_cell_data_changeset, decode_any_cell_data, CellBytes};
 use crate::services::field::{
 use crate::services::field::{
     default_type_option_builder_from_type, type_option_builder_from_bytes, type_option_builder_from_json_str,
     default_type_option_builder_from_type, type_option_builder_from_bytes, type_option_builder_from_json_str,
     FieldBuilder,
     FieldBuilder,
 };
 };
-use crate::services::filter::GridFilterService;
+
+use crate::services::filter::FilterType;
+use crate::services::grid_editor_trait_impl::GridViewEditorDelegateImpl;
 use crate::services::grid_view_manager::GridViewManager;
 use crate::services::grid_view_manager::GridViewManager;
 use crate::services::persistence::block_index::BlockIndexCache;
 use crate::services::persistence::block_index::BlockIndexCache;
-use crate::services::row::{make_grid_blocks, make_rows_from_row_revs, GridBlockSnapshot, RowRevisionBuilder};
+use crate::services::row::{GridBlock, RowRevisionBuilder};
 use bytes::Bytes;
 use bytes::Bytes;
+use flowy_database::ConnectionPool;
 use flowy_error::{ErrorCode, FlowyError, FlowyResult};
 use flowy_error::{ErrorCode, FlowyError, FlowyResult};
 use flowy_http_model::revision::Revision;
 use flowy_http_model::revision::Revision;
 use flowy_revision::{
 use flowy_revision::{
@@ -22,10 +24,9 @@ use flowy_revision::{
 use flowy_sync::client_grid::{GridRevisionChangeset, GridRevisionPad, JsonDeserializer};
 use flowy_sync::client_grid::{GridRevisionChangeset, GridRevisionPad, JsonDeserializer};
 use flowy_sync::errors::{CollaborateError, CollaborateResult};
 use flowy_sync::errors::{CollaborateError, CollaborateResult};
 use flowy_sync::util::make_operations_from_revisions;
 use flowy_sync::util::make_operations_from_revisions;
+use flowy_task::TaskDispatcher;
 use grid_rev_model::*;
 use grid_rev_model::*;
-use lib_infra::future::{wrap_future, FutureResult};
-
-use flowy_database::ConnectionPool;
+use lib_infra::future::{to_future, FutureResult};
 use lib_ot::core::EmptyAttributes;
 use lib_ot::core::EmptyAttributes;
 use std::collections::HashMap;
 use std::collections::HashMap;
 use std::sync::Arc;
 use std::sync::Arc;
@@ -39,9 +40,6 @@ pub struct GridRevisionEditor {
     view_manager: Arc<GridViewManager>,
     view_manager: Arc<GridViewManager>,
     rev_manager: Arc<RevisionManager<Arc<ConnectionPool>>>,
     rev_manager: Arc<RevisionManager<Arc<ConnectionPool>>>,
     block_manager: Arc<GridBlockManager>,
     block_manager: Arc<GridBlockManager>,
-
-    #[allow(dead_code)]
-    pub(crate) filter_service: Arc<GridFilterService>,
 }
 }
 
 
 impl Drop for GridRevisionEditor {
 impl Drop for GridRevisionEditor {
@@ -56,7 +54,7 @@ impl GridRevisionEditor {
         user: Arc<dyn GridUser>,
         user: Arc<dyn GridUser>,
         mut rev_manager: RevisionManager<Arc<ConnectionPool>>,
         mut rev_manager: RevisionManager<Arc<ConnectionPool>>,
         persistence: Arc<BlockIndexCache>,
         persistence: Arc<BlockIndexCache>,
-        task_scheduler: GridTaskSchedulerRwLock,
+        task_scheduler: Arc<RwLock<TaskDispatcher>>,
     ) -> FlowyResult<Arc<Self>> {
     ) -> FlowyResult<Arc<Self>> {
         let token = user.token()?;
         let token = user.token()?;
         let cloud = Arc::new(GridRevisionCloudService { token });
         let cloud = Arc::new(GridRevisionCloudService { token });
@@ -67,20 +65,14 @@ impl GridRevisionEditor {
         // Block manager
         // Block manager
         let block_meta_revs = grid_pad.read().await.get_block_meta_revs();
         let block_meta_revs = grid_pad.read().await.get_block_meta_revs();
         let block_manager = Arc::new(GridBlockManager::new(&user, block_meta_revs, persistence).await?);
         let block_manager = Arc::new(GridBlockManager::new(&user, block_meta_revs, persistence).await?);
-        let filter_service =
-            GridFilterService::new(grid_pad.clone(), block_manager.clone(), task_scheduler.clone()).await;
+        let delegate = Arc::new(GridViewEditorDelegateImpl {
+            pad: grid_pad.clone(),
+            block_manager: block_manager.clone(),
+            task_scheduler,
+        });
 
 
         // View manager
         // View manager
-        let view_manager = Arc::new(
-            GridViewManager::new(
-                grid_id.to_owned(),
-                user.clone(),
-                Arc::new(grid_pad.clone()),
-                Arc::new(block_manager.clone()),
-                Arc::new(task_scheduler.clone()),
-            )
-            .await?,
-        );
+        let view_manager = Arc::new(GridViewManager::new(grid_id.to_owned(), user.clone(), delegate).await?);
         let editor = Arc::new(Self {
         let editor = Arc::new(Self {
             grid_id: grid_id.to_owned(),
             grid_id: grid_id.to_owned(),
             user,
             user,
@@ -88,7 +80,6 @@ impl GridRevisionEditor {
             rev_manager,
             rev_manager,
             block_manager,
             block_manager,
             view_manager,
             view_manager,
-            filter_service: Arc::new(filter_service),
         });
         });
 
 
         Ok(editor)
         Ok(editor)
@@ -97,8 +88,11 @@ impl GridRevisionEditor {
     #[tracing::instrument(name = "close grid editor", level = "trace", skip_all)]
     #[tracing::instrument(name = "close grid editor", level = "trace", skip_all)]
     pub fn close(&self) {
     pub fn close(&self) {
         let rev_manager = self.rev_manager.clone();
         let rev_manager = self.rev_manager.clone();
+        let view_manager = self.view_manager.clone();
+        let view_id = self.grid_id.clone();
         tokio::spawn(async move {
         tokio::spawn(async move {
             rev_manager.close().await;
             rev_manager.close().await;
+            view_manager.close(&view_id).await;
         });
         });
     }
     }
 
 
@@ -352,7 +346,6 @@ impl GridRevisionEditor {
                 Ok(changeset)
                 Ok(changeset)
             })
             })
             .await?;
             .await?;
-        let _ = self.view_manager.did_update_view_field(&params.field_id).await?;
         if is_type_option_changed {
         if is_type_option_changed {
             let _ = self
             let _ = self
                 .view_manager
                 .view_manager
@@ -418,20 +411,16 @@ impl GridRevisionEditor {
         Ok(())
         Ok(())
     }
     }
 
 
-    pub async fn get_rows(&self, block_id: &str) -> FlowyResult<RepeatedRowPB> {
-        let block_ids = vec![block_id.to_owned()];
-        let mut grid_block_snapshot = self.grid_block_snapshots(Some(block_ids)).await?;
-
-        // For the moment, we only support one block.
-        // We can save the rows into multiple blocks and load them asynchronously in the future.
-        debug_assert_eq!(grid_block_snapshot.len(), 1);
-        if grid_block_snapshot.len() == 1 {
-            let snapshot = grid_block_snapshot.pop().unwrap();
-            let rows = make_rows_from_row_revs(&snapshot.row_revs);
-            Ok(rows.into())
-        } else {
-            Ok(vec![].into())
-        }
+    pub async fn get_row_pbs(&self, block_id: &str) -> FlowyResult<Vec<RowPB>> {
+        let rows = self.block_manager.get_row_revs(block_id).await?;
+        let rows = self
+            .view_manager
+            .filter_rows(block_id, rows)
+            .await?
+            .into_iter()
+            .map(|row_rev| RowPB::from(&row_rev))
+            .collect();
+        Ok(rows)
     }
     }
 
 
     pub async fn get_row_rev(&self, row_id: &str) -> FlowyResult<Option<Arc<RowRevision>>> {
     pub async fn get_row_rev(&self, row_id: &str) -> FlowyResult<Option<Arc<RowRevision>>> {
@@ -514,16 +503,27 @@ impl GridRevisionEditor {
         }
         }
     }
     }
 
 
-    pub async fn get_blocks(&self, block_ids: Option<Vec<String>>) -> FlowyResult<RepeatedBlockPB> {
-        let block_snapshots = self.grid_block_snapshots(block_ids.clone()).await?;
-        make_grid_blocks(block_ids, block_snapshots)
-    }
-
     pub async fn get_block_meta_revs(&self) -> FlowyResult<Vec<Arc<GridBlockMetaRevision>>> {
     pub async fn get_block_meta_revs(&self) -> FlowyResult<Vec<Arc<GridBlockMetaRevision>>> {
         let block_meta_revs = self.grid_pad.read().await.get_block_meta_revs();
         let block_meta_revs = self.grid_pad.read().await.get_block_meta_revs();
         Ok(block_meta_revs)
         Ok(block_meta_revs)
     }
     }
 
 
+    pub async fn get_blocks(&self, block_ids: Option<Vec<String>>) -> FlowyResult<Vec<GridBlock>> {
+        let block_ids = match block_ids {
+            None => self
+                .grid_pad
+                .read()
+                .await
+                .get_block_meta_revs()
+                .iter()
+                .map(|block_rev| block_rev.block_id.clone())
+                .collect::<Vec<String>>(),
+            Some(block_ids) => block_ids,
+        };
+        let blocks = self.block_manager.get_blocks(Some(block_ids)).await?;
+        Ok(blocks)
+    }
+
     pub async fn delete_rows(&self, row_orders: Vec<RowPB>) -> FlowyResult<()> {
     pub async fn delete_rows(&self, row_orders: Vec<RowPB>) -> FlowyResult<()> {
         let changesets = self.block_manager.delete_rows(row_orders).await?;
         let changesets = self.block_manager.delete_rows(row_orders).await?;
         for changeset in changesets {
         for changeset in changesets {
@@ -532,36 +532,43 @@ impl GridRevisionEditor {
         Ok(())
         Ok(())
     }
     }
 
 
-    pub async fn get_grid_data(&self) -> FlowyResult<GridPB> {
-        let pad_read_guard = self.grid_pad.read().await;
-        let field_orders = pad_read_guard
-            .get_field_revs(None)?
-            .iter()
-            .map(FieldIdPB::from)
-            .collect();
-        let mut block_orders = vec![];
-        for block_rev in pad_read_guard.get_block_meta_revs() {
-            let row_orders = self.block_manager.get_row_orders(&block_rev.block_id).await?;
-            let block_order = BlockPB {
+    pub async fn get_grid(&self) -> FlowyResult<GridPB> {
+        let pad = self.grid_pad.read().await;
+        let fields = pad.get_field_revs(None)?.iter().map(FieldIdPB::from).collect();
+
+        let mut blocks = vec![];
+        for block_rev in pad.get_block_meta_revs() {
+            let rows = self.get_row_pbs(&block_rev.block_id).await?;
+            let block = BlockPB {
                 id: block_rev.block_id.clone(),
                 id: block_rev.block_id.clone(),
-                rows: row_orders,
+                rows,
             };
             };
-            block_orders.push(block_order);
+            blocks.push(block);
         }
         }
 
 
         Ok(GridPB {
         Ok(GridPB {
             id: self.grid_id.clone(),
             id: self.grid_id.clone(),
-            fields: field_orders,
-            blocks: block_orders,
+            fields,
+            blocks,
         })
         })
     }
     }
 
 
-    pub async fn get_grid_setting(&self) -> FlowyResult<GridSettingPB> {
+    pub async fn get_setting(&self) -> FlowyResult<GridSettingPB> {
         self.view_manager.get_setting().await
         self.view_manager.get_setting().await
     }
     }
 
 
-    pub async fn get_grid_filter(&self) -> FlowyResult<Vec<GridFilterConfigurationPB>> {
-        self.view_manager.get_filters().await
+    pub async fn get_all_filters(&self) -> FlowyResult<Vec<FilterPB>> {
+        Ok(self
+            .view_manager
+            .get_all_filters()
+            .await?
+            .into_iter()
+            .map(|filter| FilterPB::from(filter.as_ref()))
+            .collect())
+    }
+
+    pub async fn get_filters(&self, filter_id: FilterType) -> FlowyResult<Vec<Arc<FilterRevision>>> {
+        self.view_manager.get_filters(&filter_id).await
     }
     }
 
 
     pub async fn insert_group(&self, params: InsertGroupParams) -> FlowyResult<()> {
     pub async fn insert_group(&self, params: InsertGroupParams) -> FlowyResult<()> {
@@ -572,7 +579,7 @@ impl GridRevisionEditor {
         self.view_manager.delete_group(params).await
         self.view_manager.delete_group(params).await
     }
     }
 
 
-    pub async fn create_filter(&self, params: InsertFilterParams) -> FlowyResult<()> {
+    pub async fn create_filter(&self, params: CreateFilterParams) -> FlowyResult<()> {
         let _ = self.view_manager.insert_or_update_filter(params).await?;
         let _ = self.view_manager.insert_or_update_filter(params).await?;
         Ok(())
         Ok(())
     }
     }
@@ -582,22 +589,6 @@ impl GridRevisionEditor {
         Ok(())
         Ok(())
     }
     }
 
 
-    pub async fn grid_block_snapshots(&self, block_ids: Option<Vec<String>>) -> FlowyResult<Vec<GridBlockSnapshot>> {
-        let block_ids = match block_ids {
-            None => self
-                .grid_pad
-                .read()
-                .await
-                .get_block_meta_revs()
-                .iter()
-                .map(|block_rev| block_rev.block_id.clone())
-                .collect::<Vec<String>>(),
-            Some(block_ids) => block_ids,
-        };
-        let snapshots = self.block_manager.get_block_snapshots(Some(block_ids)).await?;
-        Ok(snapshots)
-    }
-
     pub async fn move_row(&self, params: MoveRowParams) -> FlowyResult<()> {
     pub async fn move_row(&self, params: MoveRowParams) -> FlowyResult<()> {
         let MoveRowParams {
         let MoveRowParams {
             view_id: _,
             view_id: _,
@@ -641,7 +632,7 @@ impl GridRevisionEditor {
                 let block_manager = self.block_manager.clone();
                 let block_manager = self.block_manager.clone();
                 self.view_manager
                 self.view_manager
                     .move_group_row(row_rev, to_group_id, to_row_id.clone(), |row_changeset| {
                     .move_group_row(row_rev, to_group_id, to_row_id.clone(), |row_changeset| {
-                        wrap_future(async move {
+                        to_future(async move {
                             tracing::trace!("Row data changed: {:?}", row_changeset);
                             tracing::trace!("Row data changed: {:?}", row_changeset);
                             let cell_changesets = row_changeset
                             let cell_changesets = row_changeset
                                 .cell_by_field_id
                                 .cell_by_field_id

+ 0 - 42
frontend/rust-lib/flowy-grid/src/services/grid_editor_task.rs

@@ -1,42 +0,0 @@
-use crate::manager::GridTaskSchedulerRwLock;
-use crate::services::grid_editor::GridRevisionEditor;
-use crate::services::tasks::{GridTaskHandler, Task, TaskContent, TaskId};
-use flowy_error::FlowyError;
-use futures::future::BoxFuture;
-use lib_infra::future::BoxResultFuture;
-
-pub(crate) trait GridServiceTaskScheduler: Send + Sync + 'static {
-    fn gen_task_id(&self) -> BoxFuture<TaskId>;
-    fn add_task(&self, task: Task) -> BoxFuture<()>;
-}
-
-impl GridTaskHandler for GridRevisionEditor {
-    fn handler_id(&self) -> &str {
-        &self.grid_id
-    }
-
-    fn process_content(&self, content: TaskContent) -> BoxResultFuture<(), FlowyError> {
-        Box::pin(async move {
-            match content {
-                TaskContent::Snapshot => {}
-                TaskContent::Group => {}
-                TaskContent::Filter(context) => self.filter_service.process(context).await?,
-            }
-            Ok(())
-        })
-    }
-}
-
-impl GridServiceTaskScheduler for GridTaskSchedulerRwLock {
-    fn gen_task_id(&self) -> BoxFuture<TaskId> {
-        let this = self.clone();
-        Box::pin(async move { this.read().await.next_task_id() })
-    }
-
-    fn add_task(&self, task: Task) -> BoxFuture<()> {
-        let this = self.clone();
-        Box::pin(async move {
-            this.write().await.add_task(task);
-        })
-    }
-}

+ 57 - 15
frontend/rust-lib/flowy-grid/src/services/grid_editor_trait_impl.rs

@@ -1,15 +1,24 @@
-use crate::services::grid_view_manager::GridViewFieldDelegate;
+use crate::services::block_manager::GridBlockManager;
+use crate::services::grid_view_editor::GridViewEditorDelegate;
+use crate::services::row::GridBlock;
 use flowy_sync::client_grid::GridRevisionPad;
 use flowy_sync::client_grid::GridRevisionPad;
-use grid_rev_model::FieldRevision;
-use lib_infra::future::{wrap_future, AFFuture};
+use flowy_task::TaskDispatcher;
+use grid_rev_model::{FieldRevision, RowRevision};
+use lib_infra::future::{to_future, Fut};
 use std::sync::Arc;
 use std::sync::Arc;
 use tokio::sync::RwLock;
 use tokio::sync::RwLock;
 
 
-impl GridViewFieldDelegate for Arc<RwLock<GridRevisionPad>> {
-    fn get_field_revs(&self) -> AFFuture<Vec<Arc<FieldRevision>>> {
-        let pad = self.clone();
-        wrap_future(async move {
-            match pad.read().await.get_field_revs(None) {
+pub(crate) struct GridViewEditorDelegateImpl {
+    pub(crate) pad: Arc<RwLock<GridRevisionPad>>,
+    pub(crate) block_manager: Arc<GridBlockManager>,
+    pub(crate) task_scheduler: Arc<RwLock<TaskDispatcher>>,
+}
+
+impl GridViewEditorDelegate for GridViewEditorDelegateImpl {
+    fn get_field_revs(&self, field_ids: Option<Vec<String>>) -> Fut<Vec<Arc<FieldRevision>>> {
+        let pad = self.pad.clone();
+        to_future(async move {
+            match pad.read().await.get_field_revs(field_ids) {
                 Ok(field_revs) => field_revs,
                 Ok(field_revs) => field_revs,
                 Err(e) => {
                 Err(e) => {
                     tracing::error!("[GridViewRevisionDelegate] get field revisions failed: {}", e);
                     tracing::error!("[GridViewRevisionDelegate] get field revisions failed: {}", e);
@@ -19,14 +28,47 @@ impl GridViewFieldDelegate for Arc<RwLock<GridRevisionPad>> {
         })
         })
     }
     }
 
 
-    fn get_field_rev(&self, field_id: &str) -> AFFuture<Option<Arc<FieldRevision>>> {
-        let pad = self.clone();
+    fn get_field_rev(&self, field_id: &str) -> Fut<Option<Arc<FieldRevision>>> {
+        let pad = self.pad.clone();
         let field_id = field_id.to_owned();
         let field_id = field_id.to_owned();
-        wrap_future(async move {
-            pad.read()
-                .await
-                .get_field_rev(&field_id)
-                .map(|(_, field_rev)| field_rev.clone())
+        to_future(async move { Some(pad.read().await.get_field_rev(&field_id)?.1.clone()) })
+    }
+
+    fn index_of_row(&self, row_id: &str) -> Fut<Option<usize>> {
+        let block_manager = self.block_manager.clone();
+        let row_id = row_id.to_owned();
+        to_future(async move { block_manager.index_of_row(&row_id).await })
+    }
+
+    fn get_row_rev(&self, row_id: &str) -> Fut<Option<Arc<RowRevision>>> {
+        let block_manager = self.block_manager.clone();
+        let row_id = row_id.to_owned();
+        to_future(async move {
+            match block_manager.get_row_rev(&row_id).await {
+                Ok(row_rev) => row_rev,
+                Err(_) => None,
+            }
         })
         })
     }
     }
+
+    fn get_row_revs(&self) -> Fut<Vec<Arc<RowRevision>>> {
+        let block_manager = self.block_manager.clone();
+
+        to_future(async move {
+            let blocks = block_manager.get_blocks(None).await.unwrap();
+            blocks
+                .into_iter()
+                .flat_map(|block| block.row_revs)
+                .collect::<Vec<Arc<RowRevision>>>()
+        })
+    }
+
+    fn get_blocks(&self) -> Fut<Vec<GridBlock>> {
+        let block_manager = self.block_manager.clone();
+        to_future(async move { block_manager.get_blocks(None).await.unwrap_or_default() })
+    }
+
+    fn get_task_scheduler(&self) -> Arc<RwLock<TaskDispatcher>> {
+        self.task_scheduler.clone()
+    }
 }
 }

+ 183 - 112
frontend/rust-lib/flowy-grid/src/services/grid_view_editor.rs

@@ -1,16 +1,13 @@
 use crate::dart_notification::{send_dart_notification, GridNotification};
 use crate::dart_notification::{send_dart_notification, GridNotification};
-use crate::entities::{
-    CreateRowParams, DeleteFilterParams, DeleteGroupParams, GridFilterConfigurationPB, GridGroupConfigurationPB,
-    GridLayout, GridLayoutPB, GridSettingPB, GroupChangesetPB, GroupPB, GroupViewChangesetPB, InsertFilterParams,
-    InsertGroupParams, InsertedGroupPB, InsertedRowPB, MoveGroupParams, RepeatedGridFilterConfigurationPB,
-    RepeatedGridGroupConfigurationPB, RowPB,
+use crate::entities::*;
+use crate::services::filter::{
+    FilterChangeset, FilterController, FilterTaskHandler, FilterType, GridViewFilterDelegate,
 };
 };
-use crate::services::grid_editor_task::GridServiceTaskScheduler;
-use crate::services::grid_view_manager::{GridViewFieldDelegate, GridViewRowDelegate};
 use crate::services::group::{
 use crate::services::group::{
-    default_group_configuration, find_group_field, make_group_controller, GroupConfigurationReader,
+    default_group_configuration, find_group_field, make_group_controller, Group, GroupConfigurationReader,
     GroupConfigurationWriter, GroupController, MoveGroupRowContext,
     GroupConfigurationWriter, GroupController, MoveGroupRowContext,
 };
 };
+use crate::services::row::GridBlock;
 use bytes::Bytes;
 use bytes::Bytes;
 use flowy_database::ConnectionPool;
 use flowy_database::ConnectionPool;
 use flowy_error::{FlowyError, FlowyResult};
 use flowy_error::{FlowyError, FlowyResult};
@@ -20,26 +17,39 @@ use flowy_revision::{
 };
 };
 use flowy_sync::client_grid::{GridViewRevisionChangeset, GridViewRevisionPad};
 use flowy_sync::client_grid::{GridViewRevisionChangeset, GridViewRevisionPad};
 use flowy_sync::util::make_operations_from_revisions;
 use flowy_sync::util::make_operations_from_revisions;
+use flowy_task::TaskDispatcher;
 use grid_rev_model::{
 use grid_rev_model::{
-    gen_grid_filter_id, FieldRevision, FieldTypeRevision, FilterConfigurationRevision, GroupConfigurationRevision,
-    RowChangeset, RowRevision,
+    gen_grid_filter_id, FieldRevision, FieldTypeRevision, FilterRevision, GroupConfigurationRevision, RowChangeset,
+    RowRevision,
 };
 };
-use lib_infra::future::{wrap_future, AFFuture, FutureResult};
+use lib_infra::future::{to_future, Fut, FutureResult};
 use lib_ot::core::EmptyAttributes;
 use lib_ot::core::EmptyAttributes;
 use std::future::Future;
 use std::future::Future;
 use std::sync::Arc;
 use std::sync::Arc;
 use tokio::sync::RwLock;
 use tokio::sync::RwLock;
 
 
+pub trait GridViewEditorDelegate: Send + Sync + 'static {
+    /// If the field_ids is None, then it will return all the field revisions
+    fn get_field_revs(&self, field_ids: Option<Vec<String>>) -> Fut<Vec<Arc<FieldRevision>>>;
+    fn get_field_rev(&self, field_id: &str) -> Fut<Option<Arc<FieldRevision>>>;
+
+    fn index_of_row(&self, row_id: &str) -> Fut<Option<usize>>;
+    fn get_row_rev(&self, row_id: &str) -> Fut<Option<Arc<RowRevision>>>;
+    fn get_row_revs(&self) -> Fut<Vec<Arc<RowRevision>>>;
+    fn get_blocks(&self) -> Fut<Vec<GridBlock>>;
+
+    fn get_task_scheduler(&self) -> Arc<RwLock<TaskDispatcher>>;
+}
+
 #[allow(dead_code)]
 #[allow(dead_code)]
 pub struct GridViewRevisionEditor {
 pub struct GridViewRevisionEditor {
     user_id: String,
     user_id: String,
     view_id: String,
     view_id: String,
     pad: Arc<RwLock<GridViewRevisionPad>>,
     pad: Arc<RwLock<GridViewRevisionPad>>,
     rev_manager: Arc<RevisionManager<Arc<ConnectionPool>>>,
     rev_manager: Arc<RevisionManager<Arc<ConnectionPool>>>,
-    field_delegate: Arc<dyn GridViewFieldDelegate>,
-    row_delegate: Arc<dyn GridViewRowDelegate>,
+    delegate: Arc<dyn GridViewEditorDelegate>,
     group_controller: Arc<RwLock<Box<dyn GroupController>>>,
     group_controller: Arc<RwLock<Box<dyn GroupController>>>,
-    scheduler: Arc<dyn GridServiceTaskScheduler>,
+    filter_controller: Arc<RwLock<FilterController>>,
 }
 }
 impl GridViewRevisionEditor {
 impl GridViewRevisionEditor {
     #[tracing::instrument(level = "trace", skip_all, err)]
     #[tracing::instrument(level = "trace", skip_all, err)]
@@ -47,9 +57,7 @@ impl GridViewRevisionEditor {
         user_id: &str,
         user_id: &str,
         token: &str,
         token: &str,
         view_id: String,
         view_id: String,
-        field_delegate: Arc<dyn GridViewFieldDelegate>,
-        row_delegate: Arc<dyn GridViewRowDelegate>,
-        scheduler: Arc<dyn GridServiceTaskScheduler>,
+        delegate: Arc<dyn GridViewEditorDelegate>,
         mut rev_manager: RevisionManager<Arc<ConnectionPool>>,
         mut rev_manager: RevisionManager<Arc<ConnectionPool>>,
     ) -> FlowyResult<Self> {
     ) -> FlowyResult<Self> {
         let cloud = Arc::new(GridViewRevisionCloudService {
         let cloud = Arc::new(GridViewRevisionCloudService {
@@ -63,23 +71,33 @@ impl GridViewRevisionEditor {
             view_id.clone(),
             view_id.clone(),
             pad.clone(),
             pad.clone(),
             rev_manager.clone(),
             rev_manager.clone(),
-            field_delegate.clone(),
-            row_delegate.clone(),
+            delegate.clone(),
         )
         )
         .await?;
         .await?;
+
         let user_id = user_id.to_owned();
         let user_id = user_id.to_owned();
+        let group_controller = Arc::new(RwLock::new(group_controller));
+        let filter_controller = make_filter_controller(&view_id, delegate.clone(), pad.clone()).await;
         Ok(Self {
         Ok(Self {
             pad,
             pad,
             user_id,
             user_id,
             view_id,
             view_id,
             rev_manager,
             rev_manager,
-            scheduler,
-            field_delegate,
-            row_delegate,
-            group_controller: Arc::new(RwLock::new(group_controller)),
+            delegate,
+            group_controller,
+            filter_controller,
         })
         })
     }
     }
 
 
+    pub(crate) async fn close(&self) {
+        self.filter_controller.read().await.close().await;
+    }
+
+    pub(crate) async fn filter_rows(&self, _block_id: &str, mut rows: Vec<Arc<RowRevision>>) -> Vec<Arc<RowRevision>> {
+        self.filter_controller.write().await.filter_row_revs(&mut rows).await;
+        rows
+    }
+
     pub(crate) async fn duplicate_view_data(&self) -> FlowyResult<String> {
     pub(crate) async fn duplicate_view_data(&self) -> FlowyResult<String> {
         let json_str = self.pad.read().await.json_str()?;
         let json_str = self.pad.read().await.json_str()?;
         Ok(json_str)
         Ok(json_str)
@@ -178,7 +196,14 @@ impl GridViewRevisionEditor {
     /// Only call once after grid view editor initialized
     /// Only call once after grid view editor initialized
     #[tracing::instrument(level = "trace", skip(self))]
     #[tracing::instrument(level = "trace", skip(self))]
     pub(crate) async fn load_view_groups(&self) -> FlowyResult<Vec<GroupPB>> {
     pub(crate) async fn load_view_groups(&self) -> FlowyResult<Vec<GroupPB>> {
-        let groups = self.group_controller.read().await.groups();
+        let groups = self
+            .group_controller
+            .read()
+            .await
+            .groups()
+            .into_iter()
+            .cloned()
+            .collect::<Vec<Group>>();
         tracing::trace!("Number of groups: {}", groups.len());
         tracing::trace!("Number of groups: {}", groups.len());
         Ok(groups.into_iter().map(GroupPB::from).collect())
         Ok(groups.into_iter().map(GroupPB::from).collect())
     }
     }
@@ -212,32 +237,30 @@ impl GridViewRevisionEditor {
         Ok(())
         Ok(())
     }
     }
 
 
-    pub(crate) async fn group_id(&self) -> String {
-        self.group_controller.read().await.field_id().to_owned()
+    pub(crate) async fn is_grouped(&self) -> bool {
+        self.group_controller.read().await.groups().len() > 1
     }
     }
 
 
     pub(crate) async fn get_view_setting(&self) -> GridSettingPB {
     pub(crate) async fn get_view_setting(&self) -> GridSettingPB {
-        let field_revs = self.field_delegate.get_field_revs().await;
+        let field_revs = self.delegate.get_field_revs(None).await;
         let grid_setting = make_grid_setting(&*self.pad.read().await, &field_revs);
         let grid_setting = make_grid_setting(&*self.pad.read().await, &field_revs);
         grid_setting
         grid_setting
     }
     }
 
 
-    pub(crate) async fn get_view_filters(&self) -> Vec<GridFilterConfigurationPB> {
-        let field_revs = self.field_delegate.get_field_revs().await;
-        match self.pad.read().await.get_all_filters(&field_revs) {
-            None => vec![],
-            Some(filters) => filters
-                .into_values()
-                .flatten()
-                .map(|filter| GridFilterConfigurationPB::from(filter.as_ref()))
-                .collect(),
-        }
+    pub(crate) async fn get_all_view_filters(&self) -> Vec<Arc<FilterRevision>> {
+        let field_revs = self.delegate.get_field_revs(None).await;
+        self.pad.read().await.get_all_filters(&field_revs)
+    }
+
+    pub(crate) async fn get_view_filters(&self, filter_id: &FilterType) -> Vec<Arc<FilterRevision>> {
+        let field_type_rev: FieldTypeRevision = filter_id.field_type.clone().into();
+        self.pad.read().await.get_filters(&filter_id.field_id, &field_type_rev)
     }
     }
 
 
     /// Initialize new group when grouping by a new field
     /// Initialize new group when grouping by a new field
     ///
     ///
     pub(crate) async fn initialize_new_group(&self, params: InsertGroupParams) -> FlowyResult<()> {
     pub(crate) async fn initialize_new_group(&self, params: InsertGroupParams) -> FlowyResult<()> {
-        if let Some(field_rev) = self.field_delegate.get_field_rev(&params.field_id).await {
+        if let Some(field_rev) = self.delegate.get_field_rev(&params.field_id).await {
             let _ = self
             let _ = self
                 .modify(|pad| {
                 .modify(|pad| {
                     let configuration = default_group_configuration(&field_rev);
                     let configuration = default_group_configuration(&field_rev);
@@ -259,44 +282,64 @@ impl GridViewRevisionEditor {
 
 
     pub(crate) async fn delete_view_group(&self, params: DeleteGroupParams) -> FlowyResult<()> {
     pub(crate) async fn delete_view_group(&self, params: DeleteGroupParams) -> FlowyResult<()> {
         self.modify(|pad| {
         self.modify(|pad| {
-            let changeset = pad.delete_filter(&params.field_id, &params.field_type_rev, &params.group_id)?;
+            let changeset = pad.delete_group(&params.group_id, &params.field_id, &params.field_type_rev)?;
             Ok(changeset)
             Ok(changeset)
         })
         })
         .await
         .await
     }
     }
 
 
-    pub(crate) async fn insert_view_filter(&self, params: InsertFilterParams) -> FlowyResult<()> {
-        self.modify(|pad| {
-            let filter_rev = FilterConfigurationRevision {
-                id: gen_grid_filter_id(),
-                field_id: params.field_id.clone(),
-                condition: params.condition,
-                content: params.content,
-            };
-            let changeset = pad.insert_filter(&params.field_id, &params.field_type_rev, filter_rev)?;
-            Ok(changeset)
-        })
-        .await
+    pub(crate) async fn insert_view_filter(&self, params: CreateFilterParams) -> FlowyResult<()> {
+        let filter_type = FilterType::from(&params);
+        let _ = self
+            .modify(|pad| {
+                let filter_rev = FilterRevision {
+                    id: gen_grid_filter_id(),
+                    field_id: params.field_id.clone(),
+                    condition: params.condition,
+                    content: params.content,
+                };
+                let changeset = pad.insert_filter(&params.field_id, &params.field_type_rev, filter_rev)?;
+                Ok(changeset)
+            })
+            .await?;
+
+        self.filter_controller
+            .write()
+            .await
+            .apply_changeset(FilterChangeset::from_insert(filter_type))
+            .await;
+
+        Ok(())
     }
     }
 
 
-    pub(crate) async fn delete_view_filter(&self, delete_filter: DeleteFilterParams) -> FlowyResult<()> {
-        self.modify(|pad| {
-            let changeset = pad.delete_filter(
-                &delete_filter.field_id,
-                &delete_filter.field_type_rev,
-                &delete_filter.filter_id,
-            )?;
-            Ok(changeset)
-        })
-        .await
+    pub(crate) async fn delete_view_filter(&self, params: DeleteFilterParams) -> FlowyResult<()> {
+        let filter_type = params.filter_type;
+        let field_type_rev = filter_type.field_type_rev();
+        let _ = self
+            .modify(|pad| {
+                let changeset = pad.delete_filter(&params.filter_id, &filter_type.field_id, &field_type_rev)?;
+                Ok(changeset)
+            })
+            .await?;
+
+        self.filter_controller
+            .write()
+            .await
+            .apply_changeset(FilterChangeset::from_delete(filter_type))
+            .await;
+        Ok(())
     }
     }
+
     #[tracing::instrument(level = "trace", skip_all, err)]
     #[tracing::instrument(level = "trace", skip_all, err)]
-    pub(crate) async fn did_update_view_field(&self, field_id: &str) -> FlowyResult<()> {
-        let grouped_field_id = self.group_controller.read().await.field_id().to_owned();
-        if grouped_field_id == field_id {
-            let _ = self.group_by_view_field(field_id).await?;
-        } else {
-            // Do nothing
+    pub(crate) async fn did_update_view_field_type_option(&self, field_id: &str) -> FlowyResult<()> {
+        if let Some(field_rev) = self.delegate.get_field_rev(field_id).await {
+            let filter_type = FilterType::from(&field_rev);
+            let filter_changeset = FilterChangeset::from_insert(filter_type);
+            self.filter_controller
+                .write()
+                .await
+                .apply_changeset(filter_changeset)
+                .await;
         }
         }
         Ok(())
         Ok(())
     }
     }
@@ -309,18 +352,23 @@ impl GridViewRevisionEditor {
     ///
     ///
     #[tracing::instrument(level = "debug", skip_all, err)]
     #[tracing::instrument(level = "debug", skip_all, err)]
     pub(crate) async fn group_by_view_field(&self, field_id: &str) -> FlowyResult<()> {
     pub(crate) async fn group_by_view_field(&self, field_id: &str) -> FlowyResult<()> {
-        if let Some(field_rev) = self.field_delegate.get_field_rev(field_id).await {
+        if let Some(field_rev) = self.delegate.get_field_rev(field_id).await {
+            let row_revs = self.delegate.get_row_revs().await;
             let new_group_controller = new_group_controller_with_field_rev(
             let new_group_controller = new_group_controller_with_field_rev(
                 self.user_id.clone(),
                 self.user_id.clone(),
                 self.view_id.clone(),
                 self.view_id.clone(),
                 self.pad.clone(),
                 self.pad.clone(),
                 self.rev_manager.clone(),
                 self.rev_manager.clone(),
                 field_rev,
                 field_rev,
-                self.row_delegate.clone(),
+                row_revs,
             )
             )
             .await?;
             .await?;
 
 
-            let new_groups = new_group_controller.groups().into_iter().map(GroupPB::from).collect();
+            let new_groups = new_group_controller
+                .groups()
+                .into_iter()
+                .map(|group| GroupPB::from(group.clone()))
+                .collect();
 
 
             *self.group_controller.write().await = new_group_controller;
             *self.group_controller.write().await = new_group_controller;
             let changeset = GroupViewChangesetPB {
             let changeset = GroupViewChangesetPB {
@@ -377,7 +425,7 @@ impl GridViewRevisionEditor {
         F: FnOnce(&mut Box<dyn GroupController>, Arc<FieldRevision>) -> FlowyResult<T>,
         F: FnOnce(&mut Box<dyn GroupController>, Arc<FieldRevision>) -> FlowyResult<T>,
     {
     {
         let group_field_id = self.group_controller.read().await.field_id().to_owned();
         let group_field_id = self.group_controller.read().await.field_id().to_owned();
-        match self.field_delegate.get_field_rev(&group_field_id).await {
+        match self.delegate.get_field_rev(&group_field_id).await {
             None => None,
             None => None,
             Some(field_rev) => {
             Some(field_rev) => {
                 let mut write_guard = self.group_controller.write().await;
                 let mut write_guard = self.group_controller.write().await;
@@ -393,7 +441,7 @@ impl GridViewRevisionEditor {
         O: Future<Output = FlowyResult<T>> + Sync + 'static,
         O: Future<Output = FlowyResult<T>> + Sync + 'static,
     {
     {
         let group_field_id = self.group_controller.read().await.field_id().to_owned();
         let group_field_id = self.group_controller.read().await.field_id().to_owned();
-        match self.field_delegate.get_field_rev(&group_field_id).await {
+        match self.delegate.get_field_rev(&group_field_id).await {
             None => None,
             None => None,
             Some(field_rev) => {
             Some(field_rev) => {
                 let _write_guard = self.group_controller.write().await;
                 let _write_guard = self.group_controller.write().await;
@@ -408,11 +456,11 @@ async fn new_group_controller(
     view_id: String,
     view_id: String,
     view_rev_pad: Arc<RwLock<GridViewRevisionPad>>,
     view_rev_pad: Arc<RwLock<GridViewRevisionPad>>,
     rev_manager: Arc<RevisionManager<Arc<ConnectionPool>>>,
     rev_manager: Arc<RevisionManager<Arc<ConnectionPool>>>,
-    field_delegate: Arc<dyn GridViewFieldDelegate>,
-    row_delegate: Arc<dyn GridViewRowDelegate>,
+    delegate: Arc<dyn GridViewEditorDelegate>,
 ) -> FlowyResult<Box<dyn GroupController>> {
 ) -> FlowyResult<Box<dyn GroupController>> {
     let configuration_reader = GroupConfigurationReaderImpl(view_rev_pad.clone());
     let configuration_reader = GroupConfigurationReaderImpl(view_rev_pad.clone());
-    let field_revs = field_delegate.get_field_revs().await;
+    let field_revs = delegate.get_field_revs(None).await;
+    let row_revs = delegate.get_row_revs().await;
     let layout = view_rev_pad.read().await.layout();
     let layout = view_rev_pad.read().await.layout();
     // Read the group field or find a new group field
     // Read the group field or find a new group field
     let field_rev = configuration_reader
     let field_rev = configuration_reader
@@ -426,27 +474,18 @@ async fn new_group_controller(
         })
         })
         .unwrap_or_else(|| find_group_field(&field_revs, &layout).unwrap());
         .unwrap_or_else(|| find_group_field(&field_revs, &layout).unwrap());
 
 
-    new_group_controller_with_field_rev(user_id, view_id, view_rev_pad, rev_manager, field_rev, row_delegate).await
+    new_group_controller_with_field_rev(user_id, view_id, view_rev_pad, rev_manager, field_rev, row_revs).await
 }
 }
 
 
 /// Returns a [GroupController]  
 /// Returns a [GroupController]  
 ///
 ///
-/// # Arguments
-///
-/// * `user_id`:
-/// * `view_id`:
-/// * `view_rev_pad`:
-/// * `rev_manager`:
-/// * `field_rev`:
-/// * `row_delegate`:
-///
 async fn new_group_controller_with_field_rev(
 async fn new_group_controller_with_field_rev(
     user_id: String,
     user_id: String,
     view_id: String,
     view_id: String,
     view_rev_pad: Arc<RwLock<GridViewRevisionPad>>,
     view_rev_pad: Arc<RwLock<GridViewRevisionPad>>,
     rev_manager: Arc<RevisionManager<Arc<ConnectionPool>>>,
     rev_manager: Arc<RevisionManager<Arc<ConnectionPool>>>,
     field_rev: Arc<FieldRevision>,
     field_rev: Arc<FieldRevision>,
-    row_delegate: Arc<dyn GridViewRowDelegate>,
+    row_revs: Vec<Arc<RowRevision>>,
 ) -> FlowyResult<Box<dyn GroupController>> {
 ) -> FlowyResult<Box<dyn GroupController>> {
     let configuration_reader = GroupConfigurationReaderImpl(view_rev_pad.clone());
     let configuration_reader = GroupConfigurationReaderImpl(view_rev_pad.clone());
     let configuration_writer = GroupConfigurationWriterImpl {
     let configuration_writer = GroupConfigurationWriterImpl {
@@ -454,10 +493,30 @@ async fn new_group_controller_with_field_rev(
         rev_manager,
         rev_manager,
         view_pad: view_rev_pad,
         view_pad: view_rev_pad,
     };
     };
-    let row_revs = row_delegate.gv_row_revs().await;
     make_group_controller(view_id, field_rev, row_revs, configuration_reader, configuration_writer).await
     make_group_controller(view_id, field_rev, row_revs, configuration_reader, configuration_writer).await
 }
 }
 
 
+async fn make_filter_controller(
+    view_id: &str,
+    delegate: Arc<dyn GridViewEditorDelegate>,
+    pad: Arc<RwLock<GridViewRevisionPad>>,
+) -> Arc<RwLock<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();
+    let filter_delegate = GridViewFilterDelegateImpl {
+        editor_delegate: delegate.clone(),
+        view_revision_pad: pad,
+    };
+    let filter_controller = FilterController::new(view_id, filter_delegate, task_scheduler.clone(), filter_revs).await;
+    let filter_controller = Arc::new(RwLock::new(filter_controller));
+    task_scheduler
+        .write()
+        .await
+        .register_handler(FilterTaskHandler::new(filter_controller.clone()));
+    filter_controller
+}
+
 async fn apply_change(
 async fn apply_change(
     _user_id: &str,
     _user_id: &str,
     rev_manager: Arc<RevisionManager<Arc<ConnectionPool>>>,
     rev_manager: Arc<RevisionManager<Arc<ConnectionPool>>>,
@@ -477,7 +536,6 @@ struct GridViewRevisionCloudService {
 }
 }
 
 
 impl RevisionCloudService for GridViewRevisionCloudService {
 impl RevisionCloudService for GridViewRevisionCloudService {
-    #[tracing::instrument(level = "trace", skip(self))]
     fn fetch_object(&self, _user_id: &str, _object_id: &str) -> FutureResult<Vec<Revision>, FlowyError> {
     fn fetch_object(&self, _user_id: &str, _object_id: &str) -> FutureResult<Vec<Revision>, FlowyError> {
         FutureResult::new(async move { Ok(vec![]) })
         FutureResult::new(async move { Ok(vec![]) })
     }
     }
@@ -510,9 +568,9 @@ impl RevisionMergeable for GridViewRevisionCompress {
 struct GroupConfigurationReaderImpl(Arc<RwLock<GridViewRevisionPad>>);
 struct GroupConfigurationReaderImpl(Arc<RwLock<GridViewRevisionPad>>);
 
 
 impl GroupConfigurationReader for GroupConfigurationReaderImpl {
 impl GroupConfigurationReader for GroupConfigurationReaderImpl {
-    fn get_configuration(&self) -> AFFuture<Option<Arc<GroupConfigurationRevision>>> {
+    fn get_configuration(&self) -> Fut<Option<Arc<GroupConfigurationRevision>>> {
         let view_pad = self.0.clone();
         let view_pad = self.0.clone();
-        wrap_future(async move {
+        to_future(async move {
             let mut groups = view_pad.read().await.get_all_groups();
             let mut groups = view_pad.read().await.get_all_groups();
             if groups.is_empty() {
             if groups.is_empty() {
                 None
                 None
@@ -536,13 +594,13 @@ impl GroupConfigurationWriter for GroupConfigurationWriterImpl {
         field_id: &str,
         field_id: &str,
         field_type: FieldTypeRevision,
         field_type: FieldTypeRevision,
         group_configuration: GroupConfigurationRevision,
         group_configuration: GroupConfigurationRevision,
-    ) -> AFFuture<FlowyResult<()>> {
+    ) -> Fut<FlowyResult<()>> {
         let user_id = self.user_id.clone();
         let user_id = self.user_id.clone();
         let rev_manager = self.rev_manager.clone();
         let rev_manager = self.rev_manager.clone();
         let view_pad = self.view_pad.clone();
         let view_pad = self.view_pad.clone();
         let field_id = field_id.to_owned();
         let field_id = field_id.to_owned();
 
 
-        wrap_future(async move {
+        to_future(async move {
             let changeset = view_pad.write().await.insert_or_update_group_configuration(
             let changeset = view_pad.write().await.insert_or_update_group_configuration(
                 &field_id,
                 &field_id,
                 &field_type,
                 &field_type,
@@ -561,29 +619,15 @@ pub fn make_grid_setting(view_pad: &GridViewRevisionPad, field_revs: &[Arc<Field
     let layout_type: GridLayout = view_pad.layout.clone().into();
     let layout_type: GridLayout = view_pad.layout.clone().into();
     let filter_configurations = view_pad
     let filter_configurations = view_pad
         .get_all_filters(field_revs)
         .get_all_filters(field_revs)
-        .map(|filters_by_field_id| {
-            filters_by_field_id
-                .into_iter()
-                .flat_map(|(_, v)| {
-                    let repeated_filter: RepeatedGridFilterConfigurationPB = v.into();
-                    repeated_filter.items
-                })
-                .collect::<Vec<GridFilterConfigurationPB>>()
-        })
-        .unwrap_or_default();
+        .into_iter()
+        .map(|filter| FilterPB::from(filter.as_ref()))
+        .collect::<Vec<FilterPB>>();
 
 
     let group_configurations = view_pad
     let group_configurations = view_pad
         .get_groups_by_field_revs(field_revs)
         .get_groups_by_field_revs(field_revs)
-        .map(|groups_by_field_id| {
-            groups_by_field_id
-                .into_iter()
-                .flat_map(|(_, v)| {
-                    let repeated_group: RepeatedGridGroupConfigurationPB = v.into();
-                    repeated_group.items
-                })
-                .collect::<Vec<GridGroupConfigurationPB>>()
-        })
-        .unwrap_or_default();
+        .into_iter()
+        .map(|group| GridGroupConfigurationPB::from(group.as_ref()))
+        .collect::<Vec<GridGroupConfigurationPB>>();
 
 
     GridSettingPB {
     GridSettingPB {
         layouts: GridLayoutPB::all(),
         layouts: GridLayoutPB::all(),
@@ -593,6 +637,33 @@ pub fn make_grid_setting(view_pad: &GridViewRevisionPad, field_revs: &[Arc<Field
     }
     }
 }
 }
 
 
+struct GridViewFilterDelegateImpl {
+    editor_delegate: Arc<dyn GridViewEditorDelegate>,
+    view_revision_pad: Arc<RwLock<GridViewRevisionPad>>,
+}
+
+impl GridViewFilterDelegate for GridViewFilterDelegateImpl {
+    fn get_filter_rev(&self, filter_id: FilterType) -> Fut<Vec<Arc<FilterRevision>>> {
+        let pad = self.view_revision_pad.clone();
+        to_future(async move {
+            let field_type_rev: FieldTypeRevision = filter_id.field_type.into();
+            pad.read().await.get_filters(&filter_id.field_id, &field_type_rev)
+        })
+    }
+
+    fn get_field_rev(&self, field_id: &str) -> Fut<Option<Arc<FieldRevision>>> {
+        self.editor_delegate.get_field_rev(field_id)
+    }
+
+    fn get_field_revs(&self, field_ids: Option<Vec<String>>) -> Fut<Vec<Arc<FieldRevision>>> {
+        self.editor_delegate.get_field_revs(field_ids)
+    }
+
+    fn get_blocks(&self) -> Fut<Vec<GridBlock>> {
+        self.editor_delegate.get_blocks()
+    }
+}
+
 #[cfg(test)]
 #[cfg(test)]
 mod tests {
 mod tests {
     use flowy_sync::client_grid::GridOperations;
     use flowy_sync::client_grid::GridOperations;

+ 41 - 66
frontend/rust-lib/flowy-grid/src/services/grid_view_manager.rs

@@ -1,62 +1,59 @@
 use crate::entities::{
 use crate::entities::{
-    CreateRowParams, DeleteFilterParams, DeleteGroupParams, GridFilterConfigurationPB, GridSettingPB,
-    InsertFilterParams, InsertGroupParams, MoveGroupParams, RepeatedGridGroupPB, RowPB,
+    CreateFilterParams, CreateRowParams, DeleteFilterParams, DeleteGroupParams, GridSettingPB, InsertGroupParams,
+    MoveGroupParams, RepeatedGridGroupPB, RowPB,
 };
 };
 use crate::manager::GridUser;
 use crate::manager::GridUser;
-use crate::services::grid_editor_task::GridServiceTaskScheduler;
-use crate::services::grid_view_editor::{GridViewRevisionCompress, GridViewRevisionEditor};
 
 
+use crate::services::grid_view_editor::{GridViewEditorDelegate, GridViewRevisionCompress, GridViewRevisionEditor};
 use crate::services::persistence::rev_sqlite::SQLiteGridViewRevisionPersistence;
 use crate::services::persistence::rev_sqlite::SQLiteGridViewRevisionPersistence;
+
 use dashmap::DashMap;
 use dashmap::DashMap;
 use flowy_database::ConnectionPool;
 use flowy_database::ConnectionPool;
 use flowy_error::FlowyResult;
 use flowy_error::FlowyResult;
 use flowy_revision::{
 use flowy_revision::{
     RevisionManager, RevisionPersistence, RevisionPersistenceConfiguration, SQLiteRevisionSnapshotPersistence,
     RevisionManager, RevisionPersistence, RevisionPersistenceConfiguration, SQLiteRevisionSnapshotPersistence,
 };
 };
-use grid_rev_model::{FieldRevision, RowChangeset, RowRevision};
-use lib_infra::future::AFFuture;
+
+use crate::services::filter::FilterType;
+use grid_rev_model::{FilterRevision, RowChangeset, RowRevision};
+use lib_infra::future::Fut;
 use std::sync::Arc;
 use std::sync::Arc;
 
 
 type ViewId = String;
 type ViewId = String;
 
 
-pub trait GridViewFieldDelegate: Send + Sync + 'static {
-    fn get_field_revs(&self) -> AFFuture<Vec<Arc<FieldRevision>>>;
-    fn get_field_rev(&self, field_id: &str) -> AFFuture<Option<Arc<FieldRevision>>>;
-}
-
-pub trait GridViewRowDelegate: Send + Sync + 'static {
-    fn gv_index_of_row(&self, row_id: &str) -> AFFuture<Option<usize>>;
-    fn gv_get_row_rev(&self, row_id: &str) -> AFFuture<Option<Arc<RowRevision>>>;
-    fn gv_row_revs(&self) -> AFFuture<Vec<Arc<RowRevision>>>;
-}
-
 pub(crate) struct GridViewManager {
 pub(crate) struct GridViewManager {
     grid_id: String,
     grid_id: String,
     user: Arc<dyn GridUser>,
     user: Arc<dyn GridUser>,
-    field_delegate: Arc<dyn GridViewFieldDelegate>,
-    row_delegate: Arc<dyn GridViewRowDelegate>,
+    delegate: Arc<dyn GridViewEditorDelegate>,
     view_editors: DashMap<ViewId, Arc<GridViewRevisionEditor>>,
     view_editors: DashMap<ViewId, Arc<GridViewRevisionEditor>>,
-    scheduler: Arc<dyn GridServiceTaskScheduler>,
 }
 }
 
 
 impl GridViewManager {
 impl GridViewManager {
     pub(crate) async fn new(
     pub(crate) async fn new(
         grid_id: String,
         grid_id: String,
         user: Arc<dyn GridUser>,
         user: Arc<dyn GridUser>,
-        field_delegate: Arc<dyn GridViewFieldDelegate>,
-        row_delegate: Arc<dyn GridViewRowDelegate>,
-        scheduler: Arc<dyn GridServiceTaskScheduler>,
+        delegate: Arc<dyn GridViewEditorDelegate>,
     ) -> FlowyResult<Self> {
     ) -> FlowyResult<Self> {
         Ok(Self {
         Ok(Self {
             grid_id,
             grid_id,
             user,
             user,
-            scheduler,
-            field_delegate,
-            row_delegate,
+            delegate,
             view_editors: DashMap::default(),
             view_editors: DashMap::default(),
         })
         })
     }
     }
 
 
+    pub(crate) async fn close(&self, _view_id: &str) {
+        if let Ok(editor) = self.get_default_view_editor().await {
+            let _ = editor.close().await;
+        }
+    }
+
+    pub async fn filter_rows(&self, block_id: &str, rows: Vec<Arc<RowRevision>>) -> FlowyResult<Vec<Arc<RowRevision>>> {
+        let editor = self.get_default_view_editor().await?;
+        let rows = editor.filter_rows(block_id, rows).await;
+        Ok(rows)
+    }
+
     pub(crate) async fn duplicate_grid_view(&self) -> FlowyResult<String> {
     pub(crate) async fn duplicate_grid_view(&self) -> FlowyResult<String> {
         let editor = self.get_default_view_editor().await?;
         let editor = self.get_default_view_editor().await?;
         let view_data = editor.duplicate_view_data().await?;
         let view_data = editor.duplicate_view_data().await?;
@@ -79,7 +76,7 @@ impl GridViewManager {
 
 
     /// Insert/Delete the group's row if the corresponding cell data was changed.  
     /// Insert/Delete the group's row if the corresponding cell data was changed.  
     pub(crate) async fn did_update_cell(&self, row_id: &str) {
     pub(crate) async fn did_update_cell(&self, row_id: &str) {
-        match self.row_delegate.gv_get_row_rev(row_id).await {
+        match self.delegate.get_row_rev(row_id).await {
             None => {
             None => {
                 tracing::warn!("Can not find the row in grid view");
                 tracing::warn!("Can not find the row in grid view");
             }
             }
@@ -108,12 +105,17 @@ impl GridViewManager {
         Ok(view_editor.get_view_setting().await)
         Ok(view_editor.get_view_setting().await)
     }
     }
 
 
-    pub(crate) async fn get_filters(&self) -> FlowyResult<Vec<GridFilterConfigurationPB>> {
+    pub(crate) async fn get_all_filters(&self) -> FlowyResult<Vec<Arc<FilterRevision>>> {
         let view_editor = self.get_default_view_editor().await?;
         let view_editor = self.get_default_view_editor().await?;
-        Ok(view_editor.get_view_filters().await)
+        Ok(view_editor.get_all_view_filters().await)
     }
     }
 
 
-    pub(crate) async fn insert_or_update_filter(&self, params: InsertFilterParams) -> FlowyResult<()> {
+    pub(crate) async fn get_filters(&self, filter_id: &FilterType) -> FlowyResult<Vec<Arc<FilterRevision>>> {
+        let view_editor = self.get_default_view_editor().await?;
+        Ok(view_editor.get_view_filters(filter_id).await)
+    }
+
+    pub(crate) async fn insert_or_update_filter(&self, params: CreateFilterParams) -> FlowyResult<()> {
         let view_editor = self.get_default_view_editor().await?;
         let view_editor = self.get_default_view_editor().await?;
         view_editor.insert_view_filter(params).await
         view_editor.insert_view_filter(params).await
     }
     }
@@ -153,7 +155,7 @@ impl GridViewManager {
         row_rev: Arc<RowRevision>,
         row_rev: Arc<RowRevision>,
         to_group_id: String,
         to_group_id: String,
         to_row_id: Option<String>,
         to_row_id: Option<String>,
-        recv_row_changeset: impl FnOnce(RowChangeset) -> AFFuture<()>,
+        recv_row_changeset: impl FnOnce(RowChangeset) -> Fut<()>,
     ) -> FlowyResult<()> {
     ) -> FlowyResult<()> {
         let mut row_changeset = RowChangeset::new(row_rev.id.clone());
         let mut row_changeset = RowChangeset::new(row_rev.id.clone());
         let view_editor = self.get_default_view_editor().await?;
         let view_editor = self.get_default_view_editor().await?;
@@ -172,17 +174,6 @@ impl GridViewManager {
         Ok(())
         Ok(())
     }
     }
 
 
-    #[tracing::instrument(level = "trace", skip(self), err)]
-    pub(crate) async fn did_update_view_field(&self, field_id: &str) -> FlowyResult<()> {
-        let view_editor = self.get_default_view_editor().await?;
-        // Update the group if the group_id equal to the field_id
-        if view_editor.group_id().await != field_id {
-            return Ok(());
-        }
-        let _ = view_editor.did_update_view_field(field_id).await?;
-        Ok(())
-    }
-
     /// Notifies the view's field type-option data is changed
     /// Notifies the view's field type-option data is changed
     /// For the moment, only the groups will be generated after the type-option data changed. A
     /// For the moment, only the groups will be generated after the type-option data changed. A
     /// [FieldRevision] has a property named type_options contains a list of type-option data.
     /// [FieldRevision] has a property named type_options contains a list of type-option data.
@@ -193,7 +184,11 @@ impl GridViewManager {
     #[tracing::instrument(level = "trace", skip(self), err)]
     #[tracing::instrument(level = "trace", skip(self), err)]
     pub(crate) async fn did_update_view_field_type_option(&self, field_id: &str) -> FlowyResult<()> {
     pub(crate) async fn did_update_view_field_type_option(&self, field_id: &str) -> FlowyResult<()> {
         let view_editor = self.get_default_view_editor().await?;
         let view_editor = self.get_default_view_editor().await?;
-        let _ = view_editor.did_update_view_field(field_id).await?;
+        if view_editor.is_grouped().await {
+            let _ = view_editor.group_by_view_field(field_id).await?;
+        }
+
+        let _ = view_editor.did_update_view_field_type_option(field_id).await?;
         Ok(())
         Ok(())
     }
     }
 
 
@@ -201,16 +196,7 @@ impl GridViewManager {
         debug_assert!(!view_id.is_empty());
         debug_assert!(!view_id.is_empty());
         match self.view_editors.get(view_id) {
         match self.view_editors.get(view_id) {
             None => {
             None => {
-                let editor = Arc::new(
-                    make_view_editor(
-                        &self.user,
-                        view_id,
-                        self.field_delegate.clone(),
-                        self.row_delegate.clone(),
-                        self.scheduler.clone(),
-                    )
-                    .await?,
-                );
+                let editor = Arc::new(make_view_editor(&self.user, view_id, self.delegate.clone()).await?);
                 self.view_editors.insert(view_id.to_owned(), editor.clone());
                 self.view_editors.insert(view_id.to_owned(), editor.clone());
                 Ok(editor)
                 Ok(editor)
             }
             }
@@ -226,25 +212,14 @@ impl GridViewManager {
 async fn make_view_editor(
 async fn make_view_editor(
     user: &Arc<dyn GridUser>,
     user: &Arc<dyn GridUser>,
     view_id: &str,
     view_id: &str,
-    field_delegate: Arc<dyn GridViewFieldDelegate>,
-    row_delegate: Arc<dyn GridViewRowDelegate>,
-    scheduler: Arc<dyn GridServiceTaskScheduler>,
+    delegate: Arc<dyn GridViewEditorDelegate>,
 ) -> FlowyResult<GridViewRevisionEditor> {
 ) -> FlowyResult<GridViewRevisionEditor> {
     let rev_manager = make_grid_view_rev_manager(user, view_id).await?;
     let rev_manager = make_grid_view_rev_manager(user, view_id).await?;
     let user_id = user.user_id()?;
     let user_id = user.user_id()?;
     let token = user.token()?;
     let token = user.token()?;
     let view_id = view_id.to_owned();
     let view_id = view_id.to_owned();
 
 
-    GridViewRevisionEditor::new(
-        &user_id,
-        &token,
-        view_id,
-        field_delegate,
-        row_delegate,
-        scheduler,
-        rev_manager,
-    )
-    .await
+    GridViewRevisionEditor::new(&user_id, &token, view_id, delegate, rev_manager).await
 }
 }
 
 
 pub async fn make_grid_view_rev_manager(
 pub async fn make_grid_view_rev_manager(

+ 1 - 1
frontend/rust-lib/flowy-grid/src/services/group/action.rs

@@ -46,7 +46,7 @@ pub trait GroupControllerSharedActions: Send + Sync {
     fn field_id(&self) -> &str;
     fn field_id(&self) -> &str;
 
 
     /// Returns number of groups the current field has
     /// Returns number of groups the current field has
-    fn groups(&self) -> Vec<Group>;
+    fn groups(&self) -> Vec<&Group>;
 
 
     /// Returns the index and the group data with group_id
     /// Returns the index and the group data with group_id
     fn get_group(&self, group_id: &str) -> Option<(usize, Group)>;
     fn get_group(&self, group_id: &str) -> Option<(usize, Group)>;

+ 3 - 3
frontend/rust-lib/flowy-grid/src/services/group/configuration.rs

@@ -5,14 +5,14 @@ use grid_rev_model::{
     FieldRevision, FieldTypeRevision, GroupConfigurationContentSerde, GroupConfigurationRevision, GroupRevision,
     FieldRevision, FieldTypeRevision, GroupConfigurationContentSerde, GroupConfigurationRevision, GroupRevision,
 };
 };
 use indexmap::IndexMap;
 use indexmap::IndexMap;
-use lib_infra::future::AFFuture;
+use lib_infra::future::Fut;
 use std::collections::HashMap;
 use std::collections::HashMap;
 use std::fmt::Formatter;
 use std::fmt::Formatter;
 use std::marker::PhantomData;
 use std::marker::PhantomData;
 use std::sync::Arc;
 use std::sync::Arc;
 
 
 pub trait GroupConfigurationReader: Send + Sync + 'static {
 pub trait GroupConfigurationReader: Send + Sync + 'static {
-    fn get_configuration(&self) -> AFFuture<Option<Arc<GroupConfigurationRevision>>>;
+    fn get_configuration(&self) -> Fut<Option<Arc<GroupConfigurationRevision>>>;
 }
 }
 
 
 pub trait GroupConfigurationWriter: Send + Sync + 'static {
 pub trait GroupConfigurationWriter: Send + Sync + 'static {
@@ -21,7 +21,7 @@ pub trait GroupConfigurationWriter: Send + Sync + 'static {
         field_id: &str,
         field_id: &str,
         field_type: FieldTypeRevision,
         field_type: FieldTypeRevision,
         group_configuration: GroupConfigurationRevision,
         group_configuration: GroupConfigurationRevision,
-    ) -> AFFuture<FlowyResult<()>>;
+    ) -> Fut<FlowyResult<()>>;
 }
 }
 
 
 impl<T> std::fmt::Display for GroupContext<T> {
 impl<T> std::fmt::Display for GroupContext<T> {

+ 2 - 2
frontend/rust-lib/flowy-grid/src/services/group/controller.rs

@@ -165,8 +165,8 @@ where
         &self.field_id
         &self.field_id
     }
     }
 
 
-    fn groups(&self) -> Vec<Group> {
-        self.group_ctx.groups().into_iter().cloned().collect()
+    fn groups(&self) -> Vec<&Group> {
+        self.group_ctx.groups()
     }
     }
 
 
     fn get_group(&self, group_id: &str) -> Option<(usize, Group)> {
     fn get_group(&self, group_id: &str) -> Option<(usize, Group)> {

+ 2 - 2
frontend/rust-lib/flowy-grid/src/services/group/controller_impls/default_controller.rs

@@ -36,8 +36,8 @@ impl GroupControllerSharedActions for DefaultGroupController {
         &self.field_id
         &self.field_id
     }
     }
 
 
-    fn groups(&self) -> Vec<Group> {
-        vec![self.group.clone()]
+    fn groups(&self) -> Vec<&Group> {
+        vec![&self.group]
     }
     }
 
 
     fn get_group(&self, _group_id: &str) -> Option<(usize, Group)> {
     fn get_group(&self, _group_id: &str) -> Option<(usize, Group)> {

+ 1 - 5
frontend/rust-lib/flowy-grid/src/services/mod.rs

@@ -2,12 +2,10 @@ mod util;
 
 
 pub mod block_editor;
 pub mod block_editor;
 pub mod block_manager;
 pub mod block_manager;
-mod block_manager_trait_impl;
 pub mod cell;
 pub mod cell;
 pub mod field;
 pub mod field;
-mod filter;
+pub mod filter;
 pub mod grid_editor;
 pub mod grid_editor;
-mod grid_editor_task;
 mod grid_editor_trait_impl;
 mod grid_editor_trait_impl;
 pub mod grid_view_editor;
 pub mod grid_view_editor;
 pub mod grid_view_manager;
 pub mod grid_view_manager;
@@ -15,5 +13,3 @@ pub mod group;
 pub mod persistence;
 pub mod persistence;
 pub mod row;
 pub mod row;
 pub mod setting;
 pub mod setting;
-mod snapshot;
-pub mod tasks;

+ 12 - 35
frontend/rust-lib/flowy-grid/src/services/row/row_loader.rs

@@ -1,10 +1,10 @@
 use crate::entities::{BlockPB, RepeatedBlockPB, RowPB};
 use crate::entities::{BlockPB, RepeatedBlockPB, RowPB};
-use flowy_error::FlowyResult;
+
 use grid_rev_model::RowRevision;
 use grid_rev_model::RowRevision;
 use std::collections::HashMap;
 use std::collections::HashMap;
 use std::sync::Arc;
 use std::sync::Arc;
 
 
-pub struct GridBlockSnapshot {
+pub struct GridBlock {
     pub(crate) block_id: String,
     pub(crate) block_id: String,
     pub row_revs: Vec<Arc<RowRevision>>,
     pub row_revs: Vec<Arc<RowRevision>>,
 }
 }
@@ -35,7 +35,7 @@ pub(crate) fn block_from_row_orders(row_orders: Vec<RowPB>) -> Vec<BlockPB> {
 //     Some((field_id, cell))
 //     Some((field_id, cell))
 // }
 // }
 
 
-pub(crate) fn make_row_orders_from_row_revs(row_revs: &[Arc<RowRevision>]) -> Vec<RowPB> {
+pub(crate) fn make_row_pb_from_row_rev(row_revs: &[Arc<RowRevision>]) -> Vec<RowPB> {
     row_revs.iter().map(RowPB::from).collect::<Vec<_>>()
     row_revs.iter().map(RowPB::from).collect::<Vec<_>>()
 }
 }
 
 
@@ -53,36 +53,13 @@ pub(crate) fn make_rows_from_row_revs(row_revs: &[Arc<RowRevision>]) -> Vec<RowP
     row_revs.iter().map(make_row).collect::<Vec<_>>()
     row_revs.iter().map(make_row).collect::<Vec<_>>()
 }
 }
 
 
-pub(crate) fn make_grid_blocks(
-    block_ids: Option<Vec<String>>,
-    block_snapshots: Vec<GridBlockSnapshot>,
-) -> FlowyResult<RepeatedBlockPB> {
-    match block_ids {
-        None => Ok(block_snapshots
-            .into_iter()
-            .map(|snapshot| {
-                let row_orders = make_row_orders_from_row_revs(&snapshot.row_revs);
-                BlockPB::new(&snapshot.block_id, row_orders)
-            })
-            .collect::<Vec<BlockPB>>()
-            .into()),
-        Some(block_ids) => {
-            let block_meta_data_map: HashMap<&String, &Vec<Arc<RowRevision>>> = block_snapshots
-                .iter()
-                .map(|data| (&data.block_id, &data.row_revs))
-                .collect();
-
-            let mut grid_blocks = vec![];
-            for block_id in block_ids {
-                match block_meta_data_map.get(&block_id) {
-                    None => {}
-                    Some(row_revs) => {
-                        let row_orders = make_row_orders_from_row_revs(row_revs);
-                        grid_blocks.push(BlockPB::new(&block_id, row_orders));
-                    }
-                }
-            }
-            Ok(grid_blocks.into())
-        }
-    }
+pub(crate) fn make_block_pbs(blocks: Vec<GridBlock>) -> RepeatedBlockPB {
+    blocks
+        .into_iter()
+        .map(|block| {
+            let row_pbs = make_row_pb_from_row_rev(&block.row_revs);
+            BlockPB::new(&block.block_id, row_pbs)
+        })
+        .collect::<Vec<BlockPB>>()
+        .into()
 }
 }

+ 2 - 2
frontend/rust-lib/flowy-grid/src/services/setting/setting_builder.rs

@@ -1,4 +1,4 @@
-use crate::entities::{DeleteFilterParams, GridLayout, GridSettingChangesetParams, InsertFilterParams};
+use crate::entities::{CreateFilterParams, DeleteFilterParams, GridLayout, GridSettingChangesetParams};
 
 
 pub struct GridSettingChangesetBuilder {
 pub struct GridSettingChangesetBuilder {
     params: GridSettingChangesetParams,
     params: GridSettingChangesetParams,
@@ -17,7 +17,7 @@ impl GridSettingChangesetBuilder {
         Self { params }
         Self { params }
     }
     }
 
 
-    pub fn insert_filter(mut self, params: InsertFilterParams) -> Self {
+    pub fn insert_filter(mut self, params: CreateFilterParams) -> Self {
         self.params.insert_filter = Some(params);
         self.params.insert_filter = Some(params);
         self
         self
     }
     }

+ 0 - 3
frontend/rust-lib/flowy-grid/src/services/snapshot/mod.rs

@@ -1,3 +0,0 @@
-mod snapshot_service;
-
-pub use snapshot_service::*;

+ 0 - 7
frontend/rust-lib/flowy-grid/src/services/snapshot/snapshot_service.rs

@@ -1,7 +0,0 @@
-// pub struct GridSnapshotService {}
-//
-// impl GridSnapshotService {
-//     pub fn new() -> Self {
-//         Self {}
-//     }
-// }

+ 0 - 47
frontend/rust-lib/flowy-grid/src/services/tasks/runner.rs

@@ -1,47 +0,0 @@
-use crate::services::tasks::scheduler::GridTaskScheduler;
-
-use std::sync::Arc;
-use std::time::Duration;
-use tokio::sync::{watch, RwLock};
-use tokio::time::interval;
-
-pub struct GridTaskRunner {
-    scheduler: Arc<RwLock<GridTaskScheduler>>,
-    debounce_duration: Duration,
-    notifier: Option<watch::Receiver<bool>>,
-}
-
-impl GridTaskRunner {
-    pub fn new(
-        scheduler: Arc<RwLock<GridTaskScheduler>>,
-        notifier: watch::Receiver<bool>,
-        debounce_duration: Duration,
-    ) -> Self {
-        Self {
-            scheduler,
-            debounce_duration,
-            notifier: Some(notifier),
-        }
-    }
-
-    pub async fn run(mut self) {
-        let mut notifier = self
-            .notifier
-            .take()
-            .expect("The GridTaskRunner's notifier should only take once");
-
-        loop {
-            if notifier.changed().await.is_err() {
-                // The runner will be stopped if the corresponding Sender drop.
-                break;
-            }
-
-            if *notifier.borrow() {
-                break;
-            }
-            let mut interval = interval(self.debounce_duration);
-            interval.tick().await;
-            let _ = self.scheduler.write().await.process_next_task().await;
-        }
-    }
-}

+ 0 - 199
frontend/rust-lib/flowy-grid/src/services/tasks/scheduler.rs

@@ -1,199 +0,0 @@
-use crate::services::tasks::queue::GridTaskQueue;
-use crate::services::tasks::runner::GridTaskRunner;
-use crate::services::tasks::store::GridTaskStore;
-use crate::services::tasks::task::Task;
-
-use crate::services::tasks::{TaskContent, TaskId, TaskStatus};
-use flowy_error::FlowyError;
-use lib_infra::future::BoxResultFuture;
-use lib_infra::ref_map::{RefCountHashMap, RefCountValue};
-
-use std::sync::Arc;
-use std::time::Duration;
-use tokio::sync::{watch, RwLock};
-
-pub(crate) trait GridTaskHandler: Send + Sync + 'static {
-    fn handler_id(&self) -> &str;
-
-    fn process_content(&self, content: TaskContent) -> BoxResultFuture<(), FlowyError>;
-}
-
-#[derive(Clone)]
-struct RefCountTaskHandler(Arc<dyn GridTaskHandler>);
-impl RefCountValue for RefCountTaskHandler {
-    fn did_remove(&self) {}
-}
-
-pub struct GridTaskScheduler {
-    queue: GridTaskQueue,
-    store: GridTaskStore,
-    notifier: watch::Sender<bool>,
-    handlers: RefCountHashMap<RefCountTaskHandler>,
-}
-
-impl GridTaskScheduler {
-    pub(crate) fn new() -> Arc<RwLock<Self>> {
-        let (notifier, rx) = watch::channel(false);
-
-        let scheduler = Self {
-            queue: GridTaskQueue::new(),
-            store: GridTaskStore::new(),
-            notifier,
-            handlers: RefCountHashMap::new(),
-        };
-        // The runner will receive the newest value after start running.
-        scheduler.notify();
-
-        let scheduler = Arc::new(RwLock::new(scheduler));
-        let debounce_duration = Duration::from_millis(300);
-        let runner = GridTaskRunner::new(scheduler.clone(), rx, debounce_duration);
-        tokio::spawn(runner.run());
-
-        scheduler
-    }
-
-    pub(crate) fn register_handler<T>(&mut self, handler: Arc<T>)
-    where
-        T: GridTaskHandler,
-    {
-        let handler_id = handler.handler_id().to_owned();
-        self.handlers.insert(handler_id, RefCountTaskHandler(handler));
-    }
-
-    pub(crate) fn unregister_handler<T: AsRef<str>>(&mut self, handler_id: T) {
-        self.handlers.remove(handler_id.as_ref());
-    }
-
-    #[allow(dead_code)]
-    pub(crate) fn stop(&mut self) {
-        let _ = self.notifier.send(true);
-        self.queue.clear();
-        self.store.clear();
-    }
-
-    pub(crate) async fn process_next_task(&mut self) -> Option<()> {
-        let pending_task = self.queue.mut_head(|list| list.pop())?;
-        let mut task = self.store.remove_task(&pending_task.id)?;
-        let handler = self.handlers.get(&task.handler_id)?;
-
-        let ret = task.ret.take()?;
-        let content = task.content.take()?;
-
-        task.set_status(TaskStatus::Processing);
-        let _ = match handler.0.process_content(content).await {
-            Ok(_) => {
-                task.set_status(TaskStatus::Done);
-                let _ = ret.send(task.into());
-            }
-            Err(e) => {
-                tracing::error!("Process task failed: {:?}", e);
-                task.set_status(TaskStatus::Failure);
-                let _ = ret.send(task.into());
-            }
-        };
-        self.notify();
-        None
-    }
-
-    pub(crate) fn add_task(&mut self, task: Task) {
-        assert!(!task.is_finished());
-        self.queue.push(&task);
-        self.store.insert_task(task);
-        self.notify();
-    }
-
-    pub(crate) fn next_task_id(&self) -> TaskId {
-        self.store.next_task_id()
-    }
-
-    pub(crate) fn notify(&self) {
-        let _ = self.notifier.send(false);
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use crate::services::grid_editor_task::GridServiceTaskScheduler;
-    use crate::services::tasks::{GridTaskHandler, GridTaskScheduler, Task, TaskContent, TaskStatus};
-    use flowy_error::FlowyError;
-    use lib_infra::future::BoxResultFuture;
-    use lib_infra::ref_map::RefCountValue;
-    use std::sync::Arc;
-    use std::time::Duration;
-    use tokio::time::interval;
-
-    #[tokio::test]
-    async fn task_scheduler_snapshot_task_test() {
-        let scheduler = GridTaskScheduler::new();
-        scheduler
-            .write()
-            .await
-            .register_handler(Arc::new(MockGridTaskHandler()));
-
-        let task_id = scheduler.gen_task_id().await;
-        let mut task = Task::new("1", task_id, TaskContent::Snapshot);
-        let rx = task.rx.take().unwrap();
-        scheduler.write().await.add_task(task);
-        assert_eq!(rx.await.unwrap().status, TaskStatus::Done);
-    }
-
-    #[tokio::test]
-    async fn task_scheduler_snapshot_task_cancel_test() {
-        let scheduler = GridTaskScheduler::new();
-        scheduler
-            .write()
-            .await
-            .register_handler(Arc::new(MockGridTaskHandler()));
-
-        let task_id = scheduler.gen_task_id().await;
-        let mut task = Task::new("1", task_id, TaskContent::Snapshot);
-        let rx = task.rx.take().unwrap();
-        scheduler.write().await.add_task(task);
-        scheduler.write().await.stop();
-
-        assert_eq!(rx.await.unwrap().status, TaskStatus::Cancel);
-    }
-
-    #[tokio::test]
-    async fn task_scheduler_multi_task_test() {
-        let scheduler = GridTaskScheduler::new();
-        scheduler
-            .write()
-            .await
-            .register_handler(Arc::new(MockGridTaskHandler()));
-
-        let task_id = scheduler.gen_task_id().await;
-        let mut task_1 = Task::new("1", task_id, TaskContent::Snapshot);
-        let rx_1 = task_1.rx.take().unwrap();
-
-        let task_id = scheduler.gen_task_id().await;
-        let mut task_2 = Task::new("1", task_id, TaskContent::Snapshot);
-        let rx_2 = task_2.rx.take().unwrap();
-
-        scheduler.write().await.add_task(task_1);
-        scheduler.write().await.add_task(task_2);
-
-        assert_eq!(rx_1.await.unwrap().status, TaskStatus::Done);
-        assert_eq!(rx_2.await.unwrap().status, TaskStatus::Done);
-    }
-    struct MockGridTaskHandler();
-
-    impl RefCountValue for MockGridTaskHandler {
-        fn did_remove(&self) {}
-    }
-
-    impl GridTaskHandler for MockGridTaskHandler {
-        fn handler_id(&self) -> &str {
-            "1"
-        }
-
-        fn process_content(&self, _content: TaskContent) -> BoxResultFuture<(), FlowyError> {
-            Box::pin(async move {
-                let mut interval = interval(Duration::from_secs(1));
-                interval.tick().await;
-                interval.tick().await;
-                Ok(())
-            })
-        }
-    }
-}

+ 0 - 129
frontend/rust-lib/flowy-grid/src/services/tasks/task.rs

@@ -1,129 +0,0 @@
-#![allow(clippy::all)]
-#![allow(dead_code)]
-use crate::services::row::GridBlockSnapshot;
-use crate::services::tasks::queue::TaskHandlerId;
-use std::cmp::Ordering;
-
-#[derive(Eq, Debug, Clone, Copy)]
-pub enum TaskType {
-    /// Remove the row if it doesn't satisfy the filter.
-    Filter,
-    /// Generate snapshot for grid, unused by now.
-    Snapshot,
-
-    Group,
-}
-
-impl PartialEq for TaskType {
-    fn eq(&self, other: &Self) -> bool {
-        matches!(
-            (self, other),
-            (Self::Filter, Self::Filter) | (Self::Snapshot, Self::Snapshot)
-        )
-    }
-}
-
-pub type TaskId = u32;
-
-#[derive(Eq, Debug, Clone, Copy)]
-pub struct PendingTask {
-    pub ty: TaskType,
-    pub id: TaskId,
-}
-
-impl PartialEq for PendingTask {
-    fn eq(&self, other: &Self) -> bool {
-        self.id.eq(&other.id)
-    }
-}
-
-impl PartialOrd for PendingTask {
-    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
-        Some(self.cmp(other))
-    }
-}
-
-impl Ord for PendingTask {
-    fn cmp(&self, other: &Self) -> Ordering {
-        match (self.ty, other.ty) {
-            // Snapshot
-            (TaskType::Snapshot, TaskType::Snapshot) => Ordering::Equal,
-            (TaskType::Snapshot, _) => Ordering::Greater,
-            (_, TaskType::Snapshot) => Ordering::Less,
-            // Group
-            (TaskType::Group, TaskType::Group) => self.id.cmp(&other.id).reverse(),
-            (TaskType::Group, _) => Ordering::Greater,
-            (_, TaskType::Group) => Ordering::Greater,
-            // Filter
-            (TaskType::Filter, TaskType::Filter) => self.id.cmp(&other.id).reverse(),
-        }
-    }
-}
-
-pub(crate) struct FilterTaskContext {
-    pub blocks: Vec<GridBlockSnapshot>,
-}
-
-pub(crate) enum TaskContent {
-    #[allow(dead_code)]
-    Snapshot,
-    Group,
-    Filter(FilterTaskContext),
-}
-
-#[derive(Debug, Eq, PartialEq)]
-pub(crate) enum TaskStatus {
-    Pending,
-    Processing,
-    Done,
-    Failure,
-    Cancel,
-}
-
-pub(crate) struct Task {
-    pub id: TaskId,
-    pub handler_id: TaskHandlerId,
-    pub content: Option<TaskContent>,
-    status: TaskStatus,
-    pub ret: Option<tokio::sync::oneshot::Sender<TaskResult>>,
-    pub rx: Option<tokio::sync::oneshot::Receiver<TaskResult>>,
-}
-
-pub(crate) struct TaskResult {
-    pub id: TaskId,
-    pub(crate) status: TaskStatus,
-}
-
-impl std::convert::From<Task> for TaskResult {
-    fn from(task: Task) -> Self {
-        TaskResult {
-            id: task.id,
-            status: task.status,
-        }
-    }
-}
-
-impl Task {
-    pub fn new(handler_id: &str, id: TaskId, content: TaskContent) -> Self {
-        let (ret, rx) = tokio::sync::oneshot::channel();
-        Self {
-            handler_id: handler_id.to_owned(),
-            id,
-            content: Some(content),
-            ret: Some(ret),
-            rx: Some(rx),
-            status: TaskStatus::Pending,
-        }
-    }
-
-    pub fn set_status(&mut self, status: TaskStatus) {
-        self.status = status;
-    }
-
-    pub fn is_finished(&self) -> bool {
-        match self.status {
-            TaskStatus::Done => true,
-            _ => false,
-        }
-    }
-}

+ 27 - 0
frontend/rust-lib/flowy-grid/tests/grid/filter_test/checkbox_filter_test.rs

@@ -0,0 +1,27 @@
+use crate::grid::filter_test::script::FilterScript::*;
+use crate::grid::filter_test::script::GridFilterTest;
+use flowy_grid::entities::CheckboxFilterCondition;
+
+#[tokio::test]
+async fn grid_filter_checkbox_is_check_test() {
+    let mut test = GridFilterTest::new().await;
+    let scripts = vec![
+        CreateCheckboxFilter {
+            condition: CheckboxFilterCondition::IsChecked,
+        },
+        AssertNumberOfRows { expected: 2 },
+    ];
+    test.run_scripts(scripts).await;
+}
+
+#[tokio::test]
+async fn grid_filter_checkbox_is_uncheck_test() {
+    let mut test = GridFilterTest::new().await;
+    let scripts = vec![
+        CreateCheckboxFilter {
+            condition: CheckboxFilterCondition::IsUnChecked,
+        },
+        AssertNumberOfRows { expected: 3 },
+    ];
+    test.run_scripts(scripts).await;
+}

+ 17 - 0
frontend/rust-lib/flowy-grid/tests/grid/filter_test/date_filter_test.rs

@@ -0,0 +1,17 @@
+use crate::grid::filter_test::script::FilterScript::*;
+use crate::grid::filter_test::script::GridFilterTest;
+use flowy_grid::entities::DateFilterCondition;
+
+#[tokio::test]
+#[should_panic]
+async fn grid_filter_date_is_check_test() {
+    let mut test = GridFilterTest::new().await;
+    let scripts = vec![
+        CreateDateFilter {
+            condition: DateFilterCondition::DateIs,
+            content: "1647251762".to_string(),
+        },
+        AssertNumberOfRows { expected: 2 },
+    ];
+    test.run_scripts(scripts).await;
+}

+ 3 - 0
frontend/rust-lib/flowy-grid/tests/grid/filter_test/mod.rs

@@ -1,2 +1,5 @@
+mod checkbox_filter_test;
+mod date_filter_test;
+mod number_filter_test;
 mod script;
 mod script;
 mod text_filter_test;
 mod text_filter_test;

+ 82 - 0
frontend/rust-lib/flowy-grid/tests/grid/filter_test/number_filter_test.rs

@@ -0,0 +1,82 @@
+use crate::grid::filter_test::script::FilterScript::*;
+use crate::grid::filter_test::script::GridFilterTest;
+use flowy_grid::entities::NumberFilterCondition;
+
+#[tokio::test]
+async fn grid_filter_number_is_equal_test() {
+    let mut test = GridFilterTest::new().await;
+    let scripts = vec![
+        CreateNumberFilter {
+            condition: NumberFilterCondition::Equal,
+            content: "1".to_string(),
+        },
+        AssertNumberOfRows { expected: 1 },
+    ];
+    test.run_scripts(scripts).await;
+}
+
+#[tokio::test]
+async fn grid_filter_number_is_less_than_test() {
+    let mut test = GridFilterTest::new().await;
+    let scripts = vec![
+        CreateNumberFilter {
+            condition: NumberFilterCondition::LessThan,
+            content: "3".to_string(),
+        },
+        AssertNumberOfRows { expected: 2 },
+    ];
+    test.run_scripts(scripts).await;
+}
+
+#[tokio::test]
+#[should_panic]
+async fn grid_filter_number_is_less_than_test2() {
+    let mut test = GridFilterTest::new().await;
+    let scripts = vec![
+        CreateNumberFilter {
+            condition: NumberFilterCondition::LessThan,
+            content: "$3".to_string(),
+        },
+        AssertNumberOfRows { expected: 2 },
+    ];
+    test.run_scripts(scripts).await;
+}
+
+#[tokio::test]
+async fn grid_filter_number_is_less_than_or_equal_test() {
+    let mut test = GridFilterTest::new().await;
+    let scripts = vec![
+        CreateNumberFilter {
+            condition: NumberFilterCondition::LessThanOrEqualTo,
+            content: "3".to_string(),
+        },
+        AssertNumberOfRows { expected: 3 },
+    ];
+    test.run_scripts(scripts).await;
+}
+
+#[tokio::test]
+async fn grid_filter_number_is_empty_test() {
+    let mut test = GridFilterTest::new().await;
+    let scripts = vec![
+        CreateNumberFilter {
+            condition: NumberFilterCondition::NumberIsEmpty,
+            content: "".to_string(),
+        },
+        AssertNumberOfRows { expected: 1 },
+    ];
+    test.run_scripts(scripts).await;
+}
+
+#[tokio::test]
+async fn grid_filter_number_is_not_empty_test() {
+    let mut test = GridFilterTest::new().await;
+    let scripts = vec![
+        CreateNumberFilter {
+            condition: NumberFilterCondition::NumberIsNotEmpty,
+            content: "".to_string(),
+        },
+        AssertNumberOfRows { expected: 4 },
+    ];
+    test.run_scripts(scripts).await;
+}

+ 80 - 15
frontend/rust-lib/flowy-grid/tests/grid/filter_test/script.rs

@@ -3,21 +3,46 @@
 #![allow(dead_code)]
 #![allow(dead_code)]
 #![allow(unused_imports)]
 #![allow(unused_imports)]
 
 
-use flowy_grid::entities::{InsertFilterParams, InsertFilterPayloadPB, DeleteFilterParams, GridLayout, GridSettingChangesetParams, GridSettingPB};
+use futures::TryFutureExt;
+use flowy_grid::entities::{CreateFilterParams, CreateFilterPayloadPB, DeleteFilterParams, GridLayout, GridSettingChangesetParams, GridSettingPB, RowPB, TextFilterCondition, FieldType, NumberFilterCondition, CheckboxFilterCondition, DateFilterCondition};
 use flowy_grid::services::setting::GridSettingChangesetBuilder;
 use flowy_grid::services::setting::GridSettingChangesetBuilder;
 use grid_rev_model::{FieldRevision, FieldTypeRevision};
 use grid_rev_model::{FieldRevision, FieldTypeRevision};
+use flowy_grid::services::filter::FilterType;
 use crate::grid::grid_editor::GridEditorTest;
 use crate::grid::grid_editor::GridEditorTest;
 
 
 pub enum FilterScript {
 pub enum FilterScript {
-    InsertGridTableFilter {
-        payload: InsertFilterPayloadPB,
+    InsertFilter {
+        payload: CreateFilterPayloadPB,
     },
     },
-    AssertTableFilterCount {
+    CreateTextFilter {
+        condition: TextFilterCondition,
+        content: String,
+    },
+    CreateNumberFilter {
+        condition: NumberFilterCondition,
+        content: String,
+    },
+    CreateCheckboxFilter {
+        condition: CheckboxFilterCondition,
+    },
+    CreateDateFilter{
+        condition: DateFilterCondition,
+        content: String,
+    },
+    AssertFilterCount {
         count: i32,
         count: i32,
     },
     },
-    DeleteGridTableFilter {
+    DeleteFilter {
         filter_id: String,
         filter_id: String,
-        field_rev: FieldRevision,
+        filter_type: FilterType,
+    },
+    AssertFilterContent {
+        filter_type: FilterType,
+        condition: u32,
+        content: String
+    },
+    AssertNumberOfRows{
+        expected: usize,
     },
     },
     #[allow(dead_code)]
     #[allow(dead_code)]
     AssertGridSetting {
     AssertGridSetting {
@@ -45,25 +70,65 @@ impl GridFilterTest {
 
 
     pub async fn run_script(&mut self, script: FilterScript) {
     pub async fn run_script(&mut self, script: FilterScript) {
         match script {
         match script {
-           
-            FilterScript::InsertGridTableFilter { payload } => {
-                let params: InsertFilterParams = payload.try_into().unwrap();
-                let _ = self.editor.create_filter(params).await.unwrap();
+            FilterScript::InsertFilter { payload } => {
+                self.insert_filter(payload).await;
+            }
+            FilterScript::CreateTextFilter { condition, content} => {
+                let field_rev = self.get_field_rev(FieldType::RichText);
+                let payload =
+                    CreateFilterPayloadPB::new(field_rev, condition, content);
+                self.insert_filter(payload).await;
+            }
+            FilterScript::CreateNumberFilter {condition, content} => {
+                let field_rev = self.get_field_rev(FieldType::Number);
+                let payload =
+                    CreateFilterPayloadPB::new(field_rev, condition, content);
+                self.insert_filter(payload).await;
             }
             }
-            FilterScript::AssertTableFilterCount { count } => {
-                let filters = self.editor.get_grid_filter().await.unwrap();
+            FilterScript::CreateCheckboxFilter {condition} => {
+                let field_rev = self.get_field_rev(FieldType::Checkbox);
+                let payload =
+                    CreateFilterPayloadPB::new(field_rev, condition, "".to_string());
+                self.insert_filter(payload).await;
+            }
+            FilterScript::CreateDateFilter { condition, content} => {
+                let field_rev = self.get_field_rev(FieldType::DateTime);
+                let payload =
+                    CreateFilterPayloadPB::new(field_rev, condition, content);
+                self.insert_filter(payload).await;
+            }
+            FilterScript::AssertFilterCount { count } => {
+                let filters = self.editor.get_all_filters().await.unwrap();
                 assert_eq!(count as usize, filters.len());
                 assert_eq!(count as usize, filters.len());
             }
             }
-            FilterScript::DeleteGridTableFilter { filter_id, field_rev} => {
-                let params = DeleteFilterParams { field_id: field_rev.id, filter_id, field_type_rev: field_rev.ty };
+            FilterScript::AssertFilterContent { filter_type: filter_id, condition, content} => {
+                let filter = self.editor.get_filters(filter_id).await.unwrap().pop().unwrap();
+                assert_eq!(&filter.content, &content);
+                assert_eq!(filter.condition as u32, condition);
+
+            }
+            FilterScript::DeleteFilter {  filter_id, filter_type } => {
+                let params = DeleteFilterParams { filter_type, filter_id };
                 let _ = self.editor.delete_filter(params).await.unwrap();
                 let _ = self.editor.delete_filter(params).await.unwrap();
             }
             }
             FilterScript::AssertGridSetting { expected_setting } => {
             FilterScript::AssertGridSetting { expected_setting } => {
-                let setting = self.editor.get_grid_setting().await.unwrap();
+                let setting = self.editor.get_setting().await.unwrap();
                 assert_eq!(expected_setting, setting);
                 assert_eq!(expected_setting, setting);
             }
             }
+            FilterScript::AssertNumberOfRows { expected } => {
+                //
+                let grid = self.editor.get_grid().await.unwrap();
+                let rows = grid.blocks.into_iter().map(|block| block.rows).flatten().collect::<Vec<RowPB>>();
+                assert_eq!(rows.len(), expected);
+            }
         }
         }
     }
     }
+
+    async fn insert_filter(&self, payload: CreateFilterPayloadPB) {
+
+        let params: CreateFilterParams = payload.try_into().unwrap();
+        let _ = self.editor.create_filter(params).await.unwrap();
+    }
 }
 }
 
 
 
 

+ 67 - 24
frontend/rust-lib/flowy-grid/tests/grid/filter_test/text_filter_test.rs

@@ -1,26 +1,71 @@
 use crate::grid::filter_test::script::FilterScript::*;
 use crate::grid::filter_test::script::FilterScript::*;
 use crate::grid::filter_test::script::*;
 use crate::grid::filter_test::script::*;
-use flowy_grid::entities::{FieldType, InsertFilterPayloadPB, TextFilterCondition};
-use grid_rev_model::FieldRevision;
+use flowy_grid::entities::{CreateFilterPayloadPB, FieldType, TextFilterCondition};
+use flowy_grid::services::filter::FilterType;
 
 
 #[tokio::test]
 #[tokio::test]
-async fn grid_filter_create_test() {
+async fn grid_filter_text_is_empty_test() {
     let mut test = GridFilterTest::new().await;
     let mut test = GridFilterTest::new().await;
-    let field_rev = test.get_field_rev(FieldType::RichText);
-    let payload = InsertFilterPayloadPB::new(field_rev, TextFilterCondition::TextIsEmpty, Some("abc".to_owned()));
-    let scripts = vec![InsertGridTableFilter { payload }, AssertTableFilterCount { count: 1 }];
+    let scripts = vec![
+        CreateTextFilter {
+            condition: TextFilterCondition::TextIsEmpty,
+            content: "".to_string(),
+        },
+        AssertFilterCount { count: 1 },
+        AssertNumberOfRows { expected: 0 },
+    ];
     test.run_scripts(scripts).await;
     test.run_scripts(scripts).await;
 }
 }
 
 
 #[tokio::test]
 #[tokio::test]
-#[should_panic]
-async fn grid_filter_invalid_condition_panic_test() {
+async fn grid_filter_is_text_test() {
     let mut test = GridFilterTest::new().await;
     let mut test = GridFilterTest::new().await;
-    let field_rev = test.get_field_rev(FieldType::RichText).clone();
+    let scripts = vec![
+        CreateTextFilter {
+            condition: TextFilterCondition::Is,
+            content: "A".to_string(),
+        },
+        AssertNumberOfRows { expected: 1 },
+    ];
+    test.run_scripts(scripts).await;
+}
+
+#[tokio::test]
+async fn grid_filter_contain_text_test() {
+    let mut test = GridFilterTest::new().await;
+    let scripts = vec![
+        CreateTextFilter {
+            condition: TextFilterCondition::Contains,
+            content: "A".to_string(),
+        },
+        AssertNumberOfRows { expected: 3 },
+    ];
+    test.run_scripts(scripts).await;
+}
+
+#[tokio::test]
+async fn grid_filter_start_with_text_test() {
+    let mut test = GridFilterTest::new().await;
+    let scripts = vec![
+        CreateTextFilter {
+            condition: TextFilterCondition::StartsWith,
+            content: "A".to_string(),
+        },
+        AssertNumberOfRows { expected: 2 },
+    ];
+    test.run_scripts(scripts).await;
+}
 
 
-    // 100 is not a valid condition, so this test should be panic.
-    let payload = InsertFilterPayloadPB::new(&field_rev, 100, Some("".to_owned()));
-    let scripts = vec![InsertGridTableFilter { payload }];
+#[tokio::test]
+async fn grid_filter_ends_with_text_test() {
+    let mut test = GridFilterTest::new().await;
+    let scripts = vec![
+        CreateTextFilter {
+            condition: TextFilterCondition::EndsWith,
+            content: "A".to_string(),
+        },
+        AssertNumberOfRows { expected: 2 },
+    ];
     test.run_scripts(scripts).await;
     test.run_scripts(scripts).await;
 }
 }
 
 
@@ -28,24 +73,22 @@ async fn grid_filter_invalid_condition_panic_test() {
 async fn grid_filter_delete_test() {
 async fn grid_filter_delete_test() {
     let mut test = GridFilterTest::new().await;
     let mut test = GridFilterTest::new().await;
     let field_rev = test.get_field_rev(FieldType::RichText).clone();
     let field_rev = test.get_field_rev(FieldType::RichText).clone();
-    let payload = create_filter(&field_rev, TextFilterCondition::TextIsEmpty, "abc");
-    let scripts = vec![InsertGridTableFilter { payload }, AssertTableFilterCount { count: 1 }];
+    let payload = CreateFilterPayloadPB::new(&field_rev, TextFilterCondition::TextIsEmpty, "".to_string());
+    let scripts = vec![
+        InsertFilter { payload },
+        AssertFilterCount { count: 1 },
+        AssertNumberOfRows { expected: 0 },
+    ];
     test.run_scripts(scripts).await;
     test.run_scripts(scripts).await;
 
 
     let filter = test.grid_filters().await.pop().unwrap();
     let filter = test.grid_filters().await.pop().unwrap();
     test.run_scripts(vec![
     test.run_scripts(vec![
-        DeleteGridTableFilter {
+        DeleteFilter {
             filter_id: filter.id,
             filter_id: filter.id,
-            field_rev: field_rev.as_ref().clone(),
+            filter_type: FilterType::from(&field_rev),
         },
         },
-        AssertTableFilterCount { count: 0 },
+        AssertFilterCount { count: 0 },
+        AssertNumberOfRows { expected: 5 },
     ])
     ])
     .await;
     .await;
 }
 }
-
-#[tokio::test]
-async fn grid_filter_get_rows_test() {}
-
-fn create_filter(field_rev: &FieldRevision, condition: TextFilterCondition, s: &str) -> InsertFilterPayloadPB {
-    InsertFilterPayloadPB::new(field_rev, condition, Some(s.to_owned()))
-}

+ 8 - 13
frontend/rust-lib/flowy-grid/tests/grid/grid_editor.rs

@@ -3,6 +3,7 @@
 #![allow(unused_imports)]
 #![allow(unused_imports)]
 use crate::grid::block_test::util::GridRowTestBuilder;
 use crate::grid::block_test::util::GridRowTestBuilder;
 use bytes::Bytes;
 use bytes::Bytes;
+use flowy_error::FlowyResult;
 use flowy_grid::entities::*;
 use flowy_grid::entities::*;
 use flowy_grid::services::field::SelectOptionPB;
 use flowy_grid::services::field::SelectOptionPB;
 use flowy_grid::services::field::*;
 use flowy_grid::services::field::*;
@@ -55,7 +56,7 @@ impl GridEditorTest {
         let editor = sdk.grid_manager.open_grid(&test.view.id).await.unwrap();
         let editor = sdk.grid_manager.open_grid(&test.view.id).await.unwrap();
         let field_revs = editor.get_field_revs(None).await.unwrap();
         let field_revs = editor.get_field_revs(None).await.unwrap();
         let block_meta_revs = editor.get_block_meta_revs().await.unwrap();
         let block_meta_revs = editor.get_block_meta_revs().await.unwrap();
-        let row_revs = editor.grid_block_snapshots(None).await.unwrap().pop().unwrap().row_revs;
+        let row_revs = editor.get_blocks(None).await.unwrap().pop().unwrap().row_revs;
         assert_eq!(block_meta_revs.len(), 1);
         assert_eq!(block_meta_revs.len(), 1);
 
 
         // It seems like you should add the field in the make_test_grid() function.
         // It seems like you should add the field in the make_test_grid() function.
@@ -76,17 +77,11 @@ impl GridEditorTest {
     }
     }
 
 
     pub async fn get_row_revs(&self) -> Vec<Arc<RowRevision>> {
     pub async fn get_row_revs(&self) -> Vec<Arc<RowRevision>> {
-        self.editor
-            .grid_block_snapshots(None)
-            .await
-            .unwrap()
-            .pop()
-            .unwrap()
-            .row_revs
+        self.editor.get_blocks(None).await.unwrap().pop().unwrap().row_revs
     }
     }
 
 
-    pub async fn grid_filters(&self) -> Vec<GridFilterConfigurationPB> {
-        self.editor.get_grid_filter().await.unwrap()
+    pub async fn grid_filters(&self) -> Vec<FilterPB> {
+        self.editor.get_all_filters().await.unwrap()
     }
     }
 
 
     pub fn get_field_rev(&self, field_type: FieldType) -> &Arc<FieldRevision> {
     pub fn get_field_rev(&self, field_type: FieldType) -> &Arc<FieldRevision> {
@@ -239,7 +234,7 @@ fn make_test_grid() -> BuildGridContext {
             3 => {
             3 => {
                 for field_type in FieldType::iter() {
                 for field_type in FieldType::iter() {
                     match field_type {
                     match field_type {
-                        FieldType::RichText => row_builder.insert_text_cell("D"),
+                        FieldType::RichText => row_builder.insert_text_cell("DA"),
                         FieldType::Number => row_builder.insert_number_cell("4"),
                         FieldType::Number => row_builder.insert_number_cell("4"),
                         FieldType::DateTime => row_builder.insert_date_cell("1647251762"),
                         FieldType::DateTime => row_builder.insert_date_cell("1647251762"),
                         FieldType::SingleSelect => {
                         FieldType::SingleSelect => {
@@ -253,8 +248,8 @@ fn make_test_grid() -> BuildGridContext {
             4 => {
             4 => {
                 for field_type in FieldType::iter() {
                 for field_type in FieldType::iter() {
                     match field_type {
                     match field_type {
-                        FieldType::RichText => row_builder.insert_text_cell("E"),
-                        FieldType::Number => row_builder.insert_number_cell("5"),
+                        FieldType::RichText => row_builder.insert_text_cell("AE"),
+                        FieldType::Number => row_builder.insert_number_cell(""),
                         FieldType::DateTime => row_builder.insert_date_cell("1647251762"),
                         FieldType::DateTime => row_builder.insert_date_cell("1647251762"),
                         FieldType::SingleSelect => {
                         FieldType::SingleSelect => {
                             row_builder.insert_single_select_cell(|mut options| options.remove(2))
                             row_builder.insert_single_select_cell(|mut options| options.remove(2))

+ 1 - 0
frontend/rust-lib/flowy-sdk/Cargo.toml

@@ -16,6 +16,7 @@ grid-rev-model = { path = "../../../shared-lib/grid-rev-model" }
 flowy-database = { path = "../flowy-database" }
 flowy-database = { path = "../flowy-database" }
 flowy-document = { path = "../flowy-document", default-features = false }
 flowy-document = { path = "../flowy-document", default-features = false }
 flowy-revision = { path = "../flowy-revision" }
 flowy-revision = { path = "../flowy-revision" }
+flowy-task = { path = "../flowy-task" }
 
 
 tracing = { version = "0.1" }
 tracing = { version = "0.1" }
 futures-core = { version = "0.3", default-features = false }
 futures-core = { version = "0.3", default-features = false }

+ 8 - 1
frontend/rust-lib/flowy-sdk/src/deps_resolve/grid_deps.rs

@@ -6,22 +6,29 @@ use flowy_grid::services::persistence::GridDatabase;
 use flowy_http_model::ws_data::ClientRevisionWSData;
 use flowy_http_model::ws_data::ClientRevisionWSData;
 use flowy_net::ws::connection::FlowyWebSocketConnect;
 use flowy_net::ws::connection::FlowyWebSocketConnect;
 use flowy_revision::{RevisionWebSocket, WSStateReceiver};
 use flowy_revision::{RevisionWebSocket, WSStateReceiver};
+use flowy_task::TaskDispatcher;
 use flowy_user::services::UserSession;
 use flowy_user::services::UserSession;
 use futures_core::future::BoxFuture;
 use futures_core::future::BoxFuture;
 use lib_infra::future::BoxResultFuture;
 use lib_infra::future::BoxResultFuture;
 use lib_ws::{WSChannel, WebSocketRawMessage};
 use lib_ws::{WSChannel, WebSocketRawMessage};
 use std::convert::TryInto;
 use std::convert::TryInto;
 use std::sync::Arc;
 use std::sync::Arc;
+use tokio::sync::RwLock;
 
 
 pub struct GridDepsResolver();
 pub struct GridDepsResolver();
 
 
 impl GridDepsResolver {
 impl GridDepsResolver {
-    pub async fn resolve(ws_conn: Arc<FlowyWebSocketConnect>, user_session: Arc<UserSession>) -> Arc<GridManager> {
+    pub async fn resolve(
+        ws_conn: Arc<FlowyWebSocketConnect>,
+        user_session: Arc<UserSession>,
+        task_scheduler: Arc<RwLock<TaskDispatcher>>,
+    ) -> Arc<GridManager> {
         let user = Arc::new(GridUserImpl(user_session.clone()));
         let user = Arc::new(GridUserImpl(user_session.clone()));
         let rev_web_socket = Arc::new(GridRevisionWebSocket(ws_conn));
         let rev_web_socket = Arc::new(GridRevisionWebSocket(ws_conn));
         let grid_manager = Arc::new(GridManager::new(
         let grid_manager = Arc::new(GridManager::new(
             user.clone(),
             user.clone(),
             rev_web_socket,
             rev_web_socket,
+            task_scheduler,
             Arc::new(GridDatabaseImpl(user_session)),
             Arc::new(GridDatabaseImpl(user_session)),
         ));
         ));
 
 

+ 19 - 10
frontend/rust-lib/flowy-sdk/src/lib.rs

@@ -15,11 +15,13 @@ use flowy_net::{
     local_server::LocalServer,
     local_server::LocalServer,
     ws::connection::{listen_on_websocket, FlowyWebSocketConnect},
     ws::connection::{listen_on_websocket, FlowyWebSocketConnect},
 };
 };
+use flowy_task::{TaskDispatcher, TaskRunner};
 use flowy_user::services::{notifier::UserStatus, UserSession, UserSessionConfig};
 use flowy_user::services::{notifier::UserStatus, UserSession, UserSessionConfig};
 use lib_dispatch::prelude::*;
 use lib_dispatch::prelude::*;
 use lib_dispatch::runtime::tokio_default_runtime;
 use lib_dispatch::runtime::tokio_default_runtime;
 use module::mk_modules;
 use module::mk_modules;
 pub use module::*;
 pub use module::*;
+use std::time::Duration;
 use std::{
 use std::{
     fmt,
     fmt,
     sync::{
     sync::{
@@ -27,7 +29,7 @@ use std::{
         Arc,
         Arc,
     },
     },
 };
 };
-use tokio::sync::broadcast;
+use tokio::sync::{broadcast, RwLock};
 
 
 static INIT_LOG: AtomicBool = AtomicBool::new(false);
 static INIT_LOG: AtomicBool = AtomicBool::new(false);
 
 
@@ -103,9 +105,10 @@ pub struct FlowySDK {
     pub document_manager: Arc<DocumentManager>,
     pub document_manager: Arc<DocumentManager>,
     pub folder_manager: Arc<FolderManager>,
     pub folder_manager: Arc<FolderManager>,
     pub grid_manager: Arc<GridManager>,
     pub grid_manager: Arc<GridManager>,
-    pub dispatcher: Arc<EventDispatcher>,
+    pub event_dispatcher: Arc<EventDispatcher>,
     pub ws_conn: Arc<FlowyWebSocketConnect>,
     pub ws_conn: Arc<FlowyWebSocketConnect>,
     pub local_server: Option<Arc<LocalServer>>,
     pub local_server: Option<Arc<LocalServer>>,
+    pub task_dispatcher: Arc<RwLock<TaskDispatcher>>,
 }
 }
 
 
 impl FlowySDK {
 impl FlowySDK {
@@ -114,6 +117,10 @@ impl FlowySDK {
         init_kv(&config.root);
         init_kv(&config.root);
         tracing::debug!("🔥 {:?}", config);
         tracing::debug!("🔥 {:?}", config);
         let runtime = tokio_default_runtime().unwrap();
         let runtime = tokio_default_runtime().unwrap();
+        let task_scheduler = TaskDispatcher::new(Duration::from_secs(2));
+        let task_dispatcher = Arc::new(RwLock::new(task_scheduler));
+        runtime.spawn(TaskRunner::run(task_dispatcher.clone()));
+
         let (local_server, ws_conn) = mk_local_server(&config.server_config);
         let (local_server, ws_conn) = mk_local_server(&config.server_config);
         let (user_session, document_manager, folder_manager, local_server, grid_manager) = runtime.block_on(async {
         let (user_session, document_manager, folder_manager, local_server, grid_manager) = runtime.block_on(async {
             let user_session = mk_user_session(&config, &local_server, &config.server_config);
             let user_session = mk_user_session(&config, &local_server, &config.server_config);
@@ -125,7 +132,8 @@ impl FlowySDK {
                 &config.document,
                 &config.document,
             );
             );
 
 
-            let grid_manager = GridDepsResolver::resolve(ws_conn.clone(), user_session.clone()).await;
+            let grid_manager =
+                GridDepsResolver::resolve(ws_conn.clone(), user_session.clone(), task_dispatcher.clone()).await;
 
 
             let folder_manager = FolderDepsResolver::resolve(
             let folder_manager = FolderDepsResolver::resolve(
                 local_server.clone(),
                 local_server.clone(),
@@ -150,7 +158,7 @@ impl FlowySDK {
             )
             )
         });
         });
 
 
-        let dispatcher = Arc::new(EventDispatcher::construct(runtime, || {
+        let event_dispatcher = Arc::new(EventDispatcher::construct(runtime, || {
             mk_modules(
             mk_modules(
                 &ws_conn,
                 &ws_conn,
                 &folder_manager,
                 &folder_manager,
@@ -162,7 +170,7 @@ impl FlowySDK {
 
 
         _start_listening(
         _start_listening(
             &config,
             &config,
-            &dispatcher,
+            &event_dispatcher,
             &ws_conn,
             &ws_conn,
             &user_session,
             &user_session,
             &document_manager,
             &document_manager,
@@ -176,20 +184,21 @@ impl FlowySDK {
             document_manager,
             document_manager,
             folder_manager,
             folder_manager,
             grid_manager,
             grid_manager,
-            dispatcher,
+            event_dispatcher,
             ws_conn,
             ws_conn,
             local_server,
             local_server,
+            task_dispatcher,
         }
         }
     }
     }
 
 
     pub fn dispatcher(&self) -> Arc<EventDispatcher> {
     pub fn dispatcher(&self) -> Arc<EventDispatcher> {
-        self.dispatcher.clone()
+        self.event_dispatcher.clone()
     }
     }
 }
 }
 
 
 fn _start_listening(
 fn _start_listening(
     config: &FlowySDKConfig,
     config: &FlowySDKConfig,
-    dispatch: &EventDispatcher,
+    event_dispatch: &EventDispatcher,
     ws_conn: &Arc<FlowyWebSocketConnect>,
     ws_conn: &Arc<FlowyWebSocketConnect>,
     user_session: &Arc<UserSession>,
     user_session: &Arc<UserSession>,
     document_manager: &Arc<DocumentManager>,
     document_manager: &Arc<DocumentManager>,
@@ -206,7 +215,7 @@ fn _start_listening(
     let document_manager = document_manager.clone();
     let document_manager = document_manager.clone();
     let config = config.clone();
     let config = config.clone();
 
 
-    dispatch.spawn(async move {
+    event_dispatch.spawn(async move {
         user_session.init();
         user_session.init();
         listen_on_websocket(ws_conn.clone());
         listen_on_websocket(ws_conn.clone());
         _listen_user_status(
         _listen_user_status(
@@ -220,7 +229,7 @@ fn _start_listening(
         .await;
         .await;
     });
     });
 
 
-    dispatch.spawn(async move {
+    event_dispatch.spawn(async move {
         _listen_network_status(subscribe_network_type, cloned_folder_manager).await;
         _listen_network_status(subscribe_network_type, cloned_folder_manager).await;
     });
     });
 }
 }

+ 3 - 9
frontend/rust-lib/flowy-sdk/src/module.rs

@@ -11,20 +11,14 @@ pub fn mk_modules(
     folder_manager: &Arc<FolderManager>,
     folder_manager: &Arc<FolderManager>,
     grid_manager: &Arc<GridManager>,
     grid_manager: &Arc<GridManager>,
     user_session: &Arc<UserSession>,
     user_session: &Arc<UserSession>,
-    text_block_manager: &Arc<DocumentManager>,
+    document_manager: &Arc<DocumentManager>,
 ) -> Vec<Module> {
 ) -> Vec<Module> {
     let user_module = mk_user_module(user_session.clone());
     let user_module = mk_user_module(user_session.clone());
     let folder_module = mk_folder_module(folder_manager.clone());
     let folder_module = mk_folder_module(folder_manager.clone());
     let network_module = mk_network_module(ws_conn.clone());
     let network_module = mk_network_module(ws_conn.clone());
     let grid_module = mk_grid_module(grid_manager.clone());
     let grid_module = mk_grid_module(grid_manager.clone());
-    let text_block_module = mk_text_block_module(text_block_manager.clone());
-    vec![
-        user_module,
-        folder_module,
-        network_module,
-        grid_module,
-        text_block_module,
-    ]
+    let document_module = mk_text_block_module(document_manager.clone());
+    vec![user_module, folder_module, network_module, grid_module, document_module]
 }
 }
 
 
 fn mk_user_module(user_session: Arc<UserSession>) -> Module {
 fn mk_user_module(user_session: Arc<UserSession>) -> Module {

+ 17 - 0
frontend/rust-lib/flowy-task/Cargo.toml

@@ -0,0 +1,17 @@
+[package]
+name = "flowy-task"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+lib-infra = { path = "../../../shared-lib/lib-infra" }
+tokio = {version = "1", features = ["sync", "macros", ]}
+atomic_refcell = "0.1.8"
+anyhow = "1.0"
+tracing = { version = "0.1", features = ["log"] }
+
+[dev-dependencies]
+rand = "0.8.5"
+futures = "0.3.15"

+ 0 - 1
frontend/rust-lib/flowy-grid/src/services/tasks/mod.rs → frontend/rust-lib/flowy-task/src/lib.rs

@@ -1,5 +1,4 @@
 mod queue;
 mod queue;
-mod runner;
 mod scheduler;
 mod scheduler;
 mod store;
 mod store;
 mod task;
 mod task;

+ 5 - 11
frontend/rust-lib/flowy-grid/src/services/tasks/queue.rs → frontend/rust-lib/flowy-task/src/queue.rs

@@ -1,6 +1,5 @@
-use crate::services::tasks::task::{PendingTask, Task, TaskContent, TaskType};
+use crate::{PendingTask, Task};
 use atomic_refcell::AtomicRefCell;
 use atomic_refcell::AtomicRefCell;
-
 use std::cmp::Ordering;
 use std::cmp::Ordering;
 use std::collections::hash_map::Entry;
 use std::collections::hash_map::Entry;
 use std::collections::{BinaryHeap, HashMap};
 use std::collections::{BinaryHeap, HashMap};
@@ -8,30 +7,25 @@ use std::ops::{Deref, DerefMut};
 use std::sync::Arc;
 use std::sync::Arc;
 
 
 #[derive(Default)]
 #[derive(Default)]
-pub(crate) struct GridTaskQueue {
+pub(crate) struct TaskQueue {
     // index_tasks for quick access
     // index_tasks for quick access
     index_tasks: HashMap<TaskHandlerId, Arc<AtomicRefCell<TaskList>>>,
     index_tasks: HashMap<TaskHandlerId, Arc<AtomicRefCell<TaskList>>>,
     queue: BinaryHeap<Arc<AtomicRefCell<TaskList>>>,
     queue: BinaryHeap<Arc<AtomicRefCell<TaskList>>>,
 }
 }
 
 
-impl GridTaskQueue {
+impl TaskQueue {
     pub(crate) fn new() -> Self {
     pub(crate) fn new() -> Self {
         Self::default()
         Self::default()
     }
     }
 
 
     pub(crate) fn push(&mut self, task: &Task) {
     pub(crate) fn push(&mut self, task: &Task) {
         if task.content.is_none() {
         if task.content.is_none() {
-            tracing::warn!("Ignore task: {} with empty content", task.id);
+            tracing::warn!("The task:{} with empty content will be not executed", task.id);
             return;
             return;
         }
         }
 
 
-        let task_type = match task.content.as_ref().unwrap() {
-            TaskContent::Snapshot => TaskType::Snapshot,
-            TaskContent::Group => TaskType::Group,
-            TaskContent::Filter { .. } => TaskType::Filter,
-        };
         let pending_task = PendingTask {
         let pending_task = PendingTask {
-            ty: task_type,
+            qos: task.qos,
             id: task.id,
             id: task.id,
         };
         };
         match self.index_tasks.entry(task.handler_id.clone()) {
         match self.index_tasks.entry(task.handler_id.clone()) {

+ 187 - 0
frontend/rust-lib/flowy-task/src/scheduler.rs

@@ -0,0 +1,187 @@
+use crate::queue::TaskQueue;
+use crate::store::TaskStore;
+use crate::{Task, TaskContent, TaskId, TaskState};
+use anyhow::Error;
+use lib_infra::future::BoxResultFuture;
+use lib_infra::ref_map::{RefCountHashMap, RefCountValue};
+use std::sync::Arc;
+use std::time::Duration;
+
+use tokio::sync::{watch, RwLock};
+use tokio::time::interval;
+
+pub struct TaskDispatcher {
+    queue: TaskQueue,
+    store: TaskStore,
+    timeout: Duration,
+    handlers: RefCountHashMap<RefCountTaskHandler>,
+
+    notifier: watch::Sender<bool>,
+    pub(crate) notifier_rx: Option<watch::Receiver<bool>>,
+}
+
+impl TaskDispatcher {
+    pub fn new(timeout: Duration) -> Self {
+        let (notifier, notifier_rx) = watch::channel(false);
+        Self {
+            queue: TaskQueue::new(),
+            store: TaskStore::new(),
+            timeout,
+            handlers: RefCountHashMap::new(),
+            notifier,
+            notifier_rx: Some(notifier_rx),
+        }
+    }
+
+    pub fn register_handler<T>(&mut self, handler: T)
+    where
+        T: TaskHandler,
+    {
+        let handler_id = handler.handler_id().to_owned();
+        self.handlers.insert(handler_id, RefCountTaskHandler(Arc::new(handler)));
+    }
+
+    pub fn unregister_handler<T: AsRef<str>>(&mut self, handler_id: T) {
+        self.handlers.remove(handler_id.as_ref());
+    }
+
+    pub fn stop(&mut self) {
+        let _ = self.notifier.send(true);
+        self.queue.clear();
+        self.store.clear();
+    }
+
+    pub(crate) async fn process_next_task(&mut self) -> Option<()> {
+        let pending_task = self.queue.mut_head(|list| list.pop())?;
+        let mut task = self.store.remove_task(&pending_task.id)?;
+        let ret = task.ret.take()?;
+
+        // Do not execute the task if the task was cancelled.
+        if task.state().is_cancel() {
+            let _ = ret.send(task.into());
+            self.notify();
+            return None;
+        }
+
+        let content = task.content.take()?;
+        if let Some(handler) = self.handlers.get(&task.handler_id) {
+            task.set_state(TaskState::Processing);
+            match tokio::time::timeout(self.timeout, handler.run(content)).await {
+                Ok(result) => match result {
+                    Ok(_) => task.set_state(TaskState::Done),
+                    Err(e) => {
+                        tracing::error!("Process task failed: {:?}", e);
+                        task.set_state(TaskState::Failure);
+                    }
+                },
+                Err(e) => {
+                    tracing::error!("Process task timeout: {:?}", e);
+                    task.set_state(TaskState::Timeout);
+                }
+            }
+        } else {
+            task.set_state(TaskState::Cancel);
+        }
+        let _ = ret.send(task.into());
+        self.notify();
+        None
+    }
+
+    pub fn add_task(&mut self, task: Task) {
+        debug_assert!(!task.state().is_done());
+        if task.state().is_done() {
+            return;
+        }
+
+        self.queue.push(&task);
+        self.store.insert_task(task);
+        self.notify();
+    }
+
+    pub fn read_task(&self, task_id: &TaskId) -> Option<&Task> {
+        self.store.read_task(task_id)
+    }
+
+    pub fn cancel_task(&mut self, task_id: TaskId) {
+        if let Some(task) = self.store.mut_task(&task_id) {
+            task.set_state(TaskState::Cancel);
+        }
+    }
+
+    pub fn next_task_id(&self) -> TaskId {
+        self.store.next_task_id()
+    }
+
+    pub(crate) fn notify(&self) {
+        let _ = self.notifier.send(false);
+    }
+}
+pub struct TaskRunner();
+impl TaskRunner {
+    pub async fn run(dispatcher: Arc<RwLock<TaskDispatcher>>) {
+        dispatcher.read().await.notify();
+        let debounce_duration = Duration::from_millis(300);
+        let mut notifier = dispatcher.write().await.notifier_rx.take().expect("Only take once");
+        loop {
+            // stops the runner if the notifier was closed.
+            if notifier.changed().await.is_err() {
+                break;
+            }
+
+            // stops the runner if the value of notifier is `true`
+            if *notifier.borrow() {
+                break;
+            }
+
+            let mut interval = interval(debounce_duration);
+            interval.tick().await;
+            let _ = dispatcher.write().await.process_next_task().await;
+        }
+    }
+}
+
+pub trait TaskHandler: Send + Sync + 'static {
+    fn handler_id(&self) -> &str;
+
+    fn run(&self, content: TaskContent) -> BoxResultFuture<(), Error>;
+}
+
+impl<T> TaskHandler for Box<T>
+where
+    T: TaskHandler,
+{
+    fn handler_id(&self) -> &str {
+        (**self).handler_id()
+    }
+
+    fn run(&self, content: TaskContent) -> BoxResultFuture<(), Error> {
+        (**self).run(content)
+    }
+}
+
+impl<T> TaskHandler for Arc<T>
+where
+    T: TaskHandler,
+{
+    fn handler_id(&self) -> &str {
+        (**self).handler_id()
+    }
+
+    fn run(&self, content: TaskContent) -> BoxResultFuture<(), Error> {
+        (**self).run(content)
+    }
+}
+#[derive(Clone)]
+struct RefCountTaskHandler(Arc<dyn TaskHandler>);
+
+impl RefCountValue for RefCountTaskHandler {
+    fn did_remove(&self) {}
+}
+
+impl std::ops::Deref for RefCountTaskHandler {
+    type Target = Arc<dyn TaskHandler>;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}

+ 12 - 6
frontend/rust-lib/flowy-grid/src/services/tasks/store.rs → frontend/rust-lib/flowy-task/src/store.rs

@@ -1,16 +1,15 @@
-use crate::services::tasks::task::Task;
-use crate::services::tasks::{TaskId, TaskStatus};
+use crate::{Task, TaskId, TaskState};
 use std::collections::HashMap;
 use std::collections::HashMap;
 use std::mem;
 use std::mem;
 use std::sync::atomic::AtomicU32;
 use std::sync::atomic::AtomicU32;
 use std::sync::atomic::Ordering::SeqCst;
 use std::sync::atomic::Ordering::SeqCst;
 
 
-pub(crate) struct GridTaskStore {
+pub(crate) struct TaskStore {
     tasks: HashMap<TaskId, Task>,
     tasks: HashMap<TaskId, Task>,
     task_id_counter: AtomicU32,
     task_id_counter: AtomicU32,
 }
 }
 
 
-impl GridTaskStore {
+impl TaskStore {
     pub fn new() -> Self {
     pub fn new() -> Self {
         Self {
         Self {
             tasks: HashMap::new(),
             tasks: HashMap::new(),
@@ -26,13 +25,20 @@ impl GridTaskStore {
         self.tasks.remove(task_id)
         self.tasks.remove(task_id)
     }
     }
 
 
-    #[allow(dead_code)]
+    pub(crate) fn mut_task(&mut self, task_id: &TaskId) -> Option<&mut Task> {
+        self.tasks.get_mut(task_id)
+    }
+
+    pub(crate) fn read_task(&self, task_id: &TaskId) -> Option<&Task> {
+        self.tasks.get(task_id)
+    }
+
     pub(crate) fn clear(&mut self) {
     pub(crate) fn clear(&mut self) {
         let tasks = mem::take(&mut self.tasks);
         let tasks = mem::take(&mut self.tasks);
         tasks.into_values().for_each(|mut task| {
         tasks.into_values().for_each(|mut task| {
             if task.ret.is_some() {
             if task.ret.is_some() {
                 let ret = task.ret.take().unwrap();
                 let ret = task.ret.take().unwrap();
-                task.set_status(TaskStatus::Cancel);
+                task.set_state(TaskState::Cancel);
                 let _ = ret.send(task.into());
                 let _ = ret.send(task.into());
             }
             }
         });
         });

+ 142 - 0
frontend/rust-lib/flowy-task/src/task.rs

@@ -0,0 +1,142 @@
+use crate::TaskHandlerId;
+use std::cmp::Ordering;
+use tokio::sync::oneshot::{Receiver, Sender};
+
+#[derive(Eq, Debug, Clone, Copy)]
+pub enum QualityOfService {
+    Background,
+    UserInteractive,
+}
+
+impl PartialEq for QualityOfService {
+    fn eq(&self, other: &Self) -> bool {
+        matches!(
+            (self, other),
+            (Self::Background, Self::Background) | (Self::UserInteractive, Self::UserInteractive)
+        )
+    }
+}
+
+pub type TaskId = u32;
+
+#[derive(Eq, Debug, Clone, Copy)]
+pub struct PendingTask {
+    pub qos: QualityOfService,
+    pub id: TaskId,
+}
+
+impl PartialEq for PendingTask {
+    fn eq(&self, other: &Self) -> bool {
+        self.id.eq(&other.id)
+    }
+}
+
+impl PartialOrd for PendingTask {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+impl Ord for PendingTask {
+    fn cmp(&self, other: &Self) -> Ordering {
+        match (self.qos, other.qos) {
+            // User interactive
+            (QualityOfService::UserInteractive, QualityOfService::UserInteractive) => self.id.cmp(&other.id),
+            (QualityOfService::UserInteractive, _) => Ordering::Greater,
+            (_, QualityOfService::UserInteractive) => Ordering::Less,
+            // background
+            (QualityOfService::Background, QualityOfService::Background) => self.id.cmp(&other.id),
+        }
+    }
+}
+
+pub enum TaskContent {
+    Text(String),
+    Blob(Vec<u8>),
+}
+
+#[derive(Debug, Eq, PartialEq, Clone)]
+pub enum TaskState {
+    Pending,
+    Processing,
+    Done,
+    Failure,
+    Cancel,
+    Timeout,
+}
+
+impl TaskState {
+    pub fn is_pending(&self) -> bool {
+        matches!(self, TaskState::Pending)
+    }
+    pub fn is_done(&self) -> bool {
+        matches!(self, TaskState::Done)
+    }
+    pub fn is_cancel(&self) -> bool {
+        matches!(self, TaskState::Cancel)
+    }
+
+    pub fn is_processing(&self) -> bool {
+        matches!(self, TaskState::Processing)
+    }
+
+    pub fn is_failed(&self) -> bool {
+        matches!(self, TaskState::Failure)
+    }
+}
+
+pub struct Task {
+    pub id: TaskId,
+    pub handler_id: TaskHandlerId,
+    pub content: Option<TaskContent>,
+    pub qos: QualityOfService,
+    state: TaskState,
+    pub ret: Option<Sender<TaskResult>>,
+    pub recv: Option<Receiver<TaskResult>>,
+}
+
+impl Task {
+    pub fn background(handler_id: &str, id: TaskId, content: TaskContent) -> Self {
+        Self::new(handler_id, id, content, QualityOfService::Background)
+    }
+
+    pub fn user_interactive(handler_id: &str, id: TaskId, content: TaskContent) -> Self {
+        Self::new(handler_id, id, content, QualityOfService::UserInteractive)
+    }
+
+    pub fn new(handler_id: &str, id: TaskId, content: TaskContent, qos: QualityOfService) -> Self {
+        let handler_id = handler_id.to_owned();
+        let (ret, recv) = tokio::sync::oneshot::channel();
+        Self {
+            handler_id,
+            id,
+            content: Some(content),
+            qos,
+            ret: Some(ret),
+            recv: Some(recv),
+            state: TaskState::Pending,
+        }
+    }
+
+    pub fn state(&self) -> &TaskState {
+        &self.state
+    }
+
+    pub(crate) fn set_state(&mut self, status: TaskState) {
+        self.state = status;
+    }
+}
+
+pub struct TaskResult {
+    pub id: TaskId,
+    pub state: TaskState,
+}
+
+impl std::convert::From<Task> for TaskResult {
+    fn from(task: Task) -> Self {
+        TaskResult {
+            id: task.id,
+            state: task.state().clone(),
+        }
+    }
+}

+ 1 - 0
frontend/rust-lib/flowy-task/tests/main.rs

@@ -0,0 +1 @@
+mod task_test;

+ 3 - 0
frontend/rust-lib/flowy-task/tests/task_test/mod.rs

@@ -0,0 +1,3 @@
+mod script;
+mod task_cancel_test;
+mod task_order_test;

+ 196 - 0
frontend/rust-lib/flowy-task/tests/task_test/script.rs

@@ -0,0 +1,196 @@
+use anyhow::Error;
+use flowy_task::{Task, TaskContent, TaskDispatcher, TaskHandler, TaskId, TaskResult, TaskRunner, TaskState};
+use futures::stream::FuturesUnordered;
+use futures::StreamExt;
+use lib_infra::future::BoxResultFuture;
+use lib_infra::ref_map::RefCountValue;
+use rand::Rng;
+use std::sync::Arc;
+use std::time::Duration;
+use tokio::sync::oneshot::Receiver;
+use tokio::sync::RwLock;
+
+pub enum SearchScript {
+    AddTask {
+        task: Task,
+    },
+    AddTasks {
+        tasks: Vec<Task>,
+    },
+    #[allow(dead_code)]
+    Wait {
+        millisecond: u64,
+    },
+    CancelTask {
+        task_id: TaskId,
+    },
+    UnregisterHandler {
+        handler_id: String,
+    },
+    AssertTaskStatus {
+        task_id: TaskId,
+        expected_status: TaskState,
+    },
+    AssertExecuteOrder {
+        execute_order: Vec<u32>,
+        rets: Vec<Receiver<TaskResult>>,
+    },
+}
+
+pub struct SearchTest {
+    scheduler: Arc<RwLock<TaskDispatcher>>,
+}
+
+impl SearchTest {
+    pub async fn new() -> Self {
+        let duration = Duration::from_millis(1000);
+        let mut scheduler = TaskDispatcher::new(duration);
+        scheduler.register_handler(Arc::new(MockTextTaskHandler()));
+        scheduler.register_handler(Arc::new(MockBlobTaskHandler()));
+        scheduler.register_handler(Arc::new(MockTimeoutTaskHandler()));
+
+        let scheduler = Arc::new(RwLock::new(scheduler));
+        tokio::spawn(TaskRunner::run(scheduler.clone()));
+
+        Self { scheduler }
+    }
+
+    pub async fn next_task_id(&self) -> TaskId {
+        self.scheduler.read().await.next_task_id()
+    }
+
+    pub async fn run_scripts(&self, scripts: Vec<SearchScript>) {
+        for script in scripts {
+            self.run_script(script).await;
+        }
+    }
+
+    pub async fn run_script(&self, script: SearchScript) {
+        match script {
+            SearchScript::AddTask { task } => {
+                self.scheduler.write().await.add_task(task);
+            }
+            SearchScript::CancelTask { task_id } => {
+                self.scheduler.write().await.cancel_task(task_id);
+            }
+            SearchScript::AddTasks { tasks } => {
+                let mut scheduler = self.scheduler.write().await;
+                for task in tasks {
+                    scheduler.add_task(task);
+                }
+            }
+            SearchScript::Wait { millisecond } => {
+                tokio::time::sleep(Duration::from_millis(millisecond)).await;
+            }
+            SearchScript::UnregisterHandler { handler_id } => {
+                self.scheduler.write().await.unregister_handler(handler_id);
+            }
+            SearchScript::AssertTaskStatus {
+                task_id,
+                expected_status,
+            } => {
+                let status = self.scheduler.read().await.read_task(&task_id).unwrap().state().clone();
+                assert_eq!(status, expected_status);
+            }
+            SearchScript::AssertExecuteOrder { execute_order, rets } => {
+                let mut futures = FuturesUnordered::new();
+                for ret in rets {
+                    futures.push(ret);
+                }
+                let mut orders = vec![];
+                while let Some(Ok(result)) = futures.next().await {
+                    orders.push(result.id);
+                    assert!(result.state.is_done());
+                }
+                assert_eq!(execute_order, orders);
+            }
+        }
+    }
+}
+
+pub struct MockTextTaskHandler();
+impl RefCountValue for MockTextTaskHandler {
+    fn did_remove(&self) {}
+}
+
+impl TaskHandler for MockTextTaskHandler {
+    fn handler_id(&self) -> &str {
+        "1"
+    }
+
+    fn run(&self, content: TaskContent) -> BoxResultFuture<(), Error> {
+        let mut rng = rand::thread_rng();
+        let millisecond = rng.gen_range(1..50);
+        Box::pin(async move {
+            match content {
+                TaskContent::Text(_s) => {
+                    tokio::time::sleep(Duration::from_millis(millisecond)).await;
+                }
+                TaskContent::Blob(_) => panic!("Only support text"),
+            }
+            Ok(())
+        })
+    }
+}
+
+pub fn make_text_background_task(task_id: TaskId, s: &str) -> (Task, Receiver<TaskResult>) {
+    let mut task = Task::background("1", task_id, TaskContent::Text(s.to_owned()));
+    let recv = task.recv.take().unwrap();
+    (task, recv)
+}
+
+pub fn make_text_user_interactive_task(task_id: TaskId, s: &str) -> (Task, Receiver<TaskResult>) {
+    let mut task = Task::user_interactive("1", task_id, TaskContent::Text(s.to_owned()));
+    let recv = task.recv.take().unwrap();
+    (task, recv)
+}
+
+pub struct MockBlobTaskHandler();
+impl RefCountValue for MockBlobTaskHandler {
+    fn did_remove(&self) {}
+}
+
+impl TaskHandler for MockBlobTaskHandler {
+    fn handler_id(&self) -> &str {
+        "2"
+    }
+
+    fn run(&self, content: TaskContent) -> BoxResultFuture<(), Error> {
+        Box::pin(async move {
+            match content {
+                TaskContent::Text(_) => panic!("Only support blob"),
+                TaskContent::Blob(bytes) => {
+                    let _msg = String::from_utf8(bytes).unwrap();
+                    tokio::time::sleep(Duration::from_millis(20)).await;
+                }
+            }
+            Ok(())
+        })
+    }
+}
+
+pub struct MockTimeoutTaskHandler();
+
+impl TaskHandler for MockTimeoutTaskHandler {
+    fn handler_id(&self) -> &str {
+        "3"
+    }
+
+    fn run(&self, content: TaskContent) -> BoxResultFuture<(), Error> {
+        Box::pin(async move {
+            match content {
+                TaskContent::Text(_) => panic!("Only support blob"),
+                TaskContent::Blob(_bytes) => {
+                    tokio::time::sleep(Duration::from_millis(2000)).await;
+                }
+            }
+            Ok(())
+        })
+    }
+}
+
+pub fn make_timeout_task(task_id: TaskId) -> (Task, Receiver<TaskResult>) {
+    let mut task = Task::background("3", task_id, TaskContent::Blob(vec![]));
+    let recv = task.recv.take().unwrap();
+    (task, recv)
+}

+ 88 - 0
frontend/rust-lib/flowy-task/tests/task_test/task_cancel_test.rs

@@ -0,0 +1,88 @@
+use crate::task_test::script::SearchScript::*;
+use crate::task_test::script::{make_text_background_task, make_timeout_task, SearchTest};
+use flowy_task::{QualityOfService, Task, TaskContent, TaskState};
+
+#[tokio::test]
+async fn task_cancel_background_task_test() {
+    let test = SearchTest::new().await;
+    let (task_1, ret_1) = make_text_background_task(test.next_task_id().await, "Hello world");
+    let (task_2, ret_2) = make_text_background_task(test.next_task_id().await, "");
+    test.run_scripts(vec![
+        AddTask { task: task_1 },
+        AddTask { task: task_2 },
+        AssertTaskStatus {
+            task_id: 1,
+            expected_status: TaskState::Pending,
+        },
+        AssertTaskStatus {
+            task_id: 2,
+            expected_status: TaskState::Pending,
+        },
+        CancelTask { task_id: 2 },
+        AssertTaskStatus {
+            task_id: 2,
+            expected_status: TaskState::Cancel,
+        },
+    ])
+    .await;
+
+    let result = ret_1.await.unwrap();
+    assert_eq!(result.state, TaskState::Done);
+
+    let result = ret_2.await.unwrap();
+    assert_eq!(result.state, TaskState::Cancel);
+}
+
+#[tokio::test]
+async fn task_with_empty_handler_id_test() {
+    let test = SearchTest::new().await;
+    let mut task = Task::new(
+        "",
+        test.next_task_id().await,
+        TaskContent::Text("".to_owned()),
+        QualityOfService::Background,
+    );
+    let ret = task.recv.take().unwrap();
+    test.run_scripts(vec![AddTask { task }]).await;
+
+    let result = ret.await.unwrap();
+    assert_eq!(result.state, TaskState::Cancel);
+}
+
+#[tokio::test]
+async fn task_can_not_find_handler_test() {
+    let test = SearchTest::new().await;
+    let (task, ret) = make_text_background_task(test.next_task_id().await, "Hello world");
+    let handler_id = task.handler_id.clone();
+    test.run_scripts(vec![UnregisterHandler { handler_id }, AddTask { task }])
+        .await;
+
+    let result = ret.await.unwrap();
+    assert_eq!(result.state, TaskState::Cancel);
+}
+
+#[tokio::test]
+async fn task_can_not_find_handler_test2() {
+    let test = SearchTest::new().await;
+    let mut tasks = vec![];
+    let mut rets = vec![];
+    let handler_id = "1".to_owned();
+    for _i in 1..10000 {
+        let (task, ret) = make_text_background_task(test.next_task_id().await, "");
+        tasks.push(task);
+        rets.push(ret);
+    }
+
+    test.run_scripts(vec![UnregisterHandler { handler_id }, AddTasks { tasks }])
+        .await;
+}
+
+#[tokio::test]
+async fn task_run_timeout_test() {
+    let test = SearchTest::new().await;
+    let (task, ret) = make_timeout_task(test.next_task_id().await);
+    test.run_scripts(vec![AddTask { task }]).await;
+
+    let result = ret.await.unwrap();
+    assert_eq!(result.state, TaskState::Timeout);
+}

+ 111 - 0
frontend/rust-lib/flowy-task/tests/task_test/task_order_test.rs

@@ -0,0 +1,111 @@
+use crate::task_test::script::{
+    make_text_background_task, make_text_user_interactive_task, SearchScript::*, SearchTest,
+};
+
+#[tokio::test]
+async fn task_add_single_background_task_test() {
+    let test = SearchTest::new().await;
+    let (task, ret) = make_text_background_task(test.next_task_id().await, "");
+    test.run_scripts(vec![AddTask { task }]).await;
+
+    let result = ret.await.unwrap();
+    assert!(result.state.is_done())
+}
+
+#[tokio::test]
+async fn task_add_multiple_background_tasks_test() {
+    let test = SearchTest::new().await;
+    let (task_1, ret_1) = make_text_background_task(test.next_task_id().await, "");
+    let (task_2, ret_2) = make_text_background_task(test.next_task_id().await, "");
+    let (task_3, ret_3) = make_text_background_task(test.next_task_id().await, "");
+    test.run_scripts(vec![
+        AddTask { task: task_1 },
+        AddTask { task: task_2 },
+        AddTask { task: task_3 },
+        AssertExecuteOrder {
+            execute_order: vec![3, 2, 1],
+            rets: vec![ret_1, ret_2, ret_3],
+        },
+    ])
+    .await;
+}
+
+#[tokio::test]
+async fn task_add_multiple_user_interactive_tasks_test() {
+    let test = SearchTest::new().await;
+    let (task_1, ret_1) = make_text_user_interactive_task(test.next_task_id().await, "");
+    let (task_2, ret_2) = make_text_user_interactive_task(test.next_task_id().await, "");
+    let (task_3, ret_3) = make_text_user_interactive_task(test.next_task_id().await, "");
+    test.run_scripts(vec![
+        AddTask { task: task_1 },
+        AddTask { task: task_2 },
+        AddTask { task: task_3 },
+        AssertExecuteOrder {
+            execute_order: vec![3, 2, 1],
+            rets: vec![ret_1, ret_2, ret_3],
+        },
+    ])
+    .await;
+}
+#[tokio::test]
+async fn task_add_multiple_different_kind_tasks_test() {
+    let test = SearchTest::new().await;
+    let (task_1, ret_1) = make_text_background_task(test.next_task_id().await, "");
+    let (task_2, ret_2) = make_text_user_interactive_task(test.next_task_id().await, "");
+    let (task_3, ret_3) = make_text_background_task(test.next_task_id().await, "");
+    test.run_scripts(vec![
+        AddTask { task: task_1 },
+        AddTask { task: task_2 },
+        AddTask { task: task_3 },
+        AssertExecuteOrder {
+            execute_order: vec![2, 3, 1],
+            rets: vec![ret_1, ret_2, ret_3],
+        },
+    ])
+    .await;
+}
+
+#[tokio::test]
+async fn task_add_multiple_different_kind_tasks_test2() {
+    let test = SearchTest::new().await;
+    let mut tasks = vec![];
+    let mut rets = vec![];
+
+    for i in 0..10 {
+        let (task, ret) = if i % 2 == 0 {
+            make_text_background_task(test.next_task_id().await, "")
+        } else {
+            make_text_user_interactive_task(test.next_task_id().await, "")
+        };
+        tasks.push(task);
+        rets.push(ret);
+    }
+
+    test.run_scripts(vec![
+        AddTasks { tasks },
+        AssertExecuteOrder {
+            execute_order: vec![10, 8, 6, 4, 2, 9, 7, 5, 3, 1],
+            rets,
+        },
+    ])
+    .await;
+}
+
+// #[tokio::test]
+// async fn task_add_1000_tasks_test() {
+//     let test = SearchTest::new().await;
+//     let mut tasks = vec![];
+//     let mut execute_order = vec![];
+//     let mut rets = vec![];
+//
+//     for i in 1..1000 {
+//         let (task, ret) = make_text_background_task(test.next_task_id().await, "");
+//         execute_order.push(i);
+//         tasks.push(task);
+//         rets.push(ret);
+//     }
+//     execute_order.reverse();
+//
+//     test.run_scripts(vec![AddTasks { tasks }, AssertExecuteOrder { execute_order, rets }])
+//         .await;
+// }

+ 8 - 8
shared-lib/flowy-sync/src/client_grid/grid_revision_pad.rs

@@ -189,14 +189,6 @@ impl GridRevisionPad {
         })
         })
     }
     }
 
 
-    pub fn get_field_rev(&self, field_id: &str) -> Option<(usize, &Arc<FieldRevision>)> {
-        self.grid_rev
-            .fields
-            .iter()
-            .enumerate()
-            .find(|(_, field)| field.id == field_id)
-    }
-
     pub fn replace_field_rev(
     pub fn replace_field_rev(
         &mut self,
         &mut self,
         field_rev: Arc<FieldRevision>,
         field_rev: Arc<FieldRevision>,
@@ -238,6 +230,14 @@ impl GridRevisionPad {
         self.grid_rev.fields.iter().any(|field| field.id == field_id)
         self.grid_rev.fields.iter().any(|field| field.id == field_id)
     }
     }
 
 
+    pub fn get_field_rev(&self, field_id: &str) -> Option<(usize, &Arc<FieldRevision>)> {
+        self.grid_rev
+            .fields
+            .iter()
+            .enumerate()
+            .find(|(_, field)| field.id == field_id)
+    }
+
     pub fn get_field_revs(&self, field_ids: Option<Vec<String>>) -> CollaborateResult<Vec<Arc<FieldRevision>>> {
     pub fn get_field_revs(&self, field_ids: Option<Vec<String>>) -> CollaborateResult<Vec<Arc<FieldRevision>>> {
         match field_ids {
         match field_ids {
             None => Ok(self.grid_rev.fields.clone()),
             None => Ok(self.grid_rev.fields.clone()),

+ 18 - 15
shared-lib/flowy-sync/src/client_grid/view_revision_pad.rs

@@ -3,8 +3,7 @@ use crate::util::{cal_diff, make_operations_from_revisions};
 use flowy_http_model::revision::Revision;
 use flowy_http_model::revision::Revision;
 use flowy_http_model::util::md5;
 use flowy_http_model::util::md5;
 use grid_rev_model::{
 use grid_rev_model::{
-    FieldRevision, FieldTypeRevision, FilterConfigurationRevision, FilterConfigurationsByFieldId, GridViewRevision,
-    GroupConfigurationRevision, GroupConfigurationsByFieldId, LayoutRevision,
+    FieldRevision, FieldTypeRevision, FilterRevision, GridViewRevision, GroupConfigurationRevision, LayoutRevision,
 };
 };
 use lib_ot::core::{DeltaBuilder, DeltaOperations, EmptyAttributes, OperationTransform};
 use lib_ot::core::{DeltaBuilder, DeltaOperations, EmptyAttributes, OperationTransform};
 use std::sync::Arc;
 use std::sync::Arc;
@@ -61,8 +60,12 @@ impl GridViewRevisionPad {
         Self::from_operations(view_id, operations)
         Self::from_operations(view_id, operations)
     }
     }
 
 
-    pub fn get_groups_by_field_revs(&self, field_revs: &[Arc<FieldRevision>]) -> Option<GroupConfigurationsByFieldId> {
-        self.groups.get_objects_by_field_revs(field_revs)
+    pub fn get_groups_by_field_revs(&self, field_revs: &[Arc<FieldRevision>]) -> Vec<Arc<GroupConfigurationRevision>> {
+        self.groups
+            .get_objects_by_field_revs(field_revs)
+            .into_values()
+            .flatten()
+            .collect()
     }
     }
 
 
     pub fn get_all_groups(&self) -> Vec<Arc<GroupConfigurationRevision>> {
     pub fn get_all_groups(&self) -> Vec<Arc<GroupConfigurationRevision>> {
@@ -113,9 +116,9 @@ impl GridViewRevisionPad {
 
 
     pub fn delete_group(
     pub fn delete_group(
         &mut self,
         &mut self,
+        group_id: &str,
         field_id: &str,
         field_id: &str,
         field_type: &FieldTypeRevision,
         field_type: &FieldTypeRevision,
-        group_id: &str,
     ) -> CollaborateResult<Option<GridViewRevisionChangeset>> {
     ) -> CollaborateResult<Option<GridViewRevisionChangeset>> {
         self.modify(|view| {
         self.modify(|view| {
             if let Some(groups) = view.groups.get_mut_objects(field_id, field_type) {
             if let Some(groups) = view.groups.get_mut_objects(field_id, field_type) {
@@ -127,23 +130,23 @@ impl GridViewRevisionPad {
         })
         })
     }
     }
 
 
-    pub fn get_all_filters(&self, field_revs: &[Arc<FieldRevision>]) -> Option<FilterConfigurationsByFieldId> {
-        self.filters.get_objects_by_field_revs(field_revs)
+    pub fn get_all_filters(&self, field_revs: &[Arc<FieldRevision>]) -> Vec<Arc<FilterRevision>> {
+        self.filters
+            .get_objects_by_field_revs(field_revs)
+            .into_values()
+            .flatten()
+            .collect()
     }
     }
 
 
-    pub fn get_filters(
-        &self,
-        field_id: &str,
-        field_type_rev: &FieldTypeRevision,
-    ) -> Option<Vec<Arc<FilterConfigurationRevision>>> {
-        self.filters.get_objects(field_id, field_type_rev)
+    pub fn get_filters(&self, field_id: &str, field_type_rev: &FieldTypeRevision) -> Vec<Arc<FilterRevision>> {
+        self.filters.get_objects(field_id, field_type_rev).unwrap_or_default()
     }
     }
 
 
     pub fn insert_filter(
     pub fn insert_filter(
         &mut self,
         &mut self,
         field_id: &str,
         field_id: &str,
         field_type: &FieldTypeRevision,
         field_type: &FieldTypeRevision,
-        filter_rev: FilterConfigurationRevision,
+        filter_rev: FilterRevision,
     ) -> CollaborateResult<Option<GridViewRevisionChangeset>> {
     ) -> CollaborateResult<Option<GridViewRevisionChangeset>> {
         self.modify(|view| {
         self.modify(|view| {
             view.filters.add_object(field_id, field_type, filter_rev);
             view.filters.add_object(field_id, field_type, filter_rev);
@@ -153,9 +156,9 @@ impl GridViewRevisionPad {
 
 
     pub fn delete_filter(
     pub fn delete_filter(
         &mut self,
         &mut self,
+        filter_id: &str,
         field_id: &str,
         field_id: &str,
         field_type: &FieldTypeRevision,
         field_type: &FieldTypeRevision,
-        filter_id: &str,
     ) -> CollaborateResult<Option<GridViewRevisionChangeset>> {
     ) -> CollaborateResult<Option<GridViewRevisionChangeset>> {
         self.modify(|view| {
         self.modify(|view| {
             if let Some(filters) = view.filters.get_mut_objects(field_id, field_type) {
             if let Some(filters) = view.filters.get_mut_objects(field_id, field_type) {

+ 3 - 2
shared-lib/grid-rev-model/src/filter_rev.rs

@@ -1,9 +1,10 @@
 use serde::{Deserialize, Serialize};
 use serde::{Deserialize, Serialize};
 
 
 #[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq, Hash)]
 #[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq, Hash)]
-pub struct FilterConfigurationRevision {
+pub struct FilterRevision {
     pub id: String,
     pub id: String,
     pub field_id: String,
     pub field_id: String,
     pub condition: u8,
     pub condition: u8,
-    pub content: Option<String>,
+    #[serde(default)]
+    pub content: String,
 }
 }

+ 5 - 5
shared-lib/grid-rev-model/src/grid_setting_rev.rs

@@ -1,4 +1,4 @@
-use crate::{FieldRevision, FieldTypeRevision, FilterConfigurationRevision, GroupConfigurationRevision};
+use crate::{FieldRevision, FieldTypeRevision, FilterRevision, GroupConfigurationRevision};
 use indexmap::IndexMap;
 use indexmap::IndexMap;
 use nanoid::nanoid;
 use nanoid::nanoid;
 use serde::{Deserialize, Serialize};
 use serde::{Deserialize, Serialize};
@@ -19,8 +19,8 @@ pub fn gen_grid_sort_id() -> String {
     nanoid!(6)
     nanoid!(6)
 }
 }
 
 
-pub type FilterConfiguration = Configuration<FilterConfigurationRevision>;
-pub type FilterConfigurationsByFieldId = HashMap<String, Vec<Arc<FilterConfigurationRevision>>>;
+pub type FilterConfiguration = Configuration<FilterRevision>;
+pub type FilterConfigurationsByFieldId = HashMap<String, Vec<Arc<FilterRevision>>>;
 //
 //
 pub type GroupConfiguration = Configuration<GroupConfigurationRevision>;
 pub type GroupConfiguration = Configuration<GroupConfigurationRevision>;
 pub type GroupConfigurationsByFieldId = HashMap<String, Vec<Arc<GroupConfigurationRevision>>>;
 pub type GroupConfigurationsByFieldId = HashMap<String, Vec<Arc<GroupConfigurationRevision>>>;
@@ -60,7 +60,7 @@ where
             .cloned()
             .cloned()
     }
     }
 
 
-    pub fn get_objects_by_field_revs(&self, field_revs: &[Arc<FieldRevision>]) -> Option<HashMap<String, Vec<Arc<T>>>> {
+    pub fn get_objects_by_field_revs(&self, field_revs: &[Arc<FieldRevision>]) -> HashMap<String, Vec<Arc<T>>> {
         // Get the objects according to the FieldType, so we need iterate the field_revs.
         // Get the objects according to the FieldType, so we need iterate the field_revs.
         let objects_by_field_id = field_revs
         let objects_by_field_id = field_revs
             .iter()
             .iter()
@@ -73,7 +73,7 @@ where
                 Some((field_rev.id.clone(), objects))
                 Some((field_rev.id.clone(), objects))
             })
             })
             .collect::<HashMap<String, Vec<Arc<T>>>>();
             .collect::<HashMap<String, Vec<Arc<T>>>>();
-        Some(objects_by_field_id)
+        objects_by_field_id
     }
     }
 
 
     pub fn get_all_objects(&self) -> Vec<Arc<T>> {
     pub fn get_all_objects(&self) -> Vec<Arc<T>> {

+ 4 - 4
shared-lib/lib-infra/src/future.rs

@@ -8,20 +8,20 @@ use std::{
     task::{Context, Poll},
     task::{Context, Poll},
 };
 };
 
 
-pub fn wrap_future<T, O>(f: T) -> AFFuture<O>
+pub fn to_future<T, O>(f: T) -> Fut<O>
 where
 where
     T: Future<Output = O> + Send + Sync + 'static,
     T: Future<Output = O> + Send + Sync + 'static,
 {
 {
-    AFFuture { fut: Box::pin(f) }
+    Fut { fut: Box::pin(f) }
 }
 }
 
 
 #[pin_project]
 #[pin_project]
-pub struct AFFuture<T> {
+pub struct Fut<T> {
     #[pin]
     #[pin]
     pub fut: Pin<Box<dyn Future<Output = T> + Sync + Send>>,
     pub fut: Pin<Box<dyn Future<Output = T> + Sync + Send>>,
 }
 }
 
 
-impl<T> Future for AFFuture<T>
+impl<T> Future for Fut<T>
 where
 where
     T: Send + Sync,
     T: Send + Sync,
 {
 {

+ 1 - 1
shared-lib/lib-infra/src/ref_map.rs

@@ -2,7 +2,7 @@ use std::collections::HashMap;
 use std::sync::Arc;
 use std::sync::Arc;
 
 
 pub trait RefCountValue {
 pub trait RefCountValue {
-    fn did_remove(&self);
+    fn did_remove(&self) {}
 }
 }
 
 
 struct RefCountHandler<T> {
 struct RefCountHandler<T> {