chore: read group data from backend

This commit is contained in:
appflowy 2022-08-12 16:05:56 +08:00
parent e29aaf8388
commit 5de6a7447a
34 changed files with 365 additions and 300 deletions

View File

@ -1,7 +0,0 @@
use flowy_derive::ProtoBuf;
#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
pub struct CheckboxGroupConfigurationPB {
#[pb(index = 1)]
pub(crate) hide_empty: bool,
}

View File

@ -0,0 +1,56 @@
use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
pub struct UrlGroupConfigurationPB {
#[pb(index = 1)]
hide_empty: bool,
}
#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
pub struct TextGroupConfigurationPB {
#[pb(index = 1)]
hide_empty: bool,
}
#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
pub struct SelectOptionGroupConfigurationPB {
#[pb(index = 1)]
hide_empty: bool,
}
#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
pub struct NumberGroupConfigurationPB {
#[pb(index = 1)]
hide_empty: bool,
}
#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
pub struct DateGroupConfigurationPB {
#[pb(index = 1)]
pub condition: DateCondition,
#[pb(index = 2)]
hide_empty: bool,
}
#[derive(Debug, Clone, PartialEq, Eq, ProtoBuf_Enum)]
#[repr(u8)]
pub enum DateCondition {
Relative = 0,
Day = 1,
Week = 2,
Month = 3,
Year = 4,
}
impl std::default::Default for DateCondition {
fn default() -> Self {
DateCondition::Relative
}
}
#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
pub struct CheckboxGroupConfigurationPB {
#[pb(index = 1)]
pub(crate) hide_empty: bool,
}

View File

@ -1,26 +0,0 @@
use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
pub struct DateGroupConfigurationPB {
#[pb(index = 1)]
pub condition: DateCondition,
#[pb(index = 2)]
hide_empty: bool,
}
#[derive(Debug, Clone, PartialEq, Eq, ProtoBuf_Enum)]
#[repr(u8)]
pub enum DateCondition {
Relative = 0,
Day = 1,
Week = 2,
Month = 3,
Year = 4,
}
impl std::default::Default for DateCondition {
fn default() -> Self {
DateCondition::Relative
}
}

View File

@ -1,15 +1,5 @@
mod checkbox_group;
mod date_group;
mod configuration;
mod group;
mod number_group;
mod select_option_group;
mod text_group;
mod url_group;
pub use checkbox_group::*;
pub use date_group::*;
pub use configuration::*;
pub use group::*;
pub use number_group::*;
pub use select_option_group::*;
pub use text_group::*;
pub use url_group::*;

View File

@ -1,7 +0,0 @@
use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
pub struct NumberGroupConfigurationPB {
#[pb(index = 1)]
hide_empty: bool,
}

View File

@ -1,7 +0,0 @@
use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
pub struct SelectOptionGroupConfigurationPB {
#[pb(index = 1)]
hide_empty: bool,
}

View File

@ -1,7 +0,0 @@
use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
pub struct TextGroupConfigurationPB {
#[pb(index = 1)]
hide_empty: bool,
}

View File

@ -1,7 +0,0 @@
use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
pub struct UrlGroupConfigurationPB {
#[pb(index = 1)]
hide_empty: bool,
}

View File

@ -114,6 +114,11 @@ impl AnyCellData {
pub struct CellBytes(pub Bytes);
pub trait CellBytesParser {
type Object;
fn parser(bytes: &Bytes) -> FlowyResult<Self::Object>;
}
pub trait CellBytesCustomParser {
type Object;
fn parse(&self, bytes: &Bytes) -> FlowyResult<Self::Object>;
}
@ -132,11 +137,18 @@ impl CellBytes {
Ok(Self(bytes))
}
pub fn with_parser<P>(&self) -> FlowyResult<P::Object>
pub fn parser<P>(&self) -> FlowyResult<P::Object>
where
P: CellBytesParser,
{
P::parse(&self.0)
P::parser(&self.0)
}
pub fn custom_parser<P>(&self, parser: P) -> FlowyResult<P::Object>
where
P: CellBytesCustomParser,
{
parser.parse(&self.0)
}
// pub fn parse<'a, T: TryFrom<&'a [u8]>>(&'a self) -> FlowyResult<T>

View File

@ -60,7 +60,7 @@ impl ToString for CheckboxCellData {
pub struct CheckboxCellDataParser();
impl CellBytesParser for CheckboxCellDataParser {
type Object = CheckboxCellData;
fn parse(&self, bytes: &Bytes) -> FlowyResult<Self::Object> {
fn parser(bytes: &Bytes) -> FlowyResult<Self::Object> {
match String::from_utf8(bytes.to_vec()) {
Ok(s) => CheckboxCellData::from_str(&s),
Err(_) => Ok(CheckboxCellData("".to_string())),

View File

@ -3,7 +3,7 @@ mod tests {
use crate::entities::FieldType;
use crate::services::cell::CellDataOperation;
use crate::services::field::*;
// use crate::services::field::{DateCellChangeset, DateCellData, DateFormat, DateTypeOption, TimeFormat};
// use crate::services::field::{DateCellChangeset, DateCellData, DateFormat, DateTypeOptionPB, TimeFormat};
use flowy_grid_data_model::revision::FieldRevision;
use strum::IntoEnumIterator;
@ -137,7 +137,7 @@ mod tests {
let decoded_data = type_option
.decode_cell_data(encoded_data.into(), &FieldType::DateTime, field_rev)
.unwrap()
.with_parser(DateCellDataParser())
.parser::<DateCellDataParser>()
.unwrap();
if type_option.include_time {

View File

@ -204,7 +204,7 @@ pub struct DateCellDataParser();
impl CellBytesParser for DateCellDataParser {
type Object = DateCellDataPB;
fn parse(&self, bytes: &Bytes) -> FlowyResult<Self::Object> {
fn parser(bytes: &Bytes) -> FlowyResult<Self::Object> {
DateCellDataPB::try_from(bytes.as_ref()).map_err(internal_error)
}
}

View File

@ -1,4 +1,4 @@
use crate::services::cell::CellBytesParser;
use crate::services::cell::{CellBytesCustomParser, CellBytesParser};
use crate::services::field::number_currency::Currency;
use crate::services::field::{strip_currency_symbol, NumberFormat, STRIP_SYMBOL};
use bytes::Bytes;
@ -93,8 +93,19 @@ impl ToString for NumberCellData {
}
}
}
pub struct NumberCellDataParser(pub NumberFormat);
pub struct NumberCellDataParser();
impl CellBytesParser for NumberCellDataParser {
type Object = NumberCellData;
fn parser(bytes: &Bytes) -> FlowyResult<Self::Object> {
match String::from_utf8(bytes.to_vec()) {
Ok(s) => NumberCellData::from_format_str(&s, true, &NumberFormat::Num),
Err(_) => Ok(NumberCellData::default()),
}
}
}
pub struct NumberCellCustomDataParser(pub NumberFormat);
impl CellBytesCustomParser for NumberCellCustomDataParser {
type Object = NumberCellData;
fn parse(&self, bytes: &Bytes) -> FlowyResult<Self::Object> {
match String::from_utf8(bytes.to_vec()) {

View File

@ -180,7 +180,7 @@ mod tests {
type_option
.decode_cell_data(cell_data.into(), &field_type, field_rev)
.unwrap()
.with_parser(SelectOptionCellDataParser())
.parser::<SelectOptionCellDataParser>()
.unwrap()
.select_options,
);

View File

@ -206,7 +206,7 @@ impl std::ops::DerefMut for SelectOptionIds {
pub struct SelectOptionIdsParser();
impl CellBytesParser for SelectOptionIdsParser {
type Object = SelectOptionIds;
fn parse(&self, bytes: &Bytes) -> FlowyResult<Self::Object> {
fn parser(bytes: &Bytes) -> FlowyResult<Self::Object> {
match String::from_utf8(bytes.to_vec()) {
Ok(s) => Ok(SelectOptionIds::from(s)),
Err(_) => Ok(SelectOptionIds::from("".to_owned())),
@ -218,7 +218,7 @@ pub struct SelectOptionCellDataParser();
impl CellBytesParser for SelectOptionCellDataParser {
type Object = SelectOptionCellDataPB;
fn parse(&self, bytes: &Bytes) -> FlowyResult<Self::Object> {
fn parser(bytes: &Bytes) -> FlowyResult<Self::Object> {
SelectOptionCellDataPB::try_from(bytes.as_ref()).map_err(internal_error)
}
}

View File

@ -162,7 +162,7 @@ mod tests {
type_option
.decode_cell_data(cell_data.into(), &field_type, field_rev)
.unwrap()
.with_parser(SelectOptionCellDataParser())
.parser::<SelectOptionCellDataParser>()
.unwrap()
.select_options,
);

View File

@ -96,7 +96,7 @@ impl FromCellString for TextCellData {
pub struct TextCellDataParser();
impl CellBytesParser for TextCellDataParser {
type Object = TextCellData;
fn parse(&self, bytes: &Bytes) -> FlowyResult<Self::Object> {
fn parser(bytes: &Bytes) -> FlowyResult<Self::Object> {
match String::from_utf8(bytes.to_vec()) {
Ok(s) => Ok(TextCellData(s)),
Err(_) => Ok(TextCellData("".to_owned())),
@ -124,7 +124,7 @@ mod tests {
type_option
.decode_cell_data(1647251762.to_string().into(), &field_type, &date_time_field_rev)
.unwrap()
.with_parser(DateCellDataParser())
.parser::<DateCellDataParser>()
.unwrap()
.date,
"Mar 14,2022".to_owned()
@ -144,7 +144,7 @@ mod tests {
&single_select_field_rev
)
.unwrap()
.with_parser(SelectOptionCellDataParser())
.parser::<SelectOptionCellDataParser>()
.unwrap()
.select_options,
vec![done_option],
@ -167,7 +167,7 @@ mod tests {
type_option
.decode_cell_data(cell_data.into(), &FieldType::MultiSelect, &multi_select_field_rev)
.unwrap()
.with_parser(SelectOptionCellDataParser())
.parser::<SelectOptionCellDataParser>()
.unwrap()
.select_options,
vec![google_option, facebook_option]

View File

@ -184,7 +184,7 @@ mod tests {
type_option
.decode_cell_data(encoded_data.into(), field_type, field_rev)
.unwrap()
.with_parser(URLCellDataParser())
.parser::<URLCellDataParser>()
.unwrap()
}
}

View File

@ -30,7 +30,7 @@ pub struct URLCellDataParser();
impl CellBytesParser for URLCellDataParser {
type Object = URLCellDataPB;
fn parse(&self, bytes: &Bytes) -> FlowyResult<Self::Object> {
fn parser(bytes: &Bytes) -> FlowyResult<Self::Object> {
URLCellDataPB::try_from(bytes.as_ref()).map_err(internal_error)
}
}

View File

@ -564,8 +564,9 @@ impl GridRevisionEditor {
})
}
#[tracing::instrument(level = "trace", skip_all, err)]
pub async fn load_groups(&self) -> FlowyResult<RepeatedGridGroupPB> {
let groups = self.group_service.load_groups().await.unwrap_or(vec![]);
let groups = self.group_service.load_groups().await.unwrap_or_default();
Ok(RepeatedGridGroupPB { items: groups })
}

View File

@ -1,70 +0,0 @@
use crate::entities::{
CheckboxGroupConfigurationPB, DateGroupConfigurationPB, NumberGroupConfigurationPB,
SelectOptionGroupConfigurationPB, TextGroupConfigurationPB, UrlGroupConfigurationPB,
};
use crate::services::cell::CellBytes;
use crate::services::field::{
CheckboxCellDataParser, DateCellDataParser, NumberCellDataParser, NumberFormat, SelectOptionCellDataParser,
TextCellDataParser, URLCellDataParser,
};
use crate::services::group::GroupAction;
// impl GroupAction for TextGroupConfigurationPB {
// fn should_group(&self, content: &str, cell_bytes: CellBytes) -> bool {
// if let Ok(cell_data) = cell_bytes.with_parser(TextCellDataParser()) {
// cell_data.as_ref() == content
// } else {
// false
// }
// }
// }
//
// impl GroupAction for NumberGroupConfigurationPB {
// fn should_group(&self, content: &str, cell_bytes: CellBytes) -> bool {
// if let Ok(cell_data) = cell_bytes.with_parser(NumberCellDataParser(NumberFormat::Num)) {
// false
// } else {
// false
// }
// }
// }
//
// impl GroupAction for DateGroupConfigurationPB {
// fn should_group(&self, content: &str, cell_bytes: CellBytes) -> bool {
// if let Ok(cell_data) = cell_bytes.with_parser(DateCellDataParser()) {
// false
// } else {
// false
// }
// }
// }
//
// impl GroupAction for SelectOptionGroupConfigurationPB {
// fn should_group(&self, content: &str, cell_bytes: CellBytes) -> bool {
// if let Ok(cell_data) = cell_bytes.with_parser(SelectOptionCellDataParser()) {
// false
// } else {
// false
// }
// }
// }
//
// impl GroupAction for UrlGroupConfigurationPB {
// fn should_group(&self, content: &str, cell_bytes: CellBytes) -> bool {
// if let Ok(cell_data) = cell_bytes.with_parser(URLCellDataParser()) {
// false
// } else {
// false
// }
// }
// }
//
// impl GroupAction for CheckboxGroupConfigurationPB {
// fn should_group(&self, content: &str, cell_bytes: CellBytes) -> bool {
// if let Ok(cell_data) = cell_bytes.with_parser(CheckboxCellDataParser()) {
// false
// } else {
// false
// }
// }
// }

View File

@ -1,7 +1,43 @@
use crate::entities::CheckboxGroupConfigurationPB;
use crate::services::cell::{AnyCellData, CellData, CellGroupOperation};
use crate::services::field::{CheckboxCellData, CheckboxTypeOptionPB};
use crate::services::group::GroupController;
use flowy_error::FlowyResult;
// pub type CheckboxGroupGenerator = GroupGenerator<CheckboxGroupConfigurationPB, CheckboxTypeOptionPB>;
use crate::services::field::{CheckboxCellData, CheckboxCellDataParser, CheckboxTypeOptionPB, CHECK, UNCHECK};
use crate::services::group::{Group, GroupAction, GroupCellContentProvider, GroupController, GroupGenerator};
pub type CheckboxGroupController =
GroupController<CheckboxGroupConfigurationPB, CheckboxTypeOptionPB, CheckboxGroupGenerator, CheckboxCellDataParser>;
pub struct CheckboxGroupGenerator();
impl GroupGenerator for CheckboxGroupGenerator {
type ConfigurationType = CheckboxGroupConfigurationPB;
type TypeOptionType = CheckboxTypeOptionPB;
fn gen_groups(
_configuration: &Option<Self::ConfigurationType>,
_type_option: &Option<Self::TypeOptionType>,
_cell_content_provider: &dyn GroupCellContentProvider,
) -> Vec<Group> {
let check_group = Group {
id: "true".to_string(),
desc: "".to_string(),
rows: vec![],
content: CHECK.to_string(),
};
let uncheck_group = Group {
id: "false".to_string(),
desc: "".to_string(),
rows: vec![],
content: UNCHECK.to_string(),
};
vec![check_group, uncheck_group]
}
}
impl GroupAction for CheckboxGroupController {
type CellDataType = CheckboxCellData;
fn should_group(&self, _content: &str, _cell_data: &Self::CellDataType) -> bool {
false
}
}

View File

@ -1,5 +0,0 @@
use crate::entities::CheckboxGroupConfigurationPB;
use crate::services::field::DateTypeOptionPB;
use crate::services::group::GroupController;
// pub type CheckboxGroupGenerator = GroupGenerator<CheckboxGroupConfigurationPB, DateTypeOptionPB>;

View File

@ -1,52 +1,70 @@
use crate::services::cell::{decode_any_cell_data, CellBytes, CellBytesParser};
use crate::entities::{GroupPB, RowPB};
use crate::services::cell::{decode_any_cell_data, CellBytesParser};
use bytes::Bytes;
use flowy_error::FlowyResult;
use flowy_grid_data_model::revision::{
CellRevision, FieldRevision, GroupConfigurationRevision, RowRevision, TypeOptionDataDeserializer,
FieldRevision, GroupConfigurationRevision, RowRevision, TypeOptionDataDeserializer,
};
use std::collections::HashMap;
use indexmap::IndexMap;
use std::marker::PhantomData;
use std::sync::Arc;
pub trait GroupAction<CD> {
fn should_group(&self, content: &str, cell_data: CD) -> bool;
pub trait GroupAction {
type CellDataType;
fn should_group(&self, content: &str, cell_data: &Self::CellDataType) -> bool;
}
pub trait GroupCellContentProvider {
/// We need to group the rows base on the deduplication cell content when the field type is
/// RichText.
fn deduplication_cell_content(&self, field_id: &str) -> Vec<String> {
fn deduplication_cell_content(&self, _field_id: &str) -> Vec<String> {
vec![]
}
}
pub trait GroupGenerator<C, T> {
pub trait GroupGenerator {
type ConfigurationType;
type TypeOptionType;
fn gen_groups(
configuration: &Option<C>,
type_option: &Option<T>,
configuration: &Option<Self::ConfigurationType>,
type_option: &Option<Self::TypeOptionType>,
cell_content_provider: &dyn GroupCellContentProvider,
) -> HashMap<String, Group>;
) -> Vec<Group>;
}
pub struct GroupController<C, T, G, CP> {
field_rev: Arc<FieldRevision>,
groups: HashMap<String, Group>,
type_option: Option<T>,
configuration: Option<C>,
pub field_rev: Arc<FieldRevision>,
pub groups: IndexMap<String, Group>,
pub type_option: Option<T>,
pub configuration: Option<C>,
group_action_phantom: PhantomData<G>,
cell_parser_phantom: PhantomData<CP>,
}
pub struct Group {
row_ids: Vec<String>,
content: String,
pub id: String,
pub desc: String,
pub rows: Vec<RowPB>,
pub content: String,
}
impl std::convert::From<Group> for GroupPB {
fn from(group: Group) -> Self {
Self {
group_id: group.id,
desc: group.desc,
rows: group.rows,
}
}
}
impl<C, T, G, CP> GroupController<C, T, G, CP>
where
C: TryFrom<Bytes, Error = protobuf::ProtobufError>,
T: TypeOptionDataDeserializer,
G: GroupGenerator<C, T>,
G: GroupGenerator<ConfigurationType = C, TypeOptionType = T>,
{
pub fn new(
field_rev: Arc<FieldRevision>,
@ -57,46 +75,63 @@ where
None => None,
Some(content) => Some(C::try_from(Bytes::from(content))?),
};
let field_type_rev = field_rev.field_type_rev.clone();
let field_type_rev = field_rev.field_type_rev;
let type_option = field_rev.get_type_option_entry::<T>(field_type_rev);
let groups = G::gen_groups(&configuration, &type_option, cell_content_provider);
Ok(Self {
field_rev,
groups: G::gen_groups(&configuration, &type_option, cell_content_provider),
groups: groups.into_iter().map(|group| (group.id.clone(), group)).collect(),
type_option,
configuration,
group_action_phantom: PhantomData,
cell_parser_phantom: PhantomData,
})
}
pub fn take_groups(self) -> Vec<Group> {
self.groups.into_values().collect()
}
}
impl<C, T, G, CP> GroupController<C, T, G, CP>
where
CP: CellBytesParser,
Self: GroupAction<CP::Object>,
Self: GroupAction<CellDataType = CP::Object>,
{
pub fn group_row(&mut self, row: &RowRevision) {
pub fn group_rows(&mut self, rows: &[Arc<RowRevision>]) -> FlowyResult<()> {
if self.configuration.is_none() {
return;
return Ok(());
}
if let Some(cell_rev) = row.cells.get(&self.field_rev.id) {
let mut group_row_id = None;
let cell_bytes = decode_any_cell_data(cell_rev.data.clone(), &self.field_rev);
// let cell_data = cell_bytes.with_parser(CP);
for group in self.groups.values() {
let cell_rev: CellRevision = cell_rev.clone();
// if self.should_group(&group.content, cell_bytes) {
// group_row_id = Some(row.id.clone());
// break;
// }
}
for row in rows {
if let Some(cell_rev) = row.cells.get(&self.field_rev.id) {
let mut records: Vec<GroupRecord> = vec![];
if let Some(group_row_id) = group_row_id {
self.groups.get_mut(&group_row_id).map(|group| {
group.row_ids.push(group_row_id);
});
let cell_bytes = decode_any_cell_data(cell_rev.data.clone(), &self.field_rev);
let cell_data = cell_bytes.parser::<CP>()?;
for group in self.groups.values() {
if self.should_group(&group.content, &cell_data) {
records.push(GroupRecord {
row: row.into(),
group_id: group.id.clone(),
});
break;
}
}
for record in records {
if let Some(group) = self.groups.get_mut(&record.group_id) {
group.rows.push(record.row);
}
}
}
}
Ok(())
}
}
struct GroupRecord {
row: RowPB,
group_id: String,
}

View File

@ -1,15 +1,7 @@
mod checkbox_group;
mod date_group;
mod generator;
mod number_group;
mod select_option_group;
mod text_group;
mod url_group;
pub use checkbox_group::*;
pub use date_group::*;
pub use generator::*;
pub use number_group::*;
pub use select_option_group::*;
pub use text_group::*;
pub use url_group::*;

View File

@ -1,5 +0,0 @@
use crate::entities::NumberGroupConfigurationPB;
use crate::services::field::NumberTypeOptionPB;
use crate::services::group::GroupController;
// pub type NumberGroupGenerator = GroupGenerator<NumberGroupConfigurationPB, NumberTypeOptionPB>;

View File

@ -1,12 +1,11 @@
use crate::entities::SelectOptionGroupConfigurationPB;
use crate::services::cell::CellBytes;
use crate::services::field::{
MultiSelectTypeOptionPB, SelectOptionCellDataPB, SelectOptionCellDataParser, SelectedSelectOptions,
SingleSelectTypeOptionPB,
MultiSelectTypeOptionPB, SelectOptionCellDataPB, SelectOptionCellDataParser, SingleSelectTypeOptionPB,
};
use crate::services::group::{Group, GroupAction, GroupCellContentProvider, GroupController, GroupGenerator};
use std::collections::HashMap;
// SingleSelect
pub type SingleSelectGroupController = GroupController<
SelectOptionGroupConfigurationPB,
SingleSelectTypeOptionPB,
@ -15,38 +14,74 @@ pub type SingleSelectGroupController = GroupController<
>;
pub struct SingleSelectGroupGenerator();
impl GroupGenerator<SelectOptionGroupConfigurationPB, SingleSelectTypeOptionPB> for SingleSelectGroupGenerator {
impl GroupGenerator for SingleSelectGroupGenerator {
type ConfigurationType = SelectOptionGroupConfigurationPB;
type TypeOptionType = SingleSelectTypeOptionPB;
fn gen_groups(
configuration: &Option<SelectOptionGroupConfigurationPB>,
type_option: &Option<SingleSelectTypeOptionPB>,
cell_content_provider: &dyn GroupCellContentProvider,
) -> HashMap<String, Group> {
todo!()
_configuration: &Option<Self::ConfigurationType>,
type_option: &Option<Self::TypeOptionType>,
_cell_content_provider: &dyn GroupCellContentProvider,
) -> Vec<Group> {
match type_option {
None => vec![],
Some(type_option) => type_option
.options
.iter()
.map(|option| Group {
id: option.id.clone(),
desc: option.name.clone(),
rows: vec![],
content: option.id.clone(),
})
.collect(),
}
}
}
impl GroupAction<SelectOptionCellDataPB> for SingleSelectGroupController {
fn should_group(&self, content: &str, cell_data: SelectOptionCellDataPB) -> bool {
todo!()
impl GroupAction for SingleSelectGroupController {
type CellDataType = SelectOptionCellDataPB;
fn should_group(&self, content: &str, cell_data: &SelectOptionCellDataPB) -> bool {
cell_data.select_options.iter().any(|option| option.id == content)
}
}
// pub type MultiSelectGroupController =
// GroupController<SelectOptionGroupConfigurationPB, MultiSelectTypeOptionPB, MultiSelectGroupGenerator>;
//
// pub struct MultiSelectGroupGenerator();
// impl GroupGenerator<SelectOptionGroupConfigurationPB, MultiSelectTypeOptionPB> for MultiSelectGroupGenerator {
// fn gen_groups(
// configuration: &Option<SelectOptionGroupConfigurationPB>,
// type_option: &Option<MultiSelectTypeOptionPB>,
// cell_content_provider: &dyn GroupCellContentProvider,
// ) -> HashMap<String, Group> {
// todo!()
// }
// }
//
// impl GroupAction for MultiSelectGroupController {
// fn should_group(&self, content: &str, cell_bytes: CellBytes) -> bool {
// todo!()
// }
// }
// MultiSelect
pub type MultiSelectGroupController = GroupController<
SelectOptionGroupConfigurationPB,
MultiSelectTypeOptionPB,
MultiSelectGroupGenerator,
SelectOptionCellDataParser,
>;
pub struct MultiSelectGroupGenerator();
impl GroupGenerator for MultiSelectGroupGenerator {
type ConfigurationType = SelectOptionGroupConfigurationPB;
type TypeOptionType = MultiSelectTypeOptionPB;
fn gen_groups(
_configuration: &Option<Self::ConfigurationType>,
type_option: &Option<Self::TypeOptionType>,
_cell_content_provider: &dyn GroupCellContentProvider,
) -> Vec<Group> {
match type_option {
None => vec![],
Some(type_option) => type_option
.options
.iter()
.map(|option| Group {
id: option.id.clone(),
desc: option.name.clone(),
rows: vec![],
content: option.id.clone(),
})
.collect(),
}
}
}
impl GroupAction for MultiSelectGroupController {
type CellDataType = SelectOptionCellDataPB;
fn should_group(&self, content: &str, cell_data: &SelectOptionCellDataPB) -> bool {
cell_data.select_options.iter().any(|option| option.id == content)
}
}

View File

@ -1,5 +0,0 @@
use crate::entities::TextGroupConfigurationPB;
use crate::services::field::RichTextTypeOptionPB;
use crate::services::group::GroupController;
// pub type TextGroupGenerator = GroupGenerator<TextGroupConfigurationPB, RichTextTypeOptionPB>;

View File

@ -1,5 +0,0 @@
use crate::entities::UrlGroupConfigurationPB;
use crate::services::field::URLTypeOptionPB;
use crate::services::group::GroupController;
// pub type UrlGroupGenerator = GroupGenerator<UrlGroupConfigurationPB, URLTypeOptionPB>;

View File

@ -1,15 +1,16 @@
use crate::services::block_manager::GridBlockManager;
use crate::services::grid_editor_task::GridServiceTaskScheduler;
use crate::services::group::{
CheckboxGroupController, Group, GroupCellContentProvider, MultiSelectGroupController, SingleSelectGroupController,
};
use crate::entities::{
CheckboxGroupConfigurationPB, DateGroupConfigurationPB, FieldType, GroupPB, NumberGroupConfigurationPB,
SelectOptionGroupConfigurationPB, TextGroupConfigurationPB, UrlGroupConfigurationPB,
};
use crate::services::block_manager::GridBlockManager;
use crate::services::cell::{decode_any_cell_data, CellBytes};
use crate::services::field::TextCellDataParser;
use crate::services::grid_editor_task::GridServiceTaskScheduler;
use crate::services::group::{GroupAction, GroupCellContentProvider, SingleSelectGroupController};
use bytes::Bytes;
use flowy_error::FlowyResult;
use flowy_grid_data_model::revision::{CellRevision, FieldRevision, GroupConfigurationRevision, RowRevision};
use flowy_grid_data_model::revision::{gen_grid_group_id, FieldRevision, GroupConfigurationRevision, RowRevision};
use flowy_sync::client_grid::GridRevisionPad;
use std::sync::Arc;
use tokio::sync::RwLock;
@ -39,53 +40,102 @@ impl GridGroupService {
pub(crate) async fn load_groups(&self) -> Option<Vec<GroupPB>> {
let grid_pad = self.grid_pad.read().await;
let field_rev = find_group_field(grid_pad.fields())?;
let field_type: FieldType = field_rev.field_type_rev.clone().into();
let setting = grid_pad.get_setting_rev();
let mut configurations = setting.get_groups(&setting.layout, &field_rev.id, &field_rev.field_type_rev)?;
if configurations.is_empty() {
return None;
}
assert_eq!(configurations.len(), 1);
let configuration = (&*configurations.pop().unwrap()).clone();
let field_rev = find_group_field(grid_pad.fields()).unwrap();
let field_type: FieldType = field_rev.field_type_rev.into();
let configuration = self.get_group_configuration(field_rev).await;
let blocks = self.block_manager.get_block_snapshots(None).await.unwrap();
let row_revs = blocks
.into_iter()
.map(|block| block.row_revs)
.flatten()
.collect::<Vec<Arc<RowRevision>>>();
// let a = SingleSelectGroupController::new;
// let b = a(field_rev.clone(), configuration, &self.grid_pad);
match self.build_groups(&field_type, field_rev, row_revs, configuration) {
Ok(groups) => Some(groups),
Err(_) => None,
}
}
let groups = match field_type {
async fn get_group_configuration(&self, field_rev: &FieldRevision) -> GroupConfigurationRevision {
let grid_pad = self.grid_pad.read().await;
let setting = grid_pad.get_setting_rev();
let layout = &setting.layout;
let configurations = setting.get_groups(layout, &field_rev.id, &field_rev.field_type_rev);
match configurations {
None => self.default_group_configuration(field_rev),
Some(mut configurations) => {
assert_eq!(configurations.len(), 1);
(&*configurations.pop().unwrap()).clone()
}
}
}
fn default_group_configuration(&self, field_rev: &FieldRevision) -> GroupConfigurationRevision {
let field_type: FieldType = field_rev.field_type_rev.clone().into();
let bytes: Bytes = match field_type {
FieldType::RichText => TextGroupConfigurationPB::default().try_into().unwrap(),
FieldType::Number => NumberGroupConfigurationPB::default().try_into().unwrap(),
FieldType::DateTime => DateGroupConfigurationPB::default().try_into().unwrap(),
FieldType::SingleSelect => SelectOptionGroupConfigurationPB::default().try_into().unwrap(),
FieldType::MultiSelect => SelectOptionGroupConfigurationPB::default().try_into().unwrap(),
FieldType::Checkbox => CheckboxGroupConfigurationPB::default().try_into().unwrap(),
FieldType::URL => UrlGroupConfigurationPB::default().try_into().unwrap(),
};
GroupConfigurationRevision {
id: gen_grid_group_id(),
field_id: field_rev.id.clone(),
field_type_rev: field_rev.field_type_rev.clone(),
content: Some(bytes.to_vec()),
}
}
#[tracing::instrument(level = "trace", skip_all, err)]
fn build_groups(
&self,
field_type: &FieldType,
field_rev: &Arc<FieldRevision>,
row_revs: Vec<Arc<RowRevision>>,
configuration: GroupConfigurationRevision,
) -> FlowyResult<Vec<GroupPB>> {
let groups: Vec<Group> = match field_type {
FieldType::RichText => {
// let generator = GroupGenerator::<TextGroupConfigurationPB>::from_configuration(configuration);
vec![]
}
FieldType::Number => {
// let generator = GroupGenerator::<NumberGroupConfigurationPB>::from_configuration(configuration);
vec![]
}
FieldType::DateTime => {
// let generator = GroupGenerator::<DateGroupConfigurationPB>::from_configuration(configuration);
vec![]
}
FieldType::SingleSelect => {
let group_controller =
SingleSelectGroupController::new(field_rev.clone(), configuration, &self.grid_pad);
let mut group_controller =
SingleSelectGroupController::new(field_rev.clone(), configuration, &self.grid_pad)?;
let _ = group_controller.group_rows(&row_revs)?;
group_controller.take_groups()
}
FieldType::MultiSelect => {
// let group_generator = MultiSelectGroupControllern(configuration);
let mut group_controller =
MultiSelectGroupController::new(field_rev.clone(), configuration, &self.grid_pad)?;
let _ = group_controller.group_rows(&row_revs)?;
group_controller.take_groups()
}
FieldType::Checkbox => {
// let generator = GroupGenerator::<CheckboxGroupConfigurationPB>::from_configuration(configuration);
let mut group_controller =
CheckboxGroupController::new(field_rev.clone(), configuration, &self.grid_pad)?;
let _ = group_controller.group_rows(&row_revs)?;
group_controller.take_groups()
}
FieldType::URL => {
// let generator = GroupGenerator::<UrlGroupConfigurationPB>::from_configuration(configuration);
vec![]
}
};
None
Ok(groups.into_iter().map(GroupPB::from).collect())
}
}

View File

@ -1,7 +1,5 @@
mod group_configuration;
mod group_generator;
mod group_service;
pub(crate) use group_configuration::*;
pub(crate) use group_generator::*;
pub(crate) use group_service::*;

View File

@ -162,7 +162,7 @@ impl GridRowTest {
.get_cell_bytes(&cell_id)
.await
.unwrap()
.with_parser(TextCellDataParser())
.parser::<TextCellDataParser>()
.unwrap();
assert_eq!(cell_data.as_ref(), &expected);
@ -177,7 +177,7 @@ impl GridRowTest {
.get_cell_bytes(&cell_id)
.await
.unwrap()
.with_parser(NumberCellDataParser(number_type_option.format))
.custom_parser(NumberCellCustomDataParser(number_type_option.format))
.unwrap();
assert_eq!(cell_data.to_string(), expected);
}
@ -187,7 +187,7 @@ impl GridRowTest {
.get_cell_bytes(&cell_id)
.await
.unwrap()
.with_parser(DateCellDataParser())
.parser::<DateCellDataParser>()
.unwrap();
assert_eq!(cell_data.date, expected);
@ -198,7 +198,7 @@ impl GridRowTest {
.get_cell_bytes(&cell_id)
.await
.unwrap()
.with_parser(SelectOptionCellDataParser())
.parser::<SelectOptionCellDataParser>()
.unwrap();
let select_option = cell_data.select_options.first().unwrap();
assert_eq!(select_option.name, expected);
@ -209,7 +209,7 @@ impl GridRowTest {
.get_cell_bytes(&cell_id)
.await
.unwrap()
.with_parser(SelectOptionCellDataParser())
.parser::<SelectOptionCellDataParser>()
.unwrap();
let s = cell_data
@ -228,7 +228,7 @@ impl GridRowTest {
.get_cell_bytes(&cell_id)
.await
.unwrap()
.with_parser(CheckboxCellDataParser())
.parser::<CheckboxCellDataParser>()
.unwrap();
assert_eq!(cell_data.to_string(), expected);
}
@ -238,7 +238,7 @@ impl GridRowTest {
.get_cell_bytes(&cell_id)
.await
.unwrap()
.with_parser(URLCellDataParser())
.parser::<URLCellDataParser>()
.unwrap();
assert_eq!(cell_data.content, expected);

View File

@ -259,7 +259,7 @@ pub fn create_text_field(grid_id: &str) -> (InsertFieldParams, FieldMeta) {
let cloned_field_meta = field_meta.clone();
let type_option_data = field_meta
.get_type_option_entry::<RichTextTypeOption>(&field_meta.field_type)
.get_type_option_entry::<RichTextTypeOptionPB>(&field_meta.field_type)
.unwrap()
.protobuf_bytes()
.to_vec();

View File

@ -572,7 +572,7 @@ fn make_group_revision(params: &CreateGridGroupParams) -> GroupConfigurationRevi
GroupConfigurationRevision {
id: gen_grid_group_id(),
field_id: params.field_id.clone(),
field_type_rev: params.field_type_rev.clone(),
field_type_rev: params.field_type_rev,
content: params.content.clone(),
}
}