configuration.rs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408
  1. use crate::entities::{GroupPB, GroupViewChangesetPB};
  2. use crate::services::group::{default_group_configuration, GeneratedGroupContext, Group};
  3. use flowy_error::{FlowyError, FlowyResult};
  4. use flowy_grid_data_model::revision::{
  5. FieldRevision, FieldTypeRevision, GroupConfigurationContentSerde, GroupConfigurationRevision, GroupRevision,
  6. };
  7. use indexmap::IndexMap;
  8. use lib_infra::future::AFFuture;
  9. use std::collections::HashMap;
  10. use std::fmt::Formatter;
  11. use std::marker::PhantomData;
  12. use std::sync::Arc;
  13. pub trait GroupConfigurationReader: Send + Sync + 'static {
  14. fn get_configuration(&self) -> AFFuture<Option<Arc<GroupConfigurationRevision>>>;
  15. }
  16. pub trait GroupConfigurationWriter: Send + Sync + 'static {
  17. fn save_configuration(
  18. &self,
  19. field_id: &str,
  20. field_type: FieldTypeRevision,
  21. group_configuration: GroupConfigurationRevision,
  22. ) -> AFFuture<FlowyResult<()>>;
  23. }
  24. impl<T> std::fmt::Display for GroupContext<T> {
  25. fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
  26. self.groups_map.iter().for_each(|(_, group)| {
  27. let _ = f.write_fmt(format_args!("Group:{} has {} rows \n", group.id, group.rows.len()));
  28. });
  29. Ok(())
  30. }
  31. }
  32. /// A [GroupContext] represents as the groups memory cache
  33. /// Each [GenericGroupController] has its own [GroupContext], the `context` has its own configuration
  34. /// that is restored from the disk.
  35. ///
  36. /// The `context` contains a list of [Group]s and the grouping [FieldRevision]
  37. pub struct GroupContext<C> {
  38. pub view_id: String,
  39. /// The group configuration restored from the disk.
  40. ///
  41. /// Uses the [GroupConfigurationReader] to read the configuration data from disk
  42. configuration: Arc<GroupConfigurationRevision>,
  43. configuration_phantom: PhantomData<C>,
  44. /// The grouping field
  45. field_rev: Arc<FieldRevision>,
  46. /// Cache all the groups
  47. groups_map: IndexMap<String, Group>,
  48. /// A writer that implement the [GroupConfigurationWriter] trait is used to save the
  49. /// configuration to disk
  50. ///
  51. writer: Arc<dyn GroupConfigurationWriter>,
  52. }
  53. impl<C> GroupContext<C>
  54. where
  55. C: GroupConfigurationContentSerde,
  56. {
  57. #[tracing::instrument(level = "trace", skip_all, err)]
  58. pub async fn new(
  59. view_id: String,
  60. field_rev: Arc<FieldRevision>,
  61. reader: Arc<dyn GroupConfigurationReader>,
  62. writer: Arc<dyn GroupConfigurationWriter>,
  63. ) -> FlowyResult<Self> {
  64. let configuration = match reader.get_configuration().await {
  65. None => {
  66. let default_configuration = default_group_configuration(&field_rev);
  67. writer
  68. .save_configuration(&field_rev.id, field_rev.ty, default_configuration.clone())
  69. .await?;
  70. Arc::new(default_configuration)
  71. }
  72. Some(configuration) => configuration,
  73. };
  74. Ok(Self {
  75. view_id,
  76. field_rev,
  77. groups_map: IndexMap::new(),
  78. writer,
  79. configuration,
  80. configuration_phantom: PhantomData,
  81. })
  82. }
  83. /// Returns the no `status` group
  84. ///
  85. /// We take the `id` of the `field` as the default group id
  86. pub(crate) fn get_no_status_group(&self) -> Option<&Group> {
  87. self.groups_map.get(&self.field_rev.id)
  88. }
  89. pub(crate) fn get_mut_no_status_group(&mut self) -> Option<&mut Group> {
  90. self.groups_map.get_mut(&self.field_rev.id)
  91. }
  92. pub(crate) fn groups(&self) -> Vec<&Group> {
  93. self.groups_map.values().collect()
  94. }
  95. pub(crate) fn get_mut_group(&mut self, group_id: &str) -> Option<&mut Group> {
  96. self.groups_map.get_mut(group_id)
  97. }
  98. // Returns the index and group specified by the group_id
  99. pub(crate) fn get_group(&self, group_id: &str) -> Option<(usize, &Group)> {
  100. match (self.groups_map.get_index_of(group_id), self.groups_map.get(group_id)) {
  101. (Some(index), Some(group)) => Some((index, group)),
  102. _ => None,
  103. }
  104. }
  105. /// Iterate mut the groups without `No status` group
  106. pub(crate) fn iter_mut_status_groups(&mut self, mut each: impl FnMut(&mut Group)) {
  107. self.groups_map.iter_mut().for_each(|(_, group)| {
  108. if group.id != self.field_rev.id {
  109. each(group);
  110. }
  111. });
  112. }
  113. pub(crate) fn iter_mut_groups(&mut self, mut each: impl FnMut(&mut Group)) {
  114. self.groups_map.iter_mut().for_each(|(_, group)| {
  115. each(group);
  116. });
  117. }
  118. pub(crate) fn move_group(&mut self, from_id: &str, to_id: &str) -> FlowyResult<()> {
  119. let from_index = self.groups_map.get_index_of(from_id);
  120. let to_index = self.groups_map.get_index_of(to_id);
  121. match (from_index, to_index) {
  122. (Some(from_index), Some(to_index)) => {
  123. self.groups_map.move_index(from_index, to_index);
  124. self.mut_configuration(|configuration| {
  125. let from_index = configuration.groups.iter().position(|group| group.id == from_id);
  126. let to_index = configuration.groups.iter().position(|group| group.id == to_id);
  127. if let (Some(from), Some(to)) = &(from_index, to_index) {
  128. tracing::trace!("Move group from index:{:?} to index:{:?}", from_index, to_index);
  129. let group = configuration.groups.remove(*from);
  130. configuration.groups.insert(*to, group);
  131. }
  132. tracing::debug!(
  133. "Group order: {:?} ",
  134. configuration
  135. .groups
  136. .iter()
  137. .map(|group| group.name.clone())
  138. .collect::<Vec<String>>()
  139. .join(",")
  140. );
  141. from_index.is_some() && to_index.is_some()
  142. })?;
  143. Ok(())
  144. }
  145. _ => Err(FlowyError::record_not_found().context("Moving group failed. Groups are not exist")),
  146. }
  147. }
  148. /// Reset the memory cache of the groups and update the group configuration
  149. ///
  150. /// # Arguments
  151. ///
  152. /// * `generated_group_configs`: the generated groups contains a list of [GeneratedGroupConfig].
  153. ///
  154. /// Each [FieldType] can implement the [GroupGenerator] trait in order to generate different
  155. /// groups. For example, the FieldType::Checkbox has the [CheckboxGroupGenerator] that implements
  156. /// the [GroupGenerator] trait.
  157. ///
  158. /// Consider the passed-in generated_group_configs as new groups, the groups in the current
  159. /// [GroupConfigurationRevision] as old groups. The old groups and the new groups will be merged
  160. /// while keeping the order of the old groups.
  161. ///
  162. #[tracing::instrument(level = "trace", skip(self, generated_group_context), err)]
  163. pub(crate) fn init_groups(
  164. &mut self,
  165. generated_group_context: GeneratedGroupContext,
  166. ) -> FlowyResult<Option<GroupViewChangesetPB>> {
  167. let GeneratedGroupContext {
  168. no_status_group,
  169. group_configs,
  170. } = generated_group_context;
  171. let mut new_groups = vec![];
  172. let mut filter_content_map = HashMap::new();
  173. group_configs.into_iter().for_each(|generate_group| {
  174. filter_content_map.insert(generate_group.group_rev.id.clone(), generate_group.filter_content);
  175. new_groups.push(generate_group.group_rev);
  176. });
  177. let mut old_groups = self.configuration.groups.clone();
  178. // clear all the groups if grouping by a new field
  179. if self.configuration.field_id != self.field_rev.id {
  180. old_groups.clear();
  181. }
  182. // The `No status` group index is initialized to 0
  183. if let Some(no_status_group) = no_status_group {
  184. old_groups.insert(0, no_status_group);
  185. }
  186. // The `all_group_revs` is the combination of the new groups and old groups
  187. let MergeGroupResult {
  188. mut all_group_revs,
  189. new_group_revs,
  190. updated_group_revs: _,
  191. deleted_group_revs,
  192. } = merge_groups(old_groups, new_groups);
  193. let deleted_group_ids = deleted_group_revs
  194. .into_iter()
  195. .map(|group_rev| group_rev.id)
  196. .collect::<Vec<String>>();
  197. self.mut_configuration(|configuration| {
  198. let mut is_changed = !deleted_group_ids.is_empty();
  199. // Remove the groups
  200. if !deleted_group_ids.is_empty() {
  201. configuration
  202. .groups
  203. .retain(|group| !deleted_group_ids.contains(&group.id));
  204. }
  205. // Update/Insert new groups
  206. for group_rev in &mut all_group_revs {
  207. match configuration
  208. .groups
  209. .iter()
  210. .position(|old_group_rev| old_group_rev.id == group_rev.id)
  211. {
  212. None => {
  213. // Push the group to the end of the list if it doesn't exist in the group
  214. configuration.groups.push(group_rev.clone());
  215. is_changed = true;
  216. }
  217. Some(pos) => {
  218. let mut old_group = configuration.groups.get_mut(pos).unwrap();
  219. // Take the old group setting
  220. group_rev.update_with_other(old_group);
  221. if !is_changed {
  222. is_changed = is_group_changed(group_rev, old_group);
  223. }
  224. // Consider the the name of the `group_rev` as the newest.
  225. old_group.name = group_rev.name.clone();
  226. }
  227. }
  228. }
  229. is_changed
  230. })?;
  231. // Update the memory cache of the groups
  232. all_group_revs.into_iter().for_each(|group_rev| {
  233. let filter_content = filter_content_map
  234. .get(&group_rev.id)
  235. .cloned()
  236. .unwrap_or_else(|| "".to_owned());
  237. let group = Group::new(group_rev.id, self.field_rev.id.clone(), group_rev.name, filter_content);
  238. self.groups_map.insert(group.id.clone(), group);
  239. });
  240. let new_groups = new_group_revs
  241. .into_iter()
  242. .flat_map(|group_rev| {
  243. let filter_content = filter_content_map.get(&group_rev.id)?;
  244. let group = Group::new(
  245. group_rev.id,
  246. self.field_rev.id.clone(),
  247. group_rev.name,
  248. filter_content.clone(),
  249. );
  250. Some(GroupPB::from(group))
  251. })
  252. .collect();
  253. let changeset = GroupViewChangesetPB {
  254. view_id: self.view_id.clone(),
  255. new_groups,
  256. deleted_groups: deleted_group_ids,
  257. update_groups: vec![],
  258. inserted_groups: vec![],
  259. };
  260. tracing::trace!("Group changeset: {:?}", changeset);
  261. if changeset.is_empty() {
  262. Ok(None)
  263. } else {
  264. Ok(Some(changeset))
  265. }
  266. }
  267. #[allow(dead_code)]
  268. pub(crate) async fn hide_group(&mut self, group_id: &str) -> FlowyResult<()> {
  269. self.mut_group_rev(group_id, |group_rev| {
  270. group_rev.visible = false;
  271. })?;
  272. Ok(())
  273. }
  274. #[allow(dead_code)]
  275. pub(crate) async fn show_group(&mut self, group_id: &str) -> FlowyResult<()> {
  276. self.mut_group_rev(group_id, |group_rev| {
  277. group_rev.visible = true;
  278. })?;
  279. Ok(())
  280. }
  281. fn mut_configuration(
  282. &mut self,
  283. mut_configuration_fn: impl FnOnce(&mut GroupConfigurationRevision) -> bool,
  284. ) -> FlowyResult<()> {
  285. let configuration = Arc::make_mut(&mut self.configuration);
  286. let is_changed = mut_configuration_fn(configuration);
  287. if is_changed {
  288. let configuration = (&*self.configuration).clone();
  289. let writer = self.writer.clone();
  290. let field_id = self.field_rev.id.clone();
  291. let field_type = self.field_rev.ty;
  292. tokio::spawn(async move {
  293. match writer.save_configuration(&field_id, field_type, configuration).await {
  294. Ok(_) => {}
  295. Err(e) => {
  296. tracing::error!("Save group configuration failed: {}", e);
  297. }
  298. }
  299. });
  300. }
  301. Ok(())
  302. }
  303. fn mut_group_rev(&mut self, group_id: &str, mut_groups_fn: impl Fn(&mut GroupRevision)) -> FlowyResult<()> {
  304. self.mut_configuration(|configuration| {
  305. match configuration.groups.iter_mut().find(|group| group.id == group_id) {
  306. None => false,
  307. Some(group_rev) => {
  308. mut_groups_fn(group_rev);
  309. true
  310. }
  311. }
  312. })
  313. }
  314. }
  315. /// Merge the new groups into old groups while keeping the order in the old groups
  316. ///
  317. fn merge_groups(old_groups: Vec<GroupRevision>, new_groups: Vec<GroupRevision>) -> MergeGroupResult {
  318. let mut merge_result = MergeGroupResult::new();
  319. // group_map is a helper map is used to filter out the new groups.
  320. let mut new_group_map: IndexMap<String, GroupRevision> = IndexMap::new();
  321. new_groups.into_iter().for_each(|group_rev| {
  322. new_group_map.insert(group_rev.id.clone(), group_rev);
  323. });
  324. // The group is ordered in old groups. Add them before adding the new groups
  325. for old in old_groups {
  326. if let Some(new) = new_group_map.remove(&old.id) {
  327. merge_result.all_group_revs.push(new.clone());
  328. if is_group_changed(&new, &old) {
  329. merge_result.updated_group_revs.push(new);
  330. }
  331. } else {
  332. merge_result.all_group_revs.push(old);
  333. }
  334. }
  335. // Find out the new groups
  336. let new_groups = new_group_map.into_values();
  337. for (_, group) in new_groups.into_iter().enumerate() {
  338. merge_result.all_group_revs.push(group.clone());
  339. merge_result.new_group_revs.push(group);
  340. }
  341. merge_result
  342. }
  343. fn is_group_changed(new: &GroupRevision, old: &GroupRevision) -> bool {
  344. if new.name != old.name {
  345. return true;
  346. }
  347. false
  348. }
  349. struct MergeGroupResult {
  350. // Contains the new groups and the updated groups
  351. all_group_revs: Vec<GroupRevision>,
  352. new_group_revs: Vec<GroupRevision>,
  353. updated_group_revs: Vec<GroupRevision>,
  354. deleted_group_revs: Vec<GroupRevision>,
  355. }
  356. impl MergeGroupResult {
  357. fn new() -> Self {
  358. Self {
  359. all_group_revs: vec![],
  360. new_group_revs: vec![],
  361. updated_group_revs: vec![],
  362. deleted_group_revs: vec![],
  363. }
  364. }
  365. }