mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
chore: refactor group gen process
This commit is contained in:
parent
1931cdd4c0
commit
f192f89ebb
7
frontend/app_flowy/assets/images/grid/setting/group.svg
Normal file
7
frontend/app_flowy/assets/images/grid/setting/group.svg
Normal 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 |
@ -160,7 +160,8 @@
|
||||
"settings": {
|
||||
"filter": "Filter",
|
||||
"sortBy": "Sort by",
|
||||
"Properties": "Properties"
|
||||
"Properties": "Properties",
|
||||
"group": "Group"
|
||||
},
|
||||
"field": {
|
||||
"hide": "Hide",
|
||||
|
@ -43,4 +43,5 @@ class BoardSettingState with _$BoardSettingState {
|
||||
|
||||
enum BoardSettingAction {
|
||||
properties,
|
||||
groups,
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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>,
|
||||
|
||||
|
@ -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(¶ms.from_group_id, ¶ms.to_group_id)
|
||||
.await?;
|
||||
|
||||
match self.group_service.read().await.get_group(¶ms.from_group_id).await {
|
||||
.move_group(¶ms.from_group_id, ¶ms.to_group_id)?;
|
||||
match self.group_controller.read().await.get_group(¶ms.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,
|
||||
|
@ -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(),
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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]
|
||||
}
|
||||
}
|
||||
|
@ -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) {}
|
||||
}
|
@ -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::*;
|
||||
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
113
frontend/rust-lib/flowy-grid/src/services/group/group_util.rs
Normal file
113
frontend/rust-lib/flowy-grid/src/services/group/group_util.rs
Normal 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()
|
||||
}
|
||||
}
|
||||
}
|
@ -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::*;
|
||||
|
@ -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;
|
||||
// }
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user