mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
fix: edit no status card
This commit is contained in:
parent
d2933bdb04
commit
3511737bb3
@ -54,7 +54,7 @@ impl GridBlockManager {
|
||||
|
||||
pub(crate) async fn get_editor_from_row_id(&self, row_id: &str) -> FlowyResult<Arc<GridBlockRevisionEditor>> {
|
||||
let block_id = self.persistence.get_block_id(row_id)?;
|
||||
Ok(self.get_block_editor(&block_id).await?)
|
||||
self.get_block_editor(&block_id).await
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "trace", skip(self, start_row_id), err)]
|
||||
|
@ -30,8 +30,7 @@ impl GridViewRowDelegate for Arc<GridBlockManager> {
|
||||
let blocks = block_manager.get_block_snapshots(None).await.unwrap();
|
||||
blocks
|
||||
.into_iter()
|
||||
.map(|block| block.row_revs)
|
||||
.flatten()
|
||||
.flat_map(|block| block.row_revs)
|
||||
.collect::<Vec<Arc<RowRevision>>>()
|
||||
})
|
||||
}
|
||||
|
@ -113,11 +113,15 @@ impl AnyCellData {
|
||||
/// * Use URLCellData to parse the data when the FieldType is URL.
|
||||
/// * Use String to parse the data when the FieldType is RichText, Number, or Checkbox.
|
||||
/// * Check out the implementation of CellDataOperation trait for more information.
|
||||
#[derive(Default)]
|
||||
#[derive(Default, Debug)]
|
||||
pub struct CellBytes(pub Bytes);
|
||||
|
||||
pub trait CellDataIsEmpty {
|
||||
fn is_empty(&self) -> bool;
|
||||
}
|
||||
|
||||
pub trait CellBytesParser {
|
||||
type Object;
|
||||
type Object: CellDataIsEmpty;
|
||||
fn parser(bytes: &Bytes) -> FlowyResult<Self::Object>;
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::services::cell::{CellBytesParser, FromCellString};
|
||||
use crate::services::cell::{CellBytesParser, CellDataIsEmpty, FromCellString};
|
||||
use bytes::Bytes;
|
||||
use flowy_error::{FlowyError, FlowyResult};
|
||||
use std::str::FromStr;
|
||||
@ -61,6 +61,13 @@ impl ToString for CheckboxCellData {
|
||||
self.0.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl CellDataIsEmpty for CheckboxCellData {
|
||||
fn is_empty(&self) -> bool {
|
||||
self.0.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CheckboxCellDataParser();
|
||||
impl CellBytesParser for CheckboxCellDataParser {
|
||||
type Object = CheckboxCellData;
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::entities::CellChangesetPB;
|
||||
use crate::entities::{GridCellIdPB, GridCellIdParams};
|
||||
use crate::services::cell::{CellBytesParser, FromCellChangeset, FromCellString};
|
||||
use crate::services::cell::{CellBytesParser, CellDataIsEmpty, FromCellChangeset, FromCellString};
|
||||
use bytes::Bytes;
|
||||
|
||||
use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
|
||||
@ -200,6 +200,12 @@ impl std::default::Default for TimeFormat {
|
||||
}
|
||||
}
|
||||
|
||||
impl CellDataIsEmpty for DateCellDataPB {
|
||||
fn is_empty(&self) -> bool {
|
||||
self.date.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DateCellDataParser();
|
||||
impl CellBytesParser for DateCellDataParser {
|
||||
type Object = DateCellDataPB;
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::services::cell::{CellBytesCustomParser, CellBytesParser};
|
||||
use crate::services::cell::{CellBytesCustomParser, CellBytesParser, CellDataIsEmpty};
|
||||
use crate::services::field::number_currency::Currency;
|
||||
use crate::services::field::{strip_currency_symbol, NumberFormat, STRIP_SYMBOL};
|
||||
use bytes::Bytes;
|
||||
@ -93,6 +93,12 @@ impl ToString for NumberCellData {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CellDataIsEmpty for NumberCellData {
|
||||
fn is_empty(&self) -> bool {
|
||||
self.decimal.is_none()
|
||||
}
|
||||
}
|
||||
pub struct NumberCellDataParser();
|
||||
impl CellBytesParser for NumberCellDataParser {
|
||||
type Object = NumberCellData;
|
||||
|
@ -117,12 +117,12 @@ impl TypeOptionBuilder for MultiSelectTypeOptionBuilder {
|
||||
match field_type {
|
||||
FieldType::Checkbox => {
|
||||
//Add Yes and No options if it's not exist.
|
||||
if self.0.options.iter().find(|option| option.name == CHECK).is_none() {
|
||||
if !self.0.options.iter().any(|option| option.name == CHECK) {
|
||||
let check_option = SelectOptionPB::with_color(CHECK, SelectOptionColorPB::Green);
|
||||
self.0.options.push(check_option);
|
||||
}
|
||||
|
||||
if self.0.options.iter().find(|option| option.name == UNCHECK).is_none() {
|
||||
if !self.0.options.iter().any(|option| option.name == UNCHECK) {
|
||||
let uncheck_option = SelectOptionPB::with_color(UNCHECK, SelectOptionColorPB::Yellow);
|
||||
self.0.options.push(uncheck_option);
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
use crate::entities::{CellChangesetPB, FieldType, GridCellIdPB, GridCellIdParams};
|
||||
use crate::services::cell::{CellBytes, CellBytesParser, CellData, CellDisplayable, FromCellChangeset, FromCellString};
|
||||
use crate::services::cell::{
|
||||
CellBytes, CellBytesParser, CellData, CellDataIsEmpty, CellDisplayable, FromCellChangeset, FromCellString,
|
||||
};
|
||||
use crate::services::field::{MultiSelectTypeOptionPB, SingleSelectTypeOptionPB};
|
||||
use bytes::Bytes;
|
||||
use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
|
||||
@ -233,7 +235,7 @@ impl ToString for SelectOptionIds {
|
||||
impl std::convert::From<Option<String>> for SelectOptionIds {
|
||||
fn from(s: Option<String>) -> Self {
|
||||
match s {
|
||||
None => Self { 0: vec![] },
|
||||
None => Self(vec![]),
|
||||
Some(s) => Self::from(s),
|
||||
}
|
||||
}
|
||||
@ -252,6 +254,13 @@ impl std::ops::DerefMut for SelectOptionIds {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl CellDataIsEmpty for SelectOptionIds {
|
||||
fn is_empty(&self) -> bool {
|
||||
self.0.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SelectOptionIdsParser();
|
||||
impl CellBytesParser for SelectOptionIdsParser {
|
||||
type Object = SelectOptionIds;
|
||||
@ -263,6 +272,12 @@ impl CellBytesParser for SelectOptionIdsParser {
|
||||
}
|
||||
}
|
||||
|
||||
impl CellDataIsEmpty for SelectOptionCellDataPB {
|
||||
fn is_empty(&self) -> bool {
|
||||
self.select_options.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SelectOptionCellDataParser();
|
||||
impl CellBytesParser for SelectOptionCellDataParser {
|
||||
type Object = SelectOptionCellDataPB;
|
||||
|
@ -61,7 +61,6 @@ impl CellDataOperation<SelectOptionIds, SelectOptionCellChangeset> for SingleSel
|
||||
_cell_rev: Option<CellRevision>,
|
||||
) -> Result<String, FlowyError> {
|
||||
let content_changeset = changeset.try_into_inner()?;
|
||||
let new_cell_data: String;
|
||||
|
||||
let mut insert_option_ids = content_changeset
|
||||
.insert_option_ids
|
||||
@ -73,14 +72,12 @@ impl CellDataOperation<SelectOptionIds, SelectOptionCellChangeset> for SingleSel
|
||||
// Sometimes, the insert_option_ids may contain list of option ids. For example,
|
||||
// copy/paste a ids string.
|
||||
if insert_option_ids.is_empty() {
|
||||
new_cell_data = "".to_string()
|
||||
Ok("".to_string())
|
||||
} else {
|
||||
// Just take the first select option
|
||||
let _ = insert_option_ids.drain(1..);
|
||||
new_cell_data = insert_option_ids.pop().unwrap();
|
||||
Ok(insert_option_ids.pop().unwrap())
|
||||
}
|
||||
|
||||
Ok(new_cell_data)
|
||||
}
|
||||
}
|
||||
|
||||
@ -109,12 +106,12 @@ impl TypeOptionBuilder for SingleSelectTypeOptionBuilder {
|
||||
match field_type {
|
||||
FieldType::Checkbox => {
|
||||
//add Yes and No options if it's not exist.
|
||||
if self.0.options.iter().find(|option| option.name == CHECK).is_none() {
|
||||
if !self.0.options.iter().any(|option| option.name == CHECK) {
|
||||
let check_option = SelectOptionPB::with_color(CHECK, SelectOptionColorPB::Green);
|
||||
self.0.options.push(check_option);
|
||||
}
|
||||
|
||||
if self.0.options.iter().find(|option| option.name == UNCHECK).is_none() {
|
||||
if !self.0.options.iter().any(|option| option.name == UNCHECK) {
|
||||
let uncheck_option = SelectOptionPB::with_color(UNCHECK, SelectOptionColorPB::Yellow);
|
||||
self.0.options.push(uncheck_option);
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
use crate::entities::FieldType;
|
||||
use crate::impl_type_option;
|
||||
use crate::services::cell::{
|
||||
decode_cell_data_to_string, CellBytes, CellBytesParser, CellData, CellDataChangeset, CellDataOperation,
|
||||
CellDisplayable, FromCellString,
|
||||
decode_cell_data_to_string, CellBytes, CellBytesParser, CellData, CellDataChangeset, CellDataIsEmpty,
|
||||
CellDataOperation, CellDisplayable, FromCellString,
|
||||
};
|
||||
use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder};
|
||||
use bytes::Bytes;
|
||||
@ -125,6 +125,12 @@ impl ToString for TextCellData {
|
||||
}
|
||||
}
|
||||
|
||||
impl CellDataIsEmpty for TextCellData {
|
||||
fn is_empty(&self) -> bool {
|
||||
self.0.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TextCellDataParser();
|
||||
impl CellBytesParser for TextCellDataParser {
|
||||
type Object = TextCellData;
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::services::cell::{CellBytesParser, FromCellString};
|
||||
use crate::services::cell::{CellBytesParser, CellDataIsEmpty, FromCellString};
|
||||
use bytes::Bytes;
|
||||
use flowy_derive::ProtoBuf;
|
||||
use flowy_error::{internal_error, FlowyResult};
|
||||
@ -26,6 +26,12 @@ impl URLCellDataPB {
|
||||
}
|
||||
}
|
||||
|
||||
impl CellDataIsEmpty for URLCellDataPB {
|
||||
fn is_empty(&self) -> bool {
|
||||
self.content.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct URLCellDataParser();
|
||||
impl CellBytesParser for URLCellDataParser {
|
||||
type Object = URLCellDataPB;
|
||||
|
@ -123,8 +123,8 @@ impl GridViewRevisionEditor {
|
||||
})
|
||||
.await;
|
||||
|
||||
tracing::trace!("Delete row in view changeset: {:?}", changesets);
|
||||
if let Some(changesets) = changesets {
|
||||
tracing::trace!("{:?}", changesets);
|
||||
for changeset in changesets {
|
||||
self.notify_did_update_group(changeset).await;
|
||||
}
|
||||
@ -539,11 +539,10 @@ pub fn make_grid_setting(view_pad: &GridViewRevisionPad, field_revs: &[Arc<Field
|
||||
.map(|filters_by_field_id| {
|
||||
filters_by_field_id
|
||||
.into_iter()
|
||||
.map(|(_, v)| {
|
||||
.flat_map(|(_, v)| {
|
||||
let repeated_filter: RepeatedGridFilterConfigurationPB = v.into();
|
||||
repeated_filter.items
|
||||
})
|
||||
.flatten()
|
||||
.collect::<Vec<GridFilterConfigurationPB>>()
|
||||
})
|
||||
.unwrap_or_default();
|
||||
@ -553,11 +552,10 @@ pub fn make_grid_setting(view_pad: &GridViewRevisionPad, field_revs: &[Arc<Field
|
||||
.map(|groups_by_field_id| {
|
||||
groups_by_field_id
|
||||
.into_iter()
|
||||
.map(|(_, v)| {
|
||||
.flat_map(|(_, v)| {
|
||||
let repeated_group: RepeatedGridGroupConfigurationPB = v.into();
|
||||
repeated_group.items
|
||||
})
|
||||
.flatten()
|
||||
.collect::<Vec<GridGroupConfigurationPB>>()
|
||||
})
|
||||
.unwrap_or_default();
|
||||
|
@ -1,4 +1,5 @@
|
||||
use crate::entities::{GroupChangesetPB, GroupViewChangesetPB};
|
||||
use crate::services::cell::CellDataIsEmpty;
|
||||
use crate::services::group::controller::MoveGroupRowContext;
|
||||
use crate::services::group::Group;
|
||||
use flowy_error::FlowyResult;
|
||||
@ -10,7 +11,7 @@ use std::sync::Arc;
|
||||
/// For example, the `CheckboxGroupController` implements this trait to provide custom behavior.
|
||||
///
|
||||
pub trait GroupControllerCustomActions: Send + Sync {
|
||||
type CellDataType;
|
||||
type CellDataType: CellDataIsEmpty;
|
||||
/// Returns the a value of the cell, default value is None
|
||||
///
|
||||
/// Determine which group the row is placed in based on the data of the cell. If the cell data
|
||||
@ -20,22 +21,20 @@ pub trait GroupControllerCustomActions: Send + Sync {
|
||||
None
|
||||
}
|
||||
|
||||
/// Returns a bool value to determine the `No status` group should show or hide.
|
||||
///
|
||||
fn use_no_status_group(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
/// Returns a bool value to determine whether the group should contain this cell or not.
|
||||
fn can_group(&self, content: &str, cell_data: &Self::CellDataType) -> bool;
|
||||
|
||||
/// Adding a new row to the group if the cell data match the group filter.
|
||||
/// Adds or removes a row if the cell data match the group filter.
|
||||
/// It gets called after editing the cell or row
|
||||
///
|
||||
fn add_row_if_match(&mut self, row_rev: &RowRevision, cell_data: &Self::CellDataType) -> Vec<GroupChangesetPB>;
|
||||
fn add_or_remove_row_in_groups_if_match(
|
||||
&mut self,
|
||||
row_rev: &RowRevision,
|
||||
cell_data: &Self::CellDataType,
|
||||
) -> Vec<GroupChangesetPB>;
|
||||
|
||||
///
|
||||
fn remove_row_if_match(&mut self, row_rev: &RowRevision, cell_data: &Self::CellDataType) -> Vec<GroupChangesetPB>;
|
||||
/// Deletes the row from the group
|
||||
fn delete_row(&mut self, row_rev: &RowRevision, cell_data: &Self::CellDataType) -> Vec<GroupChangesetPB>;
|
||||
|
||||
/// Move row from one group to another
|
||||
fn move_row(&mut self, cell_data: &Self::CellDataType, context: MoveGroupRowContext) -> Vec<GroupChangesetPB>;
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::entities::{GroupPB, GroupViewChangesetPB};
|
||||
use crate::services::group::{default_group_configuration, make_no_status_group, GeneratedGroupConfig, Group};
|
||||
use crate::services::group::{default_group_configuration, GeneratedGroupContext, Group};
|
||||
use flowy_error::{FlowyError, FlowyResult};
|
||||
use flowy_grid_data_model::revision::{
|
||||
FieldRevision, FieldTypeRevision, GroupConfigurationContentSerde, GroupConfigurationRevision, GroupRevision,
|
||||
@ -118,8 +118,16 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// Iterate mut the groups. The default group will be the last one that get mutated.
|
||||
pub(crate) fn iter_mut_all_groups(&mut self, mut each: impl FnMut(&mut Group)) {
|
||||
/// Iterate mut the groups without `No status` group
|
||||
pub(crate) fn iter_mut_status_groups(&mut self, mut each: impl FnMut(&mut Group)) {
|
||||
self.groups_map.iter_mut().for_each(|(_, group)| {
|
||||
if group.id != self.field_rev.id {
|
||||
each(group);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub(crate) fn iter_mut_groups(&mut self, mut each: impl FnMut(&mut Group)) {
|
||||
self.groups_map.iter_mut().for_each(|(_, group)| {
|
||||
each(group);
|
||||
});
|
||||
@ -172,14 +180,19 @@ where
|
||||
/// [GroupConfigurationRevision] as old groups. The old groups and the new groups will be merged
|
||||
/// while keeping the order of the old groups.
|
||||
///
|
||||
#[tracing::instrument(level = "trace", skip(self, generated_group_configs), err)]
|
||||
#[tracing::instrument(level = "trace", skip(self, generated_group_context), err)]
|
||||
pub(crate) fn init_groups(
|
||||
&mut self,
|
||||
generated_group_configs: Vec<GeneratedGroupConfig>,
|
||||
generated_group_context: GeneratedGroupContext,
|
||||
) -> FlowyResult<Option<GroupViewChangesetPB>> {
|
||||
let GeneratedGroupContext {
|
||||
no_status_group,
|
||||
group_configs,
|
||||
} = generated_group_context;
|
||||
|
||||
let mut new_groups = vec![];
|
||||
let mut filter_content_map = HashMap::new();
|
||||
generated_group_configs.into_iter().for_each(|generate_group| {
|
||||
group_configs.into_iter().for_each(|generate_group| {
|
||||
filter_content_map.insert(generate_group.group_rev.id.clone(), generate_group.filter_content);
|
||||
new_groups.push(generate_group.group_rev);
|
||||
});
|
||||
@ -190,12 +203,9 @@ where
|
||||
old_groups.clear();
|
||||
}
|
||||
|
||||
// When grouping by a new field, there is no `No status` group. So it needs
|
||||
// to insert a `No status` group at index 0
|
||||
// The `No status` group index is initialized to 0
|
||||
//
|
||||
if !old_groups.iter().any(|group| group.id == self.field_rev.id) {
|
||||
old_groups.insert(0, make_no_status_group(&self.field_rev));
|
||||
if let Some(no_status_group) = no_status_group {
|
||||
old_groups.insert(0, no_status_group);
|
||||
}
|
||||
|
||||
// The `all_group_revs` is the combination of the new groups and old groups
|
||||
@ -236,9 +246,9 @@ where
|
||||
Some(pos) => {
|
||||
let mut old_group = configuration.groups.get_mut(pos).unwrap();
|
||||
// Take the old group setting
|
||||
group_rev.update_with_other(&old_group);
|
||||
group_rev.update_with_other(old_group);
|
||||
if !is_changed {
|
||||
is_changed = is_group_changed(group_rev, &old_group);
|
||||
is_changed = is_group_changed(group_rev, old_group);
|
||||
}
|
||||
// Consider the the name of the `group_rev` as the newest.
|
||||
old_group.name = group_rev.name.clone();
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::entities::{GroupChangesetPB, GroupViewChangesetPB, InsertedRowPB, RowPB};
|
||||
use crate::services::cell::{decode_any_cell_data, CellBytesParser};
|
||||
use crate::services::cell::{decode_any_cell_data, CellBytesParser, CellDataIsEmpty};
|
||||
use crate::services::group::action::{GroupControllerCustomActions, GroupControllerSharedActions};
|
||||
use crate::services::group::configuration::GroupContext;
|
||||
use crate::services::group::entities::Group;
|
||||
@ -29,10 +29,15 @@ pub trait GroupGenerator {
|
||||
type TypeOptionType;
|
||||
|
||||
fn generate_groups(
|
||||
field_id: &str,
|
||||
field_rev: &FieldRevision,
|
||||
group_ctx: &Self::Context,
|
||||
type_option: &Option<Self::TypeOptionType>,
|
||||
) -> Vec<GeneratedGroupConfig>;
|
||||
) -> GeneratedGroupContext;
|
||||
}
|
||||
|
||||
pub struct GeneratedGroupContext {
|
||||
pub no_status_group: Option<GroupRevision>,
|
||||
pub group_configs: Vec<GeneratedGroupConfig>,
|
||||
}
|
||||
|
||||
pub struct GeneratedGroupConfig {
|
||||
@ -67,8 +72,8 @@ where
|
||||
{
|
||||
pub async fn new(field_rev: &Arc<FieldRevision>, mut configuration: GroupContext<C>) -> FlowyResult<Self> {
|
||||
let type_option = field_rev.get_type_option::<T>(field_rev.ty);
|
||||
let groups = G::generate_groups(&field_rev.id, &configuration, &type_option);
|
||||
let _ = configuration.init_groups(groups)?;
|
||||
let generated_group_context = G::generate_groups(field_rev, &configuration, &type_option);
|
||||
let _ = configuration.init_groups(generated_group_context)?;
|
||||
|
||||
Ok(Self {
|
||||
field_id: field_rev.id.clone(),
|
||||
@ -161,16 +166,7 @@ where
|
||||
}
|
||||
|
||||
fn groups(&self) -> Vec<Group> {
|
||||
if self.use_no_status_group() {
|
||||
self.group_ctx.groups().into_iter().cloned().collect()
|
||||
} else {
|
||||
self.group_ctx
|
||||
.groups()
|
||||
.into_iter()
|
||||
.filter(|group| group.id != self.field_id)
|
||||
.cloned()
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
self.group_ctx.groups().into_iter().cloned().collect()
|
||||
}
|
||||
|
||||
fn get_group(&self, group_id: &str) -> Option<(usize, Group)> {
|
||||
@ -230,13 +226,14 @@ where
|
||||
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).1;
|
||||
let cell_data = cell_bytes.parser::<P>()?;
|
||||
let mut changesets = self.add_row_if_match(row_rev, &cell_data);
|
||||
// if let Some(default_group_changeset) = self.update_default_group(row_rev, &changesets) {
|
||||
// tracing::trace!("default_group_changeset: {}", default_group_changeset);
|
||||
// if !default_group_changeset.is_empty() {
|
||||
// changesets.push(default_group_changeset);
|
||||
// }
|
||||
// }
|
||||
let mut changesets = self.add_or_remove_row_in_groups_if_match(row_rev, &cell_data);
|
||||
|
||||
if let Some(default_group_changeset) = self.update_default_group(row_rev, &changesets) {
|
||||
tracing::trace!("default_group_changeset: {}", default_group_changeset);
|
||||
if !default_group_changeset.is_empty() {
|
||||
changesets.push(default_group_changeset);
|
||||
}
|
||||
}
|
||||
Ok(changesets)
|
||||
} else {
|
||||
Ok(vec![])
|
||||
@ -248,18 +245,30 @@ where
|
||||
row_rev: &RowRevision,
|
||||
field_rev: &FieldRevision,
|
||||
) -> FlowyResult<Vec<GroupChangesetPB>> {
|
||||
// if the cell_rev is none, then the row must be crated from the default group.
|
||||
// if the cell_rev is none, then the row must in the default group.
|
||||
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).1;
|
||||
let cell_data = cell_bytes.parser::<P>()?;
|
||||
Ok(self.remove_row_if_match(row_rev, &cell_data))
|
||||
} else if let Some(group) = self.group_ctx.get_no_status_group() {
|
||||
Ok(vec![GroupChangesetPB::delete(
|
||||
group.id.clone(),
|
||||
vec![row_rev.id.clone()],
|
||||
)])
|
||||
} else {
|
||||
Ok(vec![])
|
||||
if !cell_data.is_empty() {
|
||||
tracing::error!("did_delete_delete_row {:?}", cell_rev.data);
|
||||
return Ok(self.delete_row(row_rev, &cell_data));
|
||||
}
|
||||
}
|
||||
|
||||
match self.group_ctx.get_no_status_group() {
|
||||
None => {
|
||||
tracing::error!("Unexpected None value. It should have the no status group");
|
||||
Ok(vec![])
|
||||
}
|
||||
Some(no_status_group) => {
|
||||
if !no_status_group.contains_row(&row_rev.id) {
|
||||
tracing::error!("The row: {} should be in the no status group", row_rev.id);
|
||||
}
|
||||
Ok(vec![GroupChangesetPB::delete(
|
||||
no_status_group.id.clone(),
|
||||
vec![row_rev.id.clone()],
|
||||
)])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,7 +7,7 @@ use crate::services::group::controller::{
|
||||
};
|
||||
|
||||
use crate::services::cell::insert_checkbox_cell;
|
||||
use crate::services::group::{move_group_row, GeneratedGroupConfig};
|
||||
use crate::services::group::{move_group_row, GeneratedGroupConfig, GeneratedGroupContext};
|
||||
use flowy_grid_data_model::revision::{
|
||||
CellRevision, CheckboxGroupConfigurationRevision, FieldRevision, GroupRevision, RowRevision,
|
||||
};
|
||||
@ -27,10 +27,6 @@ impl GroupControllerCustomActions for CheckboxGroupController {
|
||||
Some(CellRevision::new(UNCHECK.to_string()))
|
||||
}
|
||||
|
||||
fn use_no_status_group(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn can_group(&self, content: &str, cell_data: &Self::CellDataType) -> bool {
|
||||
if cell_data.is_check() {
|
||||
content == CHECK
|
||||
@ -39,9 +35,13 @@ impl GroupControllerCustomActions for CheckboxGroupController {
|
||||
}
|
||||
}
|
||||
|
||||
fn add_row_if_match(&mut self, row_rev: &RowRevision, cell_data: &Self::CellDataType) -> Vec<GroupChangesetPB> {
|
||||
fn add_or_remove_row_in_groups_if_match(
|
||||
&mut self,
|
||||
row_rev: &RowRevision,
|
||||
cell_data: &Self::CellDataType,
|
||||
) -> Vec<GroupChangesetPB> {
|
||||
let mut changesets = vec![];
|
||||
self.group_ctx.iter_mut_all_groups(|group| {
|
||||
self.group_ctx.iter_mut_status_groups(|group| {
|
||||
let mut changeset = GroupChangesetPB::new(group.id.clone());
|
||||
let is_not_contained = !group.contains_row(&row_rev.id);
|
||||
if group.id == CHECK {
|
||||
@ -81,9 +81,9 @@ impl GroupControllerCustomActions for CheckboxGroupController {
|
||||
changesets
|
||||
}
|
||||
|
||||
fn remove_row_if_match(&mut self, row_rev: &RowRevision, _cell_data: &Self::CellDataType) -> Vec<GroupChangesetPB> {
|
||||
fn delete_row(&mut self, row_rev: &RowRevision, _cell_data: &Self::CellDataType) -> Vec<GroupChangesetPB> {
|
||||
let mut changesets = vec![];
|
||||
self.group_ctx.iter_mut_all_groups(|group| {
|
||||
self.group_ctx.iter_mut_groups(|group| {
|
||||
let mut changeset = GroupChangesetPB::new(group.id.clone());
|
||||
if group.contains_row(&row_rev.id) {
|
||||
changeset.deleted_rows.push(row_rev.id.clone());
|
||||
@ -99,7 +99,7 @@ impl GroupControllerCustomActions for CheckboxGroupController {
|
||||
|
||||
fn move_row(&mut self, _cell_data: &Self::CellDataType, mut context: MoveGroupRowContext) -> Vec<GroupChangesetPB> {
|
||||
let mut group_changeset = vec![];
|
||||
self.group_ctx.iter_mut_all_groups(|group| {
|
||||
self.group_ctx.iter_mut_groups(|group| {
|
||||
if let Some(changeset) = move_group_row(group, &mut context) {
|
||||
group_changeset.push(changeset);
|
||||
}
|
||||
@ -133,10 +133,10 @@ impl GroupGenerator for CheckboxGroupGenerator {
|
||||
type TypeOptionType = CheckboxTypeOptionPB;
|
||||
|
||||
fn generate_groups(
|
||||
_field_id: &str,
|
||||
_field_rev: &FieldRevision,
|
||||
_group_ctx: &Self::Context,
|
||||
_type_option: &Option<Self::TypeOptionType>,
|
||||
) -> Vec<GeneratedGroupConfig> {
|
||||
) -> GeneratedGroupContext {
|
||||
let check_group = GeneratedGroupConfig {
|
||||
group_rev: GroupRevision::new(CHECK.to_string(), "".to_string()),
|
||||
filter_content: CHECK.to_string(),
|
||||
@ -146,6 +146,10 @@ impl GroupGenerator for CheckboxGroupGenerator {
|
||||
group_rev: GroupRevision::new(UNCHECK.to_string(), "".to_string()),
|
||||
filter_content: UNCHECK.to_string(),
|
||||
};
|
||||
vec![check_group, uncheck_group]
|
||||
|
||||
GeneratedGroupContext {
|
||||
no_status_group: None,
|
||||
group_configs: vec![check_group, uncheck_group],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
use crate::entities::{GroupChangesetPB, GroupViewChangesetPB, RowPB};
|
||||
use crate::services::group::{Group, GroupController, GroupControllerSharedActions, MoveGroupRowContext};
|
||||
use crate::services::group::action::GroupControllerSharedActions;
|
||||
use crate::services::group::{Group, GroupController, MoveGroupRowContext};
|
||||
use flowy_error::FlowyResult;
|
||||
use flowy_grid_data_model::revision::{FieldRevision, RowRevision};
|
||||
use std::sync::Arc;
|
||||
|
@ -8,7 +8,7 @@ use crate::services::group::controller::{
|
||||
};
|
||||
use crate::services::group::controller_impls::select_option_controller::util::*;
|
||||
|
||||
use crate::services::group::GeneratedGroupConfig;
|
||||
use crate::services::group::{make_no_status_group, GeneratedGroupContext};
|
||||
use flowy_grid_data_model::revision::{FieldRevision, RowRevision, SelectOptionGroupConfigurationRevision};
|
||||
|
||||
// MultiSelect
|
||||
@ -26,19 +26,23 @@ impl GroupControllerCustomActions for MultiSelectGroupController {
|
||||
cell_data.select_options.iter().any(|option| option.id == content)
|
||||
}
|
||||
|
||||
fn add_row_if_match(&mut self, row_rev: &RowRevision, cell_data: &Self::CellDataType) -> Vec<GroupChangesetPB> {
|
||||
fn add_or_remove_row_in_groups_if_match(
|
||||
&mut self,
|
||||
row_rev: &RowRevision,
|
||||
cell_data: &Self::CellDataType,
|
||||
) -> Vec<GroupChangesetPB> {
|
||||
let mut changesets = vec![];
|
||||
self.group_ctx.iter_mut_all_groups(|group| {
|
||||
if let Some(changeset) = add_select_option_row(group, cell_data, row_rev) {
|
||||
self.group_ctx.iter_mut_status_groups(|group| {
|
||||
if let Some(changeset) = add_or_remove_select_option_row(group, cell_data, row_rev) {
|
||||
changesets.push(changeset);
|
||||
}
|
||||
});
|
||||
changesets
|
||||
}
|
||||
|
||||
fn remove_row_if_match(&mut self, row_rev: &RowRevision, cell_data: &Self::CellDataType) -> Vec<GroupChangesetPB> {
|
||||
fn delete_row(&mut self, row_rev: &RowRevision, cell_data: &Self::CellDataType) -> Vec<GroupChangesetPB> {
|
||||
let mut changesets = vec![];
|
||||
self.group_ctx.iter_mut_all_groups(|group| {
|
||||
self.group_ctx.iter_mut_status_groups(|group| {
|
||||
if let Some(changeset) = remove_select_option_row(group, cell_data, row_rev) {
|
||||
changesets.push(changeset);
|
||||
}
|
||||
@ -48,7 +52,7 @@ impl GroupControllerCustomActions for MultiSelectGroupController {
|
||||
|
||||
fn move_row(&mut self, _cell_data: &Self::CellDataType, mut context: MoveGroupRowContext) -> Vec<GroupChangesetPB> {
|
||||
let mut group_changeset = vec![];
|
||||
self.group_ctx.iter_mut_all_groups(|group| {
|
||||
self.group_ctx.iter_mut_groups(|group| {
|
||||
if let Some(changeset) = move_group_row(group, &mut context) {
|
||||
group_changeset.push(changeset);
|
||||
}
|
||||
@ -79,14 +83,20 @@ pub struct MultiSelectGroupGenerator();
|
||||
impl GroupGenerator for MultiSelectGroupGenerator {
|
||||
type Context = SelectOptionGroupContext;
|
||||
type TypeOptionType = MultiSelectTypeOptionPB;
|
||||
|
||||
fn generate_groups(
|
||||
field_id: &str,
|
||||
field_rev: &FieldRevision,
|
||||
group_ctx: &Self::Context,
|
||||
type_option: &Option<Self::TypeOptionType>,
|
||||
) -> Vec<GeneratedGroupConfig> {
|
||||
match type_option {
|
||||
) -> GeneratedGroupContext {
|
||||
let group_configs = match type_option {
|
||||
None => vec![],
|
||||
Some(type_option) => generate_select_option_groups(field_id, group_ctx, &type_option.options),
|
||||
Some(type_option) => generate_select_option_groups(&field_rev.id, group_ctx, &type_option.options),
|
||||
};
|
||||
|
||||
GeneratedGroupContext {
|
||||
no_status_group: Some(make_no_status_group(field_rev)),
|
||||
group_configs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ use crate::services::group::controller::{
|
||||
use crate::services::group::controller_impls::select_option_controller::util::*;
|
||||
use crate::services::group::entities::Group;
|
||||
|
||||
use crate::services::group::GeneratedGroupConfig;
|
||||
use crate::services::group::{make_no_status_group, GeneratedGroupContext};
|
||||
use flowy_grid_data_model::revision::{FieldRevision, RowRevision, SelectOptionGroupConfigurationRevision};
|
||||
|
||||
// SingleSelect
|
||||
@ -26,19 +26,23 @@ impl GroupControllerCustomActions for SingleSelectGroupController {
|
||||
cell_data.select_options.iter().any(|option| option.id == content)
|
||||
}
|
||||
|
||||
fn add_row_if_match(&mut self, row_rev: &RowRevision, cell_data: &Self::CellDataType) -> Vec<GroupChangesetPB> {
|
||||
fn add_or_remove_row_in_groups_if_match(
|
||||
&mut self,
|
||||
row_rev: &RowRevision,
|
||||
cell_data: &Self::CellDataType,
|
||||
) -> Vec<GroupChangesetPB> {
|
||||
let mut changesets = vec![];
|
||||
self.group_ctx.iter_mut_all_groups(|group| {
|
||||
if let Some(changeset) = add_select_option_row(group, cell_data, row_rev) {
|
||||
self.group_ctx.iter_mut_status_groups(|group| {
|
||||
if let Some(changeset) = add_or_remove_select_option_row(group, cell_data, row_rev) {
|
||||
changesets.push(changeset);
|
||||
}
|
||||
});
|
||||
changesets
|
||||
}
|
||||
|
||||
fn remove_row_if_match(&mut self, row_rev: &RowRevision, cell_data: &Self::CellDataType) -> Vec<GroupChangesetPB> {
|
||||
fn delete_row(&mut self, row_rev: &RowRevision, cell_data: &Self::CellDataType) -> Vec<GroupChangesetPB> {
|
||||
let mut changesets = vec![];
|
||||
self.group_ctx.iter_mut_all_groups(|group| {
|
||||
self.group_ctx.iter_mut_status_groups(|group| {
|
||||
if let Some(changeset) = remove_select_option_row(group, cell_data, row_rev) {
|
||||
changesets.push(changeset);
|
||||
}
|
||||
@ -48,7 +52,7 @@ impl GroupControllerCustomActions for SingleSelectGroupController {
|
||||
|
||||
fn move_row(&mut self, _cell_data: &Self::CellDataType, mut context: MoveGroupRowContext) -> Vec<GroupChangesetPB> {
|
||||
let mut group_changeset = vec![];
|
||||
self.group_ctx.iter_mut_all_groups(|group| {
|
||||
self.group_ctx.iter_mut_groups(|group| {
|
||||
if let Some(changeset) = move_group_row(group, &mut context) {
|
||||
group_changeset.push(changeset);
|
||||
}
|
||||
@ -80,13 +84,18 @@ impl GroupGenerator for SingleSelectGroupGenerator {
|
||||
type Context = SelectOptionGroupContext;
|
||||
type TypeOptionType = SingleSelectTypeOptionPB;
|
||||
fn generate_groups(
|
||||
field_id: &str,
|
||||
field_rev: &FieldRevision,
|
||||
group_ctx: &Self::Context,
|
||||
type_option: &Option<Self::TypeOptionType>,
|
||||
) -> Vec<GeneratedGroupConfig> {
|
||||
match type_option {
|
||||
) -> GeneratedGroupContext {
|
||||
let group_configs = match type_option {
|
||||
None => vec![],
|
||||
Some(type_option) => generate_select_option_groups(field_id, group_ctx, &type_option.options),
|
||||
Some(type_option) => generate_select_option_groups(&field_rev.id, group_ctx, &type_option.options),
|
||||
};
|
||||
|
||||
GeneratedGroupContext {
|
||||
no_status_group: Some(make_no_status_group(field_rev)),
|
||||
group_configs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ use flowy_grid_data_model::revision::{
|
||||
|
||||
pub type SelectOptionGroupContext = GroupContext<SelectOptionGroupConfigurationRevision>;
|
||||
|
||||
pub fn add_select_option_row(
|
||||
pub fn add_or_remove_select_option_row(
|
||||
group: &mut Group,
|
||||
cell_data: &SelectOptionCellDataPB,
|
||||
row_rev: &RowRevision,
|
||||
|
@ -97,7 +97,7 @@ pub fn default_group_configuration(field_rev: &FieldRevision) -> GroupConfigurat
|
||||
let field_id = field_rev.id.clone();
|
||||
let field_type_rev = field_rev.ty;
|
||||
let field_type: FieldType = field_rev.ty.into();
|
||||
let mut group_configuration_rev = match field_type {
|
||||
match field_type {
|
||||
FieldType::RichText => {
|
||||
GroupConfigurationRevision::new(field_id, field_type_rev, TextGroupConfigurationRevision::default())
|
||||
.unwrap()
|
||||
@ -130,11 +130,7 @@ pub fn default_group_configuration(field_rev: &FieldRevision) -> GroupConfigurat
|
||||
FieldType::URL => {
|
||||
GroupConfigurationRevision::new(field_id, field_type_rev, UrlGroupConfigurationRevision::default()).unwrap()
|
||||
}
|
||||
};
|
||||
|
||||
// Append the no `status` group
|
||||
group_configuration_rev.groups.push(make_no_status_group(field_rev));
|
||||
group_configuration_rev
|
||||
}
|
||||
}
|
||||
|
||||
pub fn make_no_status_group(field_rev: &FieldRevision) -> GroupRevision {
|
||||
|
@ -42,7 +42,7 @@ impl TextEditorCloudService for BlockHttpCloudService {
|
||||
|
||||
pub async fn create_document_request(token: &str, params: CreateTextBlockParams, url: &str) -> Result<(), FlowyError> {
|
||||
let _ = request_builder()
|
||||
.post(&url.to_owned())
|
||||
.post(url)
|
||||
.header(HEADER_TOKEN, token)
|
||||
.protobuf(params)?
|
||||
.send()
|
||||
@ -56,7 +56,7 @@ pub async fn read_document_request(
|
||||
url: &str,
|
||||
) -> Result<Option<DocumentPB>, FlowyError> {
|
||||
let doc = request_builder()
|
||||
.get(&url.to_owned())
|
||||
.get(url)
|
||||
.header(HEADER_TOKEN, token)
|
||||
.protobuf(params)?
|
||||
.option_response()
|
||||
@ -67,7 +67,7 @@ pub async fn read_document_request(
|
||||
|
||||
pub async fn reset_doc_request(token: &str, params: ResetTextBlockParams, url: &str) -> Result<(), FlowyError> {
|
||||
let _ = request_builder()
|
||||
.patch(&url.to_owned())
|
||||
.patch(url)
|
||||
.header(HEADER_TOKEN, token)
|
||||
.protobuf(params)?
|
||||
.send()
|
||||
|
@ -66,35 +66,23 @@ impl UserCloudService for UserHttpCloudService {
|
||||
}
|
||||
|
||||
pub async fn user_sign_up_request(params: SignUpParams, url: &str) -> Result<SignUpResponse, ServerError> {
|
||||
let response = request_builder()
|
||||
.post(&url.to_owned())
|
||||
.protobuf(params)?
|
||||
.response()
|
||||
.await?;
|
||||
let response = request_builder().post(url).protobuf(params)?.response().await?;
|
||||
Ok(response)
|
||||
}
|
||||
|
||||
pub async fn user_sign_in_request(params: SignInParams, url: &str) -> Result<SignInResponse, ServerError> {
|
||||
let response = request_builder()
|
||||
.post(&url.to_owned())
|
||||
.protobuf(params)?
|
||||
.response()
|
||||
.await?;
|
||||
let response = request_builder().post(url).protobuf(params)?.response().await?;
|
||||
Ok(response)
|
||||
}
|
||||
|
||||
pub async fn user_sign_out_request(token: &str, url: &str) -> Result<(), ServerError> {
|
||||
let _ = request_builder()
|
||||
.delete(&url.to_owned())
|
||||
.header(HEADER_TOKEN, token)
|
||||
.send()
|
||||
.await?;
|
||||
let _ = request_builder().delete(url).header(HEADER_TOKEN, token).send().await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn get_user_profile_request(token: &str, url: &str) -> Result<UserProfilePB, ServerError> {
|
||||
let user_profile = request_builder()
|
||||
.get(&url.to_owned())
|
||||
.get(url)
|
||||
.header(HEADER_TOKEN, token)
|
||||
.response()
|
||||
.await?;
|
||||
@ -107,7 +95,7 @@ pub async fn update_user_profile_request(
|
||||
url: &str,
|
||||
) -> Result<(), ServerError> {
|
||||
let _ = request_builder()
|
||||
.patch(&url.to_owned())
|
||||
.patch(url)
|
||||
.header(HEADER_TOKEN, token)
|
||||
.protobuf(params)?
|
||||
.send()
|
||||
|
@ -164,7 +164,7 @@ impl RevisionManager {
|
||||
}
|
||||
|
||||
pub async fn next_sync_revision(&self) -> FlowyResult<Option<Revision>> {
|
||||
Ok(self.rev_persistence.next_sync_revision().await?)
|
||||
self.rev_persistence.next_sync_revision().await
|
||||
}
|
||||
|
||||
pub async fn get_revision(&self, rev_id: i64) -> Option<Revision> {
|
||||
|
@ -130,7 +130,6 @@ impl RevisionPersistence {
|
||||
#[tracing::instrument(level = "trace", skip(self, revisions), err)]
|
||||
pub(crate) async fn reset(&self, revisions: Vec<Revision>) -> FlowyResult<()> {
|
||||
let records = revisions
|
||||
.to_vec()
|
||||
.into_iter()
|
||||
.map(|revision| RevisionRecord {
|
||||
revision,
|
||||
|
@ -114,11 +114,10 @@ fn format_event_message<S: Subscriber + for<'a> tracing_subscriber::registry::Lo
|
||||
let mut message = event_visitor
|
||||
.values()
|
||||
.get("message")
|
||||
.map(|v| match v {
|
||||
.and_then(|v| match v {
|
||||
Value::String(s) => Some(s.as_str()),
|
||||
_ => None,
|
||||
})
|
||||
.flatten()
|
||||
.unwrap_or_else(|| event.metadata().target())
|
||||
.to_owned();
|
||||
|
||||
|
@ -73,4 +73,8 @@ impl CellRevision {
|
||||
pub fn new(data: String) -> Self {
|
||||
Self { data }
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.data.is_empty()
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user