chore: reader and writter for group configuration

This commit is contained in:
appflowy 2022-08-20 15:40:13 +08:00
parent 5fac1f044a
commit 91b2917d60
29 changed files with 1015 additions and 895 deletions

View File

@ -2,7 +2,6 @@ use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
use flowy_error::ErrorCode;
use flowy_grid_data_model::parser::NotEmptyStr;
use flowy_grid_data_model::revision::{FieldRevision, FieldTypeRevision};
use flowy_sync::entities::grid::FieldChangesetParams;
use serde_repr::*;
use std::sync::Arc;

View File

@ -6,7 +6,6 @@ mod grid_entities;
mod group_entities;
mod row_entities;
mod setting_entities;
mod sort_entities;
pub use block_entities::*;
pub use cell_entities::*;
@ -16,4 +15,3 @@ pub use grid_entities::*;
pub use group_entities::*;
pub use row_entities::*;
pub use setting_entities::*;
pub use sort_entities::*;

View File

@ -1,13 +1,12 @@
use crate::entities::{
CreatGroupParams, CreateFilterParams, CreateGridFilterPayloadPB, CreateGridGroupPayloadPB, CreateGridSortPayloadPB,
CreateSortParams, DeleteFilterParams, DeleteFilterPayloadPB, DeleteGroupParams, DeleteGroupPayloadPB,
RepeatedGridConfigurationFilterPB, RepeatedGridGroupConfigurationPB, RepeatedGridSortPB,
CreatGroupParams, CreateFilterParams, CreateGridFilterPayloadPB, CreateGridGroupPayloadPB, DeleteFilterParams,
DeleteFilterPayloadPB, DeleteGroupParams, DeleteGroupPayloadPB, RepeatedGridConfigurationFilterPB,
RepeatedGridGroupConfigurationPB,
};
use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
use flowy_error::ErrorCode;
use flowy_grid_data_model::parser::NotEmptyStr;
use flowy_grid_data_model::revision::LayoutRevision;
use flowy_sync::entities::grid::GridSettingChangesetParams;
use std::collections::HashMap;
use std::convert::TryInto;
use strum::IntoEnumIterator;
@ -27,9 +26,6 @@ pub struct GridSettingPB {
#[pb(index = 4)]
pub group_configuration_by_field_id: HashMap<String, RepeatedGridGroupConfigurationPB>,
#[pb(index = 5)]
pub sorts_by_field_id: HashMap<String, RepeatedGridSortPB>,
}
#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
@ -99,12 +95,6 @@ pub struct GridSettingChangesetPayloadPB {
#[pb(index = 6, one_of)]
pub delete_group: Option<DeleteGroupPayloadPB>,
#[pb(index = 7, one_of)]
pub insert_sort: Option<CreateGridSortPayloadPB>,
#[pb(index = 8, one_of)]
pub delete_sort: Option<String>,
}
impl TryInto<GridSettingChangesetParams> for GridSettingChangesetPayloadPB {
@ -135,16 +125,6 @@ impl TryInto<GridSettingChangesetParams> for GridSettingChangesetPayloadPB {
None => None,
};
let insert_sort = match self.insert_sort {
None => None,
Some(payload) => Some(payload.try_into()?),
};
let delete_sort = match self.delete_sort {
None => None,
Some(filter_id) => Some(NotEmptyStr::parse(filter_id).map_err(|_| ErrorCode::FieldIdIsEmpty)?.0),
};
Ok(GridSettingChangesetParams {
grid_id: view_id,
layout_type: self.layout_type.into(),
@ -152,8 +132,6 @@ impl TryInto<GridSettingChangesetParams> for GridSettingChangesetPayloadPB {
delete_filter,
insert_group,
delete_group,
insert_sort,
delete_sort,
})
}
}
@ -165,8 +143,6 @@ pub struct GridSettingChangesetParams {
pub delete_filter: Option<DeleteFilterParams>,
pub insert_group: Option<CreatGroupParams>,
pub delete_group: Option<DeleteGroupParams>,
pub insert_sort: Option<CreateSortParams>,
pub delete_sort: Option<String>,
}
impl GridSettingChangesetParams {

View File

@ -1,68 +0,0 @@
use flowy_derive::ProtoBuf;
use flowy_error::ErrorCode;
use flowy_grid_data_model::parser::NotEmptyStr;
use flowy_grid_data_model::revision::SortConfigurationRevision;
use std::convert::TryInto;
use std::sync::Arc;
#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
pub struct GridSort {
#[pb(index = 1)]
pub id: String,
#[pb(index = 2, one_of)]
pub field_id: Option<String>,
}
impl std::convert::From<&SortConfigurationRevision> for GridSort {
fn from(rev: &SortConfigurationRevision) -> Self {
GridSort {
id: rev.id.clone(),
field_id: rev.field_id.clone(),
}
}
}
#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
pub struct RepeatedGridSortPB {
#[pb(index = 1)]
pub items: Vec<GridSort>,
}
impl std::convert::From<Vec<Arc<SortConfigurationRevision>>> for RepeatedGridSortPB {
fn from(revs: Vec<Arc<SortConfigurationRevision>>) -> Self {
RepeatedGridSortPB {
items: revs.into_iter().map(|rev| rev.as_ref().into()).collect(),
}
}
}
impl std::convert::From<Vec<GridSort>> for RepeatedGridSortPB {
fn from(items: Vec<GridSort>) -> Self {
Self { items }
}
}
#[derive(ProtoBuf, Debug, Default, Clone)]
pub struct CreateGridSortPayloadPB {
#[pb(index = 1, one_of)]
pub field_id: Option<String>,
}
impl TryInto<CreateSortParams> for CreateGridSortPayloadPB {
type Error = ErrorCode;
fn try_into(self) -> Result<CreateSortParams, Self::Error> {
let field_id = match self.field_id {
None => None,
Some(field_id) => Some(NotEmptyStr::parse(field_id).map_err(|_| ErrorCode::FieldIdIsEmpty)?.0),
};
Ok(CreateSortParams { field_id })
}
}
pub struct CreateSortParams {
pub field_id: Option<String>,
}

View File

@ -10,7 +10,6 @@ use crate::services::field::{
use crate::services::row::make_row_from_row_rev;
use flowy_error::{ErrorCode, FlowyError, FlowyResult};
use flowy_grid_data_model::revision::FieldRevision;
use flowy_sync::entities::grid::{FieldChangesetParams, GridSettingChangesetParams};
use lib_dispatch::prelude::{data_result, AppData, Data, DataResult};
use std::sync::Arc;

View File

@ -4,7 +4,7 @@
#![allow(unused_imports)]
#![allow(unused_results)]
use crate::dart_notification::{send_dart_notification, GridNotification};
use crate::entities::{FieldType, GridBlockChangesetPB};
use crate::entities::{FieldType, GridBlockChangesetPB, GridSettingChangesetParams};
use crate::services::block_manager::GridBlockManager;
use crate::services::cell::{AnyCellData, CellFilterOperation};
use crate::services::field::{
@ -20,7 +20,6 @@ use crate::services::tasks::{FilterTaskContext, Task, TaskContent};
use flowy_error::FlowyResult;
use flowy_grid_data_model::revision::{CellRevision, FieldId, FieldRevision, RowRevision};
use flowy_sync::client_grid::GridRevisionPad;
use flowy_sync::entities::grid::GridSettingChangesetParams;
use rayon::prelude::*;
use std::collections::HashMap;
use std::sync::Arc;

View File

@ -15,7 +15,6 @@ use flowy_error::{ErrorCode, FlowyError, FlowyResult};
use flowy_grid_data_model::revision::*;
use flowy_revision::{RevisionCloudService, RevisionCompactor, RevisionManager, RevisionObjectBuilder};
use flowy_sync::client_grid::{GridRevisionChangeset, GridRevisionPad, JsonDeserializer};
use flowy_sync::entities::grid::{FieldChangesetParams, GridSettingChangesetParams};
use flowy_sync::entities::revision::Revision;
use flowy_sync::errors::CollaborateResult;
use flowy_sync::util::make_text_delta_from_revisions;
@ -101,14 +100,14 @@ impl GridRevisionEditor {
grid_id,
name: Some(field.name),
desc: Some(field.desc),
field_type: Some(field.field_type.into()),
field_type: Some(field.field_type.clone().into()),
frozen: Some(field.frozen),
visibility: Some(field.visibility),
width: Some(field.width),
type_option_data: Some(type_option_data),
};
let _ = self.update_field_rev(changeset, field.field_type.clone()).await?;
let _ = self.update_field_rev(changeset, field.field_type).await?;
let _ = self.notify_did_update_grid_field(&field_id).await?;
} else {
let _ = self
@ -262,60 +261,59 @@ impl GridRevisionEditor {
}
async fn update_field_rev(&self, params: FieldChangesetParams, field_type: FieldType) -> FlowyResult<()> {
let _ = self
.modify(|grid| {
let deserializer = TypeOptionJsonDeserializer(field_type);
self.modify(|grid| {
let deserializer = TypeOptionJsonDeserializer(field_type);
let changeset = grid.modify_field(&params.field_id, |field| {
let mut is_changed = None;
if let Some(name) = changeset.name {
field.name = name;
is_changed = Some(())
}
let changeset = grid.modify_field(&params.field_id, |field| {
let mut is_changed = None;
if let Some(name) = params.name {
field.name = name;
is_changed = Some(())
}
if let Some(desc) = changeset.desc {
field.desc = desc;
is_changed = Some(())
}
if let Some(desc) = params.desc {
field.desc = desc;
is_changed = Some(())
}
if let Some(field_type) = changeset.field_type {
field.ty = field_type;
is_changed = Some(())
}
if let Some(field_type) = params.field_type {
field.ty = field_type;
is_changed = Some(())
}
if let Some(frozen) = changeset.frozen {
field.frozen = frozen;
is_changed = Some(())
}
if let Some(frozen) = params.frozen {
field.frozen = frozen;
is_changed = Some(())
}
if let Some(visibility) = changeset.visibility {
field.visibility = visibility;
is_changed = Some(())
}
if let Some(visibility) = params.visibility {
field.visibility = visibility;
is_changed = Some(())
}
if let Some(width) = changeset.width {
field.width = width;
is_changed = Some(())
}
if let Some(width) = params.width {
field.width = width;
is_changed = Some(())
}
if let Some(type_option_data) = changeset.type_option_data {
match deserializer.deserialize(type_option_data) {
Ok(json_str) => {
let field_type = field.ty;
field.insert_type_option_str(&field_type, json_str);
is_changed = Some(())
}
Err(err) => {
tracing::error!("Deserialize data to type option json failed: {}", err);
}
if let Some(type_option_data) = params.type_option_data {
match deserializer.deserialize(type_option_data) {
Ok(json_str) => {
let field_type = field.ty;
field.insert_type_option_str(&field_type, json_str);
is_changed = Some(())
}
Err(err) => {
tracing::error!("Deserialize data to type option json failed: {}", err);
}
}
}
Ok(is_changed)
})?;
Ok(changeset)
})
.await?;
Ok(is_changed)
})?;
Ok(changeset)
})
.await
}
pub async fn create_block(&self, block_meta_rev: GridBlockMetaRevision) -> FlowyResult<()> {

View File

@ -1,18 +1,23 @@
use crate::dart_notification::{send_dart_notification, GridNotification};
use crate::entities::{
CreateRowParams, GridFilterConfiguration, GridSettingPB, GroupPB, GroupRowsChangesetPB, InsertedRowPB, RowPB,
CreateRowParams, GridFilterConfiguration, GridLayout, GridLayoutPB, GridSettingChangesetParams, GridSettingPB,
GroupPB, GroupRowsChangesetPB, InsertedRowPB, RepeatedGridConfigurationFilterPB, RepeatedGridGroupConfigurationPB,
RowPB,
};
use crate::services::grid_editor_task::GridServiceTaskScheduler;
use crate::services::grid_view_manager::{GridViewFieldDelegate, GridViewRowDelegate};
use crate::services::group::{default_group_configuration, GroupConfigurationDelegate, GroupService};
use crate::services::setting::make_grid_setting;
use crate::services::group::{
default_group_configuration, GroupConfigurationReader, GroupConfigurationWriter, GroupService,
};
use flowy_error::{FlowyError, FlowyResult};
use flowy_grid_data_model::revision::{FieldRevision, GroupConfigurationRevision, RowChangeset, RowRevision};
use flowy_grid_data_model::revision::{
FieldRevision, FieldTypeRevision, GroupConfigurationRevision, RowChangeset, RowRevision,
};
use flowy_revision::{RevisionCloudService, RevisionManager, RevisionObjectBuilder};
use flowy_sync::client_grid::{GridViewRevisionChangeset, GridViewRevisionPad};
use flowy_sync::entities::grid::GridSettingChangesetParams;
use flowy_sync::entities::revision::Revision;
use lib_infra::future::{wrap_future, AFFuture, FutureResult};
use std::collections::HashMap;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use tokio::sync::RwLock;
@ -46,7 +51,14 @@ impl GridViewRevisionEditor {
let view_revision_pad = rev_manager.load::<GridViewRevisionPadBuilder>(Some(cloud)).await?;
let pad = Arc::new(RwLock::new(view_revision_pad));
let rev_manager = Arc::new(rev_manager);
let group_service = GroupService::new(Box::new(pad.clone())).await;
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(configuration_reader, configuration_writer).await;
let user_id = user_id.to_owned();
let did_load_group = AtomicBool::new(false);
Ok(Self {
@ -167,7 +179,7 @@ impl GridViewRevisionEditor {
pub(crate) async fn get_setting(&self) -> GridSettingPB {
let field_revs = self.field_delegate.get_field_revs().await;
let grid_setting = make_grid_setting(self.pad.read().await.get_setting_rev(), &field_revs);
let grid_setting = make_grid_setting(&*self.pad.read().await, &field_revs);
grid_setting
}
@ -177,13 +189,9 @@ impl GridViewRevisionEditor {
todo!()
}
// pub(crate) async fn insert_group(&self, params: CreateGroupParams) -> FlowyResult<()> {
//
// }
pub(crate) async fn get_filters(&self) -> Vec<GridFilterConfiguration> {
let field_revs = self.field_delegate.get_field_revs().await;
match self.pad.read().await.get_setting_rev().get_all_filters(&field_revs) {
match self.pad.read().await.get_all_filters(&field_revs) {
None => vec![],
Some(filters) => filters
.into_values()
@ -207,28 +215,24 @@ impl GridViewRevisionEditor {
match f(&mut *write_guard)? {
None => {}
Some(change) => {
let _ = self.apply_change(change).await?;
let _ = apply_change(&self.user_id, self.rev_manager.clone(), change).await?;
}
}
Ok(())
}
}
async fn apply_change(&self, change: GridViewRevisionChangeset) -> FlowyResult<()> {
let GridViewRevisionChangeset { delta, md5 } = change;
let user_id = self.user_id.clone();
let (base_rev_id, rev_id) = self.rev_manager.next_rev_id_pair();
let delta_data = delta.json_bytes();
let revision = Revision::new(
&self.rev_manager.object_id,
base_rev_id,
rev_id,
delta_data,
&user_id,
md5,
);
let _ = self.rev_manager.add_local_revision(&revision).await?;
Ok(())
}
async fn apply_change(
user_id: &str,
rev_manager: Arc<RevisionManager>,
change: GridViewRevisionChangeset,
) -> FlowyResult<()> {
let GridViewRevisionChangeset { delta, md5 } = change;
let (base_rev_id, rev_id) = rev_manager.next_rev_id_pair();
let delta_data = delta.json_bytes();
let revision = Revision::new(&rev_manager.object_id, base_rev_id, rev_id, delta_data, &user_id, md5);
let _ = rev_manager.add_local_revision(&revision).await?;
Ok(())
}
struct GridViewRevisionCloudService {
@ -253,19 +257,82 @@ impl RevisionObjectBuilder for GridViewRevisionPadBuilder {
}
}
impl GroupConfigurationDelegate for Arc<RwLock<GridViewRevisionPad>> {
fn get_group_configuration(&self, field_rev: Arc<FieldRevision>) -> AFFuture<GroupConfigurationRevision> {
let view_pad = self.clone();
struct GroupConfigurationReaderImpl(Arc<RwLock<GridViewRevisionPad>>);
impl GroupConfigurationReader for GroupConfigurationReaderImpl {
fn get_group_configuration(&self, field_rev: Arc<FieldRevision>) -> AFFuture<Arc<GroupConfigurationRevision>> {
let view_pad = self.0.clone();
wrap_future(async move {
let grid_pad = view_pad.read().await;
let configurations = grid_pad.get_groups(&field_rev.id, &field_rev.ty);
let view_pad = view_pad.read().await;
let configurations = view_pad.get_groups(&field_rev.id, &field_rev.ty);
match configurations {
None => default_group_configuration(&field_rev),
Some(mut configurations) => {
assert_eq!(configurations.len(), 1);
(&*configurations.pop().unwrap()).clone()
None => {
let default_configuration = default_group_configuration(&field_rev);
Arc::new(default_configuration)
}
Some(configuration) => configuration,
}
})
}
}
struct GroupConfigurationWriterImpl {
user_id: String,
rev_manager: Arc<RevisionManager>,
view_pad: Arc<RwLock<GridViewRevisionPad>>,
}
impl GroupConfigurationWriter for GroupConfigurationWriterImpl {
fn save_group_configuration(
&self,
field_id: &str,
field_type: FieldTypeRevision,
configuration: Arc<GroupConfigurationRevision>,
) -> AFFuture<FlowyResult<()>> {
let user_id = self.user_id.clone();
let rev_manager = self.rev_manager.clone();
let view_pad = self.view_pad.clone();
let field_id = field_id.to_owned();
wrap_future(async move {
let configuration = (&*configuration).clone();
match view_pad
.write()
.await
.insert_group_configuration(&field_id, &field_type, configuration)?
{
None => Ok(()),
Some(changeset) => apply_change(&user_id, rev_manager, changeset).await,
}
})
}
}
pub fn make_grid_setting(view_pad: &GridViewRevisionPad, field_revs: &[Arc<FieldRevision>]) -> GridSettingPB {
let current_layout_type: GridLayout = view_pad.layout.clone().into();
let filters_by_field_id = view_pad
.get_all_filters(field_revs)
.map(|filters_by_field_id| {
filters_by_field_id
.into_iter()
.map(|(k, v)| (k, v.into()))
.collect::<HashMap<String, RepeatedGridConfigurationFilterPB>>()
})
.unwrap_or_default();
let groups_by_field_id = view_pad
.get_all_groups(field_revs)
.map(|groups_by_field_id| {
groups_by_field_id
.into_iter()
.map(|(k, v)| (k, v.into()))
.collect::<HashMap<String, RepeatedGridGroupConfigurationPB>>()
})
.unwrap_or_default();
GridSettingPB {
layouts: GridLayoutPB::all(),
current_layout_type,
filter_configuration_by_field_id: filters_by_field_id,
group_configuration_by_field_id: groups_by_field_id,
}
}

View File

@ -1,4 +1,6 @@
use crate::entities::{CreateRowParams, GridFilterConfiguration, GridSettingPB, RepeatedGridGroupPB, RowPB};
use crate::entities::{
CreateRowParams, GridFilterConfiguration, GridSettingChangesetParams, GridSettingPB, RepeatedGridGroupPB, RowPB,
};
use crate::manager::GridUser;
use crate::services::grid_editor_task::GridServiceTaskScheduler;
use crate::services::grid_view_editor::GridViewRevisionEditor;
@ -8,7 +10,6 @@ use flowy_error::FlowyResult;
use flowy_grid_data_model::revision::{FieldRevision, RowChangeset, RowRevision};
use flowy_revision::disk::SQLiteGridViewRevisionPersistence;
use flowy_revision::{RevisionCompactor, RevisionManager, RevisionPersistence, SQLiteRevisionSnapshotPersistence};
use flowy_sync::entities::grid::GridSettingChangesetParams;
use flowy_sync::entities::revision::Revision;
use flowy_sync::util::make_text_delta_from_revisions;
use lib_infra::future::AFFuture;

View File

@ -0,0 +1,23 @@
use crate::entities::GroupRowsChangesetPB;
use flowy_grid_data_model::revision::{FieldRevision, RowChangeset, RowRevision};
pub trait GroupAction: Send + Sync {
type CellDataType;
fn can_group(&self, content: &str, cell_data: &Self::CellDataType) -> bool;
fn add_row_if_match(&mut self, row_rev: &RowRevision, cell_data: &Self::CellDataType) -> Vec<GroupRowsChangesetPB>;
fn remove_row_if_match(
&mut self,
row_rev: &RowRevision,
cell_data: &Self::CellDataType,
) -> Vec<GroupRowsChangesetPB>;
fn move_row_if_match(
&mut self,
field_rev: &FieldRevision,
row_rev: &RowRevision,
row_changeset: &mut RowChangeset,
cell_data: &Self::CellDataType,
to_row_id: &str,
) -> Vec<GroupRowsChangesetPB>;
}

View File

@ -0,0 +1,76 @@
use flowy_error::FlowyResult;
use flowy_grid_data_model::revision::{
FieldRevision, FieldTypeRevision, GroupConfigurationContentSerde, GroupConfigurationRevision, GroupRecordRevision,
};
use lib_infra::future::AFFuture;
use std::sync::Arc;
pub trait GroupConfigurationReader: Send + Sync + 'static {
fn get_group_configuration(&self, field_rev: Arc<FieldRevision>) -> AFFuture<Arc<GroupConfigurationRevision>>;
}
pub trait GroupConfigurationWriter: Send + Sync + 'static {
fn save_group_configuration(
&self,
field_id: &str,
field_type: FieldTypeRevision,
configuration: Arc<GroupConfigurationRevision>,
) -> AFFuture<FlowyResult<()>>;
}
pub trait GroupConfigurationAction: Send + Sync {
fn group_records(&self) -> &[GroupRecordRevision];
fn save_groups(&self) -> FlowyResult<()>;
fn hide_group(&self, group_id: &str) -> FlowyResult<()>;
fn show_group(&self, group_id: &str) -> FlowyResult<()>;
}
pub struct GenericGroupConfiguration<C> {
field_rev: Arc<FieldRevision>,
reader: Arc<dyn GroupConfigurationReader>,
writer: Arc<dyn GroupConfigurationWriter>,
configuration: C,
}
impl<C> GenericGroupConfiguration<C>
where
C: GroupConfigurationContentSerde,
{
pub async fn new(
field_rev: Arc<FieldRevision>,
reader: Arc<dyn GroupConfigurationReader>,
writer: Arc<dyn GroupConfigurationWriter>,
) -> FlowyResult<Self> {
let configuration = reader.get_group_configuration(field_rev.clone()).await;
let configuration = C::from_configuration(&configuration.content)?;
Ok(Self {
field_rev,
reader,
writer,
configuration,
})
}
}
impl<T> GroupConfigurationReader for Arc<T>
where
T: GroupConfigurationReader,
{
fn get_group_configuration(&self, field_rev: Arc<FieldRevision>) -> AFFuture<Arc<GroupConfigurationRevision>> {
(**self).get_group_configuration(field_rev)
}
}
impl<T> GroupConfigurationWriter for Arc<T>
where
T: GroupConfigurationWriter,
{
fn save_group_configuration(
&self,
field_id: &str,
field_type: FieldTypeRevision,
configuration: Arc<GroupConfigurationRevision>,
) -> AFFuture<FlowyResult<()>> {
(**self).save_group_configuration(field_id, field_type, configuration)
}
}

View File

@ -1,20 +1,42 @@
use crate::entities::{CheckboxGroupConfigurationPB, GroupRowsChangesetPB};
use flowy_grid_data_model::revision::{FieldRevision, RowChangeset, RowRevision};
use crate::entities::GroupRowsChangesetPB;
use crate::services::field::{CheckboxCellData, CheckboxCellDataParser, CheckboxTypeOptionPB, CHECK, UNCHECK};
use crate::services::group::{GenericGroupController, Group, GroupController, GroupGenerator, Groupable};
use crate::services::group::action::GroupAction;
use crate::services::group::configuration::{GenericGroupConfiguration, GroupConfigurationAction};
use crate::services::group::entities::Group;
use crate::services::group::group_controller::{GenericGroupController, GroupController, GroupGenerator};
use flowy_error::FlowyResult;
use flowy_grid_data_model::revision::{
CheckboxGroupConfigurationRevision, FieldRevision, GroupRecordRevision, RowChangeset, RowRevision,
};
pub type CheckboxGroupController = GenericGroupController<
CheckboxGroupConfigurationPB,
CheckboxGroupConfigurationRevision,
CheckboxTypeOptionPB,
CheckboxGroupGenerator,
CheckboxCellDataParser,
>;
impl Groupable for CheckboxGroupController {
type CellDataType = CheckboxCellData;
pub type CheckboxGroupConfiguration = GenericGroupConfiguration<CheckboxGroupConfigurationRevision>;
impl GroupConfigurationAction for CheckboxGroupConfiguration {
fn group_records(&self) -> &[GroupRecordRevision] {
todo!()
}
fn save_groups(&self) -> FlowyResult<()> {
todo!()
}
fn hide_group(&self, group_id: &str) -> FlowyResult<()> {
todo!()
}
fn show_group(&self, group_id: &str) -> FlowyResult<()> {
todo!()
}
}
impl GroupAction for CheckboxGroupController {
type CellDataType = CheckboxCellData;
fn can_group(&self, _content: &str, _cell_data: &Self::CellDataType) -> bool {
false
}
@ -55,13 +77,13 @@ impl GroupController for CheckboxGroupController {
pub struct CheckboxGroupGenerator();
impl GroupGenerator for CheckboxGroupGenerator {
type ConfigurationType = CheckboxGroupConfigurationPB;
type ConfigurationType = CheckboxGroupConfiguration;
type TypeOptionType = CheckboxTypeOptionPB;
fn generate_groups(
field_id: &str,
_configuration: &Option<Self::ConfigurationType>,
_type_option: &Option<Self::TypeOptionType>,
configuration: &Self::ConfigurationType,
type_option: &Option<Self::TypeOptionType>,
) -> Vec<Group> {
let check_group = Group::new(
"true".to_string(),

View File

@ -1,7 +1,5 @@
mod checkbox_controller;
mod group_controller;
mod select_option_controller;
pub use checkbox_controller::*;
pub use group_controller::*;
pub use select_option_controller::*;

View File

@ -0,0 +1,6 @@
mod multi_select_controller;
mod single_select_controller;
mod util;
pub use multi_select_controller::*;
pub use single_select_controller::*;

View File

@ -0,0 +1,110 @@
use crate::entities::GroupRowsChangesetPB;
use crate::services::cell::insert_select_option_cell;
use crate::services::field::{MultiSelectTypeOptionPB, SelectOptionCellDataPB, SelectOptionCellDataParser};
use crate::services::group::action::GroupAction;
use crate::services::group::controller_impls::select_option_controller::util::*;
use crate::services::group::entities::Group;
use crate::services::group::group_controller::{GenericGroupController, GroupController, GroupGenerator};
use flowy_grid_data_model::revision::{
FieldRevision, RowChangeset, RowRevision, SelectOptionGroupConfigurationRevision,
};
// MultiSelect
pub type MultiSelectGroupController = GenericGroupController<
SelectOptionGroupConfigurationRevision,
MultiSelectTypeOptionPB,
MultiSelectGroupGenerator,
SelectOptionCellDataParser,
>;
impl GroupAction for MultiSelectGroupController {
type CellDataType = SelectOptionCellDataPB;
fn can_group(&self, content: &str, cell_data: &SelectOptionCellDataPB) -> bool {
cell_data.select_options.iter().any(|option| option.id == content)
}
fn add_row_if_match(&mut self, row_rev: &RowRevision, cell_data: &Self::CellDataType) -> Vec<GroupRowsChangesetPB> {
let mut changesets = vec![];
self.groups_map.iter_mut().for_each(|(_, group): (_, &mut Group)| {
add_row(group, &mut changesets, cell_data, row_rev);
});
changesets
}
fn remove_row_if_match(
&mut self,
row_rev: &RowRevision,
cell_data: &Self::CellDataType,
) -> Vec<GroupRowsChangesetPB> {
let mut changesets = vec![];
self.groups_map.iter_mut().for_each(|(_, group): (_, &mut Group)| {
remove_row(group, &mut changesets, cell_data, row_rev);
});
changesets
}
fn move_row_if_match(
&mut self,
field_rev: &FieldRevision,
row_rev: &RowRevision,
row_changeset: &mut RowChangeset,
cell_data: &Self::CellDataType,
to_row_id: &str,
) -> Vec<GroupRowsChangesetPB> {
let mut group_changeset = vec![];
self.groups_map.iter_mut().for_each(|(_, group): (_, &mut Group)| {
move_row(
group,
&mut group_changeset,
field_rev,
row_rev,
row_changeset,
cell_data,
to_row_id,
);
});
group_changeset
}
}
impl GroupController for MultiSelectGroupController {
fn will_create_row(&mut self, row_rev: &mut RowRevision, field_rev: &FieldRevision, group_id: &str) {
let group: Option<&Group> = self.groups_map.get(group_id);
match group {
None => tracing::warn!("Can not find the group: {}", group_id),
Some(group) => {
let cell_rev = insert_select_option_cell(group.id.clone(), field_rev);
row_rev.cells.insert(field_rev.id.clone(), cell_rev);
}
}
}
}
pub struct MultiSelectGroupGenerator();
impl GroupGenerator for MultiSelectGroupGenerator {
type ConfigurationType = SelectOptionGroupConfiguration;
type TypeOptionType = MultiSelectTypeOptionPB;
fn generate_groups(
field_id: &str,
configuration: &Self::ConfigurationType,
type_option: &Option<Self::TypeOptionType>,
) -> Vec<Group> {
match type_option {
None => vec![],
Some(type_option) => type_option
.options
.iter()
.map(|option| {
Group::new(
option.id.clone(),
field_id.to_owned(),
option.name.clone(),
option.id.clone(),
)
})
.collect(),
}
}
}

View File

@ -0,0 +1,111 @@
use crate::entities::{GroupRowsChangesetPB, RowPB};
use crate::services::cell::insert_select_option_cell;
use crate::services::field::{SelectOptionCellDataPB, SelectOptionCellDataParser, SingleSelectTypeOptionPB};
use crate::services::group::action::GroupAction;
use crate::services::group::controller_impls::select_option_controller::util::*;
use crate::services::group::entities::Group;
use crate::services::group::group_controller::{GenericGroupController, GroupController, GroupGenerator};
use flowy_grid_data_model::revision::{
FieldRevision, RowChangeset, RowRevision, SelectOptionGroupConfigurationRevision,
};
// SingleSelect
pub type SingleSelectGroupController = GenericGroupController<
SelectOptionGroupConfigurationRevision,
SingleSelectTypeOptionPB,
SingleSelectGroupGenerator,
SelectOptionCellDataParser,
>;
impl GroupAction for SingleSelectGroupController {
type CellDataType = SelectOptionCellDataPB;
fn can_group(&self, content: &str, cell_data: &SelectOptionCellDataPB) -> bool {
cell_data.select_options.iter().any(|option| option.id == content)
}
fn add_row_if_match(&mut self, row_rev: &RowRevision, cell_data: &Self::CellDataType) -> Vec<GroupRowsChangesetPB> {
let mut changesets = vec![];
self.groups_map.iter_mut().for_each(|(_, group): (_, &mut Group)| {
add_row(group, &mut changesets, cell_data, row_rev);
});
changesets
}
fn remove_row_if_match(
&mut self,
row_rev: &RowRevision,
cell_data: &Self::CellDataType,
) -> Vec<GroupRowsChangesetPB> {
let mut changesets = vec![];
self.groups_map.iter_mut().for_each(|(_, group): (_, &mut Group)| {
remove_row(group, &mut changesets, cell_data, row_rev);
});
changesets
}
fn move_row_if_match(
&mut self,
field_rev: &FieldRevision,
row_rev: &RowRevision,
row_changeset: &mut RowChangeset,
cell_data: &Self::CellDataType,
to_row_id: &str,
) -> Vec<GroupRowsChangesetPB> {
let mut group_changeset = vec![];
self.groups_map.iter_mut().for_each(|(_, group): (_, &mut Group)| {
move_row(
group,
&mut group_changeset,
field_rev,
row_rev,
row_changeset,
cell_data,
to_row_id,
);
});
group_changeset
}
}
impl GroupController for SingleSelectGroupController {
fn will_create_row(&mut self, row_rev: &mut RowRevision, field_rev: &FieldRevision, group_id: &str) {
let group: Option<&mut Group> = self.groups_map.get_mut(group_id);
match group {
None => {}
Some(group) => {
let cell_rev = insert_select_option_cell(group.id.clone(), field_rev);
row_rev.cells.insert(field_rev.id.clone(), cell_rev);
group.add_row(RowPB::from(row_rev));
}
}
}
}
pub struct SingleSelectGroupGenerator();
impl GroupGenerator for SingleSelectGroupGenerator {
type ConfigurationType = SelectOptionGroupConfiguration;
type TypeOptionType = SingleSelectTypeOptionPB;
fn generate_groups(
field_id: &str,
configuration: &Self::ConfigurationType,
type_option: &Option<Self::TypeOptionType>,
) -> Vec<Group> {
match type_option {
None => vec![],
Some(type_option) => type_option
.options
.iter()
.map(|option| {
Group::new(
option.id.clone(),
field_id.to_owned(),
option.name.clone(),
option.id.clone(),
)
})
.collect(),
}
}
}

View File

@ -0,0 +1,108 @@
use crate::entities::{GroupRowsChangesetPB, InsertedRowPB, RowPB};
use crate::services::cell::insert_select_option_cell;
use crate::services::field::SelectOptionCellDataPB;
use crate::services::group::configuration::{GenericGroupConfiguration, GroupConfigurationAction};
use crate::services::group::Group;
use flowy_error::FlowyResult;
use flowy_grid_data_model::revision::{
FieldRevision, GroupRecordRevision, RowChangeset, RowRevision, SelectOptionGroupConfigurationRevision,
};
pub type SelectOptionGroupConfiguration = GenericGroupConfiguration<SelectOptionGroupConfigurationRevision>;
impl GroupConfigurationAction for SelectOptionGroupConfiguration {
fn group_records(&self) -> &[GroupRecordRevision] {
todo!()
}
fn save_groups(&self) -> FlowyResult<()> {
todo!()
}
fn hide_group(&self, group_id: &str) -> FlowyResult<()> {
todo!()
}
fn show_group(&self, group_id: &str) -> FlowyResult<()> {
todo!()
}
}
pub fn add_row(
group: &mut Group,
changesets: &mut Vec<GroupRowsChangesetPB>,
cell_data: &SelectOptionCellDataPB,
row_rev: &RowRevision,
) {
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);
changesets.push(GroupRowsChangesetPB::insert(
group.id.clone(),
vec![InsertedRowPB::new(row_pb.clone())],
));
group.add_row(row_pb);
}
} else if group.contains_row(&row_rev.id) {
changesets.push(GroupRowsChangesetPB::delete(group.id.clone(), vec![row_rev.id.clone()]));
group.remove_row(&row_rev.id);
}
});
}
pub fn remove_row(
group: &mut Group,
changesets: &mut Vec<GroupRowsChangesetPB>,
cell_data: &SelectOptionCellDataPB,
row_rev: &RowRevision,
) {
cell_data.select_options.iter().for_each(|option| {
if option.id == group.id && group.contains_row(&row_rev.id) {
changesets.push(GroupRowsChangesetPB::delete(group.id.clone(), vec![row_rev.id.clone()]));
group.remove_row(&row_rev.id);
}
});
}
pub fn move_row(
group: &mut Group,
group_changeset: &mut Vec<GroupRowsChangesetPB>,
field_rev: &FieldRevision,
row_rev: &RowRevision,
row_changeset: &mut RowChangeset,
cell_data: &SelectOptionCellDataPB,
to_row_id: &str,
) {
cell_data.select_options.iter().for_each(|option| {
// Remove the row in which group contains the row
let is_group_contains = group.contains_row(&row_rev.id);
let to_index = group.index_of_row(to_row_id);
if option.id == group.id && is_group_contains {
group_changeset.push(GroupRowsChangesetPB::delete(group.id.clone(), vec![row_rev.id.clone()]));
group.remove_row(&row_rev.id);
}
// Find the inserted group
if let Some(to_index) = to_index {
let row_pb = RowPB::from(row_rev);
let inserted_row = InsertedRowPB {
row: row_pb.clone(),
index: Some(to_index as i32),
};
group_changeset.push(GroupRowsChangesetPB::insert(group.id.clone(), vec![inserted_row]));
if group.number_of_row() == to_index {
group.add_row(row_pb);
} else {
group.insert_row(to_index, row_pb);
}
}
// If the inserted row comes from other group, it needs to update the corresponding cell content.
if to_index.is_some() && option.id != group.id {
// Update the corresponding row's cell content.
let cell_rev = insert_select_option_cell(group.id.clone(), field_rev);
row_changeset.cell_by_field_id.insert(field_rev.id.clone(), cell_rev);
}
});
}

View File

@ -1,286 +0,0 @@
use crate::entities::{GroupRowsChangesetPB, InsertedRowPB, RowPB, SelectOptionGroupConfigurationPB};
use crate::services::cell::insert_select_option_cell;
use crate::services::field::{
MultiSelectTypeOptionPB, SelectOptionCellDataPB, SelectOptionCellDataParser, SingleSelectTypeOptionPB,
};
use crate::services::group::{GenericGroupController, Group, GroupController, GroupGenerator, Groupable};
use flowy_grid_data_model::revision::{FieldRevision, RowChangeset, RowRevision};
// SingleSelect
pub type SingleSelectGroupController = GenericGroupController<
SelectOptionGroupConfigurationPB,
SingleSelectTypeOptionPB,
SingleSelectGroupGenerator,
SelectOptionCellDataParser,
>;
impl Groupable for SingleSelectGroupController {
type CellDataType = SelectOptionCellDataPB;
fn can_group(&self, content: &str, cell_data: &SelectOptionCellDataPB) -> bool {
cell_data.select_options.iter().any(|option| option.id == content)
}
fn add_row_if_match(&mut self, row_rev: &RowRevision, cell_data: &Self::CellDataType) -> Vec<GroupRowsChangesetPB> {
let mut changesets = vec![];
self.groups_map.iter_mut().for_each(|(_, group): (_, &mut Group)| {
add_row(group, &mut changesets, cell_data, row_rev);
});
changesets
}
fn remove_row_if_match(
&mut self,
row_rev: &RowRevision,
cell_data: &Self::CellDataType,
) -> Vec<GroupRowsChangesetPB> {
let mut changesets = vec![];
self.groups_map.iter_mut().for_each(|(_, group): (_, &mut Group)| {
remove_row(group, &mut changesets, cell_data, row_rev);
});
changesets
}
fn move_row_if_match(
&mut self,
field_rev: &FieldRevision,
row_rev: &RowRevision,
row_changeset: &mut RowChangeset,
cell_data: &Self::CellDataType,
to_row_id: &str,
) -> Vec<GroupRowsChangesetPB> {
let mut group_changeset = vec![];
self.groups_map.iter_mut().for_each(|(_, group): (_, &mut Group)| {
move_row(
group,
&mut group_changeset,
field_rev,
row_rev,
row_changeset,
cell_data,
to_row_id,
);
});
group_changeset
}
}
impl GroupController for SingleSelectGroupController {
fn will_create_row(&mut self, row_rev: &mut RowRevision, field_rev: &FieldRevision, group_id: &str) {
let group: Option<&mut Group> = self.groups_map.get_mut(group_id);
match group {
None => {}
Some(group) => {
let cell_rev = insert_select_option_cell(group.id.clone(), field_rev);
row_rev.cells.insert(field_rev.id.clone(), cell_rev);
group.add_row(RowPB::from(row_rev));
}
}
}
}
pub struct SingleSelectGroupGenerator();
impl GroupGenerator for SingleSelectGroupGenerator {
type ConfigurationType = SelectOptionGroupConfigurationPB;
type TypeOptionType = SingleSelectTypeOptionPB;
fn generate_groups(
field_id: &str,
_configuration: &Option<Self::ConfigurationType>,
type_option: &Option<Self::TypeOptionType>,
) -> Vec<Group> {
match type_option {
None => vec![],
Some(type_option) => type_option
.options
.iter()
.map(|option| {
Group::new(
option.id.clone(),
field_id.to_owned(),
option.name.clone(),
option.id.clone(),
)
})
.collect(),
}
}
}
// MultiSelect
pub type MultiSelectGroupController = GenericGroupController<
SelectOptionGroupConfigurationPB,
MultiSelectTypeOptionPB,
MultiSelectGroupGenerator,
SelectOptionCellDataParser,
>;
impl Groupable for MultiSelectGroupController {
type CellDataType = SelectOptionCellDataPB;
fn can_group(&self, content: &str, cell_data: &SelectOptionCellDataPB) -> bool {
cell_data.select_options.iter().any(|option| option.id == content)
}
fn add_row_if_match(&mut self, row_rev: &RowRevision, cell_data: &Self::CellDataType) -> Vec<GroupRowsChangesetPB> {
let mut changesets = vec![];
self.groups_map.iter_mut().for_each(|(_, group): (_, &mut Group)| {
add_row(group, &mut changesets, cell_data, row_rev);
});
changesets
}
fn remove_row_if_match(
&mut self,
row_rev: &RowRevision,
cell_data: &Self::CellDataType,
) -> Vec<GroupRowsChangesetPB> {
let mut changesets = vec![];
self.groups_map.iter_mut().for_each(|(_, group): (_, &mut Group)| {
remove_row(group, &mut changesets, cell_data, row_rev);
});
changesets
}
fn move_row_if_match(
&mut self,
field_rev: &FieldRevision,
row_rev: &RowRevision,
row_changeset: &mut RowChangeset,
cell_data: &Self::CellDataType,
to_row_id: &str,
) -> Vec<GroupRowsChangesetPB> {
let mut group_changeset = vec![];
self.groups_map.iter_mut().for_each(|(_, group): (_, &mut Group)| {
move_row(
group,
&mut group_changeset,
field_rev,
row_rev,
row_changeset,
cell_data,
to_row_id,
);
});
group_changeset
}
}
impl GroupController for MultiSelectGroupController {
fn will_create_row(&mut self, row_rev: &mut RowRevision, field_rev: &FieldRevision, group_id: &str) {
let group: Option<&Group> = self.groups_map.get(group_id);
match group {
None => tracing::warn!("Can not find the group: {}", group_id),
Some(group) => {
let cell_rev = insert_select_option_cell(group.id.clone(), field_rev);
row_rev.cells.insert(field_rev.id.clone(), cell_rev);
}
}
}
}
pub struct MultiSelectGroupGenerator();
impl GroupGenerator for MultiSelectGroupGenerator {
type ConfigurationType = SelectOptionGroupConfigurationPB;
type TypeOptionType = MultiSelectTypeOptionPB;
fn generate_groups(
field_id: &str,
_configuration: &Option<Self::ConfigurationType>,
type_option: &Option<Self::TypeOptionType>,
) -> Vec<Group> {
match type_option {
None => vec![],
Some(type_option) => type_option
.options
.iter()
.map(|option| {
Group::new(
option.id.clone(),
field_id.to_owned(),
option.name.clone(),
option.id.clone(),
)
})
.collect(),
}
}
}
fn add_row(
group: &mut Group,
changesets: &mut Vec<GroupRowsChangesetPB>,
cell_data: &SelectOptionCellDataPB,
row_rev: &RowRevision,
) {
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);
changesets.push(GroupRowsChangesetPB::insert(
group.id.clone(),
vec![InsertedRowPB::new(row_pb.clone())],
));
group.add_row(row_pb);
}
} else if group.contains_row(&row_rev.id) {
changesets.push(GroupRowsChangesetPB::delete(group.id.clone(), vec![row_rev.id.clone()]));
group.remove_row(&row_rev.id);
}
});
}
fn remove_row(
group: &mut Group,
changesets: &mut Vec<GroupRowsChangesetPB>,
cell_data: &SelectOptionCellDataPB,
row_rev: &RowRevision,
) {
cell_data.select_options.iter().for_each(|option| {
if option.id == group.id && group.contains_row(&row_rev.id) {
changesets.push(GroupRowsChangesetPB::delete(group.id.clone(), vec![row_rev.id.clone()]));
group.remove_row(&row_rev.id);
}
});
}
fn move_row(
group: &mut Group,
group_changeset: &mut Vec<GroupRowsChangesetPB>,
field_rev: &FieldRevision,
row_rev: &RowRevision,
row_changeset: &mut RowChangeset,
cell_data: &SelectOptionCellDataPB,
to_row_id: &str,
) {
cell_data.select_options.iter().for_each(|option| {
// Remove the row in which group contains the row
let is_group_contains = group.contains_row(&row_rev.id);
let to_index = group.index_of_row(to_row_id);
if option.id == group.id && is_group_contains {
group_changeset.push(GroupRowsChangesetPB::delete(group.id.clone(), vec![row_rev.id.clone()]));
group.remove_row(&row_rev.id);
}
// Find the inserted group
if let Some(to_index) = to_index {
let row_pb = RowPB::from(row_rev);
let inserted_row = InsertedRowPB {
row: row_pb.clone(),
index: Some(to_index as i32),
};
group_changeset.push(GroupRowsChangesetPB::insert(group.id.clone(), vec![inserted_row]));
if group.number_of_row() == to_index {
group.add_row(row_pb);
} else {
group.insert_row(to_index, row_pb);
}
}
// If the inserted row comes from other group, it needs to update the corresponding cell content.
if to_index.is_some() && option.id != group.id {
// Update the corresponding row's cell content.
let cell_rev = insert_select_option_cell(group.id.clone(), field_rev);
row_changeset.cell_by_field_id.insert(field_rev.id.clone(), cell_rev);
}
});
}

View File

@ -0,0 +1,73 @@
use crate::entities::{GroupPB, RowPB};
#[derive(Clone)]
pub struct Group {
pub id: String,
pub field_id: String,
pub desc: String,
rows: Vec<RowPB>,
/// [content] is used to determine which group the cell belongs to.
pub content: String,
}
impl std::convert::From<Group> for GroupPB {
fn from(group: Group) -> Self {
Self {
field_id: group.field_id,
group_id: group.id,
desc: group.desc,
rows: group.rows,
}
}
}
impl Group {
pub fn new(id: String, field_id: String, desc: String, content: String) -> Self {
Self {
id,
field_id,
desc,
rows: vec![],
content,
}
}
pub fn contains_row(&self, row_id: &str) -> bool {
self.rows.iter().any(|row| row.id == row_id)
}
pub fn remove_row(&mut self, row_id: &str) {
match self.rows.iter().position(|row| row.id == row_id) {
None => {}
Some(pos) => {
self.rows.remove(pos);
}
}
}
pub fn add_row(&mut self, row_pb: RowPB) {
match self.rows.iter().find(|row| row.id == row_pb.id) {
None => {
self.rows.push(row_pb);
}
Some(_) => {}
}
}
pub fn insert_row(&mut self, index: usize, row_pb: RowPB) {
if index < self.rows.len() {
self.rows.insert(index, row_pb);
} else {
tracing::error!("Insert row index:{} beyond the bounds:{},", index, self.rows.len());
}
}
pub fn index_of_row(&self, row_id: &str) -> Option<usize> {
self.rows.iter().position(|row| row.id == row_id)
}
pub fn number_of_row(&self) -> usize {
self.rows.len()
}
}

View File

@ -1,54 +1,43 @@
use crate::entities::{GroupPB, GroupRowsChangesetPB, RowPB};
use crate::entities::{GroupRowsChangesetPB, RowPB};
use crate::services::cell::{decode_any_cell_data, CellBytesParser};
use bytes::Bytes;
use crate::services::group::action::GroupAction;
use crate::services::group::configuration::{GenericGroupConfiguration, GroupConfigurationReader};
use crate::services::group::entities::Group;
use flowy_error::FlowyResult;
use flowy_grid_data_model::revision::{
FieldRevision, GroupConfigurationRevision, RowChangeset, RowRevision, TypeOptionDataDeserializer,
FieldRevision, GroupConfigurationContentSerde, GroupConfigurationRevision, RowChangeset, RowRevision,
TypeOptionDataDeserializer,
};
use indexmap::IndexMap;
use lib_infra::future::AFFuture;
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.
pub trait GroupController: GroupControllerSharedAction + Send + Sync {
fn will_create_row(&mut self, row_rev: &mut RowRevision, field_rev: &FieldRevision, group_id: &str);
}
pub trait GroupGenerator {
type ConfigurationType;
type TypeOptionType;
fn generate_groups(
field_id: &str,
configuration: &Option<Self::ConfigurationType>,
configuration: &Self::ConfigurationType,
type_option: &Option<Self::TypeOptionType>,
) -> Vec<Group>;
}
pub trait Groupable: Send + Sync {
type CellDataType;
fn can_group(&self, content: &str, cell_data: &Self::CellDataType) -> bool;
fn add_row_if_match(&mut self, row_rev: &RowRevision, cell_data: &Self::CellDataType) -> Vec<GroupRowsChangesetPB>;
fn remove_row_if_match(
&mut self,
row_rev: &RowRevision,
cell_data: &Self::CellDataType,
) -> Vec<GroupRowsChangesetPB>;
fn move_row_if_match(
&mut self,
field_rev: &FieldRevision,
row_rev: &RowRevision,
row_changeset: &mut RowChangeset,
cell_data: &Self::CellDataType,
to_row_id: &str,
) -> Vec<GroupRowsChangesetPB>;
}
pub trait GroupController: GroupControllerSharedAction + Send + Sync {
fn will_create_row(&mut self, row_rev: &mut RowRevision, field_rev: &FieldRevision, group_id: &str);
}
// Defines the shared actions each group controller can perform.
pub trait GroupControllerSharedAction: Send + Sync {
// The field that is used for grouping the rows
fn field_id(&self) -> &str;
fn groups(&self) -> Vec<Group>;
fn group_rows(&mut self, row_revs: &[Arc<RowRevision>], field_rev: &FieldRevision) -> FlowyResult<()>;
fn fill_groups(&mut self, row_revs: &[Arc<RowRevision>], field_rev: &FieldRevision) -> FlowyResult<Vec<Group>>;
fn did_update_row(
&mut self,
row_rev: &RowRevision,
@ -70,105 +59,35 @@ pub trait GroupControllerSharedAction: Send + Sync {
) -> FlowyResult<Vec<GroupRowsChangesetPB>>;
}
const DEFAULT_GROUP_ID: &str = "default_group";
/// C: represents the group configuration structure
/// C: represents the group configuration that impl [GroupConfigurationSerde]
/// T: the type option data deserializer that impl [TypeOptionDataDeserializer]
/// G: the group generator, [GroupGenerator]
/// P: the parser that impl [CellBytesParser] for the CellBytes
pub struct GenericGroupController<C, T, G, P> {
pub field_id: String,
pub groups_map: IndexMap<String, Group>,
/// default_group is used to store the rows that don't belong to any groups.
default_group: Group,
pub type_option: Option<T>,
pub configuration: Option<C>,
pub configuration: GenericGroupConfiguration<C>,
group_action_phantom: PhantomData<G>,
cell_parser_phantom: PhantomData<P>,
}
#[derive(Clone)]
pub struct Group {
pub id: String,
pub field_id: String,
pub desc: String,
rows: Vec<RowPB>,
pub content: String,
}
impl std::convert::From<Group> for GroupPB {
fn from(group: Group) -> Self {
Self {
field_id: group.field_id,
group_id: group.id,
desc: group.desc,
rows: group.rows,
}
}
}
impl Group {
pub fn new(id: String, field_id: String, desc: String, content: String) -> Self {
Self {
id,
field_id,
desc,
rows: vec![],
content,
}
}
pub fn contains_row(&self, row_id: &str) -> bool {
self.rows.iter().any(|row| row.id == row_id)
}
pub fn remove_row(&mut self, row_id: &str) {
match self.rows.iter().position(|row| row.id == row_id) {
None => {}
Some(pos) => {
self.rows.remove(pos);
}
}
}
pub fn add_row(&mut self, row_pb: RowPB) {
match self.rows.iter().find(|row| row.id == row_pb.id) {
None => {
self.rows.push(row_pb);
}
Some(_) => {}
}
}
pub fn insert_row(&mut self, index: usize, row_pb: RowPB) {
if index < self.rows.len() {
self.rows.insert(index, row_pb);
} else {
tracing::error!("Insert row index:{} beyond the bounds:{},", index, self.rows.len());
}
}
pub fn index_of_row(&self, row_id: &str) -> Option<usize> {
self.rows.iter().position(|row| row.id == row_id)
}
pub fn number_of_row(&self) -> usize {
self.rows.len()
}
}
impl<C, T, G, P> GenericGroupController<C, T, G, P>
where
C: TryFrom<Bytes, Error = protobuf::ProtobufError>,
C: GroupConfigurationContentSerde,
T: TypeOptionDataDeserializer,
G: GroupGenerator<ConfigurationType = C, TypeOptionType = T>,
G: GroupGenerator<ConfigurationType = GenericGroupConfiguration<C>, TypeOptionType = T>,
{
pub fn new(field_rev: &Arc<FieldRevision>, configuration: GroupConfigurationRevision) -> FlowyResult<Self> {
// let configuration = match configuration.content {
// None => None,
// Some(content) => Some(C::try_from(Bytes::from(content))?),
// };
let configuration = None;
pub async fn new(
field_rev: &Arc<FieldRevision>,
configuration_reader: Arc<dyn GroupConfigurationReader>,
configuration_writer: Arc<dyn GroupConfigurationReader>,
) -> FlowyResult<Self> {
let configuration =
GenericGroupConfiguration::<C>::new(field_rev.clone(), configuration_reader, configuration_writer).await?;
let field_type_rev = field_rev.ty;
let type_option = field_rev.get_type_option_entry::<T>(field_type_rev);
let groups = G::generate_groups(&field_rev.id, &configuration, &type_option);
@ -195,55 +114,52 @@ where
impl<C, T, G, P> GroupControllerSharedAction for GenericGroupController<C, T, G, P>
where
P: CellBytesParser,
Self: Groupable<CellDataType = P::Object>,
Self: GroupAction<CellDataType = P::Object>,
{
fn field_id(&self) -> &str {
&self.field_id
}
fn groups(&self) -> Vec<Group> {
let default_group = self.default_group.clone();
let mut groups: Vec<Group> = self.groups_map.values().cloned().collect();
if !default_group.rows.is_empty() {
groups.push(default_group);
}
groups
}
fn group_rows(&mut self, row_revs: &[Arc<RowRevision>], field_rev: &FieldRevision) -> FlowyResult<()> {
if self.configuration.is_none() {
return Ok(());
}
fn fill_groups(&mut self, row_revs: &[Arc<RowRevision>], field_rev: &FieldRevision) -> FlowyResult<Vec<Group>> {
// if self.configuration.is_none() {
// return Ok(vec![]);
// }
for row_rev in row_revs {
if let Some(cell_rev) = row_rev.cells.get(&self.field_id) {
let mut records: Vec<GroupRecord> = vec![];
let mut group_rows: Vec<GroupRow> = vec![];
let cell_bytes = decode_any_cell_data(cell_rev.data.clone(), field_rev);
let cell_data = cell_bytes.parser::<P>()?;
for group in self.groups_map.values() {
if self.can_group(&group.content, &cell_data) {
records.push(GroupRecord {
group_rows.push(GroupRow {
row: row_rev.into(),
group_id: group.id.clone(),
});
}
}
if records.is_empty() {
self.default_group.rows.push(row_rev.into());
if group_rows.is_empty() {
self.default_group.add_row(row_rev.into());
} else {
for record in records {
if let Some(group) = self.groups_map.get_mut(&record.group_id) {
group.rows.push(record.row);
for group_row in group_rows {
if let Some(group) = self.groups_map.get_mut(&group_row.group_id) {
group.add_row(group_row.row);
}
}
}
} else {
self.default_group.rows.push(row_rev.into());
self.default_group.add_row(row_rev.into());
}
}
Ok(())
let default_group = self.default_group.clone();
let mut groups: Vec<Group> = self.groups_map.values().cloned().collect();
if !default_group.number_of_row() == 0 {
groups.push(default_group);
}
Ok(groups)
}
fn did_update_row(
@ -292,7 +208,7 @@ where
}
}
struct GroupRecord {
struct GroupRow {
row: RowPB,
group_id: String,
}

View File

@ -2,44 +2,48 @@ use crate::entities::{
CheckboxGroupConfigurationPB, DateGroupConfigurationPB, FieldType, GroupRowsChangesetPB,
NumberGroupConfigurationPB, SelectOptionGroupConfigurationPB, TextGroupConfigurationPB, UrlGroupConfigurationPB,
};
use crate::services::group::configuration::GroupConfigurationReader;
use crate::services::group::group_controller::GroupController;
use crate::services::group::{
CheckboxGroupController, Group, GroupController, MultiSelectGroupController, SingleSelectGroupController,
CheckboxGroupController, Group, GroupConfigurationWriter, MultiSelectGroupController, SingleSelectGroupController,
};
use bytes::Bytes;
use flowy_error::FlowyResult;
use flowy_grid_data_model::revision::{
gen_grid_group_id, CheckboxGroupConfigurationRevision, DateGroupConfigurationRevision, FieldRevision,
GroupConfigurationRevision, NumberGroupConfigurationRevision, RowChangeset, RowRevision,
SelectOptionGroupConfigurationRevision, TextGroupConfigurationRevision, UrlGroupConfigurationRevision,
CheckboxGroupConfigurationRevision, DateGroupConfigurationRevision, FieldRevision, GroupConfigurationRevision,
NumberGroupConfigurationRevision, RowChangeset, RowRevision, SelectOptionGroupConfigurationRevision,
TextGroupConfigurationRevision, UrlGroupConfigurationRevision,
};
use lib_infra::future::AFFuture;
use std::future::Future;
use std::sync::Arc;
use tokio::sync::RwLock;
pub trait GroupConfigurationDelegate: Send + Sync + 'static {
fn get_group_configuration(&self, field_rev: Arc<FieldRevision>) -> AFFuture<GroupConfigurationRevision>;
}
pub(crate) struct GroupService {
delegate: Box<dyn GroupConfigurationDelegate>,
configuration_reader: Arc<dyn GroupConfigurationReader>,
configuration_writer: Arc<dyn GroupConfigurationWriter>,
group_controller: Option<Arc<RwLock<dyn GroupController>>>,
}
impl GroupService {
pub(crate) async fn new(delegate: Box<dyn GroupConfigurationDelegate>) -> Self {
pub(crate) async fn new<R, W>(configuration_reader: R, configuration_writer: W) -> Self
where
R: GroupConfigurationReader,
W: GroupConfigurationWriter,
{
Self {
delegate,
configuration_reader: Arc::new(configuration_reader),
configuration_writer: Arc::new(configuration_writer),
group_controller: None,
}
}
pub(crate) async fn groups(&self) -> Vec<Group> {
if let Some(group_action_handler) = self.group_controller.as_ref() {
group_action_handler.read().await.groups()
} else {
vec![]
}
// if let Some(group_action_handler) = self.group_controller.as_ref() {
// group_action_handler.read().await.groups()
// } else {
// vec![]
// }
todo!()
}
pub(crate) async fn load_groups(
@ -49,13 +53,25 @@ impl GroupService {
) -> Option<Vec<Group>> {
let field_rev = find_group_field(field_revs)?;
let field_type: FieldType = field_rev.ty.into();
let configuration = self.delegate.get_group_configuration(field_rev.clone()).await;
match self
.build_groups(&field_type, &field_rev, row_revs, configuration)
.await
{
Ok(groups) => Some(groups),
Err(_) => None,
match self.make_group_controller(&field_type, &field_rev).await {
Ok(group_controller) => {
self.group_controller = group_controller;
let mut groups = vec![];
if let Some(group_action_handler) = self.group_controller.as_ref() {
let mut write_guard = group_action_handler.write().await;
groups = match write_guard.fill_groups(&row_revs, &field_rev) {
Ok(groups) => groups,
Err(e) => {
tracing::error!("Fill groups failed:{:?}", e);
vec![]
}
};
drop(write_guard);
}
Some(groups)
}
Err(_) => Some(vec![]),
}
}
@ -151,14 +167,13 @@ impl GroupService {
}
}
#[tracing::instrument(level = "trace", skip_all, err)]
async fn build_groups(
#[tracing::instrument(level = "trace", skip_all)]
async fn make_group_controller(
&mut self,
field_type: &FieldType,
field_rev: &Arc<FieldRevision>,
row_revs: Vec<Arc<RowRevision>>,
configuration: GroupConfigurationRevision,
) -> FlowyResult<Vec<Group>> {
) -> FlowyResult<Option<Arc<RwLock<dyn GroupController>>>> {
let mut group_controller: Option<Arc<RwLock<dyn GroupController>>> = None;
match field_type {
FieldType::RichText => {
// let generator = GroupGenerator::<TextGroupConfigurationPB>::from_configuration(configuration);
@ -170,31 +185,37 @@ impl GroupService {
// let generator = GroupGenerator::<DateGroupConfigurationPB>::from_configuration(configuration);
}
FieldType::SingleSelect => {
let controller = SingleSelectGroupController::new(field_rev, configuration)?;
self.group_controller = Some(Arc::new(RwLock::new(controller)));
let controller = SingleSelectGroupController::new(
field_rev,
self.configuration_reader.clone(),
self.configuration_writer.clone(),
)
.await?;
group_controller = Some(Arc::new(RwLock::new(controller)));
}
FieldType::MultiSelect => {
let controller = MultiSelectGroupController::new(field_rev, configuration)?;
self.group_controller = Some(Arc::new(RwLock::new(controller)));
let controller = MultiSelectGroupController::new(
field_rev,
self.configuration_reader.clone(),
self.configuration_writer.clone(),
)
.await?;
group_controller = Some(Arc::new(RwLock::new(controller)));
}
FieldType::Checkbox => {
let controller = CheckboxGroupController::new(field_rev, configuration)?;
self.group_controller = Some(Arc::new(RwLock::new(controller)));
let controller = CheckboxGroupController::new(
field_rev,
self.configuration_reader.clone(),
self.configuration_writer.clone(),
)
.await?;
group_controller = Some(Arc::new(RwLock::new(controller)))
}
FieldType::URL => {
// let generator = GroupGenerator::<UrlGroupConfigurationPB>::from_configuration(configuration);
}
};
let mut groups = vec![];
if let Some(group_action_handler) = self.group_controller.as_ref() {
let mut write_guard = group_action_handler.write().await;
let _ = write_guard.group_rows(&row_revs, field_rev)?;
groups = write_guard.groups();
drop(write_guard);
}
Ok(groups)
Ok(group_controller)
}
}

View File

@ -1,5 +1,11 @@
mod controllers;
mod action;
mod configuration;
mod controller_impls;
mod entities;
mod group_controller;
mod group_service;
pub(crate) use controllers::*;
pub(crate) use configuration::*;
pub(crate) use controller_impls::*;
pub(crate) use entities::*;
pub(crate) use group_service::*;

View File

@ -1,11 +1,4 @@
use crate::entities::{
GridLayout, GridLayoutPB, GridSettingPB, RepeatedGridConfigurationFilterPB, RepeatedGridGroupConfigurationPB,
RepeatedGridSortPB,
};
use flowy_grid_data_model::revision::{FieldRevision, SettingRevision};
use flowy_sync::entities::grid::{CreateFilterParams, DeleteFilterParams, GridSettingChangesetParams};
use std::collections::HashMap;
use std::sync::Arc;
use crate::entities::{CreateFilterParams, DeleteFilterParams, GridLayout, GridSettingChangesetParams};
pub struct GridSettingChangesetBuilder {
params: GridSettingChangesetParams,
@ -20,8 +13,6 @@ impl GridSettingChangesetBuilder {
delete_filter: None,
insert_group: None,
delete_group: None,
insert_sort: None,
delete_sort: None,
};
Self { params }
}
@ -40,42 +31,3 @@ impl GridSettingChangesetBuilder {
self.params
}
}
pub fn make_grid_setting(grid_setting_rev: &SettingRevision, field_revs: &[Arc<FieldRevision>]) -> GridSettingPB {
let current_layout_type: GridLayout = grid_setting_rev.layout.clone().into();
let filters_by_field_id = grid_setting_rev
.get_all_filters(field_revs)
.map(|filters_by_field_id| {
filters_by_field_id
.into_iter()
.map(|(k, v)| (k, v.into()))
.collect::<HashMap<String, RepeatedGridConfigurationFilterPB>>()
})
.unwrap_or_default();
let groups_by_field_id = grid_setting_rev
.get_all_groups(field_revs)
.map(|groups_by_field_id| {
groups_by_field_id
.into_iter()
.map(|(k, v)| (k, v.into()))
.collect::<HashMap<String, RepeatedGridGroupConfigurationPB>>()
})
.unwrap_or_default();
let sorts_by_field_id = grid_setting_rev
.get_all_sort()
.map(|sorts_by_field_id| {
sorts_by_field_id
.into_iter()
.map(|(k, v)| (k, v.into()))
.collect::<HashMap<String, RepeatedGridSortPB>>()
})
.unwrap_or_default();
GridSettingPB {
layouts: GridLayoutPB::all(),
current_layout_type,
filter_configuration_by_field_id: filters_by_field_id,
group_configuration_by_field_id: groups_by_field_id,
sorts_by_field_id,
}
}

View File

@ -0,0 +1,9 @@
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq, Hash)]
pub struct FilterConfigurationRevision {
pub id: String,
pub field_id: String,
pub condition: u8,
pub content: Option<String>,
}

View File

@ -1,8 +1,7 @@
use crate::revision::{FieldRevision, FieldTypeRevision};
use crate::revision::{FieldRevision, FieldTypeRevision, FilterConfigurationRevision, GroupConfigurationRevision};
use indexmap::IndexMap;
use nanoid::nanoid;
use serde::{Deserialize, Serialize};
use serde_repr::*;
use std::collections::HashMap;
use std::fmt::Debug;
use std::sync::Arc;
@ -15,6 +14,7 @@ pub fn gen_grid_group_id() -> String {
nanoid!(6)
}
#[allow(dead_code)]
pub fn gen_grid_sort_id() -> String {
nanoid!(6)
}
@ -24,114 +24,6 @@ pub type FilterConfigurationsByFieldId = HashMap<String, Vec<Arc<FilterConfigura
//
pub type GroupConfiguration = Configuration<GroupConfigurationRevision>;
pub type GroupConfigurationsByFieldId = HashMap<String, Vec<Arc<GroupConfigurationRevision>>>;
//
pub type SortConfiguration = Configuration<SortConfigurationRevision>;
pub type SortConfigurationsByFieldId = HashMap<String, Vec<Arc<SortConfigurationRevision>>>;
#[derive(Debug, Clone, Serialize, Deserialize, Default, Eq, PartialEq)]
pub struct SettingRevision {
pub layout: LayoutRevision,
pub filters: FilterConfiguration,
#[serde(default)]
pub groups: GroupConfiguration,
#[serde(skip)]
pub sorts: SortConfiguration,
}
#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize_repr, Deserialize_repr)]
#[repr(u8)]
pub enum LayoutRevision {
Table = 0,
Board = 1,
}
impl ToString for LayoutRevision {
fn to_string(&self) -> String {
let layout_rev = self.clone() as u8;
layout_rev.to_string()
}
}
impl std::default::Default for LayoutRevision {
fn default() -> Self {
LayoutRevision::Table
}
}
impl SettingRevision {
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<Vec<Arc<GroupConfigurationRevision>>> {
self.groups.get_objects(field_id, field_type_rev)
}
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);
}
pub fn get_all_sort(&self) -> Option<SortConfigurationsByFieldId> {
None
}
}
#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
pub struct SortConfigurationRevision {
pub id: String,
pub field_id: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default, Eq, PartialEq)]
#[serde(transparent)]
@ -239,38 +131,3 @@ where
&mut self.object_by_field_type
}
}
pub trait GroupConfigurationSerde {
fn from_configuration(s: &str) -> Result<Self, serde_json::Error>;
}
#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
pub struct GroupConfigurationRevision {
pub id: String,
pub field_id: String,
pub field_type_rev: FieldTypeRevision,
pub content: String,
}
impl GroupConfigurationRevision {
pub fn new<T>(field_id: String, field_type: FieldTypeRevision, content: T) -> Result<Self, serde_json::Error>
where
T: serde::Serialize,
{
let content = serde_json::to_string(&content)?;
Ok(Self {
id: gen_grid_group_id(),
field_id,
field_type_rev: field_type,
content,
})
}
}
#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq, Hash)]
pub struct FilterConfigurationRevision {
pub id: String,
pub field_id: String,
pub condition: u8,
pub content: Option<String>,
}

View File

@ -1,19 +1,49 @@
use crate::revision::SettingRevision;
use crate::revision::{
FieldRevision, FieldTypeRevision, FilterConfiguration, FilterConfigurationRevision, FilterConfigurationsByFieldId,
GroupConfiguration, GroupConfigurationRevision, GroupConfigurationsByFieldId,
};
use nanoid::nanoid;
use serde::{Deserialize, Serialize};
use serde_repr::*;
use std::sync::Arc;
#[allow(dead_code)]
pub fn gen_grid_view_id() -> String {
nanoid!(6)
}
#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize_repr, Deserialize_repr)]
#[repr(u8)]
pub enum LayoutRevision {
Table = 0,
Board = 1,
}
impl ToString for LayoutRevision {
fn to_string(&self) -> String {
let layout_rev = self.clone() as u8;
layout_rev.to_string()
}
}
impl std::default::Default for LayoutRevision {
fn default() -> Self {
LayoutRevision::Table
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct GridViewRevision {
pub view_id: String,
pub grid_id: String,
pub setting: SettingRevision,
pub layout: LayoutRevision,
pub filters: FilterConfiguration,
#[serde(default)]
pub groups: GroupConfiguration,
// For the moment, we just use the order returned from the GridRevision
#[allow(dead_code)]
@ -26,10 +56,78 @@ impl GridViewRevision {
GridViewRevision {
view_id,
grid_id,
setting: Default::default(),
layout: Default::default(),
filters: Default::default(),
groups: Default::default(),
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)]

View File

@ -1,32 +1,91 @@
use crate::revision::{gen_grid_group_id, FieldTypeRevision};
use serde::{Deserialize, Serialize};
use serde_json::Error;
use serde_repr::*;
pub trait GroupConfigurationContentSerde: Sized {
fn from_configuration(s: &str) -> Result<Self, serde_json::Error>;
}
#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
pub struct GroupConfigurationRevision {
pub id: String,
pub field_id: String,
pub field_type_rev: FieldTypeRevision,
pub content: String,
}
impl GroupConfigurationRevision {
pub fn new<T>(field_id: String, field_type: FieldTypeRevision, content: T) -> Result<Self, serde_json::Error>
where
T: serde::Serialize,
{
let content = serde_json::to_string(&content)?;
Ok(Self {
id: gen_grid_group_id(),
field_id,
field_type_rev: field_type,
content,
})
}
}
#[derive(Default, Serialize, Deserialize)]
pub struct TextGroupConfigurationRevision {
pub hide_empty: bool,
}
impl GroupConfigurationContentSerde for TextGroupConfigurationRevision {
fn from_configuration(s: &str) -> Result<Self, Error> {
serde_json::from_str(s)
}
}
#[derive(Default, Serialize, Deserialize)]
pub struct NumberGroupConfigurationRevision {
pub hide_empty: bool,
}
impl GroupConfigurationContentSerde for NumberGroupConfigurationRevision {
fn from_configuration(s: &str) -> Result<Self, Error> {
serde_json::from_str(s)
}
}
#[derive(Default, Serialize, Deserialize)]
pub struct UrlGroupConfigurationRevision {
pub hide_empty: bool,
}
impl GroupConfigurationContentSerde for UrlGroupConfigurationRevision {
fn from_configuration(s: &str) -> Result<Self, Error> {
serde_json::from_str(s)
}
}
#[derive(Default, Serialize, Deserialize)]
pub struct CheckboxGroupConfigurationRevision {
pub hide_empty: bool,
}
impl GroupConfigurationContentSerde for CheckboxGroupConfigurationRevision {
fn from_configuration(s: &str) -> Result<Self, Error> {
serde_json::from_str(s)
}
}
#[derive(Default, Serialize, Deserialize)]
pub struct SelectOptionGroupConfigurationRevision {
pub hide_empty: bool,
pub groups: Vec<GroupRecordRevision>,
}
impl GroupConfigurationContentSerde for SelectOptionGroupConfigurationRevision {
fn from_configuration(s: &str) -> Result<Self, Error> {
serde_json::from_str(s)
}
}
#[derive(Default, Serialize, Deserialize)]
pub struct GroupRecordRevision {
pub group_id: String,
@ -42,6 +101,12 @@ pub struct DateGroupConfigurationRevision {
pub condition: DateCondition,
}
impl GroupConfigurationContentSerde for DateGroupConfigurationRevision {
fn from_configuration(s: &str) -> Result<Self, Error> {
serde_json::from_str(s)
}
}
#[derive(Serialize_repr, Deserialize_repr)]
#[repr(u8)]
pub enum DateCondition {

View File

@ -1,9 +1,11 @@
mod filter_rev;
mod grid_block;
mod grid_rev;
mod grid_setting_rev;
mod grid_view;
mod group_rev;
pub use filter_rev::*;
pub use grid_block::*;
pub use grid_rev::*;
pub use grid_setting_rev::*;

View File

@ -3,7 +3,7 @@ use crate::errors::{internal_error, CollaborateError, CollaborateResult};
use crate::util::{cal_diff, make_text_delta_from_revisions};
use flowy_grid_data_model::revision::{
FieldRevision, FieldTypeRevision, FilterConfigurationRevision, FilterConfigurationsByFieldId, GridViewRevision,
GroupConfigurationRevision, GroupConfigurationsByFieldId, SettingRevision, SortConfigurationsByFieldId,
GroupConfigurationRevision, GroupConfigurationsByFieldId,
};
use lib_ot::core::{OperationTransform, PhantomAttributes, TextDelta, TextDeltaBuilder};
use std::sync::Arc;
@ -48,23 +48,11 @@ impl GridViewRevisionPad {
Self::from_delta(delta)
}
pub fn get_setting_rev(&self) -> &SettingRevision {
&self.view.setting
}
pub fn get_all_groups(&self, field_revs: &[Arc<FieldRevision>]) -> Option<GroupConfigurationsByFieldId> {
self.setting.groups.get_all_objects(field_revs)
self.groups.get_all_objects(field_revs)
}
pub fn get_groups(
&self,
field_id: &str,
field_type_rev: &FieldTypeRevision,
) -> Option<Vec<Arc<GroupConfigurationRevision>>> {
self.setting.groups.get_objects(field_id, field_type_rev)
}
pub fn insert_group(
pub fn insert_group_configuration(
&mut self,
field_id: &str,
field_type: &FieldTypeRevision,
@ -72,8 +60,8 @@ impl GridViewRevisionPad {
) -> CollaborateResult<Option<GridViewRevisionChangeset>> {
self.modify(|view| {
// only one group can be set
view.setting.groups.remove_all();
view.setting.groups.insert_object(field_id, field_type, group_rev);
view.groups.remove_all();
view.groups.insert_object(field_id, field_type, group_rev);
Ok(Some(()))
})
}
@ -85,7 +73,7 @@ impl GridViewRevisionPad {
group_id: &str,
) -> CollaborateResult<Option<GridViewRevisionChangeset>> {
self.modify(|view| {
if let Some(groups) = view.setting.groups.get_mut_objects(field_id, field_type) {
if let Some(groups) = view.groups.get_mut_objects(field_id, field_type) {
groups.retain(|group| group.id != group_id);
Ok(Some(()))
} else {
@ -95,7 +83,7 @@ impl GridViewRevisionPad {
}
pub fn get_all_filters(&self, field_revs: &[Arc<FieldRevision>]) -> Option<FilterConfigurationsByFieldId> {
self.setting.filters.get_all_objects(field_revs)
self.filters.get_all_objects(field_revs)
}
pub fn get_filters(
@ -103,7 +91,7 @@ impl GridViewRevisionPad {
field_id: &str,
field_type_rev: &FieldTypeRevision,
) -> Option<Vec<Arc<FilterConfigurationRevision>>> {
self.setting.filters.get_objects(field_id, field_type_rev)
self.filters.get_objects(field_id, field_type_rev)
}
pub fn insert_filter(
@ -113,7 +101,7 @@ impl GridViewRevisionPad {
filter_rev: FilterConfigurationRevision,
) -> CollaborateResult<Option<GridViewRevisionChangeset>> {
self.modify(|view| {
view.setting.filters.insert_object(field_id, field_type, filter_rev);
view.filters.insert_object(field_id, field_type, filter_rev);
Ok(Some(()))
})
}
@ -125,7 +113,7 @@ impl GridViewRevisionPad {
filter_id: &str,
) -> CollaborateResult<Option<GridViewRevisionChangeset>> {
self.modify(|view| {
if let Some(filters) = view.setting.filters.get_mut_objects(field_id, field_type) {
if let Some(filters) = view.filters.get_mut_objects(field_id, field_type) {
filters.retain(|filter| filter.id != filter_id);
Ok(Some(()))
} else {
@ -134,10 +122,6 @@ impl GridViewRevisionPad {
})
}
pub fn get_all_sort(&self) -> Option<SortConfigurationsByFieldId> {
None
}
pub fn json_str(&self) -> CollaborateResult<String> {
make_grid_view_rev_json_str(&self.view)
}