refactor: move row params

This commit is contained in:
appflowy
2022-08-17 19:29:14 +08:00
parent 3a27413dfc
commit f32068d64b
14 changed files with 268 additions and 99 deletions

View File

@ -21,7 +21,7 @@ part 'board_bloc.freezed.dart';
class BoardBloc extends Bloc<BoardEvent, BoardState> { class BoardBloc extends Bloc<BoardEvent, BoardState> {
final BoardDataController _dataController; final BoardDataController _dataController;
late final AFBoardDataController afBoardDataController; late final AFBoardDataController afBoardDataController;
List<GroupController> groupControllers = []; Map<String, GroupController> groupControllers = {};
GridFieldCache get fieldCache => _dataController.fieldCache; GridFieldCache get fieldCache => _dataController.fieldCache;
String get gridId => _dataController.gridId; String get gridId => _dataController.gridId;
@ -38,13 +38,17 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
columnId, columnId,
fromIndex, fromIndex,
toIndex, toIndex,
) {}, ) {
groupControllers[columnId]?.moveRow(fromIndex, toIndex);
},
onMoveColumnItemToColumn: ( onMoveColumnItemToColumn: (
fromColumnId, fromColumnId,
fromIndex, fromIndex,
toColumnId, toColumnId,
toIndex, toIndex,
) {}, ) {
//
},
); );
on<BoardEvent>( on<BoardEvent>(
@ -84,7 +88,7 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
@override @override
Future<void> close() async { Future<void> close() async {
await _dataController.dispose(); await _dataController.dispose();
for (final controller in groupControllers) { for (final controller in groupControllers.values) {
controller.dispose(); controller.dispose();
} }
return super.close(); return super.close();
@ -94,11 +98,12 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
for (final group in groups) { for (final group in groups) {
final delegate = GroupControllerDelegateImpl(afBoardDataController); final delegate = GroupControllerDelegateImpl(afBoardDataController);
final controller = GroupController( final controller = GroupController(
gridId: state.gridId,
group: group, group: group,
delegate: delegate, delegate: delegate,
); );
controller.startListening(); controller.startListening();
groupControllers.add(controller); groupControllers[controller.group.groupId] = (controller);
} }
} }

View File

@ -1,8 +1,12 @@
import 'package:app_flowy/plugins/grid/application/row/row_service.dart';
import 'package:flowy_sdk/log.dart'; import 'package:flowy_sdk/log.dart';
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/protobuf.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/protobuf.dart';
import 'group_listener.dart'; import 'group_listener.dart';
typedef OnGroupError = void Function(FlowyError);
abstract class GroupControllerDelegate { abstract class GroupControllerDelegate {
void removeRow(String groupId, String rowId); void removeRow(String groupId, String rowId);
void insertRow(String groupId, RowPB row, int? index); void insertRow(String groupId, RowPB row, int? index);
@ -12,12 +16,36 @@ abstract class GroupControllerDelegate {
class GroupController { class GroupController {
final GroupPB group; final GroupPB group;
final GroupListener _listener; final GroupListener _listener;
final MoveRowFFIService _rowService;
final GroupControllerDelegate delegate; final GroupControllerDelegate delegate;
OnGroupError? _onError;
GroupController({required this.group, required this.delegate}) GroupController({
: _listener = GroupListener(group); required String gridId,
required this.group,
required this.delegate,
}) : _rowService = MoveRowFFIService(gridId: gridId),
_listener = GroupListener(group);
void startListening() { Future<void> moveRow(int fromIndex, int toIndex) async {
if (fromIndex < group.rows.length && toIndex < group.rows.length) {
final fromRow = group.rows[fromIndex];
final toRow = group.rows[toIndex];
final result = await _rowService.moveRow(
rowId: fromRow.id,
fromIndex: fromIndex,
toIndex: toIndex,
upperRowId: toRow.id,
layout: GridLayout.Board,
);
result.fold((l) => null, (r) => _onError?.call(r));
}
}
void startListening({OnGroupError? onError}) {
_onError = onError;
_listener.start(onGroupChanged: (result) { _listener.start(onGroupChanged: (result) {
result.fold( result.fold(
(GroupRowsChangesetPB changeset) { (GroupRowsChangesetPB changeset) {

View File

@ -71,3 +71,32 @@ class RowFFIService {
return GridEventDuplicateRow(payload).send(); return GridEventDuplicateRow(payload).send();
} }
} }
class MoveRowFFIService {
final String gridId;
MoveRowFFIService({
required this.gridId,
});
Future<Either<Unit, FlowyError>> moveRow({
required String rowId,
required int fromIndex,
required int toIndex,
required GridLayout layout,
String? upperRowId,
}) {
var payload = MoveRowPayloadPB.create()
..viewId = gridId
..rowId = rowId
..layout = layout
..fromIndex = fromIndex
..toIndex = toIndex;
if (upperRowId != null) {
payload.upperRowId = upperRowId;
}
return GridEventMoveRow(payload).send();
}
}

View File

@ -96,28 +96,27 @@ pub struct MoveRowPayloadPB {
pub view_id: String, pub view_id: String,
#[pb(index = 2)] #[pb(index = 2)]
pub row_id: String, pub from_row_id: String,
#[pb(index = 3)]
pub from_index: i32,
#[pb(index = 4)]
pub to_index: i32,
// #[pb(index = 3)]
// pub from_index: i32,
//
// #[pb(index = 4)]
// pub to_index: i32,
#[pb(index = 5)] #[pb(index = 5)]
pub layout: GridLayout, pub layout: GridLayout,
#[pb(index = 6, one_of)] #[pb(index = 6)]
pub upper_row_id: Option<String>, pub to_row_id: String,
} }
pub struct MoveRowParams { pub struct MoveRowParams {
pub view_id: String, pub view_id: String,
pub row_id: String, pub from_row_id: String,
pub from_index: i32, // pub from_index: i32,
pub to_index: i32, // pub to_index: i32,
pub layout: GridLayout, pub layout: GridLayout,
pub upper_row_id: Option<String>, pub to_row_id: String,
} }
impl TryInto<MoveRowParams> for MoveRowPayloadPB { impl TryInto<MoveRowParams> for MoveRowPayloadPB {
@ -125,18 +124,19 @@ impl TryInto<MoveRowParams> for MoveRowPayloadPB {
fn try_into(self) -> Result<MoveRowParams, Self::Error> { fn try_into(self) -> Result<MoveRowParams, Self::Error> {
let view_id = NotEmptyStr::parse(self.view_id).map_err(|_| ErrorCode::GridViewIdIsEmpty)?; let view_id = NotEmptyStr::parse(self.view_id).map_err(|_| ErrorCode::GridViewIdIsEmpty)?;
let row_id = NotEmptyStr::parse(self.row_id).map_err(|_| ErrorCode::RowIdIsEmpty)?; let from_row_id = NotEmptyStr::parse(self.from_row_id).map_err(|_| ErrorCode::RowIdIsEmpty)?;
let upper_row_id = match self.upper_row_id { let to_row_id = NotEmptyStr::parse(self.to_row_id).map_err(|_| ErrorCode::RowIdIsEmpty)?;
let upper_row_id = match self.to_row_id {
None => None, None => None,
Some(upper_row_id) => Some(NotEmptyStr::parse(upper_row_id).map_err(|_| ErrorCode::RowIdIsEmpty)?.0), Some(upper_row_id) => Some(NotEmptyStr::parse(upper_row_id).map_err(|_| ErrorCode::RowIdIsEmpty)?.0),
}; };
Ok(MoveRowParams { Ok(MoveRowParams {
view_id: view_id.0, view_id: view_id.0,
row_id: row_id.0, from_row_id: from_row_id.0,
from_index: self.from_index, // from_index: self.from_index,
to_index: self.to_index, // to_index: self.to_index,
layout: self.layout, layout: self.layout,
upper_row_id, to_row_id: upper_row_id,
}) })
} }
} }

View File

@ -1,5 +1,6 @@
use crate::entities::{InsertedRowPB, RowPB}; use crate::entities::{InsertedRowPB, RowPB};
use flowy_derive::ProtoBuf; use flowy_derive::ProtoBuf;
use std::fmt::Formatter;
#[derive(Debug, Default, ProtoBuf)] #[derive(Debug, Default, ProtoBuf)]
pub struct GroupRowsChangesetPB { pub struct GroupRowsChangesetPB {
@ -16,6 +17,14 @@ pub struct GroupRowsChangesetPB {
pub updated_rows: Vec<RowPB>, pub updated_rows: Vec<RowPB>,
} }
impl std::fmt::Display for GroupRowsChangesetPB {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let _ = f.write_fmt(format_args!("Group:{}", self.group_id))?;
let _ = f.write_fmt(format_args!("Insert:{:?}", self.inserted_rows))?;
f.write_fmt(format_args!("Delete:{:?}", self.deleted_rows))
}
}
impl GroupRowsChangesetPB { impl GroupRowsChangesetPB {
pub fn is_empty(&self) -> bool { pub fn is_empty(&self) -> bool {
self.inserted_rows.is_empty() && self.deleted_rows.is_empty() && self.updated_rows.is_empty() self.inserted_rows.is_empty() && self.deleted_rows.is_empty() && self.updated_rows.is_empty()

View File

@ -1,5 +1,5 @@
use crate::services::block_manager::GridBlockManager; use crate::services::block_manager::GridBlockManager;
use crate::services::grid_view_manager::{GridViewRowDelegate, GridViewRowOperation}; use crate::services::grid_view_manager::GridViewRowDelegate;
use flowy_error::FlowyResult; use flowy_error::FlowyResult;
use flowy_grid_data_model::revision::RowRevision; use flowy_grid_data_model::revision::RowRevision;
use lib_infra::future::{wrap_future, AFFuture}; use lib_infra::future::{wrap_future, AFFuture};
@ -36,10 +36,3 @@ impl GridViewRowDelegate for Arc<GridBlockManager> {
}) })
} }
} }
impl GridViewRowOperation for Arc<GridBlockManager> {
fn gv_move_row(&self, row_rev: Arc<RowRevision>, from: usize, to: usize) -> AFFuture<FlowyResult<()>> {
let block_manager = self.clone();
wrap_future(async move { block_manager.move_row(row_rev, from, to).await })
}
}

View File

@ -72,7 +72,6 @@ impl GridRevisionEditor {
user.clone(), user.clone(),
Arc::new(grid_pad.clone()), Arc::new(grid_pad.clone()),
Arc::new(block_manager.clone()), Arc::new(block_manager.clone()),
Arc::new(block_manager.clone()),
Arc::new(task_scheduler.clone()), Arc::new(task_scheduler.clone()),
) )
.await?, .await?,
@ -494,7 +493,42 @@ impl GridRevisionEditor {
} }
pub async fn move_row(&self, params: MoveRowParams) -> FlowyResult<()> { pub async fn move_row(&self, params: MoveRowParams) -> FlowyResult<()> {
self.view_manager.move_row(params).await let MoveRowParams {
view_id: _,
from_row_id: row_id,
from_index,
to_index,
layout: _,
to_row_id: upper_row_id,
} = params;
let from_index = from_index as usize;
let to_index = to_index as usize;
match self.block_manager.get_row_rev(&row_id).await? {
None => tracing::warn!("Move row failed, can not find the row:{}", row_id),
Some(row_rev) => match upper_row_id {
None => {
tracing::trace!("Move row from {} to {}", from_index, to_index);
let _ = self
.block_manager
.move_row(row_rev.clone(), from_index, to_index)
.await?;
}
Some(to_row_id) => match self.block_manager.index_of_row(&to_row_id).await {
None => tracing::error!("Can not find the row: {} when moving the row", to_row_id),
Some(to_row_index) => {
tracing::trace!("Move row from {} to {}", from_index, to_row_index);
let _ = self
.block_manager
.move_row(row_rev.clone(), from_index, to_row_index)
.await?;
self.view_manager.move_row(row_rev, to_row_id).await;
}
},
},
}
Ok(())
} }
pub async fn move_field(&self, params: MoveFieldParams) -> FlowyResult<()> { pub async fn move_field(&self, params: MoveFieldParams) -> FlowyResult<()> {

View File

@ -118,17 +118,22 @@ impl GridViewRevisionEditor {
} }
} }
// async fn get_mut_group<F>(&self, group_id: &str, f: F) -> FlowyResult<()> pub(crate) async fn did_move_row(&self, row_rev: &RowRevision, upper_row_id: &str) {
// where if let Some(changesets) = self
// F: Fn(&mut Group) -> FlowyResult<()>, .group_service
// { .write()
// for group in self.groups.write().await.iter_mut() { .await
// if group.id == group_id { .did_move_row(row_rev, upper_row_id, |field_id| {
// let _ = f(group)?; self.field_delegate.get_field_rev(&field_id)
// } })
// } .await
// Ok(()) {
// } for changeset in changesets {
tracing::trace!("Group changeset: {}", changeset);
self.notify_did_update_group(changeset).await;
}
}
}
pub(crate) async fn load_groups(&self) -> FlowyResult<Vec<GroupPB>> { pub(crate) async fn load_groups(&self) -> FlowyResult<Vec<GroupPB>> {
let field_revs = self.field_delegate.get_field_revs().await; let field_revs = self.field_delegate.get_field_revs().await;

View File

@ -31,17 +31,11 @@ pub trait GridViewRowDelegate: Send + Sync + 'static {
fn gv_row_revs(&self) -> AFFuture<Vec<Arc<RowRevision>>>; fn gv_row_revs(&self) -> AFFuture<Vec<Arc<RowRevision>>>;
} }
pub trait GridViewRowOperation: Send + Sync + 'static {
// Will be removed in the future.
fn gv_move_row(&self, row_rev: Arc<RowRevision>, from: usize, to: usize) -> AFFuture<FlowyResult<()>>;
}
pub(crate) struct GridViewManager { pub(crate) struct GridViewManager {
grid_id: String, grid_id: String,
user: Arc<dyn GridUser>, user: Arc<dyn GridUser>,
field_delegate: Arc<dyn GridViewFieldDelegate>, field_delegate: Arc<dyn GridViewFieldDelegate>,
row_delegate: Arc<dyn GridViewRowDelegate>, row_delegate: Arc<dyn GridViewRowDelegate>,
row_operation: Arc<dyn GridViewRowOperation>,
view_editors: DashMap<ViewId, Arc<GridViewRevisionEditor>>, view_editors: DashMap<ViewId, Arc<GridViewRevisionEditor>>,
scheduler: Arc<dyn GridServiceTaskScheduler>, scheduler: Arc<dyn GridServiceTaskScheduler>,
} }
@ -52,7 +46,6 @@ impl GridViewManager {
user: Arc<dyn GridUser>, user: Arc<dyn GridUser>,
field_delegate: Arc<dyn GridViewFieldDelegate>, field_delegate: Arc<dyn GridViewFieldDelegate>,
row_delegate: Arc<dyn GridViewRowDelegate>, row_delegate: Arc<dyn GridViewRowDelegate>,
row_operation: Arc<dyn GridViewRowOperation>,
scheduler: Arc<dyn GridServiceTaskScheduler>, scheduler: Arc<dyn GridServiceTaskScheduler>,
) -> FlowyResult<Self> { ) -> FlowyResult<Self> {
Ok(Self { Ok(Self {
@ -61,7 +54,6 @@ impl GridViewManager {
scheduler, scheduler,
field_delegate, field_delegate,
row_delegate, row_delegate,
row_operation,
view_editors: DashMap::default(), view_editors: DashMap::default(),
}) })
} }
@ -119,37 +111,10 @@ impl GridViewManager {
Ok(RepeatedGridGroupPB { items: groups }) Ok(RepeatedGridGroupPB { items: groups })
} }
pub(crate) async fn move_row(&self, params: MoveRowParams) -> FlowyResult<()> { pub(crate) async fn move_row(&self, row_rev: Arc<RowRevision>, to_row_id: String) {
let MoveRowParams { for view_editor in self.view_editors.iter() {
view_id: _, view_editor.did_move_row(&row_rev, &to_row_id).await;
row_id,
from_index,
to_index,
layout,
upper_row_id,
} = params;
let from_index = from_index as usize;
match self.row_delegate.gv_get_row_rev(&row_id).await {
None => tracing::warn!("Move row failed, can not find the row:{}", row_id),
Some(row_rev) => match layout {
GridLayout::Table => {
tracing::trace!("Move row from {} to {}", from_index, to_index);
let to_index = to_index as usize;
let _ = self.row_operation.gv_move_row(row_rev, from_index, to_index).await?;
} }
GridLayout::Board => {
if let Some(upper_row_id) = upper_row_id {
if let Some(to_index) = self.row_delegate.gv_index_of_row(&upper_row_id).await {
tracing::trace!("Move row from {} to {}", from_index, to_index);
let _ = self.row_operation.gv_move_row(row_rev, from_index, to_index).await?;
}
}
}
},
}
Ok(())
} }
pub(crate) async fn get_view_editor(&self, view_id: &str) -> FlowyResult<Arc<GridViewRevisionEditor>> { pub(crate) async fn get_view_editor(&self, view_id: &str) -> FlowyResult<Arc<GridViewRevisionEditor>> {

View File

@ -39,6 +39,7 @@ impl Groupable for CheckboxGroupController {
&mut self, &mut self,
row_rev: &RowRevision, row_rev: &RowRevision,
cell_data: &Self::CellDataType, cell_data: &Self::CellDataType,
to_row_id: &str,
) -> Vec<GroupRowsChangesetPB> { ) -> Vec<GroupRowsChangesetPB> {
todo!() todo!()
} }

View File

@ -29,8 +29,12 @@ pub trait Groupable: Send + Sync {
cell_data: &Self::CellDataType, cell_data: &Self::CellDataType,
) -> Vec<GroupRowsChangesetPB>; ) -> Vec<GroupRowsChangesetPB>;
fn move_row_if_match(&mut self, row_rev: &RowRevision, cell_data: &Self::CellDataType) fn move_row_if_match(
-> Vec<GroupRowsChangesetPB>; &mut self,
row_rev: &RowRevision,
cell_data: &Self::CellDataType,
to_row_id: &str,
) -> Vec<GroupRowsChangesetPB>;
} }
pub trait GroupController: GroupControllerSharedAction + Send + Sync { pub trait GroupController: GroupControllerSharedAction + Send + Sync {
@ -53,6 +57,13 @@ pub trait GroupControllerSharedAction: Send + Sync {
row_rev: &RowRevision, row_rev: &RowRevision,
field_rev: &FieldRevision, field_rev: &FieldRevision,
) -> FlowyResult<Vec<GroupRowsChangesetPB>>; ) -> FlowyResult<Vec<GroupRowsChangesetPB>>;
fn did_move_row(
&mut self,
row_rev: &RowRevision,
field_rev: &FieldRevision,
to_row_id: &str,
) -> FlowyResult<Vec<GroupRowsChangesetPB>>;
} }
const DEFAULT_GROUP_ID: &str = "default_group"; const DEFAULT_GROUP_ID: &str = "default_group";
@ -120,6 +131,18 @@ impl Group {
Some(_) => {} Some(_) => {}
} }
} }
pub fn insert_row(&mut self, index: usize, row_pb: RowPB) {
if index < self.rows.len() {
self.rows.insert(index, row_pb);
} else {
tracing::error!("Insert row index:{} beyond the bounds:{},", index, self.rows.len());
}
}
pub fn index_of_row(&self, row_id: &str) -> Option<usize> {
self.rows.iter().position(|row| row.id == row_id)
}
} }
impl<C, T, G, P> GenericGroupController<C, T, G, P> impl<C, T, G, P> GenericGroupController<C, T, G, P>
@ -236,6 +259,21 @@ where
Ok(vec![]) Ok(vec![])
} }
} }
fn did_move_row(
&mut self,
row_rev: &RowRevision,
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>()?;
Ok(self.move_row_if_match(row_rev, &cell_data, to_row_id))
} else {
Ok(vec![])
}
}
} }
// impl<C, T, G, P> GroupController<C, T, G, P> // impl<C, T, G, P> GroupController<C, T, G, P>

View File

@ -45,8 +45,13 @@ impl Groupable for SingleSelectGroupController {
&mut self, &mut self,
row_rev: &RowRevision, row_rev: &RowRevision,
cell_data: &Self::CellDataType, cell_data: &Self::CellDataType,
to_row_id: &str,
) -> Vec<GroupRowsChangesetPB> { ) -> Vec<GroupRowsChangesetPB> {
todo!() let mut changesets = vec![];
self.groups_map.iter_mut().for_each(|(_, group): (_, &mut Group)| {
move_row(group, &mut changesets, cell_data, row_rev, to_row_id);
});
changesets
} }
} }
@ -100,7 +105,6 @@ impl Groupable for MultiSelectGroupController {
fn add_row_if_match(&mut self, row_rev: &RowRevision, cell_data: &Self::CellDataType) -> Vec<GroupRowsChangesetPB> { fn add_row_if_match(&mut self, row_rev: &RowRevision, cell_data: &Self::CellDataType) -> Vec<GroupRowsChangesetPB> {
let mut changesets = vec![]; let mut changesets = vec![];
self.groups_map.iter_mut().for_each(|(_, group): (_, &mut Group)| { self.groups_map.iter_mut().for_each(|(_, group): (_, &mut Group)| {
add_row(group, &mut changesets, cell_data, row_rev); add_row(group, &mut changesets, cell_data, row_rev);
}); });
@ -123,8 +127,13 @@ impl Groupable for MultiSelectGroupController {
&mut self, &mut self,
row_rev: &RowRevision, row_rev: &RowRevision,
cell_data: &Self::CellDataType, cell_data: &Self::CellDataType,
to_row_id: &str,
) -> Vec<GroupRowsChangesetPB> { ) -> Vec<GroupRowsChangesetPB> {
todo!() let mut changesets = vec![];
self.groups_map.iter_mut().for_each(|(_, group): (_, &mut Group)| {
move_row(group, &mut changesets, cell_data, row_rev, to_row_id);
});
changesets
} }
} }
@ -178,11 +187,6 @@ fn add_row(
group.add_row(row_pb); group.add_row(row_pb);
} }
} }
// else if group.contains_row(&row_rev.id) {
// group.remove_row(&row_rev.id);
// changesets.push(GroupRowsChangesetPB::delete(group.id.clone(), vec![row_rev.id.clone()]));
// }
}); });
} }
@ -201,3 +205,30 @@ fn remove_row(
} }
}); });
} }
fn move_row(
group: &mut Group,
changesets: &mut Vec<GroupRowsChangesetPB>,
cell_data: &SelectOptionCellDataPB,
row_rev: &RowRevision,
upper_row_id: &str,
) {
cell_data.select_options.iter().for_each(|option| {
if option.id == group.id {
if group.contains_row(&row_rev.id) {
changesets.push(GroupRowsChangesetPB::delete(group.id.clone(), vec![row_rev.id.clone()]));
group.remove_row(&row_rev.id);
}
}
if let Some(index) = group.index_of_row(upper_row_id) {
let row_pb = RowPB::from(row_rev);
let inserted_row = InsertedRowPB {
row: row_pb.clone(),
index: Some(index as i32),
};
changesets.push(GroupRowsChangesetPB::insert(group.id.clone(), vec![inserted_row]));
group.insert_row(index, row_pb);
}
});
}

View File

@ -87,7 +87,34 @@ impl GroupService {
match group_controller.write().await.did_delete_row(row_rev, &field_rev) { match group_controller.write().await.did_delete_row(row_rev, &field_rev) {
Ok(changesets) => Some(changesets), Ok(changesets) => Some(changesets),
Err(e) => { Err(e) => {
tracing::error!("Update group data failed, {:?}", e); tracing::error!("Delete group data failed, {:?}", e);
None
}
}
}
pub(crate) async fn did_move_row<F, O>(
&self,
row_rev: &RowRevision,
upper_row_id: &str,
get_field_fn: F,
) -> Option<Vec<GroupRowsChangesetPB>>
where
F: FnOnce(String) -> O,
O: Future<Output = Option<Arc<FieldRevision>>> + Send + Sync + 'static,
{
let group_controller = self.group_controller.as_ref()?;
let field_id = group_controller.read().await.field_id().to_owned();
let field_rev = get_field_fn(field_id).await?;
match group_controller
.write()
.await
.did_move_row(row_rev, &field_rev, upper_row_id)
{
Ok(changesets) => Some(changesets),
Err(e) => {
tracing::error!("Move group data failed, {:?}", e);
None None
} }
} }

View File

@ -178,8 +178,12 @@ impl GridBlockRevisionPad {
if let Some(position) = row_revs.iter().position(|row_rev| row_rev.id == row_id) { if let Some(position) = row_revs.iter().position(|row_rev| row_rev.id == row_id) {
debug_assert_eq!(from, position); debug_assert_eq!(from, position);
let row_rev = row_revs.remove(position); let row_rev = row_revs.remove(position);
if to > row_revs.len() {
return Err(CollaborateError::out_of_bound());
} else {
row_revs.insert(to, row_rev); row_revs.insert(to, row_rev);
Ok(Some(())) Ok(Some(()))
}
} else { } else {
Ok(None) Ok(None)
} }