|
@@ -1,5 +1,5 @@
|
|
|
use crate::entities::{GroupPB, GroupViewChangesetPB};
|
|
|
-use crate::services::group::{default_group_configuration, make_default_group, GeneratedGroup, Group};
|
|
|
+use crate::services::group::{default_group_configuration, make_no_status_group, GeneratedGroupConfig, Group};
|
|
|
use flowy_error::{FlowyError, FlowyResult};
|
|
|
use flowy_grid_data_model::revision::{
|
|
|
FieldRevision, FieldTypeRevision, GroupConfigurationContentSerde, GroupConfigurationRevision, GroupRevision,
|
|
@@ -34,14 +34,28 @@ impl<T> std::fmt::Display for GroupContext<T> {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+/// A [GroupContext] represents as the groups memory cache
|
|
|
+/// Each [GenericGroupController] has its own [GroupContext], the `context` has its own configuration
|
|
|
+/// that is restored from the disk.
|
|
|
+///
|
|
|
+/// The `context` contains a list of [Group]s and the grouping [FieldRevision]
|
|
|
pub struct GroupContext<C> {
|
|
|
pub view_id: String,
|
|
|
+ /// The group configuration restored from the disk.
|
|
|
+ ///
|
|
|
+ /// Uses the [GroupConfigurationReader] to read the configuration data from disk
|
|
|
configuration: Arc<GroupConfigurationRevision>,
|
|
|
- configuration_content: PhantomData<C>,
|
|
|
+ configuration_phantom: PhantomData<C>,
|
|
|
+
|
|
|
+ /// The grouping field
|
|
|
field_rev: Arc<FieldRevision>,
|
|
|
+
|
|
|
+ /// Cache all the groups
|
|
|
groups_map: IndexMap<String, Group>,
|
|
|
- /// default_group is used to store the rows that don't belong to any groups.
|
|
|
- // default_group: Group,
|
|
|
+
|
|
|
+ /// A writer that implement the [GroupConfigurationWriter] trait is used to save the
|
|
|
+ /// configuration to disk
|
|
|
+ ///
|
|
|
writer: Arc<dyn GroupConfigurationWriter>,
|
|
|
}
|
|
|
|
|
@@ -73,19 +87,21 @@ where
|
|
|
groups_map: IndexMap::new(),
|
|
|
writer,
|
|
|
configuration,
|
|
|
- configuration_content: PhantomData,
|
|
|
+ configuration_phantom: PhantomData,
|
|
|
})
|
|
|
}
|
|
|
|
|
|
- pub(crate) fn get_default_group(&self) -> Option<&Group> {
|
|
|
+ /// Returns the no `status` group
|
|
|
+ ///
|
|
|
+ /// We take the `id` of the `field` as the default group id
|
|
|
+ pub(crate) fn get_no_status_group(&self) -> Option<&Group> {
|
|
|
self.groups_map.get(&self.field_rev.id)
|
|
|
}
|
|
|
|
|
|
- pub(crate) fn get_mut_default_group(&mut self) -> Option<&mut Group> {
|
|
|
+ pub(crate) fn get_mut_no_status_group(&mut self) -> Option<&mut Group> {
|
|
|
self.groups_map.get_mut(&self.field_rev.id)
|
|
|
}
|
|
|
|
|
|
- /// Returns the groups without the default group
|
|
|
pub(crate) fn groups(&self) -> Vec<&Group> {
|
|
|
self.groups_map.values().collect()
|
|
|
}
|
|
@@ -142,23 +158,38 @@ where
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- #[tracing::instrument(level = "debug", skip(self, generated_groups), err)]
|
|
|
+ /// Reset the memory cache of the groups and update the group configuration
|
|
|
+ ///
|
|
|
+ /// # Arguments
|
|
|
+ ///
|
|
|
+ /// * `generated_group_configs`: the generated groups contains a list of [GeneratedGroupConfig].
|
|
|
+ ///
|
|
|
+ /// Each [FieldType] can implement the [GroupGenerator] trait in order to generate different
|
|
|
+ /// groups. For example, the FieldType::Checkbox has the [CheckboxGroupGenerator] that implements
|
|
|
+ /// the [GroupGenerator] trait.
|
|
|
+ ///
|
|
|
+ /// Consider the passed-in generated_group_configs as new groups, the groups in the current
|
|
|
+ /// [GroupConfigurationRevision] as old groups. The old groups and the new groups will be merged
|
|
|
+ /// while keeping the order of the old groups.
|
|
|
+ ///
|
|
|
+ #[tracing::instrument(level = "debug", skip(self, generated_group_configs), err)]
|
|
|
pub(crate) fn init_groups(
|
|
|
&mut self,
|
|
|
- generated_groups: Vec<GeneratedGroup>,
|
|
|
+ generated_group_configs: Vec<GeneratedGroupConfig>,
|
|
|
) -> FlowyResult<Option<GroupViewChangesetPB>> {
|
|
|
let mut new_groups = vec![];
|
|
|
let mut filter_content_map = HashMap::new();
|
|
|
- generated_groups.into_iter().for_each(|generate_group| {
|
|
|
+ generated_group_configs.into_iter().for_each(|generate_group| {
|
|
|
filter_content_map.insert(generate_group.group_rev.id.clone(), generate_group.filter_content);
|
|
|
new_groups.push(generate_group.group_rev);
|
|
|
});
|
|
|
|
|
|
let mut old_groups = self.configuration.groups.clone();
|
|
|
if !old_groups.iter().any(|group| group.id == self.field_rev.id) {
|
|
|
- old_groups.push(make_default_group(&self.field_rev));
|
|
|
+ old_groups.push(make_no_status_group(&self.field_rev));
|
|
|
}
|
|
|
|
|
|
+ // The `all_group_revs` represents as the combination of the new groups and old groups
|
|
|
let MergeGroupResult {
|
|
|
mut all_group_revs,
|
|
|
new_group_revs,
|
|
@@ -171,6 +202,7 @@ where
|
|
|
.map(|group_rev| group_rev.id)
|
|
|
.collect::<Vec<String>>();
|
|
|
|
|
|
+ // Delete/Insert the group in the current configuration
|
|
|
self.mut_configuration(|configuration| {
|
|
|
let mut is_changed = false;
|
|
|
if !deleted_group_ids.is_empty() {
|
|
@@ -179,7 +211,6 @@ where
|
|
|
.retain(|group| !deleted_group_ids.contains(&group.id));
|
|
|
is_changed = true;
|
|
|
}
|
|
|
-
|
|
|
for group_rev in &mut all_group_revs {
|
|
|
match configuration
|
|
|
.groups
|
|
@@ -187,14 +218,20 @@ where
|
|
|
.position(|old_group_rev| old_group_rev.id == group_rev.id)
|
|
|
{
|
|
|
None => {
|
|
|
+ // Push the group to the end of the list if it doesn't exist in the group
|
|
|
configuration.groups.push(group_rev.clone());
|
|
|
is_changed = true;
|
|
|
}
|
|
|
Some(pos) => {
|
|
|
let mut old_group = configuration.groups.remove(pos);
|
|
|
+
|
|
|
+ // Take the old group setting
|
|
|
group_rev.update_with_other(&old_group);
|
|
|
- is_changed = is_group_changed(group_rev, &old_group);
|
|
|
+ if !is_changed {
|
|
|
+ is_changed = is_group_changed(group_rev, &old_group);
|
|
|
+ }
|
|
|
|
|
|
+ // Consider the the name of the `group_rev` as the newest.
|
|
|
old_group.name = group_rev.name.clone();
|
|
|
configuration.groups.insert(pos, old_group);
|
|
|
}
|
|
@@ -203,6 +240,7 @@ where
|
|
|
is_changed
|
|
|
})?;
|
|
|
|
|
|
+ // Update the memory cache of the groups
|
|
|
all_group_revs.into_iter().for_each(|group_rev| {
|
|
|
let filter_content = filter_content_map
|
|
|
.get(&group_rev.id)
|
|
@@ -257,24 +295,6 @@ where
|
|
|
Ok(())
|
|
|
}
|
|
|
|
|
|
- #[tracing::instrument(level = "trace", skip_all, err)]
|
|
|
- pub fn save_configuration(&self) -> FlowyResult<()> {
|
|
|
- let configuration = (&*self.configuration).clone();
|
|
|
- let writer = self.writer.clone();
|
|
|
- let field_id = self.field_rev.id.clone();
|
|
|
- let field_type = self.field_rev.ty;
|
|
|
- tokio::spawn(async move {
|
|
|
- match writer.save_configuration(&field_id, field_type, configuration).await {
|
|
|
- Ok(_) => {}
|
|
|
- Err(e) => {
|
|
|
- tracing::error!("Save group configuration failed: {}", e);
|
|
|
- }
|
|
|
- }
|
|
|
- });
|
|
|
-
|
|
|
- Ok(())
|
|
|
- }
|
|
|
-
|
|
|
fn mut_configuration(
|
|
|
&mut self,
|
|
|
mut_configuration_fn: impl FnOnce(&mut GroupConfigurationRevision) -> bool,
|
|
@@ -282,7 +302,18 @@ where
|
|
|
let configuration = Arc::make_mut(&mut self.configuration);
|
|
|
let is_changed = mut_configuration_fn(configuration);
|
|
|
if is_changed {
|
|
|
- let _ = self.save_configuration()?;
|
|
|
+ let configuration = (&*self.configuration).clone();
|
|
|
+ let writer = self.writer.clone();
|
|
|
+ let field_id = self.field_rev.id.clone();
|
|
|
+ let field_type = self.field_rev.ty;
|
|
|
+ tokio::spawn(async move {
|
|
|
+ match writer.save_configuration(&field_id, field_type, configuration).await {
|
|
|
+ Ok(_) => {}
|
|
|
+ Err(e) => {
|
|
|
+ tracing::error!("Save group configuration failed: {}", e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
}
|
|
|
Ok(())
|
|
|
}
|
|
@@ -302,13 +333,6 @@ where
|
|
|
|
|
|
fn merge_groups(old_groups: Vec<GroupRevision>, new_groups: Vec<GroupRevision>) -> MergeGroupResult {
|
|
|
let mut merge_result = MergeGroupResult::new();
|
|
|
- // if old_groups.is_empty() {
|
|
|
- // merge_result.all_group_revs.extend(new_groups.clone());
|
|
|
- // merge_result.all_group_revs.push(default_group);
|
|
|
- // merge_result.new_group_revs = new_groups;
|
|
|
- // return merge_result;
|
|
|
- // }
|
|
|
-
|
|
|
// group_map is a helper map is used to filter out the new groups.
|
|
|
let mut new_group_map: IndexMap<String, GroupRevision> = IndexMap::new();
|
|
|
new_groups.into_iter().for_each(|group_rev| {
|