chore: refactor multi-select type option and add GroupPB

This commit is contained in:
appflowy 2022-08-11 13:04:45 +08:00
parent 29ea3c83c8
commit aae2d96a4f
34 changed files with 561 additions and 245 deletions

View File

@ -0,0 +1,20 @@
import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
class BoardGroupService {
final String gridId;
GridFieldPB? groupField;
BoardGroupService(this.gridId);
void setGroupField(GridFieldPB field) {
groupField = field;
}
}
abstract class CanBeGroupField {
String get groupContent;
}
// class SingleSelectGroup extends CanBeGroupField {
// final SingleSelectTypeOptionContext typeOptionContext;
// }

View File

@ -4,22 +4,29 @@ import 'package:flowy_sdk/protobuf/flowy-grid/select_option.pb.dart';
import 'dart:async'; import 'dart:async';
import 'select_option_type_option_bloc.dart'; import 'select_option_type_option_bloc.dart';
import 'type_option_context.dart'; import 'type_option_context.dart';
import 'type_option_data_controller.dart';
import 'type_option_service.dart'; import 'type_option_service.dart';
import 'package:protobuf/protobuf.dart'; import 'package:protobuf/protobuf.dart';
class MultiSelectTypeOptionContext class MultiSelectAction with ISelectOptionAction {
extends TypeOptionContext<MultiSelectTypeOption> with ISelectOptionAction { final String gridId;
final String fieldId;
final TypeOptionFFIService service; final TypeOptionFFIService service;
final MultiSelectTypeOptionContext typeOptionContext;
MultiSelectTypeOptionContext({ MultiSelectAction({
required MultiSelectTypeOptionWidgetDataParser dataParser, required this.gridId,
required TypeOptionDataController dataController, required this.fieldId,
}) : service = TypeOptionFFIService( required this.typeOptionContext,
gridId: dataController.gridId, }) : service = TypeOptionFFIService(
fieldId: dataController.field.id, gridId: gridId,
), fieldId: fieldId,
super(dataParser: dataParser, dataController: dataController); );
MultiSelectTypeOptionPB get typeOption => typeOptionContext.typeOption;
set typeOption(MultiSelectTypeOptionPB newTypeOption) {
typeOptionContext.typeOption = newTypeOption;
}
@override @override
List<SelectOptionPB> Function(SelectOptionPB) get deleteOption { List<SelectOptionPB> Function(SelectOptionPB) get deleteOption {

View File

@ -0,0 +1,195 @@
import 'package:flowy_sdk/dispatch/dispatch.dart';
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/checkbox_type_option.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
import 'package:dartz/dartz.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/multi_select_type_option.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/number_type_option.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/single_select_type_option.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/text_type_option.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/url_type_option.pb.dart';
import 'package:protobuf/protobuf.dart';
import 'type_option_data_controller.dart';
abstract class TypeOptionDataParser<T> {
T fromBuffer(List<int> buffer);
}
// Number
typedef NumberTypeOptionContext = TypeOptionContext<NumberTypeOption>;
class NumberTypeOptionWidgetDataParser
extends TypeOptionDataParser<NumberTypeOption> {
@override
NumberTypeOption fromBuffer(List<int> buffer) {
return NumberTypeOption.fromBuffer(buffer);
}
}
// RichText
typedef RichTextTypeOptionContext = TypeOptionContext<RichTextTypeOption>;
class RichTextTypeOptionWidgetDataParser
extends TypeOptionDataParser<RichTextTypeOption> {
@override
RichTextTypeOption fromBuffer(List<int> buffer) {
return RichTextTypeOption.fromBuffer(buffer);
}
}
// Checkbox
typedef CheckboxTypeOptionContext = TypeOptionContext<CheckboxTypeOption>;
class CheckboxTypeOptionWidgetDataParser
extends TypeOptionDataParser<CheckboxTypeOption> {
@override
CheckboxTypeOption fromBuffer(List<int> buffer) {
return CheckboxTypeOption.fromBuffer(buffer);
}
}
// URL
typedef URLTypeOptionContext = TypeOptionContext<URLTypeOption>;
class URLTypeOptionWidgetDataParser
extends TypeOptionDataParser<URLTypeOption> {
@override
URLTypeOption fromBuffer(List<int> buffer) {
return URLTypeOption.fromBuffer(buffer);
}
}
// Date
typedef DateTypeOptionContext = TypeOptionContext<DateTypeOption>;
class DateTypeOptionDataParser extends TypeOptionDataParser<DateTypeOption> {
@override
DateTypeOption fromBuffer(List<int> buffer) {
return DateTypeOption.fromBuffer(buffer);
}
}
// SingleSelect
typedef SingleSelectTypeOptionContext
= TypeOptionContext<SingleSelectTypeOptionPB>;
class SingleSelectTypeOptionWidgetDataParser
extends TypeOptionDataParser<SingleSelectTypeOptionPB> {
@override
SingleSelectTypeOptionPB fromBuffer(List<int> buffer) {
return SingleSelectTypeOptionPB.fromBuffer(buffer);
}
}
// Multi-select
typedef MultiSelectTypeOptionContext
= TypeOptionContext<MultiSelectTypeOptionPB>;
class MultiSelectTypeOptionWidgetDataParser
extends TypeOptionDataParser<MultiSelectTypeOptionPB> {
@override
MultiSelectTypeOptionPB fromBuffer(List<int> buffer) {
return MultiSelectTypeOptionPB.fromBuffer(buffer);
}
}
class TypeOptionContext<T extends GeneratedMessage> {
T? _typeOptionObject;
final TypeOptionDataParser<T> dataParser;
final TypeOptionDataController _dataController;
TypeOptionContext({
required this.dataParser,
required TypeOptionDataController dataController,
}) : _dataController = dataController;
String get gridId => _dataController.gridId;
String get fieldId => _dataController.field.id;
Future<void> loadTypeOptionData({
required void Function(T) onCompleted,
required void Function(FlowyError) onError,
}) async {
await _dataController.loadTypeOptionData().then((result) {
result.fold((l) => null, (err) => onError(err));
});
onCompleted(typeOption);
}
T get typeOption {
if (_typeOptionObject != null) {
return _typeOptionObject!;
}
final T object = _dataController.getTypeOption(dataParser);
_typeOptionObject = object;
return object;
}
set typeOption(T typeOption) {
_dataController.typeOptionData = typeOption.writeToBuffer();
_typeOptionObject = typeOption;
}
}
abstract class TypeOptionFieldDelegate {
void onFieldChanged(void Function(String) callback);
void dispose();
}
abstract class IFieldTypeOptionLoader {
String get gridId;
Future<Either<FieldTypeOptionDataPB, FlowyError>> load();
Future<Either<FieldTypeOptionDataPB, FlowyError>> switchToField(
String fieldId, FieldType fieldType) {
final payload = EditFieldPayloadPB.create()
..gridId = gridId
..fieldId = fieldId
..fieldType = fieldType;
return GridEventSwitchToField(payload).send();
}
}
class NewFieldTypeOptionLoader extends IFieldTypeOptionLoader {
@override
final String gridId;
NewFieldTypeOptionLoader({
required this.gridId,
});
@override
Future<Either<FieldTypeOptionDataPB, FlowyError>> load() {
final payload = CreateFieldPayloadPB.create()
..gridId = gridId
..fieldType = FieldType.RichText;
return GridEventCreateFieldTypeOption(payload).send();
}
}
class FieldTypeOptionLoader extends IFieldTypeOptionLoader {
@override
final String gridId;
final GridFieldPB field;
FieldTypeOptionLoader({
required this.gridId,
required this.field,
});
@override
Future<Either<FieldTypeOptionDataPB, FlowyError>> load() {
final payload = GridFieldTypeOptionIdPB.create()
..gridId = gridId
..fieldId = field.id
..fieldType = field.fieldType;
return GridEventGetFieldTypeOption(payload).send();
}
}

View File

@ -92,11 +92,11 @@ TypeOptionWidgetBuilder makeTypeOptionWidgetBuilder({
); );
case FieldType.MultiSelect: case FieldType.MultiSelect:
return MultiSelectTypeOptionWidgetBuilder( return MultiSelectTypeOptionWidgetBuilder(
makeTypeOptionContextWithDataController<MultiSelectTypeOption>( makeTypeOptionContextWithDataController<MultiSelectTypeOptionPB>(
gridId: gridId, gridId: gridId,
fieldType: fieldType, fieldType: fieldType,
dataController: dataController, dataController: dataController,
) as MultiSelectTypeOptionContext, ),
overlayDelegate, overlayDelegate,
); );
case FieldType.Number: case FieldType.Number:

View File

@ -9,7 +9,7 @@ class MultiSelectTypeOptionWidgetBuilder extends TypeOptionWidgetBuilder {
final MultiSelectTypeOptionWidget _widget; final MultiSelectTypeOptionWidget _widget;
MultiSelectTypeOptionWidgetBuilder( MultiSelectTypeOptionWidgetBuilder(
MultiSelectTypeOptionContext typeOptionContext, MultiSelectAction typeOptionContext,
TypeOptionOverlayDelegate overlayDelegate, TypeOptionOverlayDelegate overlayDelegate,
) : _widget = MultiSelectTypeOptionWidget( ) : _widget = MultiSelectTypeOptionWidget(
typeOptionContext: typeOptionContext, typeOptionContext: typeOptionContext,
@ -21,7 +21,7 @@ class MultiSelectTypeOptionWidgetBuilder extends TypeOptionWidgetBuilder {
} }
class MultiSelectTypeOptionWidget extends TypeOptionWidget { class MultiSelectTypeOptionWidget extends TypeOptionWidget {
final MultiSelectTypeOptionContext typeOptionContext; final MultiSelectAction typeOptionContext;
final TypeOptionOverlayDelegate overlayDelegate; final TypeOptionOverlayDelegate overlayDelegate;
const MultiSelectTypeOptionWidget({ const MultiSelectTypeOptionWidget({

View File

@ -981,6 +981,7 @@ dependencies = [
"serde", "serde",
"serde_json", "serde_json",
"serde_repr", "serde_repr",
"tracing",
] ]
[[package]] [[package]]

View File

@ -11,33 +11,33 @@ use std::convert::TryInto;
use std::sync::Arc; use std::sync::Arc;
#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)] #[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
pub struct GridFilter { pub struct GridFilterConfiguration {
#[pb(index = 1)] #[pb(index = 1)]
pub id: String, pub id: String,
} }
#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)] #[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
pub struct RepeatedGridFilterPB { pub struct RepeatedGridConfigurationFilterPB {
#[pb(index = 1)] #[pb(index = 1)]
pub items: Vec<GridFilter>, pub items: Vec<GridFilterConfiguration>,
} }
impl std::convert::From<&GridFilterRevision> for GridFilter { impl std::convert::From<&GridFilterRevision> for GridFilterConfiguration {
fn from(rev: &GridFilterRevision) -> Self { fn from(rev: &GridFilterRevision) -> Self {
Self { id: rev.id.clone() } Self { id: rev.id.clone() }
} }
} }
impl std::convert::From<Vec<Arc<GridFilterRevision>>> for RepeatedGridFilterPB { impl std::convert::From<Vec<Arc<GridFilterRevision>>> for RepeatedGridConfigurationFilterPB {
fn from(revs: Vec<Arc<GridFilterRevision>>) -> Self { fn from(revs: Vec<Arc<GridFilterRevision>>) -> Self {
RepeatedGridFilterPB { RepeatedGridConfigurationFilterPB {
items: revs.into_iter().map(|rev| rev.as_ref().into()).collect(), items: revs.into_iter().map(|rev| rev.as_ref().into()).collect(),
} }
} }
} }
impl std::convert::From<Vec<GridFilter>> for RepeatedGridFilterPB { impl std::convert::From<Vec<GridFilterConfiguration>> for RepeatedGridConfigurationFilterPB {
fn from(items: Vec<GridFilter>) -> Self { fn from(items: Vec<GridFilterConfiguration>) -> Self {
Self { items } Self { items }
} }
} }

View File

@ -1,4 +1,4 @@
use crate::entities::FieldType; use crate::entities::{FieldType, GridRowPB};
use flowy_derive::ProtoBuf; use flowy_derive::ProtoBuf;
use flowy_error::ErrorCode; use flowy_error::ErrorCode;
use flowy_grid_data_model::parser::NotEmptyStr; use flowy_grid_data_model::parser::NotEmptyStr;
@ -8,7 +8,7 @@ use std::convert::TryInto;
use std::sync::Arc; use std::sync::Arc;
#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)] #[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
pub struct GridGroupPB { pub struct GridGroupConfigurationPB {
#[pb(index = 1)] #[pb(index = 1)]
pub id: String, pub id: String,
@ -19,9 +19,9 @@ pub struct GridGroupPB {
pub sub_group_field_id: Option<String>, pub sub_group_field_id: Option<String>,
} }
impl std::convert::From<&GridGroupRevision> for GridGroupPB { impl std::convert::From<&GridGroupRevision> for GridGroupConfigurationPB {
fn from(rev: &GridGroupRevision) -> Self { fn from(rev: &GridGroupRevision) -> Self {
GridGroupPB { GridGroupConfigurationPB {
id: rev.id.clone(), id: rev.id.clone(),
group_field_id: rev.field_id.clone(), group_field_id: rev.field_id.clone(),
sub_group_field_id: rev.sub_field_id.clone(), sub_group_field_id: rev.sub_field_id.clone(),
@ -29,21 +29,39 @@ impl std::convert::From<&GridGroupRevision> for GridGroupPB {
} }
} }
#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)] #[derive(ProtoBuf, Debug, Default, Clone)]
pub struct RepeatedGridGroupPB { pub struct RepeatedGridGroupPB {
#[pb(index = 1)] #[pb(index = 1)]
pub items: Vec<GridGroupPB>, groups: Vec<GroupPB>,
} }
impl std::convert::From<Vec<GridGroupPB>> for RepeatedGridGroupPB { #[derive(ProtoBuf, Debug, Default, Clone)]
fn from(items: Vec<GridGroupPB>) -> Self { pub struct GroupPB {
#[pb(index = 1)]
pub group_id: String,
#[pb(index = 2)]
pub desc: String,
#[pb(index = 3)]
pub rows: Vec<GridRowPB>,
}
#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
pub struct RepeatedGridGroupConfigurationPB {
#[pb(index = 1)]
pub items: Vec<GridGroupConfigurationPB>,
}
impl std::convert::From<Vec<GridGroupConfigurationPB>> for RepeatedGridGroupConfigurationPB {
fn from(items: Vec<GridGroupConfigurationPB>) -> Self {
Self { items } Self { items }
} }
} }
impl std::convert::From<Vec<Arc<GridGroupRevision>>> for RepeatedGridGroupPB { impl std::convert::From<Vec<Arc<GridGroupRevision>>> for RepeatedGridGroupConfigurationPB {
fn from(revs: Vec<Arc<GridGroupRevision>>) -> Self { fn from(revs: Vec<Arc<GridGroupRevision>>) -> Self {
RepeatedGridGroupPB { RepeatedGridGroupConfigurationPB {
items: revs.iter().map(|rev| rev.as_ref().into()).collect(), items: revs.iter().map(|rev| rev.as_ref().into()).collect(),
} }
} }

View File

@ -1,6 +1,6 @@
use crate::entities::{ use crate::entities::{
CreateGridFilterPayloadPB, CreateGridGroupPayloadPB, CreateGridSortPayloadPB, DeleteFilterPayloadPB, CreateGridFilterPayloadPB, CreateGridGroupPayloadPB, CreateGridSortPayloadPB, DeleteFilterPayloadPB,
DeleteGroupPayloadPB, RepeatedGridFilterPB, RepeatedGridGroupPB, RepeatedGridSortPB, DeleteGroupPayloadPB, RepeatedGridConfigurationFilterPB, RepeatedGridGroupConfigurationPB, RepeatedGridSortPB,
}; };
use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
use flowy_error::ErrorCode; use flowy_error::ErrorCode;
@ -22,10 +22,10 @@ pub struct GridSettingPB {
pub current_layout_type: GridLayoutType, pub current_layout_type: GridLayoutType,
#[pb(index = 3)] #[pb(index = 3)]
pub filters_by_field_id: HashMap<String, RepeatedGridFilterPB>, pub filter_configuration_by_field_id: HashMap<String, RepeatedGridConfigurationFilterPB>,
#[pb(index = 4)] #[pb(index = 4)]
pub groups_by_field_id: HashMap<String, RepeatedGridGroupPB>, pub group_configuration_by_field_id: HashMap<String, RepeatedGridGroupConfigurationPB>,
#[pb(index = 5)] #[pb(index = 5)]
pub sorts_by_field_id: HashMap<String, RepeatedGridSortPB>, pub sorts_by_field_id: HashMap<String, RepeatedGridSortPB>,

View File

@ -405,3 +405,14 @@ pub(crate) async fn update_date_cell_handler(
let _ = editor.update_cell(params.into()).await?; let _ = editor.update_cell(params.into()).await?;
Ok(()) Ok(())
} }
#[tracing::instrument(level = "trace", skip_all, err)]
pub(crate) async fn get_group_handler(
data: Data<GridIdPB>,
manager: AppData<Arc<GridManager>>,
) -> DataResult<RepeatedGridGroupPB, FlowyError> {
let params: GridIdPB = data.into_inner();
let editor = manager.get_grid_editor(&params.value)?;
let group = editor.get_group().await?;
data_result(group)
}

View File

@ -37,7 +37,9 @@ pub fn create(grid_manager: Arc<GridManager>) -> Module {
.event(GridEvent::GetSelectOptionCellData, get_select_option_handler) .event(GridEvent::GetSelectOptionCellData, get_select_option_handler)
.event(GridEvent::UpdateSelectOptionCell, update_select_option_cell_handler) .event(GridEvent::UpdateSelectOptionCell, update_select_option_cell_handler)
// Date // Date
.event(GridEvent::UpdateDateCell, update_date_cell_handler); .event(GridEvent::UpdateDateCell, update_date_cell_handler)
// Group
.event(GridEvent::GetGroup, update_date_cell_handler);
module module
} }
@ -204,4 +206,7 @@ pub enum GridEvent {
/// will be used by the `update_cell` function. /// will be used by the `update_cell` function.
#[event(input = "DateChangesetPayloadPB")] #[event(input = "DateChangesetPayloadPB")]
UpdateDateCell = 80, UpdateDateCell = 80,
#[event(input = "GridIdPB", output = "RepeatedGridGroupPB")]
GetGroup = 100,
} }

View File

@ -61,7 +61,7 @@ pub fn apply_cell_data_changeset<C: ToString, T: AsRef<FieldRevision>>(
FieldType::SingleSelect => { FieldType::SingleSelect => {
SingleSelectTypeOptionPB::from(field_rev).apply_changeset(changeset.into(), cell_rev) SingleSelectTypeOptionPB::from(field_rev).apply_changeset(changeset.into(), cell_rev)
} }
FieldType::MultiSelect => MultiSelectTypeOption::from(field_rev).apply_changeset(changeset.into(), cell_rev), FieldType::MultiSelect => MultiSelectTypeOptionPB::from(field_rev).apply_changeset(changeset.into(), cell_rev),
FieldType::Checkbox => CheckboxTypeOption::from(field_rev).apply_changeset(changeset.into(), cell_rev), FieldType::Checkbox => CheckboxTypeOption::from(field_rev).apply_changeset(changeset.into(), cell_rev),
FieldType::URL => URLTypeOption::from(field_rev).apply_changeset(changeset.into(), cell_rev), FieldType::URL => URLTypeOption::from(field_rev).apply_changeset(changeset.into(), cell_rev),
}?; }?;
@ -109,7 +109,7 @@ pub fn try_decode_cell_data(
.get_type_option_entry::<SingleSelectTypeOptionPB>(field_type)? .get_type_option_entry::<SingleSelectTypeOptionPB>(field_type)?
.decode_cell_data(cell_data.into(), s_field_type, field_rev), .decode_cell_data(cell_data.into(), s_field_type, field_rev),
FieldType::MultiSelect => field_rev FieldType::MultiSelect => field_rev
.get_type_option_entry::<MultiSelectTypeOption>(field_type)? .get_type_option_entry::<MultiSelectTypeOptionPB>(field_type)?
.decode_cell_data(cell_data.into(), s_field_type, field_rev), .decode_cell_data(cell_data.into(), s_field_type, field_rev),
FieldType::Checkbox => field_rev FieldType::Checkbox => field_rev
.get_type_option_entry::<CheckboxTypeOption>(field_type)? .get_type_option_entry::<CheckboxTypeOption>(field_type)?

View File

@ -94,7 +94,7 @@ pub fn default_type_option_builder_from_type(field_type: &FieldType) -> Box<dyn
FieldType::Number => NumberTypeOption::default().into(), FieldType::Number => NumberTypeOption::default().into(),
FieldType::DateTime => DateTypeOption::default().into(), FieldType::DateTime => DateTypeOption::default().into(),
FieldType::SingleSelect => SingleSelectTypeOptionPB::default().into(), FieldType::SingleSelect => SingleSelectTypeOptionPB::default().into(),
FieldType::MultiSelect => MultiSelectTypeOption::default().into(), FieldType::MultiSelect => MultiSelectTypeOptionPB::default().into(),
FieldType::Checkbox => CheckboxTypeOption::default().into(), FieldType::Checkbox => CheckboxTypeOption::default().into(),
FieldType::URL => URLTypeOption::default().into(), FieldType::URL => URLTypeOption::default().into(),
}; };

View File

@ -14,16 +14,16 @@ use serde::{Deserialize, Serialize};
// Multiple select // Multiple select
#[derive(Clone, Debug, Default, Serialize, Deserialize, ProtoBuf)] #[derive(Clone, Debug, Default, Serialize, Deserialize, ProtoBuf)]
pub struct MultiSelectTypeOption { pub struct MultiSelectTypeOptionPB {
#[pb(index = 1)] #[pb(index = 1)]
pub options: Vec<SelectOptionPB>, pub options: Vec<SelectOptionPB>,
#[pb(index = 2)] #[pb(index = 2)]
pub disable_color: bool, pub disable_color: bool,
} }
impl_type_option!(MultiSelectTypeOption, FieldType::MultiSelect); impl_type_option!(MultiSelectTypeOptionPB, FieldType::MultiSelect);
impl SelectOptionOperation for MultiSelectTypeOption { impl SelectOptionOperation for MultiSelectTypeOptionPB {
fn selected_select_option(&self, cell_data: CellData<SelectOptionIds>) -> SelectOptionCellDataPB { fn selected_select_option(&self, cell_data: CellData<SelectOptionIds>) -> SelectOptionCellDataPB {
let select_options = make_selected_select_options(cell_data, &self.options); let select_options = make_selected_select_options(cell_data, &self.options);
SelectOptionCellDataPB { SelectOptionCellDataPB {
@ -41,7 +41,7 @@ impl SelectOptionOperation for MultiSelectTypeOption {
} }
} }
impl CellDataOperation<SelectOptionIds, SelectOptionCellChangeset> for MultiSelectTypeOption { impl CellDataOperation<SelectOptionIds, SelectOptionCellChangeset> for MultiSelectTypeOptionPB {
fn decode_cell_data( fn decode_cell_data(
&self, &self,
cell_data: CellData<SelectOptionIds>, cell_data: CellData<SelectOptionIds>,
@ -93,9 +93,9 @@ impl CellDataOperation<SelectOptionIds, SelectOptionCellChangeset> for MultiSele
} }
#[derive(Default)] #[derive(Default)]
pub struct MultiSelectTypeOptionBuilder(MultiSelectTypeOption); pub struct MultiSelectTypeOptionBuilder(MultiSelectTypeOptionPB);
impl_into_box_type_option_builder!(MultiSelectTypeOptionBuilder); impl_into_box_type_option_builder!(MultiSelectTypeOptionBuilder);
impl_builder_from_json_str_and_from_bytes!(MultiSelectTypeOptionBuilder, MultiSelectTypeOption); impl_builder_from_json_str_and_from_bytes!(MultiSelectTypeOptionBuilder, MultiSelectTypeOptionPB);
impl MultiSelectTypeOptionBuilder { impl MultiSelectTypeOptionBuilder {
pub fn option(mut self, opt: SelectOptionPB) -> Self { pub fn option(mut self, opt: SelectOptionPB) -> Self {
self.0.options.push(opt); self.0.options.push(opt);
@ -118,7 +118,7 @@ mod tests {
use crate::services::cell::CellDataOperation; use crate::services::cell::CellDataOperation;
use crate::services::field::type_options::selection_type_option::*; use crate::services::field::type_options::selection_type_option::*;
use crate::services::field::FieldBuilder; use crate::services::field::FieldBuilder;
use crate::services::field::{MultiSelectTypeOption, MultiSelectTypeOptionBuilder}; use crate::services::field::{MultiSelectTypeOptionBuilder, MultiSelectTypeOptionPB};
use flowy_grid_data_model::revision::FieldRevision; use flowy_grid_data_model::revision::FieldRevision;
#[test] #[test]
@ -136,7 +136,7 @@ mod tests {
.visibility(true) .visibility(true)
.build(); .build();
let type_option = MultiSelectTypeOption::from(&field_rev); let type_option = MultiSelectTypeOptionPB::from(&field_rev);
let option_ids = vec![google_option.id.clone(), facebook_option.id.clone()].join(SELECTION_IDS_SEPARATOR); let option_ids = vec![google_option.id.clone(), facebook_option.id.clone()].join(SELECTION_IDS_SEPARATOR);
let data = SelectOptionCellChangeset::from_insert(&option_ids).to_str(); let data = SelectOptionCellChangeset::from_insert(&option_ids).to_str();
@ -170,7 +170,7 @@ mod tests {
fn assert_multi_select_options( fn assert_multi_select_options(
cell_data: String, cell_data: String,
type_option: &MultiSelectTypeOption, type_option: &MultiSelectTypeOptionPB,
field_rev: &FieldRevision, field_rev: &FieldRevision,
expected: Vec<SelectOptionPB>, expected: Vec<SelectOptionPB>,
) { ) {

View File

@ -1,6 +1,6 @@
use crate::entities::{CellChangesetPB, FieldType, GridCellIdPB, GridCellIdParams}; use crate::entities::{CellChangesetPB, FieldType, GridCellIdPB, GridCellIdParams};
use crate::services::cell::{CellBytes, CellBytesParser, CellData, CellDisplayable, FromCellChangeset, FromCellString}; use crate::services::cell::{CellBytes, CellBytesParser, CellData, CellDisplayable, FromCellChangeset, FromCellString};
use crate::services::field::{MultiSelectTypeOption, SingleSelectTypeOptionPB}; use crate::services::field::{MultiSelectTypeOptionPB, SingleSelectTypeOptionPB};
use bytes::Bytes; use bytes::Bytes;
use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
use flowy_error::{internal_error, ErrorCode, FlowyResult}; use flowy_error::{internal_error, ErrorCode, FlowyResult};
@ -130,7 +130,7 @@ pub fn select_option_operation(field_rev: &FieldRevision) -> FlowyResult<Box<dyn
Ok(Box::new(type_option)) Ok(Box::new(type_option))
} }
FieldType::MultiSelect => { FieldType::MultiSelect => {
let type_option = MultiSelectTypeOption::from(field_rev); let type_option = MultiSelectTypeOptionPB::from(field_rev);
Ok(Box::new(type_option)) Ok(Box::new(type_option))
} }
ty => { ty => {

View File

@ -159,7 +159,7 @@ mod tests {
.option(google_option.clone()) .option(google_option.clone())
.option(facebook_option.clone()); .option(facebook_option.clone());
let multi_select_field_rev = FieldBuilder::new(multi_select).build(); let multi_select_field_rev = FieldBuilder::new(multi_select).build();
let multi_type_option = MultiSelectTypeOption::from(&multi_select_field_rev); let multi_type_option = MultiSelectTypeOptionPB::from(&multi_select_field_rev);
let cell_data = multi_type_option let cell_data = multi_type_option
.apply_changeset(cell_data_changeset.into(), None) .apply_changeset(cell_data_changeset.into(), None)
.unwrap(); .unwrap();

View File

@ -3,7 +3,7 @@ use crate::entities::{FieldType, GridBlockChangesetPB};
use crate::services::block_manager::GridBlockManager; use crate::services::block_manager::GridBlockManager;
use crate::services::cell::{AnyCellData, CellFilterOperation}; use crate::services::cell::{AnyCellData, CellFilterOperation};
use crate::services::field::{ use crate::services::field::{
CheckboxTypeOption, DateTypeOption, MultiSelectTypeOption, NumberTypeOption, RichTextTypeOption, CheckboxTypeOption, DateTypeOption, MultiSelectTypeOptionPB, NumberTypeOption, RichTextTypeOption,
SingleSelectTypeOptionPB, URLTypeOption, SingleSelectTypeOptionPB, URLTypeOption,
}; };
use crate::services::filter::filter_cache::{ use crate::services::filter::filter_cache::{
@ -22,8 +22,6 @@ use std::sync::Arc;
use tokio::sync::RwLock; use tokio::sync::RwLock;
pub(crate) struct GridFilterService { pub(crate) struct GridFilterService {
#[allow(dead_code)]
grid_id: String,
scheduler: Arc<dyn GridServiceTaskScheduler>, scheduler: Arc<dyn GridServiceTaskScheduler>,
grid_pad: Arc<RwLock<GridRevisionPad>>, grid_pad: Arc<RwLock<GridRevisionPad>>,
block_manager: Arc<GridBlockManager>, block_manager: Arc<GridBlockManager>,
@ -36,12 +34,10 @@ impl GridFilterService {
block_manager: Arc<GridBlockManager>, block_manager: Arc<GridBlockManager>,
scheduler: S, scheduler: S,
) -> Self { ) -> Self {
let grid_id = grid_pad.read().await.grid_id();
let scheduler = Arc::new(scheduler); let scheduler = Arc::new(scheduler);
let filter_cache = FilterCache::from_grid_pad(&grid_pad).await; let filter_cache = FilterCache::from_grid_pad(&grid_pad).await;
let filter_result_cache = FilterResultCache::new(); let filter_result_cache = FilterResultCache::new();
Self { Self {
grid_id,
grid_pad, grid_pad,
block_manager, block_manager,
scheduler, scheduler,
@ -134,8 +130,9 @@ impl GridFilterService {
} }
async fn notify(&self, changesets: Vec<GridBlockChangesetPB>) { async fn notify(&self, changesets: Vec<GridBlockChangesetPB>) {
let grid_id = self.grid_pad.read().await.grid_id();
for changeset in changesets { for changeset in changesets {
send_dart_notification(&self.grid_id, GridNotification::DidUpdateGridBlock) send_dart_notification(&grid_id, GridNotification::DidUpdateGridBlock)
.payload(changeset) .payload(changeset)
.send(); .send();
} }
@ -217,7 +214,7 @@ fn filter_cell(
FieldType::MultiSelect => filter_cache.select_option_filter.get(&filter_id).and_then(|filter| { FieldType::MultiSelect => filter_cache.select_option_filter.get(&filter_id).and_then(|filter| {
Some( Some(
field_rev field_rev
.get_type_option_entry::<MultiSelectTypeOption>(field_type_rev)? .get_type_option_entry::<MultiSelectTypeOptionPB>(field_type_rev)?
.apply_filter(any_cell_data, filter.value()) .apply_filter(any_cell_data, filter.value())
.ok(), .ok(),
) )

View File

@ -2,7 +2,7 @@
use crate::entities::{GridSelectOptionFilter, SelectOptionCondition}; use crate::entities::{GridSelectOptionFilter, SelectOptionCondition};
use crate::services::cell::{AnyCellData, CellFilterOperation}; use crate::services::cell::{AnyCellData, CellFilterOperation};
use crate::services::field::{MultiSelectTypeOption, SingleSelectTypeOptionPB}; use crate::services::field::{MultiSelectTypeOptionPB, SingleSelectTypeOptionPB};
use crate::services::field::{SelectOptionOperation, SelectedSelectOptions}; use crate::services::field::{SelectOptionOperation, SelectedSelectOptions};
use flowy_error::FlowyResult; use flowy_error::FlowyResult;
@ -39,7 +39,7 @@ impl GridSelectOptionFilter {
} }
} }
impl CellFilterOperation<GridSelectOptionFilter> for MultiSelectTypeOption { impl CellFilterOperation<GridSelectOptionFilter> for MultiSelectTypeOptionPB {
fn apply_filter(&self, any_cell_data: AnyCellData, filter: &GridSelectOptionFilter) -> FlowyResult<bool> { fn apply_filter(&self, any_cell_data: AnyCellData, filter: &GridSelectOptionFilter) -> FlowyResult<bool> {
if !any_cell_data.is_multi_select() { if !any_cell_data.is_multi_select() {
return Ok(true); return Ok(true);

View File

@ -61,7 +61,8 @@ impl GridRevisionEditor {
let block_manager = Arc::new(GridBlockManager::new(grid_id, &user, block_meta_revs, persistence).await?); let block_manager = Arc::new(GridBlockManager::new(grid_id, &user, block_meta_revs, persistence).await?);
let filter_service = let filter_service =
Arc::new(GridFilterService::new(grid_pad.clone(), block_manager.clone(), task_scheduler.clone()).await); Arc::new(GridFilterService::new(grid_pad.clone(), block_manager.clone(), task_scheduler.clone()).await);
let group_service = Arc::new(GridGroupService::new()); let group_service =
Arc::new(GridGroupService::new(grid_pad.clone(), block_manager.clone(), task_scheduler.clone()).await);
let editor = Arc::new(Self { let editor = Arc::new(Self {
grid_id: grid_id.to_owned(), grid_id: grid_id.to_owned(),
user, user,
@ -455,14 +456,14 @@ impl GridRevisionEditor {
Ok(grid_setting) Ok(grid_setting)
} }
pub async fn get_grid_filter(&self, layout_type: &GridLayoutType) -> FlowyResult<Vec<GridFilter>> { pub async fn get_grid_filter(&self, layout_type: &GridLayoutType) -> FlowyResult<Vec<GridFilterConfiguration>> {
let read_guard = self.grid_pad.read().await; let read_guard = self.grid_pad.read().await;
let layout_rev = layout_type.clone().into(); let layout_rev = layout_type.clone().into();
match read_guard.get_filters(Some(&layout_rev), None) { match read_guard.get_filters(Some(&layout_rev), None) {
Some(filter_revs) => Ok(filter_revs Some(filter_revs) => Ok(filter_revs
.iter() .iter()
.map(|filter_rev| filter_rev.as_ref().into()) .map(|filter_rev| filter_rev.as_ref().into())
.collect::<Vec<GridFilter>>()), .collect::<Vec<GridFilterConfiguration>>()),
None => Ok(vec![]), None => Ok(vec![]),
} }
} }
@ -561,6 +562,10 @@ impl GridRevisionEditor {
}) })
} }
pub async fn get_group(&self) -> FlowyResult<RepeatedGridGroupPB> {
todo!()
}
async fn modify<F>(&self, f: F) -> FlowyResult<()> async fn modify<F>(&self, f: F) -> FlowyResult<()>
where where
F: for<'a> FnOnce(&'a mut GridRevisionPad) -> FlowyResult<Option<GridChangeset>>, F: for<'a> FnOnce(&'a mut GridRevisionPad) -> FlowyResult<Option<GridChangeset>>,

View File

@ -1,7 +1,26 @@
pub struct GridGroupService {} use crate::services::block_manager::GridBlockManager;
use crate::services::grid_editor_task::GridServiceTaskScheduler;
use flowy_sync::client_grid::GridRevisionPad;
use std::sync::Arc;
use tokio::sync::RwLock;
pub(crate) struct GridGroupService {
scheduler: Arc<dyn GridServiceTaskScheduler>,
grid_pad: Arc<RwLock<GridRevisionPad>>,
block_manager: Arc<GridBlockManager>,
}
impl GridGroupService { impl GridGroupService {
pub fn new() -> Self { pub(crate) async fn new<S: GridServiceTaskScheduler>(
Self {} grid_pad: Arc<RwLock<GridRevisionPad>>,
block_manager: Arc<GridBlockManager>,
scheduler: S,
) -> Self {
let scheduler = Arc::new(scheduler);
Self {
scheduler,
grid_pad,
block_manager,
}
} }
} }

View File

@ -1,5 +1,6 @@
use crate::entities::{ use crate::entities::{
GridLayoutPB, GridLayoutType, GridSettingPB, RepeatedGridFilterPB, RepeatedGridGroupPB, RepeatedGridSortPB, GridLayoutPB, GridLayoutType, GridSettingPB, RepeatedGridConfigurationFilterPB, RepeatedGridGroupConfigurationPB,
RepeatedGridSortPB,
}; };
use flowy_grid_data_model::revision::{FieldRevision, GridSettingRevision}; use flowy_grid_data_model::revision::{FieldRevision, GridSettingRevision};
use flowy_sync::entities::grid::{CreateGridFilterParams, DeleteFilterParams, GridSettingChangesetParams}; use flowy_sync::entities::grid::{CreateGridFilterParams, DeleteFilterParams, GridSettingChangesetParams};
@ -43,21 +44,21 @@ impl GridSettingChangesetBuilder {
pub fn make_grid_setting(grid_setting_rev: &GridSettingRevision, field_revs: &[Arc<FieldRevision>]) -> GridSettingPB { pub fn make_grid_setting(grid_setting_rev: &GridSettingRevision, field_revs: &[Arc<FieldRevision>]) -> GridSettingPB {
let current_layout_type: GridLayoutType = grid_setting_rev.layout.clone().into(); let current_layout_type: GridLayoutType = grid_setting_rev.layout.clone().into();
let filters_by_field_id = grid_setting_rev let filters_by_field_id = grid_setting_rev
.get_all_filter(field_revs) .get_all_filters(field_revs)
.map(|filters_by_field_id| { .map(|filters_by_field_id| {
filters_by_field_id filters_by_field_id
.into_iter() .into_iter()
.map(|(k, v)| (k, v.into())) .map(|(k, v)| (k, v.into()))
.collect::<HashMap<String, RepeatedGridFilterPB>>() .collect::<HashMap<String, RepeatedGridConfigurationFilterPB>>()
}) })
.unwrap_or_default(); .unwrap_or_default();
let groups_by_field_id = grid_setting_rev let groups_by_field_id = grid_setting_rev
.get_all_group() .get_all_groups(field_revs)
.map(|groups_by_field_id| { .map(|groups_by_field_id| {
groups_by_field_id groups_by_field_id
.into_iter() .into_iter()
.map(|(k, v)| (k, v.into())) .map(|(k, v)| (k, v.into()))
.collect::<HashMap<String, RepeatedGridGroupPB>>() .collect::<HashMap<String, RepeatedGridGroupConfigurationPB>>()
}) })
.unwrap_or_default(); .unwrap_or_default();
let sorts_by_field_id = grid_setting_rev let sorts_by_field_id = grid_setting_rev
@ -73,8 +74,8 @@ pub fn make_grid_setting(grid_setting_rev: &GridSettingRevision, field_revs: &[A
GridSettingPB { GridSettingPB {
layouts: GridLayoutPB::all(), layouts: GridLayoutPB::all(),
current_layout_type, current_layout_type,
filters_by_field_id, filter_configuration_by_field_id: filters_by_field_id,
groups_by_field_id, group_configuration_by_field_id: groups_by_field_id,
sorts_by_field_id, sorts_by_field_id,
} }
} }

View File

@ -2,7 +2,7 @@ use flowy_grid::entities::FieldType;
use std::sync::Arc; use std::sync::Arc;
use flowy_grid::services::field::{ use flowy_grid::services::field::{
DateCellChangesetPB, MultiSelectTypeOption, SelectOptionPB, SingleSelectTypeOptionPB, SELECTION_IDS_SEPARATOR, DateCellChangesetPB, MultiSelectTypeOptionPB, SelectOptionPB, SingleSelectTypeOptionPB, SELECTION_IDS_SEPARATOR,
}; };
use flowy_grid::services::row::RowRevisionBuilder; use flowy_grid::services::row::RowRevisionBuilder;
use flowy_grid_data_model::revision::{FieldRevision, RowRevision}; use flowy_grid_data_model::revision::{FieldRevision, RowRevision};
@ -87,7 +87,7 @@ impl<'a> GridRowTestBuilder<'a> {
F: Fn(Vec<SelectOptionPB>) -> Vec<SelectOptionPB>, F: Fn(Vec<SelectOptionPB>) -> Vec<SelectOptionPB>,
{ {
let multi_select_field = self.field_rev_with_type(&FieldType::MultiSelect); let multi_select_field = self.field_rev_with_type(&FieldType::MultiSelect);
let type_option = MultiSelectTypeOption::from(&multi_select_field); let type_option = MultiSelectTypeOptionPB::from(&multi_select_field);
let options = f(type_option.options); let options = f(type_option.options);
let ops_ids = options let ops_ids = options
.iter() .iter()

View File

@ -3,7 +3,7 @@ use crate::grid::cell_test::script::GridCellTest;
use crate::grid::field_test::util::make_date_cell_string; use crate::grid::field_test::util::make_date_cell_string;
use flowy_grid::entities::{CellChangesetPB, FieldType}; use flowy_grid::entities::{CellChangesetPB, FieldType};
use flowy_grid::services::field::selection_type_option::SelectOptionCellChangeset; use flowy_grid::services::field::selection_type_option::SelectOptionCellChangeset;
use flowy_grid::services::field::{MultiSelectTypeOption, SingleSelectTypeOptionPB}; use flowy_grid::services::field::{MultiSelectTypeOptionPB, SingleSelectTypeOptionPB};
#[tokio::test] #[tokio::test]
async fn grid_cell_update() { async fn grid_cell_update() {
@ -28,7 +28,7 @@ async fn grid_cell_update() {
SelectOptionCellChangeset::from_insert(&type_option.options.first().unwrap().id).to_str() SelectOptionCellChangeset::from_insert(&type_option.options.first().unwrap().id).to_str()
} }
FieldType::MultiSelect => { FieldType::MultiSelect => {
let type_option = MultiSelectTypeOption::from(field_rev); let type_option = MultiSelectTypeOptionPB::from(field_rev);
SelectOptionCellChangeset::from_insert(&type_option.options.first().unwrap().id).to_str() SelectOptionCellChangeset::from_insert(&type_option.options.first().unwrap().id).to_str()
} }
FieldType::Checkbox => "1".to_string(), FieldType::Checkbox => "1".to_string(),

View File

@ -75,7 +75,7 @@ impl GridEditorTest {
.row_revs .row_revs
} }
pub async fn grid_filters(&self) -> Vec<GridFilter> { pub async fn grid_filters(&self) -> Vec<GridFilterConfiguration> {
let layout_type = GridLayoutType::Table; let layout_type = GridLayoutType::Table;
self.editor.get_grid_filter(&layout_type).await.unwrap() self.editor.get_grid_filter(&layout_type).await.unwrap()
} }

View File

@ -2,7 +2,7 @@ use crate::grid::script::EditorScript::*;
use crate::grid::script::*; use crate::grid::script::*;
use chrono::NaiveDateTime; use chrono::NaiveDateTime;
use flowy_grid::services::field::{ use flowy_grid::services::field::{
DateCellContentChangeset, DateCellData, MultiSelectTypeOption, SelectOption, SelectOptionCellContentChangeset, DateCellContentChangeset, DateCellData, MultiSelectTypeOptionPB, SelectOption, SelectOptionCellContentChangeset,
SingleSelectTypeOption, SELECTION_IDS_SEPARATOR, SingleSelectTypeOption, SELECTION_IDS_SEPARATOR,
}; };
use flowy_grid::services::row::{decode_cell_data_from_type_option_cell_data, CreateRowMetaBuilder}; use flowy_grid::services::row::{decode_cell_data_from_type_option_cell_data, CreateRowMetaBuilder};
@ -250,7 +250,7 @@ async fn grid_row_add_cells_test() {
builder.add_select_option_cell(&field.id, option.id.clone()).unwrap(); builder.add_select_option_cell(&field.id, option.id.clone()).unwrap();
} }
FieldType::MultiSelect => { FieldType::MultiSelect => {
let type_option = MultiSelectTypeOption::from(field); let type_option = MultiSelectTypeOptionPB::from(field);
let ops_ids = type_option let ops_ids = type_option
.options .options
.iter() .iter()
@ -327,7 +327,7 @@ async fn grid_cell_update() {
SelectOptionCellContentChangeset::from_insert(&type_option.options.first().unwrap().id).to_str() SelectOptionCellContentChangeset::from_insert(&type_option.options.first().unwrap().id).to_str()
} }
FieldType::MultiSelect => { FieldType::MultiSelect => {
let type_option = MultiSelectTypeOption::from(field_meta); let type_option = MultiSelectTypeOptionPB::from(field_meta);
SelectOptionCellContentChangeset::from_insert(&type_option.options.first().unwrap().id).to_str() SelectOptionCellContentChangeset::from_insert(&type_option.options.first().unwrap().id).to_str()
} }
FieldType::Checkbox => "1".to_string(), FieldType::Checkbox => "1".to_string(),

1
shared-lib/Cargo.lock generated
View File

@ -436,6 +436,7 @@ dependencies = [
"serde", "serde",
"serde_json", "serde_json",
"serde_repr", "serde_repr",
"tracing",
] ]
[[package]] [[package]]

View File

@ -13,6 +13,7 @@ serde_repr = "0.1"
nanoid = "0.4.0" nanoid = "0.4.0"
flowy-error-code = { path = "../flowy-error-code"} flowy-error-code = { path = "../flowy-error-code"}
indexmap = {version = "1.8.1", features = ["serde"]} indexmap = {version = "1.8.1", features = ["serde"]}
tracing = { version = "0.1", features = ["log"] }
[build-dependencies] [build-dependencies]
lib-infra = { path = "../lib-infra", features = ["protobuf_file_gen"] } lib-infra = { path = "../lib-infra", features = ["protobuf_file_gen"] }

View File

@ -1,7 +1,4 @@
use crate::revision::FieldTypeRevision;
use indexmap::IndexMap;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::sync::Arc;
#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq, Hash)]
pub struct GridFilterRevision { pub struct GridFilterRevision {

View File

@ -1,7 +1,4 @@
use crate::revision::FieldTypeRevision;
use indexmap::IndexMap;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::sync::Arc;
#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)] #[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
pub struct GridGroupRevision { pub struct GridGroupRevision {

View File

@ -1,5 +1,5 @@
use crate::revision::filter_rev::GridFilterRevision; use crate::revision::filter_rev::GridFilterRevision;
use crate::revision::group_rev::GridGroupRevision; use crate::revision::grid_group::GridGroupRevision;
use crate::revision::{FieldRevision, FieldTypeRevision}; use crate::revision::{FieldRevision, FieldTypeRevision};
use indexmap::IndexMap; use indexmap::IndexMap;
use nanoid::nanoid; use nanoid::nanoid;
@ -21,28 +21,28 @@ pub fn gen_grid_sort_id() -> String {
nanoid!(6) nanoid!(6)
} }
pub type GridFilters = SettingContainer<GridFilterRevision>;
pub type GridFilterRevisionMap = GridObjectRevisionMap<GridFilterRevision>;
pub type FiltersByFieldId = HashMap<String, Vec<Arc<GridFilterRevision>>>;
//
pub type GridGroups = SettingContainer<GridGroupRevision>;
pub type GridGroupRevisionMap = GridObjectRevisionMap<GridGroupRevision>;
pub type GroupsByFieldId = HashMap<String, Vec<Arc<GridGroupRevision>>>;
//
pub type GridSorts = SettingContainer<GridSortRevision>;
pub type GridSortRevisionMap = GridObjectRevisionMap<GridSortRevision>;
pub type SortsByFieldId = HashMap<String, Vec<Arc<GridSortRevision>>>;
#[derive(Debug, Clone, Serialize, Deserialize, Default, Eq, PartialEq)] #[derive(Debug, Clone, Serialize, Deserialize, Default, Eq, PartialEq)]
pub struct GridSettingRevision { pub struct GridSettingRevision {
pub layout: GridLayoutRevision, pub layout: GridLayoutRevision,
/// Each layout contains multiple key/value. pub filters: GridFilters,
/// Key: field_id
/// Value: this value contains key/value.
/// Key: FieldType,
/// Value: the corresponding filters.
#[serde(with = "indexmap::serde_seq")]
filters: IndexMap<GridLayoutRevision, IndexMap<String, GridFilterRevisionMap>>,
/// Each layout contains multiple key/value. pub groups: GridGroups,
/// Key: field_id
/// Value: this value contains key/value.
/// Key: FieldType,
/// Value: the corresponding groups.
#[serde(skip, with = "indexmap::serde_seq")]
pub groups: IndexMap<GridLayoutRevision, IndexMap<String, GridGroupRevisionMap>>,
#[serde(skip, with = "indexmap::serde_seq")] #[serde(skip)]
pub sorts: IndexMap<GridLayoutRevision, Vec<GridSortRevision>>, pub sorts: GridSorts,
} }
#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize_repr, Deserialize_repr)] #[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize_repr, Deserialize_repr)]
@ -65,12 +65,18 @@ impl std::default::Default for GridLayoutRevision {
} }
} }
pub type FiltersByFieldId = HashMap<String, Vec<Arc<GridFilterRevision>>>;
pub type GroupsByFieldId = HashMap<String, Vec<Arc<GridGroupRevision>>>;
pub type SortsByFieldId = HashMap<String, Vec<Arc<GridSortRevision>>>;
impl GridSettingRevision { impl GridSettingRevision {
pub fn get_all_group(&self) -> Option<GroupsByFieldId> { pub fn get_all_groups(&self, field_revs: &[Arc<FieldRevision>]) -> Option<GroupsByFieldId> {
None self.groups.get_all_objects(&self.layout, field_revs)
}
pub fn get_groups(
&self,
layout: &GridLayoutRevision,
field_id: &str,
field_type_rev: &FieldTypeRevision,
) -> Option<Vec<Arc<GridGroupRevision>>> {
self.groups.get_objects(layout, field_id, field_type_rev)
} }
pub fn get_mut_groups( pub fn get_mut_groups(
@ -79,10 +85,7 @@ impl GridSettingRevision {
field_id: &str, field_id: &str,
field_type: &FieldTypeRevision, field_type: &FieldTypeRevision,
) -> Option<&mut Vec<Arc<GridGroupRevision>>> { ) -> Option<&mut Vec<Arc<GridGroupRevision>>> {
self.groups self.groups.get_mut_objects(layout, field_id, field_type)
.get_mut(layout)
.and_then(|group_rev_map_by_field_id| group_rev_map_by_field_id.get_mut(field_id))
.and_then(|group_rev_map| group_rev_map.get_mut(field_type))
} }
pub fn insert_group( pub fn insert_group(
@ -90,59 +93,13 @@ impl GridSettingRevision {
layout: &GridLayoutRevision, layout: &GridLayoutRevision,
field_id: &str, field_id: &str,
field_type: &FieldTypeRevision, field_type: &FieldTypeRevision,
filter_rev: GridGroupRevision, group_rev: GridGroupRevision,
) { ) {
let filter_rev_map_by_field_id = self.groups.entry(layout.clone()).or_insert_with(IndexMap::new); self.groups.insert_object(layout, field_id, field_type, group_rev);
let filter_rev_map = filter_rev_map_by_field_id
.entry(field_id.to_string())
.or_insert_with(GridGroupRevisionMap::new);
filter_rev_map
.entry(field_type.to_owned())
.or_insert_with(Vec::new)
.push(Arc::new(filter_rev))
} }
pub fn get_all_sort(&self) -> Option<SortsByFieldId> { pub fn get_all_filters(&self, field_revs: &[Arc<FieldRevision>]) -> Option<FiltersByFieldId> {
None self.filters.get_all_objects(&self.layout, field_revs)
}
/// Return the Filters of the current layout
pub fn get_all_filter(&self, field_revs: &[Arc<FieldRevision>]) -> Option<FiltersByFieldId> {
let layout = &self.layout;
// Acquire the read lock of the filters.
let filter_rev_map_by_field_id = self.filters.get(layout)?;
// Get the filters according to the FieldType, so we need iterate the field_revs.
let filters_by_field_id = field_revs
.iter()
.flat_map(|field_rev| {
let field_type = &field_rev.field_type_rev;
let field_id = &field_rev.id;
let filter_rev_map: &GridFilterRevisionMap = filter_rev_map_by_field_id.get(field_id)?;
let filters: Vec<Arc<GridFilterRevision>> = filter_rev_map.get(field_type)?.clone();
Some((field_rev.id.clone(), filters))
})
.collect::<FiltersByFieldId>();
Some(filters_by_field_id)
}
#[allow(dead_code)]
fn get_filter_rev_map(&self, layout: &GridLayoutRevision, field_id: &str) -> Option<&GridFilterRevisionMap> {
let filter_rev_map_by_field_id = self.filters.get(layout)?;
filter_rev_map_by_field_id.get(field_id)
}
pub fn get_mut_filters(
&mut self,
layout: &GridLayoutRevision,
field_id: &str,
field_type: &FieldTypeRevision,
) -> Option<&mut Vec<Arc<GridFilterRevision>>> {
self.filters
.get_mut(layout)
.and_then(|filter_rev_map_by_field_id| filter_rev_map_by_field_id.get_mut(field_id))
.and_then(|filter_rev_map| filter_rev_map.get_mut(field_type))
} }
pub fn get_filters( pub fn get_filters(
@ -151,11 +108,16 @@ impl GridSettingRevision {
field_id: &str, field_id: &str,
field_type_rev: &FieldTypeRevision, field_type_rev: &FieldTypeRevision,
) -> Option<Vec<Arc<GridFilterRevision>>> { ) -> Option<Vec<Arc<GridFilterRevision>>> {
self.filters self.filters.get_objects(layout, field_id, field_type_rev)
.get(layout) }
.and_then(|filter_rev_map_by_field_id| filter_rev_map_by_field_id.get(field_id))
.and_then(|filter_rev_map| filter_rev_map.get(field_type_rev)) pub fn get_mut_filters(
.cloned() &mut self,
layout: &GridLayoutRevision,
field_id: &str,
field_type: &FieldTypeRevision,
) -> Option<&mut Vec<Arc<GridFilterRevision>>> {
self.filters.get_mut_objects(layout, field_id, field_type)
} }
pub fn insert_filter( pub fn insert_filter(
@ -165,15 +127,11 @@ impl GridSettingRevision {
field_type: &FieldTypeRevision, field_type: &FieldTypeRevision,
filter_rev: GridFilterRevision, filter_rev: GridFilterRevision,
) { ) {
let filter_rev_map_by_field_id = self.filters.entry(layout.clone()).or_insert_with(IndexMap::new); self.filters.insert_object(layout, field_id, field_type, filter_rev);
let filter_rev_map = filter_rev_map_by_field_id }
.entry(field_id.to_string())
.or_insert_with(GridFilterRevisionMap::new);
filter_rev_map pub fn get_all_sort(&self) -> Option<SortsByFieldId> {
.entry(field_type.to_owned()) None
.or_insert_with(Vec::new)
.push(Arc::new(filter_rev))
} }
} }
@ -183,8 +141,94 @@ pub struct GridSortRevision {
pub field_id: Option<String>, pub field_id: Option<String>,
} }
pub type GridFilterRevisionMap = GridObjectRevisionMap<GridFilterRevision>; #[derive(Debug, Clone, Serialize, Deserialize, Default, Eq, PartialEq)]
pub type GridGroupRevisionMap = GridObjectRevisionMap<GridGroupRevision>; #[serde(transparent)]
pub struct SettingContainer<T>
where
T: Debug + Clone + Default + Eq + PartialEq + serde::Serialize + serde::de::DeserializeOwned + 'static,
{
/// Each layout contains multiple key/value.
/// Key: field_id
/// Value: this value contains key/value.
/// Key: FieldType,
/// Value: the corresponding objects.
#[serde(with = "indexmap::serde_seq")]
inner: IndexMap<GridLayoutRevision, IndexMap<String, GridObjectRevisionMap<T>>>,
}
impl<T> SettingContainer<T>
where
T: Debug + Clone + Default + Eq + PartialEq + serde::Serialize + serde::de::DeserializeOwned + 'static,
{
pub fn get_mut_objects(
&mut self,
layout: &GridLayoutRevision,
field_id: &str,
field_type: &FieldTypeRevision,
) -> Option<&mut Vec<Arc<T>>> {
let value = self
.inner
.get_mut(layout)
.and_then(|object_rev_map_by_field_id| object_rev_map_by_field_id.get_mut(field_id))
.and_then(|object_rev_map| object_rev_map.get_mut(field_type));
if value.is_none() {
tracing::warn!("Can't find the {:?} with", std::any::type_name::<T>());
}
value
}
pub fn get_objects(
&self,
layout: &GridLayoutRevision,
field_id: &str,
field_type_rev: &FieldTypeRevision,
) -> Option<Vec<Arc<T>>> {
self.inner
.get(layout)
.and_then(|object_rev_map_by_field_id| object_rev_map_by_field_id.get(field_id))
.and_then(|object_rev_map| object_rev_map.get(field_type_rev))
.cloned()
}
pub fn get_all_objects(
&self,
layout: &GridLayoutRevision,
field_revs: &[Arc<FieldRevision>],
) -> Option<HashMap<String, Vec<Arc<T>>>> {
// Acquire the read lock.
let object_rev_map_by_field_id = self.inner.get(layout)?;
// Get the objects according to the FieldType, so we need iterate the field_revs.
let objects_by_field_id = field_revs
.iter()
.flat_map(|field_rev| {
let field_type = &field_rev.field_type_rev;
let field_id = &field_rev.id;
let object_rev_map = object_rev_map_by_field_id.get(field_id)?;
let objects: Vec<Arc<T>> = object_rev_map.get(field_type)?.clone();
Some((field_rev.id.clone(), objects))
})
.collect::<HashMap<String, Vec<Arc<T>>>>();
Some(objects_by_field_id)
}
pub fn insert_object(
&mut self,
layout: &GridLayoutRevision,
field_id: &str,
field_type: &FieldTypeRevision,
object: T,
) {
let object_rev_map_by_field_id = self.inner.entry(layout.clone()).or_insert_with(IndexMap::new);
let object_rev_map = object_rev_map_by_field_id
.entry(field_id.to_string())
.or_insert_with(GridObjectRevisionMap::<T>::new);
object_rev_map
.entry(field_type.to_owned())
.or_insert_with(Vec::new)
.push(Arc::new(object))
}
}
#[derive(Debug, Clone, Serialize, Deserialize, Default, Eq, PartialEq)] #[derive(Debug, Clone, Serialize, Deserialize, Default, Eq, PartialEq)]
#[serde(transparent)] #[serde(transparent)]

View File

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

View File

@ -457,7 +457,6 @@ mod tests {
AppRevision, FolderRevision, TrashRevision, ViewRevision, WorkspaceRevision, AppRevision, FolderRevision, TrashRevision, ViewRevision, WorkspaceRevision,
}; };
use lib_ot::core::{OperationTransform, TextDelta, TextDeltaBuilder}; use lib_ot::core::{OperationTransform, TextDelta, TextDeltaBuilder};
use serde_json::json;
#[test] #[test]
fn folder_add_workspace() { fn folder_add_workspace() {

View File

@ -1,4 +1,6 @@
use crate::entities::grid::{FieldChangesetParams, GridSettingChangesetParams}; use crate::entities::grid::{
CreateGridFilterParams, CreateGridGroupParams, FieldChangesetParams, GridSettingChangesetParams,
};
use crate::entities::revision::{md5, RepeatedRevision, Revision}; use crate::entities::revision::{md5, RepeatedRevision, Revision};
use crate::errors::{internal_error, CollaborateError, CollaborateResult}; use crate::errors::{internal_error, CollaborateError, CollaborateResult};
use crate::util::{cal_diff, make_delta_from_revisions}; use crate::util::{cal_diff, make_delta_from_revisions};
@ -380,88 +382,65 @@ impl GridRevisionPad {
self.modify_grid(|grid_rev| { self.modify_grid(|grid_rev| {
let mut is_changed = None; let mut is_changed = None;
let layout_rev = changeset.layout_type; let layout_rev = changeset.layout_type;
if let Some(params) = changeset.insert_filter { if let Some(params) = changeset.insert_filter {
let filter_rev = GridFilterRevision { grid_rev.setting.insert_filter(
id: gen_grid_filter_id(), &layout_rev,
field_id: params.field_id.clone(), &params.field_id,
condition: params.condition, &params.field_type_rev,
content: params.content, make_filter_revision(&params),
}; );
grid_rev
.setting
.insert_filter(&layout_rev, &params.field_id, &params.field_type_rev, filter_rev);
is_changed = Some(()) is_changed = Some(())
} }
if let Some(params) = changeset.delete_filter { if let Some(params) = changeset.delete_filter {
match grid_rev if let Some(filters) =
.setting grid_rev
.get_mut_filters(&layout_rev, &params.field_id, &params.field_type_rev) .setting
.get_mut_filters(&layout_rev, &params.field_id, &params.field_type_rev)
{ {
Some(filters) => { filters.retain(|filter| filter.id != params.filter_id);
filters.retain(|filter| filter.id != params.filter_id);
}
None => {
tracing::warn!("Can't find the filter with {:?}", layout_rev);
}
} }
} }
if let Some(params) = changeset.insert_group { if let Some(params) = changeset.insert_group {
let group_rev = GridGroupRevision { grid_rev.setting.insert_group(
id: gen_grid_group_id(), &layout_rev,
field_id: params.field_id.clone(), &params.field_id,
sub_field_id: params.sub_field_id, &params.field_type_rev,
}; make_group_revision(&params),
);
grid_rev
.setting
.insert_group(&layout_rev, &params.field_id, &params.field_type_rev, group_rev);
is_changed = Some(()); is_changed = Some(());
} }
if let Some(params) = changeset.delete_group { if let Some(params) = changeset.delete_group {
// match grid_rev.setting.groups.get_mut(&layout_rev) { if let Some(groups) =
// Some(groups) => groups.retain(|group| group.id != delete_group_id), grid_rev
// None => { .setting
// tracing::warn!("Can't find the group with {:?}", layout_rev); .get_mut_groups(&layout_rev, &params.field_id, &params.field_type_rev)
// }
// }
match grid_rev
.setting
.get_mut_groups(&layout_rev, &params.field_id, &params.field_type_rev)
{ {
Some(groups) => { groups.retain(|filter| filter.id != params.group_id);
groups.retain(|filter| filter.id != params.group_id);
}
None => {
tracing::warn!("Can't find the group with {:?}", layout_rev);
}
} }
} }
if let Some(sort) = changeset.insert_sort { if let Some(sort) = changeset.insert_sort {
let rev = GridSortRevision { // let rev = GridSortRevision {
id: gen_grid_sort_id(), // id: gen_grid_sort_id(),
field_id: sort.field_id, // field_id: sort.field_id,
}; // };
//
grid_rev // grid_rev
.setting // .setting
.sorts // .sorts
.entry(layout_rev.clone()) // .entry(layout_rev.clone())
.or_insert_with(std::vec::Vec::new) // .or_insert_with(std::vec::Vec::new)
.push(rev); // .push(rev);
is_changed = Some(()) is_changed = Some(())
} }
if let Some(delete_sort_id) = changeset.delete_sort { if let Some(delete_sort_id) = changeset.delete_sort {
match grid_rev.setting.sorts.get_mut(&layout_rev) { // match grid_rev.setting.sorts.get_mut(&layout_rev) {
Some(sorts) => sorts.retain(|sort| sort.id != delete_sort_id), // Some(sorts) => sorts.retain(|sort| sort.id != delete_sort_id),
None => { // None => {
tracing::warn!("Can't find the sort with {:?}", layout_rev); // tracing::warn!("Can't find the sort with {:?}", layout_rev);
} // }
} // }
} }
Ok(is_changed) Ok(is_changed)
}) })
@ -579,3 +558,20 @@ impl std::default::Default for GridRevisionPad {
} }
} }
} }
fn make_filter_revision(params: &CreateGridFilterParams) -> GridFilterRevision {
GridFilterRevision {
id: gen_grid_filter_id(),
field_id: params.field_id.clone(),
condition: params.condition.clone(),
content: params.content.clone(),
}
}
fn make_group_revision(params: &CreateGridGroupParams) -> GridGroupRevision {
GridGroupRevision {
id: gen_grid_group_id(),
field_id: params.field_id.clone(),
sub_field_id: params.sub_field_id.clone(),
}
}