Browse Source

Merge pull request #865 from AppFlowy-IO/feat/group_row_after_modify

Feat: move the card to the corresponding column after modifying the data
Nathan.fooo 2 years ago
parent
commit
e38c300009

+ 6 - 0
frontend/rust-lib/flowy-grid/src/entities/block_entities.rs

@@ -112,6 +112,12 @@ pub struct InsertedRowPB {
     pub index: Option<i32>,
 }
 
+impl InsertedRowPB {
+    pub fn new(row: RowPB) -> Self {
+        Self { row, index: None }
+    }
+}
+
 impl std::convert::From<RowPB> for InsertedRowPB {
     fn from(row: RowPB) -> Self {
         Self { row, index: None }

+ 3 - 0
frontend/rust-lib/flowy-grid/src/entities/group_entities/group_changeset.rs

@@ -17,6 +17,9 @@ pub struct GroupRowsChangesetPB {
 }
 
 impl GroupRowsChangesetPB {
+    pub fn is_empty(&self) -> bool {
+        self.inserted_rows.is_empty() && self.deleted_rows.is_empty() && self.updated_rows.is_empty()
+    }
     pub fn insert(group_id: String, inserted_rows: Vec<InsertedRowPB>) -> Self {
         Self {
             group_id,

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

@@ -0,0 +1,45 @@
+use crate::services::block_manager::GridBlockManager;
+use crate::services::grid_view_manager::{GridViewRowDelegate, GridViewRowOperation};
+use flowy_error::FlowyResult;
+use flowy_grid_data_model::revision::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()
+                .map(|block| block.row_revs)
+                .flatten()
+                .collect::<Vec<Arc<RowRevision>>>()
+        })
+    }
+}
+
+impl GridViewRowOperation for Arc<GridBlockManager> {
+    fn gv_move_row(&self, row_rev: Arc<RowRevision>, from: usize, to: usize) -> AFFuture<FlowyResult<()>> {
+        let block_manager = self.clone();
+        wrap_future(async move { block_manager.move_row(row_rev, from, to).await })
+    }
+}

+ 8 - 4
frontend/rust-lib/flowy-grid/src/services/grid_editor.rs

@@ -3,6 +3,7 @@ use crate::entities::GridCellIdParams;
 use crate::entities::*;
 use crate::manager::{GridTaskSchedulerRwLock, GridUser};
 use crate::services::block_manager::GridBlockManager;
+
 use crate::services::cell::{apply_cell_data_changeset, decode_any_cell_data, CellBytes};
 use crate::services::field::{default_type_option_builder_from_type, type_option_builder_from_bytes, FieldBuilder};
 use crate::services::filter::GridFilterService;
@@ -11,7 +12,6 @@ use crate::services::persistence::block_index::BlockIndexCache;
 use crate::services::row::{
     make_grid_blocks, make_row_from_row_rev, make_rows_from_row_revs, GridBlockSnapshot, RowRevisionBuilder,
 };
-
 use bytes::Bytes;
 use flowy_error::{ErrorCode, FlowyError, FlowyResult};
 use flowy_grid_data_model::revision::*;
@@ -68,9 +68,11 @@ impl GridRevisionEditor {
         // View manager
         let view_manager = Arc::new(
             GridViewManager::new(
+                grid_id.to_owned(),
                 user.clone(),
-                grid_pad.clone(),
-                block_manager.clone(),
+                Arc::new(grid_pad.clone()),
+                Arc::new(block_manager.clone()),
+                Arc::new(block_manager.clone()),
                 Arc::new(task_scheduler.clone()),
             )
             .await?,
@@ -403,7 +405,7 @@ impl GridRevisionEditor {
                 content = Some(apply_cell_data_changeset(content.unwrap(), cell_rev, field_rev)?);
                 let cell_changeset = CellChangesetPB {
                     grid_id,
-                    row_id,
+                    row_id: row_id.clone(),
                     field_id,
                     content,
                 };
@@ -411,6 +413,8 @@ impl GridRevisionEditor {
                     .block_manager
                     .update_cell(cell_changeset, make_row_from_row_rev)
                     .await?;
+
+                self.view_manager.did_update_row(&row_id).await;
                 Ok(())
             }
         }

+ 32 - 0
frontend/rust-lib/flowy-grid/src/services/grid_editor_trait_impl.rs

@@ -0,0 +1,32 @@
+use crate::services::grid_view_manager::GridViewFieldDelegate;
+use flowy_grid_data_model::revision::FieldRevision;
+use flowy_sync::client_grid::GridRevisionPad;
+use lib_infra::future::{wrap_future, AFFuture};
+use std::sync::Arc;
+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) {
+                Ok(field_revs) => field_revs,
+                Err(e) => {
+                    tracing::error!("[GridViewRevisionDelegate] get field revisions failed: {}", e);
+                    vec![]
+                }
+            }
+        })
+    }
+
+    fn get_field_rev(&self, field_id: &str) -> AFFuture<Option<Arc<FieldRevision>>> {
+        let pad = self.clone();
+        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())
+        })
+    }
+}

+ 57 - 46
frontend/rust-lib/flowy-grid/src/services/grid_view_editor.rs

@@ -1,59 +1,44 @@
-use flowy_error::{FlowyError, FlowyResult};
-
+use crate::dart_notification::{send_dart_notification, GridNotification};
 use crate::entities::{
     CreateRowParams, GridFilterConfiguration, GridLayout, GridSettingPB, GroupPB, GroupRowsChangesetPB, InsertedRowPB,
     RowPB,
 };
 use crate::services::grid_editor_task::GridServiceTaskScheduler;
-use crate::services::group::{default_group_configuration, Group, GroupConfigurationDelegate, GroupService};
+use crate::services::grid_view_manager::{GridViewFieldDelegate, GridViewRowDelegate};
+use crate::services::group::{default_group_configuration, GroupConfigurationDelegate, GroupService};
+use crate::services::setting::make_grid_setting;
+use flowy_error::{FlowyError, FlowyResult};
 use flowy_grid_data_model::revision::{FieldRevision, GroupConfigurationRevision, RowRevision};
 use flowy_revision::{RevisionCloudService, RevisionManager, RevisionObjectBuilder};
 use flowy_sync::client_grid::{GridViewRevisionChangeset, GridViewRevisionPad};
-use flowy_sync::entities::revision::Revision;
-
-use crate::dart_notification::{send_dart_notification, GridNotification};
-use crate::services::setting::make_grid_setting;
 use flowy_sync::entities::grid::GridSettingChangesetParams;
+use flowy_sync::entities::revision::Revision;
 use lib_infra::future::{wrap_future, AFFuture, FutureResult};
 use std::sync::Arc;
 use tokio::sync::RwLock;
 
-pub trait GridViewRevisionDelegate: 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 GridViewRevisionRowDataSource: Send + Sync + 'static {
-    fn row_revs(&self) -> AFFuture<Vec<Arc<RowRevision>>>;
-}
-
 #[allow(dead_code)]
 pub struct GridViewRevisionEditor {
     user_id: String,
     view_id: String,
     pad: Arc<RwLock<GridViewRevisionPad>>,
     rev_manager: Arc<RevisionManager>,
-    delegate: Arc<dyn GridViewRevisionDelegate>,
-    data_source: Arc<dyn GridViewRevisionRowDataSource>,
+    field_delegate: Arc<dyn GridViewFieldDelegate>,
+    row_delegate: Arc<dyn GridViewRowDelegate>,
     group_service: Arc<RwLock<GroupService>>,
-    groups: Arc<RwLock<Vec<Group>>>,
     scheduler: Arc<dyn GridServiceTaskScheduler>,
 }
 
 impl GridViewRevisionEditor {
-    pub(crate) async fn new<Delegate, DataSource>(
+    pub(crate) async fn new(
         user_id: &str,
         token: &str,
         view_id: String,
-        delegate: Delegate,
-        data_source: DataSource,
+        field_delegate: Arc<dyn GridViewFieldDelegate>,
+        row_delegate: Arc<dyn GridViewRowDelegate>,
         scheduler: Arc<dyn GridServiceTaskScheduler>,
         mut rev_manager: RevisionManager,
-    ) -> FlowyResult<Self>
-    where
-        Delegate: GridViewRevisionDelegate,
-        DataSource: GridViewRevisionRowDataSource,
-    {
+    ) -> FlowyResult<Self> {
         let cloud = Arc::new(GridViewRevisionCloudService {
             token: token.to_owned(),
         });
@@ -62,16 +47,14 @@ impl GridViewRevisionEditor {
         let rev_manager = Arc::new(rev_manager);
         let group_service = GroupService::new(Box::new(pad.clone())).await;
         let user_id = user_id.to_owned();
-        let groups = Arc::new(RwLock::new(vec![]));
         Ok(Self {
             pad,
             user_id,
             view_id,
             rev_manager,
             scheduler,
-            groups,
-            delegate: Arc::new(delegate),
-            data_source: Arc::new(data_source),
+            field_delegate,
+            row_delegate,
             group_service: Arc::new(RwLock::new(group_service)),
         })
     }
@@ -87,7 +70,9 @@ impl GridViewRevisionEditor {
                     self.group_service
                         .read()
                         .await
-                        .update_row(row_rev, group_id, |field_id| self.delegate.get_field_rev(&field_id))
+                        .fill_row(row_rev, group_id, |field_id| {
+                            self.field_delegate.get_field_rev(&field_id)
+                        })
                         .await;
                 }
             },
@@ -120,34 +105,60 @@ impl GridViewRevisionEditor {
         }
     }
 
+    pub(crate) async fn did_update_row(&self, row_rev: &RowRevision) {
+        if let Some(changesets) = self
+            .group_service
+            .write()
+            .await
+            .did_update_row(row_rev, |field_id| self.field_delegate.get_field_rev(&field_id))
+            .await
+        {
+            for changeset in changesets {
+                self.notify_did_update_group(changeset).await;
+            }
+        }
+    }
+
     async fn group_id_of_row(&self, row_id: &str) -> Option<String> {
-        let read_guard = self.groups.read().await;
+        let read_guard = &self.group_service.read().await.groups;
         for group in read_guard.iter() {
-            if group.rows.iter().any(|row| row.id == row_id) {
+            if group.contains_row(row_id) {
                 return Some(group.id.clone());
             }
         }
-
         None
     }
 
+    // async fn get_mut_group<F>(&self, group_id: &str, f: F) -> FlowyResult<()>
+    // where
+    //     F: Fn(&mut Group) -> FlowyResult<()>,
+    // {
+    //     for group in self.groups.write().await.iter_mut() {
+    //         if group.id == group_id {
+    //             let _ = f(group)?;
+    //         }
+    //     }
+    //     Ok(())
+    // }
+
     pub(crate) async fn load_groups(&self) -> FlowyResult<Vec<GroupPB>> {
-        let field_revs = self.delegate.get_field_revs().await;
-        let row_revs = self.data_source.row_revs().await;
+        let field_revs = self.field_delegate.get_field_revs().await;
+        let row_revs = self.row_delegate.gv_row_revs().await;
 
-        //
-        let mut write_guard = self.group_service.write().await;
-        match write_guard.load_groups(&field_revs, row_revs).await {
+        match self
+            .group_service
+            .write()
+            .await
+            .load_groups(&field_revs, row_revs)
+            .await
+        {
             None => Ok(vec![]),
-            Some(groups) => {
-                *self.groups.write().await = groups.clone();
-                Ok(groups.into_iter().map(GroupPB::from).collect())
-            }
+            Some(groups) => Ok(groups.into_iter().map(GroupPB::from).collect()),
         }
     }
 
     pub(crate) async fn get_setting(&self) -> GridSettingPB {
-        let field_revs = self.delegate.get_field_revs().await;
+        let field_revs = self.field_delegate.get_field_revs().await;
         let grid_setting = make_grid_setting(self.pad.read().await.get_setting_rev(), &field_revs);
         grid_setting
     }
@@ -158,7 +169,7 @@ impl GridViewRevisionEditor {
     }
 
     pub(crate) async fn get_filters(&self) -> Vec<GridFilterConfiguration> {
-        let field_revs = self.delegate.get_field_revs().await;
+        let field_revs = self.field_delegate.get_field_revs().await;
         match self.pad.read().await.get_setting_rev().get_all_filters(&field_revs) {
             None => vec![],
             Some(filters) => filters

+ 63 - 72
frontend/rust-lib/flowy-grid/src/services/grid_view_manager.rs

@@ -2,47 +2,66 @@ use crate::entities::{
     CreateRowParams, GridFilterConfiguration, GridLayout, GridSettingPB, MoveRowParams, RepeatedGridGroupPB, RowPB,
 };
 use crate::manager::GridUser;
-use crate::services::block_manager::GridBlockManager;
+
 use crate::services::grid_editor_task::GridServiceTaskScheduler;
-use crate::services::grid_view_editor::{
-    GridViewRevisionDelegate, GridViewRevisionEditor, GridViewRevisionRowDataSource,
-};
+use crate::services::grid_view_editor::GridViewRevisionEditor;
 use bytes::Bytes;
 use dashmap::DashMap;
 use flowy_error::FlowyResult;
 use flowy_grid_data_model::revision::{FieldRevision, RowRevision};
 use flowy_revision::disk::SQLiteGridViewRevisionPersistence;
 use flowy_revision::{RevisionCompactor, RevisionManager, RevisionPersistence, SQLiteRevisionSnapshotPersistence};
-use flowy_sync::client_grid::GridRevisionPad;
+
 use flowy_sync::entities::grid::GridSettingChangesetParams;
 use flowy_sync::entities::revision::Revision;
 use flowy_sync::util::make_text_delta_from_revisions;
-use lib_infra::future::{wrap_future, AFFuture};
+use lib_infra::future::AFFuture;
 use std::sync::Arc;
-use tokio::sync::RwLock;
 
 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 trait GridViewRowOperation: Send + Sync + 'static {
+    // Will be removed in the future.
+    fn gv_move_row(&self, row_rev: Arc<RowRevision>, from: usize, to: usize) -> AFFuture<FlowyResult<()>>;
+}
+
 pub(crate) struct GridViewManager {
+    grid_id: String,
     user: Arc<dyn GridUser>,
-    grid_pad: Arc<RwLock<GridRevisionPad>>,
-    block_manager: Arc<GridBlockManager>,
+    field_delegate: Arc<dyn GridViewFieldDelegate>,
+    row_delegate: Arc<dyn GridViewRowDelegate>,
+    row_operation: Arc<dyn GridViewRowOperation>,
     view_editors: DashMap<ViewId, Arc<GridViewRevisionEditor>>,
     scheduler: Arc<dyn GridServiceTaskScheduler>,
 }
 
 impl GridViewManager {
     pub(crate) async fn new(
+        grid_id: String,
         user: Arc<dyn GridUser>,
-        grid_pad: Arc<RwLock<GridRevisionPad>>,
-        block_manager: Arc<GridBlockManager>,
+        field_delegate: Arc<dyn GridViewFieldDelegate>,
+        row_delegate: Arc<dyn GridViewRowDelegate>,
+        row_operation: Arc<dyn GridViewRowOperation>,
         scheduler: Arc<dyn GridServiceTaskScheduler>,
     ) -> FlowyResult<Self> {
         Ok(Self {
+            grid_id,
             user,
-            grid_pad,
             scheduler,
-            block_manager,
+            field_delegate,
+            row_delegate,
+            row_operation,
             view_editors: DashMap::default(),
         })
     }
@@ -54,7 +73,16 @@ impl GridViewManager {
     }
 
     pub(crate) async fn did_update_row(&self, row_id: &str) {
-        let row = self.block_manager.get_row_rev(row_id).await;
+        match self.row_delegate.gv_get_row_rev(row_id).await {
+            None => {
+                tracing::warn!("Can not find the row in grid view");
+            }
+            Some(row_rev) => {
+                for view_editor in self.view_editors.iter() {
+                    view_editor.did_update_row(&row_rev).await;
+                }
+            }
+        }
     }
 
     pub(crate) async fn did_create_row(&self, row_pb: &RowPB, params: &CreateRowParams) {
@@ -103,19 +131,19 @@ impl GridViewManager {
 
         let from_index = from_index as usize;
 
-        match self.block_manager.get_row_rev(&row_id).await? {
+        match self.row_delegate.gv_get_row_rev(&row_id).await {
             None => tracing::warn!("Move row failed, can not find the row:{}", row_id),
             Some(row_rev) => match layout {
                 GridLayout::Table => {
                     tracing::trace!("Move row from {} to {}", from_index, to_index);
                     let to_index = to_index as usize;
-                    let _ = self.block_manager.move_row(row_rev, from_index, to_index).await?;
+                    let _ = self.row_operation.gv_move_row(row_rev, from_index, to_index).await?;
                 }
                 GridLayout::Board => {
                     if let Some(upper_row_id) = upper_row_id {
-                        if let Some(to_index) = self.block_manager.index_of_row(&upper_row_id).await {
+                        if let Some(to_index) = self.row_delegate.gv_index_of_row(&upper_row_id).await {
                             tracing::trace!("Move row from {} to {}", from_index, to_index);
-                            let _ = self.block_manager.move_row(row_rev, from_index, to_index).await?;
+                            let _ = self.row_operation.gv_move_row(row_rev, from_index, to_index).await?;
                         }
                     }
                 }
@@ -132,8 +160,8 @@ impl GridViewManager {
                     make_view_editor(
                         &self.user,
                         view_id,
-                        self.grid_pad.clone(),
-                        self.block_manager.clone(),
+                        self.field_delegate.clone(),
+                        self.row_delegate.clone(),
                         self.scheduler.clone(),
                     )
                     .await?,
@@ -146,29 +174,33 @@ impl GridViewManager {
     }
 
     async fn get_default_view_editor(&self) -> FlowyResult<Arc<GridViewRevisionEditor>> {
-        let grid_id = self.grid_pad.read().await.grid_id();
-        self.get_view_editor(&grid_id).await
+        self.get_view_editor(&self.grid_id).await
     }
 }
 
-async fn make_view_editor<Delegate, DataSource>(
+async fn make_view_editor(
     user: &Arc<dyn GridUser>,
     view_id: &str,
-    delegate: Delegate,
-    data_source: DataSource,
+    field_delegate: Arc<dyn GridViewFieldDelegate>,
+    row_delegate: Arc<dyn GridViewRowDelegate>,
     scheduler: Arc<dyn GridServiceTaskScheduler>,
-) -> FlowyResult<GridViewRevisionEditor>
-where
-    Delegate: GridViewRevisionDelegate,
-    DataSource: GridViewRevisionRowDataSource,
-{
+) -> FlowyResult<GridViewRevisionEditor> {
     tracing::trace!("Open view:{} editor", view_id);
 
     let rev_manager = make_grid_view_rev_manager(user, view_id).await?;
     let user_id = user.user_id()?;
     let token = user.token()?;
     let view_id = view_id.to_owned();
-    GridViewRevisionEditor::new(&user_id, &token, view_id, delegate, data_source, scheduler, rev_manager).await
+    GridViewRevisionEditor::new(
+        &user_id,
+        &token,
+        view_id,
+        field_delegate,
+        row_delegate,
+        scheduler,
+        rev_manager,
+    )
+    .await
 }
 
 pub async fn make_grid_view_rev_manager(user: &Arc<dyn GridUser>, view_id: &str) -> FlowyResult<RevisionManager> {
@@ -197,44 +229,3 @@ impl RevisionCompactor for GridViewRevisionCompactor {
         Ok(delta.json_bytes())
     }
 }
-
-impl GridViewRevisionRowDataSource for Arc<GridBlockManager> {
-    fn 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()
-                .map(|block| block.row_revs)
-                .flatten()
-                .collect::<Vec<Arc<RowRevision>>>()
-        })
-    }
-}
-
-impl GridViewRevisionDelegate 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) {
-                Ok(field_revs) => field_revs,
-                Err(e) => {
-                    tracing::error!("[GridViewRevisionDelegate] get field revisions failed: {}", e);
-                    vec![]
-                }
-            }
-        })
-    }
-
-    fn get_field_rev(&self, field_id: &str) -> AFFuture<Option<Arc<FieldRevision>>> {
-        let pad = self.clone();
-        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())
-        })
-    }
-}

+ 16 - 33
frontend/rust-lib/flowy-grid/src/services/group/group_generator/checkbox_group.rs

@@ -1,13 +1,16 @@
-use crate::entities::CheckboxGroupConfigurationPB;
-use flowy_error::FlowyResult;
+use crate::entities::{CheckboxGroupConfigurationPB, GroupRowsChangesetPB};
+
 use flowy_grid_data_model::revision::{FieldRevision, RowRevision};
-use std::sync::Arc;
 
 use crate::services::field::{CheckboxCellData, CheckboxCellDataParser, CheckboxTypeOptionPB, CHECK, UNCHECK};
-use crate::services::group::{Group, GroupActionHandler, GroupController, GroupGenerator, Groupable};
+use crate::services::group::{GenericGroupController, Group, GroupController, GroupGenerator, Groupable};
 
-pub type CheckboxGroupController =
-    GroupController<CheckboxGroupConfigurationPB, CheckboxTypeOptionPB, CheckboxGroupGenerator, CheckboxCellDataParser>;
+pub type CheckboxGroupController = GenericGroupController<
+    CheckboxGroupConfigurationPB,
+    CheckboxTypeOptionPB,
+    CheckboxGroupGenerator,
+    CheckboxCellDataParser,
+>;
 
 impl Groupable for CheckboxGroupController {
     type CellDataType = CheckboxCellData;
@@ -15,22 +18,14 @@ impl Groupable for CheckboxGroupController {
     fn can_group(&self, _content: &str, _cell_data: &Self::CellDataType) -> bool {
         false
     }
-}
 
-impl GroupActionHandler for CheckboxGroupController {
-    fn field_id(&self) -> &str {
-        &self.field_id
-    }
-
-    fn build_groups(&self) -> Vec<Group> {
-        self.make_groups()
-    }
-
-    fn group_rows(&mut self, row_revs: &[Arc<RowRevision>], field_rev: &FieldRevision) -> FlowyResult<()> {
-        self.handle_rows(row_revs, field_rev)
+    fn group_row(&mut self, _row_rev: &RowRevision, _cell_data: &Self::CellDataType) -> Vec<GroupRowsChangesetPB> {
+        todo!()
     }
+}
 
-    fn update_card(&self, _row_rev: &mut RowRevision, _field_rev: &FieldRevision, _group_id: &str) {
+impl GroupController for CheckboxGroupController {
+    fn fill_row(&self, _row_rev: &mut RowRevision, _field_rev: &FieldRevision, _group_id: &str) {
         todo!()
     }
 }
@@ -44,20 +39,8 @@ impl GroupGenerator for CheckboxGroupGenerator {
         _configuration: &Option<Self::ConfigurationType>,
         _type_option: &Option<Self::TypeOptionType>,
     ) -> Vec<Group> {
-        let check_group = Group {
-            id: "true".to_string(),
-            desc: "".to_string(),
-            rows: vec![],
-            content: CHECK.to_string(),
-        };
-
-        let uncheck_group = Group {
-            id: "false".to_string(),
-            desc: "".to_string(),
-            rows: vec![],
-            content: UNCHECK.to_string(),
-        };
-
+        let check_group = Group::new("true".to_string(), "".to_string(), CHECK.to_string());
+        let uncheck_group = Group::new("false".to_string(), "".to_string(), UNCHECK.to_string());
         vec![check_group, uncheck_group]
     }
 }

+ 130 - 34
frontend/rust-lib/flowy-grid/src/services/group/group_generator/generator.rs

@@ -1,13 +1,11 @@
-use crate::entities::{GroupPB, RowPB};
+use crate::entities::{GroupPB, GroupRowsChangesetPB, RowPB};
 use crate::services::cell::{decode_any_cell_data, CellBytesParser};
 use bytes::Bytes;
 use flowy_error::FlowyResult;
 use flowy_grid_data_model::revision::{
     FieldRevision, GroupConfigurationRevision, RowRevision, TypeOptionDataDeserializer,
 };
-
 use indexmap::IndexMap;
-
 use std::marker::PhantomData;
 use std::sync::Arc;
 
@@ -21,29 +19,35 @@ pub trait GroupGenerator {
     ) -> Vec<Group>;
 }
 
-pub trait Groupable {
+pub trait Groupable: Send + Sync {
     type CellDataType;
     fn can_group(&self, content: &str, cell_data: &Self::CellDataType) -> bool;
+    fn group_row(&mut self, row_rev: &RowRevision, cell_data: &Self::CellDataType) -> Vec<GroupRowsChangesetPB>;
 }
 
-pub trait GroupActionHandler: Send + Sync {
+pub trait GroupController: GroupControllerSharedAction + Send + Sync {
+    fn fill_row(&self, row_rev: &mut RowRevision, field_rev: &FieldRevision, group_id: &str);
+}
+
+pub trait GroupControllerSharedAction: Send + Sync {
+    // The field that is used for grouping the rows
     fn field_id(&self) -> &str;
     fn build_groups(&self) -> Vec<Group>;
     fn group_rows(&mut self, row_revs: &[Arc<RowRevision>], field_rev: &FieldRevision) -> FlowyResult<()>;
-    fn update_card(&self, row_rev: &mut RowRevision, field_rev: &FieldRevision, group_id: &str);
-}
-
-pub trait GroupActionHandler2: Send + Sync {
-    fn create_card(&self, row_rev: &mut RowRevision, field_rev: &FieldRevision, group_id: &str);
+    fn did_update_row(
+        &mut self,
+        row_rev: &RowRevision,
+        field_rev: &FieldRevision,
+    ) -> FlowyResult<Vec<GroupRowsChangesetPB>>;
 }
 
 const DEFAULT_GROUP_ID: &str = "default_group";
 
 /// C: represents the group configuration structure
 /// T: the type option data deserializer that impl [TypeOptionDataDeserializer]
-/// G: the group container generator
+/// G: the group generator, [GroupGenerator]
 /// P: the parser that impl [CellBytesParser] for the CellBytes
-pub struct GroupController<C, T, G, P> {
+pub struct GenericGroupController<C, T, G, P> {
     pub field_id: String,
     pub groups_map: IndexMap<String, Group>,
     default_group: Group,
@@ -57,7 +61,7 @@ pub struct GroupController<C, T, G, P> {
 pub struct Group {
     pub id: String,
     pub desc: String,
-    pub rows: Vec<RowPB>,
+    rows: Vec<RowPB>,
     pub content: String,
 }
 
@@ -71,7 +75,40 @@ impl std::convert::From<Group> for GroupPB {
     }
 }
 
-impl<C, T, G, P> GroupController<C, T, G, P>
+impl Group {
+    pub fn new(id: String, desc: String, content: String) -> Self {
+        Self {
+            id,
+            desc,
+            rows: vec![],
+            content,
+        }
+    }
+
+    pub fn contains_row(&self, row_id: &str) -> bool {
+        self.rows.iter().any(|row| row.id == row_id)
+    }
+
+    pub fn remove_row(&mut self, row_id: &str) {
+        match self.rows.iter().position(|row| row.id == row_id) {
+            None => {}
+            Some(pos) => {
+                self.rows.remove(pos);
+            }
+        }
+    }
+
+    pub fn add_row(&mut self, row_pb: RowPB) {
+        match self.rows.iter().find(|row| row.id == row_pb.id) {
+            None => {
+                self.rows.push(row_pb);
+            }
+            Some(_) => {}
+        }
+    }
+}
+
+impl<C, T, G, P> GenericGroupController<C, T, G, P>
 where
     C: TryFrom<Bytes, Error = protobuf::ProtobufError>,
     T: TypeOptionDataDeserializer,
@@ -86,12 +123,11 @@ where
         let type_option = field_rev.get_type_option_entry::<T>(field_type_rev);
         let groups = G::generate_groups(&configuration, &type_option);
 
-        let default_group = Group {
-            id: DEFAULT_GROUP_ID.to_owned(),
-            desc: format!("No {}", field_rev.name),
-            rows: vec![],
-            content: "".to_string(),
-        };
+        let default_group = Group::new(
+            DEFAULT_GROUP_ID.to_owned(),
+            format!("No {}", field_rev.name),
+            "".to_string(),
+        );
 
         Ok(Self {
             field_id: field_rev.id.clone(),
@@ -103,8 +139,18 @@ where
             cell_parser_phantom: PhantomData,
         })
     }
+}
+
+impl<C, T, G, P> GroupControllerSharedAction for GenericGroupController<C, T, G, P>
+where
+    P: CellBytesParser,
+    Self: Groupable<CellDataType = P::Object>,
+{
+    fn field_id(&self) -> &str {
+        &self.field_id
+    }
 
-    pub fn make_groups(&self) -> Vec<Group> {
+    fn build_groups(&self) -> Vec<Group> {
         let default_group = self.default_group.clone();
         let mut groups: Vec<Group> = self.groups_map.values().cloned().collect();
         if !default_group.rows.is_empty() {
@@ -112,35 +158,28 @@ where
         }
         groups
     }
-}
 
-impl<C, T, G, P> GroupController<C, T, G, P>
-where
-    P: CellBytesParser,
-    Self: Groupable<CellDataType = P::Object>,
-{
-    pub fn handle_rows(&mut self, rows: &[Arc<RowRevision>], field_rev: &FieldRevision) -> FlowyResult<()> {
-        // The field_rev might be None if corresponding field_rev is deleted.
+    fn group_rows(&mut self, row_revs: &[Arc<RowRevision>], field_rev: &FieldRevision) -> FlowyResult<()> {
         if self.configuration.is_none() {
             return Ok(());
         }
 
-        for row in rows {
-            if let Some(cell_rev) = row.cells.get(&self.field_id) {
+        for row_rev in row_revs {
+            if let Some(cell_rev) = row_rev.cells.get(&self.field_id) {
                 let mut records: Vec<GroupRecord> = vec![];
                 let cell_bytes = decode_any_cell_data(cell_rev.data.clone(), field_rev);
                 let cell_data = cell_bytes.parser::<P>()?;
                 for group in self.groups_map.values() {
                     if self.can_group(&group.content, &cell_data) {
                         records.push(GroupRecord {
-                            row: row.into(),
+                            row: row_rev.into(),
                             group_id: group.id.clone(),
                         });
                     }
                 }
 
                 if records.is_empty() {
-                    self.default_group.rows.push(row.into());
+                    self.default_group.rows.push(row_rev.into());
                 } else {
                     for record in records {
                         if let Some(group) = self.groups_map.get_mut(&record.group_id) {
@@ -149,14 +188,71 @@ where
                     }
                 }
             } else {
-                self.default_group.rows.push(row.into());
+                self.default_group.rows.push(row_rev.into());
             }
         }
 
         Ok(())
     }
+
+    fn did_update_row(
+        &mut self,
+        row_rev: &RowRevision,
+        field_rev: &FieldRevision,
+    ) -> FlowyResult<Vec<GroupRowsChangesetPB>> {
+        if let Some(cell_rev) = row_rev.cells.get(&self.field_id) {
+            let cell_bytes = decode_any_cell_data(cell_rev.data.clone(), field_rev);
+            let cell_data = cell_bytes.parser::<P>()?;
+            Ok(self.group_row(row_rev, &cell_data))
+        } else {
+            Ok(vec![])
+        }
+    }
 }
 
+// impl<C, T, G, P> GroupController<C, T, G, P>
+// where
+//     P: CellBytesParser,
+//     Self: Groupable<CellDataType = P::Object>,
+// {
+//     pub fn handle_rows(&mut self, rows: &[Arc<RowRevision>], field_rev: &FieldRevision) -> FlowyResult<()> {
+//         // The field_rev might be None if corresponding field_rev is deleted.
+//         if self.configuration.is_none() {
+//             return Ok(());
+//         }
+//
+//         for row in rows {
+//             if let Some(cell_rev) = row.cells.get(&self.field_id) {
+//                 let mut records: Vec<GroupRecord> = vec![];
+//                 let cell_bytes = decode_any_cell_data(cell_rev.data.clone(), field_rev);
+//                 let cell_data = cell_bytes.parser::<P>()?;
+//                 for group in self.groups_map.values() {
+//                     if self.can_group(&group.content, &cell_data) {
+//                         records.push(GroupRecord {
+//                             row: row.into(),
+//                             group_id: group.id.clone(),
+//                         });
+//                     }
+//                 }
+//
+//                 if records.is_empty() {
+//                     self.default_group.rows.push(row.into());
+//                 } else {
+//                     for record in records {
+//                         if let Some(group) = self.groups_map.get_mut(&record.group_id) {
+//                             group.rows.push(record.row);
+//                         }
+//                     }
+//                 }
+//             } else {
+//                 self.default_group.rows.push(row.into());
+//             }
+//         }
+//
+//         Ok(())
+//     }
+// }
+
 struct GroupRecord {
     row: RowPB,
     group_id: String,

+ 50 - 46
frontend/rust-lib/flowy-grid/src/services/group/group_generator/select_option_group.rs

@@ -1,17 +1,14 @@
-use crate::entities::SelectOptionGroupConfigurationPB;
+use crate::entities::{GroupRowsChangesetPB, InsertedRowPB, RowPB, SelectOptionGroupConfigurationPB};
 use crate::services::cell::insert_select_option_cell;
-use flowy_error::FlowyResult;
-use flowy_grid_data_model::revision::{FieldRevision, RowRevision};
-
-use std::sync::Arc;
-
 use crate::services::field::{
     MultiSelectTypeOptionPB, SelectOptionCellDataPB, SelectOptionCellDataParser, SingleSelectTypeOptionPB,
 };
-use crate::services::group::{Group, GroupActionHandler, GroupController, GroupGenerator, Groupable};
+use crate::services::group::{GenericGroupController, Group, GroupController, GroupGenerator, Groupable};
+
+use flowy_grid_data_model::revision::{FieldRevision, RowRevision};
 
 // SingleSelect
-pub type SingleSelectGroupController = GroupController<
+pub type SingleSelectGroupController = GenericGroupController<
     SelectOptionGroupConfigurationPB,
     SingleSelectTypeOptionPB,
     SingleSelectGroupGenerator,
@@ -23,22 +20,18 @@ impl Groupable for SingleSelectGroupController {
     fn can_group(&self, content: &str, cell_data: &SelectOptionCellDataPB) -> bool {
         cell_data.select_options.iter().any(|option| option.id == content)
     }
-}
 
-impl GroupActionHandler for SingleSelectGroupController {
-    fn field_id(&self) -> &str {
-        &self.field_id
-    }
-
-    fn build_groups(&self) -> Vec<Group> {
-        self.make_groups()
-    }
-
-    fn group_rows(&mut self, row_revs: &[Arc<RowRevision>], field_rev: &FieldRevision) -> FlowyResult<()> {
-        self.handle_rows(row_revs, field_rev)
+    fn group_row(&mut self, row_rev: &RowRevision, cell_data: &Self::CellDataType) -> Vec<GroupRowsChangesetPB> {
+        let mut changesets = vec![];
+        self.groups_map.iter_mut().for_each(|(_, group): (_, &mut Group)| {
+            group_select_option_row(group, &mut changesets, cell_data, row_rev);
+        });
+        changesets
     }
+}
 
-    fn update_card(&self, row_rev: &mut RowRevision, field_rev: &FieldRevision, group_id: &str) {
+impl GroupController for SingleSelectGroupController {
+    fn fill_row(&self, row_rev: &mut RowRevision, field_rev: &FieldRevision, group_id: &str) {
         let group: Option<&Group> = self.groups_map.get(group_id);
         match group {
             None => {}
@@ -63,19 +56,14 @@ impl GroupGenerator for SingleSelectGroupGenerator {
             Some(type_option) => type_option
                 .options
                 .iter()
-                .map(|option| Group {
-                    id: option.id.clone(),
-                    desc: option.name.clone(),
-                    rows: vec![],
-                    content: option.id.clone(),
-                })
+                .map(|option| Group::new(option.id.clone(), option.name.clone(), option.id.clone()))
                 .collect(),
         }
     }
 }
 
 // MultiSelect
-pub type MultiSelectGroupController = GroupController<
+pub type MultiSelectGroupController = GenericGroupController<
     SelectOptionGroupConfigurationPB,
     MultiSelectTypeOptionPB,
     MultiSelectGroupGenerator,
@@ -84,25 +72,23 @@ pub type MultiSelectGroupController = GroupController<
 
 impl Groupable for MultiSelectGroupController {
     type CellDataType = SelectOptionCellDataPB;
+
     fn can_group(&self, content: &str, cell_data: &SelectOptionCellDataPB) -> bool {
         cell_data.select_options.iter().any(|option| option.id == content)
     }
-}
 
-impl GroupActionHandler for MultiSelectGroupController {
-    fn field_id(&self) -> &str {
-        &self.field_id
-    }
-
-    fn build_groups(&self) -> Vec<Group> {
-        self.make_groups()
-    }
+    fn group_row(&mut self, row_rev: &RowRevision, cell_data: &Self::CellDataType) -> Vec<GroupRowsChangesetPB> {
+        let mut changesets = vec![];
 
-    fn group_rows(&mut self, row_revs: &[Arc<RowRevision>], field_rev: &FieldRevision) -> FlowyResult<()> {
-        self.handle_rows(row_revs, field_rev)
+        self.groups_map.iter_mut().for_each(|(_, group): (_, &mut Group)| {
+            group_select_option_row(group, &mut changesets, cell_data, row_rev);
+        });
+        changesets
     }
+}
 
-    fn update_card(&self, row_rev: &mut RowRevision, field_rev: &FieldRevision, group_id: &str) {
+impl GroupController for MultiSelectGroupController {
+    fn fill_row(&self, row_rev: &mut RowRevision, field_rev: &FieldRevision, group_id: &str) {
         let group: Option<&Group> = self.groups_map.get(group_id);
         match group {
             None => tracing::warn!("Can not find the group: {}", group_id),
@@ -128,13 +114,31 @@ impl GroupGenerator for MultiSelectGroupGenerator {
             Some(type_option) => type_option
                 .options
                 .iter()
-                .map(|option| Group {
-                    id: option.id.clone(),
-                    desc: option.name.clone(),
-                    rows: vec![],
-                    content: option.id.clone(),
-                })
+                .map(|option| Group::new(option.id.clone(), option.name.clone(), option.id.clone()))
                 .collect(),
         }
     }
 }
+
+fn group_select_option_row(
+    group: &mut Group,
+    changesets: &mut Vec<GroupRowsChangesetPB>,
+    cell_data: &SelectOptionCellDataPB,
+    row_rev: &RowRevision,
+) {
+    cell_data.select_options.iter().for_each(|option| {
+        if option.id == group.id {
+            if !group.contains_row(&row_rev.id) {
+                let row_pb = RowPB::from(row_rev);
+                changesets.push(GroupRowsChangesetPB::insert(
+                    group.id.clone(),
+                    vec![InsertedRowPB::new(row_pb.clone())],
+                ));
+                group.add_row(row_pb);
+            }
+        } else if group.contains_row(&row_rev.id) {
+            group.remove_row(&row_rev.id);
+            changesets.push(GroupRowsChangesetPB::delete(group.id.clone(), vec![row_rev.id.clone()]));
+        }
+    });
+}

+ 43 - 30
frontend/rust-lib/flowy-grid/src/services/group/group_service.rs

@@ -1,9 +1,9 @@
 use crate::entities::{
-    CheckboxGroupConfigurationPB, DateGroupConfigurationPB, FieldType, NumberGroupConfigurationPB,
-    SelectOptionGroupConfigurationPB, TextGroupConfigurationPB, UrlGroupConfigurationPB,
+    CheckboxGroupConfigurationPB, DateGroupConfigurationPB, FieldType, GroupRowsChangesetPB,
+    NumberGroupConfigurationPB, SelectOptionGroupConfigurationPB, TextGroupConfigurationPB, UrlGroupConfigurationPB,
 };
 use crate::services::group::{
-    CheckboxGroupController, Group, GroupActionHandler, MultiSelectGroupController, SingleSelectGroupController,
+    CheckboxGroupController, Group, GroupController, MultiSelectGroupController, SingleSelectGroupController,
 };
 use bytes::Bytes;
 use flowy_error::FlowyResult;
@@ -18,15 +18,17 @@ pub trait GroupConfigurationDelegate: Send + Sync + 'static {
 }
 
 pub(crate) struct GroupService {
+    pub groups: Vec<Group>,
     delegate: Box<dyn GroupConfigurationDelegate>,
-    action_handler: Option<Arc<RwLock<dyn GroupActionHandler>>>,
+    group_controller: Option<Arc<RwLock<dyn GroupController>>>,
 }
 
 impl GroupService {
     pub(crate) async fn new(delegate: Box<dyn GroupConfigurationDelegate>) -> Self {
         Self {
+            groups: vec![],
             delegate,
-            action_handler: None,
+            group_controller: None,
         }
     }
 
@@ -35,47 +37,58 @@ impl GroupService {
         field_revs: &[Arc<FieldRevision>],
         row_revs: Vec<Arc<RowRevision>>,
     ) -> Option<Vec<Group>> {
-        let field_rev = find_group_field(field_revs).unwrap();
+        let field_rev = find_group_field(field_revs)?;
         let field_type: FieldType = field_rev.field_type_rev.into();
         let configuration = self.delegate.get_group_configuration(field_rev.clone()).await;
-
         match self
             .build_groups(&field_type, &field_rev, row_revs, configuration)
             .await
         {
-            Ok(groups) => Some(groups),
+            Ok(groups) => {
+                self.groups = groups.clone();
+                Some(groups)
+            }
             Err(_) => None,
         }
     }
 
-    pub(crate) async fn update_row<F, O>(&self, row_rev: &mut RowRevision, group_id: &str, f: F)
+    pub(crate) async fn fill_row<F, O>(&self, row_rev: &mut RowRevision, group_id: &str, get_field_fn: F)
     where
         F: FnOnce(String) -> O,
         O: Future<Output = Option<Arc<FieldRevision>>> + Send + Sync + 'static,
     {
-        if let Some(group_action_handler) = self.action_handler.as_ref() {
-            let field_id = group_action_handler.read().await.field_id().to_owned();
-            match f(field_id).await {
+        if let Some(group_controller) = self.group_controller.as_ref() {
+            let field_id = group_controller.read().await.field_id().to_owned();
+            match get_field_fn(field_id).await {
                 None => {}
                 Some(field_rev) => {
-                    group_action_handler
-                        .write()
-                        .await
-                        .update_card(row_rev, &field_rev, group_id);
+                    group_controller.write().await.fill_row(row_rev, &field_rev, group_id);
                 }
             }
         }
     }
-    #[allow(dead_code)]
-    pub async fn move_card(&self, _group_id: &str, _from: i32, _to: i32) {
-        // BoardCardChangesetPB {
-        //     group_id: "".to_string(),
-        //     inserted_cards: vec![],
-        //     deleted_cards: vec![],
-        //     updated_cards: vec![]
-        // }
-        // let row_pb = make_row_from_row_rev(row_rev);
-        todo!()
+
+    #[tracing::instrument(level = "trace", skip_all)]
+    pub(crate) async fn did_update_row<F, O>(
+        &self,
+        row_rev: &RowRevision,
+        get_field_fn: F,
+    ) -> Option<Vec<GroupRowsChangesetPB>>
+    where
+        F: FnOnce(String) -> O,
+        O: Future<Output = Option<Arc<FieldRevision>>> + Send + Sync + 'static,
+    {
+        let group_controller = self.group_controller.as_ref()?;
+        let field_id = group_controller.read().await.field_id().to_owned();
+        let field_rev = get_field_fn(field_id).await?;
+
+        match group_controller.write().await.did_update_row(row_rev, &field_rev) {
+            Ok(changeset) => Some(changeset),
+            Err(e) => {
+                tracing::error!("Update group data failed, {:?}", e);
+                None
+            }
+        }
     }
 
     #[tracing::instrument(level = "trace", skip_all, err)]
@@ -98,15 +111,15 @@ impl GroupService {
             }
             FieldType::SingleSelect => {
                 let controller = SingleSelectGroupController::new(field_rev, configuration)?;
-                self.action_handler = Some(Arc::new(RwLock::new(controller)));
+                self.group_controller = Some(Arc::new(RwLock::new(controller)));
             }
             FieldType::MultiSelect => {
                 let controller = MultiSelectGroupController::new(field_rev, configuration)?;
-                self.action_handler = Some(Arc::new(RwLock::new(controller)));
+                self.group_controller = Some(Arc::new(RwLock::new(controller)));
             }
             FieldType::Checkbox => {
                 let controller = CheckboxGroupController::new(field_rev, configuration)?;
-                self.action_handler = Some(Arc::new(RwLock::new(controller)));
+                self.group_controller = Some(Arc::new(RwLock::new(controller)));
             }
             FieldType::URL => {
                 // let generator = GroupGenerator::<UrlGroupConfigurationPB>::from_configuration(configuration);
@@ -114,7 +127,7 @@ impl GroupService {
         };
 
         let mut groups = vec![];
-        if let Some(group_action_handler) = self.action_handler.as_ref() {
+        if let Some(group_action_handler) = self.group_controller.as_ref() {
             let mut write_guard = group_action_handler.write().await;
             let _ = write_guard.group_rows(&row_revs, field_rev)?;
             groups = write_guard.build_groups();

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

@@ -2,11 +2,13 @@ mod util;
 
 pub mod block_editor;
 mod block_manager;
+mod block_manager_trait_impl;
 pub mod cell;
 pub mod field;
 mod filter;
 pub mod grid_editor;
 mod grid_editor_task;
+mod grid_editor_trait_impl;
 pub mod grid_view_editor;
 pub mod grid_view_manager;
 pub mod group;

+ 0 - 1
frontend/rust-lib/flowy-revision/src/cache/reset.rs

@@ -38,7 +38,6 @@ where
     pub async fn run(&self) -> FlowyResult<()> {
         match KV::get_str(self.target.target_id()) {
             None => {
-                tracing::trace!("😁 reset object");
                 let _ = self.reset_object().await?;
                 let _ = self.save_migrate_record()?;
             }

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

@@ -75,7 +75,7 @@ fn crate_log_filter(level: String) -> String {
     filters.push(format!("lib_ws={}", level));
     filters.push(format!("lib_infra={}", level));
     filters.push(format!("flowy_sync={}", level));
-    filters.push(format!("flowy_revision={}", level));
+    // filters.push(format!("flowy_revision={}", level));
     // filters.push(format!("lib_dispatch={}", level));
 
     filters.push(format!("dart_ffi={}", "info"));