fix: fix some bugs

This commit is contained in:
appflowy 2022-08-22 16:16:15 +08:00
parent ffc6f141fa
commit 074c497d57
27 changed files with 486 additions and 252 deletions

View File

@ -29,7 +29,7 @@
"program": "./lib/main.dart", "program": "./lib/main.dart",
"type": "dart", "type": "dart",
"env": { "env": {
"RUST_LOG": "trace" "RUST_LOG": "debug"
}, },
"cwd": "${workspaceRoot}/app_flowy" "cwd": "${workspaceRoot}/app_flowy"
}, },

View File

@ -23,7 +23,7 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
final BoardDataController _dataController; final BoardDataController _dataController;
late final AFBoardDataController afBoardDataController; late final AFBoardDataController afBoardDataController;
final MoveRowFFIService _rowService; final MoveRowFFIService _rowService;
Map<String, GroupController> groupControllers = {}; LinkedHashMap<String, GroupController> groupControllers = LinkedHashMap.new();
GridFieldCache get fieldCache => _dataController.fieldCache; GridFieldCache get fieldCache => _dataController.fieldCache;
String get gridId => _dataController.gridId; String get gridId => _dataController.gridId;
@ -34,9 +34,13 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
super(BoardState.initial(view.id)) { super(BoardState.initial(view.id)) {
afBoardDataController = AFBoardDataController( afBoardDataController = AFBoardDataController(
onMoveColumn: ( onMoveColumn: (
fromColumnId,
fromIndex, fromIndex,
toColumnId,
toIndex, toIndex,
) {}, ) {
_moveGroup(fromColumnId, toColumnId);
},
onMoveColumnItem: ( onMoveColumnItem: (
columnId, columnId,
fromIndex, fromIndex,
@ -44,7 +48,7 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
) { ) {
final fromRow = groupControllers[columnId]?.rowAtIndex(fromIndex); final fromRow = groupControllers[columnId]?.rowAtIndex(fromIndex);
final toRow = groupControllers[columnId]?.rowAtIndex(toIndex); final toRow = groupControllers[columnId]?.rowAtIndex(toIndex);
_moveRow(fromRow, toRow); _moveRow(fromRow, columnId, toRow);
}, },
onMoveColumnItemToColumn: ( onMoveColumnItemToColumn: (
fromColumnId, fromColumnId,
@ -54,7 +58,7 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
) { ) {
final fromRow = groupControllers[fromColumnId]?.rowAtIndex(fromIndex); final fromRow = groupControllers[fromColumnId]?.rowAtIndex(fromIndex);
final toRow = groupControllers[toColumnId]?.rowAtIndex(toIndex); final toRow = groupControllers[toColumnId]?.rowAtIndex(toIndex);
_moveRow(fromRow, toRow); _moveRow(fromRow, toColumnId, toRow);
}, },
); );
@ -95,12 +99,13 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
); );
} }
void _moveRow(RowPB? fromRow, RowPB? toRow) { void _moveRow(RowPB? fromRow, String columnId, RowPB? toRow) {
if (fromRow != null && toRow != null) { if (fromRow != null) {
_rowService _rowService
.moveRow( .moveGroupRow(
fromRowId: fromRow.id, fromRowId: fromRow.id,
toRowId: toRow.id, toGroupId: columnId,
toRowId: toRow?.id,
) )
.then((result) { .then((result) {
result.fold((l) => null, (r) => add(BoardEvent.didReceiveError(r))); result.fold((l) => null, (r) => add(BoardEvent.didReceiveError(r)));
@ -108,6 +113,17 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
} }
} }
void _moveGroup(String fromColumnId, String toColumnId) {
_rowService
.moveGroup(
fromGroupId: fromColumnId,
toGroupId: toColumnId,
)
.then((result) {
result.fold((l) => null, (r) => add(BoardEvent.didReceiveError(r)));
});
}
@override @override
Future<void> close() async { Future<void> close() async {
await _dataController.dispose(); await _dataController.dispose();

View File

@ -37,6 +37,14 @@ class GroupController {
(GroupRowsChangesetPB changeset) { (GroupRowsChangesetPB changeset) {
for (final insertedRow in changeset.insertedRows) { for (final insertedRow in changeset.insertedRows) {
final index = insertedRow.hasIndex() ? insertedRow.index : null; final index = insertedRow.hasIndex() ? insertedRow.index : null;
if (insertedRow.hasIndex() &&
group.rows.length > insertedRow.index) {
group.rows.insert(insertedRow.index, insertedRow.row);
} else {
group.rows.add(insertedRow.row);
}
delegate.insertRow( delegate.insertRow(
group.groupId, group.groupId,
insertedRow.row, insertedRow.row,
@ -45,10 +53,19 @@ class GroupController {
} }
for (final deletedRow in changeset.deletedRows) { for (final deletedRow in changeset.deletedRows) {
group.rows.removeWhere((rowPB) => rowPB.id == deletedRow);
delegate.removeRow(group.groupId, deletedRow); delegate.removeRow(group.groupId, deletedRow);
} }
for (final updatedRow in changeset.updatedRows) { for (final updatedRow in changeset.updatedRows) {
final index = group.rows.indexWhere(
(rowPB) => rowPB.id == updatedRow.id,
);
if (index != -1) {
group.rows[index] = updatedRow;
}
delegate.updateRow(group.groupId, updatedRow); delegate.updateRow(group.groupId, updatedRow);
} }
}, },

View File

@ -31,7 +31,7 @@ class BoardPluginBuilder implements PluginBuilder {
class BoardPluginConfig implements PluginConfig { class BoardPluginConfig implements PluginConfig {
@override @override
bool get creatable => true; bool get creatable => false;
} }
class BoardPlugin extends Plugin { class BoardPlugin extends Plugin {

View File

@ -3,6 +3,7 @@ import 'package:flowy_sdk/dispatch/dispatch.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/block_entities.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/block_entities.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/grid_entities.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/grid_entities.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/group_changeset.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/row_entities.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/row_entities.pb.dart';
class RowFFIService { class RowFFIService {
@ -68,4 +69,33 @@ class MoveRowFFIService {
return GridEventMoveRow(payload).send(); return GridEventMoveRow(payload).send();
} }
Future<Either<Unit, FlowyError>> moveGroupRow({
required String fromRowId,
required String toGroupId,
required String? toRowId,
}) {
var payload = MoveGroupRowPayloadPB.create()
..viewId = gridId
..fromRowId = fromRowId
..toGroupId = toGroupId;
if (toRowId != null) {
payload.toRowId = toRowId;
}
return GridEventMoveGroupRow(payload).send();
}
Future<Either<Unit, FlowyError>> moveGroup({
required String fromGroupId,
required String toGroupId,
}) {
final payload = MoveGroupPayloadPB.create()
..viewId = gridId
..fromGroupId = fromGroupId
..toGroupId = toGroupId;
return GridEventMoveGroup(payload).send();
}
} }

View File

@ -10,7 +10,7 @@ class MultiBoardListExample extends StatefulWidget {
class _MultiBoardListExampleState extends State<MultiBoardListExample> { class _MultiBoardListExampleState extends State<MultiBoardListExample> {
final AFBoardDataController boardDataController = AFBoardDataController( final AFBoardDataController boardDataController = AFBoardDataController(
onMoveColumn: (fromIndex, toIndex) { onMoveColumn: (fromColumnId, fromIndex, toColumnId, toIndex) {
debugPrint('Move column from $fromIndex to $toIndex'); debugPrint('Move column from $fromIndex to $toIndex');
}, },
onMoveColumnItem: (columnId, fromIndex, toIndex) { onMoveColumnItem: (columnId, fromIndex, toIndex) {

View File

@ -145,7 +145,8 @@ class AFBoardColumnData<CustomData> extends ReoderFlexItem with EquatableMixin {
}) : _items = items; }) : _items = items;
/// Returns the readonly List<ColumnItem> /// Returns the readonly List<ColumnItem>
UnmodifiableListView<AFColumnItem> get items => UnmodifiableListView(_items); UnmodifiableListView<AFColumnItem> get items =>
UnmodifiableListView([..._items]);
@override @override
List<Object?> get props => [id, ..._items]; List<Object?> get props => [id, ..._items];

View File

@ -8,7 +8,12 @@ import 'reorder_flex/reorder_flex.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'reorder_phantom/phantom_controller.dart'; import 'reorder_phantom/phantom_controller.dart';
typedef OnMoveColumn = void Function(int fromIndex, int toIndex); typedef OnMoveColumn = void Function(
String fromColumnId,
int fromIndex,
String toColumnId,
int toIndex,
);
typedef OnMoveColumnItem = void Function( typedef OnMoveColumnItem = void Function(
String columnId, String columnId,
@ -98,9 +103,11 @@ class AFBoardDataController extends ChangeNotifier
} }
void moveColumn(int fromIndex, int toIndex, {bool notify = true}) { void moveColumn(int fromIndex, int toIndex, {bool notify = true}) {
final columnData = _columnDatas.removeAt(fromIndex); final toColumnData = _columnDatas[toIndex];
_columnDatas.insert(toIndex, columnData); final fromColumnData = _columnDatas.removeAt(fromIndex);
onMoveColumn?.call(fromIndex, toIndex);
_columnDatas.insert(toIndex, fromColumnData);
onMoveColumn?.call(fromColumnData.id, fromIndex, toColumnData.id, toIndex);
if (notify) notifyListeners(); if (notify) notifyListeners();
} }

View File

@ -123,3 +123,46 @@ impl TryInto<MoveRowParams> for MoveRowPayloadPB {
}) })
} }
} }
#[derive(Debug, Clone, Default, ProtoBuf)]
pub struct MoveGroupRowPayloadPB {
#[pb(index = 1)]
pub view_id: String,
#[pb(index = 2)]
pub from_row_id: String,
#[pb(index = 3)]
pub to_group_id: String,
#[pb(index = 4, one_of)]
pub to_row_id: Option<String>,
}
pub struct MoveGroupRowParams {
pub view_id: String,
pub from_row_id: String,
pub to_group_id: String,
pub to_row_id: Option<String>,
}
impl TryInto<MoveGroupRowParams> for MoveGroupRowPayloadPB {
type Error = ErrorCode;
fn try_into(self) -> Result<MoveGroupRowParams, Self::Error> {
let view_id = NotEmptyStr::parse(self.view_id).map_err(|_| ErrorCode::GridViewIdIsEmpty)?;
let from_row_id = NotEmptyStr::parse(self.from_row_id).map_err(|_| ErrorCode::RowIdIsEmpty)?;
let to_group_id = NotEmptyStr::parse(self.to_group_id).map_err(|_| ErrorCode::GroupIdIsEmpty)?;
let to_row_id = match self.to_row_id {
None => None,
Some(to_row_id) => Some(NotEmptyStr::parse(to_row_id).map_err(|_| ErrorCode::RowIdIsEmpty)?.0),
};
Ok(MoveGroupRowParams {
view_id: view_id.0,
from_row_id: from_row_id.0,
to_group_id: to_group_id.0,
to_row_id,
})
}
}

View File

@ -436,3 +436,14 @@ pub(crate) async fn move_group_handler(
let _ = editor.move_group(params).await?; let _ = editor.move_group(params).await?;
Ok(()) Ok(())
} }
#[tracing::instrument(level = "debug", skip(data, manager), err)]
pub(crate) async fn move_group_row_handler(
data: Data<MoveGroupRowPayloadPB>,
manager: AppData<Arc<GridManager>>,
) -> FlowyResult<()> {
let params: MoveGroupRowParams = data.into_inner().try_into()?;
let editor = manager.get_grid_editor(params.view_id.as_ref())?;
let _ = editor.move_group_row(params).await?;
Ok(())
}

View File

@ -42,6 +42,7 @@ pub fn create(grid_manager: Arc<GridManager>) -> Module {
// Group // Group
.event(GridEvent::CreateBoardCard, create_board_card_handler) .event(GridEvent::CreateBoardCard, create_board_card_handler)
.event(GridEvent::MoveGroup, move_group_handler) .event(GridEvent::MoveGroup, move_group_handler)
.event(GridEvent::MoveGroupRow, move_group_row_handler)
.event(GridEvent::GetGroup, get_groups_handler); .event(GridEvent::GetGroup, get_groups_handler);
module module
@ -221,4 +222,7 @@ pub enum GridEvent {
#[event(input = "MoveGroupPayloadPB")] #[event(input = "MoveGroupPayloadPB")]
MoveGroup = 111, MoveGroup = 111,
#[event(input = "MoveGroupRowPayloadPB")]
MoveGroupRow = 112,
} }

View File

@ -560,16 +560,6 @@ impl GridRevisionEditor {
.block_manager .block_manager
.move_row(row_rev.clone(), from_index, to_index) .move_row(row_rev.clone(), from_index, to_index)
.await?; .await?;
if let Some(row_changeset) = self.view_manager.move_row(row_rev, to_row_id.clone()).await {
tracing::trace!("Receive row changeset after moving the row");
match self.block_manager.update_row(row_changeset).await {
Ok(_) => {}
Err(e) => {
tracing::error!("Apply row changeset error:{:?}", e);
}
}
}
} }
(_, None) => tracing::warn!("Can not find the from row id: {}", from_row_id), (_, None) => tracing::warn!("Can not find the from row id: {}", from_row_id),
(None, _) => tracing::warn!("Can not find the to row id: {}", to_row_id), (None, _) => tracing::warn!("Can not find the to row id: {}", to_row_id),
@ -579,6 +569,35 @@ impl GridRevisionEditor {
Ok(()) Ok(())
} }
pub async fn move_group_row(&self, params: MoveGroupRowParams) -> FlowyResult<()> {
let MoveGroupRowParams {
view_id: _,
from_row_id,
to_group_id,
to_row_id,
} = params;
match self.block_manager.get_row_rev(&from_row_id).await? {
None => tracing::warn!("Move row failed, can not find the row:{}", from_row_id),
Some(row_rev) => {
if let Some(row_changeset) = self
.view_manager
.move_group_row(row_rev, to_group_id, to_row_id.clone())
.await
{
match self.block_manager.update_row(row_changeset).await {
Ok(_) => {}
Err(e) => {
tracing::error!("Apply row changeset error:{:?}", e);
}
}
}
}
}
Ok(())
}
pub async fn move_field(&self, params: MoveFieldParams) -> FlowyResult<()> { pub async fn move_field(&self, params: MoveFieldParams) -> FlowyResult<()> {
let MoveFieldParams { let MoveFieldParams {
grid_id: _, grid_id: _,

View File

@ -80,7 +80,7 @@ impl GridViewRevisionEditor {
None => {} None => {}
Some(group_id) => { Some(group_id) => {
self.group_service self.group_service
.read() .write()
.await .await
.will_create_row(row_rev, group_id, |field_id| { .will_create_row(row_rev, group_id, |field_id| {
self.field_delegate.get_field_rev(&field_id) self.field_delegate.get_field_rev(&field_id)
@ -109,7 +109,7 @@ impl GridViewRevisionEditor {
// Send the group notification if the current view has groups; // Send the group notification if the current view has groups;
if let Some(changesets) = self if let Some(changesets) = self
.group_service .group_service
.read() .write()
.await .await
.did_delete_row(row_rev, |field_id| self.field_delegate.get_field_rev(&field_id)) .did_delete_row(row_rev, |field_id| self.field_delegate.get_field_rev(&field_id))
.await .await
@ -123,7 +123,7 @@ impl GridViewRevisionEditor {
pub(crate) async fn did_update_row(&self, row_rev: &RowRevision) { pub(crate) async fn did_update_row(&self, row_rev: &RowRevision) {
if let Some(changesets) = self if let Some(changesets) = self
.group_service .group_service
.read() .write()
.await .await
.did_update_row(row_rev, |field_id| self.field_delegate.get_field_rev(&field_id)) .did_update_row(row_rev, |field_id| self.field_delegate.get_field_rev(&field_id))
.await .await
@ -134,23 +134,23 @@ impl GridViewRevisionEditor {
} }
} }
pub(crate) async fn did_move_row( pub(crate) async fn move_group_row(
&self, &self,
row_rev: &RowRevision, row_rev: &RowRevision,
row_changeset: &mut RowChangeset, row_changeset: &mut RowChangeset,
upper_row_id: &str, to_group_id: &str,
to_row_id: Option<String>,
) { ) {
if let Some(changesets) = self if let Some(changesets) = self
.group_service .group_service
.read() .write()
.await .await
.did_move_row(row_rev, row_changeset, upper_row_id, |field_id| { .move_group_row(row_rev, row_changeset, to_group_id, to_row_id, |field_id| {
self.field_delegate.get_field_rev(&field_id) self.field_delegate.get_field_rev(&field_id)
}) })
.await .await
{ {
for changeset in changesets { for changeset in changesets {
tracing::trace!("Group: {} changeset: {}", changeset.group_id, changeset);
self.notify_did_update_group_rows(changeset).await; self.notify_did_update_group_rows(changeset).await;
} }
} }
@ -184,7 +184,7 @@ impl GridViewRevisionEditor {
pub(crate) async fn move_group(&self, params: MoveGroupParams) -> FlowyResult<()> { pub(crate) async fn move_group(&self, params: MoveGroupParams) -> FlowyResult<()> {
let _ = self let _ = self
.group_service .group_service
.read() .write()
.await .await
.move_group(&params.from_group_id, &params.to_group_id) .move_group(&params.from_group_id, &params.to_group_id)
.await?; .await?;
@ -326,7 +326,6 @@ impl GroupConfigurationReader for GroupConfigurationReaderImpl {
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.groups.get_objects(&field_rev.id, &field_rev.ty)?;
if groups.is_empty() { if groups.is_empty() {
None None
} else { } else {

View File

@ -129,10 +129,17 @@ impl GridViewManager {
/// It may generate a RowChangeset when the Row was moved from one group to another. /// It may generate a RowChangeset when the Row was moved from one group to another.
/// The return value, [RowChangeset], contains the changes made by the groups. /// The return value, [RowChangeset], contains the changes made by the groups.
/// ///
pub(crate) async fn move_row(&self, row_rev: Arc<RowRevision>, to_row_id: String) -> Option<RowChangeset> { pub(crate) async fn move_group_row(
&self,
row_rev: Arc<RowRevision>,
to_group_id: String,
to_row_id: Option<String>,
) -> Option<RowChangeset> {
let mut row_changeset = RowChangeset::new(row_rev.id.clone()); let mut row_changeset = RowChangeset::new(row_rev.id.clone());
for view_editor in self.view_editors.iter() { for view_editor in self.view_editors.iter() {
view_editor.did_move_row(&row_rev, &mut row_changeset, &to_row_id).await; view_editor
.move_group_row(&row_rev, &mut row_changeset, &to_group_id, to_row_id.clone())
.await;
} }
if row_changeset.has_changed() { if row_changeset.has_changed() {

View File

@ -1,6 +1,7 @@
use crate::entities::GroupRowsChangesetPB; use crate::entities::GroupRowsChangesetPB;
use flowy_grid_data_model::revision::{FieldRevision, RowChangeset, RowRevision}; use crate::services::group::controller::MoveGroupRowContext;
use flowy_grid_data_model::revision::RowRevision;
pub trait GroupAction: Send + Sync { pub trait GroupAction: Send + Sync {
type CellDataType; type CellDataType;
@ -12,12 +13,5 @@ pub trait GroupAction: Send + Sync {
cell_data: &Self::CellDataType, cell_data: &Self::CellDataType,
) -> Vec<GroupRowsChangesetPB>; ) -> Vec<GroupRowsChangesetPB>;
fn move_row_if_match( fn move_row(&mut self, cell_data: &Self::CellDataType, context: MoveGroupRowContext) -> Vec<GroupRowsChangesetPB>;
&mut self,
field_rev: &FieldRevision,
row_rev: &RowRevision,
row_changeset: &mut RowChangeset,
cell_data: &Self::CellDataType,
to_row_id: &str,
) -> Vec<GroupRowsChangesetPB>;
} }

View File

@ -101,9 +101,9 @@ where
Ok(()) Ok(())
} }
pub(crate) fn with_mut_groups(&mut self, mut mut_groups_fn: impl FnMut(&mut Group)) { pub(crate) fn with_mut_groups(&mut self, mut each: impl FnMut(&mut Group)) {
self.groups_map.iter_mut().for_each(|(_, group)| { self.groups_map.iter_mut().for_each(|(_, group)| {
mut_groups_fn(group); each(group);
}) })
} }
@ -111,22 +111,16 @@ where
self.groups_map.get_mut(group_id) self.groups_map.get_mut(group_id)
} }
pub(crate) fn move_group(&mut self, from_group_id: &str, to_group_id: &str) -> FlowyResult<()> { pub(crate) fn move_group(&mut self, from_id: &str, to_id: &str) -> FlowyResult<()> {
let from_group_index = self.groups_map.get_index_of(from_group_id); let from_index = self.groups_map.get_index_of(from_id);
let to_group_index = self.groups_map.get_index_of(to_group_id); let to_index = self.groups_map.get_index_of(to_id);
match (from_group_index, to_group_index) { match (from_index, to_index) {
(Some(from_index), Some(to_index)) => { (Some(from_index), Some(to_index)) => {
self.groups_map.swap_indices(from_index, to_index); self.groups_map.swap_indices(from_index, to_index);
self.mut_configuration(|configuration| { self.mut_configuration(|configuration| {
let from_index = configuration let from_index = configuration.groups.iter().position(|group| group.group_id == from_id);
.groups let to_index = configuration.groups.iter().position(|group| group.group_id == to_id);
.iter()
.position(|group| group.group_id == from_group_id);
let to_index = configuration
.groups
.iter()
.position(|group| group.group_id == to_group_id);
if let (Some(from), Some(to)) = (from_index, to_index) { if let (Some(from), Some(to)) = (from_index, to_index) {
configuration.groups.swap(from, to); configuration.groups.swap(from, to);
} }
@ -150,7 +144,7 @@ where
let configuration = (&*self.configuration).clone(); let configuration = (&*self.configuration).clone();
let writer = self.writer.clone(); let writer = self.writer.clone();
let field_id = self.field_rev.id.clone(); let field_id = self.field_rev.id.clone();
let field_type = self.field_rev.ty.clone(); let field_type = self.field_rev.ty;
tokio::spawn(async move { tokio::spawn(async move {
match writer match writer
.save_group_configuration(&field_id, field_type, configuration) .save_group_configuration(&field_id, field_type, configuration)
@ -196,7 +190,6 @@ where
} }
fn merge_groups(old_group_revs: &[GroupRecordRevision], groups: Vec<Group>) -> (Vec<GroupRecordRevision>, Vec<Group>) { fn merge_groups(old_group_revs: &[GroupRecordRevision], groups: Vec<Group>) -> (Vec<GroupRecordRevision>, Vec<Group>) {
tracing::trace!("Merge group: old: {}, new: {}", old_group_revs.len(), groups.len());
if old_group_revs.is_empty() { if old_group_revs.is_empty() {
let new_groups = groups let new_groups = groups
.iter() .iter()

View File

@ -31,6 +31,14 @@ pub trait GroupGenerator {
) -> Vec<Group>; ) -> Vec<Group>;
} }
pub struct MoveGroupRowContext<'a> {
pub row_rev: &'a RowRevision,
pub row_changeset: &'a mut RowChangeset,
pub field_rev: &'a FieldRevision,
pub to_group_id: &'a str,
pub to_row_id: Option<String>,
}
// Defines the shared actions each group controller can perform. // Defines the shared actions each group controller can perform.
pub trait GroupControllerSharedOperation: Send + Sync { pub trait GroupControllerSharedOperation: Send + Sync {
// The field that is used for grouping the rows // The field that is used for grouping the rows
@ -51,13 +59,7 @@ pub trait GroupControllerSharedOperation: Send + Sync {
field_rev: &FieldRevision, field_rev: &FieldRevision,
) -> FlowyResult<Vec<GroupRowsChangesetPB>>; ) -> FlowyResult<Vec<GroupRowsChangesetPB>>;
fn did_move_row( fn move_group_row(&mut self, context: MoveGroupRowContext) -> FlowyResult<Vec<GroupRowsChangesetPB>>;
&mut self,
row_rev: &RowRevision,
row_changeset: &mut RowChangeset,
field_rev: &FieldRevision,
to_row_id: &str,
) -> FlowyResult<Vec<GroupRowsChangesetPB>>;
} }
/// C: represents the group configuration that impl [GroupConfigurationSerde] /// C: represents the group configuration that impl [GroupConfigurationSerde]
@ -195,18 +197,11 @@ where
} }
} }
fn did_move_row( fn move_group_row(&mut self, context: MoveGroupRowContext) -> FlowyResult<Vec<GroupRowsChangesetPB>> {
&mut self, if let Some(cell_rev) = context.row_rev.cells.get(&self.field_id) {
row_rev: &RowRevision, let cell_bytes = decode_any_cell_data(cell_rev.data.clone(), context.field_rev);
row_changeset: &mut RowChangeset,
field_rev: &FieldRevision,
to_row_id: &str,
) -> FlowyResult<Vec<GroupRowsChangesetPB>> {
if let Some(cell_rev) = row_rev.cells.get(&self.field_id) {
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>()?;
tracing::trace!("Move row:{} to row:{}", row_rev.id, to_row_id); Ok(self.move_row(&cell_data, context))
Ok(self.move_row_if_match(field_rev, row_rev, row_changeset, &cell_data, to_row_id))
} else { } else {
Ok(vec![]) Ok(vec![])
} }

View File

@ -2,10 +2,12 @@ use crate::entities::GroupRowsChangesetPB;
use crate::services::field::{CheckboxCellData, CheckboxCellDataParser, CheckboxTypeOptionPB, CHECK, UNCHECK}; use crate::services::field::{CheckboxCellData, CheckboxCellDataParser, CheckboxTypeOptionPB, CHECK, UNCHECK};
use crate::services::group::action::GroupAction; use crate::services::group::action::GroupAction;
use crate::services::group::configuration::GenericGroupConfiguration; use crate::services::group::configuration::GenericGroupConfiguration;
use crate::services::group::controller::{GenericGroupController, GroupController, GroupGenerator}; use crate::services::group::controller::{
GenericGroupController, GroupController, GroupGenerator, MoveGroupRowContext,
};
use crate::services::group::entities::Group; use crate::services::group::entities::Group;
use flowy_grid_data_model::revision::{CheckboxGroupConfigurationRevision, FieldRevision, RowChangeset, RowRevision}; use flowy_grid_data_model::revision::{CheckboxGroupConfigurationRevision, FieldRevision, RowRevision};
pub type CheckboxGroupController = GenericGroupController< pub type CheckboxGroupController = GenericGroupController<
CheckboxGroupConfigurationRevision, CheckboxGroupConfigurationRevision,
@ -38,13 +40,10 @@ impl GroupAction for CheckboxGroupController {
todo!() todo!()
} }
fn move_row_if_match( fn move_row(
&mut self, &mut self,
_field_rev: &FieldRevision,
_row_rev: &RowRevision,
_row_changeset: &mut RowChangeset,
_cell_data: &Self::CellDataType, _cell_data: &Self::CellDataType,
_to_row_id: &str, _context: MoveGroupRowContext,
) -> Vec<GroupRowsChangesetPB> { ) -> Vec<GroupRowsChangesetPB> {
todo!() todo!()
} }

View File

@ -3,12 +3,12 @@ use crate::services::cell::insert_select_option_cell;
use crate::services::field::{MultiSelectTypeOptionPB, SelectOptionCellDataPB, SelectOptionCellDataParser}; use crate::services::field::{MultiSelectTypeOptionPB, SelectOptionCellDataPB, SelectOptionCellDataParser};
use crate::services::group::action::GroupAction; use crate::services::group::action::GroupAction;
use crate::services::group::controller::{GenericGroupController, GroupController, GroupGenerator}; use crate::services::group::controller::{
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::entities::Group;
use flowy_grid_data_model::revision::{ use flowy_grid_data_model::revision::{FieldRevision, RowRevision, SelectOptionGroupConfigurationRevision};
FieldRevision, RowChangeset, RowRevision, SelectOptionGroupConfigurationRevision,
};
// MultiSelect // MultiSelect
pub type MultiSelectGroupController = GenericGroupController< pub type MultiSelectGroupController = GenericGroupController<
@ -45,25 +45,14 @@ impl GroupAction for MultiSelectGroupController {
changesets changesets
} }
fn move_row_if_match( fn move_row(
&mut self, &mut self,
field_rev: &FieldRevision,
row_rev: &RowRevision,
row_changeset: &mut RowChangeset,
cell_data: &Self::CellDataType, cell_data: &Self::CellDataType,
to_row_id: &str, mut context: MoveGroupRowContext,
) -> Vec<GroupRowsChangesetPB> { ) -> Vec<GroupRowsChangesetPB> {
let mut group_changeset = vec![]; let mut group_changeset = vec![];
self.configuration.with_mut_groups(|group| { self.configuration.with_mut_groups(|group| {
move_row( move_select_option_row(group, &mut group_changeset, cell_data, &mut context);
group,
&mut group_changeset,
field_rev,
row_rev,
row_changeset,
cell_data,
to_row_id,
);
}); });
group_changeset group_changeset
} }

View File

@ -3,13 +3,13 @@ use crate::services::cell::insert_select_option_cell;
use crate::services::field::{SelectOptionCellDataPB, SelectOptionCellDataParser, SingleSelectTypeOptionPB}; use crate::services::field::{SelectOptionCellDataPB, SelectOptionCellDataParser, SingleSelectTypeOptionPB};
use crate::services::group::action::GroupAction; use crate::services::group::action::GroupAction;
use crate::services::group::controller::{GenericGroupController, GroupController, GroupGenerator}; use crate::services::group::controller::{
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::entities::Group;
use flowy_grid_data_model::revision::{ use flowy_grid_data_model::revision::{FieldRevision, RowRevision, SelectOptionGroupConfigurationRevision};
FieldRevision, RowChangeset, RowRevision, SelectOptionGroupConfigurationRevision,
};
// SingleSelect // SingleSelect
pub type SingleSelectGroupController = GenericGroupController< pub type SingleSelectGroupController = GenericGroupController<
@ -45,25 +45,14 @@ impl GroupAction for SingleSelectGroupController {
changesets changesets
} }
fn move_row_if_match( fn move_row(
&mut self, &mut self,
field_rev: &FieldRevision,
row_rev: &RowRevision,
row_changeset: &mut RowChangeset,
cell_data: &Self::CellDataType, cell_data: &Self::CellDataType,
to_row_id: &str, mut context: MoveGroupRowContext,
) -> Vec<GroupRowsChangesetPB> { ) -> Vec<GroupRowsChangesetPB> {
let mut group_changeset = vec![]; let mut group_changeset = vec![];
self.configuration.with_mut_groups(|group| { self.configuration.with_mut_groups(|group| {
move_row( move_select_option_row(group, &mut group_changeset, cell_data, &mut context);
group,
&mut group_changeset,
field_rev,
row_rev,
row_changeset,
cell_data,
to_row_id,
);
}); });
group_changeset group_changeset
} }

View File

@ -4,9 +4,8 @@ use crate::services::field::SelectOptionCellDataPB;
use crate::services::group::configuration::GenericGroupConfiguration; use crate::services::group::configuration::GenericGroupConfiguration;
use crate::services::group::Group; use crate::services::group::Group;
use flowy_grid_data_model::revision::{ use crate::services::group::controller::MoveGroupRowContext;
FieldRevision, RowChangeset, RowRevision, SelectOptionGroupConfigurationRevision, use flowy_grid_data_model::revision::{RowRevision, SelectOptionGroupConfigurationRevision};
};
pub type SelectOptionGroupConfiguration = GenericGroupConfiguration<SelectOptionGroupConfigurationRevision>; pub type SelectOptionGroupConfiguration = GenericGroupConfiguration<SelectOptionGroupConfigurationRevision>;
@ -47,45 +46,60 @@ pub fn remove_row(
}); });
} }
pub fn move_row( pub fn move_select_option_row(
group: &mut Group, group: &mut Group,
group_changeset: &mut Vec<GroupRowsChangesetPB>, group_changeset: &mut Vec<GroupRowsChangesetPB>,
field_rev: &FieldRevision, _cell_data: &SelectOptionCellDataPB,
row_rev: &RowRevision, context: &mut MoveGroupRowContext,
row_changeset: &mut RowChangeset,
cell_data: &SelectOptionCellDataPB,
to_row_id: &str,
) { ) {
cell_data.select_options.iter().for_each(|option| { let MoveGroupRowContext {
// Remove the row in which group contains the row row_rev,
let is_group_contains = group.contains_row(&row_rev.id); row_changeset,
let to_index = group.index_of_row(to_row_id); field_rev,
to_group_id,
to_row_id,
} = context;
if option.id == group.id && is_group_contains { let from_index = group.index_of_row(&row_rev.id);
group_changeset.push(GroupRowsChangesetPB::delete(group.id.clone(), vec![row_rev.id.clone()])); let to_index = match to_row_id {
group.remove_row(&row_rev.id); None => None,
} Some(to_row_id) => group.index_of_row(to_row_id),
};
// Find the inserted group // Remove the row in which group contains it
if let Some(to_index) = to_index { if from_index.is_some() {
let row_pb = RowPB::from(row_rev); group_changeset.push(GroupRowsChangesetPB::delete(group.id.clone(), vec![row_rev.id.clone()]));
let inserted_row = InsertedRowPB { tracing::debug!("Group:{} remove row:{}", group.id, row_rev.id);
row: row_pb.clone(), group.remove_row(&row_rev.id);
index: Some(to_index as i32), }
};
group_changeset.push(GroupRowsChangesetPB::insert(group.id.clone(), vec![inserted_row])); if group.id == *to_group_id {
if group.number_of_row() == to_index { let row_pb = RowPB::from(*row_rev);
let mut inserted_row = InsertedRowPB::new(row_pb.clone());
match to_index {
None => {
group_changeset.push(GroupRowsChangesetPB::insert(group.id.clone(), vec![inserted_row]));
tracing::debug!("Group:{} append row:{}", group.id, row_rev.id);
group.add_row(row_pb); group.add_row(row_pb);
} else { }
group.insert_row(to_index, row_pb); Some(to_index) => {
if to_index < group.number_of_row() {
tracing::debug!("Group:{} insert row:{} at {} ", group.id, row_rev.id, to_index);
inserted_row.index = Some(to_index as i32);
group.insert_row(to_index, row_pb);
} else {
tracing::debug!("Group:{} append row:{}", group.id, row_rev.id);
group.add_row(row_pb);
}
group_changeset.push(GroupRowsChangesetPB::insert(group.id.clone(), vec![inserted_row]));
} }
} }
// If the inserted row comes from other group, it needs to update the corresponding cell content. // Update the corresponding row's cell content.
if to_index.is_some() && option.id != group.id { if from_index.is_none() {
// Update the corresponding row's cell content. tracing::debug!("Mark row:{} belong to group:{}", row_rev.id, group.id);
let cell_rev = insert_select_option_cell(group.id.clone(), field_rev); let cell_rev = insert_select_option_cell(group.id.clone(), field_rev);
row_changeset.cell_by_field_id.insert(field_rev.id.clone(), cell_rev); row_changeset.cell_by_field_id.insert(field_rev.id.clone(), cell_rev);
} }
}); }
} }

View File

@ -1,5 +1,6 @@
use crate::entities::{FieldType, GroupRowsChangesetPB};
use crate::services::group::configuration::GroupConfigurationReader; use crate::services::group::configuration::GroupConfigurationReader;
use crate::services::group::controller::GroupController; use crate::services::group::controller::{GroupController, MoveGroupRowContext};
use crate::services::group::{ use crate::services::group::{
CheckboxGroupConfiguration, CheckboxGroupController, Group, GroupConfigurationWriter, MultiSelectGroupController, CheckboxGroupConfiguration, CheckboxGroupController, Group, GroupConfigurationWriter, MultiSelectGroupController,
SelectOptionGroupConfiguration, SingleSelectGroupController, SelectOptionGroupConfiguration, SingleSelectGroupController,
@ -10,16 +11,13 @@ use flowy_grid_data_model::revision::{
NumberGroupConfigurationRevision, RowChangeset, RowRevision, SelectOptionGroupConfigurationRevision, NumberGroupConfigurationRevision, RowChangeset, RowRevision, SelectOptionGroupConfigurationRevision,
TextGroupConfigurationRevision, UrlGroupConfigurationRevision, TextGroupConfigurationRevision, UrlGroupConfigurationRevision,
}; };
use crate::entities::{FieldType, GroupRowsChangesetPB};
use std::future::Future; use std::future::Future;
use std::sync::Arc; use std::sync::Arc;
use tokio::sync::RwLock;
pub(crate) struct GroupService { pub(crate) struct GroupService {
configuration_reader: Arc<dyn GroupConfigurationReader>, configuration_reader: Arc<dyn GroupConfigurationReader>,
configuration_writer: Arc<dyn GroupConfigurationWriter>, configuration_writer: Arc<dyn GroupConfigurationWriter>,
group_controller: Option<Arc<RwLock<dyn GroupController>>>, group_controller: Option<Box<dyn GroupController>>,
} }
impl GroupService { impl GroupService {
@ -36,19 +34,16 @@ impl GroupService {
} }
pub(crate) async fn groups(&self) -> Vec<Group> { pub(crate) async fn groups(&self) -> Vec<Group> {
if let Some(group_controller) = self.group_controller.as_ref() { self.group_controller
group_controller.read().await.groups() .as_ref()
} else { .and_then(|group_controller| Some(group_controller.groups()))
vec![] .unwrap_or(vec![])
}
} }
pub(crate) async fn get_group(&self, group_id: &str) -> Option<(usize, Group)> { pub(crate) async fn get_group(&self, group_id: &str) -> Option<(usize, Group)> {
if let Some(group_controller) = self.group_controller.as_ref() { self.group_controller
group_controller.read().await.get_group(group_id) .as_ref()
} else { .and_then(|group_controller| group_controller.get_group(group_id))
None
}
} }
pub(crate) async fn load_groups( pub(crate) async fn load_groups(
@ -58,51 +53,37 @@ impl GroupService {
) -> Option<Vec<Group>> { ) -> Option<Vec<Group>> {
let field_rev = find_group_field(field_revs)?; let field_rev = find_group_field(field_revs)?;
let field_type: FieldType = field_rev.ty.into(); let field_type: FieldType = field_rev.ty.into();
match self.make_group_controller(&field_type, &field_rev).await {
Ok(group_controller) => { let mut group_controller = self.make_group_controller(&field_type, &field_rev).await.ok()??;
self.group_controller = group_controller; let groups = match group_controller.fill_groups(&row_revs, &field_rev) {
let mut groups = vec![]; Ok(groups) => groups,
if let Some(group_action_handler) = self.group_controller.as_ref() { Err(e) => {
let mut write_guard = group_action_handler.write().await; tracing::error!("Fill groups failed:{:?}", e);
groups = match write_guard.fill_groups(&row_revs, &field_rev) { vec![]
Ok(groups) => groups,
Err(e) => {
tracing::error!("Fill groups failed:{:?}", e);
vec![]
}
};
drop(write_guard);
}
Some(groups)
} }
Err(err) => { };
tracing::error!("Load group failed: {}", err); self.group_controller = Some(group_controller);
Some(vec![]) Some(groups)
}
}
} }
pub(crate) async fn will_create_row<F, O>(&self, row_rev: &mut RowRevision, group_id: &str, get_field_fn: F) pub(crate) async fn will_create_row<F, O>(&mut self, row_rev: &mut RowRevision, group_id: &str, get_field_fn: F)
where where
F: FnOnce(String) -> O, F: FnOnce(String) -> O,
O: Future<Output = Option<Arc<FieldRevision>>> + Send + Sync + 'static, O: Future<Output = Option<Arc<FieldRevision>>> + Send + Sync + 'static,
{ {
if let Some(group_controller) = self.group_controller.as_ref() { if let Some(group_controller) = self.group_controller.as_mut() {
let field_id = group_controller.read().await.field_id().to_owned(); let field_id = group_controller.field_id().to_owned();
match get_field_fn(field_id).await { match get_field_fn(field_id).await {
None => {} None => {}
Some(field_rev) => { Some(field_rev) => {
group_controller group_controller.will_create_row(row_rev, &field_rev, group_id);
.write()
.await
.will_create_row(row_rev, &field_rev, group_id);
} }
} }
} }
} }
pub(crate) async fn did_delete_row<F, O>( pub(crate) async fn did_delete_row<F, O>(
&self, &mut self,
row_rev: &RowRevision, row_rev: &RowRevision,
get_field_fn: F, get_field_fn: F,
) -> Option<Vec<GroupRowsChangesetPB>> ) -> Option<Vec<GroupRowsChangesetPB>>
@ -110,11 +91,11 @@ impl GroupService {
F: FnOnce(String) -> O, F: FnOnce(String) -> O,
O: Future<Output = Option<Arc<FieldRevision>>> + Send + Sync + 'static, O: Future<Output = Option<Arc<FieldRevision>>> + Send + Sync + 'static,
{ {
let group_controller = self.group_controller.as_ref()?; let group_controller = self.group_controller.as_mut()?;
let field_id = group_controller.read().await.field_id().to_owned(); let field_id = group_controller.field_id().to_owned();
let field_rev = get_field_fn(field_id).await?; let field_rev = get_field_fn(field_id).await?;
match group_controller.write().await.did_delete_row(row_rev, &field_rev) { match group_controller.did_delete_row(row_rev, &field_rev) {
Ok(changesets) => Some(changesets), Ok(changesets) => Some(changesets),
Err(e) => { Err(e) => {
tracing::error!("Delete group data failed, {:?}", e); tracing::error!("Delete group data failed, {:?}", e);
@ -123,26 +104,30 @@ impl GroupService {
} }
} }
pub(crate) async fn did_move_row<F, O>( pub(crate) async fn move_group_row<F, O>(
&self, &mut self,
row_rev: &RowRevision, row_rev: &RowRevision,
row_changeset: &mut RowChangeset, row_changeset: &mut RowChangeset,
upper_row_id: &str, to_group_id: &str,
to_row_id: Option<String>,
get_field_fn: F, get_field_fn: F,
) -> Option<Vec<GroupRowsChangesetPB>> ) -> Option<Vec<GroupRowsChangesetPB>>
where where
F: FnOnce(String) -> O, F: FnOnce(String) -> O,
O: Future<Output = Option<Arc<FieldRevision>>> + Send + Sync + 'static, O: Future<Output = Option<Arc<FieldRevision>>> + Send + Sync + 'static,
{ {
let group_controller = self.group_controller.as_ref()?; let group_controller = self.group_controller.as_mut()?;
let field_id = group_controller.read().await.field_id().to_owned(); let field_id = group_controller.field_id().to_owned();
let field_rev = get_field_fn(field_id).await?; 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 match group_controller.move_group_row(move_row_context) {
.write()
.await
.did_move_row(row_rev, row_changeset, &field_rev, upper_row_id)
{
Ok(changesets) => Some(changesets), Ok(changesets) => Some(changesets),
Err(e) => { Err(e) => {
tracing::error!("Move group data failed, {:?}", e); tracing::error!("Move group data failed, {:?}", e);
@ -153,7 +138,7 @@ impl GroupService {
#[tracing::instrument(level = "trace", skip_all)] #[tracing::instrument(level = "trace", skip_all)]
pub(crate) async fn did_update_row<F, O>( pub(crate) async fn did_update_row<F, O>(
&self, &mut self,
row_rev: &RowRevision, row_rev: &RowRevision,
get_field_fn: F, get_field_fn: F,
) -> Option<Vec<GroupRowsChangesetPB>> ) -> Option<Vec<GroupRowsChangesetPB>>
@ -161,11 +146,11 @@ impl GroupService {
F: FnOnce(String) -> O, F: FnOnce(String) -> O,
O: Future<Output = Option<Arc<FieldRevision>>> + Send + Sync + 'static, O: Future<Output = Option<Arc<FieldRevision>>> + Send + Sync + 'static,
{ {
let group_controller = self.group_controller.as_ref()?; let group_controller = self.group_controller.as_mut()?;
let field_id = group_controller.read().await.field_id().to_owned(); let field_id = group_controller.field_id().to_owned();
let field_rev = get_field_fn(field_id).await?; let field_rev = get_field_fn(field_id).await?;
match group_controller.write().await.did_update_row(row_rev, &field_rev) { match group_controller.did_update_row(row_rev, &field_rev) {
Ok(changeset) => Some(changeset), Ok(changeset) => Some(changeset),
Err(e) => { Err(e) => {
tracing::error!("Update group data failed, {:?}", e); tracing::error!("Update group data failed, {:?}", e);
@ -175,11 +160,11 @@ impl GroupService {
} }
#[tracing::instrument(level = "trace", skip_all)] #[tracing::instrument(level = "trace", skip_all)]
pub(crate) async fn move_group(&self, from_group_id: &str, to_group_id: &str) -> FlowyResult<()> { pub(crate) async fn move_group(&mut self, from_group_id: &str, to_group_id: &str) -> FlowyResult<()> {
match self.group_controller.as_ref() { match self.group_controller.as_mut() {
None => Ok(()), None => Ok(()),
Some(group_controller) => { Some(group_controller) => {
let _ = group_controller.write().await.move_group(from_group_id, to_group_id)?; let _ = group_controller.move_group(from_group_id, to_group_id)?;
Ok(()) Ok(())
} }
} }
@ -190,8 +175,8 @@ impl GroupService {
&self, &self,
field_type: &FieldType, field_type: &FieldType,
field_rev: &Arc<FieldRevision>, field_rev: &Arc<FieldRevision>,
) -> FlowyResult<Option<Arc<RwLock<dyn GroupController>>>> { ) -> FlowyResult<Option<Box<dyn GroupController>>> {
let mut group_controller: Option<Arc<RwLock<dyn GroupController>>> = None; let mut group_controller: Option<Box<dyn GroupController>> = None;
match field_type { match field_type {
FieldType::RichText => { FieldType::RichText => {
// let generator = GroupGenerator::<TextGroupConfigurationPB>::from_configuration(configuration); // let generator = GroupGenerator::<TextGroupConfigurationPB>::from_configuration(configuration);
@ -210,7 +195,7 @@ impl GroupService {
) )
.await?; .await?;
let controller = SingleSelectGroupController::new(field_rev, configuration).await?; let controller = SingleSelectGroupController::new(field_rev, configuration).await?;
group_controller = Some(Arc::new(RwLock::new(controller))); group_controller = Some(Box::new(controller));
} }
FieldType::MultiSelect => { FieldType::MultiSelect => {
let configuration = SelectOptionGroupConfiguration::new( let configuration = SelectOptionGroupConfiguration::new(
@ -220,7 +205,7 @@ impl GroupService {
) )
.await?; .await?;
let controller = MultiSelectGroupController::new(field_rev, configuration).await?; let controller = MultiSelectGroupController::new(field_rev, configuration).await?;
group_controller = Some(Arc::new(RwLock::new(controller))); group_controller = Some(Box::new(controller));
} }
FieldType::Checkbox => { FieldType::Checkbox => {
let configuration = CheckboxGroupConfiguration::new( let configuration = CheckboxGroupConfiguration::new(
@ -230,7 +215,7 @@ impl GroupService {
) )
.await?; .await?;
let controller = CheckboxGroupController::new(field_rev, configuration).await?; let controller = CheckboxGroupController::new(field_rev, configuration).await?;
group_controller = Some(Arc::new(RwLock::new(controller))) group_controller = Some(Box::new(controller));
} }
FieldType::URL => { FieldType::URL => {
// let generator = GroupGenerator::<UrlGroupConfigurationPB>::from_configuration(configuration); // let generator = GroupGenerator::<UrlGroupConfigurationPB>::from_configuration(configuration);

View File

@ -1,5 +1,7 @@
use crate::grid::grid_editor::GridEditorTest; use crate::grid::grid_editor::GridEditorTest;
use flowy_grid::entities::{CreateRowParams, FieldType, GridLayout, GroupPB, MoveGroupParams, MoveRowParams, RowPB}; use flowy_grid::entities::{
CreateRowParams, FieldType, GridLayout, GroupPB, MoveGroupParams, MoveGroupRowParams, RowPB,
};
use flowy_grid::services::cell::insert_select_option_cell; use flowy_grid::services::cell::insert_select_option_cell;
use flowy_grid_data_model::revision::RowChangeset; use flowy_grid_data_model::revision::RowChangeset;
@ -75,14 +77,16 @@ impl GridGroupTest {
} => { } => {
let groups: Vec<GroupPB> = self.editor.load_groups().await.unwrap().items; let groups: Vec<GroupPB> = self.editor.load_groups().await.unwrap().items;
let from_row = groups.get(from_group_index).unwrap().rows.get(from_row_index).unwrap(); let from_row = groups.get(from_group_index).unwrap().rows.get(from_row_index).unwrap();
let to_row = groups.get(to_group_index).unwrap().rows.get(to_row_index).unwrap(); let to_group = groups.get(to_group_index).unwrap();
let params = MoveRowParams { let to_row = to_group.rows.get(to_row_index).unwrap();
let params = MoveGroupRowParams {
view_id: self.inner.grid_id.clone(), view_id: self.inner.grid_id.clone(),
from_row_id: from_row.id.clone(), from_row_id: from_row.id.clone(),
to_row_id: to_row.id.clone(), to_group_id: to_group.group_id.clone(),
to_row_id: Some(to_row.id.clone()),
}; };
self.editor.move_row(params).await.unwrap(); self.editor.move_group_row(params).await.unwrap();
} }
GroupScript::AssertRow { GroupScript::AssertRow {
group_index, group_index,

View File

@ -2,7 +2,7 @@ use crate::grid::group_test::script::GridGroupTest;
use crate::grid::group_test::script::GroupScript::*; use crate::grid::group_test::script::GroupScript::*;
#[tokio::test] #[tokio::test]
async fn board_init_test() { async fn group_init_test() {
let mut test = GridGroupTest::new().await; let mut test = GridGroupTest::new().await;
let scripts = vec![ let scripts = vec![
AssertGroupCount(3), AssertGroupCount(3),
@ -23,7 +23,7 @@ async fn board_init_test() {
} }
#[tokio::test] #[tokio::test]
async fn board_move_row_test() { async fn group_move_row_test() {
let mut test = GridGroupTest::new().await; let mut test = GridGroupTest::new().await;
let group = test.group_at_index(0).await; let group = test.group_at_index(0).await;
let scripts = vec![ let scripts = vec![
@ -48,7 +48,7 @@ async fn board_move_row_test() {
} }
#[tokio::test] #[tokio::test]
async fn board_move_row_to_other_group_test() { async fn group_move_row_to_other_group_test() {
let mut test = GridGroupTest::new().await; let mut test = GridGroupTest::new().await;
let group = test.group_at_index(0).await; let group = test.group_at_index(0).await;
let scripts = vec![ let scripts = vec![
@ -76,7 +76,7 @@ async fn board_move_row_to_other_group_test() {
} }
#[tokio::test] #[tokio::test]
async fn board_move_row_to_other_group_and_reorder_test() { async fn group_move_two_row_to_other_group_test() {
let mut test = GridGroupTest::new().await; let mut test = GridGroupTest::new().await;
let group = test.group_at_index(0).await; let group = test.group_at_index(0).await;
let scripts = vec![ let scripts = vec![
@ -86,15 +86,41 @@ async fn board_move_row_to_other_group_and_reorder_test() {
to_group_index: 1, to_group_index: 1,
to_row_index: 1, to_row_index: 1,
}, },
MoveRow { AssertGroupRowCount {
from_group_index: 1, group_index: 0,
from_row_index: 1, row_count: 1,
to_group_index: 1, },
to_row_index: 2, AssertGroupRowCount {
group_index: 1,
row_count: 3,
}, },
AssertRow { AssertRow {
group_index: 1, group_index: 1,
row_index: 2, row_index: 1,
row: group.rows.get(0).unwrap().clone(),
},
];
test.run_scripts(scripts).await;
let group = test.group_at_index(0).await;
let scripts = vec![
MoveRow {
from_group_index: 0,
from_row_index: 0,
to_group_index: 1,
to_row_index: 1,
},
AssertGroupRowCount {
group_index: 0,
row_count: 0,
},
AssertGroupRowCount {
group_index: 1,
row_count: 4,
},
AssertRow {
group_index: 1,
row_index: 1,
row: group.rows.get(0).unwrap().clone(), row: group.rows.get(0).unwrap().clone(),
}, },
]; ];
@ -102,7 +128,74 @@ async fn board_move_row_to_other_group_and_reorder_test() {
} }
#[tokio::test] #[tokio::test]
async fn board_create_row_test() { async fn group_move_row_to_other_group_and_reorder_from_up_to_down_test() {
let mut test = GridGroupTest::new().await;
let group_0 = test.group_at_index(0).await;
let group_1 = test.group_at_index(1).await;
let scripts = vec![
MoveRow {
from_group_index: 0,
from_row_index: 0,
to_group_index: 1,
to_row_index: 1,
},
AssertRow {
group_index: 1,
row_index: 1,
row: group_0.rows.get(0).unwrap().clone(),
},
];
test.run_scripts(scripts).await;
let scripts = vec![
MoveRow {
from_group_index: 1,
from_row_index: 0,
to_group_index: 1,
to_row_index: 2,
},
AssertRow {
group_index: 1,
row_index: 2,
row: group_1.rows.get(0).unwrap().clone(),
},
];
test.run_scripts(scripts).await;
}
#[tokio::test]
async fn group_move_row_to_other_group_and_reorder_from_bottom_to_up_test() {
let mut test = GridGroupTest::new().await;
let scripts = vec![MoveRow {
from_group_index: 0,
from_row_index: 0,
to_group_index: 1,
to_row_index: 1,
}];
test.run_scripts(scripts).await;
let group = test.group_at_index(1).await;
let scripts = vec![
AssertGroupRowCount {
group_index: 1,
row_count: 3,
},
MoveRow {
from_group_index: 1,
from_row_index: 2,
to_group_index: 1,
to_row_index: 0,
},
AssertRow {
group_index: 1,
row_index: 0,
row: group.rows.get(2).unwrap().clone(),
},
];
test.run_scripts(scripts).await;
}
#[tokio::test]
async fn group_create_row_test() {
let mut test = GridGroupTest::new().await; let mut test = GridGroupTest::new().await;
let scripts = vec![ let scripts = vec![
CreateRow { group_index: 0 }, CreateRow { group_index: 0 },
@ -121,7 +214,7 @@ async fn board_create_row_test() {
} }
#[tokio::test] #[tokio::test]
async fn board_delete_row_test() { async fn group_delete_row_test() {
let mut test = GridGroupTest::new().await; let mut test = GridGroupTest::new().await;
let scripts = vec![ let scripts = vec![
DeleteRow { DeleteRow {
@ -137,7 +230,7 @@ async fn board_delete_row_test() {
} }
#[tokio::test] #[tokio::test]
async fn board_delete_all_row_test() { async fn group_delete_all_row_test() {
let mut test = GridGroupTest::new().await; let mut test = GridGroupTest::new().await;
let scripts = vec![ let scripts = vec![
DeleteRow { DeleteRow {
@ -157,7 +250,7 @@ async fn board_delete_all_row_test() {
} }
#[tokio::test] #[tokio::test]
async fn board_update_row_test() { async fn group_update_row_test() {
let mut test = GridGroupTest::new().await; let mut test = GridGroupTest::new().await;
let scripts = vec![ let scripts = vec![
// Update the row at 0 in group0 by setting the row's group field data // Update the row at 0 in group0 by setting the row's group field data
@ -179,7 +272,7 @@ async fn board_update_row_test() {
} }
#[tokio::test] #[tokio::test]
async fn board_reorder_group_test() { async fn group_reorder_group_test() {
let mut test = GridGroupTest::new().await; let mut test = GridGroupTest::new().await;
let scripts = vec![ let scripts = vec![
// Update the row at 0 in group0 by setting the row's group field data // Update the row at 0 in group0 by setting the row's group field data
@ -201,7 +294,7 @@ async fn board_reorder_group_test() {
} }
#[tokio::test] #[tokio::test]
async fn board_move_group_test() { async fn group_move_group_test() {
let mut test = GridGroupTest::new().await; let mut test = GridGroupTest::new().await;
let group_0 = test.group_at_index(0).await; let group_0 = test.group_at_index(0).await;
let group_1 = test.group_at_index(1).await; let group_1 = test.group_at_index(1).await;

View File

@ -76,7 +76,8 @@ where
Some(objects_by_field_id) Some(objects_by_field_id)
} }
pub fn insert_object(&mut self, field_id: &str, field_type: &FieldTypeRevision, object: T) { /// add object to the end of the list
pub fn add_object(&mut self, field_id: &str, field_type: &FieldTypeRevision, object: T) {
let object_rev_map = self let object_rev_map = self
.inner .inner
.entry(field_id.to_string()) .entry(field_id.to_string())
@ -88,7 +89,7 @@ where
.push(Arc::new(object)) .push(Arc::new(object))
} }
pub fn remove_all(&mut self) { pub fn clear(&mut self) {
self.inner.clear() self.inner.clear()
} }
} }

View File

@ -155,3 +155,27 @@ impl std::default::Default for DateCondition {
DateCondition::Relative DateCondition::Relative
} }
} }
#[cfg(test)]
mod tests {
use crate::revision::{GroupConfigurationRevision, SelectOptionGroupConfigurationRevision};
#[test]
fn group_configuration_serde_test() {
let content = SelectOptionGroupConfigurationRevision { hide_empty: false };
let rev = GroupConfigurationRevision::new("1".to_owned(), 2, content).unwrap();
let json = serde_json::to_string(&rev).unwrap();
let rev: GroupConfigurationRevision = serde_json::from_str(&json).unwrap();
let _content: SelectOptionGroupConfigurationRevision = serde_json::from_str(&rev.content).unwrap();
}
#[test]
fn group_configuration_serde_test2() {
let content = SelectOptionGroupConfigurationRevision { hide_empty: false };
let content_json = serde_json::to_string(&content).unwrap();
let rev = GroupConfigurationRevision::new("1".to_owned(), 2, content).unwrap();
assert_eq!(rev.content, content_json);
}
}

View File

@ -60,7 +60,9 @@ impl GridViewRevisionPad {
group_rev: GroupConfigurationRevision, group_rev: GroupConfigurationRevision,
) -> CollaborateResult<Option<GridViewRevisionChangeset>> { ) -> CollaborateResult<Option<GridViewRevisionChangeset>> {
self.modify(|view| { self.modify(|view| {
view.groups.insert_object(field_id, field_type, group_rev); // Only save one group
view.groups.clear();
view.groups.add_object(field_id, field_type, group_rev);
Ok(Some(())) Ok(Some(()))
}) })
} }
@ -127,7 +129,7 @@ impl GridViewRevisionPad {
filter_rev: FilterConfigurationRevision, filter_rev: FilterConfigurationRevision,
) -> CollaborateResult<Option<GridViewRevisionChangeset>> { ) -> CollaborateResult<Option<GridViewRevisionChangeset>> {
self.modify(|view| { self.modify(|view| {
view.filters.insert_object(field_id, field_type, filter_rev); view.filters.add_object(field_id, field_type, filter_rev);
Ok(Some(())) Ok(Some(()))
}) })
} }
@ -166,8 +168,6 @@ impl GridViewRevisionPad {
None => Ok(None), None => Ok(None),
Some(delta) => { Some(delta) => {
self.delta = self.delta.compose(&delta)?; self.delta = self.delta.compose(&delta)?;
tracing::info!("GridView: {:?}", delta);
let md5 = md5(&self.delta.json_bytes()); let md5 = md5(&self.delta.json_bytes());
Ok(Some(GridViewRevisionChangeset { delta, md5 })) Ok(Some(GridViewRevisionChangeset { delta, md5 }))
} }