Selaa lähdekoodia

chore: add board no status column

appflowy 2 vuotta sitten
vanhempi
commit
940289c6e3

+ 9 - 2
frontend/app_flowy/lib/plugins/board/presentation/board_page.dart

@@ -15,6 +15,7 @@ import 'package:flowy_infra_ui/style_widget/text.dart';
 import 'package:flowy_infra_ui/widget/error_page.dart';
 import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart';
 import 'package:flowy_sdk/protobuf/flowy-grid/block_entities.pb.dart';
+import 'package:flowy_sdk/protobuf/flowy-grid/group.pbserver.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
 import '../../grid/application/row/row_cache.dart';
@@ -154,7 +155,11 @@ class _BoardContentState extends State<BoardContent> {
   }
 
   Widget _buildFooter(BuildContext context, AFBoardColumnData columnData) {
-    return AppFlowyColumnFooter(
+    final group = columnData.customData as GroupPB;
+    if (group.isDefault) {
+      return const SizedBox();
+    } else {
+      return AppFlowyColumnFooter(
         icon: SizedBox(
           height: 20,
           width: 20,
@@ -172,7 +177,9 @@ class _BoardContentState extends State<BoardContent> {
         margin: config.footerPadding,
         onAddButtonClick: () {
           context.read<BoardBloc>().add(BoardEvent.createRow(columnData.id));
-        });
+        },
+      );
+    }
   }
 
   Widget _buildCard(

+ 4 - 0
frontend/rust-lib/flowy-grid/src/entities/group_entities/group.rs

@@ -81,6 +81,9 @@ pub struct GroupPB {
 
     #[pb(index = 4)]
     pub rows: Vec<RowPB>,
+
+    #[pb(index = 5)]
+    pub is_default: bool,
 }
 
 impl std::convert::From<Group> for GroupPB {
@@ -90,6 +93,7 @@ impl std::convert::From<Group> for GroupPB {
             group_id: group.id,
             desc: group.name,
             rows: group.rows,
+            is_default: group.is_default,
         }
     }
 }

+ 6 - 0
frontend/rust-lib/flowy-grid/src/services/cell/cell_operation.rs

@@ -176,6 +176,12 @@ pub fn insert_select_option_cell(option_id: String, field_rev: &FieldRevision) -
     CellRevision::new(data)
 }
 
+pub fn delete_select_option_cell(option_id: String, field_rev: &FieldRevision) -> CellRevision {
+    let cell_data = SelectOptionCellChangeset::from_delete(&option_id).to_str();
+    let data = apply_cell_data_changeset(cell_data, None, field_rev).unwrap();
+    CellRevision::new(data)
+}
+
 /// If the cell data is not String type, it should impl this trait.
 /// Deserialize the String into cell specific data type.  
 pub trait FromCellString {

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

@@ -31,6 +31,10 @@ impl<T> std::fmt::Display for GenericGroupConfiguration<T> {
         self.groups_map.iter().for_each(|(_, group)| {
             let _ = f.write_fmt(format_args!("Group:{} has {} rows \n", group.id, group.rows.len()));
         });
+        let _ = f.write_fmt(format_args!(
+            "Default group has {} rows \n",
+            self.default_group.rows.len()
+        ));
         Ok(())
     }
 }
@@ -41,6 +45,8 @@ pub struct GenericGroupConfiguration<C> {
     configuration_content: PhantomData<C>,
     field_rev: Arc<FieldRevision>,
     groups_map: IndexMap<String, Group>,
+    /// default_group is used to store the rows that don't belong to any groups.
+    default_group: Group,
     writer: Arc<dyn GroupConfigurationWriter>,
 }
 
@@ -55,6 +61,15 @@ where
         reader: Arc<dyn GroupConfigurationReader>,
         writer: Arc<dyn GroupConfigurationWriter>,
     ) -> FlowyResult<Self> {
+        let default_group_id = format!("{}_default_group", view_id);
+        let default_group = Group {
+            id: default_group_id,
+            field_id: field_rev.id.clone(),
+            name: format!("No {}", field_rev.name),
+            is_default: true,
+            rows: vec![],
+            content: "".to_string(),
+        };
         let configuration = match reader.get_group_configuration(field_rev.clone()).await {
             None => {
                 let default_group_configuration = default_group_configuration(&field_rev);
@@ -71,6 +86,7 @@ where
             view_id,
             field_rev,
             groups_map: IndexMap::new(),
+            default_group,
             writer,
             configuration,
             configuration_content: PhantomData,
@@ -82,7 +98,9 @@ where
     }
 
     pub(crate) fn clone_groups(&self) -> Vec<Group> {
-        self.groups_map.values().cloned().collect()
+        let mut groups: Vec<Group> = self.groups_map.values().cloned().collect();
+        groups.push(self.default_group.clone());
+        groups
     }
 
     pub(crate) fn merge_groups(&mut self, groups: Vec<Group>) -> FlowyResult<Option<GroupViewChangesetPB>> {
@@ -160,6 +178,10 @@ where
         self.groups_map.get_mut(group_id)
     }
 
+    pub(crate) fn get_mut_default_group(&mut self) -> &mut Group {
+        &mut self.default_group
+    }
+
     pub(crate) fn move_group(&mut self, from_id: &str, to_id: &str) -> FlowyResult<()> {
         let from_index = self.groups_map.get_index_of(from_id);
         let to_index = self.groups_map.get_index_of(to_id);

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

@@ -1,4 +1,4 @@
-use crate::entities::{GroupChangesetPB, GroupViewChangesetPB, RowPB};
+use crate::entities::{GroupChangesetPB, GroupViewChangesetPB, InsertedRowPB, RowPB};
 use crate::services::cell::{decode_any_cell_data, CellBytesParser};
 use crate::services::group::action::GroupAction;
 use crate::services::group::configuration::GenericGroupConfiguration;
@@ -11,8 +11,6 @@ use flowy_grid_data_model::revision::{
 use std::marker::PhantomData;
 use std::sync::Arc;
 
-const DEFAULT_GROUP_ID: &str = "default_group";
-
 // Each kind of group must implement this trait to provide custom group
 // operations. For example, insert cell data to the row_rev when creating
 // a new row.
@@ -72,8 +70,6 @@ pub struct GenericGroupController<C, T, G, P> {
     pub field_id: String,
     pub type_option: Option<T>,
     pub configuration: GenericGroupConfiguration<C>,
-    /// default_group is used to store the rows that don't belong to any groups.
-    default_group: Group,
     group_action_phantom: PhantomData<G>,
     cell_parser_phantom: PhantomData<P>,
 }
@@ -92,22 +88,85 @@ where
         let type_option = field_rev.get_type_option_entry::<T>(field_type_rev);
         let groups = G::generate_groups(&field_rev.id, &configuration, &type_option);
         let _ = configuration.merge_groups(groups)?;
-        let default_group = Group::new(
-            DEFAULT_GROUP_ID.to_owned(),
-            field_rev.id.clone(),
-            format!("No {}", field_rev.name),
-            "".to_string(),
-        );
 
         Ok(Self {
             field_id: field_rev.id.clone(),
-            default_group,
             type_option,
             configuration,
             group_action_phantom: PhantomData,
             cell_parser_phantom: PhantomData,
         })
     }
+
+    fn update_default_group(
+        &mut self,
+        row_rev: &RowRevision,
+        other_group_changesets: &Vec<GroupChangesetPB>,
+    ) -> GroupChangesetPB {
+        let default_group = self.configuration.get_mut_default_group();
+
+        // [other_group_inserted_row] contains all the inserted rows except the default group.
+        let other_group_inserted_row = other_group_changesets
+            .iter()
+            .flat_map(|changeset| &changeset.inserted_rows)
+            .collect::<Vec<&InsertedRowPB>>();
+
+        // Calculate the inserted_rows of the default_group
+        let default_group_inserted_row = other_group_changesets
+            .iter()
+            .flat_map(|changeset| &changeset.deleted_rows)
+            .cloned()
+            .filter(|row_id| {
+                // if the [other_group_inserted_row] contains the row_id of the row
+                // which means the row should not move to the default group.
+                other_group_inserted_row
+                    .iter()
+                    .find(|inserted_row| &inserted_row.row.id == row_id)
+                    .is_none()
+            })
+            .collect::<Vec<String>>();
+
+        let mut changeset = GroupChangesetPB::new(default_group.id.clone());
+        if default_group_inserted_row.is_empty() == false {
+            changeset.inserted_rows.push(InsertedRowPB::new(row_rev.into()));
+            default_group.add_row(row_rev.into());
+        }
+
+        // [other_group_delete_rows] contains all the deleted rows except the default group.
+        let other_group_delete_rows: Vec<String> = other_group_changesets
+            .iter()
+            .flat_map(|changeset| &changeset.deleted_rows)
+            .cloned()
+            .collect();
+
+        let default_group_deleted_rows = other_group_changesets
+            .iter()
+            .flat_map(|changeset| &changeset.inserted_rows)
+            .filter(|inserted_row| {
+                // if the [other_group_delete_rows] contain the inserted_row, which means this row should move
+                // out from the default_group.
+                let inserted_row_id = &inserted_row.row.id;
+                other_group_delete_rows
+                    .iter()
+                    .find(|row_id| inserted_row_id == row_id.clone())
+                    .is_none()
+            })
+            .collect::<Vec<&InsertedRowPB>>();
+
+        let mut deleted_row_ids = vec![];
+        for row in &default_group.rows {
+            if default_group_deleted_rows
+                .iter()
+                .find(|deleted_row| deleted_row.row.id == row.id)
+                .is_some()
+            {
+                deleted_row_ids.push(row.id.clone());
+            }
+        }
+        default_group.rows.retain(|row| !deleted_row_ids.contains(&row.id));
+        changeset.deleted_rows.extend(deleted_row_ids);
+        changeset
+    }
 }
 
 impl<C, T, G, P> GroupControllerSharedOperation for GenericGroupController<C, T, G, P>
@@ -124,11 +183,7 @@ where
     }
 
     fn groups(&self) -> Vec<Group> {
-        let mut groups = self.configuration.clone_groups();
-        if self.default_group.is_empty() == false {
-            groups.insert(0, self.default_group.clone());
-        }
-        groups
+        self.configuration.clone_groups()
     }
 
     fn get_group(&self, group_id: &str) -> Option<(usize, Group)> {
@@ -138,7 +193,6 @@ where
 
     #[tracing::instrument(level = "trace", skip_all, fields(row_count=%row_revs.len(), group_result))]
     fn fill_groups(&mut self, row_revs: &[Arc<RowRevision>], field_rev: &FieldRevision) -> FlowyResult<Vec<Group>> {
-        // let mut ungrouped_rows = vec![];
         for row_rev in row_revs {
             if let Some(cell_rev) = row_rev.cells.get(&self.field_id) {
                 let mut grouped_rows: Vec<GroupedRow> = vec![];
@@ -154,8 +208,7 @@ where
                 }
 
                 if grouped_rows.is_empty() {
-                    // ungrouped_rows.push(RowPB::from(row_rev));
-                    self.default_group.add_row(row_rev.into());
+                    self.configuration.get_mut_default_group().add_row(row_rev.into());
                 } else {
                     for group_row in grouped_rows {
                         if let Some(group) = self.configuration.get_mut_group(&group_row.group_id) {
@@ -164,30 +217,11 @@ where
                     }
                 }
             } else {
-                self.default_group.add_row(row_rev.into());
+                self.configuration.get_mut_default_group().add_row(row_rev.into());
             }
         }
 
-        // if !ungrouped_rows.is_empty() {
-        //     let default_group_rev = GroupRevision::default_group(gen_grid_group_id(), format!("No {}", field_rev.name));
-        //     let default_group = Group::new(
-        //         default_group_rev.id.clone(),
-        //         field_rev.id.clone(),
-        //         default_group_rev.name.clone(),
-        //         "".to_owned(),
-        //     );
-        // }
-
-        tracing::Span::current().record(
-            "group_result",
-            &format!(
-                "{}, default_group has {} rows",
-                self.configuration,
-                self.default_group.rows.len()
-            )
-            .as_str(),
-        );
-
+        tracing::Span::current().record("group_result", &format!("{},", self.configuration,).as_str());
         Ok(self.groups())
     }
 
@@ -203,7 +237,12 @@ where
         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>()?;
-            let changesets = self.add_row_if_match(row_rev, &cell_data);
+            let mut changesets = self.add_row_if_match(row_rev, &cell_data);
+            let default_group_changeset = self.update_default_group(row_rev, &changesets);
+            tracing::info!("default_group_changeset: {}", default_group_changeset);
+            if !default_group_changeset.is_empty() {
+                changesets.push(default_group_changeset);
+            }
             Ok(changesets)
         } else {
             Ok(vec![])

+ 16 - 9
frontend/rust-lib/flowy-grid/src/services/group/controller_impls/select_option_controller/util.rs

@@ -15,18 +15,25 @@ pub fn add_row(
     row_rev: &RowRevision,
 ) -> Option<GroupChangesetPB> {
     let mut changeset = GroupChangesetPB::new(group.id.clone());
-    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);
-                changeset.inserted_rows.push(InsertedRowPB::new(row_pb.clone()));
-                group.add_row(row_pb);
-            }
-        } else if group.contains_row(&row_rev.id) {
+    if cell_data.select_options.is_empty() {
+        if group.contains_row(&row_rev.id) {
             changeset.deleted_rows.push(row_rev.id.clone());
             group.remove_row(&row_rev.id);
         }
-    });
+    } else {
+        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);
+                    changeset.inserted_rows.push(InsertedRowPB::new(row_pb.clone()));
+                    group.add_row(row_pb);
+                }
+            } else if group.contains_row(&row_rev.id) {
+                changeset.deleted_rows.push(row_rev.id.clone());
+                group.remove_row(&row_rev.id);
+            }
+        });
+    }
 
     if changeset.is_empty() {
         None

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

@@ -5,6 +5,7 @@ pub struct Group {
     pub id: String,
     pub field_id: String,
     pub name: String,
+    pub is_default: bool,
     pub(crate) rows: Vec<RowPB>,
 
     /// [content] is used to determine which group the cell belongs to.
@@ -16,6 +17,7 @@ impl Group {
         Self {
             id,
             field_id,
+            is_default: false,
             name,
             rows: vec![],
             content,

+ 17 - 6
frontend/rust-lib/flowy-grid/tests/grid/group_test/script.rs

@@ -2,7 +2,7 @@ use crate::grid::grid_editor::GridEditorTest;
 use flowy_grid::entities::{
     CreateRowParams, FieldChangesetParams, FieldType, GridLayout, GroupPB, MoveGroupParams, MoveGroupRowParams, RowPB,
 };
-use flowy_grid::services::cell::insert_select_option_cell;
+use flowy_grid::services::cell::{delete_select_option_cell, insert_select_option_cell};
 use flowy_grid_data_model::revision::RowChangeset;
 use std::time::Duration;
 use tokio::time::interval;
@@ -128,11 +128,22 @@ impl GridGroupTest {
                 let field_id = from_group.field_id;
                 let field_rev = self.editor.get_field_rev(&field_id).await.unwrap();
                 let field_type: FieldType = field_rev.ty.into();
-                let cell_rev = match field_type {
-                    FieldType::SingleSelect => insert_select_option_cell(to_group.group_id.clone(), &field_rev),
-                    FieldType::MultiSelect => insert_select_option_cell(to_group.group_id.clone(), &field_rev),
-                    _ => {
-                        panic!("Unsupported group field type");
+
+                let cell_rev = if to_group.is_default {
+                    match field_type {
+                        FieldType::SingleSelect => delete_select_option_cell(to_group.group_id.clone(), &field_rev),
+                        FieldType::MultiSelect => delete_select_option_cell(to_group.group_id.clone(), &field_rev),
+                        _ => {
+                            panic!("Unsupported group field type");
+                        }
+                    }
+                } else {
+                    match field_type {
+                        FieldType::SingleSelect => insert_select_option_cell(to_group.group_id.clone(), &field_rev),
+                        FieldType::MultiSelect => insert_select_option_cell(to_group.group_id.clone(), &field_rev),
+                        _ => {
+                            panic!("Unsupported group field type");
+                        }
                     }
                 };
 

+ 54 - 1
frontend/rust-lib/flowy-grid/tests/grid/group_test/test.rs

@@ -6,7 +6,7 @@ use flowy_grid::entities::FieldChangesetParams;
 async fn group_init_test() {
     let mut test = GridGroupTest::new().await;
     let scripts = vec![
-        AssertGroupCount(3),
+        AssertGroupCount(4),
         AssertGroupRowCount {
             group_index: 0,
             row_count: 2,
@@ -19,6 +19,10 @@ async fn group_init_test() {
             group_index: 2,
             row_count: 1,
         },
+        AssertGroupRowCount {
+            group_index: 3,
+            row_count: 0,
+        },
     ];
     test.run_scripts(scripts).await;
 }
@@ -294,6 +298,55 @@ async fn group_reorder_group_test() {
     test.run_scripts(scripts).await;
 }
 
+#[tokio::test]
+async fn group_move_to_default_group_test() {
+    let mut test = GridGroupTest::new().await;
+    let scripts = vec![
+        UpdateRow {
+            from_group_index: 0,
+            row_index: 0,
+            to_group_index: 3,
+        },
+        AssertGroupRowCount {
+            group_index: 0,
+            row_count: 1,
+        },
+        AssertGroupRowCount {
+            group_index: 3,
+            row_count: 1,
+        },
+    ];
+    test.run_scripts(scripts).await;
+}
+
+#[tokio::test]
+async fn group_move_from_default_group_test() {
+    let mut test = GridGroupTest::new().await;
+    let scripts = vec![UpdateRow {
+        from_group_index: 0,
+        row_index: 0,
+        to_group_index: 3,
+    }];
+    test.run_scripts(scripts).await;
+
+    let scripts = vec![
+        UpdateRow {
+            from_group_index: 3,
+            row_index: 0,
+            to_group_index: 0,
+        },
+        AssertGroupRowCount {
+            group_index: 0,
+            row_count: 2,
+        },
+        AssertGroupRowCount {
+            group_index: 3,
+            row_count: 0,
+        },
+    ];
+    test.run_scripts(scripts).await;
+}
+
 #[tokio::test]
 async fn group_move_group_test() {
     let mut test = GridGroupTest::new().await;