mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
chore: reader and writter for group configuration
This commit is contained in:
parent
5fac1f044a
commit
91b2917d60
@ -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;
|
||||
|
||||
|
@ -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::*;
|
||||
|
@ -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 {
|
||||
|
@ -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>,
|
||||
}
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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(¶ms.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(¶ms.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<()> {
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
23
frontend/rust-lib/flowy-grid/src/services/group/action.rs
Normal file
23
frontend/rust-lib/flowy-grid/src/services/group/action.rs
Normal 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>;
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
@ -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(),
|
@ -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::*;
|
@ -0,0 +1,6 @@
|
||||
mod multi_select_controller;
|
||||
mod single_select_controller;
|
||||
mod util;
|
||||
|
||||
pub use multi_select_controller::*;
|
||||
pub use single_select_controller::*;
|
@ -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(),
|
||||
}
|
||||
}
|
||||
}
|
@ -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(),
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
});
|
||||
}
|
@ -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);
|
||||
}
|
||||
});
|
||||
}
|
73
frontend/rust-lib/flowy-grid/src/services/group/entities.rs
Normal file
73
frontend/rust-lib/flowy-grid/src/services/group/entities.rs
Normal 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()
|
||||
}
|
||||
}
|
@ -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,
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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::*;
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
@ -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>,
|
||||
}
|
@ -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>,
|
||||
}
|
||||
|
@ -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)]
|
||||
|
@ -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 {
|
||||
|
@ -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::*;
|
||||
|
@ -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)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user