diff --git a/frontend/rust-lib/flowy-grid/src/dart_notification.rs b/frontend/rust-lib/flowy-grid/src/dart_notification.rs index ba5ab22ae1..7aaa0f55f3 100644 --- a/frontend/rust-lib/flowy-grid/src/dart_notification.rs +++ b/frontend/rust-lib/flowy-grid/src/dart_notification.rs @@ -17,6 +17,8 @@ pub enum GridDartNotification { DidGroupByNewField = 62, DidUpdateFilter = 63, DidUpdateSort = 64, + DidReorderRows = 65, + DidReorderSingleRow = 66, DidUpdateGridSetting = 70, } diff --git a/frontend/rust-lib/flowy-grid/src/entities/sort_entities.rs b/frontend/rust-lib/flowy-grid/src/entities/sort_entities.rs index ee74e0d2c9..b65aa79ddd 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/sort_entities.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/sort_entities.rs @@ -4,7 +4,7 @@ use crate::services::sort::SortType; use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; use flowy_error::ErrorCode; -use grid_rev_model::FieldTypeRevision; +use grid_rev_model::{FieldTypeRevision, SortCondition, SortRevision}; #[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)] pub struct GridSortPB { @@ -21,6 +21,17 @@ pub struct GridSortPB { pub condition: GridSortConditionPB, } +impl std::convert::From<&SortRevision> for GridSortPB { + fn from(sort_rev: &SortRevision) -> Self { + Self { + id: sort_rev.id.clone(), + field_id: sort_rev.field_id.clone(), + field_type: sort_rev.field_type.into(), + condition: sort_rev.condition.clone().into(), + } + } +} + #[derive(Debug, Clone, PartialEq, Eq, ProtoBuf_Enum)] #[repr(u8)] pub enum GridSortConditionPB { @@ -32,6 +43,16 @@ impl std::default::Default for GridSortConditionPB { Self::Ascending } } + +impl std::convert::From for GridSortConditionPB { + fn from(condition: SortCondition) -> Self { + match condition { + SortCondition::Ascending => GridSortConditionPB::Ascending, + SortCondition::Descending => GridSortConditionPB::Descending, + } + } +} + #[derive(ProtoBuf, Debug, Default, Clone)] pub struct AlterSortPayloadPB { #[pb(index = 1)] @@ -151,3 +172,30 @@ pub struct SortChangesetNotificationPB { #[pb(index = 4)] pub update_sorts: Vec, } + +impl SortChangesetNotificationPB { + pub fn extend(&mut self, other: SortChangesetNotificationPB) { + self.insert_sorts.extend(other.insert_sorts); + self.delete_sorts.extend(other.delete_sorts); + self.update_sorts.extend(other.update_sorts); + } + + pub fn is_empty(&self) -> bool { + self.insert_sorts.is_empty() && self.delete_sorts.is_empty() && self.update_sorts.is_empty() + } +} + +#[derive(Debug, Default, ProtoBuf)] +pub struct ReorderAllRowsPB { + #[pb(index = 1)] + pub row_orders: Vec, +} + +#[derive(Debug, Default, ProtoBuf)] +pub struct ReorderSingleRowPB { + #[pb(index = 1)] + pub old_index: i32, + + #[pb(index = 2)] + pub new_index: i32, +} diff --git a/frontend/rust-lib/flowy-grid/src/event_handler.rs b/frontend/rust-lib/flowy-grid/src/event_handler.rs index 027e6cae9e..72330e3b40 100644 --- a/frontend/rust-lib/flowy-grid/src/event_handler.rs +++ b/frontend/rust-lib/flowy-grid/src/event_handler.rs @@ -1,6 +1,6 @@ use crate::entities::*; use crate::manager::GridManager; -use crate::services::cell::{FromCellString, TypeCellData}; +use crate::services::cell::{FromCellString, ToCellChangesetString, TypeCellData}; use crate::services::field::{ default_type_option_builder_from_type, select_type_option_from_field_rev, type_option_builder_from_json_str, DateCellChangeset, DateChangesetPB, SelectOptionCellChangeset, SelectOptionCellChangesetPB, @@ -317,7 +317,9 @@ pub(crate) async fn update_cell_handler( ) -> Result<(), FlowyError> { let changeset: CellChangesetPB = data.into_inner(); let editor = manager.get_grid_editor(&changeset.grid_id).await?; - let _ = editor.update_cell_with_changeset(changeset).await?; + let _ = editor + .update_cell_with_changeset(&changeset.row_id, &changeset.field_id, changeset.type_cell_data) + .await?; Ok(()) } @@ -344,16 +346,17 @@ pub(crate) async fn update_select_option_handler( manager: AFPluginState>, ) -> Result<(), FlowyError> { let changeset: SelectOptionChangeset = data.into_inner().try_into()?; - let editor = manager.get_grid_editor(&changeset.cell_identifier.view_id).await?; - + let editor = manager.get_grid_editor(&changeset.cell_path.view_id).await?; + let field_id = changeset.cell_path.field_id.clone(); let _ = editor - .modify_field_rev(&changeset.cell_identifier.field_id, |field_rev| { + .modify_field_rev(&field_id, |field_rev| { let mut type_option = select_type_option_from_field_rev(field_rev)?; - let mut cell_content_changeset = None; + let mut cell_changeset_str = None; let mut is_changed = None; for option in changeset.insert_options { - cell_content_changeset = Some(SelectOptionCellChangeset::from_insert_option_id(&option.id).to_str()); + cell_changeset_str = + Some(SelectOptionCellChangeset::from_insert_option_id(&option.id).to_cell_changeset_str()); type_option.insert_option(option); is_changed = Some(()); } @@ -364,7 +367,8 @@ pub(crate) async fn update_select_option_handler( } for option in changeset.delete_options { - cell_content_changeset = Some(SelectOptionCellChangeset::from_delete_option_id(&option.id).to_str()); + cell_changeset_str = + Some(SelectOptionCellChangeset::from_delete_option_id(&option.id).to_cell_changeset_str()); type_option.delete_option(option); is_changed = Some(()); } @@ -373,16 +377,17 @@ pub(crate) async fn update_select_option_handler( field_rev.insert_type_option(&*type_option); } - if let Some(cell_content_changeset) = cell_content_changeset { - let changeset = CellChangesetPB { - grid_id: changeset.cell_identifier.view_id, - row_id: changeset.cell_identifier.row_id, - field_id: changeset.cell_identifier.field_id.clone(), - type_cell_data: cell_content_changeset, - }; + if let Some(cell_changeset_str) = cell_changeset_str { let cloned_editor = editor.clone(); tokio::spawn(async move { - match cloned_editor.update_cell_with_changeset(changeset).await { + match cloned_editor + .update_cell_with_changeset( + &changeset.cell_path.row_id, + &changeset.cell_path.field_id, + cell_changeset_str, + ) + .await + { Ok(_) => {} Err(e) => tracing::error!("{}", e), } @@ -432,7 +437,18 @@ pub(crate) async fn update_select_option_cell_handler( ) -> Result<(), FlowyError> { let params: SelectOptionCellChangesetParams = data.into_inner().try_into()?; let editor = manager.get_grid_editor(¶ms.cell_identifier.view_id).await?; - let _ = editor.update_cell_with_changeset(params.into()).await?; + let changeset = SelectOptionCellChangeset { + insert_option_ids: params.insert_option_ids, + delete_option_ids: params.delete_option_ids, + }; + + let _ = editor + .update_cell_with_changeset( + ¶ms.cell_identifier.row_id, + ¶ms.cell_identifier.field_id, + changeset, + ) + .await?; Ok(()) } @@ -443,7 +459,7 @@ pub(crate) async fn update_date_cell_handler( ) -> Result<(), FlowyError> { let data = data.into_inner(); let cell_path: CellPathParams = data.cell_path.try_into()?; - let content = DateCellChangeset { + let cell_changeset = DateCellChangeset { date: data.date, time: data.time, is_utc: data.is_utc, @@ -451,7 +467,7 @@ pub(crate) async fn update_date_cell_handler( let editor = manager.get_grid_editor(&cell_path.view_id).await?; let _ = editor - .update_cell(cell_path.view_id, cell_path.row_id, cell_path.field_id, content) + .update_cell(cell_path.row_id, cell_path.field_id, cell_changeset) .await?; Ok(()) } diff --git a/frontend/rust-lib/flowy-grid/src/services/block_editor.rs b/frontend/rust-lib/flowy-grid/src/services/block_editor.rs index 07bc1ffdaf..f07859688a 100644 --- a/frontend/rust-lib/flowy-grid/src/services/block_editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/block_editor.rs @@ -118,8 +118,13 @@ impl GridBlockRevisionEditor { } pub async fn get_row_rev(&self, row_id: &str) -> FlowyResult)>> { - let row_rev = self.pad.read().await.get_row_rev(row_id); - Ok(row_rev) + if self.pad.try_read().is_err() { + tracing::error!("Required GridBlockRevisionPad's read lock failed"); + Ok(None) + } else { + let row_rev = self.pad.read().await.get_row_rev(row_id); + Ok(row_rev) + } } pub async fn get_row_revs(&self, row_ids: Option>>) -> FlowyResult>> diff --git a/frontend/rust-lib/flowy-grid/src/services/cell/cell_operation.rs b/frontend/rust-lib/flowy-grid/src/services/cell/cell_operation.rs index 06340f1b42..b47e82db6b 100644 --- a/frontend/rust-lib/flowy-grid/src/services/cell/cell_operation.rs +++ b/frontend/rust-lib/flowy-grid/src/services/cell/cell_operation.rs @@ -34,7 +34,7 @@ pub trait CellDataDecoder: TypeOption { pub trait CellDataChangeset: TypeOption { /// The changeset is able to parse into the concrete data struct if `TypeOption::CellChangeset` - /// implements the `FromCellChangeset` trait. + /// implements the `FromCellChangesetString` trait. /// For example,the SelectOptionCellChangeset,DateCellChangeset. etc. /// fn apply_changeset( @@ -50,14 +50,14 @@ pub trait CellDataChangeset: TypeOption { /// FieldType::SingleSelect => SelectOptionChangeset /// /// cell_rev: It will be None if the cell does not contain any data. -pub fn apply_cell_data_changeset>( +pub fn apply_cell_data_changeset>( changeset: C, cell_rev: Option, field_rev: T, cell_data_cache: Option, ) -> Result { let field_rev = field_rev.as_ref(); - let changeset = changeset.to_string(); + let changeset = changeset.to_cell_changeset_str(); let field_type: FieldType = field_rev.ty.into(); let type_cell_data = cell_rev.and_then(|cell_rev| match TypeCellData::try_from(cell_rev) { @@ -108,7 +108,8 @@ pub fn decode_type_cell_data + Debu /// /// # Arguments /// -/// * `cell_str`: the opaque cell string +/// * `cell_str`: the opaque cell string that can be decoded by corresponding structs that implement the +/// `FromCellString` trait. /// * `from_field_type`: the original field type of the passed-in cell data. Check the `TypeCellData` /// that is used to save the origin field type of the cell data. /// * `to_field_type`: decode the passed-in cell data to this field type. It will use the to_field_type's @@ -155,7 +156,7 @@ pub fn insert_text_cell(s: String, field_rev: &FieldRevision) -> CellRevision { } pub fn insert_number_cell(num: i64, field_rev: &FieldRevision) -> CellRevision { - let data = apply_cell_data_changeset(num, None, field_rev, None).unwrap(); + let data = apply_cell_data_changeset(num.to_string(), None, field_rev, None).unwrap(); CellRevision::new(data) } @@ -186,14 +187,14 @@ pub fn insert_date_cell(timestamp: i64, field_rev: &FieldRevision) -> CellRevisi } pub fn insert_select_option_cell(option_ids: Vec, field_rev: &FieldRevision) -> CellRevision { - let cell_data = SelectOptionCellChangeset::from_insert_options(option_ids).to_str(); - let data = apply_cell_data_changeset(cell_data, None, field_rev, None).unwrap(); + let changeset = SelectOptionCellChangeset::from_insert_options(option_ids).to_cell_changeset_str(); + let data = apply_cell_data_changeset(changeset, None, field_rev, None).unwrap(); CellRevision::new(data) } pub fn delete_select_option_cell(option_ids: Vec, field_rev: &FieldRevision) -> CellRevision { - let cell_data = SelectOptionCellChangeset::from_delete_options(option_ids).to_str(); - let data = apply_cell_data_changeset(cell_data, None, field_rev, None).unwrap(); + let changeset = SelectOptionCellChangeset::from_delete_options(option_ids).to_cell_changeset_str(); + let data = apply_cell_data_changeset(changeset, None, field_rev, None).unwrap(); CellRevision::new(data) } @@ -252,13 +253,13 @@ impl std::convert::From> for String { /// If the changeset applying to the cell is not String type, it should impl this trait. /// Deserialize the string into cell specific changeset. -pub trait FromCellChangeset { +pub trait FromCellChangesetString { fn from_changeset(changeset: String) -> FlowyResult where Self: Sized; } -impl FromCellChangeset for String { +impl FromCellChangesetString for String { fn from_changeset(changeset: String) -> FlowyResult where Self: Sized, @@ -267,6 +268,16 @@ impl FromCellChangeset for String { } } +pub trait ToCellChangesetString: Debug { + fn to_cell_changeset_str(&self) -> String; +} + +impl ToCellChangesetString for String { + fn to_cell_changeset_str(&self) -> String { + self.clone() + } +} + pub struct AnyCellChangeset(pub Option); impl AnyCellChangeset { @@ -280,7 +291,7 @@ impl AnyCellChangeset { impl std::convert::From for AnyCellChangeset where - T: FromCellChangeset, + T: FromCellChangesetString, { fn from(changeset: C) -> Self { match T::from_changeset(changeset.to_string()) { diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_filter.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_filter.rs index da617eb096..5401d8428c 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_filter.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_filter.rs @@ -1,5 +1,4 @@ use crate::entities::{DateFilterConditionPB, DateFilterPB}; - use chrono::NaiveDateTime; impl DateFilterPB { diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_type_option_entities.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_type_option_entities.rs index 12e42b1237..fe8a0e6537 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_type_option_entities.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_type_option_entities.rs @@ -1,5 +1,7 @@ use crate::entities::CellPathPB; -use crate::services::cell::{CellProtobufBlobParser, DecodedCellData, FromCellChangeset, FromCellString}; +use crate::services::cell::{ + CellProtobufBlobParser, DecodedCellData, FromCellChangesetString, FromCellString, ToCellChangesetString, +}; use bytes::Bytes; use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; use flowy_error::{internal_error, FlowyResult}; @@ -33,7 +35,7 @@ pub struct DateChangesetPB { pub is_utc: bool, } -#[derive(Clone, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct DateCellChangeset { pub date: Option, pub time: Option, @@ -53,7 +55,7 @@ impl DateCellChangeset { } } -impl FromCellChangeset for DateCellChangeset { +impl FromCellChangesetString for DateCellChangeset { fn from_changeset(changeset: String) -> FlowyResult where Self: Sized, @@ -62,9 +64,9 @@ impl FromCellChangeset for DateCellChangeset { } } -impl ToString for DateCellChangeset { - fn to_string(&self) -> String { - serde_json::to_string(self).unwrap_or_else(|_| "".to_string()) +impl ToCellChangesetString for DateCellChangeset { + fn to_cell_changeset_str(&self) -> String { + serde_json::to_string(self).unwrap_or_default() } } diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/select_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/select_type_option.rs index 06dea283ec..d3a8bbad44 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/select_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/select_type_option.rs @@ -1,7 +1,8 @@ use crate::entities::parser::NotEmptyStr; -use crate::entities::{CellChangesetPB, CellPathPB, CellPathParams, FieldType}; +use crate::entities::{CellPathPB, CellPathParams, FieldType}; use crate::services::cell::{ - CellDataDecoder, CellProtobufBlobParser, DecodedCellData, FromCellChangeset, FromCellString, + CellDataDecoder, CellProtobufBlobParser, DecodedCellData, FromCellChangesetString, FromCellString, + ToCellChangesetString, }; use crate::services::field::selection_type_option::type_option_transform::SelectOptionTypeOptionTransformHelper; @@ -379,22 +380,6 @@ pub struct SelectOptionCellChangesetParams { pub delete_option_ids: Vec, } -impl std::convert::From for CellChangesetPB { - fn from(params: SelectOptionCellChangesetParams) -> Self { - let changeset = SelectOptionCellChangeset { - insert_option_ids: params.insert_option_ids, - delete_option_ids: params.delete_option_ids, - }; - let content = serde_json::to_string(&changeset).unwrap(); - CellChangesetPB { - grid_id: params.cell_identifier.view_id, - row_id: params.cell_identifier.row_id, - field_id: params.cell_identifier.field_id, - type_cell_data: content, - } - } -} - impl TryInto for SelectOptionCellChangesetPB { type Error = ErrorCode; @@ -432,13 +417,13 @@ impl TryInto for SelectOptionCellChangesetPB { } } -#[derive(Clone, Serialize, Deserialize)] +#[derive(Clone, Serialize, Deserialize, Debug)] pub struct SelectOptionCellChangeset { pub insert_option_ids: Vec, pub delete_option_ids: Vec, } -impl FromCellChangeset for SelectOptionCellChangeset { +impl FromCellChangesetString for SelectOptionCellChangeset { fn from_changeset(changeset: String) -> FlowyResult where Self: Sized, @@ -447,6 +432,12 @@ impl FromCellChangeset for SelectOptionCellChangeset { } } +impl ToCellChangesetString for SelectOptionCellChangeset { + fn to_cell_changeset_str(&self) -> String { + serde_json::to_string(self).unwrap_or_default() + } +} + impl SelectOptionCellChangeset { pub fn from_insert_option_id(option_id: &str) -> Self { SelectOptionCellChangeset { @@ -475,10 +466,6 @@ impl SelectOptionCellChangeset { delete_option_ids: option_ids, } } - - pub fn to_str(&self) -> String { - serde_json::to_string(self).unwrap() - } } /// [SelectOptionCellDataPB] contains a list of user's selected options and a list of all the options @@ -512,7 +499,7 @@ pub struct SelectOptionChangesetPB { } pub struct SelectOptionChangeset { - pub cell_identifier: CellPathParams, + pub cell_path: CellPathParams, pub insert_options: Vec, pub update_options: Vec, pub delete_options: Vec, @@ -524,7 +511,7 @@ impl TryInto for SelectOptionChangesetPB { fn try_into(self) -> Result { let cell_identifier = self.cell_identifier.try_into()?; Ok(SelectOptionChangeset { - cell_identifier, + cell_path: cell_identifier, insert_options: self.insert_options, update_options: self.update_options, delete_options: self.delete_options, diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/type_option.rs index 8d6128b91a..1b96e404d2 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/type_option.rs @@ -1,5 +1,5 @@ use crate::entities::FieldType; -use crate::services::cell::{CellDataDecoder, FromCellChangeset, FromCellString}; +use crate::services::cell::{CellDataDecoder, FromCellChangesetString, FromCellString, ToCellChangesetString}; use crate::services::filter::FromFilterString; use bytes::Bytes; @@ -23,10 +23,10 @@ pub trait TypeOption { type CellData: FromCellString + ToString + Default + Send + Sync + Clone + 'static; /// Represents as the corresponding field type cell changeset. - /// The changeset must implements the `FromCellChangeset` trait. The `CellChangeset` is implemented - /// for `String`. + /// The changeset must implements the `FromCellChangesetString` and the `ToCellChangesetString` trait. + /// These two traits are auto implemented for `String`. /// - type CellChangeset: FromCellChangeset; + type CellChangeset: FromCellChangesetString + ToCellChangesetString; /// For the moment, the protobuf type only be used in the FFI of `Dart`. If the decoded cell /// struct is just a `String`, then use the `StrCellData` as its `CellProtobufType`. diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/type_option_cell.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/type_option_cell.rs index a33808d6a3..a0d5b6a7cf 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/type_option_cell.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/type_option_cell.rs @@ -1,7 +1,7 @@ use crate::entities::FieldType; use crate::services::cell::{ AtomicCellDataCache, AtomicCellFilterCache, CellDataChangeset, CellDataDecoder, CellProtobufBlob, - FromCellChangeset, FromCellString, TypeCellData, + FromCellChangesetString, FromCellString, TypeCellData, }; use crate::services::field::{ default_order, CheckboxTypeOptionPB, ChecklistTypeOptionPB, DateTypeOptionPB, MultiSelectTypeOptionPB, diff --git a/frontend/rust-lib/flowy-grid/src/services/filter/controller.rs b/frontend/rust-lib/flowy-grid/src/services/filter/controller.rs index 73a37dd36e..531a6a6ae2 100644 --- a/frontend/rust-lib/flowy-grid/src/services/filter/controller.rs +++ b/frontend/rust-lib/flowy-grid/src/services/filter/controller.rs @@ -77,7 +77,7 @@ impl FilterController { } #[tracing::instrument(name = "schedule_filter_task", level = "trace", skip(self))] - async fn gen_task(&mut self, task_type: FilterEvent, qos: QualityOfService) { + async fn gen_task(&self, task_type: FilterEvent, qos: QualityOfService) { let task_id = self.task_scheduler.read().await.next_task_id(); let task = Task::new(&self.handler_id, task_id, TaskContent::Text(task_type.to_string()), qos); self.task_scheduler.write().await.add_task(task); @@ -148,9 +148,7 @@ impl FilterController { } } - let _ = self - .notifier - .send(GridViewChanged::DidReceiveFilterResult(notification)); + let _ = self.notifier.send(GridViewChanged::FilterNotification(notification)); } Ok(()) } @@ -186,14 +184,12 @@ impl FilterController { visible_rows, }; tracing::Span::current().record("filter_result", &format!("{:?}", ¬ification).as_str()); - let _ = self - .notifier - .send(GridViewChanged::DidReceiveFilterResult(notification)); + let _ = self.notifier.send(GridViewChanged::FilterNotification(notification)); } Ok(()) } - pub async fn did_receive_row_changed(&mut self, row_id: &str) { + pub async fn did_receive_row_changed(&self, row_id: &str) { self.gen_task( FilterEvent::RowDidChanged(row_id.to_string()), QualityOfService::UserInteractive, diff --git a/frontend/rust-lib/flowy-grid/src/services/filter/task.rs b/frontend/rust-lib/flowy-grid/src/services/filter/task.rs index b903156ad3..62eafc229e 100644 --- a/frontend/rust-lib/flowy-grid/src/services/filter/task.rs +++ b/frontend/rust-lib/flowy-grid/src/services/filter/task.rs @@ -24,6 +24,10 @@ impl TaskHandler for FilterTaskHandler { &self.handler_id } + fn handler_name(&self) -> &str { + "FilterTaskHandler" + } + fn run(&self, content: TaskContent) -> BoxResultFuture<(), anyhow::Error> { let filter_controller = self.filter_controller.clone(); Box::pin(async move { @@ -33,7 +37,7 @@ impl TaskHandler for FilterTaskHandler { .await .process(&predicate) .await - .map_err(anyhow::Error::from); + .map_err(anyhow::Error::from)?; } Ok(()) }) diff --git a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs index 91a3e2b924..31312dacc8 100644 --- a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs @@ -5,7 +5,7 @@ use crate::manager::GridUser; use crate::services::block_manager::GridBlockManager; use crate::services::cell::{ apply_cell_data_changeset, decode_type_cell_data, stringify_cell_data, AnyTypeCache, AtomicCellDataCache, - CellProtobufBlob, TypeCellData, + CellProtobufBlob, ToCellChangesetString, TypeCellData, }; use crate::services::field::{ default_type_option_builder_from_type, transform_type_option, type_option_builder_from_bytes, FieldBuilder, @@ -31,6 +31,7 @@ use grid_rev_model::*; use lib_infra::future::{to_fut, FutureResult}; use lib_ot::core::EmptyAttributes; use std::collections::HashMap; + use std::sync::Arc; use tokio::sync::{broadcast, RwLock}; @@ -405,16 +406,20 @@ impl GridRevisionEditor { /// Returns all the rows in this block. pub async fn get_row_pbs(&self, view_id: &str, block_id: &str) -> FlowyResult> { let rows = self.view_manager.get_row_revs(view_id, block_id).await?; - let rows = self - .view_manager - .filter_rows(view_id, block_id, rows) - .await? - .into_iter() - .map(|row_rev| RowPB::from(&row_rev)) - .collect(); + let rows = rows.into_iter().map(|row_rev| RowPB::from(&row_rev)).collect(); Ok(rows) } + pub async fn get_all_row_revs(&self, view_id: &str) -> FlowyResult>> { + let mut all_rows = vec![]; + let blocks = self.block_manager.get_blocks(None).await?; + for block in blocks { + let rows = self.view_manager.get_row_revs(view_id, &block.block_id).await?; + all_rows.extend(rows); + } + Ok(all_rows) + } + pub async fn get_row_rev(&self, row_id: &str) -> FlowyResult>> { match self.block_manager.get_row_rev(row_id).await? { None => Ok(None), @@ -458,7 +463,7 @@ impl GridRevisionEditor { )) }; - display_str().await.unwrap_or("".to_string()) + display_str().await.unwrap_or_else(|| "".to_string()) } pub async fn get_cell_bytes(&self, params: &CellPathParams) -> Option { @@ -488,52 +493,45 @@ impl GridRevisionEditor { } #[tracing::instrument(level = "trace", skip_all, err)] - pub async fn update_cell_with_changeset(&self, cell_changeset: CellChangesetPB) -> FlowyResult<()> { - let CellChangesetPB { - grid_id, - row_id, - field_id, - type_cell_data: mut content, - } = cell_changeset; - - match self.grid_pad.read().await.get_field_rev(&field_id) { + pub async fn update_cell_with_changeset( + &self, + row_id: &str, + field_id: &str, + cell_changeset: T, + ) -> FlowyResult<()> { + match self.grid_pad.read().await.get_field_rev(field_id) { None => { let msg = format!("Field:{} not found", &field_id); Err(FlowyError::internal().context(msg)) } Some((_, field_rev)) => { - tracing::trace!("field changeset: id:{} / value:{:?}", &field_id, content); - let cell_rev = self.get_cell_rev(&row_id, &field_id).await?; + tracing::trace!("Cell changeset: id:{} / value:{:?}", &field_id, cell_changeset); + let cell_rev = self.get_cell_rev(row_id, field_id).await?; // Update the changeset.data property with the return value. - content = apply_cell_data_changeset(content, cell_rev, field_rev, Some(self.cell_data_cache.clone()))?; + let type_cell_data = + apply_cell_data_changeset(cell_changeset, cell_rev, field_rev, Some(self.cell_data_cache.clone()))?; let cell_changeset = CellChangesetPB { - grid_id, - row_id: row_id.clone(), - field_id: field_id.clone(), - type_cell_data: content, + grid_id: self.grid_id.clone(), + row_id: row_id.to_owned(), + field_id: field_id.to_owned(), + type_cell_data, }; let _ = self.block_manager.update_cell(cell_changeset).await?; - self.view_manager.did_update_cell(&row_id).await; + self.view_manager.did_update_cell(row_id).await; Ok(()) } } } #[tracing::instrument(level = "trace", skip_all, err)] - pub async fn update_cell( + pub async fn update_cell( &self, - grid_id: String, row_id: String, field_id: String, - content: T, + cell_changeset: T, ) -> FlowyResult<()> { - self.update_cell_with_changeset(CellChangesetPB { - grid_id, - row_id, - field_id, - type_cell_data: content.to_string(), - }) - .await + self.update_cell_with_changeset(&row_id, &field_id, cell_changeset) + .await } pub async fn get_block_meta_revs(&self) -> FlowyResult>> { diff --git a/frontend/rust-lib/flowy-grid/src/services/persistence/rev_sqlite/grid_snapshot_sqlite_impl.rs b/frontend/rust-lib/flowy-grid/src/services/persistence/rev_sqlite/grid_snapshot_sqlite_impl.rs index 74a0a2aa75..0abf98f398 100644 --- a/frontend/rust-lib/flowy-grid/src/services/persistence/rev_sqlite/grid_snapshot_sqlite_impl.rs +++ b/frontend/rust-lib/flowy-grid/src/services/persistence/rev_sqlite/grid_snapshot_sqlite_impl.rs @@ -92,7 +92,7 @@ impl RevisionSnapshotDiskCache for SQLiteGridRevisionSnapshotPersistence { Ok(Some(latest_record.into())) } } -//noinspection ALL + #[derive(PartialEq, Clone, Debug, Queryable, Identifiable, Insertable, Associations)] #[table_name = "grid_rev_snapshot"] #[primary_key("snapshot_id")] diff --git a/frontend/rust-lib/flowy-grid/src/services/sort/controller.rs b/frontend/rust-lib/flowy-grid/src/services/sort/controller.rs index cb97da53eb..db2960bc16 100644 --- a/frontend/rust-lib/flowy-grid/src/services/sort/controller.rs +++ b/frontend/rust-lib/flowy-grid/src/services/sort/controller.rs @@ -1,52 +1,61 @@ -#![allow(clippy::all)] - use crate::entities::FieldType; -#[allow(unused_attributes)] use crate::entities::SortChangesetNotificationPB; -use crate::services::sort::{SortChangeset, SortType}; -use flowy_task::TaskDispatcher; -use grid_rev_model::{CellRevision, FieldRevision, RowRevision, SortCondition, SortRevision}; -use lib_infra::future::Fut; - use crate::services::cell::{AtomicCellDataCache, TypeCellData}; use crate::services::field::{default_order, TypeOptionCellExt}; +use crate::services::sort::{ReorderAllRowsResult, ReorderSingleRowResult, SortChangeset, SortType}; +use crate::services::view_editor::{GridViewChanged, GridViewChangedNotifier}; +use flowy_error::FlowyResult; +use flowy_task::{QualityOfService, Task, TaskContent, TaskDispatcher}; +use grid_rev_model::{CellRevision, FieldRevision, RowRevision, SortCondition, SortRevision}; +use lib_infra::future::Fut; use rayon::prelude::ParallelSliceMut; +use serde::{Deserialize, Serialize}; use std::cmp::Ordering; - +use std::collections::HashMap; +use std::str::FromStr; use std::sync::Arc; use tokio::sync::RwLock; pub trait SortDelegate: Send + Sync { fn get_sort_rev(&self, sort_type: SortType) -> Fut>>; + /// Returns all the rows after applying grid's filter + fn get_row_revs(&self) -> Fut>>; fn get_field_rev(&self, field_id: &str) -> Fut>>; fn get_field_revs(&self, field_ids: Option>) -> Fut>>; } pub struct SortController { + view_id: String, handler_id: String, delegate: Box, task_scheduler: Arc>, sorts: Vec>, cell_data_cache: AtomicCellDataCache, + row_index_cache: HashMap, + notifier: GridViewChangedNotifier, } impl SortController { pub fn new( - _view_id: &str, + view_id: &str, handler_id: &str, delegate: T, task_scheduler: Arc>, cell_data_cache: AtomicCellDataCache, + notifier: GridViewChangedNotifier, ) -> Self where T: SortDelegate + 'static, { Self { + view_id: view_id.to_string(), handler_id: handler_id.to_string(), delegate: Box::new(delegate), task_scheduler, sorts: vec![], cell_data_cache, + row_index_cache: Default::default(), + notifier, } } @@ -58,65 +67,139 @@ impl SortController { .await; } - pub async fn sort_rows(&self, rows: &mut Vec>) { + pub async fn did_receive_row_changed(&self, row_id: &str) { + let task_type = SortEvent::RowDidChanged(row_id.to_string()); + self.gen_task(task_type, QualityOfService::Background).await; + } + + #[tracing::instrument(name = "receive_sort_task_result", level = "trace", skip_all, err)] + pub async fn process(&mut self, predicate: &str) -> FlowyResult<()> { + let event_type = SortEvent::from_str(predicate).unwrap(); + let mut row_revs = self.delegate.get_row_revs().await; + match event_type { + SortEvent::SortDidChanged => { + self.sort_rows(&mut row_revs).await; + let row_orders = row_revs + .iter() + .map(|row_rev| row_rev.id.clone()) + .collect::>(); + + let notification = ReorderAllRowsResult { + view_id: self.view_id.clone(), + row_orders, + }; + + let _ = self + .notifier + .send(GridViewChanged::ReorderAllRowsNotification(notification)); + } + SortEvent::RowDidChanged(row_id) => { + let old_row_index = self.row_index_cache.get(&row_id).cloned(); + self.sort_rows(&mut row_revs).await; + let new_row_index = self.row_index_cache.get(&row_id).cloned(); + match (old_row_index, new_row_index) { + (Some(old_row_index), Some(new_row_index)) => { + if old_row_index == new_row_index { + return Ok(()); + } + let notification = ReorderSingleRowResult { + view_id: self.view_id.clone(), + old_index: old_row_index, + new_index: new_row_index, + }; + let _ = self + .notifier + .send(GridViewChanged::ReorderSingleRowNotification(notification)); + } + _ => tracing::trace!("The row index cache is outdated"), + } + } + } + Ok(()) + } + + #[tracing::instrument(name = "schedule_sort_task", level = "trace", skip(self))] + async fn gen_task(&self, task_type: SortEvent, qos: QualityOfService) { + if self.sorts.is_empty() { + return; + } + let task_id = self.task_scheduler.read().await.next_task_id(); + let task = Task::new(&self.handler_id, task_id, TaskContent::Text(task_type.to_string()), qos); + self.task_scheduler.write().await.add_task(task); + } + + pub async fn sort_rows(&mut self, rows: &mut Vec>) { + if self.sorts.is_empty() { + return; + } + let field_revs = self.delegate.get_field_revs(None).await; - rows.par_sort_by(|left, right| cmp_row(left, right, &self.sorts, &field_revs, &self.cell_data_cache)); + for sort in self.sorts.iter() { + rows.par_sort_by(|left, right| cmp_row(left, right, sort, &field_revs, &self.cell_data_cache)); + } + rows.iter().enumerate().for_each(|(index, row)| { + self.row_index_cache.insert(row.id.to_string(), index); + }); } #[tracing::instrument(level = "trace", skip(self))] - pub async fn did_receive_changes(&mut self, changeset: SortChangeset) -> Option { + pub async fn did_receive_changes(&mut self, changeset: SortChangeset) -> SortChangesetNotificationPB { + let mut notification = SortChangesetNotificationPB::default(); if let Some(insert_sort) = changeset.insert_sort { if let Some(sort) = self.delegate.get_sort_rev(insert_sort).await { + notification.insert_sorts.push(sort.as_ref().into()); self.sorts.push(sort); } } if let Some(delete_sort_type) = changeset.delete_sort { if let Some(index) = self.sorts.iter().position(|sort| sort.id == delete_sort_type.sort_id) { - self.sorts.remove(index); + let sort = self.sorts.remove(index); + notification.delete_sorts.push(sort.as_ref().into()); } } - if let Some(_update_sort) = changeset.update_sort { - // + if let Some(update_sort) = changeset.update_sort { + if let Some(updated_sort) = self.delegate.get_sort_rev(update_sort).await { + notification.update_sorts.push(updated_sort.as_ref().into()); + if let Some(index) = self.sorts.iter().position(|sort| sort.id == updated_sort.id) { + self.sorts[index] = updated_sort; + } + } } - None + if !notification.insert_sorts.is_empty() || !notification.delete_sorts.is_empty() { + self.gen_task(SortEvent::SortDidChanged, QualityOfService::Background) + .await; + } + notification } } fn cmp_row( left: &Arc, right: &Arc, - sorts: &[Arc], + sort: &Arc, field_revs: &[Arc], cell_data_cache: &AtomicCellDataCache, ) -> Ordering { - let mut order = default_order(); - for sort in sorts.iter() { - let cmp_order = match (left.cells.get(&sort.field_id), right.cells.get(&sort.field_id)) { - (Some(left_cell), Some(right_cell)) => { - let field_type: FieldType = sort.field_type.into(); - match field_revs.iter().find(|field_rev| field_rev.id == sort.field_id) { - None => default_order(), - Some(field_rev) => cmp_cell(left_cell, right_cell, field_rev, field_type, cell_data_cache), - } + let order = match (left.cells.get(&sort.field_id), right.cells.get(&sort.field_id)) { + (Some(left_cell), Some(right_cell)) => { + let field_type: FieldType = sort.field_type.into(); + match field_revs.iter().find(|field_rev| field_rev.id == sort.field_id) { + None => default_order(), + Some(field_rev) => cmp_cell(left_cell, right_cell, field_rev, field_type, cell_data_cache), } - (Some(_), None) => Ordering::Greater, - (None, Some(_)) => Ordering::Less, - _ => default_order(), - }; - - if cmp_order.is_ne() { - // If the cmp_order is not Ordering::Equal, then break the loop. - order = match sort.condition { - SortCondition::Ascending => cmp_order, - SortCondition::Descending => cmp_order.reverse(), - }; - break; } + (Some(_), None) => Ordering::Greater, + (None, Some(_)) => Ordering::Less, + _ => default_order(), + }; + + match sort.condition { + SortCondition::Ascending => order, + SortCondition::Descending => order.reverse(), } - order } fn cmp_cell( @@ -142,3 +225,21 @@ fn cmp_cell( } } } +#[derive(Serialize, Deserialize, Clone, Debug)] +enum SortEvent { + SortDidChanged, + RowDidChanged(String), +} + +impl ToString for SortEvent { + fn to_string(&self) -> String { + serde_json::to_string(self).unwrap() + } +} + +impl FromStr for SortEvent { + type Err = serde_json::Error; + fn from_str(s: &str) -> Result { + serde_json::from_str(s) + } +} diff --git a/frontend/rust-lib/flowy-grid/src/services/sort/entities.rs b/frontend/rust-lib/flowy-grid/src/services/sort/entities.rs index 905bc594da..bdbc8eb17c 100644 --- a/frontend/rust-lib/flowy-grid/src/services/sort/entities.rs +++ b/frontend/rust-lib/flowy-grid/src/services/sort/entities.rs @@ -32,7 +32,25 @@ impl std::convert::From<&Arc> for SortType { } } -#[allow(dead_code)] +#[derive(Clone)] +pub struct ReorderAllRowsResult { + pub view_id: String, + pub row_orders: Vec, +} + +impl ReorderAllRowsResult { + pub fn new(view_id: String, row_orders: Vec) -> Self { + Self { view_id, row_orders } + } +} + +#[derive(Clone)] +pub struct ReorderSingleRowResult { + pub view_id: String, + pub old_index: usize, + pub new_index: usize, +} + #[derive(Debug)] pub struct SortChangeset { pub(crate) insert_sort: Option, diff --git a/frontend/rust-lib/flowy-grid/src/services/sort/task.rs b/frontend/rust-lib/flowy-grid/src/services/sort/task.rs index 66365dc8b1..fe8c3066b0 100644 --- a/frontend/rust-lib/flowy-grid/src/services/sort/task.rs +++ b/frontend/rust-lib/flowy-grid/src/services/sort/task.rs @@ -24,7 +24,22 @@ impl TaskHandler for SortTaskHandler { &self.handler_id } - fn run(&self, _content: TaskContent) -> BoxResultFuture<(), anyhow::Error> { - todo!(); + fn handler_name(&self) -> &str { + "SortTaskHandler" + } + + fn run(&self, content: TaskContent) -> BoxResultFuture<(), anyhow::Error> { + let sort_controller = self.sort_controller.clone(); + Box::pin(async move { + if let TaskContent::Text(predicate) = content { + let _ = sort_controller + .write() + .await + .process(&predicate) + .await + .map_err(anyhow::Error::from)?; + } + Ok(()) + }) } } diff --git a/frontend/rust-lib/flowy-grid/src/services/view_editor/changed_notifier.rs b/frontend/rust-lib/flowy-grid/src/services/view_editor/changed_notifier.rs index acf8f1e52d..16e05ac1dc 100644 --- a/frontend/rust-lib/flowy-grid/src/services/view_editor/changed_notifier.rs +++ b/frontend/rust-lib/flowy-grid/src/services/view_editor/changed_notifier.rs @@ -1,13 +1,16 @@ use crate::dart_notification::{send_dart_notification, GridDartNotification}; -use crate::entities::GridRowsVisibilityChangesetPB; +use crate::entities::{GridRowsVisibilityChangesetPB, ReorderAllRowsPB, ReorderSingleRowPB}; use crate::services::filter::FilterResultNotification; +use crate::services::sort::{ReorderAllRowsResult, ReorderSingleRowResult}; use async_stream::stream; use futures::stream::StreamExt; use tokio::sync::broadcast; #[derive(Clone)] pub enum GridViewChanged { - DidReceiveFilterResult(FilterResultNotification), + FilterNotification(FilterResultNotification), + ReorderAllRowsNotification(ReorderAllRowsResult), + ReorderSingleRowNotification(ReorderSingleRowResult), } pub type GridViewChangedNotifier = broadcast::Sender; @@ -27,7 +30,7 @@ impl GridViewChangedReceiverRunner { stream .for_each(|changed| async { match changed { - GridViewChanged::DidReceiveFilterResult(notification) => { + GridViewChanged::FilterNotification(notification) => { let changeset = GridRowsVisibilityChangesetPB { view_id: notification.view_id, visible_rows: notification.visible_rows, @@ -41,6 +44,23 @@ impl GridViewChangedReceiverRunner { .payload(changeset) .send() } + GridViewChanged::ReorderAllRowsNotification(notification) => { + let row_orders = ReorderAllRowsPB { + row_orders: notification.row_orders, + }; + send_dart_notification(¬ification.view_id, GridDartNotification::DidReorderRows) + .payload(row_orders) + .send() + } + GridViewChanged::ReorderSingleRowNotification(notification) => { + let reorder_row = ReorderSingleRowPB { + old_index: notification.old_index as i32, + new_index: notification.new_index as i32, + }; + send_dart_notification(¬ification.view_id, GridDartNotification::DidReorderSingleRow) + .payload(reorder_row) + .send() + } } }) .await; diff --git a/frontend/rust-lib/flowy-grid/src/services/view_editor/editor.rs b/frontend/rust-lib/flowy-grid/src/services/view_editor/editor.rs index 11ff83242f..bbb784c896 100644 --- a/frontend/rust-lib/flowy-grid/src/services/view_editor/editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/view_editor/editor.rs @@ -112,24 +112,26 @@ impl GridViewRevisionEditor { ) .await?; - let sort_controller = make_sort_controller( - &view_id, - delegate.clone(), - view_rev_pad.clone(), - cell_data_cache.clone(), - ) - .await; - let user_id = user_id.to_owned(); let group_controller = Arc::new(RwLock::new(group_controller)); let filter_controller = make_filter_controller( &view_id, delegate.clone(), notifier.clone(), - cell_data_cache, + cell_data_cache.clone(), view_rev_pad.clone(), ) .await; + + let sort_controller = make_sort_controller( + &view_id, + delegate.clone(), + notifier.clone(), + filter_controller.clone(), + view_rev_pad.clone(), + cell_data_cache, + ) + .await; Ok(Self { pad: view_rev_pad, user_id, @@ -181,12 +183,11 @@ impl GridViewRevisionEditor { } pub async fn sort_rows(&self, rows: &mut Vec>) { - self.sort_controller.read().await.sort_rows(rows).await + self.sort_controller.write().await.sort_rows(rows).await } - pub async fn filter_rows(&self, _block_id: &str, mut rows: Vec>) -> Vec> { - self.filter_controller.write().await.filter_row_revs(&mut rows).await; - rows + pub async fn filter_rows(&self, _block_id: &str, rows: &mut Vec>) { + self.filter_controller.write().await.filter_row_revs(rows).await; } pub async fn duplicate_view_data(&self) -> FlowyResult { @@ -260,9 +261,11 @@ impl GridViewRevisionEditor { } let filter_controller = self.filter_controller.clone(); + let sort_controller = self.sort_controller.clone(); let row_id = row_rev.id.clone(); tokio::spawn(async move { - filter_controller.write().await.did_receive_row_changed(&row_id).await; + filter_controller.read().await.did_receive_row_changed(&row_id).await; + sort_controller.read().await.did_receive_row_changed(&row_id).await; }); } @@ -423,10 +426,9 @@ impl GridViewRevisionEditor { .did_receive_changes(SortChangeset::from_insert(sort_type)) .await }; + drop(sort_controller); - if let Some(changeset) = changeset { - self.notify_did_update_sort(changeset).await; - } + self.notify_did_update_sort(changeset).await; Ok(sort_rev) } @@ -446,9 +448,7 @@ impl GridViewRevisionEditor { }) .await?; - if changeset.is_some() { - self.notify_did_update_sort(changeset.unwrap()).await; - } + self.notify_did_update_sort(changeset).await; Ok(()) } @@ -495,6 +495,7 @@ impl GridViewRevisionEditor { .did_receive_changes(FilterChangeset::from_insert(filter_type)) .await }; + drop(filter_controller); if let Some(changeset) = changeset { self.notify_did_update_filter(changeset).await; @@ -612,9 +613,11 @@ impl GridViewRevisionEditor { } pub async fn notify_did_update_sort(&self, changeset: SortChangesetNotificationPB) { - send_dart_notification(&changeset.view_id, GridDartNotification::DidUpdateSort) - .payload(changeset) - .send(); + if !changeset.is_empty() { + send_dart_notification(&changeset.view_id, GridDartNotification::DidUpdateSort) + .payload(changeset) + .send(); + } } async fn notify_did_update_view(&self, changeset: GroupViewChangesetPB) { @@ -756,6 +759,8 @@ async fn make_filter_controller( async fn make_sort_controller( view_id: &str, delegate: Arc, + notifier: GridViewChangedNotifier, + filter_controller: Arc>, pad: Arc>, cell_data_cache: AtomicCellDataCache, ) -> Arc> { @@ -763,6 +768,7 @@ async fn make_sort_controller( let sort_delegate = GridViewSortDelegateImpl { editor_delegate: delegate.clone(), view_revision_pad: pad, + filter_controller, }; let task_scheduler = delegate.get_task_scheduler(); let sort_controller = Arc::new(RwLock::new(SortController::new( @@ -771,6 +777,7 @@ async fn make_sort_controller( sort_delegate, task_scheduler.clone(), cell_data_cache, + notifier, ))); task_scheduler .write() diff --git a/frontend/rust-lib/flowy-grid/src/services/view_editor/editor_manager.rs b/frontend/rust-lib/flowy-grid/src/services/view_editor/editor_manager.rs index 586bcd0feb..3a2648fc78 100644 --- a/frontend/rust-lib/flowy-grid/src/services/view_editor/editor_manager.rs +++ b/frontend/rust-lib/flowy-grid/src/services/view_editor/editor_manager.rs @@ -60,22 +60,11 @@ impl GridViewManager { pub async fn get_row_revs(&self, view_id: &str, block_id: &str) -> FlowyResult>> { let mut row_revs = self.delegate.get_row_revs(Some(vec![block_id.to_owned()])).await; if let Ok(view_editor) = self.get_view_editor(view_id).await { + view_editor.filter_rows(block_id, &mut row_revs).await; view_editor.sort_rows(&mut row_revs).await; } - Ok(row_revs) - } - pub async fn filter_rows( - &self, - view_id: &str, - block_id: &str, - rows: Vec>, - ) -> FlowyResult>> { - let rows = match self.get_view_editor(view_id).await { - Ok(view_editor) => view_editor.filter_rows(block_id, rows).await, - Err(_) => rows, - }; - Ok(rows) + Ok(row_revs) } pub async fn duplicate_grid_view(&self) -> FlowyResult { diff --git a/frontend/rust-lib/flowy-grid/src/services/view_editor/trait_impl.rs b/frontend/rust-lib/flowy-grid/src/services/view_editor/trait_impl.rs index 5764857106..3687e2e802 100644 --- a/frontend/rust-lib/flowy-grid/src/services/view_editor/trait_impl.rs +++ b/frontend/rust-lib/flowy-grid/src/services/view_editor/trait_impl.rs @@ -1,5 +1,5 @@ use crate::entities::{GridLayout, GridLayoutPB, GridSettingPB}; -use crate::services::filter::{FilterDelegate, FilterType}; +use crate::services::filter::{FilterController, FilterDelegate, FilterType}; use crate::services::group::{GroupConfigurationReader, GroupConfigurationWriter}; use crate::services::row::GridBlockRowRevision; use crate::services::sort::{SortDelegate, SortType}; @@ -169,6 +169,7 @@ impl FilterDelegate for GridViewFilterDelegateImpl { pub(crate) struct GridViewSortDelegateImpl { pub(crate) editor_delegate: Arc, pub(crate) view_revision_pad: Arc>, + pub(crate) filter_controller: Arc>, } impl SortDelegate for GridViewSortDelegateImpl { @@ -187,6 +188,16 @@ impl SortDelegate for GridViewSortDelegateImpl { }) } + fn get_row_revs(&self) -> Fut>> { + let filter_controller = self.filter_controller.clone(); + let editor_delegate = self.editor_delegate.clone(); + to_fut(async move { + let mut row_revs = editor_delegate.get_row_revs(None).await; + filter_controller.write().await.filter_row_revs(&mut row_revs).await; + row_revs + }) + } + fn get_field_rev(&self, field_id: &str) -> Fut>> { self.editor_delegate.get_field_rev(field_id) } diff --git a/frontend/rust-lib/flowy-grid/tests/grid/block_test/row_test.rs b/frontend/rust-lib/flowy-grid/tests/grid/block_test/row_test.rs index db3d735f29..54e7375277 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/block_test/row_test.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/block_test/row_test.rs @@ -9,13 +9,13 @@ use grid_rev_model::RowChangeset; async fn grid_create_row_count_test() { let mut test = GridRowTest::new().await; let scripts = vec![ - AssertRowCount(5), + AssertRowCount(6), CreateEmptyRow, CreateEmptyRow, CreateRow { row_rev: test.row_builder().build(), }, - AssertRowCount(8), + AssertRowCount(9), ]; test.run_scripts(scripts).await; } @@ -30,12 +30,12 @@ async fn grid_update_row() { visibility: None, cell_by_field_id: Default::default(), }; - - let scripts = vec![AssertRowCount(5), CreateRow { row_rev }, UpdateRow { changeset }]; + let row_count = test.row_revs.len(); + let scripts = vec![CreateRow { row_rev }, UpdateRow { changeset }]; test.run_scripts(scripts).await; let expected_row = test.last_row().unwrap(); - let scripts = vec![AssertRow { expected_row }, AssertRowCount(6)]; + let scripts = vec![AssertRow { expected_row }, AssertRowCount(row_count + 1)]; test.run_scripts(scripts).await; } @@ -45,20 +45,20 @@ async fn grid_delete_row() { let row_1 = test.row_builder().build(); let row_2 = test.row_builder().build(); let row_ids = vec![row_1.id.clone(), row_2.id.clone()]; + let row_count = test.row_revs.len() as i32; let scripts = vec![ - AssertRowCount(5), CreateRow { row_rev: row_1 }, CreateRow { row_rev: row_2 }, AssertBlockCount(1), AssertBlock { block_index: 0, - row_count: 7, + row_count: row_count + 2, start_row_index: 0, }, DeleteRows { row_ids }, AssertBlock { block_index: 0, - row_count: 5, + row_count, start_row_index: 0, }, ]; diff --git a/frontend/rust-lib/flowy-grid/tests/grid/block_test/script.rs b/frontend/rust-lib/flowy-grid/tests/grid/block_test/script.rs index be8d23f33c..c97bbb2341 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/block_test/script.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/block_test/script.rs @@ -113,7 +113,7 @@ impl GridRowTest { expected, } => { let id = CellPathParams { - view_id: self.grid_id.clone(), + view_id: self.view_id.clone(), field_id, row_id, }; diff --git a/frontend/rust-lib/flowy-grid/tests/grid/cell_test/script.rs b/frontend/rust-lib/flowy-grid/tests/grid/cell_test/script.rs index ad184682bd..3727e4897a 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/cell_test/script.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/cell_test/script.rs @@ -24,17 +24,19 @@ impl GridCellTest { pub async fn run_script(&mut self, script: CellScript) { // let grid_manager = self.sdk.grid_manager.clone(); // let pool = self.sdk.user_session.db_pool().unwrap(); - let rev_manager = self.editor.rev_manager(); - let _cache = rev_manager.revision_cache().await; + // let rev_manager = self.editor.rev_manager(); + // let _cache = rev_manager.revision_cache().await; match script { CellScript::UpdateCell { changeset, is_err } => { - let result = self.editor.update_cell_with_changeset(changeset).await; + let result = self + .editor + .update_cell_with_changeset(&changeset.row_id, &changeset.field_id, changeset.type_cell_data) + .await; if is_err { assert!(result.is_err()) } else { let _ = result.unwrap(); - self.row_revs = self.get_row_revs().await; } } // CellScript::AssertGridRevisionPad => { // sleep(Duration::from_millis(2 * REVISION_WRITE_INTERVAL_IN_MILLIS)).await; diff --git a/frontend/rust-lib/flowy-grid/tests/grid/cell_test/test.rs b/frontend/rust-lib/flowy-grid/tests/grid/cell_test/test.rs index 66781ccbbc..12dc5ee0ff 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/cell_test/test.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/cell_test/test.rs @@ -2,6 +2,7 @@ use crate::grid::cell_test::script::CellScript::*; use crate::grid::cell_test::script::GridCellTest; use crate::grid::field_test::util::make_date_cell_string; use flowy_grid::entities::{CellChangesetPB, FieldType}; +use flowy_grid::services::cell::ToCellChangesetString; use flowy_grid::services::field::selection_type_option::SelectOptionCellChangeset; use flowy_grid::services::field::{ChecklistTypeOptionPB, MultiSelectTypeOptionPB, SingleSelectTypeOptionPB}; @@ -25,15 +26,18 @@ async fn grid_cell_update() { FieldType::DateTime => make_date_cell_string("123"), FieldType::SingleSelect => { let type_option = SingleSelectTypeOptionPB::from(field_rev); - SelectOptionCellChangeset::from_insert_option_id(&type_option.options.first().unwrap().id).to_str() + SelectOptionCellChangeset::from_insert_option_id(&type_option.options.first().unwrap().id) + .to_cell_changeset_str() } FieldType::MultiSelect => { let type_option = MultiSelectTypeOptionPB::from(field_rev); - SelectOptionCellChangeset::from_insert_option_id(&type_option.options.first().unwrap().id).to_str() + SelectOptionCellChangeset::from_insert_option_id(&type_option.options.first().unwrap().id) + .to_cell_changeset_str() } FieldType::Checklist => { let type_option = ChecklistTypeOptionPB::from(field_rev); - SelectOptionCellChangeset::from_insert_option_id(&type_option.options.first().unwrap().id).to_str() + SelectOptionCellChangeset::from_insert_option_id(&type_option.options.first().unwrap().id) + .to_cell_changeset_str() } FieldType::Checkbox => "1".to_string(), FieldType::URL => "1".to_string(), diff --git a/frontend/rust-lib/flowy-grid/tests/grid/field_test/script.rs b/frontend/rust-lib/flowy-grid/tests/grid/field_test/script.rs index 1b79caeea2..9e5cfaa653 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/field_test/script.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/field_test/script.rs @@ -49,7 +49,7 @@ impl GridFieldTest { } pub fn view_id(&self) -> String { - self.grid_id.clone() + self.view_id.clone() } pub fn field_count(&self) -> usize { @@ -100,7 +100,7 @@ impl GridFieldTest { FieldScript::UpdateTypeOption { field_id, type_option } => { // self.editor - .update_field_type_option(&self.grid_id, &field_id, type_option, None) + .update_field_type_option(&self.view_id, &field_id, type_option, None) .await .unwrap(); self.field_revs = self.editor.get_field_revs(None).await.unwrap(); diff --git a/frontend/rust-lib/flowy-grid/tests/grid/filter_test/checklist_filter_test.rs b/frontend/rust-lib/flowy-grid/tests/grid/filter_test/checklist_filter_test.rs index 05b4754ff7..0155de52bd 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/filter_test/checklist_filter_test.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/filter_test/checklist_filter_test.rs @@ -9,7 +9,7 @@ async fn grid_filter_checklist_is_incomplete_test() { CreateChecklistFilter { condition: ChecklistFilterConditionPB::IsIncomplete, }, - AssertNumberOfVisibleRows { expected: 4 }, + AssertNumberOfVisibleRows { expected: 5 }, ]; test.run_scripts(scripts).await; } diff --git a/frontend/rust-lib/flowy-grid/tests/grid/filter_test/date_filter_test.rs b/frontend/rust-lib/flowy-grid/tests/grid/filter_test/date_filter_test.rs index 8be96ad4f0..5d587732bd 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/filter_test/date_filter_test.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/filter_test/date_filter_test.rs @@ -27,7 +27,7 @@ async fn grid_filter_date_after_test() { end: None, timestamp: Some(1647251762), }, - AssertNumberOfVisibleRows { expected: 2 }, + AssertNumberOfVisibleRows { expected: 3 }, ]; test.run_scripts(scripts).await; } @@ -42,7 +42,7 @@ async fn grid_filter_date_on_or_after_test() { end: None, timestamp: Some(1668359085), }, - AssertNumberOfVisibleRows { expected: 2 }, + AssertNumberOfVisibleRows { expected: 3 }, ]; test.run_scripts(scripts).await; } diff --git a/frontend/rust-lib/flowy-grid/tests/grid/filter_test/number_filter_test.rs b/frontend/rust-lib/flowy-grid/tests/grid/filter_test/number_filter_test.rs index a4bb99e4e0..5e80836b43 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/filter_test/number_filter_test.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/filter_test/number_filter_test.rs @@ -76,7 +76,7 @@ async fn grid_filter_number_is_not_empty_test() { condition: NumberFilterConditionPB::NumberIsNotEmpty, content: "".to_string(), }, - AssertNumberOfVisibleRows { expected: 4 }, + AssertNumberOfVisibleRows { expected: 5 }, ]; test.run_scripts(scripts).await; } diff --git a/frontend/rust-lib/flowy-grid/tests/grid/filter_test/script.rs b/frontend/rust-lib/flowy-grid/tests/grid/filter_test/script.rs index 47c4f74d73..7737232472 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/filter_test/script.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/filter_test/script.rs @@ -19,11 +19,11 @@ use crate::grid::grid_editor::GridEditorTest; pub enum FilterScript { UpdateTextCell { - row_index: usize, + row_id: String, text: String, }, UpdateSingleSelectCell { - row_index: usize, + row_id: String, option_id: String, }, InsertFilter { @@ -103,7 +103,7 @@ impl GridFilterTest { } pub fn view_id(&self) -> String { - self.grid_id.clone() + self.view_id.clone() } pub async fn get_all_filters(&self) -> Vec { @@ -118,13 +118,13 @@ impl GridFilterTest { pub async fn run_script(&mut self, script: FilterScript) { match script { - FilterScript::UpdateTextCell { row_index, text} => { + FilterScript::UpdateTextCell { row_id, text} => { self.recv = Some(self.editor.subscribe_view_changed(&self.view_id()).await.unwrap()); - self.update_text_cell(row_index, &text).await; + self.update_text_cell(row_id, &text).await; } - FilterScript::UpdateSingleSelectCell { row_index, option_id} => { + FilterScript::UpdateSingleSelectCell { row_id, option_id} => { self.recv = Some(self.editor.subscribe_view_changed(&self.view_id()).await.unwrap()); - self.update_single_select_cell(row_index, &option_id).await; + self.update_single_select_cell(row_id, &option_id).await; } FilterScript::InsertFilter { payload } => { self.recv = Some(self.editor.subscribe_view_changed(&self.view_id()).await.unwrap()); @@ -241,13 +241,15 @@ impl GridFilterTest { match tokio::time::timeout(Duration::from_secs(2), receiver.recv()).await { Ok(changed) => { // - match changed.unwrap() { GridViewChanged::DidReceiveFilterResult(changed) => { + match changed.unwrap() { GridViewChanged::FilterNotification(changed) => { assert_eq!(changed.visible_rows.len(), visible_row_len, "visible rows not match"); assert_eq!(changed.invisible_rows.len(), hide_row_len, "invisible rows not match"); - } } + } + _ => {} + } }, Err(e) => { - panic!("Process task timeout: {:?}", e); + panic!("Process filter task timeout: {:?}", e); } } } @@ -268,38 +270,6 @@ impl GridFilterTest { let _ = self.editor.create_or_update_filter(params).await.unwrap(); } - async fn update_text_cell(&self, row_index: usize, content: &str) { - let row_rev = &self.inner.row_revs[row_index]; - let field_rev = self.inner.field_revs.iter().find(|field_rev| { - let field_type: FieldType = field_rev.ty.into(); - field_type == FieldType::RichText - }).unwrap(); - let changeset =CellChangesetPB { - grid_id: self.grid_id.clone(), - row_id: row_rev.id.clone(), - field_id: field_rev.id.clone(), - type_cell_data: content.to_string(), - }; - self.editor.update_cell_with_changeset(changeset).await.unwrap(); - - } - async fn update_single_select_cell(&self, row_index: usize, option_id: &str) { - let row_rev = &self.inner.row_revs[row_index]; - let field_rev = self.inner.field_revs.iter().find(|field_rev| { - let field_type: FieldType = field_rev.ty.into(); - field_type == FieldType::SingleSelect - }).unwrap(); - - let content = SelectOptionCellChangeset::from_insert_option_id(&option_id).to_str(); - let changeset =CellChangesetPB { - grid_id: self.grid_id.clone(), - row_id: row_rev.id.clone(), - field_id: field_rev.id.clone(), - type_cell_data: content, - }; - self.editor.update_cell_with_changeset(changeset).await.unwrap(); - - } } diff --git a/frontend/rust-lib/flowy-grid/tests/grid/filter_test/select_option_filter_test.rs b/frontend/rust-lib/flowy-grid/tests/grid/filter_test/select_option_filter_test.rs index 1c73afa820..7db6c36c9b 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/filter_test/select_option_filter_test.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/filter_test/select_option_filter_test.rs @@ -10,7 +10,7 @@ async fn grid_filter_multi_select_is_empty_test() { condition: SelectOptionConditionPB::OptionIsEmpty, option_ids: vec![], }, - AssertNumberOfVisibleRows { expected: 2 }, + AssertNumberOfVisibleRows { expected: 3 }, ]; test.run_scripts(scripts).await; } @@ -90,6 +90,7 @@ async fn grid_filter_single_select_is_test() { async fn grid_filter_single_select_is_test2() { let mut test = GridFilterTest::new().await; let field_rev = test.get_first_field_rev(FieldType::SingleSelect); + let row_revs = test.get_row_revs().await; let mut options = test.get_single_select_type_option(&field_rev.id).options; let option = options.remove(0); let scripts = vec![ @@ -99,12 +100,12 @@ async fn grid_filter_single_select_is_test2() { }, AssertNumberOfVisibleRows { expected: 2 }, UpdateSingleSelectCell { - row_index: 1, + row_id: row_revs[1].id.clone(), option_id: option.id.clone(), }, AssertNumberOfVisibleRows { expected: 3 }, UpdateSingleSelectCell { - row_index: 1, + row_id: row_revs[1].id.clone(), option_id: "".to_string(), }, AssertFilterChanged { diff --git a/frontend/rust-lib/flowy-grid/tests/grid/filter_test/text_filter_test.rs b/frontend/rust-lib/flowy-grid/tests/grid/filter_test/text_filter_test.rs index 916f454a84..b9ce68f61d 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/filter_test/text_filter_test.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/filter_test/text_filter_test.rs @@ -14,7 +14,7 @@ async fn grid_filter_text_is_empty_test() { AssertFilterCount { count: 1 }, AssertFilterChanged { visible_row_len: 0, - hide_row_len: 4, + hide_row_len: 5, }, ]; test.run_scripts(scripts).await; @@ -65,7 +65,7 @@ async fn grid_filter_is_text_test() { }, AssertFilterChanged { visible_row_len: 0, - hide_row_len: 4, + hide_row_len: 5, }, ]; test.run_scripts(scripts).await; @@ -90,6 +90,8 @@ async fn grid_filter_contain_text_test() { #[tokio::test] async fn grid_filter_contain_text_test2() { let mut test = GridFilterTest::new().await; + let row_revs = test.row_revs.clone(); + let scripts = vec![ CreateTextFilter { condition: TextFilterConditionPB::Contains, @@ -100,7 +102,7 @@ async fn grid_filter_contain_text_test2() { hide_row_len: 2, }, UpdateTextCell { - row_index: 1, + row_id: row_revs[1].id.clone(), text: "ABC".to_string(), }, AssertFilterChanged { @@ -206,7 +208,7 @@ async fn grid_filter_delete_test() { filter_type: FilterType::from(&field_rev), }, AssertFilterCount { count: 0 }, - AssertNumberOfVisibleRows { expected: 5 }, + AssertNumberOfVisibleRows { expected: 6 }, ]) .await; } @@ -214,6 +216,7 @@ async fn grid_filter_delete_test() { #[tokio::test] async fn grid_filter_update_empty_text_cell_test() { let mut test = GridFilterTest::new().await; + let row_revs = test.row_revs.clone(); let scripts = vec![ CreateTextFilter { condition: TextFilterConditionPB::TextIsEmpty, @@ -222,10 +225,10 @@ async fn grid_filter_update_empty_text_cell_test() { AssertFilterCount { count: 1 }, AssertFilterChanged { visible_row_len: 0, - hide_row_len: 4, + hide_row_len: 5, }, UpdateTextCell { - row_index: 0, + row_id: row_revs[0].id.clone(), text: "".to_string(), }, AssertFilterChanged { diff --git a/frontend/rust-lib/flowy-grid/tests/grid/grid_editor.rs b/frontend/rust-lib/flowy-grid/tests/grid/grid_editor.rs index 9ad9d201b2..b507e7ca17 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/grid_editor.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/grid_editor.rs @@ -5,6 +5,7 @@ use crate::grid::block_test::util::GridRowTestBuilder; use bytes::Bytes; use flowy_error::FlowyResult; use flowy_grid::entities::*; +use flowy_grid::services::cell::ToCellChangesetString; use flowy_grid::services::field::SelectOptionPB; use flowy_grid::services::field::*; use flowy_grid::services::grid_editor::{GridRevisionEditor, GridRevisionSerde}; @@ -24,7 +25,7 @@ use tokio::time::sleep; pub struct GridEditorTest { pub sdk: FlowySDKTest, - pub grid_id: String, + pub view_id: String, pub editor: Arc, pub field_revs: Vec>, pub block_meta_revs: Vec>, @@ -61,7 +62,7 @@ impl GridEditorTest { let editor = sdk.grid_manager.open_grid(&test.view.id).await.unwrap(); let field_revs = editor.get_field_revs(None).await.unwrap(); let block_meta_revs = editor.get_block_meta_revs().await.unwrap(); - let row_revs = editor.get_blocks(None).await.unwrap().pop().unwrap().row_revs; + let row_pbs = editor.get_all_row_revs(&test.view.id).await.unwrap(); assert_eq!(block_meta_revs.len(), 1); // It seems like you should add the field in the make_test_grid() function. @@ -71,18 +72,18 @@ impl GridEditorTest { let grid_id = test.view.id; Self { sdk, - grid_id, + view_id: grid_id, editor, field_revs, block_meta_revs, - row_revs, + row_revs: row_pbs, field_count: FieldType::COUNT, row_by_row_id: HashMap::default(), } } pub async fn get_row_revs(&self) -> Vec> { - self.editor.get_blocks(None).await.unwrap().pop().unwrap().row_revs + self.editor.get_all_row_revs(&self.view_id).await.unwrap() } pub async fn grid_filters(&self) -> Vec { @@ -153,6 +154,48 @@ impl GridEditorTest { pub fn block_id(&self) -> &str { &self.block_meta_revs.last().unwrap().block_id } + + pub async fn update_cell(&mut self, field_id: &str, row_id: String, cell_changeset: T) { + let field_rev = self + .field_revs + .iter() + .find(|field_rev| field_rev.id == field_id) + .unwrap(); + + self.editor + .update_cell_with_changeset(&row_id, &field_rev.id, cell_changeset) + .await + .unwrap(); + } + + pub(crate) async fn update_text_cell(&mut self, row_id: String, content: &str) { + let field_rev = self + .field_revs + .iter() + .find(|field_rev| { + let field_type: FieldType = field_rev.ty.into(); + field_type == FieldType::RichText + }) + .unwrap() + .clone(); + + self.update_cell(&field_rev.id, row_id, content.to_string()).await; + } + + pub(crate) async fn update_single_select_cell(&mut self, row_id: String, option_id: &str) { + let field_rev = self + .field_revs + .iter() + .find(|field_rev| { + let field_type: FieldType = field_rev.ty.into(); + field_type == FieldType::SingleSelect + }) + .unwrap() + .clone(); + + let cell_changeset = SelectOptionCellChangeset::from_insert_option_id(&option_id); + self.update_cell(&field_rev.id, row_id, cell_changeset).await; + } } pub const GOOGLE: &str = "Google"; @@ -243,7 +286,7 @@ fn make_test_grid() -> BuildGridContext { } } - for i in 0..5 { + for i in 0..6 { let block_id = grid_builder.block_id().to_owned(); let field_revs = grid_builder.field_revs(); let mut row_builder = GridRowTestBuilder::new(&block_id, field_revs); @@ -321,6 +364,20 @@ fn make_test_grid() -> BuildGridContext { }; } } + 5 => { + for field_type in FieldType::iter() { + match field_type { + FieldType::RichText => row_builder.insert_text_cell("AE"), + FieldType::Number => row_builder.insert_number_cell("5"), + FieldType::DateTime => row_builder.insert_date_cell("1671938394"), + FieldType::SingleSelect => { + row_builder.insert_single_select_cell(|mut options| options.remove(1)) + } + FieldType::Checkbox => row_builder.insert_checkbox_cell("true"), + _ => "".to_owned(), + }; + } + } _ => {} } diff --git a/frontend/rust-lib/flowy-grid/tests/grid/group_test/script.rs b/frontend/rust-lib/flowy-grid/tests/grid/group_test/script.rs index 3e673889a4..bc64551f8b 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/group_test/script.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/group_test/script.rs @@ -90,7 +90,7 @@ impl GridGroupTest { let to_group = groups.get(to_group_index).unwrap(); let to_row = to_group.rows.get(to_row_index).unwrap(); let params = MoveGroupRowParams { - view_id: self.inner.grid_id.clone(), + view_id: self.inner.view_id.clone(), from_row_id: from_row.id.clone(), to_group_id: to_group.group_id.clone(), to_row_id: Some(to_row.id.clone()), diff --git a/frontend/rust-lib/flowy-grid/tests/grid/snapshot_test/script.rs b/frontend/rust-lib/flowy-grid/tests/grid/snapshot_test/script.rs index 901a260636..d63ac76ed2 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/snapshot_test/script.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/snapshot_test/script.rs @@ -43,7 +43,7 @@ impl GridSnapshotTest { } pub fn grid_id(&self) -> String { - self.grid_id.clone() + self.view_id.clone() } pub async fn grid_pad(&self) -> GridRevisionPad { diff --git a/frontend/rust-lib/flowy-grid/tests/grid/sort_test/mod.rs b/frontend/rust-lib/flowy-grid/tests/grid/sort_test/mod.rs index 20ed425231..d84b43ca7b 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/sort_test/mod.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/sort_test/mod.rs @@ -1,2 +1,3 @@ +mod multi_sort_test; mod script; -mod sort_test; +mod single_sort_test; diff --git a/frontend/rust-lib/flowy-grid/tests/grid/sort_test/multi_sort_test.rs b/frontend/rust-lib/flowy-grid/tests/grid/sort_test/multi_sort_test.rs new file mode 100644 index 0000000000..b1444f0d0f --- /dev/null +++ b/frontend/rust-lib/flowy-grid/tests/grid/sort_test/multi_sort_test.rs @@ -0,0 +1,46 @@ +use crate::grid::sort_test::script::GridSortTest; +use crate::grid::sort_test::script::SortScript::*; +use flowy_grid::entities::FieldType; +use grid_rev_model::SortCondition; + +#[tokio::test] +async fn sort_text_with_checkbox_by_ascending_test() { + let mut test = GridSortTest::new().await; + let text_field = test.get_first_field_rev(FieldType::RichText).clone(); + let checkbox_field = test.get_first_field_rev(FieldType::Checkbox).clone(); + let scripts = vec![ + AssertCellContentOrder { + field_id: text_field.id.clone(), + orders: vec!["A", "", "C", "DA", "AE", "AE"], + }, + AssertCellContentOrder { + field_id: checkbox_field.id.clone(), + orders: vec!["Yes", "Yes", "No", "No", "No"], + }, + InsertSort { + field_rev: text_field.clone(), + condition: SortCondition::Ascending, + }, + AssertCellContentOrder { + field_id: text_field.id.clone(), + orders: vec!["", "A", "AE", "AE", "C", "DA"], + }, + ]; + test.run_scripts(scripts).await; + + let scripts = vec![ + InsertSort { + field_rev: checkbox_field.clone(), + condition: SortCondition::Descending, + }, + AssertCellContentOrder { + field_id: text_field.id.clone(), + orders: vec!["", "A", "AE", "AE", "C", "DA"], + }, + AssertCellContentOrder { + field_id: checkbox_field.id.clone(), + orders: vec!["Yes", "Yes", "Yes", "No", "No"], + }, + ]; + test.run_scripts(scripts).await; +} diff --git a/frontend/rust-lib/flowy-grid/tests/grid/sort_test/script.rs b/frontend/rust-lib/flowy-grid/tests/grid/sort_test/script.rs index a60eeb544b..dbeee849a1 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/sort_test/script.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/sort_test/script.rs @@ -1,23 +1,45 @@ use crate::grid::grid_editor::GridEditorTest; +use async_stream::stream; use flowy_grid::entities::{AlterSortParams, CellPathParams, DeleteSortParams}; -use grid_rev_model::SortRevision; +use flowy_grid::services::sort::SortType; +use flowy_grid::services::view_editor::GridViewChanged; +use futures::stream::StreamExt; +use grid_rev_model::{FieldRevision, SortCondition, SortRevision}; +use std::cmp::min; +use std::sync::Arc; +use std::time::Duration; +use tokio::sync::broadcast::Receiver; pub enum SortScript { InsertSort { - params: AlterSortParams, + field_rev: Arc, + condition: SortCondition, }, DeleteSort { - params: DeleteSortParams, + field_rev: Arc, + sort_id: String, }, - AssertTextOrder { + AssertCellContentOrder { field_id: String, orders: Vec<&'static str>, }, + UpdateTextCell { + row_id: String, + text: String, + }, + AssertSortChanged { + old_row_orders: Vec<&'static str>, + new_row_orders: Vec<&'static str>, + }, + Wait { + millis: u64, + }, } pub struct GridSortTest { inner: GridEditorTest, pub current_sort_rev: Option, + recv: Option>, } impl GridSortTest { @@ -26,6 +48,7 @@ impl GridSortTest { Self { inner: editor_test, current_sort_rev: None, + recv: None, } } pub async fn run_scripts(&mut self, scripts: Vec) { @@ -36,32 +59,101 @@ impl GridSortTest { pub async fn run_script(&mut self, script: SortScript) { match script { - SortScript::InsertSort { params } => { + SortScript::InsertSort { condition, field_rev } => { + self.recv = Some(self.editor.subscribe_view_changed(&self.view_id).await.unwrap()); + let params = AlterSortParams { + view_id: self.view_id.clone(), + field_id: field_rev.id.clone(), + sort_id: None, + field_type: field_rev.ty, + condition: condition.into(), + }; let sort_rev = self.editor.create_or_update_sort(params).await.unwrap(); self.current_sort_rev = Some(sort_rev); } - SortScript::DeleteSort { params } => { - // + SortScript::DeleteSort { field_rev, sort_id } => { + self.recv = Some(self.editor.subscribe_view_changed(&self.view_id).await.unwrap()); + let params = DeleteSortParams { + view_id: self.view_id.clone(), + sort_type: SortType::from(&field_rev), + sort_id, + }; self.editor.delete_sort(params).await.unwrap(); + self.current_sort_rev = None; } - SortScript::AssertTextOrder { field_id, orders } => { + SortScript::AssertCellContentOrder { field_id, orders } => { let mut cells = vec![]; - let rows = self.editor.get_grid(&self.grid_id).await.unwrap().rows; + let rows = self.editor.get_grid(&self.view_id).await.unwrap().rows; for row in rows { let params = CellPathParams { - view_id: self.grid_id.clone(), + view_id: self.view_id.clone(), field_id: field_id.clone(), row_id: row.id, }; let cell = self.editor.get_cell_display_str(¶ms).await; cells.push(cell); } - assert_eq!(cells, orders) + if orders.is_empty() { + assert_eq!(cells, orders); + } else { + let len = min(cells.len(), orders.len()); + assert_eq!(cells.split_at(len).0, orders); + } + } + SortScript::UpdateTextCell { row_id, text } => { + self.recv = Some(self.editor.subscribe_view_changed(&self.view_id).await.unwrap()); + self.update_text_cell(row_id, &text).await; + } + SortScript::AssertSortChanged { + new_row_orders, + old_row_orders, + } => { + if let Some(receiver) = self.recv.take() { + assert_sort_changed( + receiver, + new_row_orders.into_iter().map(|order| order.to_owned()).collect(), + old_row_orders.into_iter().map(|order| order.to_owned()).collect(), + ) + .await; + } + } + SortScript::Wait { millis } => { + tokio::time::sleep(Duration::from_millis(millis)).await; } } } } +async fn assert_sort_changed( + mut receiver: Receiver, + new_row_orders: Vec, + old_row_orders: Vec, +) { + let stream = stream! { + loop { + tokio::select! { + changed = receiver.recv() => yield changed.unwrap(), + _ = tokio::time::sleep(Duration::from_secs(2)) => break, + }; + } + }; + + stream + .for_each(|changed| async { + match changed { + GridViewChanged::ReorderAllRowsNotification(_changed) => {} + GridViewChanged::ReorderSingleRowNotification(changed) => { + let mut old_row_orders = old_row_orders.clone(); + let old = old_row_orders.remove(changed.old_index); + old_row_orders.insert(changed.new_index, old); + assert_eq!(old_row_orders, new_row_orders); + } + _ => {} + } + }) + .await; +} + impl std::ops::Deref for GridSortTest { type Target = GridEditorTest; diff --git a/frontend/rust-lib/flowy-grid/tests/grid/sort_test/single_sort_test.rs b/frontend/rust-lib/flowy-grid/tests/grid/sort_test/single_sort_test.rs new file mode 100644 index 0000000000..3714e9fc3e --- /dev/null +++ b/frontend/rust-lib/flowy-grid/tests/grid/sort_test/single_sort_test.rs @@ -0,0 +1,257 @@ +use crate::grid::sort_test::script::{GridSortTest, SortScript::*}; +use flowy_grid::entities::FieldType; +use grid_rev_model::SortCondition; + +#[tokio::test] +async fn sort_text_by_ascending_test() { + let mut test = GridSortTest::new().await; + let text_field = test.get_first_field_rev(FieldType::RichText); + let scripts = vec![ + AssertCellContentOrder { + field_id: text_field.id.clone(), + orders: vec!["A", "", "C", "DA", "AE", "AE"], + }, + InsertSort { + field_rev: text_field.clone(), + condition: SortCondition::Ascending, + }, + AssertCellContentOrder { + field_id: text_field.id.clone(), + orders: vec!["", "A", "AE", "AE", "C", "DA"], + }, + ]; + test.run_scripts(scripts).await; +} + +#[tokio::test] +async fn sort_change_notification_by_update_text_test() { + let mut test = GridSortTest::new().await; + let text_field = test.get_first_field_rev(FieldType::RichText).clone(); + let scripts = vec![ + InsertSort { + field_rev: text_field.clone(), + condition: SortCondition::Ascending, + }, + AssertCellContentOrder { + field_id: text_field.id.clone(), + orders: vec!["", "A", "AE", "AE", "C", "DA"], + }, + // Wait the insert task to finish. The cost of time should be less than 200 milliseconds. + Wait { millis: 200 }, + ]; + test.run_scripts(scripts).await; + + let row_revs = test.get_row_revs().await; + let scripts = vec![ + UpdateTextCell { + row_id: row_revs[2].id.clone(), + text: "E".to_string(), + }, + AssertSortChanged { + old_row_orders: vec!["", "A", "E", "AE", "C", "DA"], + new_row_orders: vec!["", "A", "AE", "C", "DA", "E"], + }, + ]; + test.run_scripts(scripts).await; +} + +#[tokio::test] +async fn sort_text_by_ascending_and_delete_sort_test() { + let mut test = GridSortTest::new().await; + let text_field = test.get_first_field_rev(FieldType::RichText).clone(); + let scripts = vec![InsertSort { + field_rev: text_field.clone(), + condition: SortCondition::Ascending, + }]; + test.run_scripts(scripts).await; + let sort_rev = test.current_sort_rev.as_ref().unwrap(); + let scripts = vec![ + DeleteSort { + field_rev: text_field.clone(), + sort_id: sort_rev.id.clone(), + }, + AssertCellContentOrder { + field_id: text_field.id.clone(), + orders: vec!["A", "", "C", "DA", "AE"], + }, + ]; + test.run_scripts(scripts).await; +} + +#[tokio::test] +async fn sort_text_by_descending_test() { + let mut test = GridSortTest::new().await; + let text_field = test.get_first_field_rev(FieldType::RichText); + let scripts = vec![ + AssertCellContentOrder { + field_id: text_field.id.clone(), + orders: vec!["A", "", "C", "DA", "AE", "AE"], + }, + InsertSort { + field_rev: text_field.clone(), + condition: SortCondition::Descending, + }, + AssertCellContentOrder { + field_id: text_field.id.clone(), + orders: vec!["DA", "C", "AE", "AE", "A", ""], + }, + ]; + test.run_scripts(scripts).await; +} + +#[tokio::test] +async fn sort_checkbox_by_ascending_test() { + let mut test = GridSortTest::new().await; + let checkbox_field = test.get_first_field_rev(FieldType::Checkbox); + let scripts = vec![ + AssertCellContentOrder { + field_id: checkbox_field.id.clone(), + orders: vec!["Yes", "Yes", "No", "No", "No"], + }, + InsertSort { + field_rev: checkbox_field.clone(), + condition: SortCondition::Ascending, + }, + ]; + test.run_scripts(scripts).await; +} + +#[tokio::test] +async fn sort_checkbox_by_descending_test() { + let mut test = GridSortTest::new().await; + let checkbox_field = test.get_first_field_rev(FieldType::Checkbox); + let scripts = vec![ + AssertCellContentOrder { + field_id: checkbox_field.id.clone(), + orders: vec!["Yes", "Yes", "No", "No", "No", "Yes"], + }, + InsertSort { + field_rev: checkbox_field.clone(), + condition: SortCondition::Descending, + }, + AssertCellContentOrder { + field_id: checkbox_field.id.clone(), + orders: vec!["Yes", "Yes", "Yes", "No", "No", "No"], + }, + ]; + test.run_scripts(scripts).await; +} + +#[tokio::test] +async fn sort_date_by_ascending_test() { + let mut test = GridSortTest::new().await; + let date_field = test.get_first_field_rev(FieldType::DateTime); + let scripts = vec![ + AssertCellContentOrder { + field_id: date_field.id.clone(), + orders: vec!["2022/03/14", "2022/03/14", "2022/03/14", "2022/11/17", "2022/11/13"], + }, + InsertSort { + field_rev: date_field.clone(), + condition: SortCondition::Ascending, + }, + AssertCellContentOrder { + field_id: date_field.id.clone(), + orders: vec!["2022/03/14", "2022/03/14", "2022/03/14", "2022/11/13", "2022/11/17"], + }, + ]; + test.run_scripts(scripts).await; +} + +#[tokio::test] +async fn sort_date_by_descending_test() { + let mut test = GridSortTest::new().await; + let date_field = test.get_first_field_rev(FieldType::DateTime); + let scripts = vec![ + AssertCellContentOrder { + field_id: date_field.id.clone(), + orders: vec![ + "2022/03/14", + "2022/03/14", + "2022/03/14", + "2022/11/17", + "2022/11/13", + "2022/12/25", + ], + }, + InsertSort { + field_rev: date_field.clone(), + condition: SortCondition::Descending, + }, + AssertCellContentOrder { + field_id: date_field.id.clone(), + orders: vec![ + "2022/12/25", + "2022/11/17", + "2022/11/13", + "2022/03/14", + "2022/03/14", + "2022/03/14", + ], + }, + ]; + test.run_scripts(scripts).await; +} + +#[tokio::test] +async fn sort_number_by_descending_test() { + let mut test = GridSortTest::new().await; + let number_field = test.get_first_field_rev(FieldType::Number); + let scripts = vec![ + AssertCellContentOrder { + field_id: number_field.id.clone(), + orders: vec!["$1", "$2", "$3", "$4", "", "$5"], + }, + InsertSort { + field_rev: number_field.clone(), + condition: SortCondition::Descending, + }, + AssertCellContentOrder { + field_id: number_field.id.clone(), + orders: vec!["$5", "$4", "$3", "$2", "$1", ""], + }, + ]; + test.run_scripts(scripts).await; +} + +#[tokio::test] +async fn sort_single_select_by_descending_test() { + let mut test = GridSortTest::new().await; + let single_select = test.get_first_field_rev(FieldType::SingleSelect); + let scripts = vec![ + AssertCellContentOrder { + field_id: single_select.id.clone(), + orders: vec!["", "", "Completed", "Completed", "Planned", "Planned"], + }, + InsertSort { + field_rev: single_select.clone(), + condition: SortCondition::Descending, + }, + AssertCellContentOrder { + field_id: single_select.id.clone(), + orders: vec!["Planned", "Planned", "Completed", "Completed", "", ""], + }, + ]; + test.run_scripts(scripts).await; +} + +#[tokio::test] +async fn sort_multi_select_by_ascending_test() { + let mut test = GridSortTest::new().await; + let multi_select = test.get_first_field_rev(FieldType::MultiSelect); + let scripts = vec![ + AssertCellContentOrder { + field_id: multi_select.id.clone(), + orders: vec!["Google,Facebook", "Google,Twitter", "Facebook", "", "", ""], + }, + InsertSort { + field_rev: multi_select.clone(), + condition: SortCondition::Ascending, + }, + AssertCellContentOrder { + field_id: multi_select.id.clone(), + orders: vec!["", "", "", "Facebook", "Google,Facebook", "Google,Twitter"], + }, + ]; + test.run_scripts(scripts).await; +} diff --git a/frontend/rust-lib/flowy-grid/tests/grid/sort_test/sort_test.rs b/frontend/rust-lib/flowy-grid/tests/grid/sort_test/sort_test.rs deleted file mode 100644 index 7097c864ea..0000000000 --- a/frontend/rust-lib/flowy-grid/tests/grid/sort_test/sort_test.rs +++ /dev/null @@ -1,279 +0,0 @@ -use crate::grid::sort_test::script::{GridSortTest, SortScript::*}; -use flowy_grid::entities::{AlterSortParams, DeleteSortParams, FieldType}; -use flowy_grid::services::sort::SortType; -use grid_rev_model::SortCondition; - -#[tokio::test] -async fn sort_text_by_ascending_test() { - let mut test = GridSortTest::new().await; - let text_field = test.get_first_field_rev(FieldType::RichText); - let view_id = test.grid_id.clone(); - let scripts = vec![ - AssertTextOrder { - field_id: text_field.id.clone(), - orders: vec!["A", "", "C", "DA", "AE"], - }, - InsertSort { - params: AlterSortParams { - view_id, - field_id: text_field.id.clone(), - sort_id: None, - field_type: FieldType::RichText.into(), - condition: SortCondition::Ascending.into(), - }, - }, - AssertTextOrder { - field_id: text_field.id.clone(), - orders: vec!["", "A", "AE", "C", "DA"], - }, - ]; - test.run_scripts(scripts).await; -} - -#[tokio::test] -async fn sort_text_by_ascending_and_delete_sort_test() { - let mut test = GridSortTest::new().await; - let text_field = test.get_first_field_rev(FieldType::RichText).clone(); - let view_id = test.grid_id.clone(); - let scripts = vec![InsertSort { - params: AlterSortParams { - view_id: view_id.clone(), - field_id: text_field.id.clone(), - sort_id: None, - field_type: FieldType::RichText.into(), - condition: SortCondition::Ascending.into(), - }, - }]; - test.run_scripts(scripts).await; - let sort_rev = test.current_sort_rev.as_ref().unwrap(); - let scripts = vec![ - DeleteSort { - params: DeleteSortParams { - view_id, - sort_type: SortType::from(&text_field), - sort_id: sort_rev.id.clone(), - }, - }, - AssertTextOrder { - field_id: text_field.id.clone(), - orders: vec!["A", "", "C", "DA", "AE"], - }, - ]; - test.run_scripts(scripts).await; -} - -#[tokio::test] -async fn sort_text_by_descending_test() { - let mut test = GridSortTest::new().await; - let text_field = test.get_first_field_rev(FieldType::RichText); - let view_id = test.grid_id.clone(); - let scripts = vec![ - AssertTextOrder { - field_id: text_field.id.clone(), - orders: vec!["A", "", "C", "DA", "AE"], - }, - InsertSort { - params: AlterSortParams { - view_id, - field_id: text_field.id.clone(), - sort_id: None, - field_type: FieldType::RichText.into(), - condition: SortCondition::Descending.into(), - }, - }, - AssertTextOrder { - field_id: text_field.id.clone(), - orders: vec!["DA", "C", "AE", "A", ""], - }, - ]; - test.run_scripts(scripts).await; -} - -#[tokio::test] -async fn sort_checkbox_by_ascending_test() { - let mut test = GridSortTest::new().await; - let checkbox_field = test.get_first_field_rev(FieldType::Checkbox); - let view_id = test.grid_id.clone(); - let scripts = vec![ - AssertTextOrder { - field_id: checkbox_field.id.clone(), - orders: vec!["Yes", "Yes", "No", "No", "No"], - }, - InsertSort { - params: AlterSortParams { - view_id, - field_id: checkbox_field.id.clone(), - sort_id: None, - field_type: FieldType::Checkbox.into(), - condition: SortCondition::Ascending.into(), - }, - }, - // AssertTextOrder { - // field_id: checkbox_field.id.clone(), - // orders: vec!["No", "No", "No", "Yes", "Yes"], - // }, - ]; - test.run_scripts(scripts).await; -} - -#[tokio::test] -async fn sort_checkbox_by_descending_test() { - let mut test = GridSortTest::new().await; - let checkbox_field = test.get_first_field_rev(FieldType::Checkbox); - let view_id = test.grid_id.clone(); - let scripts = vec![ - AssertTextOrder { - field_id: checkbox_field.id.clone(), - orders: vec!["Yes", "Yes", "No", "No", "No"], - }, - InsertSort { - params: AlterSortParams { - view_id, - field_id: checkbox_field.id.clone(), - sort_id: None, - field_type: FieldType::Checkbox.into(), - condition: SortCondition::Descending.into(), - }, - }, - AssertTextOrder { - field_id: checkbox_field.id.clone(), - orders: vec!["Yes", "Yes", "No", "No", "No"], - }, - ]; - test.run_scripts(scripts).await; -} - -#[tokio::test] -async fn sort_date_by_ascending_test() { - let mut test = GridSortTest::new().await; - let date_field = test.get_first_field_rev(FieldType::DateTime); - let view_id = test.grid_id.clone(); - let scripts = vec![ - AssertTextOrder { - field_id: date_field.id.clone(), - orders: vec!["2022/03/14", "2022/03/14", "2022/03/14", "2022/11/17", "2022/11/13"], - }, - InsertSort { - params: AlterSortParams { - view_id, - field_id: date_field.id.clone(), - sort_id: None, - field_type: FieldType::DateTime.into(), - condition: SortCondition::Ascending.into(), - }, - }, - AssertTextOrder { - field_id: date_field.id.clone(), - orders: vec!["2022/03/14", "2022/03/14", "2022/03/14", "2022/11/13", "2022/11/17"], - }, - ]; - test.run_scripts(scripts).await; -} - -#[tokio::test] -async fn sort_date_by_descending_test() { - let mut test = GridSortTest::new().await; - let date_field = test.get_first_field_rev(FieldType::DateTime); - let view_id = test.grid_id.clone(); - let scripts = vec![ - AssertTextOrder { - field_id: date_field.id.clone(), - orders: vec!["2022/03/14", "2022/03/14", "2022/03/14", "2022/11/17", "2022/11/13"], - }, - InsertSort { - params: AlterSortParams { - view_id, - field_id: date_field.id.clone(), - sort_id: None, - field_type: FieldType::DateTime.into(), - condition: SortCondition::Descending.into(), - }, - }, - AssertTextOrder { - field_id: date_field.id.clone(), - orders: vec!["2022/11/17", "2022/11/13", "2022/03/14", "2022/03/14", "2022/03/14"], - }, - ]; - test.run_scripts(scripts).await; -} - -#[tokio::test] -async fn sort_number_by_descending_test() { - let mut test = GridSortTest::new().await; - let number_field = test.get_first_field_rev(FieldType::Number); - let view_id = test.grid_id.clone(); - let scripts = vec![ - AssertTextOrder { - field_id: number_field.id.clone(), - orders: vec!["$1", "$2", "$3", "$4", ""], - }, - InsertSort { - params: AlterSortParams { - view_id, - field_id: number_field.id.clone(), - sort_id: None, - field_type: FieldType::Number.into(), - condition: SortCondition::Descending.into(), - }, - }, - AssertTextOrder { - field_id: number_field.id.clone(), - orders: vec!["$4", "$3", "$2", "$1", ""], - }, - ]; - test.run_scripts(scripts).await; -} - -#[tokio::test] -async fn sort_single_select_by_descending_test() { - let mut test = GridSortTest::new().await; - let single_select = test.get_first_field_rev(FieldType::SingleSelect); - let view_id = test.grid_id.clone(); - let scripts = vec![ - AssertTextOrder { - field_id: single_select.id.clone(), - orders: vec!["", "", "Completed", "Completed", "Planned"], - }, - InsertSort { - params: AlterSortParams { - view_id, - field_id: single_select.id.clone(), - sort_id: None, - field_type: FieldType::SingleSelect.into(), - condition: SortCondition::Descending.into(), - }, - }, - AssertTextOrder { - field_id: single_select.id.clone(), - orders: vec!["Planned", "Completed", "Completed", "", ""], - }, - ]; - test.run_scripts(scripts).await; -} - -#[tokio::test] -async fn sort_multi_select_by_ascending_test() { - let mut test = GridSortTest::new().await; - let multi_select = test.get_first_field_rev(FieldType::MultiSelect); - let view_id = test.grid_id.clone(); - let scripts = vec![ - AssertTextOrder { - field_id: multi_select.id.clone(), - orders: vec!["Google,Facebook", "Google,Twitter", "Facebook", "", ""], - }, - InsertSort { - params: AlterSortParams { - view_id, - field_id: multi_select.id.clone(), - sort_id: None, - field_type: FieldType::MultiSelect.into(), - condition: SortCondition::Ascending.into(), - }, - }, - AssertTextOrder { - field_id: multi_select.id.clone(), - orders: vec!["", "", "Facebook", "Google,Facebook", "Google,Twitter"], - }, - ]; - test.run_scripts(scripts).await; -} diff --git a/frontend/rust-lib/flowy-task/src/scheduler.rs b/frontend/rust-lib/flowy-task/src/scheduler.rs index b0d9998210..5e9d599241 100644 --- a/frontend/rust-lib/flowy-task/src/scheduler.rs +++ b/frontend/rust-lib/flowy-task/src/scheduler.rs @@ -71,12 +71,12 @@ impl TaskDispatcher { Ok(result) => match result { Ok(_) => task.set_state(TaskState::Done), Err(e) => { - tracing::error!("Process {} task failed: {:?}", handler.handler_id(), e); + tracing::error!("Process {} task failed: {:?}", handler.handler_name(), e); task.set_state(TaskState::Failure); } }, Err(e) => { - tracing::error!("Process {} task timeout: {:?}", handler.handler_id(), e); + tracing::error!("Process {} task timeout: {:?}", handler.handler_name(), e); task.set_state(TaskState::Timeout); } } @@ -144,6 +144,10 @@ impl TaskRunner { pub trait TaskHandler: Send + Sync + 'static { fn handler_id(&self) -> &str; + fn handler_name(&self) -> &str { + "" + } + fn run(&self, content: TaskContent) -> BoxResultFuture<(), Error>; } @@ -155,6 +159,10 @@ where (**self).handler_id() } + fn handler_name(&self) -> &str { + (**self).handler_name() + } + fn run(&self, content: TaskContent) -> BoxResultFuture<(), Error> { (**self).run(content) } @@ -168,6 +176,10 @@ where (**self).handler_id() } + fn handler_name(&self) -> &str { + (**self).handler_name() + } + fn run(&self, content: TaskContent) -> BoxResultFuture<(), Error> { (**self).run(content) }