fix: save group rev without apply change

This commit is contained in:
appflowy 2022-08-21 22:47:24 +08:00
parent 23efbc00c1
commit 93f5b5d754
16 changed files with 302 additions and 149 deletions

View File

@ -66,6 +66,7 @@ impl FlowyError {
static_flowy_error!(user_not_exist, ErrorCode::UserNotExist); static_flowy_error!(user_not_exist, ErrorCode::UserNotExist);
static_flowy_error!(text_too_long, ErrorCode::TextTooLong); static_flowy_error!(text_too_long, ErrorCode::TextTooLong);
static_flowy_error!(invalid_data, ErrorCode::InvalidData); static_flowy_error!(invalid_data, ErrorCode::InvalidData);
static_flowy_error!(out_of_bounds, ErrorCode::OutOfBounds);
} }
impl std::convert::From<ErrorCode> for FlowyError { impl std::convert::From<ErrorCode> for FlowyError {

View File

@ -109,10 +109,19 @@ pub struct GroupViewChangesetPB {
pub view_id: String, pub view_id: String,
#[pb(index = 2)] #[pb(index = 2)]
pub inserted_groups: Vec<GroupPB>, pub inserted_groups: Vec<InsertedGroupPB>,
#[pb(index = 3)] #[pb(index = 3)]
pub deleted_groups: Vec<String>, pub deleted_groups: Vec<String>,
} }
impl GroupViewChangesetPB {} impl GroupViewChangesetPB {}
#[derive(Debug, Default, ProtoBuf)]
pub struct InsertedGroupPB {
#[pb(index = 1)]
pub group: GroupPB,
#[pb(index = 2)]
pub index: i32,
}

View File

@ -1,14 +1,12 @@
use crate::dart_notification::{send_dart_notification, GridNotification}; use crate::dart_notification::{send_dart_notification, GridNotification};
use crate::entities::{ use crate::entities::{
CreateFilterParams, CreateRowParams, DeleteFilterParams, GridFilterConfiguration, GridLayout, GridLayoutPB, CreateFilterParams, CreateRowParams, DeleteFilterParams, GridFilterConfiguration, GridLayout, GridLayoutPB,
GridSettingChangesetParams, GridSettingPB, GroupPB, GroupRowsChangesetPB, GroupViewChangesetPB, InsertedRowPB, GridSettingPB, GroupPB, GroupRowsChangesetPB, GroupViewChangesetPB, InsertedGroupPB, InsertedRowPB,
MoveGroupParams, RepeatedGridConfigurationFilterPB, RepeatedGridGroupConfigurationPB, RowPB, MoveGroupParams, RepeatedGridConfigurationFilterPB, RepeatedGridGroupConfigurationPB, RowPB,
}; };
use crate::services::grid_editor_task::GridServiceTaskScheduler; use crate::services::grid_editor_task::GridServiceTaskScheduler;
use crate::services::grid_view_manager::{GridViewFieldDelegate, GridViewRowDelegate}; use crate::services::grid_view_manager::{GridViewFieldDelegate, GridViewRowDelegate};
use crate::services::group::{ use crate::services::group::{GroupConfigurationReader, GroupConfigurationWriter, GroupService};
default_group_configuration, GroupConfigurationReader, GroupConfigurationWriter, GroupService,
};
use flowy_error::{FlowyError, FlowyResult}; use flowy_error::{FlowyError, FlowyResult};
use flowy_grid_data_model::revision::{ use flowy_grid_data_model::revision::{
gen_grid_filter_id, FieldRevision, FieldTypeRevision, FilterConfigurationRevision, GroupConfigurationRevision, gen_grid_filter_id, FieldRevision, FieldTypeRevision, FilterConfigurationRevision, GroupConfigurationRevision,
@ -19,6 +17,7 @@ use flowy_sync::client_grid::{GridViewRevisionChangeset, GridViewRevisionPad};
use flowy_sync::entities::revision::Revision; use flowy_sync::entities::revision::Revision;
use lib_infra::future::{wrap_future, AFFuture, FutureResult}; use lib_infra::future::{wrap_future, AFFuture, FutureResult};
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc; use std::sync::Arc;
use tokio::sync::RwLock; use tokio::sync::RwLock;
@ -37,6 +36,7 @@ pub struct GridViewRevisionEditor {
} }
impl GridViewRevisionEditor { impl GridViewRevisionEditor {
#[tracing::instrument(level = "trace", skip_all, err)]
pub(crate) async fn new( pub(crate) async fn new(
user_id: &str, user_id: &str,
token: &str, token: &str,
@ -109,7 +109,7 @@ impl GridViewRevisionEditor {
// Send the group notification if the current view has groups; // Send the group notification if the current view has groups;
if let Some(changesets) = self if let Some(changesets) = self
.group_service .group_service
.write() .read()
.await .await
.did_delete_row(row_rev, |field_id| self.field_delegate.get_field_rev(&field_id)) .did_delete_row(row_rev, |field_id| self.field_delegate.get_field_rev(&field_id))
.await .await
@ -123,7 +123,7 @@ impl GridViewRevisionEditor {
pub(crate) async fn did_update_row(&self, row_rev: &RowRevision) { pub(crate) async fn did_update_row(&self, row_rev: &RowRevision) {
if let Some(changesets) = self if let Some(changesets) = self
.group_service .group_service
.write() .read()
.await .await
.did_update_row(row_rev, |field_id| self.field_delegate.get_field_rev(&field_id)) .did_update_row(row_rev, |field_id| self.field_delegate.get_field_rev(&field_id))
.await .await
@ -142,7 +142,7 @@ impl GridViewRevisionEditor {
) { ) {
if let Some(changesets) = self if let Some(changesets) = self
.group_service .group_service
.write() .read()
.await .await
.did_move_row(row_rev, row_changeset, upper_row_id, |field_id| { .did_move_row(row_rev, row_changeset, upper_row_id, |field_id| {
self.field_delegate.get_field_rev(&field_id) self.field_delegate.get_field_rev(&field_id)
@ -156,11 +156,13 @@ impl GridViewRevisionEditor {
} }
} }
#[tracing::instrument(level = "trace", skip(self))]
pub(crate) async fn load_groups(&self) -> FlowyResult<Vec<GroupPB>> { pub(crate) async fn load_groups(&self) -> FlowyResult<Vec<GroupPB>> {
let groups = if !self.did_load_group.load(Ordering::SeqCst) { let groups = if !self.did_load_group.load(Ordering::SeqCst) {
self.did_load_group.store(true, Ordering::SeqCst); self.did_load_group.store(true, Ordering::SeqCst);
let field_revs = self.field_delegate.get_field_revs().await; let field_revs = self.field_delegate.get_field_revs().await;
let row_revs = self.row_delegate.gv_row_revs().await; let row_revs = self.row_delegate.gv_row_revs().await;
match self match self
.group_service .group_service
.write() .write()
@ -174,11 +176,37 @@ impl GridViewRevisionEditor {
} else { } else {
self.group_service.read().await.groups().await self.group_service.read().await.groups().await
}; };
tracing::trace!("Number of groups: {}", groups.len());
Ok(groups.into_iter().map(GroupPB::from).collect()) Ok(groups.into_iter().map(GroupPB::from).collect())
} }
pub(crate) async fn move_group(&self, params: MoveGroupParams) -> FlowyResult<()> { pub(crate) async fn move_group(&self, params: MoveGroupParams) -> FlowyResult<()> {
todo!() let _ = self
.group_service
.read()
.await
.move_group(&params.from_group_id, &params.to_group_id)
.await?;
match self.group_service.read().await.get_group(&params.from_group_id).await {
None => {}
Some((index, group)) => {
let inserted_group = InsertedGroupPB {
group: GroupPB::from(group),
index: index as i32,
};
let changeset = GroupViewChangesetPB {
view_id: "".to_string(),
inserted_groups: vec![inserted_group],
deleted_groups: vec![params.from_group_id.clone()],
};
self.notify_did_update_view(changeset).await;
}
}
Ok(())
} }
pub(crate) async fn get_setting(&self) -> GridSettingPB { pub(crate) async fn get_setting(&self) -> GridSettingPB {
@ -291,17 +319,19 @@ impl RevisionObjectBuilder for GridViewRevisionPadBuilder {
struct GroupConfigurationReaderImpl(Arc<RwLock<GridViewRevisionPad>>); struct GroupConfigurationReaderImpl(Arc<RwLock<GridViewRevisionPad>>);
impl GroupConfigurationReader for GroupConfigurationReaderImpl { impl GroupConfigurationReader for GroupConfigurationReaderImpl {
fn get_group_configuration(&self, field_rev: Arc<FieldRevision>) -> AFFuture<Arc<GroupConfigurationRevision>> { fn get_group_configuration(
&self,
field_rev: Arc<FieldRevision>,
) -> AFFuture<Option<Arc<GroupConfigurationRevision>>> {
let view_pad = self.0.clone(); let view_pad = self.0.clone();
wrap_future(async move { wrap_future(async move {
let view_pad = view_pad.read().await; let mut groups = view_pad.read().await.groups.get_objects(&field_rev.id, &field_rev.ty)?;
let configurations = view_pad.get_groups(&field_rev.id, &field_rev.ty);
match configurations { if groups.is_empty() {
None => { None
let default_configuration = default_group_configuration(&field_rev); } else {
Arc::new(default_configuration) debug_assert_eq!(groups.len(), 1);
} Some(groups.pop().unwrap())
Some(configuration) => configuration,
} }
}) })
} }
@ -328,17 +358,25 @@ impl GroupConfigurationWriter for GroupConfigurationWriterImpl {
let field_id = field_id.to_owned(); let field_id = field_id.to_owned();
wrap_future(async move { wrap_future(async move {
match view_pad.write().await.get_mut_group( let is_contained = view_pad.read().await.contains_group(&field_id, &field_type);
&field_id, let changeset = if is_contained {
&field_type, view_pad.write().await.with_mut_group(
&configuration_id, &field_id,
|group_configuration| { &field_type,
group_configuration.content = content; &configuration_id,
}, |group_configuration| {
)? { group_configuration.content = content;
None => Ok(()), },
Some(changeset) => apply_change(&user_id, rev_manager, changeset).await, )?
} else {
let group_rev = GroupConfigurationRevision::new(field_id.clone(), field_type, content)?;
view_pad.write().await.insert_group(&field_id, &field_type, group_rev)?
};
if let Some(changeset) = changeset {
let _ = apply_change(&user_id, rev_manager, changeset).await?;
} }
Ok(())
}) })
} }
} }
@ -371,3 +409,17 @@ pub fn make_grid_setting(view_pad: &GridViewRevisionPad, field_revs: &[Arc<Field
group_configuration_by_field_id: groups_by_field_id, group_configuration_by_field_id: groups_by_field_id,
} }
} }
#[cfg(test)]
mod tests {
use lib_ot::core::TextDelta;
#[test]
fn test() {
let s1 = r#"[{"insert":"{\"view_id\":\"fTURELffPr\",\"grid_id\":\"fTURELffPr\",\"layout\":0,\"filters\":[],\"groups\":[]}"}]"#;
let _delta_1 = TextDelta::from_json(s1).unwrap();
let s2 = r#"[{"retain":195},{"insert":"{\\\"group_id\\\":\\\"wD9i\\\",\\\"visible\\\":true},{\\\"group_id\\\":\\\"xZtv\\\",\\\"visible\\\":true},{\\\"group_id\\\":\\\"tFV2\\\",\\\"visible\\\":true}"},{"retain":10}]"#;
let _delta_2 = TextDelta::from_json(s2).unwrap();
}
}

View File

@ -1,6 +1,6 @@
use crate::entities::{ use crate::entities::{
CreateFilterParams, CreateRowParams, DeleteFilterParams, GridFilterConfiguration, GridSettingChangesetParams, CreateFilterParams, CreateRowParams, DeleteFilterParams, GridFilterConfiguration, GridSettingPB, MoveGroupParams,
GridSettingPB, MoveGroupParams, RepeatedGridGroupPB, RowPB, RepeatedGridGroupPB, RowPB,
}; };
use crate::manager::GridUser; use crate::manager::GridUser;
use crate::services::grid_editor_task::GridServiceTaskScheduler; use crate::services::grid_editor_task::GridServiceTaskScheduler;
@ -122,7 +122,7 @@ impl GridViewManager {
pub(crate) async fn move_group(&self, params: MoveGroupParams) -> FlowyResult<()> { pub(crate) async fn move_group(&self, params: MoveGroupParams) -> FlowyResult<()> {
let view_editor = self.get_default_view_editor().await?; let view_editor = self.get_default_view_editor().await?;
let _s = view_editor.move_group(params).await?; let _ = view_editor.move_group(params).await?;
Ok(()) Ok(())
} }
@ -175,12 +175,11 @@ async fn make_view_editor(
row_delegate: Arc<dyn GridViewRowDelegate>, row_delegate: Arc<dyn GridViewRowDelegate>,
scheduler: Arc<dyn GridServiceTaskScheduler>, scheduler: Arc<dyn GridServiceTaskScheduler>,
) -> FlowyResult<GridViewRevisionEditor> { ) -> FlowyResult<GridViewRevisionEditor> {
tracing::trace!("Open view:{} editor", view_id);
let rev_manager = make_grid_view_rev_manager(user, view_id).await?; let rev_manager = make_grid_view_rev_manager(user, view_id).await?;
let user_id = user.user_id()?; let user_id = user.user_id()?;
let token = user.token()?; let token = user.token()?;
let view_id = view_id.to_owned(); let view_id = view_id.to_owned();
GridViewRevisionEditor::new( GridViewRevisionEditor::new(
&user_id, &user_id,
&token, &token,
@ -194,7 +193,6 @@ async fn make_view_editor(
} }
pub async fn make_grid_view_rev_manager(user: &Arc<dyn GridUser>, view_id: &str) -> FlowyResult<RevisionManager> { pub async fn make_grid_view_rev_manager(user: &Arc<dyn GridUser>, view_id: &str) -> FlowyResult<RevisionManager> {
tracing::trace!("Open view:{} editor", view_id);
let user_id = user.user_id()?; let user_id = user.user_id()?;
let pool = user.db_pool()?; let pool = user.db_pool()?;

View File

@ -1,5 +1,5 @@
use crate::services::group::Group; use crate::services::group::{default_group_configuration, Group};
use flowy_error::FlowyResult; use flowy_error::{FlowyError, FlowyResult};
use flowy_grid_data_model::revision::{ use flowy_grid_data_model::revision::{
FieldRevision, FieldTypeRevision, GroupConfigurationContent, GroupConfigurationRevision, GroupRecordRevision, FieldRevision, FieldTypeRevision, GroupConfigurationContent, GroupConfigurationRevision, GroupRecordRevision,
}; };
@ -9,7 +9,10 @@ use lib_infra::future::AFFuture;
use std::sync::Arc; use std::sync::Arc;
pub trait GroupConfigurationReader: Send + Sync + 'static { pub trait GroupConfigurationReader: Send + Sync + 'static {
fn get_group_configuration(&self, field_rev: Arc<FieldRevision>) -> AFFuture<Arc<GroupConfigurationRevision>>; fn get_group_configuration(
&self,
field_rev: Arc<FieldRevision>,
) -> AFFuture<Option<Arc<GroupConfigurationRevision>>>;
} }
pub trait GroupConfigurationWriter: Send + Sync + 'static { pub trait GroupConfigurationWriter: Send + Sync + 'static {
@ -39,7 +42,22 @@ where
reader: Arc<dyn GroupConfigurationReader>, reader: Arc<dyn GroupConfigurationReader>,
writer: Arc<dyn GroupConfigurationWriter>, writer: Arc<dyn GroupConfigurationWriter>,
) -> FlowyResult<Self> { ) -> FlowyResult<Self> {
let configuration_rev = reader.get_group_configuration(field_rev.clone()).await; let configuration_rev = match reader.get_group_configuration(field_rev.clone()).await {
None => {
let default_group_configuration = default_group_configuration(&field_rev);
writer
.save_group_configuration(
&field_rev.id,
field_rev.ty,
&default_group_configuration.id,
default_group_configuration.content.clone(),
)
.await?;
Arc::new(default_group_configuration)
}
Some(configuration) => configuration,
};
let configuration_id = configuration_rev.id.clone(); let configuration_id = configuration_rev.id.clone();
let configuration = C::from_configuration_content(&configuration_rev.content)?; let configuration = C::from_configuration_content(&configuration_rev.content)?;
Ok(Self { Ok(Self {
@ -63,6 +81,8 @@ where
let (group_revs, groups) = merge_groups(self.configuration.get_groups(), groups); let (group_revs, groups) = merge_groups(self.configuration.get_groups(), groups);
self.configuration.set_groups(group_revs); self.configuration.set_groups(group_revs);
let _ = self.save_configuration().await?; let _ = self.save_configuration().await?;
tracing::trace!("merge new groups: {}", groups.len());
groups.into_iter().for_each(|group| { groups.into_iter().for_each(|group| {
self.groups_map.insert(group.id.clone(), group); self.groups_map.insert(group.id.clone(), group);
}); });
@ -97,8 +117,25 @@ where
self.groups_map.get_mut(group_id) self.groups_map.get_mut(group_id)
} }
pub(crate) fn get_group(&mut self, group_id: &str) -> Option<&Group> { pub(crate) fn move_group(&mut self, from_group_id: &str, to_group_id: &str) -> FlowyResult<()> {
self.groups_map.get(group_id) let from_group_index = self.groups_map.get_index_of(from_group_id);
let to_group_index = self.groups_map.get_index_of(to_group_id);
match (from_group_index, to_group_index) {
(Some(from_index), Some(to_index)) => {
self.groups_map.swap_indices(from_index, to_index);
self.configuration.swap_group(from_group_id, to_group_id);
Ok(())
}
_ => Err(FlowyError::out_of_bounds()),
}
}
// Returns the index and group specified by the group_id
pub(crate) fn get_group(&self, group_id: &str) -> Option<(usize, &Group)> {
match (self.groups_map.get_index_of(group_id), self.groups_map.get(group_id)) {
(Some(index), Some(group)) => Some((index, group)),
_ => None,
}
} }
pub async fn save_configuration(&self) -> FlowyResult<()> { pub async fn save_configuration(&self) -> FlowyResult<()> {
@ -111,17 +148,17 @@ where
} }
} }
impl<T> GroupConfigurationReader for Arc<T> // impl<T> GroupConfigurationReader for Arc<T>
where // where
T: GroupConfigurationReader, // T: GroupConfigurationReader,
{ // {
fn get_group_configuration(&self, field_rev: Arc<FieldRevision>) -> AFFuture<Arc<GroupConfigurationRevision>> { // fn get_group_configuration(&self, field_rev: Arc<FieldRevision>) -> AFFuture<Arc<GroupConfigurationRevision>> {
(**self).get_group_configuration(field_rev) // (**self).get_group_configuration(field_rev)
} // }
} // }
fn merge_groups(old_group_revs: &[GroupRecordRevision], groups: Vec<Group>) -> (Vec<GroupRecordRevision>, Vec<Group>) { fn merge_groups(old_group_revs: &[GroupRecordRevision], groups: Vec<Group>) -> (Vec<GroupRecordRevision>, Vec<Group>) {
// tracing::trace!("Merge group: old: {}, new: {}", old_group.len(), groups.len()); tracing::trace!("Merge group: old: {}, new: {}", old_group_revs.len(), groups.len());
if old_group_revs.is_empty() { if old_group_revs.is_empty() {
let new_groups = groups let new_groups = groups
.iter() .iter()

View File

@ -36,7 +36,9 @@ pub trait GroupControllerSharedOperation: Send + Sync {
// The field that is used for grouping the rows // The field that is used for grouping the rows
fn field_id(&self) -> &str; fn field_id(&self) -> &str;
fn groups(&self) -> Vec<Group>; fn groups(&self) -> Vec<Group>;
fn get_group(&self, group_id: &str) -> Option<(usize, Group)>;
fn fill_groups(&mut self, row_revs: &[Arc<RowRevision>], field_rev: &FieldRevision) -> FlowyResult<Vec<Group>>; fn fill_groups(&mut self, row_revs: &[Arc<RowRevision>], field_rev: &FieldRevision) -> FlowyResult<Vec<Group>>;
fn move_group(&mut self, from_group_id: &str, to_group_id: &str) -> FlowyResult<()>;
fn did_update_row( fn did_update_row(
&mut self, &mut self,
row_rev: &RowRevision, row_rev: &RowRevision,
@ -118,6 +120,11 @@ where
self.configuration.clone_groups() self.configuration.clone_groups()
} }
fn get_group(&self, group_id: &str) -> Option<(usize, Group)> {
let group = self.configuration.get_group(group_id)?;
Some((group.0, group.1.clone()))
}
fn fill_groups(&mut self, row_revs: &[Arc<RowRevision>], field_rev: &FieldRevision) -> FlowyResult<Vec<Group>> { fn fill_groups(&mut self, row_revs: &[Arc<RowRevision>], field_rev: &FieldRevision) -> FlowyResult<Vec<Group>> {
for row_rev in row_revs { for row_rev in row_revs {
if let Some(cell_rev) = row_rev.cells.get(&self.field_id) { if let Some(cell_rev) = row_rev.cells.get(&self.field_id) {
@ -156,6 +163,10 @@ where
Ok(groups) Ok(groups)
} }
fn move_group(&mut self, from_group_id: &str, to_group_id: &str) -> FlowyResult<()> {
self.configuration.move_group(from_group_id, to_group_id)
}
fn did_update_row( fn did_update_row(
&mut self, &mut self,
row_rev: &RowRevision, row_rev: &RowRevision,

View File

@ -71,10 +71,9 @@ impl GroupAction for MultiSelectGroupController {
impl GroupController for MultiSelectGroupController { impl GroupController for MultiSelectGroupController {
fn will_create_row(&mut self, row_rev: &mut RowRevision, field_rev: &FieldRevision, group_id: &str) { fn will_create_row(&mut self, row_rev: &mut RowRevision, field_rev: &FieldRevision, group_id: &str) {
let group: Option<&Group> = self.configuration.get_group(group_id); match self.configuration.get_group(group_id) {
match group {
None => tracing::warn!("Can not find the group: {}", group_id), None => tracing::warn!("Can not find the group: {}", group_id),
Some(group) => { Some((_, group)) => {
let cell_rev = insert_select_option_cell(group.id.clone(), field_rev); let cell_rev = insert_select_option_cell(group.id.clone(), field_rev);
row_rev.cells.insert(field_rev.id.clone(), cell_rev); row_rev.cells.insert(field_rev.id.clone(), cell_rev);
} }

View File

@ -43,6 +43,14 @@ impl GroupService {
} }
} }
pub(crate) async fn get_group(&self, group_id: &str) -> Option<(usize, Group)> {
if let Some(group_controller) = self.group_controller.as_ref() {
group_controller.read().await.get_group(group_id)
} else {
None
}
}
pub(crate) async fn load_groups( pub(crate) async fn load_groups(
&mut self, &mut self,
field_revs: &[Arc<FieldRevision>], field_revs: &[Arc<FieldRevision>],
@ -164,9 +172,20 @@ impl GroupService {
} }
} }
#[tracing::instrument(level = "trace", skip_all)]
pub(crate) async fn move_group(&self, from_group_id: &str, to_group_id: &str) -> FlowyResult<()> {
match self.group_controller.as_ref() {
None => Ok(()),
Some(group_controller) => {
let _ = group_controller.write().await.move_group(from_group_id, to_group_id)?;
Ok(())
}
}
}
#[tracing::instrument(level = "trace", skip_all)] #[tracing::instrument(level = "trace", skip_all)]
async fn make_group_controller( async fn make_group_controller(
&mut self, &self,
field_type: &FieldType, field_type: &FieldType,
field_rev: &Arc<FieldRevision>, field_rev: &Arc<FieldRevision>,
) -> FlowyResult<Option<Arc<RwLock<dyn GroupController>>>> { ) -> FlowyResult<Option<Arc<RwLock<dyn GroupController>>>> {

View File

@ -4,11 +4,15 @@ use flowy_grid::services::cell::insert_select_option_cell;
use flowy_grid_data_model::revision::RowChangeset; use flowy_grid_data_model::revision::RowChangeset;
pub enum GroupScript { pub enum GroupScript {
AssertGroup { AssertGroupRowCount {
group_index: usize, group_index: usize,
row_count: usize, row_count: usize,
}, },
AssertGroupCount(usize), AssertGroupCount(usize),
AssertGroup {
group_index: usize,
expected_group: GroupPB,
},
AssertRow { AssertRow {
group_index: usize, group_index: usize,
row_index: usize, row_index: usize,
@ -56,7 +60,7 @@ impl GridGroupTest {
pub async fn run_script(&mut self, script: GroupScript) { pub async fn run_script(&mut self, script: GroupScript) {
match script { match script {
GroupScript::AssertGroup { group_index, row_count } => { GroupScript::AssertGroupRowCount { group_index, row_count } => {
assert_eq!(row_count, self.group_at_index(group_index).await.rows.len()); assert_eq!(row_count, self.group_at_index(group_index).await.rows.len());
} }
GroupScript::AssertGroupCount(count) => { GroupScript::AssertGroupCount(count) => {
@ -142,6 +146,13 @@ impl GridGroupTest {
self.editor.move_group(params).await.unwrap(); self.editor.move_group(params).await.unwrap();
// //
} }
GroupScript::AssertGroup {
group_index,
expected_group: group_pb,
} => {
let group = self.group_at_index(group_index).await;
assert_eq!(group.group_id, group_pb.group_id);
}
} }
} }

View File

@ -6,15 +6,15 @@ async fn board_init_test() {
let mut test = GridGroupTest::new().await; let mut test = GridGroupTest::new().await;
let scripts = vec![ let scripts = vec![
AssertGroupCount(3), AssertGroupCount(3),
AssertGroup { AssertGroupRowCount {
group_index: 0, group_index: 0,
row_count: 2, row_count: 2,
}, },
AssertGroup { AssertGroupRowCount {
group_index: 1, group_index: 1,
row_count: 2, row_count: 2,
}, },
AssertGroup { AssertGroupRowCount {
group_index: 2, group_index: 2,
row_count: 1, row_count: 1,
}, },
@ -34,7 +34,7 @@ async fn board_move_row_test() {
to_group_index: 0, to_group_index: 0,
to_row_index: 1, to_row_index: 1,
}, },
AssertGroup { AssertGroupRowCount {
group_index: 0, group_index: 0,
row_count: 2, row_count: 2,
}, },
@ -58,11 +58,11 @@ async fn board_move_row_to_other_group_test() {
to_group_index: 1, to_group_index: 1,
to_row_index: 1, to_row_index: 1,
}, },
AssertGroup { AssertGroupRowCount {
group_index: 0, group_index: 0,
row_count: 1, row_count: 1,
}, },
AssertGroup { AssertGroupRowCount {
group_index: 1, group_index: 1,
row_count: 3, row_count: 3,
}, },
@ -106,13 +106,13 @@ async fn board_create_row_test() {
let mut test = GridGroupTest::new().await; let mut test = GridGroupTest::new().await;
let scripts = vec![ let scripts = vec![
CreateRow { group_index: 0 }, CreateRow { group_index: 0 },
AssertGroup { AssertGroupRowCount {
group_index: 0, group_index: 0,
row_count: 3, row_count: 3,
}, },
CreateRow { group_index: 1 }, CreateRow { group_index: 1 },
CreateRow { group_index: 1 }, CreateRow { group_index: 1 },
AssertGroup { AssertGroupRowCount {
group_index: 1, group_index: 1,
row_count: 4, row_count: 4,
}, },
@ -128,7 +128,7 @@ async fn board_delete_row_test() {
group_index: 0, group_index: 0,
row_index: 0, row_index: 0,
}, },
AssertGroup { AssertGroupRowCount {
group_index: 0, group_index: 0,
row_count: 1, row_count: 1,
}, },
@ -148,7 +148,7 @@ async fn board_delete_all_row_test() {
group_index: 0, group_index: 0,
row_index: 0, row_index: 0,
}, },
AssertGroup { AssertGroupRowCount {
group_index: 0, group_index: 0,
row_count: 0, row_count: 0,
}, },
@ -166,11 +166,11 @@ async fn board_update_row_test() {
row_index: 0, row_index: 0,
to_group_index: 1, to_group_index: 1,
}, },
AssertGroup { AssertGroupRowCount {
group_index: 0, group_index: 0,
row_count: 1, row_count: 1,
}, },
AssertGroup { AssertGroupRowCount {
group_index: 1, group_index: 1,
row_count: 3, row_count: 3,
}, },
@ -188,14 +188,36 @@ async fn board_reorder_group_test() {
row_index: 0, row_index: 0,
to_group_index: 1, to_group_index: 1,
}, },
AssertGroup { AssertGroupRowCount {
group_index: 0, group_index: 0,
row_count: 1, row_count: 1,
}, },
AssertGroup { AssertGroupRowCount {
group_index: 1, group_index: 1,
row_count: 3, row_count: 3,
}, },
]; ];
test.run_scripts(scripts).await; test.run_scripts(scripts).await;
} }
#[tokio::test]
async fn board_move_group_test() {
let mut test = GridGroupTest::new().await;
let group_0 = test.group_at_index(0).await;
let group_1 = test.group_at_index(1).await;
let scripts = vec![
MoveGroup {
from_group_index: 0,
to_group_index: 1,
},
AssertGroup {
group_index: 0,
expected_group: group_1,
},
AssertGroup {
group_index: 1,
expected_group: group_0,
},
];
test.run_scripts(scripts).await;
}

View File

@ -74,7 +74,7 @@ fn crate_log_filter(level: String) -> String {
filters.push(format!("lib_ot={}", level)); filters.push(format!("lib_ot={}", level));
filters.push(format!("lib_ws={}", level)); filters.push(format!("lib_ws={}", level));
filters.push(format!("lib_infra={}", level)); filters.push(format!("lib_infra={}", level));
// filters.push(format!("flowy_sync={}", 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!("lib_dispatch={}", level));

View File

@ -125,6 +125,9 @@ pub enum ErrorCode {
#[display(fmt = "Invalid data")] #[display(fmt = "Invalid data")]
InvalidData = 1000, InvalidData = 1000,
#[display(fmt = "Out of bounds")]
OutOfBounds = 10001,
} }
impl ErrorCode { impl ErrorCode {

View File

@ -49,7 +49,7 @@ where
.get_mut(field_id) .get_mut(field_id)
.and_then(|object_rev_map| object_rev_map.get_mut(field_type)); .and_then(|object_rev_map| object_rev_map.get_mut(field_type));
if value.is_none() { if value.is_none() {
tracing::warn!("Can't find the {:?} with", std::any::type_name::<T>()); tracing::warn!("[Configuration] Can't find the {:?} with", std::any::type_name::<T>());
} }
value value
} }

View File

@ -1,11 +1,7 @@
use crate::revision::{ use crate::revision::{FilterConfiguration, GroupConfiguration};
FieldRevision, FieldTypeRevision, FilterConfiguration, FilterConfigurationRevision, FilterConfigurationsByFieldId,
GroupConfiguration, GroupConfigurationRevision, GroupConfigurationsByFieldId,
};
use nanoid::nanoid; use nanoid::nanoid;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_repr::*; use serde_repr::*;
use std::sync::Arc;
#[allow(dead_code)] #[allow(dead_code)]
pub fn gen_grid_view_id() -> String { pub fn gen_grid_view_id() -> String {
@ -40,15 +36,15 @@ pub struct GridViewRevision {
pub layout: LayoutRevision, pub layout: LayoutRevision,
#[serde(default)]
pub filters: FilterConfiguration, pub filters: FilterConfiguration,
#[serde(default)] #[serde(default)]
pub groups: GroupConfiguration, pub groups: GroupConfiguration,
// // For the moment, we just use the order returned from the GridRevision
// For the moment, we just use the order returned from the GridRevision // #[allow(dead_code)]
#[allow(dead_code)] // #[serde(skip, rename = "rows")]
#[serde(skip, rename = "row")] // pub row_orders: Vec<RowOrderRevision>,
pub row_orders: Vec<RowOrderRevision>,
} }
impl GridViewRevision { impl GridViewRevision {
@ -59,78 +55,33 @@ impl GridViewRevision {
layout: Default::default(), layout: Default::default(),
filters: Default::default(), filters: Default::default(),
groups: Default::default(), groups: Default::default(),
row_orders: vec![], // row_orders: vec![],
} }
} }
pub fn get_all_groups(&self, field_revs: &[Arc<FieldRevision>]) -> Option<GroupConfigurationsByFieldId> {
self.groups.get_all_objects(field_revs)
}
pub fn get_groups(
&self,
field_id: &str,
field_type_rev: &FieldTypeRevision,
) -> Option<Arc<GroupConfigurationRevision>> {
let mut groups = self.groups.get_objects(field_id, field_type_rev)?;
if groups.is_empty() {
debug_assert_eq!(groups.len(), 1);
Some(groups.pop().unwrap())
} else {
None
}
}
pub fn get_mut_groups(
&mut self,
field_id: &str,
field_type: &FieldTypeRevision,
) -> Option<&mut Vec<Arc<GroupConfigurationRevision>>> {
self.groups.get_mut_objects(field_id, field_type)
}
pub fn insert_group(
&mut self,
field_id: &str,
field_type: &FieldTypeRevision,
group_rev: GroupConfigurationRevision,
) {
// only one group can be set
self.groups.remove_all();
self.groups.insert_object(field_id, field_type, group_rev);
}
pub fn get_all_filters(&self, field_revs: &[Arc<FieldRevision>]) -> Option<FilterConfigurationsByFieldId> {
self.filters.get_all_objects(field_revs)
}
pub fn get_filters(
&self,
field_id: &str,
field_type_rev: &FieldTypeRevision,
) -> Option<Vec<Arc<FilterConfigurationRevision>>> {
self.filters.get_objects(field_id, field_type_rev)
}
pub fn get_mut_filters(
&mut self,
field_id: &str,
field_type: &FieldTypeRevision,
) -> Option<&mut Vec<Arc<FilterConfigurationRevision>>> {
self.filters.get_mut_objects(field_id, field_type)
}
pub fn insert_filter(
&mut self,
field_id: &str,
field_type: &FieldTypeRevision,
filter_rev: FilterConfigurationRevision,
) {
self.filters.insert_object(field_id, field_type, filter_rev);
}
} }
#[derive(Debug, Clone, Default, Serialize, Deserialize)] #[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct RowOrderRevision { pub struct RowOrderRevision {
pub row_id: String, pub row_id: String,
} }
#[cfg(test)]
mod tests {
use crate::revision::GridViewRevision;
#[test]
fn grid_view_revision_serde_test() {
let grid_view_revision = GridViewRevision {
view_id: "1".to_string(),
grid_id: "1".to_string(),
layout: Default::default(),
filters: Default::default(),
groups: Default::default(),
};
let s = serde_json::to_string(&grid_view_revision).unwrap();
assert_eq!(
s,
r#"{"view_id":"1","grid_id":"1","layout":0,"filters":[],"groups":[]}"#
);
}
}

View File

@ -12,8 +12,23 @@ pub trait GroupConfigurationContent: Sized {
&[] &[]
} }
fn mut_groups(&mut self) -> &mut Vec<GroupRecordRevision> {
todo!()
}
fn set_groups(&mut self, _new_groups: Vec<GroupRecordRevision>) {} fn set_groups(&mut self, _new_groups: Vec<GroupRecordRevision>) {}
fn swap_group(&mut self, from_group_id: &str, to_group_id: &str) {
let from_index = self
.get_groups()
.iter()
.position(|group| group.group_id == from_group_id);
let to_index = self.get_groups().iter().position(|group| group.group_id == to_group_id);
if let (Some(from), Some(to)) = (from_index, to_index) {
self.mut_groups().swap(from, to);
}
}
fn with_mut_group<F>(&mut self, _group_id: &str, _f: F) fn with_mut_group<F>(&mut self, _group_id: &str, _f: F)
where where
F: FnOnce(&mut GroupRecordRevision), F: FnOnce(&mut GroupRecordRevision),
@ -120,6 +135,10 @@ impl GroupConfigurationContent for SelectOptionGroupConfigurationRevision {
&self.groups &self.groups
} }
fn mut_groups(&mut self) -> &mut Vec<GroupRecordRevision> {
&mut self.groups
}
fn set_groups(&mut self, new_groups: Vec<GroupRecordRevision>) { fn set_groups(&mut self, new_groups: Vec<GroupRecordRevision>) {
self.groups = new_groups; self.groups = new_groups;
} }

View File

@ -52,7 +52,26 @@ impl GridViewRevisionPad {
self.groups.get_all_objects(field_revs) self.groups.get_all_objects(field_revs)
} }
pub fn get_mut_group<F: FnOnce(&mut GroupConfigurationRevision)>( #[tracing::instrument(level = "trace", skip_all, err)]
pub fn insert_group(
&mut self,
field_id: &str,
field_type: &FieldTypeRevision,
group_rev: GroupConfigurationRevision,
) -> CollaborateResult<Option<GridViewRevisionChangeset>> {
self.modify(|view| {
view.groups.insert_object(field_id, field_type, group_rev);
Ok(Some(()))
})
}
#[tracing::instrument(level = "trace", skip_all)]
pub fn contains_group(&self, field_id: &str, field_type: &FieldTypeRevision) -> bool {
self.view.groups.get_objects(field_id, field_type).is_some()
}
#[tracing::instrument(level = "trace", skip_all, err)]
pub fn with_mut_group<F: FnOnce(&mut GroupConfigurationRevision)>(
&mut self, &mut self,
field_id: &str, field_id: &str,
field_type: &FieldTypeRevision, field_type: &FieldTypeRevision,
@ -147,6 +166,8 @@ impl GridViewRevisionPad {
None => Ok(None), None => Ok(None),
Some(delta) => { Some(delta) => {
self.delta = self.delta.compose(&delta)?; self.delta = self.delta.compose(&delta)?;
tracing::info!("GridView: {:?}", delta);
let md5 = md5(&self.delta.json_bytes()); let md5 = md5(&self.delta.json_bytes());
Ok(Some(GridViewRevisionChangeset { delta, md5 })) Ok(Some(GridViewRevisionChangeset { delta, md5 }))
} }