mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
feat: add new group (#3854)
* feat: implement backend logic * fix: did_create_row not working properly * fix: did_delete_group not working properly * fix: test * chore: fix clippy * fix: new card not editable and in wrong position * feat: imlement UI for add new stack * test: add integration test * chore: i18n * chore: remove debug message * chore: merge conflict --------- Co-authored-by: nathan <nathan@appflowy.io>
This commit is contained in:
@ -197,3 +197,36 @@ impl From<UpdateGroupParams> for GroupChangeset {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, ProtoBuf)]
|
||||
pub struct CreateGroupPayloadPB {
|
||||
#[pb(index = 1)]
|
||||
pub view_id: String,
|
||||
|
||||
#[pb(index = 2)]
|
||||
pub group_config_id: String,
|
||||
|
||||
#[pb(index = 3)]
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CreateGroupParams {
|
||||
pub view_id: String,
|
||||
pub group_config_id: String,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
impl TryFrom<CreateGroupPayloadPB> for CreateGroupParams {
|
||||
type Error = ErrorCode;
|
||||
|
||||
fn try_from(value: CreateGroupPayloadPB) -> Result<Self, Self::Error> {
|
||||
let view_id = NotEmptyStr::parse(value.view_id).map_err(|_| ErrorCode::ViewIdIsInvalid)?;
|
||||
let name = NotEmptyStr::parse(value.name).map_err(|_| ErrorCode::ViewIdIsInvalid)?;
|
||||
Ok(CreateGroupParams {
|
||||
view_id: view_id.0,
|
||||
group_config_id: value.group_config_id,
|
||||
name: name.0,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -741,6 +741,20 @@ pub(crate) async fn move_group_row_handler(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip(manager), err)]
|
||||
pub(crate) async fn create_group_handler(
|
||||
data: AFPluginData<CreateGroupPayloadPB>,
|
||||
manager: AFPluginState<Weak<DatabaseManager>>,
|
||||
) -> FlowyResult<()> {
|
||||
let manager = upgrade_manager(manager)?;
|
||||
let params: CreateGroupParams = data.into_inner().try_into()?;
|
||||
let database_editor = manager.get_database_with_view_id(¶ms.view_id).await?;
|
||||
database_editor
|
||||
.create_group(¶ms.view_id, ¶ms.name)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip(manager), err)]
|
||||
pub(crate) async fn get_databases_handler(
|
||||
manager: AFPluginState<Weak<DatabaseManager>>,
|
||||
|
@ -60,6 +60,7 @@ pub fn init(database_manager: Weak<DatabaseManager>) -> AFPlugin {
|
||||
.event(DatabaseEvent::GetGroups, get_groups_handler)
|
||||
.event(DatabaseEvent::GetGroup, get_group_handler)
|
||||
.event(DatabaseEvent::UpdateGroup, update_group_handler)
|
||||
.event(DatabaseEvent::CreateGroup, create_group_handler)
|
||||
// Database
|
||||
.event(DatabaseEvent::GetDatabases, get_databases_handler)
|
||||
// Calendar
|
||||
@ -284,6 +285,9 @@ pub enum DatabaseEvent {
|
||||
#[event(input = "UpdateGroupPB")]
|
||||
UpdateGroup = 113,
|
||||
|
||||
#[event(input = "CreateGroupPayloadPB")]
|
||||
CreateGroup = 114,
|
||||
|
||||
/// Returns all the databases
|
||||
#[event(output = "RepeatedDatabaseDescriptionPB")]
|
||||
GetDatabases = 120,
|
||||
|
@ -442,7 +442,7 @@ impl DatabaseEditor {
|
||||
let row_detail = self.database.lock().get_row_detail(&row_order.id);
|
||||
if let Some(row_detail) = row_detail {
|
||||
for view in self.database_views.editors().await {
|
||||
view.v_did_create_row(&row_detail, &group_id, index).await;
|
||||
view.v_did_create_row(&row_detail, index).await;
|
||||
}
|
||||
return Ok(Some(row_detail));
|
||||
}
|
||||
@ -961,6 +961,12 @@ impl DatabaseEditor {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn create_group(&self, view_id: &str, name: &str) -> FlowyResult<()> {
|
||||
let view_editor = self.database_views.get_view_editor(view_id).await?;
|
||||
view_editor.v_create_group(name).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "trace", skip_all)]
|
||||
pub async fn set_layout_setting(
|
||||
&self,
|
||||
|
@ -14,8 +14,8 @@ use lib_dispatch::prelude::af_spawn;
|
||||
use crate::entities::{
|
||||
CalendarEventPB, DatabaseLayoutMetaPB, DatabaseLayoutSettingPB, DeleteFilterParams,
|
||||
DeleteGroupParams, DeleteSortParams, FieldType, FieldVisibility, GroupChangesPB, GroupPB,
|
||||
GroupRowsNotificationPB, InsertedRowPB, LayoutSettingChangeset, LayoutSettingParams, RowMetaPB,
|
||||
RowsChangePB, SortChangesetNotificationPB, SortPB, UpdateFilterParams, UpdateSortParams,
|
||||
InsertedRowPB, LayoutSettingChangeset, LayoutSettingParams, RowMetaPB, RowsChangePB,
|
||||
SortChangesetNotificationPB, SortPB, UpdateFilterParams, UpdateSortParams,
|
||||
};
|
||||
use crate::notification::{send_notification, DatabaseNotification};
|
||||
use crate::services::cell::CellCache;
|
||||
@ -126,39 +126,22 @@ impl DatabaseViewEditor {
|
||||
.send();
|
||||
}
|
||||
|
||||
pub async fn v_did_create_row(
|
||||
&self,
|
||||
row_detail: &RowDetail,
|
||||
group_id: &Option<String>,
|
||||
index: usize,
|
||||
) {
|
||||
let changes: RowsChangePB;
|
||||
pub async fn v_did_create_row(&self, row_detail: &RowDetail, index: usize) {
|
||||
// Send the group notification if the current view has groups
|
||||
match group_id.as_ref() {
|
||||
None => {
|
||||
let row = InsertedRowPB::new(RowMetaPB::from(row_detail)).with_index(index as i32);
|
||||
changes = RowsChangePB::from_insert(row);
|
||||
},
|
||||
Some(group_id) => {
|
||||
self
|
||||
.mut_group_controller(|group_controller, _| {
|
||||
group_controller.did_create_row(row_detail, group_id);
|
||||
Ok(())
|
||||
})
|
||||
.await;
|
||||
if let Some(controller) = self.group_controller.write().await.as_mut() {
|
||||
let changesets = controller.did_create_row(row_detail, index);
|
||||
|
||||
let inserted_row = InsertedRowPB {
|
||||
row_meta: RowMetaPB::from(row_detail),
|
||||
index: Some(index as i32),
|
||||
is_new: true,
|
||||
};
|
||||
let changeset =
|
||||
GroupRowsNotificationPB::insert(group_id.clone(), vec![inserted_row.clone()]);
|
||||
for changeset in changesets {
|
||||
notify_did_update_group_rows(changeset).await;
|
||||
changes = RowsChangePB::from_insert(inserted_row);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
let inserted_row = InsertedRowPB {
|
||||
row_meta: RowMetaPB::from(row_detail),
|
||||
index: Some(index as i32),
|
||||
is_new: true,
|
||||
};
|
||||
let changes = RowsChangePB::from_insert(inserted_row);
|
||||
send_notification(&self.view_id, DatabaseNotification::DidUpdateViewRows)
|
||||
.payload(changes)
|
||||
.send();
|
||||
@ -168,16 +151,22 @@ impl DatabaseViewEditor {
|
||||
pub async fn v_did_delete_row(&self, row: &Row) {
|
||||
// Send the group notification if the current view has groups;
|
||||
let result = self
|
||||
.mut_group_controller(|group_controller, field| {
|
||||
group_controller.did_delete_delete_row(row, &field)
|
||||
})
|
||||
.mut_group_controller(|group_controller, _| group_controller.did_delete_row(row))
|
||||
.await;
|
||||
|
||||
if let Some(result) = result {
|
||||
tracing::trace!("Delete row in view changeset: {:?}", result.row_changesets);
|
||||
tracing::trace!("Delete row in view changeset: {:?}", result);
|
||||
for changeset in result.row_changesets {
|
||||
notify_did_update_group_rows(changeset).await;
|
||||
}
|
||||
if let Some(deleted_group) = result.deleted_group {
|
||||
let payload = GroupChangesPB {
|
||||
view_id: self.view_id.clone(),
|
||||
deleted_groups: vec![deleted_group.group_id],
|
||||
..Default::default()
|
||||
};
|
||||
notify_did_update_num_of_groups(&self.view_id, payload).await;
|
||||
}
|
||||
}
|
||||
let changes = RowsChangePB::from_delete(row.id.clone().into_inner());
|
||||
send_notification(&self.view_id, DatabaseNotification::DidUpdateViewRows)
|
||||
@ -319,7 +308,7 @@ impl DatabaseViewEditor {
|
||||
.read()
|
||||
.await
|
||||
.as_ref()?
|
||||
.groups()
|
||||
.get_all_groups()
|
||||
.into_iter()
|
||||
.filter(|group| group.is_visible)
|
||||
.map(|group_data| GroupPB::from(group_data.clone()))
|
||||
@ -371,6 +360,36 @@ impl DatabaseViewEditor {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn v_create_group(&self, name: &str) -> FlowyResult<()> {
|
||||
let mut old_field: Option<Field> = None;
|
||||
let result = if let Some(controller) = self.group_controller.write().await.as_mut() {
|
||||
let create_group_results = controller.create_group(name.to_string())?;
|
||||
old_field = self.delegate.get_field(controller.field_id());
|
||||
create_group_results
|
||||
} else {
|
||||
(None, None)
|
||||
};
|
||||
|
||||
if let Some(old_field) = old_field {
|
||||
if let (Some(type_option_data), Some(payload)) = result {
|
||||
self
|
||||
.delegate
|
||||
.update_field(&self.view_id, type_option_data, old_field)
|
||||
.await?;
|
||||
|
||||
let group_changes = GroupChangesPB {
|
||||
view_id: self.view_id.clone(),
|
||||
inserted_groups: vec![payload],
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
notify_did_update_num_of_groups(&self.view_id, group_changes).await;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn v_delete_group(&self, _params: DeleteGroupParams) -> FlowyResult<()> {
|
||||
Ok(())
|
||||
}
|
||||
@ -671,7 +690,7 @@ impl DatabaseViewEditor {
|
||||
.await?;
|
||||
|
||||
let new_groups = new_group_controller
|
||||
.groups()
|
||||
.get_all_groups()
|
||||
.into_iter()
|
||||
.map(|group| GroupPB::from(group.clone()))
|
||||
.collect();
|
||||
|
@ -25,15 +25,27 @@ pub trait SelectTypeOptionSharedAction: Send + Sync {
|
||||
/// If the option already exists, it will be updated.
|
||||
/// If the option does not exist, it will be inserted at the beginning.
|
||||
fn insert_option(&mut self, new_option: SelectOption) {
|
||||
self.insert_option_at_index(new_option, None);
|
||||
}
|
||||
|
||||
fn insert_option_at_index(&mut self, new_option: SelectOption, new_index: Option<usize>) {
|
||||
let options = self.mut_options();
|
||||
let safe_new_index = new_index.map(|index| {
|
||||
if index > options.len() {
|
||||
options.len()
|
||||
} else {
|
||||
index
|
||||
}
|
||||
});
|
||||
|
||||
if let Some(index) = options
|
||||
.iter()
|
||||
.position(|option| option.id == new_option.id || option.name == new_option.name)
|
||||
{
|
||||
options.remove(index);
|
||||
options.insert(index, new_option);
|
||||
options.insert(safe_new_index.unwrap_or(index), new_option);
|
||||
} else {
|
||||
options.insert(0, new_option);
|
||||
options.insert(safe_new_index.unwrap_or(0), new_option);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -54,7 +54,7 @@ pub trait GroupCustomize: Send + Sync {
|
||||
&mut self,
|
||||
row: &Row,
|
||||
cell_data: &<Self::GroupTypeOption as TypeOption>::CellData,
|
||||
) -> Vec<GroupRowsNotificationPB>;
|
||||
) -> (Option<GroupPB>, Vec<GroupRowsNotificationPB>);
|
||||
|
||||
/// Move row from one group to another
|
||||
fn move_row(
|
||||
@ -71,27 +71,71 @@ pub trait GroupCustomize: Send + Sync {
|
||||
) -> Option<GroupPB> {
|
||||
None
|
||||
}
|
||||
|
||||
fn generate_new_group(
|
||||
&mut self,
|
||||
_name: String,
|
||||
) -> FlowyResult<(Option<TypeOptionData>, Option<InsertedGroupPB>)> {
|
||||
Ok((None, None))
|
||||
}
|
||||
}
|
||||
|
||||
/// Defines the shared actions any group controller can perform.
|
||||
#[async_trait]
|
||||
pub trait GroupControllerOperation: Send + Sync {
|
||||
/// The field that is used for grouping the rows
|
||||
/// Returns the id of field that is being used to group the rows
|
||||
fn field_id(&self) -> &str;
|
||||
|
||||
/// Returns number of groups the current field has
|
||||
fn groups(&self) -> Vec<&GroupData>;
|
||||
/// Returns all of the groups currently managed by the controller
|
||||
fn get_all_groups(&self) -> Vec<&GroupData>;
|
||||
|
||||
/// Returns the index and the group data with group_id
|
||||
/// Returns the index and the group data with the given group id if it exists.
|
||||
///
|
||||
/// * `group_id` - A string slice that is used to match the group
|
||||
fn get_group(&self, group_id: &str) -> Option<(usize, GroupData)>;
|
||||
|
||||
/// Separates the rows into different groups
|
||||
/// Sort the rows into the different groups.
|
||||
///
|
||||
/// * `rows`: rows to be inserted
|
||||
/// * `field`: reference to the field being sorted (currently unused)
|
||||
fn fill_groups(&mut self, rows: &[&RowDetail], field: &Field) -> FlowyResult<()>;
|
||||
|
||||
/// Remove the group with from_group_id and insert it to the index with to_group_id
|
||||
/// Create a new group, currently only supports single and multi-select.
|
||||
///
|
||||
/// Returns a new type option data for the grouping field if it's altered.
|
||||
///
|
||||
/// * `name`: name of the new group
|
||||
fn create_group(
|
||||
&mut self,
|
||||
name: String,
|
||||
) -> FlowyResult<(Option<TypeOptionData>, Option<InsertedGroupPB>)>;
|
||||
|
||||
/// Reorders the group in the group controller.
|
||||
///
|
||||
/// * `from_group_id`: id of the group being moved
|
||||
/// * `to_group_id`: id of the group whose index is the one at which the
|
||||
/// reordered group will be placed
|
||||
fn move_group(&mut self, from_group_id: &str, to_group_id: &str) -> FlowyResult<()>;
|
||||
|
||||
/// Insert/Remove the row to the group if the corresponding cell data is changed
|
||||
/// Adds a newly-created row to one or more suitable groups.
|
||||
///
|
||||
/// Returns a changeset payload to be sent as a notification.
|
||||
///
|
||||
/// * `row_detail`: the newly-created row
|
||||
fn did_create_row(
|
||||
&mut self,
|
||||
row_detail: &RowDetail,
|
||||
index: usize,
|
||||
) -> Vec<GroupRowsNotificationPB>;
|
||||
|
||||
/// Called after a row's cell data is changed, this moves the row to the
|
||||
/// correct group. It may also insert a new group and/or remove an old group.
|
||||
///
|
||||
/// Returns the inserted and removed groups if necessary for notification.
|
||||
///
|
||||
/// * `old_row_detail`:
|
||||
/// * `row_detail`:
|
||||
/// * `field`:
|
||||
fn did_update_group_row(
|
||||
&mut self,
|
||||
old_row_detail: &Option<RowDetail>,
|
||||
@ -99,22 +143,31 @@ pub trait GroupControllerOperation: Send + Sync {
|
||||
field: &Field,
|
||||
) -> FlowyResult<DidUpdateGroupRowResult>;
|
||||
|
||||
/// Remove the row from the group if the row gets deleted
|
||||
fn did_delete_delete_row(
|
||||
&mut self,
|
||||
row: &Row,
|
||||
field: &Field,
|
||||
) -> FlowyResult<DidMoveGroupRowResult>;
|
||||
/// Called after the row is deleted, this removes the row from the group.
|
||||
/// A group could be deleted as a result.
|
||||
///
|
||||
/// Returns a the removed group when this occurs.
|
||||
fn did_delete_row(&mut self, row: &Row) -> FlowyResult<DidMoveGroupRowResult>;
|
||||
|
||||
/// Move the row from one group to another group
|
||||
/// Reorders a row within the current group or move the row to another group.
|
||||
///
|
||||
/// * `context`: information about the row being moved and its destination
|
||||
fn move_group_row(&mut self, context: MoveGroupRowContext) -> FlowyResult<DidMoveGroupRowResult>;
|
||||
|
||||
/// Update the group if the corresponding field is changed
|
||||
/// Updates the groups after a field change. (currently never does anything)
|
||||
///
|
||||
/// * `field`: new changeset
|
||||
fn did_update_group_field(&mut self, field: &Field) -> FlowyResult<Option<GroupChangesPB>>;
|
||||
|
||||
/// Updates the name and/or visibility of groups.
|
||||
///
|
||||
/// Returns a non-empty `TypeOptionData` when the changes require a change
|
||||
/// in the field type option data.
|
||||
///
|
||||
/// * `changesets`: list of changesets to be made to one or more groups
|
||||
async fn apply_group_changeset(
|
||||
&mut self,
|
||||
changeset: &GroupChangesets,
|
||||
changesets: &GroupChangesets,
|
||||
) -> FlowyResult<TypeOptionData>;
|
||||
}
|
||||
|
||||
|
@ -124,6 +124,7 @@ where
|
||||
/// Returns the no `status` group
|
||||
///
|
||||
/// We take the `id` of the `field` as the no status group id
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn get_no_status_group(&self) -> Option<&GroupData> {
|
||||
self.group_by_id.get(&self.field.id)
|
||||
}
|
||||
@ -249,7 +250,7 @@ where
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `generated_group_configs`: the generated groups contains a list of [GeneratedGroupConfig].
|
||||
/// * `generated_groups`: the generated groups contains a list of [GeneratedGroupConfig].
|
||||
///
|
||||
/// Each [FieldType] can implement the [GroupGenerator] trait in order to generate different
|
||||
/// groups. For example, the FieldType::Checkbox has the [CheckboxGroupGenerator] that implements
|
||||
|
@ -11,7 +11,7 @@ use serde::Serialize;
|
||||
use flowy_error::FlowyResult;
|
||||
|
||||
use crate::entities::{
|
||||
FieldType, GroupChangesPB, GroupRowsNotificationPB, InsertedRowPB, RowMetaPB,
|
||||
FieldType, GroupChangesPB, GroupRowsNotificationPB, InsertedGroupPB, InsertedRowPB, RowMetaPB,
|
||||
};
|
||||
use crate::services::cell::{get_cell_protobuf, CellProtobufBlobParser};
|
||||
use crate::services::field::{default_type_option_data_from_type, TypeOption, TypeOptionCellData};
|
||||
@ -38,9 +38,6 @@ pub trait GroupController: GroupControllerOperation + Send + Sync {
|
||||
|
||||
/// Called before the row was created.
|
||||
fn will_create_row(&mut self, cells: &mut Cells, field: &Field, group_id: &str);
|
||||
|
||||
/// Called after the row was created.
|
||||
fn did_create_row(&mut self, row_detail: &RowDetail, group_id: &str);
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
@ -184,7 +181,7 @@ where
|
||||
&self.grouping_field_id
|
||||
}
|
||||
|
||||
fn groups(&self) -> Vec<&GroupData> {
|
||||
fn get_all_groups(&self) -> Vec<&GroupData> {
|
||||
self.context.groups()
|
||||
}
|
||||
|
||||
@ -233,10 +230,70 @@ where
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn create_group(
|
||||
&mut self,
|
||||
name: String,
|
||||
) -> FlowyResult<(Option<TypeOptionData>, Option<InsertedGroupPB>)> {
|
||||
self.generate_new_group(name)
|
||||
}
|
||||
|
||||
fn move_group(&mut self, from_group_id: &str, to_group_id: &str) -> FlowyResult<()> {
|
||||
self.context.move_group(from_group_id, to_group_id)
|
||||
}
|
||||
|
||||
fn did_create_row(
|
||||
&mut self,
|
||||
row_detail: &RowDetail,
|
||||
index: usize,
|
||||
) -> Vec<GroupRowsNotificationPB> {
|
||||
let cell = match row_detail.row.cells.get(&self.grouping_field_id) {
|
||||
None => self.placeholder_cell(),
|
||||
Some(cell) => Some(cell.clone()),
|
||||
};
|
||||
|
||||
let mut changesets: Vec<GroupRowsNotificationPB> = vec![];
|
||||
if let Some(cell) = cell {
|
||||
let cell_data = <T as TypeOption>::CellData::from(&cell);
|
||||
|
||||
let mut suitable_group_ids = vec![];
|
||||
|
||||
for group in self.get_all_groups() {
|
||||
if self.can_group(&group.filter_content, &cell_data) {
|
||||
suitable_group_ids.push(group.id.clone());
|
||||
let changeset = GroupRowsNotificationPB::insert(
|
||||
group.id.clone(),
|
||||
vec![InsertedRowPB {
|
||||
row_meta: row_detail.into(),
|
||||
index: Some(index as i32),
|
||||
is_new: true,
|
||||
}],
|
||||
);
|
||||
changesets.push(changeset);
|
||||
}
|
||||
}
|
||||
if !suitable_group_ids.is_empty() {
|
||||
for group_id in suitable_group_ids.iter() {
|
||||
if let Some(group) = self.context.get_mut_group(group_id) {
|
||||
group.add_row(row_detail.clone());
|
||||
}
|
||||
}
|
||||
} else if let Some(no_status_group) = self.context.get_mut_no_status_group() {
|
||||
no_status_group.add_row(row_detail.clone());
|
||||
let changeset = GroupRowsNotificationPB::insert(
|
||||
no_status_group.id.clone(),
|
||||
vec![InsertedRowPB {
|
||||
row_meta: row_detail.into(),
|
||||
index: Some(index as i32),
|
||||
is_new: true,
|
||||
}],
|
||||
);
|
||||
changesets.push(changeset);
|
||||
}
|
||||
}
|
||||
|
||||
changesets
|
||||
}
|
||||
|
||||
fn did_update_group_row(
|
||||
&mut self,
|
||||
old_row_detail: &Option<RowDetail>,
|
||||
@ -278,26 +335,21 @@ where
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
fn did_delete_delete_row(
|
||||
&mut self,
|
||||
row: &Row,
|
||||
_field: &Field,
|
||||
) -> FlowyResult<DidMoveGroupRowResult> {
|
||||
// if the cell_rev is none, then the row must in the default group.
|
||||
fn did_delete_row(&mut self, row: &Row) -> FlowyResult<DidMoveGroupRowResult> {
|
||||
let mut result = DidMoveGroupRowResult {
|
||||
deleted_group: None,
|
||||
row_changesets: vec![],
|
||||
};
|
||||
// early return if the row is not in the default group
|
||||
if let Some(cell) = row.cells.get(&self.grouping_field_id) {
|
||||
let cell_data = <T as TypeOption>::CellData::from(cell);
|
||||
if !cell_data.is_cell_empty() {
|
||||
tracing::error!("did_delete_delete_row {:?}", cell);
|
||||
result.row_changesets = self.delete_row(row, &cell_data);
|
||||
(result.deleted_group, result.row_changesets) = self.delete_row(row, &cell_data);
|
||||
return Ok(result);
|
||||
}
|
||||
}
|
||||
|
||||
match self.context.get_no_status_group() {
|
||||
match self.context.get_mut_no_status_group() {
|
||||
None => {
|
||||
tracing::error!("Unexpected None value. It should have the no status group");
|
||||
},
|
||||
@ -305,6 +357,7 @@ where
|
||||
if !no_status_group.contains_row(&row.id) {
|
||||
tracing::error!("The row: {:?} should be in the no status group", row.id);
|
||||
}
|
||||
no_status_group.remove_row(&row.id);
|
||||
result.row_changesets = vec![GroupRowsNotificationPB::delete(
|
||||
no_status_group.id.clone(),
|
||||
vec![row.id.clone().into_inner()],
|
||||
|
@ -3,7 +3,7 @@ use collab_database::fields::{Field, TypeOptionData};
|
||||
use collab_database::rows::{new_cell_builder, Cell, Cells, Row, RowDetail};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::entities::{FieldType, GroupRowsNotificationPB, InsertedRowPB, RowMetaPB};
|
||||
use crate::entities::{FieldType, GroupPB, GroupRowsNotificationPB, InsertedRowPB, RowMetaPB};
|
||||
use crate::services::cell::insert_checkbox_cell;
|
||||
use crate::services::field::{
|
||||
CheckboxCellDataParser, CheckboxTypeOption, TypeOption, CHECK, UNCHECK,
|
||||
@ -109,7 +109,7 @@ impl GroupCustomize for CheckboxGroupController {
|
||||
&mut self,
|
||||
row: &Row,
|
||||
_cell_data: &<Self::GroupTypeOption as TypeOption>::CellData,
|
||||
) -> Vec<GroupRowsNotificationPB> {
|
||||
) -> (Option<GroupPB>, Vec<GroupRowsNotificationPB>) {
|
||||
let mut changesets = vec![];
|
||||
self.context.iter_mut_groups(|group| {
|
||||
let mut changeset = GroupRowsNotificationPB::new(group.id.clone());
|
||||
@ -122,7 +122,7 @@ impl GroupCustomize for CheckboxGroupController {
|
||||
changesets.push(changeset);
|
||||
}
|
||||
});
|
||||
changesets
|
||||
(None, changesets)
|
||||
}
|
||||
|
||||
fn move_row(
|
||||
@ -155,12 +155,6 @@ impl GroupController for CheckboxGroupController {
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn did_create_row(&mut self, row_detail: &RowDetail, group_id: &str) {
|
||||
if let Some(group) = self.context.get_mut_group(group_id) {
|
||||
group.add_row(row_detail.clone())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CheckboxGroupBuilder();
|
||||
|
@ -178,8 +178,8 @@ impl GroupCustomize for DateGroupController {
|
||||
fn delete_row(
|
||||
&mut self,
|
||||
row: &Row,
|
||||
_cell_data: &<Self::GroupTypeOption as TypeOption>::CellData,
|
||||
) -> Vec<GroupRowsNotificationPB> {
|
||||
cell_data: &<Self::GroupTypeOption as TypeOption>::CellData,
|
||||
) -> (Option<GroupPB>, Vec<GroupRowsNotificationPB>) {
|
||||
let mut changesets = vec![];
|
||||
self.context.iter_mut_groups(|group| {
|
||||
let mut changeset = GroupRowsNotificationPB::new(group.id.clone());
|
||||
@ -192,7 +192,23 @@ impl GroupCustomize for DateGroupController {
|
||||
changesets.push(changeset);
|
||||
}
|
||||
});
|
||||
changesets
|
||||
|
||||
let setting_content = self.context.get_setting_content();
|
||||
let deleted_group =
|
||||
match self
|
||||
.context
|
||||
.get_group(&group_id(cell_data, &self.type_option, &setting_content))
|
||||
{
|
||||
Some((_, group)) if group.rows.len() == 1 => Some(group.clone()),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
let deleted_group = deleted_group.map(|group| {
|
||||
let _ = self.context.delete_group(&group.id);
|
||||
group.into()
|
||||
});
|
||||
|
||||
(deleted_group, changesets)
|
||||
}
|
||||
|
||||
fn move_row(
|
||||
@ -247,12 +263,6 @@ impl GroupController for DateGroupController {
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn did_create_row(&mut self, row_detail: &RowDetail, group_id: &str) {
|
||||
if let Some(group) = self.context.get_mut_group(group_id) {
|
||||
group.add_row(row_detail.clone())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DateGroupBuilder();
|
||||
|
@ -6,7 +6,7 @@ use collab_database::rows::{Cells, Row, RowDetail};
|
||||
|
||||
use flowy_error::FlowyResult;
|
||||
|
||||
use crate::entities::GroupChangesPB;
|
||||
use crate::entities::{GroupChangesPB, GroupRowsNotificationPB, InsertedGroupPB, InsertedRowPB};
|
||||
use crate::services::group::action::{
|
||||
DidMoveGroupRowResult, DidUpdateGroupRowResult, GroupControllerOperation,
|
||||
};
|
||||
@ -44,7 +44,7 @@ impl GroupControllerOperation for DefaultGroupController {
|
||||
&self.field_id
|
||||
}
|
||||
|
||||
fn groups(&self) -> Vec<&GroupData> {
|
||||
fn get_all_groups(&self) -> Vec<&GroupData> {
|
||||
vec![&self.group]
|
||||
}
|
||||
|
||||
@ -59,10 +59,34 @@ impl GroupControllerOperation for DefaultGroupController {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn create_group(
|
||||
&mut self,
|
||||
_name: String,
|
||||
) -> FlowyResult<(Option<TypeOptionData>, Option<InsertedGroupPB>)> {
|
||||
Ok((None, None))
|
||||
}
|
||||
|
||||
fn move_group(&mut self, _from_group_id: &str, _to_group_id: &str) -> FlowyResult<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn did_create_row(
|
||||
&mut self,
|
||||
row_detail: &RowDetail,
|
||||
index: usize,
|
||||
) -> Vec<GroupRowsNotificationPB> {
|
||||
self.group.add_row(row_detail.clone());
|
||||
|
||||
vec![GroupRowsNotificationPB::insert(
|
||||
self.group.id.clone(),
|
||||
vec![InsertedRowPB {
|
||||
row_meta: row_detail.into(),
|
||||
index: Some(index as i32),
|
||||
is_new: true,
|
||||
}],
|
||||
)]
|
||||
}
|
||||
|
||||
fn did_update_group_row(
|
||||
&mut self,
|
||||
_old_row_detail: &Option<RowDetail>,
|
||||
@ -76,14 +100,15 @@ impl GroupControllerOperation for DefaultGroupController {
|
||||
})
|
||||
}
|
||||
|
||||
fn did_delete_delete_row(
|
||||
&mut self,
|
||||
_row: &Row,
|
||||
_field: &Field,
|
||||
) -> FlowyResult<DidMoveGroupRowResult> {
|
||||
fn did_delete_row(&mut self, row: &Row) -> FlowyResult<DidMoveGroupRowResult> {
|
||||
let mut changeset = GroupRowsNotificationPB::new(self.group.id.clone());
|
||||
if self.group.contains_row(&row.id) {
|
||||
self.group.remove_row(&row.id);
|
||||
changeset.deleted_rows.push(row.id.clone().into_inner());
|
||||
}
|
||||
Ok(DidMoveGroupRowResult {
|
||||
deleted_group: None,
|
||||
row_changesets: vec![],
|
||||
row_changesets: vec![changeset],
|
||||
})
|
||||
}
|
||||
|
||||
@ -115,6 +140,4 @@ impl GroupController for DefaultGroupController {
|
||||
}
|
||||
|
||||
fn will_create_row(&mut self, _cells: &mut Cells, _field: &Field, _group_id: &str) {}
|
||||
|
||||
fn did_create_row(&mut self, _row_detail: &RowDetail, _group_id: &str) {}
|
||||
}
|
||||
|
@ -1,9 +1,10 @@
|
||||
use async_trait::async_trait;
|
||||
use collab_database::fields::{Field, TypeOptionData};
|
||||
use collab_database::rows::{new_cell_builder, Cell, Cells, Row, RowDetail};
|
||||
use flowy_error::FlowyResult;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::entities::{FieldType, GroupRowsNotificationPB};
|
||||
use crate::entities::{FieldType, GroupPB, GroupRowsNotificationPB, InsertedGroupPB};
|
||||
use crate::services::cell::insert_select_option_cell;
|
||||
use crate::services::field::{
|
||||
MultiSelectTypeOption, SelectOption, SelectOptionCellDataParser, SelectTypeOptionSharedAction,
|
||||
@ -13,7 +14,7 @@ use crate::services::group::action::GroupCustomize;
|
||||
use crate::services::group::controller::{BaseGroupController, GroupController};
|
||||
use crate::services::group::{
|
||||
add_or_remove_select_option_row, generate_select_option_groups, make_no_status_group,
|
||||
move_group_row, remove_select_option_row, GeneratedGroups, GroupChangeset, GroupContext,
|
||||
move_group_row, remove_select_option_row, GeneratedGroups, Group, GroupChangeset, GroupContext,
|
||||
GroupOperationInterceptor, GroupsBuilder, MoveGroupRowContext,
|
||||
};
|
||||
|
||||
@ -69,14 +70,14 @@ impl GroupCustomize for MultiSelectGroupController {
|
||||
&mut self,
|
||||
row: &Row,
|
||||
cell_data: &<Self::GroupTypeOption as TypeOption>::CellData,
|
||||
) -> Vec<GroupRowsNotificationPB> {
|
||||
) -> (Option<GroupPB>, Vec<GroupRowsNotificationPB>) {
|
||||
let mut changesets = vec![];
|
||||
self.context.iter_mut_status_groups(|group| {
|
||||
if let Some(changeset) = remove_select_option_row(group, cell_data, row) {
|
||||
changesets.push(changeset);
|
||||
}
|
||||
});
|
||||
changesets
|
||||
(None, changesets)
|
||||
}
|
||||
|
||||
fn move_row(
|
||||
@ -92,6 +93,20 @@ impl GroupCustomize for MultiSelectGroupController {
|
||||
});
|
||||
group_changeset
|
||||
}
|
||||
|
||||
fn generate_new_group(
|
||||
&mut self,
|
||||
name: String,
|
||||
) -> FlowyResult<(Option<TypeOptionData>, Option<InsertedGroupPB>)> {
|
||||
let mut new_type_option = self.type_option.clone();
|
||||
let new_select_option = self.type_option.create_option(&name);
|
||||
new_type_option.insert_option(new_select_option.clone());
|
||||
|
||||
let new_group = Group::new(new_select_option.id, new_select_option.name);
|
||||
let inserted_group_pb = self.context.add_new_group(new_group)?;
|
||||
|
||||
Ok((Some(new_type_option.into()), Some(inserted_group_pb)))
|
||||
}
|
||||
}
|
||||
|
||||
impl GroupController for MultiSelectGroupController {
|
||||
@ -106,12 +121,6 @@ impl GroupController for MultiSelectGroupController {
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn did_create_row(&mut self, row_detail: &RowDetail, group_id: &str) {
|
||||
if let Some(group) = self.context.get_mut_group(group_id) {
|
||||
group.add_row(row_detail.clone())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MultiSelectGroupBuilder;
|
||||
|
@ -1,9 +1,10 @@
|
||||
use async_trait::async_trait;
|
||||
use collab_database::fields::{Field, TypeOptionData};
|
||||
use collab_database::rows::{new_cell_builder, Cell, Cells, Row, RowDetail};
|
||||
use flowy_error::FlowyResult;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::entities::{FieldType, GroupRowsNotificationPB};
|
||||
use crate::entities::{FieldType, GroupPB, GroupRowsNotificationPB, InsertedGroupPB};
|
||||
use crate::services::cell::insert_select_option_cell;
|
||||
use crate::services::field::{
|
||||
SelectOption, SelectOptionCellDataParser, SelectTypeOptionSharedAction, SingleSelectTypeOption,
|
||||
@ -14,8 +15,8 @@ use crate::services::group::controller::{BaseGroupController, GroupController};
|
||||
use crate::services::group::controller_impls::select_option_controller::util::*;
|
||||
use crate::services::group::entities::GroupData;
|
||||
use crate::services::group::{
|
||||
make_no_status_group, GeneratedGroups, GroupChangeset, GroupContext, GroupOperationInterceptor,
|
||||
GroupsBuilder, MoveGroupRowContext,
|
||||
make_no_status_group, GeneratedGroups, Group, GroupChangeset, GroupContext,
|
||||
GroupOperationInterceptor, GroupsBuilder, MoveGroupRowContext,
|
||||
};
|
||||
|
||||
#[derive(Default, Serialize, Deserialize)]
|
||||
@ -70,14 +71,14 @@ impl GroupCustomize for SingleSelectGroupController {
|
||||
&mut self,
|
||||
row: &Row,
|
||||
cell_data: &<Self::GroupTypeOption as TypeOption>::CellData,
|
||||
) -> Vec<GroupRowsNotificationPB> {
|
||||
) -> (Option<GroupPB>, Vec<GroupRowsNotificationPB>) {
|
||||
let mut changesets = vec![];
|
||||
self.context.iter_mut_status_groups(|group| {
|
||||
if let Some(changeset) = remove_select_option_row(group, cell_data, row) {
|
||||
changesets.push(changeset);
|
||||
}
|
||||
});
|
||||
changesets
|
||||
(None, changesets)
|
||||
}
|
||||
|
||||
fn move_row(
|
||||
@ -93,6 +94,23 @@ impl GroupCustomize for SingleSelectGroupController {
|
||||
});
|
||||
group_changeset
|
||||
}
|
||||
|
||||
fn generate_new_group(
|
||||
&mut self,
|
||||
name: String,
|
||||
) -> FlowyResult<(Option<TypeOptionData>, Option<InsertedGroupPB>)> {
|
||||
let mut new_type_option = self.type_option.clone();
|
||||
let new_select_option = self.type_option.create_option(&name);
|
||||
new_type_option.insert_option_at_index(
|
||||
new_select_option.clone(),
|
||||
Some(new_type_option.options.len()),
|
||||
);
|
||||
|
||||
let new_group = Group::new(new_select_option.id, new_select_option.name);
|
||||
let inserted_group_pb = self.context.add_new_group(new_group)?;
|
||||
|
||||
Ok((Some(new_type_option.into()), Some(inserted_group_pb)))
|
||||
}
|
||||
}
|
||||
|
||||
impl GroupController for SingleSelectGroupController {
|
||||
@ -108,12 +126,6 @@ impl GroupController for SingleSelectGroupController {
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn did_create_row(&mut self, row_detail: &RowDetail, group_id: &str) {
|
||||
if let Some(group) = self.context.get_mut_group(group_id) {
|
||||
group.add_row(row_detail.clone())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SingleSelectGroupBuilder();
|
||||
|
@ -185,6 +185,7 @@ pub fn make_inserted_cell(group_id: &str, field: &Field) -> Option<Cell> {
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generate_select_option_groups(
|
||||
_field_id: &str,
|
||||
options: &[SelectOption],
|
||||
|
@ -128,8 +128,8 @@ impl GroupCustomize for URLGroupController {
|
||||
fn delete_row(
|
||||
&mut self,
|
||||
row: &Row,
|
||||
_cell_data: &<Self::GroupTypeOption as TypeOption>::CellData,
|
||||
) -> Vec<GroupRowsNotificationPB> {
|
||||
cell_data: &<Self::GroupTypeOption as TypeOption>::CellData,
|
||||
) -> (Option<GroupPB>, Vec<GroupRowsNotificationPB>) {
|
||||
let mut changesets = vec![];
|
||||
self.context.iter_mut_groups(|group| {
|
||||
let mut changeset = GroupRowsNotificationPB::new(group.id.clone());
|
||||
@ -142,7 +142,18 @@ impl GroupCustomize for URLGroupController {
|
||||
changesets.push(changeset);
|
||||
}
|
||||
});
|
||||
changesets
|
||||
|
||||
let deleted_group = match self.context.get_group(&cell_data.data) {
|
||||
Some((_, group)) if group.rows.len() == 1 => Some(group.clone()),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
let deleted_group = deleted_group.map(|group| {
|
||||
let _ = self.context.delete_group(&group.id);
|
||||
group.into()
|
||||
});
|
||||
|
||||
(deleted_group, changesets)
|
||||
}
|
||||
|
||||
fn move_row(
|
||||
@ -190,12 +201,6 @@ impl GroupController for URLGroupController {
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn did_create_row(&mut self, row_detail: &RowDetail, group_id: &str) {
|
||||
if let Some(group) = self.context.get_mut_group(group_id) {
|
||||
group.add_row(row_detail.clone())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct URLGroupGenerator();
|
||||
|
Reference in New Issue
Block a user