fix: edit no status card

This commit is contained in:
appflowy 2022-10-12 15:41:34 +08:00
parent d2933bdb04
commit 3511737bb3
27 changed files with 221 additions and 149 deletions

View File

@ -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)]

View File

@ -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>>>()
})
}

View File

@ -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>;
}

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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);
}

View File

@ -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;

View File

@ -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);
}

View File

@ -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;

View File

@ -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;

View File

@ -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();

View File

@ -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>;

View File

@ -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();

View File

@ -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()],
)])
}
}
}

View File

@ -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],
}
}
}

View File

@ -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;

View File

@ -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,
}
}
}

View File

@ -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,
}
}
}

View File

@ -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,

View File

@ -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 {

View File

@ -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()

View File

@ -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()

View File

@ -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> {

View File

@ -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,

View File

@ -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();

View File

@ -73,4 +73,8 @@ impl CellRevision {
pub fn new(data: String) -> Self {
Self { data }
}
pub fn is_empty(&self) -> bool {
self.data.is_empty()
}
}