chore: refactor group gen process

This commit is contained in:
appflowy 2022-09-01 20:41:15 +08:00
parent 1931cdd4c0
commit f192f89ebb
22 changed files with 554 additions and 662 deletions

View File

@ -0,0 +1,7 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10 2H13C13.5523 2 14 2.44772 14 3V6" stroke="#333333" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M6 2H3C2.44772 2 2 2.44772 2 3V6" stroke="#333333" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M6 14H3C2.44772 14 2 13.5523 2 13V10" stroke="#333333" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M10 14H13C13.5523 14 14 13.5523 14 13V10" stroke="#333333" stroke-linecap="round" stroke-linejoin="round"/>
<rect x="6" y="6" width="4" height="4" rx="1" stroke="#333333"/>
</svg>

After

Width:  |  Height:  |  Size: 620 B

View File

@ -160,7 +160,8 @@
"settings": {
"filter": "Filter",
"sortBy": "Sort by",
"Properties": "Properties"
"Properties": "Properties",
"group": "Group"
},
"field": {
"hide": "Hide",

View File

@ -43,4 +43,5 @@ class BoardSettingState with _$BoardSettingState {
enum BoardSettingAction {
properties,
groups,
}

View File

@ -95,6 +95,12 @@ class BoardSettingList extends StatelessWidget {
fieldCache: settingContext.fieldCache)
.show(context);
break;
case BoardSettingAction.groups:
GridPropertyList(
gridId: settingContext.viewId,
fieldCache: settingContext.fieldCache)
.show(context);
break;
}
},
);
@ -156,6 +162,8 @@ extension _GridSettingExtension on BoardSettingAction {
switch (this) {
case BoardSettingAction.properties:
return 'grid/setting/properties';
case BoardSettingAction.groups:
return 'grid/setting/group';
}
}
@ -163,6 +171,8 @@ extension _GridSettingExtension on BoardSettingAction {
switch (this) {
case BoardSettingAction.properties:
return LocaleKeys.grid_settings_Properties.tr();
case BoardSettingAction.groups:
return LocaleKeys.grid_settings_group.tr();
}
}
}

View File

@ -0,0 +1,27 @@
import 'package:flowy_infra/theme.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class GridGroupList extends StatelessWidget {
const GridGroupList({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container();
}
}
class _GridGroupCell extends StatelessWidget {
const _GridGroupCell({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final theme = context.watch<AppTheme>();
// final checkmark = field.visibility
// ? svgWidget('home/show', color: theme.iconColor)
// : svgWidget('home/hide', color: theme.iconColor);
return Container();
}
}

View File

@ -91,6 +91,9 @@ pub struct GroupPB {
#[pb(index = 5)]
pub is_default: bool,
#[pb(index = 6)]
pub is_visible: bool,
}
impl std::convert::From<Group> for GroupPB {
@ -101,6 +104,7 @@ impl std::convert::From<Group> for GroupPB {
desc: group.name,
rows: group.rows,
is_default: group.is_default,
is_visible: group.is_visible,
}
}
}

View File

@ -133,6 +133,9 @@ pub struct GroupViewChangesetPB {
#[pb(index = 2)]
pub inserted_groups: Vec<InsertedGroupPB>,
#[pb(index = 2)]
pub new_groups: Vec<GroupPB>,
#[pb(index = 3)]
pub deleted_groups: Vec<String>,

View File

@ -7,7 +7,7 @@ use crate::entities::{
use crate::services::grid_editor_task::GridServiceTaskScheduler;
use crate::services::grid_view_manager::{GridViewFieldDelegate, GridViewRowDelegate};
use crate::services::group::{
make_group_controller, GroupConfigurationReader, GroupConfigurationWriter, GroupController, GroupService,
make_group_controller, GroupConfigurationReader, GroupConfigurationWriter, GroupController, MoveGroupRowContext,
};
use flowy_error::{FlowyError, FlowyResult};
use flowy_grid_data_model::revision::{
@ -20,8 +20,6 @@ use flowy_sync::entities::revision::Revision;
use lib_infra::future::{wrap_future, AFFuture, FutureResult};
use std::collections::HashMap;
use std::future::Future;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use tokio::sync::RwLock;
@ -87,18 +85,16 @@ impl GridViewRevisionEditor {
}
pub(crate) async fn will_create_row(&self, row_rev: &mut RowRevision, params: &CreateRowParams) {
match params.group_id.as_ref() {
None => {}
Some(group_id) => {
self.group_service
.write()
.await
.will_create_row(row_rev, group_id, |field_id| {
self.field_delegate.get_field_rev(&field_id)
})
.await;
}
if params.group_id.is_none() {
return;
}
let group_id = params.group_id.as_ref().unwrap();
let _ = self
.mut_group_controller(|group_controller, field_rev| {
group_controller.will_create_row(row_rev, &field_rev, group_id);
Ok(())
})
.await;
}
pub(crate) async fn did_create_row(&self, row_pb: &RowPB, params: &CreateRowParams) {
@ -123,58 +119,29 @@ impl GridViewRevisionEditor {
pub(crate) async fn did_delete_row(&self, row_rev: &RowRevision) {
// Send the group notification if the current view has groups;
let group_field_id = self.group_controller.read().await.field_id().to_owned();
let field_rev = self.field_delegate.get_field_rev(&group_field_id).await;
field_rev.and_then(|field_rev| {
if let Some(changesets) = self
.group_controller
.write()
.await
.did_delete_row(row_rev, &field_rev)
.await
{
for changeset in changesets {
self.notify_did_update_group(changeset).await;
}
}
None
});
}
let changesets = self
.mut_group_controller(|group_controller, field_rev| group_controller.did_delete_row(row_rev, &field_rev))
.await;
pub(crate) async fn did_update_row(&self, row_rev: &RowRevision) {
let changeset = self
.mut_group_controller(|group_controller, field_rev| async {
group_controller.did_update_row(row_rev, &field_rev).await
})
.await?;
if let Some(changeset) = changeset {
if let Some(changesets) = changesets {
for changeset in changesets {
self.notify_did_update_group(changeset).await;
}
}
}
async fn mut_group_controller<F, O, T>(&self, f: F) -> Option<T>
where
F: FnOnce(&mut Box<dyn GroupController>, Arc<FieldRevision>) -> O,
O: Future<Output = Option<T>> + Send + Sync + 'static,
{
let group_field_id = self.group_controller.read().await.field_id().to_owned();
match self.field_delegate.get_field_rev(&group_field_id).await {
None => None,
Some(field_rev) => {
let mut write_guard = self.group_controller.write().await;
Some(f(&mut write_guard, field_rev).await)
pub(crate) async fn did_update_row(&self, row_rev: &RowRevision) {
let changesets = self
.mut_group_controller(|group_controller, field_rev| group_controller.did_update_row(row_rev, &field_rev))
.await;
if let Some(changesets) = changesets {
for changeset in changesets {
self.notify_did_update_group(changeset).await;
}
}
}
async fn get_group_field_rev(&self) -> Option<Arc<FieldRevision>> {
let group_field_id = self.group_controller.read().await.field_id().to_owned();
self.field_delegate.get_field_rev(&group_field_id).await
}
pub(crate) async fn move_group_row(
&self,
row_rev: &RowRevision,
@ -182,54 +149,38 @@ impl GridViewRevisionEditor {
to_group_id: &str,
to_row_id: Option<String>,
) -> Vec<GroupChangesetPB> {
match self
.group_service
.write()
.await
.move_group_row(row_rev, row_changeset, to_group_id, to_row_id, |field_id| {
self.field_delegate.get_field_rev(&field_id)
let changesets = self
.mut_group_controller(|group_controller, field_rev| {
let move_row_context = MoveGroupRowContext {
row_rev,
row_changeset,
field_rev: field_rev.as_ref(),
to_group_id,
to_row_id,
};
let changesets = group_controller.move_group_row(move_row_context)?;
Ok(changesets)
})
.await
{
None => vec![],
Some(changesets) => changesets,
}
.await;
changesets.unwrap_or_default()
}
/// Only call once after grid view editor initialized
#[tracing::instrument(level = "trace", skip(self))]
pub(crate) async fn load_groups(&self) -> FlowyResult<Vec<GroupPB>> {
let groups = if !self.did_load_group.load(Ordering::SeqCst) {
self.did_load_group.store(true, Ordering::SeqCst);
let field_revs = self.field_delegate.get_field_revs().await;
let row_revs = self.row_delegate.gv_row_revs().await;
match self
.group_service
.write()
.await
.load_groups(&field_revs, row_revs)
.await
{
None => vec![],
Some(groups) => groups,
}
} else {
self.group_service.read().await.groups().await
};
let groups = self.group_controller.read().await.groups();
tracing::trace!("Number of groups: {}", groups.len());
Ok(groups.into_iter().map(GroupPB::from).collect())
}
pub(crate) async fn move_group(&self, params: MoveGroupParams) -> FlowyResult<()> {
let _ = self
.group_service
.group_controller
.write()
.await
.move_group(&params.from_group_id, &params.to_group_id)
.await?;
match self.group_service.read().await.get_group(&params.from_group_id).await {
.move_group(&params.from_group_id, &params.to_group_id)?;
match self.group_controller.read().await.get_group(&params.from_group_id) {
None => {}
Some((index, group)) => {
let inserted_group = InsertedGroupPB {
@ -242,6 +193,7 @@ impl GridViewRevisionEditor {
inserted_groups: vec![inserted_group],
deleted_groups: vec![params.from_group_id.clone()],
update_groups: vec![],
new_groups: vec![],
};
self.notify_did_update_view(changeset).await;
@ -296,7 +248,7 @@ impl GridViewRevisionEditor {
#[tracing::instrument(level = "trace", skip_all, err)]
pub(crate) async fn did_update_field(&self, field_id: &str) -> FlowyResult<()> {
if let Some(field_rev) = self.field_delegate.get_field_rev(field_id).await {
match self.group_service.write().await.did_update_field(&field_rev).await? {
match self.group_controller.write().await.did_update_field(&field_rev)? {
None => {}
Some(changeset) => {
self.notify_did_update_view(changeset).await;
@ -331,6 +283,36 @@ impl GridViewRevisionEditor {
}
Ok(())
}
async fn mut_group_controller<F, T>(&self, f: F) -> Option<T>
where
F: FnOnce(&mut Box<dyn GroupController>, Arc<FieldRevision>) -> FlowyResult<T>,
{
let group_field_id = self.group_controller.read().await.field_id().to_owned();
match self.field_delegate.get_field_rev(&group_field_id).await {
None => None,
Some(field_rev) => {
let mut write_guard = self.group_controller.write().await;
f(&mut write_guard, field_rev).ok()
}
}
}
#[allow(dead_code)]
async fn async_mut_group_controller<F, O, T>(&self, f: F) -> Option<T>
where
F: FnOnce(Arc<RwLock<Box<dyn GroupController>>>, Arc<FieldRevision>) -> O,
O: Future<Output = FlowyResult<T>> + Sync + 'static,
{
let group_field_id = self.group_controller.read().await.field_id().to_owned();
match self.field_delegate.get_field_rev(&group_field_id).await {
None => None,
Some(field_rev) => {
let _write_guard = self.group_controller.write().await;
f(self.group_controller.clone(), field_rev).await.ok()
}
}
}
}
async fn apply_change(
@ -371,10 +353,7 @@ impl RevisionObjectBuilder for GridViewRevisionPadBuilder {
struct GroupConfigurationReaderImpl(Arc<RwLock<GridViewRevisionPad>>);
impl GroupConfigurationReader for GroupConfigurationReaderImpl {
fn get_group_configuration(
&self,
field_rev: Arc<FieldRevision>,
) -> AFFuture<Option<Arc<GroupConfigurationRevision>>> {
fn get_configuration(&self, field_rev: Arc<FieldRevision>) -> AFFuture<Option<Arc<GroupConfigurationRevision>>> {
let view_pad = self.0.clone();
wrap_future(async move {
let mut groups = view_pad.read().await.groups.get_objects(&field_rev.id, &field_rev.ty)?;
@ -395,7 +374,7 @@ struct GroupConfigurationWriterImpl {
}
impl GroupConfigurationWriter for GroupConfigurationWriterImpl {
fn save_group_configuration(
fn save_configuration(
&self,
field_id: &str,
field_type: FieldTypeRevision,

View File

@ -1,24 +1,22 @@
use crate::entities::{GroupPB, GroupViewChangesetPB, InsertedGroupPB};
use crate::services::group::{default_group_configuration, Group};
use crate::services::group::{default_group_configuration, GeneratedGroup, Group};
use flowy_error::{FlowyError, FlowyResult};
use flowy_grid_data_model::revision::{
FieldRevision, FieldTypeRevision, GroupConfigurationContentSerde, GroupConfigurationRevision, GroupRevision,
};
use indexmap::IndexMap;
use lib_infra::future::AFFuture;
use std::collections::HashMap;
use std::fmt::Formatter;
use std::marker::PhantomData;
use std::sync::Arc;
pub trait GroupConfigurationReader: Send + Sync + 'static {
fn get_group_configuration(
&self,
field_rev: Arc<FieldRevision>,
) -> AFFuture<Option<Arc<GroupConfigurationRevision>>>;
fn get_configuration(&self, field_rev: Arc<FieldRevision>) -> AFFuture<Option<Arc<GroupConfigurationRevision>>>;
}
pub trait GroupConfigurationWriter: Send + Sync + 'static {
fn save_group_configuration(
fn save_configuration(
&self,
field_id: &str,
field_type: FieldTypeRevision,
@ -26,7 +24,7 @@ pub trait GroupConfigurationWriter: Send + Sync + 'static {
) -> AFFuture<FlowyResult<()>>;
}
impl<T> std::fmt::Display for GenericGroupConfiguration<T> {
impl<T> std::fmt::Display for GroupContext<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
self.groups_map.iter().for_each(|(_, group)| {
let _ = f.write_fmt(format_args!("Group:{} has {} rows \n", group.id, group.rows.len()));
@ -39,7 +37,7 @@ impl<T> std::fmt::Display for GenericGroupConfiguration<T> {
}
}
pub struct GenericGroupConfiguration<C> {
pub struct GroupContext<C> {
view_id: String,
pub configuration: Arc<GroupConfigurationRevision>,
configuration_content: PhantomData<C>,
@ -50,7 +48,7 @@ pub struct GenericGroupConfiguration<C> {
writer: Arc<dyn GroupConfigurationWriter>,
}
impl<C> GenericGroupConfiguration<C>
impl<C> GroupContext<C>
where
C: GroupConfigurationContentSerde,
{
@ -67,16 +65,17 @@ where
field_id: field_rev.id.clone(),
name: format!("No {}", field_rev.name),
is_default: true,
is_visible: true,
rows: vec![],
content: "".to_string(),
filter_content: "".to_string(),
};
let configuration = match reader.get_group_configuration(field_rev.clone()).await {
let configuration = match reader.get_configuration(field_rev.clone()).await {
None => {
let default_group_configuration = default_group_configuration(&field_rev);
let default_configuration = default_group_configuration(&field_rev);
writer
.save_group_configuration(&field_rev.id, field_rev.ty, default_group_configuration.clone())
.save_configuration(&field_rev.id, field_rev.ty, default_configuration.clone())
.await?;
Arc::new(default_group_configuration)
Arc::new(default_configuration)
}
Some(configuration) => configuration,
};
@ -134,47 +133,100 @@ where
}
}
pub(crate) fn merge_groups(&mut self, groups: Vec<Group>) -> FlowyResult<Option<GroupViewChangesetPB>> {
pub(crate) fn init_group_revs(
&mut self,
generated_groups: Vec<GeneratedGroup>,
) -> FlowyResult<Option<GroupViewChangesetPB>> {
let mut new_groups = vec![];
let mut filter_content_map = HashMap::new();
generated_groups.into_iter().for_each(|generate_group| {
filter_content_map.insert(generate_group.group_rev.id.clone(), generate_group.filter_content);
new_groups.push(generate_group.group_rev);
});
let MergeGroupResult {
groups,
inserted_groups,
updated_groups,
} = merge_groups(&self.configuration.groups, groups);
mut all_group_revs,
new_group_revs,
updated_group_revs: _,
deleted_group_revs,
} = merge_groups(&self.configuration.groups, new_groups);
let group_revs = groups
let deleted_group_ids = deleted_group_revs
.iter()
.map(|group| GroupRevision::new(group.id.clone(), group.name.clone()))
.collect::<Vec<GroupRevision>>();
.map(|group_rev| group_rev.id)
.collect::<Vec<String>>();
self.mut_configuration(move |configuration| {
self.mut_configuration(|configuration| {
let mut is_changed = false;
for new_group_rev in group_revs {
if !deleted_group_ids.is_empty() {
configuration
.groups
.retain(|group| !deleted_group_ids.contains(&group.id));
is_changed = true;
}
for mut group_rev in &mut all_group_revs {
match configuration
.groups
.iter()
.position(|group_rev| group_rev.id == new_group_rev.id)
.position(|old_group_rev| old_group_rev.id == group_rev.id)
{
None => {
configuration.groups.push(new_group_rev);
configuration.groups.push(group_rev.clone());
is_changed = true;
}
Some(pos) => {
let removed_group = configuration.groups.remove(pos);
if removed_group != new_group_rev {
let mut old_group = configuration.groups.remove(pos);
// Update the group configuration base on the GroupRevision
group_rev.visible = old_group.visible;
// Take the GroupRevision if the name has changed
if is_group_changed(&group_rev, &old_group) {
old_group.name = group_rev.name.clone();
is_changed = true;
configuration.groups.insert(pos, old_group);
}
configuration.groups.insert(pos, new_group_rev);
}
}
}
is_changed
})?;
groups.into_iter().for_each(|group| {
self.groups_map.insert(group.id.clone(), group);
debug_assert_eq!(filter_content_map.len(), all_group_revs.len());
all_group_revs.into_iter().for_each(|group_rev| {
if let Some(filter_content) = filter_content_map.get(&group_rev.id) {
let group = Group::new(
group_rev.id,
self.field_rev.id.clone(),
group_rev.name,
filter_content.clone(),
);
self.groups_map.insert(group.id.clone(), group);
}
});
let changeset = make_group_view_changeset(self.view_id.clone(), inserted_groups, updated_groups);
let new_groups = new_group_revs
.into_iter()
.map(|group_rev| {
if let Some(filter_content) = filter_content_map.get(&group_rev.id) {
let group = Group::new(
group_rev.id,
self.field_rev.id.clone(),
group_rev.name,
filter_content.clone(),
);
GroupPB::from(group)
}
})
.collect();
let changeset = GroupViewChangesetPB {
view_id,
new_groups,
deleted_groups: deleted_group_ids,
update_groups: vec![],
inserted_groups: vec![],
};
tracing::trace!("Group changeset: {:?}", changeset);
if changeset.is_empty() {
Ok(None)
@ -221,10 +273,7 @@ where
let field_id = self.field_rev.id.clone();
let field_type = self.field_rev.ty;
tokio::spawn(async move {
match writer
.save_group_configuration(&field_id, field_type, configuration)
.await
{
match writer.save_configuration(&field_id, field_type, configuration).await {
Ok(_) => {}
Err(e) => {
tracing::error!("Save group configuration failed: {}", e);
@ -260,82 +309,63 @@ where
}
}
fn merge_groups(old_groups: &[GroupRevision], groups: Vec<Group>) -> MergeGroupResult {
fn merge_groups(old_groups: &[GroupRevision], new_groups: Vec<GroupRevision>) -> MergeGroupResult {
let mut merge_result = MergeGroupResult::new();
if old_groups.is_empty() {
merge_result.groups = groups;
merge_result.all_group_revs = new_groups;
return merge_result;
}
// group_map is a helper map is used to filter out the new groups.
let mut group_map: IndexMap<String, Group> = IndexMap::new();
groups.into_iter().for_each(|group| {
group_map.insert(group.id.clone(), group);
let mut new_group_map: IndexMap<String, GroupRevision> = IndexMap::new();
new_groups.into_iter().for_each(|group_rev| {
new_group_map.insert(group_rev.id.clone(), group_rev);
});
// The group is ordered in old groups. Add them before adding the new groups
for group_rev in old_groups {
if let Some(group) = group_map.remove(&group_rev.id) {
if group.name == group_rev.name {
merge_result.add_group(group);
} else {
merge_result.add_updated_group(group);
for old in old_groups {
if let Some(new) = new_group_map.remove(&old.id) {
merge_result.all_group_revs.push(new.clone());
if is_group_changed(&new, old) {
merge_result.updated_group_revs.push(new);
}
} else {
merge_result.deleted_group_revs.push(old.clone());
}
}
// Find out the new groups
group_map
.into_values()
.enumerate()
.for_each(|(index, group)| merge_result.add_insert_group(index, group));
let new_groups = new_group_map.into_values();
for (_, group) in new_groups.into_iter().enumerate() {
merge_result.all_group_revs.push(group.clone());
merge_result.new_group_revs.push(group);
}
merge_result
}
fn is_group_changed(new: &GroupRevision, old: &GroupRevision) -> bool {
if new.name != old.name {
return true;
}
false
}
struct MergeGroupResult {
groups: Vec<Group>,
inserted_groups: Vec<InsertedGroupPB>,
updated_groups: Vec<Group>,
// Contains the new groups and the updated groups
all_group_revs: Vec<GroupRevision>,
new_group_revs: Vec<GroupRevision>,
updated_group_revs: Vec<GroupRevision>,
deleted_group_revs: Vec<GroupRevision>,
}
impl MergeGroupResult {
fn new() -> Self {
Self {
groups: vec![],
inserted_groups: vec![],
updated_groups: vec![],
all_group_revs: vec![],
new_group_revs: vec![],
updated_group_revs: vec![],
deleted_group_revs: vec![],
}
}
fn add_updated_group(&mut self, group: Group) {
self.groups.push(group.clone());
self.updated_groups.push(group);
}
fn add_group(&mut self, group: Group) {
self.groups.push(group);
}
fn add_insert_group(&mut self, index: usize, group: Group) {
self.groups.push(group.clone());
let inserted_group = InsertedGroupPB {
group: GroupPB::from(group),
index: index as i32,
};
self.inserted_groups.push(inserted_group);
}
}
fn make_group_view_changeset(
view_id: String,
inserted_groups: Vec<InsertedGroupPB>,
updated_group: Vec<Group>,
) -> GroupViewChangesetPB {
GroupViewChangesetPB {
view_id,
inserted_groups,
deleted_groups: vec![],
update_groups: updated_group.into_iter().map(GroupPB::from).collect(),
}
}

View File

@ -1,11 +1,11 @@
use crate::entities::{GroupChangesetPB, GroupViewChangesetPB, InsertedRowPB, RowPB};
use crate::services::cell::{decode_any_cell_data, CellBytesParser};
use crate::services::group::action::GroupAction;
use crate::services::group::configuration::GenericGroupConfiguration;
use crate::services::group::configuration::GroupContext;
use crate::services::group::entities::Group;
use flowy_error::FlowyResult;
use flowy_grid_data_model::revision::{
FieldRevision, GroupConfigurationContentSerde, RowChangeset, RowRevision, TypeOptionDataDeserializer,
FieldRevision, GroupConfigurationContentSerde, GroupRevision, RowChangeset, RowRevision, TypeOptionDataDeserializer,
};
use std::marker::PhantomData;
@ -19,14 +19,19 @@ pub trait GroupController: GroupControllerSharedOperation + Send + Sync {
}
pub trait GroupGenerator {
type ConfigurationType;
type Context;
type TypeOptionType;
fn generate_groups(
field_id: &str,
configuration: &Self::ConfigurationType,
group_ctx: &Self::Context,
type_option: &Option<Self::TypeOptionType>,
) -> Vec<Group>;
) -> Vec<GeneratedGroup>;
}
pub struct GeneratedGroup {
pub group_rev: GroupRevision,
pub filter_content: String,
}
pub struct MoveGroupRowContext<'a> {
@ -43,7 +48,7 @@ pub trait GroupControllerSharedOperation: Send + Sync {
fn field_id(&self) -> &str;
fn groups(&self) -> Vec<Group>;
fn get_group(&self, group_id: &str) -> Option<(usize, Group)>;
fn fill_groups(&mut self, row_revs: &[Arc<RowRevision>], field_rev: &FieldRevision) -> FlowyResult<Vec<Group>>;
fn fill_groups(&mut self, row_revs: &[Arc<RowRevision>], field_rev: &FieldRevision) -> FlowyResult<()>;
fn move_group(&mut self, from_group_id: &str, to_group_id: &str) -> FlowyResult<()>;
fn did_update_row(
&mut self,
@ -69,7 +74,7 @@ pub trait GroupControllerSharedOperation: Send + Sync {
pub struct GenericGroupController<C, T, G, P> {
pub field_id: String,
pub type_option: Option<T>,
pub configuration: GenericGroupConfiguration<C>,
pub configuration: GroupContext<C>,
group_action_phantom: PhantomData<G>,
cell_parser_phantom: PhantomData<P>,
}
@ -78,16 +83,13 @@ impl<C, T, G, P> GenericGroupController<C, T, G, P>
where
C: GroupConfigurationContentSerde,
T: TypeOptionDataDeserializer,
G: GroupGenerator<ConfigurationType = GenericGroupConfiguration<C>, TypeOptionType = T>,
G: GroupGenerator<Context = GroupContext<C>, TypeOptionType = T>,
{
pub async fn new(
field_rev: &Arc<FieldRevision>,
mut configuration: GenericGroupConfiguration<C>,
) -> FlowyResult<Self> {
pub async fn new(field_rev: &Arc<FieldRevision>, mut configuration: GroupContext<C>) -> FlowyResult<Self> {
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);
let _ = configuration.merge_groups(groups)?;
let _ = configuration.init_group_revs(groups)?;
Ok(Self {
field_id: field_rev.id.clone(),
@ -171,7 +173,7 @@ where
P: CellBytesParser,
C: GroupConfigurationContentSerde,
T: TypeOptionDataDeserializer,
G: GroupGenerator<ConfigurationType = GenericGroupConfiguration<C>, TypeOptionType = T>,
G: GroupGenerator<Context = GroupContext<C>, TypeOptionType = T>,
Self: GroupAction<CellDataType = P::Object>,
{
@ -189,14 +191,14 @@ where
}
#[tracing::instrument(level = "trace", skip_all, fields(row_count=%row_revs.len(), group_result))]
fn fill_groups(&mut self, row_revs: &[Arc<RowRevision>], field_rev: &FieldRevision) -> FlowyResult<Vec<Group>> {
fn fill_groups(&mut self, row_revs: &[Arc<RowRevision>], field_rev: &FieldRevision) -> FlowyResult<()> {
for row_rev in row_revs {
if let Some(cell_rev) = row_rev.cells.get(&self.field_id) {
let mut grouped_rows: Vec<GroupedRow> = 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.configuration.concrete_groups() {
if self.can_group(&group.content, &cell_data) {
if self.can_group(&group.filter_content, &cell_data) {
grouped_rows.push(GroupedRow {
row: row_rev.into(),
group_id: group.id.clone(),
@ -219,7 +221,7 @@ where
}
tracing::Span::current().record("group_result", &format!("{},", self.configuration,).as_str());
Ok(self.groups())
Ok(())
}
fn move_group(&mut self, from_group_id: &str, to_group_id: &str) -> FlowyResult<()> {
@ -274,7 +276,7 @@ where
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, &self.configuration, &type_option);
let changeset = self.configuration.merge_groups(groups)?;
let changeset = self.configuration.init_group_revs(groups)?;
Ok(changeset)
}
}

View File

@ -1,13 +1,14 @@
use crate::entities::GroupChangesetPB;
use crate::services::field::{CheckboxCellData, CheckboxCellDataParser, CheckboxTypeOptionPB, CHECK, UNCHECK};
use crate::services::group::action::GroupAction;
use crate::services::group::configuration::GenericGroupConfiguration;
use crate::services::group::configuration::GroupContext;
use crate::services::group::controller::{
GenericGroupController, GroupController, GroupGenerator, MoveGroupRowContext,
};
use crate::services::group::entities::Group;
use flowy_grid_data_model::revision::{CheckboxGroupConfigurationRevision, FieldRevision, RowRevision};
use crate::services::group::GeneratedGroup;
use flowy_grid_data_model::revision::{CheckboxGroupConfigurationRevision, FieldRevision, GroupRevision, RowRevision};
pub type CheckboxGroupController = GenericGroupController<
CheckboxGroupConfigurationRevision,
@ -16,7 +17,7 @@ pub type CheckboxGroupController = GenericGroupController<
CheckboxCellDataParser,
>;
pub type CheckboxGroupConfiguration = GenericGroupConfiguration<CheckboxGroupConfigurationRevision>;
pub type CheckboxGroupContext = GroupContext<CheckboxGroupConfigurationRevision>;
impl GroupAction for CheckboxGroupController {
type CellDataType = CheckboxCellData;
@ -49,26 +50,23 @@ impl GroupController for CheckboxGroupController {
pub struct CheckboxGroupGenerator();
impl GroupGenerator for CheckboxGroupGenerator {
type ConfigurationType = CheckboxGroupConfiguration;
type Context = CheckboxGroupContext;
type TypeOptionType = CheckboxTypeOptionPB;
fn generate_groups(
field_id: &str,
_configuration: &Self::ConfigurationType,
_type_option: &Option<Self::TypeOptionType>,
) -> Vec<Group> {
let check_group = Group::new(
"true".to_string(),
field_id.to_owned(),
"".to_string(),
CHECK.to_string(),
);
let uncheck_group = Group::new(
"false".to_string(),
field_id.to_owned(),
"".to_string(),
UNCHECK.to_string(),
);
group_ctx: &Self::Context,
type_option: &Option<Self::TypeOptionType>,
) -> Vec<GeneratedGroup> {
let check_group = GeneratedGroup {
group_rev: GroupRevision::new("true".to_string(), CHECK.to_string()),
filter_content: "".to_string(),
};
let uncheck_group = GeneratedGroup {
group_rev: GroupRevision::new("false".to_string(), UNCHECK.to_string()),
filter_content: "".to_string(),
};
vec![check_group, uncheck_group]
}
}

View File

@ -0,0 +1,80 @@
use crate::entities::{GroupChangesetPB, GroupViewChangesetPB, RowPB};
use crate::services::group::{Group, GroupController, GroupControllerSharedOperation, MoveGroupRowContext};
use flowy_error::FlowyResult;
use flowy_grid_data_model::revision::{FieldRevision, RowRevision};
use std::sync::Arc;
pub struct DefaultGroupController {
pub field_id: String,
pub group: Group,
}
const DEFAULT_GROUP_CONTROLLER: &str = "DefaultGroupController";
impl DefaultGroupController {
pub fn new(field_rev: &Arc<FieldRevision>) -> Self {
let group = Group::new(
DEFAULT_GROUP_CONTROLLER.to_owned(),
field_rev.id.clone(),
"Oops".to_owned(),
"".to_owned(),
);
Self {
field_id: field_rev.id.clone(),
group,
}
}
}
impl GroupControllerSharedOperation for DefaultGroupController {
fn field_id(&self) -> &str {
&self.field_id
}
fn groups(&self) -> Vec<Group> {
vec![self.group.clone()]
}
fn get_group(&self, group_id: &str) -> Option<(usize, Group)> {
Some((0, self.group.clone()))
}
fn fill_groups(&mut self, row_revs: &[Arc<RowRevision>], field_rev: &FieldRevision) -> FlowyResult<()> {
row_revs.iter().for_each(|row_rev| {
self.group.add_row(RowPB::from(row_rev));
});
Ok(())
}
fn move_group(&mut self, from_group_id: &str, to_group_id: &str) -> FlowyResult<()> {
Ok(())
}
fn did_update_row(
&mut self,
row_rev: &RowRevision,
field_rev: &FieldRevision,
) -> FlowyResult<Vec<GroupChangesetPB>> {
todo!()
}
fn did_delete_row(
&mut self,
row_rev: &RowRevision,
field_rev: &FieldRevision,
) -> FlowyResult<Vec<GroupChangesetPB>> {
todo!()
}
fn move_group_row(&mut self, context: MoveGroupRowContext) -> FlowyResult<Vec<GroupChangesetPB>> {
todo!()
}
fn did_update_field(&mut self, field_rev: &FieldRevision) -> FlowyResult<Option<GroupViewChangesetPB>> {
Ok(None)
}
}
impl GroupController for DefaultGroupController {
fn will_create_row(&mut self, row_rev: &mut RowRevision, field_rev: &FieldRevision, group_id: &str) {}
}

View File

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

View File

@ -8,7 +8,10 @@ use crate::services::group::controller::{
};
use crate::services::group::controller_impls::select_option_controller::util::*;
use crate::services::group::entities::Group;
use flowy_grid_data_model::revision::{FieldRevision, RowRevision, SelectOptionGroupConfigurationRevision};
use crate::services::group::GeneratedGroup;
use flowy_grid_data_model::revision::{
FieldRevision, GroupRevision, RowRevision, SelectOptionGroupConfigurationRevision,
};
// MultiSelect
pub type MultiSelectGroupController = GenericGroupController<
@ -28,7 +31,7 @@ impl GroupAction for MultiSelectGroupController {
fn add_row_if_match(&mut self, row_rev: &RowRevision, cell_data: &Self::CellDataType) -> Vec<GroupChangesetPB> {
let mut changesets = vec![];
self.configuration.iter_mut_groups(|group| {
if let Some(changeset) = add_row(group, cell_data, row_rev) {
if let Some(changeset) = add_select_option_row(group, cell_data, row_rev) {
changesets.push(changeset);
}
});
@ -38,7 +41,7 @@ impl GroupAction for MultiSelectGroupController {
fn remove_row_if_match(&mut self, row_rev: &RowRevision, cell_data: &Self::CellDataType) -> Vec<GroupChangesetPB> {
let mut changesets = vec![];
self.configuration.iter_mut_groups(|group| {
if let Some(changeset) = remove_row(group, cell_data, row_rev) {
if let Some(changeset) = remove_select_option_row(group, cell_data, row_rev) {
changesets.push(changeset);
}
});
@ -70,27 +73,16 @@ impl GroupController for MultiSelectGroupController {
pub struct MultiSelectGroupGenerator();
impl GroupGenerator for MultiSelectGroupGenerator {
type ConfigurationType = SelectOptionGroupConfiguration;
type Context = SelectOptionGroupContext;
type TypeOptionType = MultiSelectTypeOptionPB;
fn generate_groups(
field_id: &str,
_configuration: &Self::ConfigurationType,
group_ctx: &Self::Context,
type_option: &Option<Self::TypeOptionType>,
) -> Vec<Group> {
) -> Vec<GeneratedGroup> {
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(),
Some(type_option) => generate_select_option_groups(field_id, group_ctx, &type_option.options),
}
}
}

View File

@ -9,7 +9,10 @@ use crate::services::group::controller::{
use crate::services::group::controller_impls::select_option_controller::util::*;
use crate::services::group::entities::Group;
use flowy_grid_data_model::revision::{FieldRevision, RowRevision, SelectOptionGroupConfigurationRevision};
use crate::services::group::GeneratedGroup;
use flowy_grid_data_model::revision::{
FieldRevision, GroupRevision, RowRevision, SelectOptionGroupConfigurationRevision,
};
// SingleSelect
pub type SingleSelectGroupController = GenericGroupController<
@ -28,7 +31,7 @@ impl GroupAction for SingleSelectGroupController {
fn add_row_if_match(&mut self, row_rev: &RowRevision, cell_data: &Self::CellDataType) -> Vec<GroupChangesetPB> {
let mut changesets = vec![];
self.configuration.iter_mut_groups(|group| {
if let Some(changeset) = add_row(group, cell_data, row_rev) {
if let Some(changeset) = add_select_option_row(group, cell_data, row_rev) {
changesets.push(changeset);
}
});
@ -38,7 +41,7 @@ impl GroupAction for SingleSelectGroupController {
fn remove_row_if_match(&mut self, row_rev: &RowRevision, cell_data: &Self::CellDataType) -> Vec<GroupChangesetPB> {
let mut changesets = vec![];
self.configuration.iter_mut_groups(|group| {
if let Some(changeset) = remove_row(group, cell_data, row_rev) {
if let Some(changeset) = remove_select_option_row(group, cell_data, row_rev) {
changesets.push(changeset);
}
});
@ -72,27 +75,16 @@ impl GroupController for SingleSelectGroupController {
pub struct SingleSelectGroupGenerator();
impl GroupGenerator for SingleSelectGroupGenerator {
type ConfigurationType = SelectOptionGroupConfiguration;
type Context = SelectOptionGroupContext;
type TypeOptionType = SingleSelectTypeOptionPB;
fn generate_groups(
field_id: &str,
_configuration: &Self::ConfigurationType,
group_ctx: &Self::Context,
type_option: &Option<Self::TypeOptionType>,
) -> Vec<Group> {
) -> Vec<GeneratedGroup> {
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(),
Some(type_option) => generate_select_option_groups(field_id, group_ctx, &type_option.options),
}
}
}

View File

@ -1,15 +1,15 @@
use crate::entities::{GroupChangesetPB, InsertedRowPB, RowPB};
use crate::services::cell::insert_select_option_cell;
use crate::services::field::SelectOptionCellDataPB;
use crate::services::group::configuration::GenericGroupConfiguration;
use crate::services::group::Group;
use crate::services::field::{SelectOptionCellDataPB, SelectOptionPB};
use crate::services::group::configuration::GroupContext;
use crate::services::group::{GeneratedGroup, Group};
use crate::services::group::controller::MoveGroupRowContext;
use flowy_grid_data_model::revision::{RowRevision, SelectOptionGroupConfigurationRevision};
use flowy_grid_data_model::revision::{GroupRevision, RowRevision, SelectOptionGroupConfigurationRevision};
pub type SelectOptionGroupConfiguration = GenericGroupConfiguration<SelectOptionGroupConfigurationRevision>;
pub type SelectOptionGroupContext = GroupContext<SelectOptionGroupConfigurationRevision>;
pub fn add_row(
pub fn add_select_option_row(
group: &mut Group,
cell_data: &SelectOptionCellDataPB,
row_rev: &RowRevision,
@ -42,7 +42,7 @@ pub fn add_row(
}
}
pub fn remove_row(
pub fn remove_select_option_row(
group: &mut Group,
cell_data: &SelectOptionCellDataPB,
row_rev: &RowRevision,
@ -125,3 +125,19 @@ pub fn move_select_option_row(
Some(changeset)
}
}
pub fn generate_select_option_groups(
field_id: &str,
group_ctx: &SelectOptionGroupContext,
options: &[SelectOptionPB],
) -> Vec<GeneratedGroup> {
let groups = options
.iter()
.map(|option| GeneratedGroup {
group_rev: GroupRevision::new(option.id.clone(), option.name.clone()),
filter_content: option.id.clone(),
})
.collect();
groups
}

View File

@ -6,21 +6,23 @@ pub struct Group {
pub field_id: String,
pub name: String,
pub is_default: bool,
pub is_visible: bool,
pub(crate) rows: Vec<RowPB>,
/// [content] is used to determine which group the cell belongs to.
pub content: String,
pub filter_content: String,
}
impl Group {
pub fn new(id: String, field_id: String, name: String, content: String) -> Self {
pub fn new(id: String, field_id: String, name: String, filter_content: String) -> Self {
Self {
id,
field_id,
is_default: false,
is_visible: true,
name,
rows: vec![],
content,
filter_content,
}
}

View File

@ -1,361 +0,0 @@
use crate::entities::{FieldType, GroupChangesetPB, GroupViewChangesetPB};
use crate::services::group::configuration::GroupConfigurationReader;
use crate::services::group::controller::{GroupController, MoveGroupRowContext};
use crate::services::group::{
CheckboxGroupConfiguration, CheckboxGroupController, Group, GroupConfigurationWriter, MultiSelectGroupController,
SelectOptionGroupConfiguration, SingleSelectGroupController,
};
use flowy_error::FlowyResult;
use flowy_grid_data_model::revision::{
CheckboxGroupConfigurationRevision, DateGroupConfigurationRevision, FieldRevision, GroupConfigurationRevision,
NumberGroupConfigurationRevision, RowChangeset, RowRevision, SelectOptionGroupConfigurationRevision,
TextGroupConfigurationRevision, UrlGroupConfigurationRevision,
};
use std::future::Future;
use std::sync::Arc;
pub(crate) struct GroupService {
view_id: String,
configuration_reader: Arc<dyn GroupConfigurationReader>,
configuration_writer: Arc<dyn GroupConfigurationWriter>,
group_controller: Option<Box<dyn GroupController>>,
}
impl GroupService {
pub(crate) async fn new<R, W>(view_id: String, configuration_reader: R, configuration_writer: W) -> Self
where
R: GroupConfigurationReader,
W: GroupConfigurationWriter,
{
Self {
view_id,
configuration_reader: Arc::new(configuration_reader),
configuration_writer: Arc::new(configuration_writer),
group_controller: None,
}
}
pub(crate) async fn groups(&self) -> Vec<Group> {
self.group_controller
.as_ref()
.map(|group_controller| group_controller.groups())
.unwrap_or_default()
}
pub(crate) async fn get_group(&self, group_id: &str) -> Option<(usize, Group)> {
self.group_controller
.as_ref()
.and_then(|group_controller| group_controller.get_group(group_id))
}
pub(crate) async fn load_groups(
&mut self,
field_revs: &[Arc<FieldRevision>],
row_revs: Vec<Arc<RowRevision>>,
) -> Option<Vec<Group>> {
let field_rev = find_group_field(field_revs)?;
let field_type: FieldType = field_rev.ty.into();
let mut group_controller = self.make_group_controller(&field_type, &field_rev).await.ok()??;
let groups = match group_controller.fill_groups(&row_revs, &field_rev) {
Ok(groups) => groups,
Err(e) => {
tracing::error!("Fill groups failed:{:?}", e);
vec![]
}
};
self.group_controller = Some(group_controller);
Some(groups)
}
pub(crate) async fn will_create_row<F, O>(&mut self, row_rev: &mut RowRevision, group_id: &str, get_field_fn: F)
where
F: FnOnce(String) -> O,
O: Future<Output = Option<Arc<FieldRevision>>> + Send + Sync + 'static,
{
if let Some(group_controller) = self.group_controller.as_mut() {
let field_id = group_controller.field_id().to_owned();
match get_field_fn(field_id).await {
None => {}
Some(field_rev) => {
group_controller.will_create_row(row_rev, &field_rev, group_id);
}
}
}
}
pub(crate) async fn did_delete_row<F, O>(
&mut self,
row_rev: &RowRevision,
get_field_fn: F,
) -> Option<Vec<GroupChangesetPB>>
where
F: FnOnce(String) -> O,
O: Future<Output = Option<Arc<FieldRevision>>> + Send + Sync + 'static,
{
let group_controller = self.group_controller.as_mut()?;
let field_id = group_controller.field_id().to_owned();
let field_rev = get_field_fn(field_id).await?;
match group_controller.did_delete_row(row_rev, &field_rev) {
Ok(changesets) => Some(changesets),
Err(e) => {
tracing::error!("Delete group data failed, {:?}", e);
None
}
}
}
pub(crate) async fn move_group_row<F, O>(
&mut self,
row_rev: &RowRevision,
row_changeset: &mut RowChangeset,
to_group_id: &str,
to_row_id: Option<String>,
get_field_fn: F,
) -> Option<Vec<GroupChangesetPB>>
where
F: FnOnce(String) -> O,
O: Future<Output = Option<Arc<FieldRevision>>> + Send + Sync + 'static,
{
let group_controller = self.group_controller.as_mut()?;
let field_id = group_controller.field_id().to_owned();
let field_rev = get_field_fn(field_id).await?;
let move_row_context = MoveGroupRowContext {
row_rev,
row_changeset,
field_rev: field_rev.as_ref(),
to_group_id,
to_row_id,
};
match group_controller.move_group_row(move_row_context) {
Ok(changesets) => Some(changesets),
Err(e) => {
tracing::error!("Move group data failed, {:?}", e);
None
}
}
}
#[tracing::instrument(level = "trace", skip_all)]
pub(crate) async fn did_update_row<F, O>(
&mut self,
row_rev: &RowRevision,
get_field_fn: F,
) -> Option<Vec<GroupChangesetPB>>
where
F: FnOnce(String) -> O,
O: Future<Output = Option<Arc<FieldRevision>>> + Send + Sync + 'static,
{
let group_controller = self.group_controller.as_mut()?;
let field_id = group_controller.field_id().to_owned();
let field_rev = get_field_fn(field_id).await?;
match group_controller.did_update_row(row_rev, &field_rev) {
Ok(changeset) => Some(changeset),
Err(e) => {
tracing::error!("Update group data failed, {:?}", e);
None
}
}
}
#[tracing::instrument(level = "trace", skip_all)]
pub(crate) async fn move_group(&mut self, from_group_id: &str, to_group_id: &str) -> FlowyResult<()> {
match self.group_controller.as_mut() {
None => Ok(()),
Some(group_controller) => {
let _ = group_controller.move_group(from_group_id, to_group_id)?;
Ok(())
}
}
}
#[tracing::instrument(level = "trace", name = "group_did_update_field", skip(self, field_rev), err)]
pub(crate) async fn did_update_field(
&mut self,
field_rev: &FieldRevision,
) -> FlowyResult<Option<GroupViewChangesetPB>> {
match self.group_controller.as_mut() {
None => Ok(None),
Some(group_controller) => group_controller.did_update_field(field_rev),
}
}
#[tracing::instrument(level = "trace", skip(self, field_rev), err)]
async fn make_group_controller(
&self,
field_type: &FieldType,
field_rev: &Arc<FieldRevision>,
) -> FlowyResult<Option<Box<dyn GroupController>>> {
let mut group_controller: Option<Box<dyn GroupController>> = None;
match field_type {
FieldType::RichText => {
// let generator = GroupGenerator::<TextGroupConfigurationPB>::from_configuration(configuration);
}
FieldType::Number => {
// let generator = GroupGenerator::<NumberGroupConfigurationPB>::from_configuration(configuration);
}
FieldType::DateTime => {
// let generator = GroupGenerator::<DateGroupConfigurationPB>::from_configuration(configuration);
}
FieldType::SingleSelect => {
let configuration = SelectOptionGroupConfiguration::new(
self.view_id.clone(),
field_rev.clone(),
self.configuration_reader.clone(),
self.configuration_writer.clone(),
)
.await?;
let controller = SingleSelectGroupController::new(field_rev, configuration).await?;
group_controller = Some(Box::new(controller));
}
FieldType::MultiSelect => {
let configuration = SelectOptionGroupConfiguration::new(
self.view_id.clone(),
field_rev.clone(),
self.configuration_reader.clone(),
self.configuration_writer.clone(),
)
.await?;
let controller = MultiSelectGroupController::new(field_rev, configuration).await?;
group_controller = Some(Box::new(controller));
}
FieldType::Checkbox => {
let configuration = CheckboxGroupConfiguration::new(
self.view_id.clone(),
field_rev.clone(),
self.configuration_reader.clone(),
self.configuration_writer.clone(),
)
.await?;
let controller = CheckboxGroupController::new(field_rev, configuration).await?;
group_controller = Some(Box::new(controller));
}
FieldType::URL => {
// let generator = GroupGenerator::<UrlGroupConfigurationPB>::from_configuration(configuration);
}
}
Ok(group_controller)
}
}
#[tracing::instrument(level = "trace", skip_all, err)]
pub async fn make_group_controller<R, W>(
view_id: String,
field_revs: Vec<Arc<FieldRevision>>,
row_revs: Vec<Arc<RowRevision>>,
configuration_reader: R,
configuration_writer: W,
) -> FlowyResult<Box<dyn GroupController>>
where
R: GroupConfigurationReader,
W: GroupConfigurationWriter,
{
let field_rev = find_group_field(&field_revs)?;
let field_type: FieldType = field_rev.ty.into();
let mut group_controller: Box<dyn GroupController>;
match field_type {
FieldType::RichText => {
// let generator = GroupGenerator::<TextGroupConfigurationPB>::from_configuration(configuration);
panic!()
}
FieldType::Number => {
// let generator = GroupGenerator::<NumberGroupConfigurationPB>::from_configuration(configuration);
panic!()
}
FieldType::DateTime => {
// let generator = GroupGenerator::<DateGroupConfigurationPB>::from_configuration(configuration);
panic!()
}
FieldType::SingleSelect => {
let configuration = SelectOptionGroupConfiguration::new(
view_id,
field_rev.clone(),
configuration_reader,
configuration_writer,
)
.await?;
let controller = SingleSelectGroupController::new(&field_rev, configuration).await?;
group_controller = Box::new(controller);
}
FieldType::MultiSelect => {
let configuration = SelectOptionGroupConfiguration::new(
view_id,
field_rev.clone(),
configuration_reader,
configuration_writer,
)
.await?;
let controller = MultiSelectGroupController::new(&field_rev, configuration).await?;
group_controller = Box::new(controller);
}
FieldType::Checkbox => {
let configuration =
CheckboxGroupConfiguration::new(view_id, field_rev.clone(), configuration_reader, configuration_writer)
.await?;
let controller = CheckboxGroupController::new(&field_rev, configuration).await?;
group_controller = Box::new(controller);
}
FieldType::URL => {
// let generator = GroupGenerator::<UrlGroupConfigurationPB>::from_configuration(configuration);
panic!()
}
}
let _ = group_controller.fill_groups(&row_revs, &field_rev)?;
Ok(group_controller)
}
fn find_group_field(field_revs: &[Arc<FieldRevision>]) -> Option<Arc<FieldRevision>> {
let field_rev = field_revs
.iter()
.find(|field_rev| {
let field_type: FieldType = field_rev.ty.into();
field_type.can_be_group()
})
.cloned();
field_rev
}
pub fn default_group_configuration(field_rev: &FieldRevision) -> GroupConfigurationRevision {
let field_id = field_rev.id.clone();
let field_type_rev = field_rev.ty;
let field_type: FieldType = field_rev.ty.into();
match field_type {
FieldType::RichText => {
GroupConfigurationRevision::new(field_id, field_type_rev, TextGroupConfigurationRevision::default())
.unwrap()
}
FieldType::Number => {
GroupConfigurationRevision::new(field_id, field_type_rev, NumberGroupConfigurationRevision::default())
.unwrap()
}
FieldType::DateTime => {
GroupConfigurationRevision::new(field_id, field_type_rev, DateGroupConfigurationRevision::default())
.unwrap()
}
FieldType::SingleSelect => GroupConfigurationRevision::new(
field_id,
field_type_rev,
SelectOptionGroupConfigurationRevision::default(),
)
.unwrap(),
FieldType::MultiSelect => GroupConfigurationRevision::new(
field_id,
field_type_rev,
SelectOptionGroupConfigurationRevision::default(),
)
.unwrap(),
FieldType::Checkbox => {
GroupConfigurationRevision::new(field_id, field_type_rev, CheckboxGroupConfigurationRevision::default())
.unwrap()
}
FieldType::URL => {
GroupConfigurationRevision::new(field_id, field_type_rev, UrlGroupConfigurationRevision::default()).unwrap()
}
}
}

View File

@ -0,0 +1,113 @@
use crate::entities::FieldType;
use crate::services::group::configuration::GroupConfigurationReader;
use crate::services::group::controller::GroupController;
use crate::services::group::{
CheckboxGroupContext, CheckboxGroupController, DefaultGroupController, GroupConfigurationWriter,
MultiSelectGroupController, SelectOptionGroupContext, SingleSelectGroupController,
};
use flowy_error::FlowyResult;
use flowy_grid_data_model::revision::{
CheckboxGroupConfigurationRevision, DateGroupConfigurationRevision, FieldRevision, GroupConfigurationRevision,
NumberGroupConfigurationRevision, RowRevision, SelectOptionGroupConfigurationRevision,
TextGroupConfigurationRevision, UrlGroupConfigurationRevision,
};
use std::sync::Arc;
#[tracing::instrument(level = "trace", skip_all, err)]
pub async fn make_group_controller<R, W>(
view_id: String,
field_revs: Vec<Arc<FieldRevision>>,
row_revs: Vec<Arc<RowRevision>>,
configuration_reader: R,
configuration_writer: W,
) -> FlowyResult<Box<dyn GroupController>>
where
R: GroupConfigurationReader,
W: GroupConfigurationWriter,
{
let field_rev = find_group_field(&field_revs).unwrap();
let field_type: FieldType = field_rev.ty.into();
let mut group_controller: Box<dyn GroupController>;
let configuration_reader = Arc::new(configuration_reader);
let configuration_writer = Arc::new(configuration_writer);
match field_type {
FieldType::SingleSelect => {
let configuration =
SelectOptionGroupContext::new(view_id, field_rev.clone(), configuration_reader, configuration_writer)
.await?;
let controller = SingleSelectGroupController::new(&field_rev, configuration).await?;
group_controller = Box::new(controller);
}
FieldType::MultiSelect => {
let configuration =
SelectOptionGroupContext::new(view_id, field_rev.clone(), configuration_reader, configuration_writer)
.await?;
let controller = MultiSelectGroupController::new(&field_rev, configuration).await?;
group_controller = Box::new(controller);
}
FieldType::Checkbox => {
let configuration =
CheckboxGroupContext::new(view_id, field_rev.clone(), configuration_reader, configuration_writer)
.await?;
let controller = CheckboxGroupController::new(&field_rev, configuration).await?;
group_controller = Box::new(controller);
}
_ => {
group_controller = Box::new(DefaultGroupController::new(&field_rev));
}
}
let _ = group_controller.fill_groups(&row_revs, &field_rev)?;
Ok(group_controller)
}
fn find_group_field(field_revs: &[Arc<FieldRevision>]) -> Option<Arc<FieldRevision>> {
let field_rev = field_revs
.iter()
.find(|field_rev| {
let field_type: FieldType = field_rev.ty.into();
field_type.can_be_group()
})
.cloned();
field_rev
}
pub fn default_group_configuration(field_rev: &FieldRevision) -> GroupConfigurationRevision {
let field_id = field_rev.id.clone();
let field_type_rev = field_rev.ty;
let field_type: FieldType = field_rev.ty.into();
match field_type {
FieldType::RichText => {
GroupConfigurationRevision::new(field_id, field_type_rev, TextGroupConfigurationRevision::default())
.unwrap()
}
FieldType::Number => {
GroupConfigurationRevision::new(field_id, field_type_rev, NumberGroupConfigurationRevision::default())
.unwrap()
}
FieldType::DateTime => {
GroupConfigurationRevision::new(field_id, field_type_rev, DateGroupConfigurationRevision::default())
.unwrap()
}
FieldType::SingleSelect => GroupConfigurationRevision::new(
field_id,
field_type_rev,
SelectOptionGroupConfigurationRevision::default(),
)
.unwrap(),
FieldType::MultiSelect => GroupConfigurationRevision::new(
field_id,
field_type_rev,
SelectOptionGroupConfigurationRevision::default(),
)
.unwrap(),
FieldType::Checkbox => {
GroupConfigurationRevision::new(field_id, field_type_rev, CheckboxGroupConfigurationRevision::default())
.unwrap()
}
FieldType::URL => {
GroupConfigurationRevision::new(field_id, field_type_rev, UrlGroupConfigurationRevision::default()).unwrap()
}
}
}

View File

@ -3,10 +3,10 @@ mod configuration;
mod controller;
mod controller_impls;
mod entities;
mod group_service;
mod group_util;
pub(crate) use configuration::*;
pub(crate) use controller::*;
pub(crate) use controller_impls::*;
pub(crate) use entities::*;
pub(crate) use group_service::*;
pub(crate) use group_util::*;

View File

@ -391,11 +391,11 @@ async fn group_update_field_test() {
test.run_scripts(scripts).await;
}
#[tokio::test]
async fn group_multi_select_field_test() {
let mut test = GridGroupTest::new().await;
let multi_select_field = test.get_multi_select_field().await;
let scripts = vec![];
test.run_scripts(scripts).await;
}
// #[tokio::test]
// async fn group_multi_select_field_test() {
// let mut test = GridGroupTest::new().await;
// let multi_select_field = test.get_multi_select_field().await;
//
// let scripts = vec![];
// test.run_scripts(scripts).await;
// }

View File

@ -4,9 +4,8 @@ use serde_json::Error;
use serde_repr::*;
pub trait GroupConfigurationContentSerde: Sized + Send + Sync {
fn from_configuration_content(s: &str) -> Result<Self, serde_json::Error>;
fn to_configuration_content(&self) -> Result<String, serde_json::Error>;
fn from_json(s: &str) -> Result<Self, serde_json::Error>;
fn to_json(&self) -> Result<String, serde_json::Error>;
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
@ -15,6 +14,7 @@ pub struct GroupConfigurationRevision {
pub field_id: String,
pub field_type_rev: FieldTypeRevision,
pub groups: Vec<GroupRevision>,
// This content is serde in Json format
pub content: String,
}
@ -23,7 +23,7 @@ impl GroupConfigurationRevision {
where
T: GroupConfigurationContentSerde,
{
let content = content.to_configuration_content()?;
let content = content.to_json()?;
Ok(Self {
id: gen_grid_group_id(),
field_id,
@ -40,10 +40,10 @@ pub struct TextGroupConfigurationRevision {
}
impl GroupConfigurationContentSerde for TextGroupConfigurationRevision {
fn from_configuration_content(s: &str) -> Result<Self, Error> {
fn from_json(s: &str) -> Result<Self, Error> {
serde_json::from_str(s)
}
fn to_configuration_content(&self) -> Result<String, Error> {
fn to_json(&self) -> Result<String, Error> {
serde_json::to_string(self)
}
}
@ -54,10 +54,10 @@ pub struct NumberGroupConfigurationRevision {
}
impl GroupConfigurationContentSerde for NumberGroupConfigurationRevision {
fn from_configuration_content(s: &str) -> Result<Self, Error> {
fn from_json(s: &str) -> Result<Self, Error> {
serde_json::from_str(s)
}
fn to_configuration_content(&self) -> Result<String, Error> {
fn to_json(&self) -> Result<String, Error> {
serde_json::to_string(self)
}
}
@ -68,10 +68,10 @@ pub struct UrlGroupConfigurationRevision {
}
impl GroupConfigurationContentSerde for UrlGroupConfigurationRevision {
fn from_configuration_content(s: &str) -> Result<Self, Error> {
fn from_json(s: &str) -> Result<Self, Error> {
serde_json::from_str(s)
}
fn to_configuration_content(&self) -> Result<String, Error> {
fn to_json(&self) -> Result<String, Error> {
serde_json::to_string(self)
}
}
@ -82,11 +82,11 @@ pub struct CheckboxGroupConfigurationRevision {
}
impl GroupConfigurationContentSerde for CheckboxGroupConfigurationRevision {
fn from_configuration_content(s: &str) -> Result<Self, Error> {
fn from_json(s: &str) -> Result<Self, Error> {
serde_json::from_str(s)
}
fn to_configuration_content(&self) -> Result<String, Error> {
fn to_json(&self) -> Result<String, Error> {
serde_json::to_string(self)
}
}
@ -97,11 +97,11 @@ pub struct SelectOptionGroupConfigurationRevision {
}
impl GroupConfigurationContentSerde for SelectOptionGroupConfigurationRevision {
fn from_configuration_content(s: &str) -> Result<Self, Error> {
fn from_json(s: &str) -> Result<Self, Error> {
serde_json::from_str(s)
}
fn to_configuration_content(&self) -> Result<String, Error> {
fn to_json(&self) -> Result<String, Error> {
serde_json::to_string(self)
}
}
@ -113,22 +113,17 @@ pub struct GroupRevision {
#[serde(default)]
pub name: String,
#[serde(skip, default = "IS_DEFAULT_GROUP")]
pub is_default: bool,
#[serde(default = "GROUP_REV_VISIBILITY")]
pub visible: bool,
}
const GROUP_REV_VISIBILITY: fn() -> bool = || true;
const IS_DEFAULT_GROUP: fn() -> bool = || false;
impl GroupRevision {
pub fn new(id: String, group_name: String) -> Self {
Self {
id,
name: group_name,
is_default: false,
visible: true,
}
}
@ -137,7 +132,6 @@ impl GroupRevision {
Self {
id,
name: group_name,
is_default: true,
visible: true,
}
}
@ -150,10 +144,10 @@ pub struct DateGroupConfigurationRevision {
}
impl GroupConfigurationContentSerde for DateGroupConfigurationRevision {
fn from_configuration_content(s: &str) -> Result<Self, Error> {
fn from_json(s: &str) -> Result<Self, Error> {
serde_json::from_str(s)
}
fn to_configuration_content(&self) -> Result<String, Error> {
fn to_json(&self) -> Result<String, Error> {
serde_json::to_string(self)
}
}