chore: reload group when group by new field

This commit is contained in:
appflowy
2022-09-02 21:34:00 +08:00
parent e75d8f22c8
commit bb7cddc7f7
26 changed files with 353 additions and 209 deletions

View File

@ -110,9 +110,11 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
emit(state.copyWith(noneOrError: some(error))); emit(state.copyWith(noneOrError: some(error)));
}, },
didReceiveGroups: (List<GroupPB> groups) { didReceiveGroups: (List<GroupPB> groups) {
emit(state.copyWith( emit(
groupIds: groups.map((group) => group.groupId).toList(), state.copyWith(
)); groupIds: groups.map((group) => group.groupId).toList(),
),
);
}, },
); );
}, },
@ -154,6 +156,23 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
} }
void initializeGroups(List<GroupPB> groups) { void initializeGroups(List<GroupPB> groups) {
for (var controller in groupControllers.values) {
controller.dispose();
}
groupControllers.clear();
boardController.clear();
//
List<AFBoardColumnData> columns = groups.map((group) {
return AFBoardColumnData(
id: group.groupId,
name: group.desc,
items: _buildRows(group),
customData: group,
);
}).toList();
boardController.addColumns(columns);
for (final group in groups) { for (final group in groups) {
final delegate = GroupControllerDelegateImpl( final delegate = GroupControllerDelegateImpl(
controller: boardController, controller: boardController,
@ -184,16 +203,6 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
} }
}, },
didLoadGroups: (groups) { didLoadGroups: (groups) {
List<AFBoardColumnData> columns = groups.map((group) {
return AFBoardColumnData(
id: group.groupId,
name: group.desc,
items: _buildRows(group),
customData: group,
);
}).toList();
boardController.addColumns(columns);
initializeGroups(groups); initializeGroups(groups);
add(BoardEvent.didReceiveGroups(groups)); add(BoardEvent.didReceiveGroups(groups));
}, },
@ -204,18 +213,19 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
// //
}, },
onUpdatedGroup: (updatedGroups) { onUpdatedGroup: (updatedGroups) {
//
for (final group in updatedGroups) { for (final group in updatedGroups) {
final columnController = final columnController =
boardController.getColumnController(group.groupId); boardController.getColumnController(group.groupId);
if (columnController != null) { columnController?.updateColumnName(group.desc);
columnController.updateColumnName(group.desc);
}
} }
}, },
onError: (err) { onError: (err) {
Log.error(err); Log.error(err);
}, },
onResetGroups: (groups) {
initializeGroups(groups);
add(BoardEvent.didReceiveGroups(groups));
},
); );
} }

View File

@ -18,6 +18,7 @@ typedef DidLoadGroups = void Function(List<GroupPB>);
typedef OnUpdatedGroup = void Function(List<GroupPB>); typedef OnUpdatedGroup = void Function(List<GroupPB>);
typedef OnDeletedGroup = void Function(List<String>); typedef OnDeletedGroup = void Function(List<String>);
typedef OnInsertedGroup = void Function(List<InsertedGroupPB>); typedef OnInsertedGroup = void Function(List<InsertedGroupPB>);
typedef OnResetGroups = void Function(List<GroupPB>);
typedef OnRowsChanged = void Function( typedef OnRowsChanged = void Function(
List<RowInfo>, List<RowInfo>,
@ -65,6 +66,7 @@ class BoardDataController {
required OnUpdatedGroup onUpdatedGroup, required OnUpdatedGroup onUpdatedGroup,
required OnDeletedGroup onDeletedGroup, required OnDeletedGroup onDeletedGroup,
required OnInsertedGroup onInsertedGroup, required OnInsertedGroup onInsertedGroup,
required OnResetGroups onResetGroups,
required OnError? onError, required OnError? onError,
}) { }) {
_onGridChanged = onGridChanged; _onGridChanged = onGridChanged;
@ -77,24 +79,32 @@ class BoardDataController {
_onFieldsChanged?.call(UnmodifiableListView(fields)); _onFieldsChanged?.call(UnmodifiableListView(fields));
}); });
_listener.start(onBoardChanged: (result) { _listener.start(
result.fold( onBoardChanged: (result) {
(changeset) { result.fold(
if (changeset.updateGroups.isNotEmpty) { (changeset) {
onUpdatedGroup.call(changeset.updateGroups); if (changeset.updateGroups.isNotEmpty) {
} onUpdatedGroup.call(changeset.updateGroups);
}
if (changeset.insertedGroups.isNotEmpty) { if (changeset.insertedGroups.isNotEmpty) {
onInsertedGroup.call(changeset.insertedGroups); onInsertedGroup.call(changeset.insertedGroups);
} }
if (changeset.deletedGroups.isNotEmpty) { if (changeset.deletedGroups.isNotEmpty) {
onDeletedGroup.call(changeset.deletedGroups); onDeletedGroup.call(changeset.deletedGroups);
} }
}, },
(e) => _onError?.call(e), (e) => _onError?.call(e),
); );
}); },
onGroupByNewField: (result) {
result.fold(
(groups) => onResetGroups(groups),
(e) => _onError?.call(e),
);
},
);
} }
Future<Either<Unit, FlowyError>> loadData() async { Future<Either<Unit, FlowyError>> loadData() async {

View File

@ -5,20 +5,26 @@ import 'package:flowy_infra/notifier.dart';
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/dart_notification.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/dart_notification.pb.dart';
import 'package:dartz/dartz.dart'; import 'package:dartz/dartz.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/group.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/group_changeset.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/group_changeset.pb.dart';
typedef UpdateBoardNotifiedValue = Either<GroupViewChangesetPB, FlowyError>; typedef GroupUpdateValue = Either<GroupViewChangesetPB, FlowyError>;
typedef GroupByNewFieldValue = Either<List<GroupPB>, FlowyError>;
class BoardListener { class BoardListener {
final String viewId; final String viewId;
PublishNotifier<UpdateBoardNotifiedValue>? _groupNotifier = PublishNotifier(); PublishNotifier<GroupUpdateValue>? _groupUpdateNotifier = PublishNotifier();
PublishNotifier<GroupByNewFieldValue>? _groupByNewFieldNotifier =
PublishNotifier();
GridNotificationListener? _listener; GridNotificationListener? _listener;
BoardListener(this.viewId); BoardListener(this.viewId);
void start({ void start({
required void Function(UpdateBoardNotifiedValue) onBoardChanged, required void Function(GroupUpdateValue) onBoardChanged,
required void Function(GroupByNewFieldValue) onGroupByNewField,
}) { }) {
_groupNotifier?.addPublishListener(onBoardChanged); _groupUpdateNotifier?.addPublishListener(onBoardChanged);
_groupByNewFieldNotifier?.addPublishListener(onGroupByNewField);
_listener = GridNotificationListener( _listener = GridNotificationListener(
objectId: viewId, objectId: viewId,
handler: _handler, handler: _handler,
@ -32,9 +38,16 @@ class BoardListener {
switch (ty) { switch (ty) {
case GridNotification.DidUpdateGroupView: case GridNotification.DidUpdateGroupView:
result.fold( result.fold(
(payload) => _groupNotifier?.value = (payload) => _groupUpdateNotifier?.value =
left(GroupViewChangesetPB.fromBuffer(payload)), left(GroupViewChangesetPB.fromBuffer(payload)),
(error) => _groupNotifier?.value = right(error), (error) => _groupUpdateNotifier?.value = right(error),
);
break;
case GridNotification.DidGroupByNewField:
result.fold(
(payload) => _groupByNewFieldNotifier?.value =
left(GroupViewChangesetPB.fromBuffer(payload).newGroups),
(error) => _groupByNewFieldNotifier?.value = right(error),
); );
break; break;
default: default:
@ -44,7 +57,10 @@ class BoardListener {
Future<void> stop() async { Future<void> stop() async {
await _listener?.stop(); await _listener?.stop();
_groupNotifier?.dispose(); _groupUpdateNotifier?.dispose();
_groupNotifier = null; _groupUpdateNotifier = null;
_groupByNewFieldNotifier?.dispose();
_groupByNewFieldNotifier = null;
} }
} }

View File

@ -89,6 +89,11 @@ class AFBoardDataController extends ChangeNotifier
if (columnIds.isNotEmpty && notify) notifyListeners(); if (columnIds.isNotEmpty && notify) notifyListeners();
} }
void clear() {
_columnDatas.clear();
notifyListeners();
}
AFBoardColumnDataController? getColumnController(String columnId) { AFBoardColumnDataController? getColumnController(String columnId) {
final columnController = _columnControllers[columnId]; final columnController = _columnControllers[columnId];
if (columnController == null) { if (columnController == null) {

View File

@ -13,6 +13,7 @@ pub enum GridNotification {
DidUpdateField = 50, DidUpdateField = 50,
DidUpdateGroupView = 60, DidUpdateGroupView = 60,
DidUpdateGroup = 61, DidUpdateGroup = 61,
DidGroupByNewField = 62,
} }
impl std::default::Default for GridNotification { impl std::default::Default for GridNotification {

View File

@ -145,7 +145,10 @@ pub struct GroupViewChangesetPB {
impl GroupViewChangesetPB { impl GroupViewChangesetPB {
pub fn is_empty(&self) -> bool { pub fn is_empty(&self) -> bool {
self.inserted_groups.is_empty() && self.deleted_groups.is_empty() && self.update_groups.is_empty() self.new_groups.is_empty()
&& self.inserted_groups.is_empty()
&& self.deleted_groups.is_empty()
&& self.update_groups.is_empty()
} }
} }

View File

@ -1,14 +1,13 @@
use crate::entities::{FieldChangesetParams, FieldType}; use crate::services::field::{MultiSelectTypeOptionPB, SingleSelectTypeOptionPB};
use crate::services::field::{select_option_operation, SelectOptionPB};
use crate::services::grid_editor::GridRevisionEditor; use crate::services::grid_editor::GridRevisionEditor;
use flowy_error::FlowyResult; use flowy_error::FlowyResult;
use flowy_grid_data_model::revision::{FieldRevision, TypeOptionDataDeserializer, TypeOptionDataFormat}; use flowy_grid_data_model::revision::{TypeOptionDataDeserializer, TypeOptionDataFormat};
use std::sync::Arc; use std::sync::Arc;
pub async fn edit_field<T>( pub async fn edit_field_type_option<T>(
field_id: &str, field_id: &str,
editor: Arc<GridRevisionEditor>, editor: Arc<GridRevisionEditor>,
action: impl FnOnce(&mut T) -> bool, action: impl FnOnce(&mut T),
) -> FlowyResult<()> ) -> FlowyResult<()>
where where
T: TypeOptionDataDeserializer + TypeOptionDataFormat, T: TypeOptionDataDeserializer + TypeOptionDataFormat,
@ -19,29 +18,28 @@ where
}; };
if let Some(mut type_option) = get_type_option.await { if let Some(mut type_option) = get_type_option.await {
if action(&mut type_option) { action(&mut type_option);
let changeset = FieldChangesetParams { ..Default::default() }; let bytes = type_option.protobuf_bytes().to_vec();
let _ = editor.update_field(changeset).await?; let _ = editor
} .update_field_type_option(&editor.grid_id, field_id, bytes)
.await?;
} }
Ok(()) Ok(())
} }
pub fn insert_single_select_option(field_rev: &mut FieldRevision, options: Vec<SelectOptionPB>) -> FlowyResult<()> { pub async fn edit_single_select_type_option(
if options.is_empty() { field_id: &str,
return Ok(()); editor: Arc<GridRevisionEditor>,
} action: impl FnOnce(&mut SingleSelectTypeOptionPB),
let mut type_option = select_option_operation(field_rev)?; ) -> FlowyResult<()> {
options.into_iter().for_each(|option| type_option.insert_option(option)); edit_field_type_option(field_id, editor, action).await
Ok(())
} }
pub fn insert_multi_select_option(field_rev: &mut FieldRevision, options: Vec<SelectOptionPB>) -> FlowyResult<()> { pub async fn edit_multi_select_type_option(
if options.is_empty() { field_id: &str,
return Ok(()); editor: Arc<GridRevisionEditor>,
} action: impl FnOnce(&mut MultiSelectTypeOptionPB),
let mut type_option = select_option_operation(field_rev)?; ) -> FlowyResult<()> {
options.into_iter().for_each(|option| type_option.insert_option(option)); edit_field_type_option(field_id, editor, action).await
Ok(())
} }

View File

@ -212,7 +212,8 @@ impl GridRevisionEditor {
} }
pub async fn group_field(&self, field_id: &str) -> FlowyResult<()> { pub async fn group_field(&self, field_id: &str) -> FlowyResult<()> {
todo!() let _ = self.view_manager.group_by_field(field_id).await?;
Ok(())
} }
pub async fn switch_to_field_type(&self, field_id: &str, field_type: &FieldType) -> FlowyResult<()> { pub async fn switch_to_field_type(&self, field_id: &str, field_type: &FieldType) -> FlowyResult<()> {

View File

@ -7,7 +7,8 @@ use crate::entities::{
use crate::services::grid_editor_task::GridServiceTaskScheduler; use crate::services::grid_editor_task::GridServiceTaskScheduler;
use crate::services::grid_view_manager::{GridViewFieldDelegate, GridViewRowDelegate}; use crate::services::grid_view_manager::{GridViewFieldDelegate, GridViewRowDelegate};
use crate::services::group::{ use crate::services::group::{
make_group_controller, GroupConfigurationReader, GroupConfigurationWriter, GroupController, MoveGroupRowContext, find_group_field, make_group_controller, GroupConfigurationReader, GroupConfigurationWriter, GroupController,
MoveGroupRowContext,
}; };
use flowy_error::{FlowyError, FlowyResult}; use flowy_error::{FlowyError, FlowyResult};
use flowy_grid_data_model::revision::{ use flowy_grid_data_model::revision::{
@ -34,7 +35,6 @@ pub struct GridViewRevisionEditor {
group_controller: Arc<RwLock<Box<dyn GroupController>>>, group_controller: Arc<RwLock<Box<dyn GroupController>>>,
scheduler: Arc<dyn GridServiceTaskScheduler>, scheduler: Arc<dyn GridServiceTaskScheduler>,
} }
impl GridViewRevisionEditor { impl GridViewRevisionEditor {
#[tracing::instrument(level = "trace", skip_all, err)] #[tracing::instrument(level = "trace", skip_all, err)]
pub(crate) async fn new( pub(crate) async fn new(
@ -52,25 +52,15 @@ impl GridViewRevisionEditor {
let view_revision_pad = rev_manager.load::<GridViewRevisionPadBuilder>(Some(cloud)).await?; let view_revision_pad = rev_manager.load::<GridViewRevisionPadBuilder>(Some(cloud)).await?;
let pad = Arc::new(RwLock::new(view_revision_pad)); let pad = Arc::new(RwLock::new(view_revision_pad));
let rev_manager = Arc::new(rev_manager); let rev_manager = Arc::new(rev_manager);
let group_controller = new_group_controller(
// Load group user_id.to_owned(),
let configuration_reader = GroupConfigurationReaderImpl(pad.clone());
let configuration_writer = GroupConfigurationWriterImpl {
user_id: user_id.to_owned(),
rev_manager: rev_manager.clone(),
view_pad: pad.clone(),
};
let field_revs = field_delegate.get_field_revs().await;
let row_revs = row_delegate.gv_row_revs().await;
let group_controller = make_group_controller(
view_id.clone(), view_id.clone(),
field_revs, pad.clone(),
row_revs, rev_manager.clone(),
configuration_reader, field_delegate.clone(),
configuration_writer, row_delegate.clone(),
) )
.await?; .await?;
let user_id = user_id.to_owned(); let user_id = user_id.to_owned();
Ok(Self { Ok(Self {
pad, pad,
@ -258,6 +248,37 @@ impl GridViewRevisionEditor {
Ok(()) Ok(())
} }
pub(crate) async fn group_by_field(&self, field_id: &str) -> FlowyResult<()> {
if let Some(field_rev) = self.field_delegate.get_field_rev(field_id).await {
let new_group_controller = new_group_controller_with_field_rev(
self.user_id.clone(),
self.view_id.clone(),
self.pad.clone(),
self.rev_manager.clone(),
field_rev,
self.row_delegate.clone(),
)
.await?;
let new_groups = new_group_controller.groups().into_iter().map(GroupPB::from).collect();
*self.group_controller.write().await = new_group_controller;
let changeset = GroupViewChangesetPB {
view_id: self.view_id.clone(),
new_groups,
..Default::default()
};
debug_assert!(!changeset.is_empty());
if !changeset.is_empty() {
send_dart_notification(&changeset.view_id, GridNotification::DidGroupByNewField)
.payload(changeset)
.send();
}
}
Ok(())
}
pub async fn notify_did_update_group(&self, changeset: GroupChangesetPB) { pub async fn notify_did_update_group(&self, changeset: GroupChangesetPB) {
send_dart_notification(&changeset.group_id, GridNotification::DidUpdateGroup) send_dart_notification(&changeset.group_id, GridNotification::DidUpdateGroup)
.payload(changeset) .payload(changeset)
@ -314,6 +335,48 @@ impl GridViewRevisionEditor {
} }
} }
} }
async fn new_group_controller(
user_id: String,
view_id: String,
pad: Arc<RwLock<GridViewRevisionPad>>,
rev_manager: Arc<RevisionManager>,
field_delegate: Arc<dyn GridViewFieldDelegate>,
row_delegate: Arc<dyn GridViewRowDelegate>,
) -> FlowyResult<Box<dyn GroupController>> {
let configuration_reader = GroupConfigurationReaderImpl(pad.clone());
let field_revs = field_delegate.get_field_revs().await;
// Read the group field or find a new group field
let field_rev = configuration_reader
.get_configuration()
.await
.and_then(|configuration| {
field_revs
.iter()
.find(|field_rev| field_rev.id == configuration.field_id)
.cloned()
})
.unwrap_or_else(|| find_group_field(&field_revs).unwrap());
new_group_controller_with_field_rev(user_id, view_id, pad, rev_manager, field_rev, row_delegate).await
}
async fn new_group_controller_with_field_rev(
user_id: String,
view_id: String,
pad: Arc<RwLock<GridViewRevisionPad>>,
rev_manager: Arc<RevisionManager>,
field_rev: Arc<FieldRevision>,
row_delegate: Arc<dyn GridViewRowDelegate>,
) -> FlowyResult<Box<dyn GroupController>> {
let configuration_reader = GroupConfigurationReaderImpl(pad.clone());
let configuration_writer = GroupConfigurationWriterImpl {
user_id,
rev_manager,
view_pad: pad,
};
let row_revs = row_delegate.gv_row_revs().await;
make_group_controller(view_id, field_rev, row_revs, configuration_reader, configuration_writer).await
}
async fn apply_change( async fn apply_change(
user_id: &str, user_id: &str,
@ -353,10 +416,10 @@ impl RevisionObjectBuilder for GridViewRevisionPadBuilder {
struct GroupConfigurationReaderImpl(Arc<RwLock<GridViewRevisionPad>>); struct GroupConfigurationReaderImpl(Arc<RwLock<GridViewRevisionPad>>);
impl GroupConfigurationReader for GroupConfigurationReaderImpl { impl GroupConfigurationReader for GroupConfigurationReaderImpl {
fn get_configuration(&self, field_rev: Arc<FieldRevision>) -> AFFuture<Option<Arc<GroupConfigurationRevision>>> { fn get_configuration(&self) -> AFFuture<Option<Arc<GroupConfigurationRevision>>> {
let view_pad = self.0.clone(); let view_pad = self.0.clone();
wrap_future(async move { wrap_future(async move {
let mut groups = view_pad.read().await.groups.get_objects(&field_rev.id, &field_rev.ty)?; let mut groups = view_pad.read().await.get_all_groups();
if groups.is_empty() { if groups.is_empty() {
None None
} else { } else {
@ -411,7 +474,7 @@ pub fn make_grid_setting(view_pad: &GridViewRevisionPad, field_revs: &[Arc<Field
}) })
.unwrap_or_default(); .unwrap_or_default();
let groups_by_field_id = view_pad let groups_by_field_id = view_pad
.get_all_groups(field_revs) .get_groups_by_field_revs(field_revs)
.map(|groups_by_field_id| { .map(|groups_by_field_id| {
groups_by_field_id groups_by_field_id
.into_iter() .into_iter()

View File

@ -84,6 +84,12 @@ impl GridViewManager {
} }
} }
pub(crate) async fn group_by_field(&self, field_id: &str) -> FlowyResult<()> {
let view_editor = self.get_default_view_editor().await?;
let _ = view_editor.group_by_field(field_id).await?;
Ok(())
}
pub(crate) async fn did_update_cell(&self, row_id: &str, _field_id: &str) { pub(crate) async fn did_update_cell(&self, row_id: &str, _field_id: &str) {
self.did_update_row(row_id).await self.did_update_row(row_id).await
} }

View File

@ -1,4 +1,4 @@
use crate::entities::{GroupPB, GroupViewChangesetPB, InsertedGroupPB}; use crate::entities::{GroupPB, GroupViewChangesetPB};
use crate::services::group::{default_group_configuration, GeneratedGroup, Group}; use crate::services::group::{default_group_configuration, GeneratedGroup, Group};
use flowy_error::{FlowyError, FlowyResult}; use flowy_error::{FlowyError, FlowyResult};
use flowy_grid_data_model::revision::{ use flowy_grid_data_model::revision::{
@ -12,7 +12,7 @@ use std::marker::PhantomData;
use std::sync::Arc; use std::sync::Arc;
pub trait GroupConfigurationReader: Send + Sync + 'static { pub trait GroupConfigurationReader: Send + Sync + 'static {
fn get_configuration(&self, field_rev: Arc<FieldRevision>) -> AFFuture<Option<Arc<GroupConfigurationRevision>>>; fn get_configuration(&self) -> AFFuture<Option<Arc<GroupConfigurationRevision>>>;
} }
pub trait GroupConfigurationWriter: Send + Sync + 'static { pub trait GroupConfigurationWriter: Send + Sync + 'static {
@ -38,8 +38,8 @@ impl<T> std::fmt::Display for GroupContext<T> {
} }
pub struct GroupContext<C> { pub struct GroupContext<C> {
view_id: String, pub view_id: String,
pub configuration: Arc<GroupConfigurationRevision>, configuration: Arc<GroupConfigurationRevision>,
configuration_content: PhantomData<C>, configuration_content: PhantomData<C>,
field_rev: Arc<FieldRevision>, field_rev: Arc<FieldRevision>,
groups_map: IndexMap<String, Group>, groups_map: IndexMap<String, Group>,
@ -69,7 +69,7 @@ where
rows: vec![], rows: vec![],
filter_content: "".to_string(), filter_content: "".to_string(),
}; };
let configuration = match reader.get_configuration(field_rev.clone()).await { let configuration = match reader.get_configuration().await {
None => { None => {
let default_configuration = default_group_configuration(&field_rev); let default_configuration = default_group_configuration(&field_rev);
writer writer
@ -133,9 +133,10 @@ where
} }
} }
pub(crate) fn init_group_revs( pub(crate) fn init_groups(
&mut self, &mut self,
generated_groups: Vec<GeneratedGroup>, generated_groups: Vec<GeneratedGroup>,
reset: bool,
) -> FlowyResult<Option<GroupViewChangesetPB>> { ) -> FlowyResult<Option<GroupViewChangesetPB>> {
let mut new_groups = vec![]; let mut new_groups = vec![];
let mut filter_content_map = HashMap::new(); let mut filter_content_map = HashMap::new();
@ -149,7 +150,11 @@ where
new_group_revs, new_group_revs,
updated_group_revs: _, updated_group_revs: _,
deleted_group_revs, deleted_group_revs,
} = merge_groups(&self.configuration.groups, new_groups); } = if reset {
merge_groups(&[], new_groups)
} else {
merge_groups(&self.configuration.groups, new_groups)
};
let deleted_group_ids = deleted_group_revs let deleted_group_ids = deleted_group_revs
.into_iter() .into_iter()
@ -180,7 +185,7 @@ where
group_rev.update_with_other(&old_group); group_rev.update_with_other(&old_group);
// Take the GroupRevision if the name has changed // Take the GroupRevision if the name has changed
if is_group_changed(&group_rev, &old_group) { if is_group_changed(group_rev, &old_group) {
old_group.name = group_rev.name.clone(); old_group.name = group_rev.name.clone();
is_changed = true; is_changed = true;
configuration.groups.insert(pos, old_group); configuration.groups.insert(pos, old_group);

View File

@ -74,7 +74,7 @@ pub trait GroupControllerSharedOperation: Send + Sync {
pub struct GenericGroupController<C, T, G, P> { pub struct GenericGroupController<C, T, G, P> {
pub field_id: String, pub field_id: String,
pub type_option: Option<T>, pub type_option: Option<T>,
pub configuration: GroupContext<C>, pub group_ctx: GroupContext<C>,
group_action_phantom: PhantomData<G>, group_action_phantom: PhantomData<G>,
cell_parser_phantom: PhantomData<P>, cell_parser_phantom: PhantomData<P>,
} }
@ -89,12 +89,12 @@ where
let field_type_rev = field_rev.ty; let field_type_rev = field_rev.ty;
let type_option = field_rev.get_type_option::<T>(field_type_rev); let type_option = field_rev.get_type_option::<T>(field_type_rev);
let groups = G::generate_groups(&field_rev.id, &configuration, &type_option); let groups = G::generate_groups(&field_rev.id, &configuration, &type_option);
let _ = configuration.init_group_revs(groups)?; let _ = configuration.init_groups(groups, false)?;
Ok(Self { Ok(Self {
field_id: field_rev.id.clone(), field_id: field_rev.id.clone(),
type_option, type_option,
configuration, group_ctx: configuration,
group_action_phantom: PhantomData, group_action_phantom: PhantomData,
cell_parser_phantom: PhantomData, cell_parser_phantom: PhantomData,
}) })
@ -107,7 +107,7 @@ where
row_rev: &RowRevision, row_rev: &RowRevision,
other_group_changesets: &[GroupChangesetPB], other_group_changesets: &[GroupChangesetPB],
) -> GroupChangesetPB { ) -> GroupChangesetPB {
let default_group = self.configuration.get_mut_default_group(); let default_group = self.group_ctx.get_mut_default_group();
// [other_group_inserted_row] contains all the inserted rows except the default group. // [other_group_inserted_row] contains all the inserted rows except the default group.
let other_group_inserted_row = other_group_changesets let other_group_inserted_row = other_group_changesets
@ -182,11 +182,11 @@ where
} }
fn groups(&self) -> Vec<Group> { fn groups(&self) -> Vec<Group> {
self.configuration.clone_groups() self.group_ctx.clone_groups()
} }
fn get_group(&self, group_id: &str) -> Option<(usize, Group)> { fn get_group(&self, group_id: &str) -> Option<(usize, Group)> {
let group = self.configuration.get_group(group_id)?; let group = self.group_ctx.get_group(group_id)?;
Some((group.0, group.1.clone())) Some((group.0, group.1.clone()))
} }
@ -197,7 +197,7 @@ where
let mut grouped_rows: Vec<GroupedRow> = vec![]; let mut grouped_rows: Vec<GroupedRow> = vec![];
let cell_bytes = decode_any_cell_data(cell_rev.data.clone(), field_rev); let cell_bytes = decode_any_cell_data(cell_rev.data.clone(), field_rev);
let cell_data = cell_bytes.parser::<P>()?; let cell_data = cell_bytes.parser::<P>()?;
for group in self.configuration.concrete_groups() { for group in self.group_ctx.concrete_groups() {
if self.can_group(&group.filter_content, &cell_data) { if self.can_group(&group.filter_content, &cell_data) {
grouped_rows.push(GroupedRow { grouped_rows.push(GroupedRow {
row: row_rev.into(), row: row_rev.into(),
@ -207,25 +207,25 @@ where
} }
if grouped_rows.is_empty() { if grouped_rows.is_empty() {
self.configuration.get_mut_default_group().add_row(row_rev.into()); self.group_ctx.get_mut_default_group().add_row(row_rev.into());
} else { } else {
for group_row in grouped_rows { for group_row in grouped_rows {
if let Some(group) = self.configuration.get_mut_group(&group_row.group_id) { if let Some(group) = self.group_ctx.get_mut_group(&group_row.group_id) {
group.add_row(group_row.row); group.add_row(group_row.row);
} }
} }
} }
} else { } else {
self.configuration.get_mut_default_group().add_row(row_rev.into()); self.group_ctx.get_mut_default_group().add_row(row_rev.into());
} }
} }
tracing::Span::current().record("group_result", &format!("{},", self.configuration,).as_str()); tracing::Span::current().record("group_result", &format!("{},", self.group_ctx,).as_str());
Ok(()) Ok(())
} }
fn move_group(&mut self, from_group_id: &str, to_group_id: &str) -> FlowyResult<()> { fn move_group(&mut self, from_group_id: &str, to_group_id: &str) -> FlowyResult<()> {
self.configuration.move_group(from_group_id, to_group_id) self.group_ctx.move_group(from_group_id, to_group_id)
} }
fn did_update_row( fn did_update_row(
@ -273,10 +273,9 @@ where
} }
fn did_update_field(&mut self, field_rev: &FieldRevision) -> FlowyResult<Option<GroupViewChangesetPB>> { fn did_update_field(&mut self, field_rev: &FieldRevision) -> FlowyResult<Option<GroupViewChangesetPB>> {
let field_type_rev = field_rev.ty; let type_option = field_rev.get_type_option::<T>(field_rev.ty);
let type_option = field_rev.get_type_option::<T>(field_type_rev); let groups = G::generate_groups(&field_rev.id, &self.group_ctx, &type_option);
let groups = G::generate_groups(&field_rev.id, &self.configuration, &type_option); let changeset = self.group_ctx.init_groups(groups, false)?;
let changeset = self.configuration.init_group_revs(groups)?;
Ok(changeset) Ok(changeset)
} }
} }

View File

@ -5,7 +5,6 @@ use crate::services::group::configuration::GroupContext;
use crate::services::group::controller::{ use crate::services::group::controller::{
GenericGroupController, GroupController, GroupGenerator, MoveGroupRowContext, GenericGroupController, GroupController, GroupGenerator, MoveGroupRowContext,
}; };
use crate::services::group::entities::Group;
use crate::services::group::GeneratedGroup; use crate::services::group::GeneratedGroup;
use flowy_grid_data_model::revision::{CheckboxGroupConfigurationRevision, FieldRevision, GroupRevision, RowRevision}; use flowy_grid_data_model::revision::{CheckboxGroupConfigurationRevision, FieldRevision, GroupRevision, RowRevision};
@ -54,9 +53,9 @@ impl GroupGenerator for CheckboxGroupGenerator {
type TypeOptionType = CheckboxTypeOptionPB; type TypeOptionType = CheckboxTypeOptionPB;
fn generate_groups( fn generate_groups(
field_id: &str, _field_id: &str,
group_ctx: &Self::Context, _group_ctx: &Self::Context,
type_option: &Option<Self::TypeOptionType>, _type_option: &Option<Self::TypeOptionType>,
) -> Vec<GeneratedGroup> { ) -> Vec<GeneratedGroup> {
let check_group = GeneratedGroup { let check_group = GeneratedGroup {
group_rev: GroupRevision::new("true".to_string(), CHECK.to_string()), group_rev: GroupRevision::new("true".to_string(), CHECK.to_string()),

View File

@ -35,46 +35,46 @@ impl GroupControllerSharedOperation for DefaultGroupController {
vec![self.group.clone()] vec![self.group.clone()]
} }
fn get_group(&self, group_id: &str) -> Option<(usize, Group)> { fn get_group(&self, _group_id: &str) -> Option<(usize, Group)> {
Some((0, self.group.clone())) Some((0, self.group.clone()))
} }
fn fill_groups(&mut self, row_revs: &[Arc<RowRevision>], field_rev: &FieldRevision) -> FlowyResult<()> { fn fill_groups(&mut self, row_revs: &[Arc<RowRevision>], _field_rev: &FieldRevision) -> FlowyResult<()> {
row_revs.iter().for_each(|row_rev| { row_revs.iter().for_each(|row_rev| {
self.group.add_row(RowPB::from(row_rev)); self.group.add_row(RowPB::from(row_rev));
}); });
Ok(()) Ok(())
} }
fn move_group(&mut self, from_group_id: &str, to_group_id: &str) -> FlowyResult<()> { fn move_group(&mut self, _from_group_id: &str, _to_group_id: &str) -> FlowyResult<()> {
Ok(()) Ok(())
} }
fn did_update_row( fn did_update_row(
&mut self, &mut self,
row_rev: &RowRevision, _row_rev: &RowRevision,
field_rev: &FieldRevision, _field_rev: &FieldRevision,
) -> FlowyResult<Vec<GroupChangesetPB>> { ) -> FlowyResult<Vec<GroupChangesetPB>> {
todo!() todo!()
} }
fn did_delete_row( fn did_delete_row(
&mut self, &mut self,
row_rev: &RowRevision, _row_rev: &RowRevision,
field_rev: &FieldRevision, _field_rev: &FieldRevision,
) -> FlowyResult<Vec<GroupChangesetPB>> { ) -> FlowyResult<Vec<GroupChangesetPB>> {
todo!() todo!()
} }
fn move_group_row(&mut self, context: MoveGroupRowContext) -> FlowyResult<Vec<GroupChangesetPB>> { fn move_group_row(&mut self, _context: MoveGroupRowContext) -> FlowyResult<Vec<GroupChangesetPB>> {
todo!() todo!()
} }
fn did_update_field(&mut self, field_rev: &FieldRevision) -> FlowyResult<Option<GroupViewChangesetPB>> { fn did_update_field(&mut self, _field_rev: &FieldRevision) -> FlowyResult<Option<GroupViewChangesetPB>> {
Ok(None) Ok(None)
} }
} }
impl GroupController for DefaultGroupController { impl GroupController for DefaultGroupController {
fn will_create_row(&mut self, row_rev: &mut RowRevision, field_rev: &FieldRevision, group_id: &str) {} fn will_create_row(&mut self, _row_rev: &mut RowRevision, _field_rev: &FieldRevision, _group_id: &str) {}
} }

View File

@ -7,11 +7,9 @@ use crate::services::group::controller::{
GenericGroupController, GroupController, GroupGenerator, MoveGroupRowContext, GenericGroupController, GroupController, GroupGenerator, MoveGroupRowContext,
}; };
use crate::services::group::controller_impls::select_option_controller::util::*; use crate::services::group::controller_impls::select_option_controller::util::*;
use crate::services::group::entities::Group;
use crate::services::group::GeneratedGroup; use crate::services::group::GeneratedGroup;
use flowy_grid_data_model::revision::{ use flowy_grid_data_model::revision::{FieldRevision, RowRevision, SelectOptionGroupConfigurationRevision};
FieldRevision, GroupRevision, RowRevision, SelectOptionGroupConfigurationRevision,
};
// MultiSelect // MultiSelect
pub type MultiSelectGroupController = GenericGroupController< pub type MultiSelectGroupController = GenericGroupController<
@ -30,7 +28,7 @@ impl GroupAction for MultiSelectGroupController {
fn add_row_if_match(&mut self, row_rev: &RowRevision, cell_data: &Self::CellDataType) -> Vec<GroupChangesetPB> { fn add_row_if_match(&mut self, row_rev: &RowRevision, cell_data: &Self::CellDataType) -> Vec<GroupChangesetPB> {
let mut changesets = vec![]; let mut changesets = vec![];
self.configuration.iter_mut_groups(|group| { self.group_ctx.iter_mut_groups(|group| {
if let Some(changeset) = add_select_option_row(group, cell_data, row_rev) { if let Some(changeset) = add_select_option_row(group, cell_data, row_rev) {
changesets.push(changeset); changesets.push(changeset);
} }
@ -40,7 +38,7 @@ impl GroupAction for MultiSelectGroupController {
fn remove_row_if_match(&mut self, row_rev: &RowRevision, cell_data: &Self::CellDataType) -> Vec<GroupChangesetPB> { fn remove_row_if_match(&mut self, row_rev: &RowRevision, cell_data: &Self::CellDataType) -> Vec<GroupChangesetPB> {
let mut changesets = vec![]; let mut changesets = vec![];
self.configuration.iter_mut_groups(|group| { self.group_ctx.iter_mut_groups(|group| {
if let Some(changeset) = remove_select_option_row(group, cell_data, row_rev) { if let Some(changeset) = remove_select_option_row(group, cell_data, row_rev) {
changesets.push(changeset); changesets.push(changeset);
} }
@ -50,7 +48,7 @@ impl GroupAction for MultiSelectGroupController {
fn move_row(&mut self, cell_data: &Self::CellDataType, mut context: MoveGroupRowContext) -> Vec<GroupChangesetPB> { fn move_row(&mut self, cell_data: &Self::CellDataType, mut context: MoveGroupRowContext) -> Vec<GroupChangesetPB> {
let mut group_changeset = vec![]; let mut group_changeset = vec![];
self.configuration.iter_mut_groups(|group| { self.group_ctx.iter_mut_groups(|group| {
if let Some(changeset) = move_select_option_row(group, cell_data, &mut context) { if let Some(changeset) = move_select_option_row(group, cell_data, &mut context) {
group_changeset.push(changeset); group_changeset.push(changeset);
} }
@ -61,7 +59,7 @@ impl GroupAction for MultiSelectGroupController {
impl GroupController for MultiSelectGroupController { impl GroupController for MultiSelectGroupController {
fn will_create_row(&mut self, row_rev: &mut RowRevision, field_rev: &FieldRevision, group_id: &str) { fn will_create_row(&mut self, row_rev: &mut RowRevision, field_rev: &FieldRevision, group_id: &str) {
match self.configuration.get_group(group_id) { match self.group_ctx.get_group(group_id) {
None => tracing::warn!("Can not find the group: {}", group_id), None => tracing::warn!("Can not find the group: {}", group_id),
Some((_, group)) => { Some((_, group)) => {
let cell_rev = insert_select_option_cell(group.id.clone(), field_rev); let cell_rev = insert_select_option_cell(group.id.clone(), field_rev);

View File

@ -10,9 +10,7 @@ use crate::services::group::controller_impls::select_option_controller::util::*;
use crate::services::group::entities::Group; use crate::services::group::entities::Group;
use crate::services::group::GeneratedGroup; use crate::services::group::GeneratedGroup;
use flowy_grid_data_model::revision::{ use flowy_grid_data_model::revision::{FieldRevision, RowRevision, SelectOptionGroupConfigurationRevision};
FieldRevision, GroupRevision, RowRevision, SelectOptionGroupConfigurationRevision,
};
// SingleSelect // SingleSelect
pub type SingleSelectGroupController = GenericGroupController< pub type SingleSelectGroupController = GenericGroupController<
@ -30,7 +28,7 @@ impl GroupAction for SingleSelectGroupController {
fn add_row_if_match(&mut self, row_rev: &RowRevision, cell_data: &Self::CellDataType) -> Vec<GroupChangesetPB> { fn add_row_if_match(&mut self, row_rev: &RowRevision, cell_data: &Self::CellDataType) -> Vec<GroupChangesetPB> {
let mut changesets = vec![]; let mut changesets = vec![];
self.configuration.iter_mut_groups(|group| { self.group_ctx.iter_mut_groups(|group| {
if let Some(changeset) = add_select_option_row(group, cell_data, row_rev) { if let Some(changeset) = add_select_option_row(group, cell_data, row_rev) {
changesets.push(changeset); changesets.push(changeset);
} }
@ -40,7 +38,7 @@ impl GroupAction for SingleSelectGroupController {
fn remove_row_if_match(&mut self, row_rev: &RowRevision, cell_data: &Self::CellDataType) -> Vec<GroupChangesetPB> { fn remove_row_if_match(&mut self, row_rev: &RowRevision, cell_data: &Self::CellDataType) -> Vec<GroupChangesetPB> {
let mut changesets = vec![]; let mut changesets = vec![];
self.configuration.iter_mut_groups(|group| { self.group_ctx.iter_mut_groups(|group| {
if let Some(changeset) = remove_select_option_row(group, cell_data, row_rev) { if let Some(changeset) = remove_select_option_row(group, cell_data, row_rev) {
changesets.push(changeset); changesets.push(changeset);
} }
@ -50,7 +48,7 @@ impl GroupAction for SingleSelectGroupController {
fn move_row(&mut self, cell_data: &Self::CellDataType, mut context: MoveGroupRowContext) -> Vec<GroupChangesetPB> { fn move_row(&mut self, cell_data: &Self::CellDataType, mut context: MoveGroupRowContext) -> Vec<GroupChangesetPB> {
let mut group_changeset = vec![]; let mut group_changeset = vec![];
self.configuration.iter_mut_groups(|group| { self.group_ctx.iter_mut_groups(|group| {
if let Some(changeset) = move_select_option_row(group, cell_data, &mut context) { if let Some(changeset) = move_select_option_row(group, cell_data, &mut context) {
group_changeset.push(changeset); group_changeset.push(changeset);
} }
@ -61,7 +59,7 @@ impl GroupAction for SingleSelectGroupController {
impl GroupController for SingleSelectGroupController { impl GroupController for SingleSelectGroupController {
fn will_create_row(&mut self, row_rev: &mut RowRevision, field_rev: &FieldRevision, group_id: &str) { fn will_create_row(&mut self, row_rev: &mut RowRevision, field_rev: &FieldRevision, group_id: &str) {
let group: Option<&mut Group> = self.configuration.get_mut_group(group_id); let group: Option<&mut Group> = self.group_ctx.get_mut_group(group_id);
match group { match group {
None => {} None => {}
Some(group) => { Some(group) => {

View File

@ -127,8 +127,8 @@ pub fn move_select_option_row(
} }
pub fn generate_select_option_groups( pub fn generate_select_option_groups(
field_id: &str, _field_id: &str,
group_ctx: &SelectOptionGroupContext, _group_ctx: &SelectOptionGroupContext,
options: &[SelectOptionPB], options: &[SelectOptionPB],
) -> Vec<GeneratedGroup> { ) -> Vec<GeneratedGroup> {
let groups = options let groups = options

View File

@ -16,7 +16,7 @@ use std::sync::Arc;
#[tracing::instrument(level = "trace", skip_all, err)] #[tracing::instrument(level = "trace", skip_all, err)]
pub async fn make_group_controller<R, W>( pub async fn make_group_controller<R, W>(
view_id: String, view_id: String,
field_revs: Vec<Arc<FieldRevision>>, field_rev: Arc<FieldRevision>,
row_revs: Vec<Arc<RowRevision>>, row_revs: Vec<Arc<RowRevision>>,
configuration_reader: R, configuration_reader: R,
configuration_writer: W, configuration_writer: W,
@ -25,11 +25,12 @@ where
R: GroupConfigurationReader, R: GroupConfigurationReader,
W: GroupConfigurationWriter, W: GroupConfigurationWriter,
{ {
let field_rev = find_group_field(&field_revs).unwrap();
let field_type: FieldType = field_rev.ty.into(); let field_type: FieldType = field_rev.ty.into();
let mut group_controller: Box<dyn GroupController>; let mut group_controller: Box<dyn GroupController>;
let configuration_reader = Arc::new(configuration_reader); let configuration_reader = Arc::new(configuration_reader);
let configuration_writer = Arc::new(configuration_writer); let configuration_writer = Arc::new(configuration_writer);
match field_type { match field_type {
FieldType::SingleSelect => { FieldType::SingleSelect => {
let configuration = let configuration =
@ -61,7 +62,7 @@ where
Ok(group_controller) Ok(group_controller)
} }
fn find_group_field(field_revs: &[Arc<FieldRevision>]) -> Option<Arc<FieldRevision>> { pub fn find_group_field(field_revs: &[Arc<FieldRevision>]) -> Option<Arc<FieldRevision>> {
let field_rev = field_revs let field_rev = field_revs
.iter() .iter()
.find(|field_rev| { .find(|field_rev| {

View File

@ -195,6 +195,8 @@ fn make_test_grid() -> BuildGridContext {
FieldType::SingleSelect => { FieldType::SingleSelect => {
row_builder.insert_single_select_cell(|mut options| options.remove(0)) row_builder.insert_single_select_cell(|mut options| options.remove(0))
} }
FieldType::MultiSelect => row_builder
.insert_multi_select_cell(|mut options| vec![options.remove(0), options.remove(0)]),
FieldType::Checkbox => row_builder.insert_checkbox_cell("true"), FieldType::Checkbox => row_builder.insert_checkbox_cell("true"),
_ => "".to_owned(), _ => "".to_owned(),
}; };
@ -209,6 +211,8 @@ fn make_test_grid() -> BuildGridContext {
FieldType::SingleSelect => { FieldType::SingleSelect => {
row_builder.insert_single_select_cell(|mut options| options.remove(0)) row_builder.insert_single_select_cell(|mut options| options.remove(0))
} }
FieldType::MultiSelect => row_builder
.insert_multi_select_cell(|mut options| vec![options.remove(0), options.remove(0)]),
FieldType::Checkbox => row_builder.insert_checkbox_cell("true"), FieldType::Checkbox => row_builder.insert_checkbox_cell("true"),
_ => "".to_owned(), _ => "".to_owned(),
}; };
@ -223,6 +227,9 @@ fn make_test_grid() -> BuildGridContext {
FieldType::SingleSelect => { FieldType::SingleSelect => {
row_builder.insert_single_select_cell(|mut options| options.remove(1)) row_builder.insert_single_select_cell(|mut options| options.remove(1))
} }
FieldType::MultiSelect => {
row_builder.insert_multi_select_cell(|mut options| vec![options.remove(0)])
}
FieldType::Checkbox => row_builder.insert_checkbox_cell("false"), FieldType::Checkbox => row_builder.insert_checkbox_cell("false"),
_ => "".to_owned(), _ => "".to_owned(),
}; };

View File

@ -1,13 +1,13 @@
use crate::grid::grid_editor::GridEditorTest; use crate::grid::grid_editor::GridEditorTest;
use flowy_grid::entities::{ use flowy_grid::entities::{
CreateRowParams, FieldChangesetParams, FieldType, GridLayout, GroupPB, MoveGroupParams, MoveGroupRowParams, RowPB, CreateRowParams, FieldType, GridLayout, GroupPB, MoveGroupParams, MoveGroupRowParams, RowPB,
}; };
use flowy_grid::services::cell::{delete_select_option_cell, insert_select_option_cell}; use flowy_grid::services::cell::{delete_select_option_cell, insert_select_option_cell};
use flowy_grid::services::field::{select_option_operation, SelectOptionOperation}; use flowy_grid::services::field::{
edit_single_select_type_option, SelectOptionOperation, SelectOptionPB, SingleSelectTypeOptionPB,
};
use flowy_grid_data_model::revision::{FieldRevision, RowChangeset}; use flowy_grid_data_model::revision::{FieldRevision, RowChangeset};
use std::sync::Arc; use std::sync::Arc;
use std::time::Duration;
use tokio::time::interval;
pub enum GroupScript { pub enum GroupScript {
AssertGroupRowCount { AssertGroupRowCount {
@ -46,10 +46,10 @@ pub enum GroupScript {
from_group_index: usize, from_group_index: usize,
to_group_index: usize, to_group_index: usize,
}, },
UpdateField { UpdateSingleSelectOption {
changeset: FieldChangesetParams, inserted_options: Vec<SelectOptionPB>,
}, },
GroupField { GroupByField {
field_id: String, field_id: String,
}, },
} }
@ -179,12 +179,15 @@ impl GridGroupTest {
assert_eq!(group.group_id, group_pb.group_id); assert_eq!(group.group_id, group_pb.group_id);
assert_eq!(group.desc, group_pb.desc); assert_eq!(group.desc, group_pb.desc);
} }
GroupScript::UpdateField { changeset } => { GroupScript::UpdateSingleSelectOption { inserted_options } => {
self.editor.update_field(changeset).await.unwrap(); self.edit_single_select_type_option(|type_option| {
let mut interval = interval(Duration::from_millis(130)); for inserted_option in inserted_options {
interval.tick().await; type_option.insert_option(inserted_option);
}
})
.await;
} }
GroupScript::GroupField { field_id } => { GroupScript::GroupByField { field_id } => {
self.editor.group_field(&field_id).await.unwrap(); self.editor.group_field(&field_id).await.unwrap();
} }
} }
@ -200,6 +203,7 @@ impl GridGroupTest {
groups.rows.get(row_index).unwrap().clone() groups.rows.get(row_index).unwrap().clone()
} }
#[allow(dead_code)]
pub async fn get_multi_select_field(&self) -> Arc<FieldRevision> { pub async fn get_multi_select_field(&self) -> Arc<FieldRevision> {
let field = self let field = self
.inner .inner
@ -211,7 +215,7 @@ impl GridGroupTest {
}) })
.unwrap() .unwrap()
.clone(); .clone();
return field; field
} }
pub async fn get_single_select_field(&self) -> Arc<FieldRevision> { pub async fn get_single_select_field(&self) -> Arc<FieldRevision> {
@ -226,14 +230,11 @@ impl GridGroupTest {
.clone() .clone()
} }
pub async fn edit_single_select_type_option(&self, f: impl FnOnce(Box<dyn SelectOptionOperation>)) { pub async fn edit_single_select_type_option(&self, action: impl FnOnce(&mut SingleSelectTypeOptionPB)) {
let single_select = self.get_single_select_field().await; let single_select = self.get_single_select_field().await;
let mut field_rev = self.editor.get_field_rev(&single_select.id).await.unwrap(); edit_single_select_type_option(&single_select.id, self.editor.clone(), action)
let mut_field_rev = Arc::make_mut(&mut field_rev); .await
let mut type_option = select_option_operation(mut_field_rev)?; .unwrap();
f(type_option);
mut_field_rev.insert_type_option(&*type_option);
let _ = self.editor.replace_field(field_rev).await?;
} }
} }

View File

@ -1,6 +1,7 @@
use crate::grid::group_test::script::GridGroupTest; use crate::grid::group_test::script::GridGroupTest;
use crate::grid::group_test::script::GroupScript::*; use crate::grid::group_test::script::GroupScript::*;
use flowy_grid::entities::FieldChangesetParams;
use flowy_grid::services::field::SelectOptionPB;
#[tokio::test] #[tokio::test]
async fn group_init_test() { async fn group_init_test() {
@ -370,32 +371,41 @@ async fn group_move_group_test() {
} }
#[tokio::test] #[tokio::test]
async fn group_update_field_test() { async fn group_insert_single_select_option_test() {
let mut test = GridGroupTest::new().await; let mut test = GridGroupTest::new().await;
let group = test.group_at_index(0).await; let new_option_name = "New option";
let changeset = FieldChangesetParams {
field_id: group.field_id.clone(),
grid_id: test.grid_id.clone(),
name: Some("ABC".to_string()),
..Default::default()
};
// group.desc = "ABC".to_string();
let scripts = vec![ let scripts = vec![
UpdateField { changeset }, AssertGroupCount(4),
AssertGroup { UpdateSingleSelectOption {
group_index: 0, inserted_options: vec![SelectOptionPB::new(new_option_name)],
expected_group: group,
}, },
AssertGroupCount(5),
];
test.run_scripts(scripts).await;
// the group at index 4 is the default_group, so the new insert group will be the
// index 3.
let group_3 = test.group_at_index(3).await;
assert_eq!(group_3.desc, new_option_name);
}
#[tokio::test]
async fn group_group_by_other_field() {
let mut test = GridGroupTest::new().await;
let multi_select_field = test.get_multi_select_field().await;
let scripts = vec![
GroupByField {
field_id: multi_select_field.id.clone(),
},
AssertGroupRowCount {
group_index: 0,
row_count: 3,
},
AssertGroupRowCount {
group_index: 1,
row_count: 2,
},
AssertGroupCount(4),
]; ];
test.run_scripts(scripts).await; 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

@ -60,7 +60,7 @@ where
.cloned() .cloned()
} }
pub fn get_all_objects(&self, field_revs: &[Arc<FieldRevision>]) -> Option<HashMap<String, Vec<Arc<T>>>> { pub fn get_objects_by_field_revs(&self, field_revs: &[Arc<FieldRevision>]) -> Option<HashMap<String, Vec<Arc<T>>>> {
// Get the objects according to the FieldType, so we need iterate the field_revs. // Get the objects according to the FieldType, so we need iterate the field_revs.
let objects_by_field_id = field_revs let objects_by_field_id = field_revs
.iter() .iter()
@ -76,6 +76,10 @@ where
Some(objects_by_field_id) Some(objects_by_field_id)
} }
pub fn get_all_objects(&self) -> Vec<Arc<T>> {
self.inner.values().map(|map| map.all_objects()).flatten().collect()
}
/// add object to the end of the list /// add object to the end of the list
pub fn add_object(&mut self, field_id: &str, field_type: &FieldTypeRevision, object: T) { pub fn add_object(&mut self, field_id: &str, field_type: &FieldTypeRevision, object: T) {
let object_rev_map = self let object_rev_map = self
@ -111,6 +115,10 @@ where
pub fn new() -> Self { pub fn new() -> Self {
ObjectIndexMap::default() ObjectIndexMap::default()
} }
pub fn all_objects(&self) -> Vec<Arc<T>> {
self.object_by_field_type.values().cloned().flatten().collect()
}
} }
impl<T> std::ops::Deref for ObjectIndexMap<T> impl<T> std::ops::Deref for ObjectIndexMap<T>

View File

@ -48,8 +48,12 @@ impl GridViewRevisionPad {
Self::from_delta(delta) Self::from_delta(delta)
} }
pub fn get_all_groups(&self, field_revs: &[Arc<FieldRevision>]) -> Option<GroupConfigurationsByFieldId> { pub fn get_groups_by_field_revs(&self, field_revs: &[Arc<FieldRevision>]) -> Option<GroupConfigurationsByFieldId> {
self.groups.get_all_objects(field_revs) self.groups.get_objects_by_field_revs(field_revs)
}
pub fn get_all_groups(&self) -> Vec<Arc<GroupConfigurationRevision>> {
self.groups.get_all_objects()
} }
#[tracing::instrument(level = "trace", skip_all, err)] #[tracing::instrument(level = "trace", skip_all, err)]
@ -111,7 +115,7 @@ impl GridViewRevisionPad {
} }
pub fn get_all_filters(&self, field_revs: &[Arc<FieldRevision>]) -> Option<FilterConfigurationsByFieldId> { pub fn get_all_filters(&self, field_revs: &[Arc<FieldRevision>]) -> Option<FilterConfigurationsByFieldId> {
self.filters.get_all_objects(field_revs) self.filters.get_objects_by_field_revs(field_revs)
} }
pub fn get_filters( pub fn get_filters(

View File

@ -178,7 +178,7 @@ mod tests {
node_type: "text".into(), node_type: "text".into(),
attributes: NodeAttributes::new(), attributes: NodeAttributes::new(),
delta: None, delta: None,
children: vec![Box::new(NodeSubTree::new("text".into()))], children: vec![Box::new(NodeSubTree::new("text"))],
})], })],
}; };
let result = serde_json::to_string(&insert).unwrap(); let result = serde_json::to_string(&insert).unwrap();

View File

@ -1,3 +1,4 @@
#![allow(clippy::module_inception)]
mod attributes; mod attributes;
mod document; mod document;
mod document_operation; mod document_operation;

View File

@ -13,7 +13,7 @@ fn test_documents() {
let mut document = DocumentTree::new(); let mut document = DocumentTree::new();
let transaction = { let transaction = {
let mut tb = TransactionBuilder::new(&document); let mut tb = TransactionBuilder::new(&document);
tb.insert_nodes_at_path(&vec![0].into(), &vec![Box::new(NodeSubTree::new("text"))]); tb.insert_nodes_at_path(&vec![0].into(), &[Box::new(NodeSubTree::new("text"))]);
tb.finalize() tb.finalize()
}; };
document.apply(transaction).unwrap(); document.apply(transaction).unwrap();
@ -47,16 +47,16 @@ fn test_inserts_nodes() {
let mut document = DocumentTree::new(); let mut document = DocumentTree::new();
let transaction = { let transaction = {
let mut tb = TransactionBuilder::new(&document); let mut tb = TransactionBuilder::new(&document);
tb.insert_nodes_at_path(&vec![0].into(), &vec![Box::new(NodeSubTree::new("text"))]); tb.insert_nodes_at_path(&vec![0].into(), &[Box::new(NodeSubTree::new("text"))]);
tb.insert_nodes_at_path(&vec![1].into(), &vec![Box::new(NodeSubTree::new("text"))]); tb.insert_nodes_at_path(&vec![1].into(), &[Box::new(NodeSubTree::new("text"))]);
tb.insert_nodes_at_path(&vec![2].into(), &vec![Box::new(NodeSubTree::new("text"))]); tb.insert_nodes_at_path(&vec![2].into(), &[Box::new(NodeSubTree::new("text"))]);
tb.finalize() tb.finalize()
}; };
document.apply(transaction).unwrap(); document.apply(transaction).unwrap();
let transaction = { let transaction = {
let mut tb = TransactionBuilder::new(&document); let mut tb = TransactionBuilder::new(&document);
tb.insert_nodes_at_path(&vec![1].into(), &vec![Box::new(NodeSubTree::new("text"))]); tb.insert_nodes_at_path(&vec![1].into(), &[Box::new(NodeSubTree::new("text"))]);
tb.finalize() tb.finalize()
}; };
document.apply(transaction).unwrap(); document.apply(transaction).unwrap();
@ -69,11 +69,11 @@ fn test_inserts_subtrees() {
let mut tb = TransactionBuilder::new(&document); let mut tb = TransactionBuilder::new(&document);
tb.insert_nodes_at_path( tb.insert_nodes_at_path(
&vec![0].into(), &vec![0].into(),
&vec![Box::new(NodeSubTree { &[Box::new(NodeSubTree {
node_type: "text".into(), node_type: "text".into(),
attributes: NodeAttributes::new(), attributes: NodeAttributes::new(),
delta: None, delta: None,
children: vec![Box::new(NodeSubTree::new("image".into()))], children: vec![Box::new(NodeSubTree::new("image"))],
})], })],
); );
tb.finalize() tb.finalize()
@ -90,9 +90,9 @@ fn test_update_nodes() {
let mut document = DocumentTree::new(); let mut document = DocumentTree::new();
let transaction = { let transaction = {
let mut tb = TransactionBuilder::new(&document); let mut tb = TransactionBuilder::new(&document);
tb.insert_nodes_at_path(&vec![0].into(), &vec![Box::new(NodeSubTree::new("text"))]); tb.insert_nodes_at_path(&vec![0].into(), &[Box::new(NodeSubTree::new("text"))]);
tb.insert_nodes_at_path(&vec![1].into(), &vec![Box::new(NodeSubTree::new("text"))]); tb.insert_nodes_at_path(&vec![1].into(), &[Box::new(NodeSubTree::new("text"))]);
tb.insert_nodes_at_path(&vec![2].into(), &vec![Box::new(NodeSubTree::new("text"))]); tb.insert_nodes_at_path(&vec![2].into(), &[Box::new(NodeSubTree::new("text"))]);
tb.finalize() tb.finalize()
}; };
document.apply(transaction).unwrap(); document.apply(transaction).unwrap();
@ -115,9 +115,9 @@ fn test_delete_nodes() {
let mut document = DocumentTree::new(); let mut document = DocumentTree::new();
let transaction = { let transaction = {
let mut tb = TransactionBuilder::new(&document); let mut tb = TransactionBuilder::new(&document);
tb.insert_nodes_at_path(&vec![0].into(), &vec![Box::new(NodeSubTree::new("text"))]); tb.insert_nodes_at_path(&vec![0].into(), &[Box::new(NodeSubTree::new("text"))]);
tb.insert_nodes_at_path(&vec![1].into(), &vec![Box::new(NodeSubTree::new("text"))]); tb.insert_nodes_at_path(&vec![1].into(), &[Box::new(NodeSubTree::new("text"))]);
tb.insert_nodes_at_path(&vec![2].into(), &vec![Box::new(NodeSubTree::new("text"))]); tb.insert_nodes_at_path(&vec![2].into(), &[Box::new(NodeSubTree::new("text"))]);
tb.finalize() tb.finalize()
}; };
document.apply(transaction).unwrap(); document.apply(transaction).unwrap();
@ -138,8 +138,8 @@ fn test_errors() {
let mut document = DocumentTree::new(); let mut document = DocumentTree::new();
let transaction = { let transaction = {
let mut tb = TransactionBuilder::new(&document); let mut tb = TransactionBuilder::new(&document);
tb.insert_nodes_at_path(&vec![0].into(), &vec![Box::new(NodeSubTree::new("text"))]); tb.insert_nodes_at_path(&vec![0].into(), &[Box::new(NodeSubTree::new("text"))]);
tb.insert_nodes_at_path(&vec![100].into(), &vec![Box::new(NodeSubTree::new("text"))]); tb.insert_nodes_at_path(&vec![100].into(), &[Box::new(NodeSubTree::new("text"))]);
tb.finalize() tb.finalize()
}; };
let result = document.apply(transaction); let result = document.apply(transaction);