ソースを参照

chore: support switch to multi select field

appflowy 2 年 前
コミット
1931cdd4c0

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

@@ -207,6 +207,10 @@ impl GridRevisionEditor {
         Ok(())
     }
 
+    pub async fn group_field(&self, field_id: &str) -> FlowyResult<()> {
+        todo!()
+    }
+
     pub async fn switch_to_field_type(&self, field_id: &str, field_type: &FieldType) -> FlowyResult<()> {
         // let block_ids = self
         //     .get_block_metas()

+ 60 - 24
frontend/rust-lib/flowy-grid/src/services/grid_view_editor.rs

@@ -6,7 +6,9 @@ use crate::entities::{
 };
 use crate::services::grid_editor_task::GridServiceTaskScheduler;
 use crate::services::grid_view_manager::{GridViewFieldDelegate, GridViewRowDelegate};
-use crate::services::group::{GroupConfigurationReader, GroupConfigurationWriter, GroupService};
+use crate::services::group::{
+    make_group_controller, GroupConfigurationReader, GroupConfigurationWriter, GroupController, GroupService,
+};
 use flowy_error::{FlowyError, FlowyResult};
 use flowy_grid_data_model::revision::{
     gen_grid_filter_id, FieldRevision, FieldTypeRevision, FilterConfigurationRevision, GroupConfigurationRevision,
@@ -17,6 +19,7 @@ use flowy_sync::client_grid::{GridViewRevisionChangeset, GridViewRevisionPad};
 use flowy_sync::entities::revision::Revision;
 use lib_infra::future::{wrap_future, AFFuture, FutureResult};
 use std::collections::HashMap;
+use std::future::Future;
 
 use std::sync::atomic::{AtomicBool, Ordering};
 use std::sync::Arc;
@@ -30,9 +33,8 @@ pub struct GridViewRevisionEditor {
     rev_manager: Arc<RevisionManager>,
     field_delegate: Arc<dyn GridViewFieldDelegate>,
     row_delegate: Arc<dyn GridViewRowDelegate>,
-    group_service: Arc<RwLock<GroupService>>,
+    group_controller: Arc<RwLock<Box<dyn GroupController>>>,
     scheduler: Arc<dyn GridServiceTaskScheduler>,
-    did_load_group: AtomicBool,
 }
 
 impl GridViewRevisionEditor {
@@ -53,15 +55,25 @@ impl GridViewRevisionEditor {
         let pad = Arc::new(RwLock::new(view_revision_pad));
         let rev_manager = Arc::new(rev_manager);
 
+        // Load group
         let configuration_reader = GroupConfigurationReaderImpl(pad.clone());
         let configuration_writer = GroupConfigurationWriterImpl {
             user_id: user_id.to_owned(),
             rev_manager: rev_manager.clone(),
             view_pad: pad.clone(),
         };
-        let group_service = GroupService::new(view_id.clone(), configuration_reader, configuration_writer).await;
+        let field_revs = field_delegate.get_field_revs().await;
+        let row_revs = row_delegate.gv_row_revs().await;
+        let group_controller = make_group_controller(
+            view_id.clone(),
+            field_revs,
+            row_revs,
+            configuration_reader,
+            configuration_writer,
+        )
+        .await?;
+
         let user_id = user_id.to_owned();
-        let did_load_group = AtomicBool::new(false);
         Ok(Self {
             pad,
             user_id,
@@ -70,8 +82,7 @@ impl GridViewRevisionEditor {
             scheduler,
             field_delegate,
             row_delegate,
-            group_service: Arc::new(RwLock::new(group_service)),
-            did_load_group,
+            group_controller: Arc::new(RwLock::new(group_controller)),
         })
     }
 
@@ -112,33 +123,58 @@ impl GridViewRevisionEditor {
 
     pub(crate) async fn did_delete_row(&self, row_rev: &RowRevision) {
         // Send the group notification if the current view has groups;
-        if let Some(changesets) = self
-            .group_service
-            .write()
-            .await
-            .did_delete_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;
+        let group_field_id = self.group_controller.read().await.field_id().to_owned();
+        let field_rev = self.field_delegate.get_field_rev(&group_field_id).await;
+        field_rev.and_then(|field_rev| {
+            if let Some(changesets) = self
+                .group_controller
+                .write()
+                .await
+                .did_delete_row(row_rev, &field_rev)
+                .await
+            {
+                for changeset in changesets {
+                    self.notify_did_update_group(changeset).await;
+                }
             }
-        }
+            None
+        });
     }
 
     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
-        {
+        let changeset = self
+            .mut_group_controller(|group_controller, field_rev| async {
+                group_controller.did_update_row(row_rev, &field_rev).await
+            })
+            .await?;
+
+        if let Some(changeset) = changeset {
             for changeset in changesets {
                 self.notify_did_update_group(changeset).await;
             }
         }
     }
 
+    async fn mut_group_controller<F, O, T>(&self, f: F) -> Option<T>
+    where
+        F: FnOnce(&mut Box<dyn GroupController>, Arc<FieldRevision>) -> O,
+        O: Future<Output = Option<T>> + Send + Sync + 'static,
+    {
+        let group_field_id = self.group_controller.read().await.field_id().to_owned();
+        match self.field_delegate.get_field_rev(&group_field_id).await {
+            None => None,
+            Some(field_rev) => {
+                let mut write_guard = self.group_controller.write().await;
+                Some(f(&mut write_guard, field_rev).await)
+            }
+        }
+    }
+
+    async fn get_group_field_rev(&self) -> Option<Arc<FieldRevision>> {
+        let group_field_id = self.group_controller.read().await.field_id().to_owned();
+        self.field_delegate.get_field_rev(&group_field_id).await
+    }
+
     pub(crate) async fn move_group_row(
         &self,
         row_rev: &RowRevision,

+ 68 - 0
frontend/rust-lib/flowy-grid/src/services/group/group_service.rs

@@ -241,6 +241,74 @@ impl GroupService {
     }
 }
 
+#[tracing::instrument(level = "trace", skip_all, err)]
+pub async fn make_group_controller<R, W>(
+    view_id: String,
+    field_revs: Vec<Arc<FieldRevision>>,
+    row_revs: Vec<Arc<RowRevision>>,
+    configuration_reader: R,
+    configuration_writer: W,
+) -> FlowyResult<Box<dyn GroupController>>
+where
+    R: GroupConfigurationReader,
+    W: GroupConfigurationWriter,
+{
+    let field_rev = find_group_field(&field_revs)?;
+    let field_type: FieldType = field_rev.ty.into();
+    let mut group_controller: Box<dyn GroupController>;
+    match field_type {
+        FieldType::RichText => {
+            // let generator = GroupGenerator::<TextGroupConfigurationPB>::from_configuration(configuration);
+            panic!()
+        }
+        FieldType::Number => {
+            // let generator = GroupGenerator::<NumberGroupConfigurationPB>::from_configuration(configuration);
+            panic!()
+        }
+        FieldType::DateTime => {
+            // let generator = GroupGenerator::<DateGroupConfigurationPB>::from_configuration(configuration);
+            panic!()
+        }
+        FieldType::SingleSelect => {
+            let configuration = SelectOptionGroupConfiguration::new(
+                view_id,
+                field_rev.clone(),
+                configuration_reader,
+                configuration_writer,
+            )
+            .await?;
+            let controller = SingleSelectGroupController::new(&field_rev, configuration).await?;
+            group_controller = Box::new(controller);
+        }
+        FieldType::MultiSelect => {
+            let configuration = SelectOptionGroupConfiguration::new(
+                view_id,
+                field_rev.clone(),
+                configuration_reader,
+                configuration_writer,
+            )
+            .await?;
+            let controller = MultiSelectGroupController::new(&field_rev, configuration).await?;
+            group_controller = Box::new(controller);
+        }
+        FieldType::Checkbox => {
+            let configuration =
+                CheckboxGroupConfiguration::new(view_id, field_rev.clone(), configuration_reader, configuration_writer)
+                    .await?;
+            let controller = CheckboxGroupController::new(&field_rev, configuration).await?;
+            group_controller = Box::new(controller);
+        }
+        FieldType::URL => {
+            // let generator = GroupGenerator::<UrlGroupConfigurationPB>::from_configuration(configuration);
+            panic!()
+        }
+    }
+
+    let _ = group_controller.fill_groups(&row_revs, &field_rev)?;
+
+    Ok(group_controller)
+}
+
 fn find_group_field(field_revs: &[Arc<FieldRevision>]) -> Option<Arc<FieldRevision>> {
     let field_rev = field_revs
         .iter()

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

@@ -6,6 +6,7 @@ mod entities;
 mod group_service;
 
 pub(crate) use configuration::*;
+pub(crate) use controller::*;
 pub(crate) use controller_impls::*;
 pub(crate) use entities::*;
 pub(crate) use group_service::*;

+ 22 - 1
frontend/rust-lib/flowy-grid/tests/grid/group_test/script.rs

@@ -3,7 +3,8 @@ use flowy_grid::entities::{
     CreateRowParams, FieldChangesetParams, FieldType, GridLayout, GroupPB, MoveGroupParams, MoveGroupRowParams, RowPB,
 };
 use flowy_grid::services::cell::{delete_select_option_cell, insert_select_option_cell};
-use flowy_grid_data_model::revision::RowChangeset;
+use flowy_grid_data_model::revision::{FieldRevision, RowChangeset};
+use std::sync::Arc;
 use std::time::Duration;
 use tokio::time::interval;
 
@@ -47,6 +48,9 @@ pub enum GroupScript {
     UpdateField {
         changeset: FieldChangesetParams,
     },
+    GroupField {
+        field_id: String,
+    },
 }
 
 pub struct GridGroupTest {
@@ -179,6 +183,9 @@ impl GridGroupTest {
                 let mut interval = interval(Duration::from_millis(130));
                 interval.tick().await;
             }
+            GroupScript::GroupField { field_id } => {
+                self.editor.group_field(&field_id).await.unwrap();
+            }
         }
     }
 
@@ -191,6 +198,20 @@ impl GridGroupTest {
         let groups = self.group_at_index(group_index).await;
         groups.rows.get(row_index).unwrap().clone()
     }
+
+    pub async fn get_multi_select_field(&self) -> Arc<FieldRevision> {
+        let field = self
+            .inner
+            .field_revs
+            .iter()
+            .find(|field_rev| {
+                let field_type: FieldType = field_rev.ty.into();
+                field_type.is_multi_select()
+            })
+            .unwrap()
+            .clone();
+        return field;
+    }
 }
 
 impl std::ops::Deref for GridGroupTest {

+ 9 - 0
frontend/rust-lib/flowy-grid/tests/grid/group_test/test.rs

@@ -390,3 +390,12 @@ async fn group_update_field_test() {
     ];
     test.run_scripts(scripts).await;
 }
+
+#[tokio::test]
+async fn group_multi_select_field_test() {
+    let mut test = GridGroupTest::new().await;
+    let multi_select_field = test.get_multi_select_field().await;
+
+    let scripts = vec![];
+    test.run_scripts(scripts).await;
+}