chore: rename trait

This commit is contained in:
appflowy
2022-03-15 11:07:18 +08:00
parent 46be04f94e
commit 50f32521c5
59 changed files with 1444 additions and 852 deletions

View File

@ -26,7 +26,7 @@ impl TextBlockEditorTest {
pub async fn new() -> Self {
let sdk = FlowySDKTest::default();
let _ = sdk.init_user().await;
let test = ViewTest::new_grid_view(&sdk).await;
let test = ViewTest::new_text_block_view(&sdk).await;
let editor = sdk.text_block_manager.open_block(&test.view.id).await.unwrap();
Self { sdk, editor }
}

View File

@ -171,7 +171,6 @@ impl ViewController {
data_type: view.data_type,
data: delta_str,
view_id: uuid(),
ext_data: view.ext_data,
plugin_type: view.plugin_type,
};

View File

@ -350,8 +350,8 @@ pub async fn create_view(sdk: &FlowySDKTest, app_id: &str, name: &str, desc: &st
desc: desc.to_string(),
thumbnail: None,
data_type,
ext_data: "".to_string(),
plugin_type: 0,
data: "".to_string(),
};
let view = FolderEventBuilder::new(sdk.clone())
.event(CreateView)

View File

@ -1,7 +1,7 @@
use crate::manager::GridManager;
use flowy_error::FlowyError;
use flowy_grid_data_model::entities::{
Cell, Grid, GridId, QueryFieldPayload, QueryRowPayload, RepeatedField, RepeatedRow,
Cell, Field, Grid, GridId, QueryFieldPayload, QueryRowPayload, RepeatedField, RepeatedRow,
};
use lib_dispatch::prelude::{data_result, AppData, Data, DataResult};
use std::sync::Arc;
@ -13,7 +13,7 @@ pub(crate) async fn get_grid_data_handler(
) -> DataResult<Grid, FlowyError> {
let grid_id: GridId = data.into_inner();
let editor = manager.open_grid(grid_id).await?;
let grid = editor.grid_data().await;
let grid = editor.grid_data().await?;
data_result(grid)
}
@ -35,7 +35,12 @@ pub(crate) async fn get_fields_handler(
) -> DataResult<RepeatedField, FlowyError> {
let payload: QueryFieldPayload = data.into_inner();
let editor = manager.get_grid_editor(&payload.grid_id)?;
let repeated_field: RepeatedField = editor.get_fields(Some(payload.field_orders)).await?.into();
let field_metas = editor.get_field_metas(Some(payload.field_orders)).await?;
let repeated_field: RepeatedField = field_metas
.into_iter()
.map(|field_meta| Field::from(field_meta))
.collect::<Vec<_>>()
.into();
data_result(repeated_field)
}

View File

@ -9,9 +9,9 @@ macro_rules! impl_from_and_to_type_option {
#[macro_export]
macro_rules! impl_from_field_type_option {
($target: ident) => {
impl std::convert::From<&Field> for $target {
fn from(field: &Field) -> $target {
match serde_json::from_str(&field.type_options) {
impl std::convert::From<&FieldMeta> for $target {
fn from(field_meta: &FieldMeta) -> $target {
match serde_json::from_str(&field_meta.type_options) {
Ok(obj) => obj,
Err(err) => {
tracing::error!("{} convert from any data failed, {:?}", stringify!($target), err);

View File

@ -119,11 +119,11 @@ impl GridBlockMetaEditorManager {
}
}
pub(crate) async fn get_all_rows(&self, grid_blocks: Vec<GridBlock>) -> FlowyResult<Vec<RowMeta>> {
pub(crate) async fn get_all_rows(&self, grid_blocks: Vec<GridBlock>) -> FlowyResult<Vec<Arc<RowMeta>>> {
let mut row_metas = vec![];
for grid_block in grid_blocks {
let editor = self.get_editor(&grid_block.id).await?;
let new_row_metas = editor.get_rows(None).await?;
let new_row_metas = editor.get_row_metas(None).await?;
new_row_metas.iter().for_each(|row_meta| {
self.block_id_by_row_id
.insert(row_meta.id.clone(), row_meta.block_id.clone());
@ -134,12 +134,23 @@ impl GridBlockMetaEditorManager {
Ok(row_metas)
}
pub(crate) async fn get_rows(&self, row_orders: &RepeatedRowOrder) -> FlowyResult<Vec<RowMeta>> {
pub(crate) async fn get_row_orders(&self, grid_blocks: Vec<GridBlock>) -> FlowyResult<Vec<RowOrder>> {
let mut row_orders = vec![];
for grid_block in grid_blocks {
let editor = self.get_editor(&grid_block.id).await?;
let row_metas = editor.get_row_metas(None).await?;
let block_row_orders = row_metas.iter().map(|row_meta| RowOrder::from(row_meta));
row_orders.extend(block_row_orders);
}
Ok(row_orders)
}
pub(crate) async fn get_rows(&self, row_orders: &RepeatedRowOrder) -> FlowyResult<Vec<Arc<RowMeta>>> {
let row_ids_per_blocks = make_row_ids_per_block(row_orders);
let mut row_metas = vec![];
for row_ids_per_block in row_ids_per_blocks {
let editor = self.get_editor(&row_ids_per_block.block_id).await?;
let new_row_metas = editor.get_rows(Some(row_ids_per_block.row_ids)).await?;
let new_row_metas = editor.get_row_metas(Some(row_ids_per_block.row_ids)).await?;
new_row_metas.iter().for_each(|row_meta| {
self.block_id_by_row_id
.insert(row_meta.id.clone(), row_meta.block_id.clone());
@ -234,14 +245,21 @@ impl ClientGridBlockMetaEditor {
Ok(())
}
pub async fn get_rows(&self, row_ids: Option<Vec<String>>) -> FlowyResult<Vec<RowMeta>> {
match row_ids {
None => Ok(self.meta_pad.read().await.all_rows()),
Some(row_ids) => {
let rows = self.meta_pad.read().await.get_rows(row_ids)?;
Ok(rows)
}
}
pub async fn get_row_metas(&self, row_ids: Option<Vec<String>>) -> FlowyResult<Vec<Arc<RowMeta>>> {
let row_metas = self.meta_pad.read().await.get_rows(row_ids)?;
Ok(row_metas)
}
pub async fn get_row_orders(&self) -> FlowyResult<Vec<RowOrder>> {
let row_orders = self
.meta_pad
.read()
.await
.get_rows(None)?
.iter()
.map(|row_meta| RowOrder::from(row_meta))
.collect::<Vec<RowOrder>>();
Ok(row_orders)
}
async fn modify<F>(&self, f: F) -> FlowyResult<()>

View File

@ -1,8 +1,8 @@
use crate::impl_from_and_to_type_option;
use crate::services::row::StringifyCellData;
use crate::services::row::CellDataSerde;
use flowy_derive::ProtoBuf;
use flowy_error::FlowyError;
use flowy_grid_data_model::entities::{Field, FieldType};
use flowy_grid_data_model::entities::{FieldMeta, FieldType};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize, Default, ProtoBuf)]
@ -12,13 +12,13 @@ pub struct CheckboxDescription {
}
impl_from_and_to_type_option!(CheckboxDescription, FieldType::Checkbox);
impl StringifyCellData for CheckboxDescription {
fn str_from_cell_data(&self, data: String) -> String {
impl CellDataSerde for CheckboxDescription {
fn deserialize_cell_data(&self, data: String) -> String {
data
}
fn str_to_cell_data(&self, s: &str) -> Result<String, FlowyError> {
let s = match string_to_bool(s) {
fn serialize_cell_data(&self, data: &str) -> Result<String, FlowyError> {
let s = match string_to_bool(data) {
true => "1",
false => "0",
};
@ -42,19 +42,19 @@ fn string_to_bool(bool_str: &str) -> bool {
#[cfg(test)]
mod tests {
use crate::services::cell::CheckboxDescription;
use crate::services::row::StringifyCellData;
use crate::services::row::CellDataSerde;
#[test]
fn checkout_box_description_test() {
let description = CheckboxDescription::default();
assert_eq!(description.str_to_cell_data("true").unwrap(), "1".to_owned());
assert_eq!(description.str_to_cell_data("1").unwrap(), "1".to_owned());
assert_eq!(description.str_to_cell_data("yes").unwrap(), "1".to_owned());
assert_eq!(description.serialize_cell_data("true").unwrap(), "1".to_owned());
assert_eq!(description.serialize_cell_data("1").unwrap(), "1".to_owned());
assert_eq!(description.serialize_cell_data("yes").unwrap(), "1".to_owned());
assert_eq!(description.str_to_cell_data("false").unwrap(), "0".to_owned());
assert_eq!(description.str_to_cell_data("no").unwrap(), "0".to_owned());
assert_eq!(description.str_to_cell_data("123").unwrap(), "0".to_owned());
assert_eq!(description.serialize_cell_data("false").unwrap(), "0".to_owned());
assert_eq!(description.serialize_cell_data("no").unwrap(), "0".to_owned());
assert_eq!(description.serialize_cell_data("123").unwrap(), "0".to_owned());
assert_eq!(description.str_from_cell_data("1".to_owned()), "1".to_owned());
assert_eq!(description.deserialize_cell_data("1".to_owned()), "1".to_owned());
}
}

View File

@ -1,11 +1,11 @@
use crate::impl_from_and_to_type_option;
use crate::services::row::StringifyCellData;
use crate::services::row::CellDataSerde;
use chrono::format::strftime::StrftimeItems;
use chrono::NaiveDateTime;
use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
use flowy_error::FlowyError;
use flowy_grid_data_model::entities::{Field, FieldType};
use flowy_grid_data_model::entities::{FieldMeta, FieldType};
use serde::{Deserialize, Serialize};
use strum_macros::EnumIter;
@ -38,8 +38,8 @@ impl DateDescription {
}
}
impl StringifyCellData for DateDescription {
fn str_from_cell_data(&self, data: String) -> String {
impl CellDataSerde for DateDescription {
fn deserialize_cell_data(&self, data: String) -> String {
match data.parse::<i64>() {
Ok(timestamp) => {
let native = NaiveDateTime::from_timestamp(timestamp, 0);
@ -52,11 +52,11 @@ impl StringifyCellData for DateDescription {
}
}
fn str_to_cell_data(&self, s: &str) -> Result<String, FlowyError> {
let timestamp = match s.parse::<i64>() {
fn serialize_cell_data(&self, data: &str) -> Result<String, FlowyError> {
let timestamp = match data.parse::<i64>() {
Ok(timestamp) => timestamp,
Err(e) => {
tracing::error!("Parse {} to i64 failed: {}", s, e);
tracing::error!("Parse {} to i64 failed: {}", data, e);
chrono::Utc::now().timestamp()
}
};
@ -149,7 +149,7 @@ impl std::default::Default for TimeFormat {
#[cfg(test)]
mod tests {
use crate::services::cell::{DateDescription, DateFormat, TimeFormat};
use crate::services::row::StringifyCellData;
use crate::services::row::CellDataSerde;
use strum::IntoEnumIterator;
#[test]
@ -167,7 +167,7 @@ mod tests {
);
assert_eq!(
"Mar 14,2022 17:56".to_owned(),
description.str_from_cell_data("1647251762".to_owned())
description.deserialize_cell_data("1647251762".to_owned())
);
}
DateFormat::US => {
@ -177,7 +177,7 @@ mod tests {
);
assert_eq!(
"2022/03/14 17:56".to_owned(),
description.str_from_cell_data("1647251762".to_owned())
description.deserialize_cell_data("1647251762".to_owned())
);
}
DateFormat::ISO => {
@ -187,7 +187,7 @@ mod tests {
);
assert_eq!(
"2022-03-14 17:56".to_owned(),
description.str_from_cell_data("1647251762".to_owned())
description.deserialize_cell_data("1647251762".to_owned())
);
}
DateFormat::Local => {
@ -197,7 +197,7 @@ mod tests {
);
assert_eq!(
"2022/03/14 17:56".to_owned(),
description.str_from_cell_data("1647251762".to_owned())
description.deserialize_cell_data("1647251762".to_owned())
);
}
}
@ -217,7 +217,7 @@ mod tests {
);
assert_eq!(
"Mar 14,2022 17:56".to_owned(),
description.str_from_cell_data("1647251762".to_owned())
description.deserialize_cell_data("1647251762".to_owned())
);
}
TimeFormat::TwelveHour => {
@ -227,7 +227,7 @@ mod tests {
);
assert_eq!(
"Mar 14,2022 05:56:02 PM".to_owned(),
description.str_from_cell_data("1647251762".to_owned())
description.deserialize_cell_data("1647251762".to_owned())
);
}
}
@ -237,6 +237,6 @@ mod tests {
#[test]
fn date_description_invalid_data_test() {
let description = DateDescription::default();
description.str_to_cell_data("he").unwrap();
description.serialize_cell_data("he").unwrap();
}
}

View File

@ -1,8 +1,8 @@
use crate::impl_from_and_to_type_option;
use crate::services::row::StringifyCellData;
use crate::services::row::CellDataSerde;
use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
use flowy_error::FlowyError;
use flowy_grid_data_model::entities::{Field, FieldType};
use flowy_grid_data_model::entities::{FieldMeta, FieldType};
use lazy_static::lazy_static;
use rust_decimal::prelude::Zero;
use rust_decimal::Decimal;
@ -119,8 +119,8 @@ impl NumberDescription {
}
}
impl StringifyCellData for NumberDescription {
fn str_from_cell_data(&self, data: String) -> String {
impl CellDataSerde for NumberDescription {
fn deserialize_cell_data(&self, data: String) -> String {
match self.format {
NumberFormat::Number => data,
NumberFormat::USD => self.money_from_str(&data, USD),
@ -129,8 +129,8 @@ impl StringifyCellData for NumberDescription {
}
}
fn str_to_cell_data(&self, s: &str) -> Result<String, FlowyError> {
Ok(self.strip_symbol(s))
fn serialize_cell_data(&self, data: &str) -> Result<String, FlowyError> {
Ok(self.strip_symbol(data))
}
}
@ -145,30 +145,42 @@ fn make_strip_symbol() -> Vec<String> {
#[cfg(test)]
mod tests {
use crate::services::cell::{NumberDescription, NumberFormat};
use crate::services::row::StringifyCellData;
use crate::services::row::CellDataSerde;
use strum::IntoEnumIterator;
#[test]
fn number_description_test() {
let mut description = NumberDescription::default();
assert_eq!(description.str_to_cell_data("¥18,443").unwrap(), "18443".to_owned());
assert_eq!(description.str_to_cell_data("$18,443").unwrap(), "18443".to_owned());
assert_eq!(description.str_to_cell_data("€18.443").unwrap(), "18443".to_owned());
assert_eq!(description.serialize_cell_data("¥18,443").unwrap(), "18443".to_owned());
assert_eq!(description.serialize_cell_data("$18,443").unwrap(), "18443".to_owned());
assert_eq!(description.serialize_cell_data("€18.443").unwrap(), "18443".to_owned());
for format in NumberFormat::iter() {
description.format = format;
match format {
NumberFormat::Number => {
assert_eq!(description.str_from_cell_data("18443".to_owned()), "18443".to_owned());
assert_eq!(
description.deserialize_cell_data("18443".to_owned()),
"18443".to_owned()
);
}
NumberFormat::USD => {
assert_eq!(description.str_from_cell_data("18443".to_owned()), "$18,443".to_owned());
assert_eq!(
description.deserialize_cell_data("18443".to_owned()),
"$18,443".to_owned()
);
}
NumberFormat::CNY => {
assert_eq!(description.str_from_cell_data("18443".to_owned()), "¥18,443".to_owned());
assert_eq!(
description.deserialize_cell_data("18443".to_owned()),
"¥18,443".to_owned()
);
}
NumberFormat::EUR => {
assert_eq!(description.str_from_cell_data("18443".to_owned()), "€18.443".to_owned());
assert_eq!(
description.deserialize_cell_data("18443".to_owned()),
"€18.443".to_owned()
);
}
}
}
@ -183,23 +195,26 @@ mod tests {
description.format = format;
match format {
NumberFormat::Number => {
assert_eq!(description.str_from_cell_data("18443".to_owned()), "18443".to_owned());
assert_eq!(
description.deserialize_cell_data("18443".to_owned()),
"18443".to_owned()
);
}
NumberFormat::USD => {
assert_eq!(
description.str_from_cell_data("18443".to_owned()),
description.deserialize_cell_data("18443".to_owned()),
"$1,844.3".to_owned()
);
}
NumberFormat::CNY => {
assert_eq!(
description.str_from_cell_data("18443".to_owned()),
description.deserialize_cell_data("18443".to_owned()),
"¥1,844.3".to_owned()
);
}
NumberFormat::EUR => {
assert_eq!(
description.str_from_cell_data("18443".to_owned()),
description.deserialize_cell_data("18443".to_owned()),
"€1.844,3".to_owned()
);
}
@ -216,23 +231,26 @@ mod tests {
description.format = format;
match format {
NumberFormat::Number => {
assert_eq!(description.str_from_cell_data("18443".to_owned()), "18443".to_owned());
assert_eq!(
description.deserialize_cell_data("18443".to_owned()),
"18443".to_owned()
);
}
NumberFormat::USD => {
assert_eq!(
description.str_from_cell_data("18443".to_owned()),
description.deserialize_cell_data("18443".to_owned()),
"-$18,443".to_owned()
);
}
NumberFormat::CNY => {
assert_eq!(
description.str_from_cell_data("18443".to_owned()),
description.deserialize_cell_data("18443".to_owned()),
"-¥18,443".to_owned()
);
}
NumberFormat::EUR => {
assert_eq!(
description.str_from_cell_data("18443".to_owned()),
description.deserialize_cell_data("18443".to_owned()),
"-€18.443".to_owned()
);
}

View File

@ -1,9 +1,9 @@
use crate::impl_from_and_to_type_option;
use crate::services::row::StringifyCellData;
use crate::services::row::CellDataSerde;
use crate::services::util::*;
use flowy_derive::ProtoBuf;
use flowy_error::FlowyError;
use flowy_grid_data_model::entities::{Field, FieldType};
use flowy_grid_data_model::entities::{FieldMeta, FieldType};
use serde::{Deserialize, Serialize};
// Single select
@ -17,13 +17,13 @@ pub struct SingleSelectDescription {
}
impl_from_and_to_type_option!(SingleSelectDescription, FieldType::SingleSelect);
impl StringifyCellData for SingleSelectDescription {
fn str_from_cell_data(&self, data: String) -> String {
impl CellDataSerde for SingleSelectDescription {
fn deserialize_cell_data(&self, data: String) -> String {
data
}
fn str_to_cell_data(&self, s: &str) -> Result<String, FlowyError> {
Ok(select_option_id_from_data(s.to_owned(), true))
fn serialize_cell_data(&self, data: &str) -> Result<String, FlowyError> {
Ok(select_option_id_from_data(data.to_owned(), true))
}
}
@ -37,13 +37,13 @@ pub struct MultiSelectDescription {
pub disable_color: bool,
}
impl_from_and_to_type_option!(MultiSelectDescription, FieldType::MultiSelect);
impl StringifyCellData for MultiSelectDescription {
fn str_from_cell_data(&self, data: String) -> String {
impl CellDataSerde for MultiSelectDescription {
fn deserialize_cell_data(&self, data: String) -> String {
data
}
fn str_to_cell_data(&self, s: &str) -> Result<String, FlowyError> {
Ok(select_option_id_from_data(s.to_owned(), false))
fn serialize_cell_data(&self, data: &str) -> Result<String, FlowyError> {
Ok(select_option_id_from_data(data.to_owned(), false))
}
}
@ -84,14 +84,14 @@ impl SelectOption {
#[cfg(test)]
mod tests {
use crate::services::cell::{MultiSelectDescription, SingleSelectDescription};
use crate::services::row::StringifyCellData;
use crate::services::row::CellDataSerde;
#[test]
fn selection_description_test() {
let description = SingleSelectDescription::default();
assert_eq!(description.str_to_cell_data("1,2,3").unwrap(), "1".to_owned());
assert_eq!(description.serialize_cell_data("1,2,3").unwrap(), "1".to_owned());
let description = MultiSelectDescription::default();
assert_eq!(description.str_to_cell_data("1,2,3").unwrap(), "1,2,3".to_owned());
assert_eq!(description.serialize_cell_data("1,2,3").unwrap(), "1,2,3".to_owned());
}
}

View File

@ -1,9 +1,9 @@
use crate::impl_from_and_to_type_option;
use crate::services::row::StringifyCellData;
use crate::services::row::CellDataSerde;
use flowy_derive::ProtoBuf;
use flowy_error::FlowyError;
use flowy_grid_data_model::entities::{Field, FieldType};
use flowy_grid_data_model::entities::{FieldMeta, FieldType};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Default, Serialize, Deserialize, ProtoBuf)]
@ -13,12 +13,12 @@ pub struct RichTextDescription {
}
impl_from_and_to_type_option!(RichTextDescription, FieldType::RichText);
impl StringifyCellData for RichTextDescription {
fn str_from_cell_data(&self, data: String) -> String {
impl CellDataSerde for RichTextDescription {
fn deserialize_cell_data(&self, data: String) -> String {
data
}
fn str_to_cell_data(&self, s: &str) -> Result<String, FlowyError> {
Ok(s.to_owned())
fn serialize_cell_data(&self, data: &str) -> Result<String, FlowyError> {
Ok(data.to_owned())
}
}

View File

@ -1,55 +1,55 @@
use flowy_grid_data_model::entities::{Field, FieldType};
use flowy_grid_data_model::entities::{FieldMeta, FieldType};
pub struct FieldBuilder {
field: Field,
field_meta: FieldMeta,
type_options_builder: Box<dyn TypeOptionsBuilder>,
}
impl FieldBuilder {
pub fn new<T: TypeOptionsBuilder + 'static>(type_options_builder: T) -> Self {
let field = Field::new("Name", "", FieldType::RichText);
let field_meta = FieldMeta::new("Name", "", FieldType::RichText);
Self {
field,
field_meta,
type_options_builder: Box::new(type_options_builder),
}
}
pub fn name(mut self, name: &str) -> Self {
self.field.name = name.to_owned();
self.field_meta.name = name.to_owned();
self
}
pub fn desc(mut self, desc: &str) -> Self {
self.field.desc = desc.to_owned();
self.field_meta.desc = desc.to_owned();
self
}
pub fn field_type(mut self, field_type: FieldType) -> Self {
self.field.field_type = field_type;
self.field_meta.field_type = field_type;
self
}
pub fn visibility(mut self, visibility: bool) -> Self {
self.field.visibility = visibility;
self.field_meta.visibility = visibility;
self
}
pub fn width(mut self, width: i32) -> Self {
self.field.width = width;
self.field_meta.width = width;
self
}
pub fn frozen(mut self, frozen: bool) -> Self {
self.field.frozen = frozen;
self.field_meta.frozen = frozen;
self
}
pub fn build(mut self) -> Field {
assert_eq!(self.field.field_type, self.type_options_builder.field_type());
pub fn build(mut self) -> FieldMeta {
assert_eq!(self.field_meta.field_type, self.type_options_builder.field_type());
let type_options = self.type_options_builder.build();
self.field.type_options = type_options;
self.field
self.field_meta.type_options = type_options;
self.field_meta
}
}

View File

@ -7,7 +7,7 @@ use flowy_collaboration::entities::revision::Revision;
use flowy_collaboration::util::make_delta_from_revisions;
use flowy_error::{FlowyError, FlowyResult};
use flowy_grid_data_model::entities::{
CellMetaChangeset, Field, FieldChangeset, Grid, GridBlock, GridBlockChangeset, RepeatedFieldOrder,
CellMetaChangeset, Field, FieldChangeset, FieldMeta, Grid, GridBlock, GridBlockChangeset, RepeatedFieldOrder,
RepeatedRowOrder, Row, RowMeta, RowMetaChangeset,
};
use std::collections::HashMap;
@ -56,8 +56,8 @@ impl ClientGridEditor {
}))
}
pub async fn create_field(&self, field: Field) -> FlowyResult<()> {
let _ = self.modify(|grid| Ok(grid.create_field(field)?)).await?;
pub async fn create_field(&self, field_meta: FieldMeta) -> FlowyResult<()> {
let _ = self.modify(|grid| Ok(grid.create_field(field_meta)?)).await?;
Ok(())
}
@ -82,9 +82,9 @@ impl ClientGridEditor {
}
pub async fn create_row(&self) -> FlowyResult<()> {
let fields = self.grid_meta_pad.read().await.get_fields(None)?;
let field_metas = self.grid_meta_pad.read().await.get_field_metas(None)?;
let block_id = self.last_block_id().await?;
let row = row_meta_from_context(&block_id, CreateRowContextBuilder::new(&fields).build());
let row = row_meta_from_context(&block_id, CreateRowContextBuilder::new(&field_metas).build());
let row_count = self.block_meta_manager.create_row(row).await?;
let changeset = GridBlockChangeset::from_row_count(&block_id, row_count);
let _ = self.update_block(changeset).await?;
@ -119,12 +119,12 @@ impl ClientGridEditor {
}
pub async fn get_rows(&self, row_orders: Option<RepeatedRowOrder>) -> FlowyResult<Vec<Row>> {
let row_metas = self.get_row_metas(&row_orders).await?;
let fields = self.grid_meta_pad.read().await.get_fields(None)?;
let row_metas = self.get_row_metas(row_orders.as_ref()).await?;
let field_meta = self.grid_meta_pad.read().await.get_field_metas(None)?;
match row_orders {
None => Ok(make_rows(&fields, row_metas)),
None => Ok(make_rows(&field_meta, row_metas)),
Some(row_orders) => {
let mut row_map: HashMap<String, Row> = make_row_by_row_id(&fields, row_metas);
let mut row_map: HashMap<String, Row> = make_row_by_row_id(&field_meta, row_metas);
let rows = row_orders
.iter()
.flat_map(|row_order| row_map.remove(&row_order.row_id))
@ -134,7 +134,7 @@ impl ClientGridEditor {
}
}
pub async fn get_row_metas(&self, row_orders: &Option<RepeatedRowOrder>) -> FlowyResult<Vec<RowMeta>> {
pub async fn get_row_metas(&self, row_orders: Option<&RepeatedRowOrder>) -> FlowyResult<Vec<Arc<RowMeta>>> {
match row_orders {
None => {
let grid_blocks = self.grid_meta_pad.read().await.get_blocks();
@ -156,13 +156,20 @@ impl ClientGridEditor {
Ok(())
}
pub async fn grid_data(&self) -> Grid {
todo!()
pub async fn grid_data(&self) -> FlowyResult<Grid> {
let field_orders = self.grid_meta_pad.read().await.get_field_orders();
let grid_blocks = self.grid_meta_pad.read().await.get_blocks();
let row_orders = self.block_meta_manager.get_row_orders(grid_blocks).await?;
Ok(Grid {
id: self.grid_id.clone(),
field_orders,
row_orders,
})
}
pub async fn get_fields(&self, field_orders: Option<RepeatedFieldOrder>) -> FlowyResult<Vec<Field>> {
let fields = self.grid_meta_pad.read().await.get_fields(field_orders)?;
Ok(fields)
pub async fn get_field_metas(&self, field_orders: Option<RepeatedFieldOrder>) -> FlowyResult<Vec<FieldMeta>> {
let field_meta = self.grid_meta_pad.read().await.get_field_metas(field_orders)?;
Ok(field_meta)
}
pub async fn get_blocks(&self) -> FlowyResult<Vec<GridBlock>> {

View File

@ -0,0 +1,32 @@
use crate::services::cell::*;
use flowy_error::FlowyError;
use flowy_grid_data_model::entities::{FieldMeta, FieldType};
pub trait CellDataSerde {
fn deserialize_cell_data(&self, data: String) -> String;
fn serialize_cell_data(&self, data: &str) -> Result<String, FlowyError>;
}
#[allow(dead_code)]
pub fn serialize_cell_data(data: &str, field: &FieldMeta) -> Result<String, FlowyError> {
match field.field_type {
FieldType::RichText => RichTextDescription::from(field).serialize_cell_data(data),
FieldType::Number => NumberDescription::from(field).serialize_cell_data(data),
FieldType::DateTime => DateDescription::from(field).serialize_cell_data(data),
FieldType::SingleSelect => SingleSelectDescription::from(field).serialize_cell_data(data),
FieldType::MultiSelect => MultiSelectDescription::from(field).serialize_cell_data(data),
FieldType::Checkbox => CheckboxDescription::from(field).serialize_cell_data(data),
}
}
pub fn deserialize_cell_data(data: String, field: &FieldMeta) -> Result<String, FlowyError> {
let s = match field.field_type {
FieldType::RichText => RichTextDescription::from(field).deserialize_cell_data(data),
FieldType::Number => NumberDescription::from(field).deserialize_cell_data(data),
FieldType::DateTime => DateDescription::from(field).deserialize_cell_data(data),
FieldType::SingleSelect => SingleSelectDescription::from(field).deserialize_cell_data(data),
FieldType::MultiSelect => MultiSelectDescription::from(field).deserialize_cell_data(data),
FieldType::Checkbox => CheckboxDescription::from(field).deserialize_cell_data(data),
};
Ok(s)
}

View File

@ -1,33 +0,0 @@
use crate::services::cell::*;
use flowy_error::FlowyError;
use flowy_grid_data_model::entities::{Field, FieldType};
pub trait StringifyCellData {
fn str_from_cell_data(&self, data: String) -> String;
fn str_to_cell_data(&self, s: &str) -> Result<String, FlowyError>;
}
#[allow(dead_code)]
pub fn stringify_serialize(field: &Field, s: &str) -> Result<String, FlowyError> {
match field.field_type {
FieldType::RichText => RichTextDescription::from(field).str_to_cell_data(s),
FieldType::Number => NumberDescription::from(field).str_to_cell_data(s),
FieldType::DateTime => DateDescription::from(field).str_to_cell_data(s),
FieldType::SingleSelect => SingleSelectDescription::from(field).str_to_cell_data(s),
FieldType::MultiSelect => MultiSelectDescription::from(field).str_to_cell_data(s),
FieldType::Checkbox => CheckboxDescription::from(field).str_to_cell_data(s),
}
}
pub(crate) fn stringify_deserialize(data: String, field: &Field) -> Result<String, FlowyError> {
// let _ = check_type_id(&data, field)?;
let s = match field.field_type {
FieldType::RichText => RichTextDescription::from(field).str_from_cell_data(data),
FieldType::Number => NumberDescription::from(field).str_from_cell_data(data),
FieldType::DateTime => DateDescription::from(field).str_from_cell_data(data),
FieldType::SingleSelect => SingleSelectDescription::from(field).str_from_cell_data(data),
FieldType::MultiSelect => MultiSelectDescription::from(field).str_from_cell_data(data),
FieldType::Checkbox => CheckboxDescription::from(field).str_from_cell_data(data),
};
Ok(s)
}

View File

@ -1,7 +1,7 @@
mod cell_stringify;
mod cell_data_serde;
mod row_builder;
mod row_loader;
pub use cell_stringify::*;
pub use cell_data_serde::*;
pub use row_builder::*;
pub(crate) use row_loader::*;

View File

@ -1,14 +1,14 @@
use flowy_grid_data_model::entities::{CellMeta, Field, RowMeta, DEFAULT_ROW_HEIGHT};
use flowy_grid_data_model::entities::{CellMeta, FieldMeta, RowMeta, DEFAULT_ROW_HEIGHT};
use std::collections::HashMap;
pub struct CreateRowContextBuilder<'a> {
#[allow(dead_code)]
fields: &'a [Field],
fields: &'a [FieldMeta],
ctx: CreateRowContext,
}
impl<'a> CreateRowContextBuilder<'a> {
pub fn new(fields: &'a [Field]) -> Self {
pub fn new(fields: &'a [FieldMeta]) -> Self {
let ctx = CreateRowContext {
row_id: uuid::Uuid::new_v4().to_string(),
cell_by_field_id: Default::default(),

View File

@ -1,7 +1,8 @@
use crate::services::row::stringify_deserialize;
use flowy_grid_data_model::entities::{Cell, CellMeta, Field, Row, RowMeta, RowOrder};
use crate::services::row::deserialize_cell_data;
use flowy_grid_data_model::entities::{Cell, CellMeta, FieldMeta, Row, RowMeta, RowOrder};
use rayon::iter::{IntoParallelIterator, ParallelIterator};
use std::collections::HashMap;
use std::sync::Arc;
pub(crate) struct RowIdsPerBlock {
pub(crate) block_id: String,
@ -21,15 +22,16 @@ pub(crate) fn make_row_ids_per_block(row_orders: &[RowOrder]) -> Vec<RowIdsPerBl
map.into_values().collect::<Vec<_>>()
}
pub(crate) fn make_rows(fields: &[Field], row_metas: Vec<RowMeta>) -> Vec<Row> {
pub(crate) fn make_rows(fields: &[FieldMeta], row_metas: Vec<Arc<RowMeta>>) -> Vec<Row> {
let field_map = fields
.iter()
.map(|field| (&field.id, field))
.collect::<HashMap<&String, &Field>>();
.collect::<HashMap<&String, &FieldMeta>>();
let make_row = |row_meta: RowMeta| {
let make_row = |row_meta: Arc<RowMeta>| {
let cell_by_field_id = row_meta
.cell_by_field_id
.clone()
.into_par_iter()
.flat_map(|(field_id, raw_cell)| make_cell(&field_map, field_id, raw_cell))
.collect::<HashMap<String, Cell>>();
@ -45,9 +47,9 @@ pub(crate) fn make_rows(fields: &[Field], row_metas: Vec<RowMeta>) -> Vec<Row> {
}
#[inline(always)]
fn make_cell(field_map: &HashMap<&String, &Field>, field_id: String, raw_cell: CellMeta) -> Option<(String, Cell)> {
let field = field_map.get(&field_id)?;
match stringify_deserialize(raw_cell.data, field) {
fn make_cell(field_map: &HashMap<&String, &FieldMeta>, field_id: String, raw_cell: CellMeta) -> Option<(String, Cell)> {
let field_meta = field_map.get(&field_id)?;
match deserialize_cell_data(raw_cell.data, field_meta) {
Ok(content) => {
let cell = Cell::new(&field_id, content);
Some((field_id, cell))
@ -59,15 +61,16 @@ fn make_cell(field_map: &HashMap<&String, &Field>, field_id: String, raw_cell: C
}
}
pub(crate) fn make_row_by_row_id(fields: &[Field], row_metas: Vec<RowMeta>) -> HashMap<String, Row> {
pub(crate) fn make_row_by_row_id(fields: &[FieldMeta], row_metas: Vec<Arc<RowMeta>>) -> HashMap<String, Row> {
let field_map = fields
.iter()
.map(|field| (&field.id, field))
.collect::<HashMap<&String, &Field>>();
.collect::<HashMap<&String, &FieldMeta>>();
let make_row = |row_meta: RowMeta| {
let make_row = |row_meta: Arc<RowMeta>| {
let cell_by_field_id = row_meta
.cell_by_field_id
.clone()
.into_par_iter()
.flat_map(|(field_id, raw_cell)| make_cell(&field_map, field_id, raw_cell))
.collect::<HashMap<String, Cell>>();

View File

@ -1,7 +1,7 @@
use crate::grid::script::EditorScript::*;
use crate::grid::script::*;
use flowy_grid::services::cell::*;
use flowy_grid::services::row::{CreateRowContextBuilder, StringifyCellData};
use flowy_grid::services::row::{deserialize_cell_data, serialize_cell_data, CellDataSerde, CreateRowContextBuilder};
use flowy_grid_data_model::entities::{FieldChangeset, FieldType, GridBlock, GridBlockChangeset, RowMetaChangeset};
#[tokio::test]
@ -17,19 +17,19 @@ async fn grid_create_field() {
let scripts = vec![
AssertFieldCount(2),
CreateField {
field: text_field.clone(),
field_meta: text_field.clone(),
},
AssertFieldEqual {
field_index: 2,
field: text_field,
field_meta: text_field,
},
AssertFieldCount(3),
CreateField {
field: single_select_field.clone(),
field_meta: single_select_field.clone(),
},
AssertFieldEqual {
field_index: 3,
field: single_select_field,
field_meta: single_select_field,
},
AssertFieldCount(4),
];
@ -42,11 +42,11 @@ async fn grid_create_duplicate_field() {
let scripts = vec![
AssertFieldCount(2),
CreateField {
field: text_field.clone(),
field_meta: text_field.clone(),
},
AssertFieldCount(3),
CreateField {
field: text_field.clone(),
field_meta: text_field.clone(),
},
AssertFieldCount(3),
];
@ -69,12 +69,12 @@ async fn grid_update_field_with_empty_change() {
let scripts = vec![
CreateField {
field: single_select_field.clone(),
field_meta: single_select_field.clone(),
},
UpdateField { changeset },
AssertFieldEqual {
field_index: 2,
field: single_select_field,
field_meta: single_select_field,
},
];
GridEditorTest::new().await.run_scripts(scripts).await;
@ -105,12 +105,12 @@ async fn grid_update_field() {
let scripts = vec![
CreateField {
field: single_select_field.clone(),
field_meta: single_select_field.clone(),
},
UpdateField { changeset },
AssertFieldEqual {
field_index: 2,
field: cloned_field,
field_meta: cloned_field,
},
AssertGridMetaPad,
];
@ -122,10 +122,10 @@ async fn grid_delete_field() {
let text_field = create_text_field();
let scripts = vec![
CreateField {
field: text_field.clone(),
field_meta: text_field.clone(),
},
AssertFieldCount(3),
DeleteField { field: text_field },
DeleteField { field_meta: text_field },
AssertFieldCount(2),
];
GridEditorTest::new().await.run_scripts(scripts).await;
@ -177,7 +177,7 @@ async fn grid_create_row() {
#[tokio::test]
async fn grid_create_row2() {
let mut test = GridEditorTest::new().await;
let create_row_context = CreateRowContextBuilder::new(&test.fields).build();
let create_row_context = CreateRowContextBuilder::new(&test.field_metas).build();
let scripts = vec![
AssertRowCount(3),
CreateRow {
@ -191,7 +191,7 @@ async fn grid_create_row2() {
#[tokio::test]
async fn grid_update_row() {
let mut test = GridEditorTest::new().await;
let context = CreateRowContextBuilder::new(&test.fields).build();
let context = CreateRowContextBuilder::new(&test.field_metas).build();
let changeset = RowMetaChangeset {
row_id: context.row_id.clone(),
height: None,
@ -214,8 +214,8 @@ async fn grid_update_row() {
#[tokio::test]
async fn grid_delete_row() {
let mut test = GridEditorTest::new().await;
let context_1 = CreateRowContextBuilder::new(&test.fields).build();
let context_2 = CreateRowContextBuilder::new(&test.fields).build();
let context_1 = CreateRowContextBuilder::new(&test.field_metas).build();
let context_2 = CreateRowContextBuilder::new(&test.field_metas).build();
let row_ids = vec![context_1.row_id.clone(), context_2.row_id.clone()];
let scripts = vec![
AssertRowCount(3),
@ -240,26 +240,26 @@ async fn grid_delete_row() {
#[tokio::test]
async fn grid_update_cell() {
let mut test = GridEditorTest::new().await;
let mut builder = CreateRowContextBuilder::new(&test.fields);
for field in &test.fields {
let mut builder = CreateRowContextBuilder::new(&test.field_metas);
for field in &test.field_metas {
match field.field_type {
FieldType::RichText => {
builder = builder.add_cell(&field.id, "hello world".to_owned());
let data = serialize_cell_data("hello world", field).unwrap();
builder = builder.add_cell(&field.id, data);
}
FieldType::Number => {
let description = NumberDescription::from(field);
let data = description.str_to_cell_data("¥18,443").unwrap();
let data = serialize_cell_data("¥18,443", field).unwrap();
builder = builder.add_cell(&field.id, data);
}
FieldType::DateTime => {
let description = DateDescription::from(field);
let data = description.str_to_cell_data("1647251762").unwrap();
let data = serialize_cell_data("1647251762", field).unwrap();
builder = builder.add_cell(&field.id, data);
}
FieldType::SingleSelect => {
let description = SingleSelectDescription::from(field);
let options = description.options.first().unwrap();
let data = description.str_to_cell_data(&options.id).unwrap();
let data = description.serialize_cell_data(&options.id).unwrap();
builder = builder.add_cell(&field.id, data);
}
FieldType::MultiSelect => {
@ -270,12 +270,11 @@ async fn grid_update_cell() {
.map(|option| option.id.clone())
.collect::<Vec<_>>()
.join(",");
let data = description.str_to_cell_data(&options).unwrap();
let data = description.serialize_cell_data(&options).unwrap();
builder = builder.add_cell(&field.id, data);
}
FieldType::Checkbox => {
let description = CheckboxDescription::from(field);
let data = description.str_to_cell_data("false").unwrap();
let data = serialize_cell_data("false", field).unwrap();
builder = builder.add_cell(&field.id, data);
}
}

View File

@ -3,7 +3,7 @@ use flowy_grid::services::field::*;
use flowy_grid::services::grid_editor::{ClientGridEditor, GridPadBuilder};
use flowy_grid::services::row::CreateRowContext;
use flowy_grid_data_model::entities::{
CellMetaChangeset, Field, FieldChangeset, FieldType, GridBlock, GridBlockChangeset, RowMeta, RowMetaChangeset,
CellMetaChangeset, FieldChangeset, FieldMeta, FieldType, GridBlock, GridBlockChangeset, RowMeta, RowMetaChangeset,
};
use flowy_sync::REVISION_WRITE_INTERVAL_IN_MILLIS;
use flowy_test::helper::ViewTest;
@ -14,18 +14,18 @@ use tokio::time::sleep;
pub enum EditorScript {
CreateField {
field: Field,
field_meta: FieldMeta,
},
UpdateField {
changeset: FieldChangeset,
},
DeleteField {
field: Field,
field_meta: FieldMeta,
},
AssertFieldCount(usize),
AssertFieldEqual {
field_index: usize,
field: Field,
field_meta: FieldMeta,
},
CreateBlock {
block: GridBlock,
@ -68,27 +68,31 @@ pub struct GridEditorTest {
pub sdk: FlowySDKTest,
pub grid_id: String,
pub editor: Arc<ClientGridEditor>,
pub fields: Vec<Field>,
pub field_metas: Vec<FieldMeta>,
pub grid_blocks: Vec<GridBlock>,
pub row_metas: Vec<RowMeta>,
pub row_metas: Vec<Arc<RowMeta>>,
}
impl GridEditorTest {
pub async fn new() -> Self {
Self::with_data("".to_owned()).await
}
pub async fn with_data(data: String) -> Self {
let sdk = FlowySDKTest::default();
let _ = sdk.init_user().await;
let test = ViewTest::new_grid_view(&sdk).await;
let test = ViewTest::new_grid_view(&sdk, data).await;
let editor = sdk.grid_manager.open_grid(&test.view.id).await.unwrap();
let fields = editor.get_fields(None).await.unwrap();
let fields = editor.get_field_metas(None).await.unwrap();
let grid_blocks = editor.get_blocks().await.unwrap();
let row_metas = editor.get_row_metas(&None).await.unwrap();
let row_metas = editor.get_row_metas(None).await.unwrap();
let grid_id = test.view.id;
Self {
sdk,
grid_id,
editor,
fields,
field_metas: fields,
grid_blocks,
row_metas,
}
@ -107,26 +111,28 @@ impl GridEditorTest {
let _cache = rev_manager.revision_cache().await;
match script {
EditorScript::CreateField { field } => {
EditorScript::CreateField { field_meta: field } => {
self.editor.create_field(field).await.unwrap();
self.fields = self.editor.get_fields(None).await.unwrap();
self.field_metas = self.editor.get_field_metas(None).await.unwrap();
}
EditorScript::UpdateField { changeset: change } => {
self.editor.update_field(change).await.unwrap();
self.fields = self.editor.get_fields(None).await.unwrap();
self.field_metas = self.editor.get_field_metas(None).await.unwrap();
}
EditorScript::DeleteField { field } => {
EditorScript::DeleteField { field_meta: field } => {
self.editor.delete_field(&field.id).await.unwrap();
self.fields = self.editor.get_fields(None).await.unwrap();
self.field_metas = self.editor.get_field_metas(None).await.unwrap();
}
EditorScript::AssertFieldCount(count) => {
assert_eq!(self.editor.get_fields(None).await.unwrap().len(), count);
assert_eq!(self.editor.get_field_metas(None).await.unwrap().len(), count);
}
EditorScript::AssertFieldEqual { field_index, field } => {
let repeated_fields = self.editor.get_fields(None).await.unwrap();
let compared_field = repeated_fields[field_index].clone();
assert_eq!(compared_field, field);
EditorScript::AssertFieldEqual {
field_index,
field_meta,
} => {
let field_metas = self.editor.get_field_metas(None).await.unwrap();
assert_eq!(field_metas[field_index].clone(), field_meta);
}
EditorScript::CreateBlock { block } => {
self.editor.create_block(block).await.unwrap();
@ -153,18 +159,18 @@ impl GridEditorTest {
}
EditorScript::CreateEmptyRow => {
self.editor.create_row().await.unwrap();
self.row_metas = self.editor.get_row_metas(&None).await.unwrap();
self.row_metas = self.editor.get_row_metas(None).await.unwrap();
self.grid_blocks = self.editor.get_blocks().await.unwrap();
}
EditorScript::CreateRow { context } => {
self.editor.insert_rows(vec![context]).await.unwrap();
self.row_metas = self.editor.get_row_metas(&None).await.unwrap();
self.row_metas = self.editor.get_row_metas(None).await.unwrap();
self.grid_blocks = self.editor.get_blocks().await.unwrap();
}
EditorScript::UpdateRow { changeset: change } => self.editor.update_row(change).await.unwrap(),
EditorScript::DeleteRow { row_ids } => {
self.editor.delete_rows(row_ids).await.unwrap();
self.row_metas = self.editor.get_row_metas(&None).await.unwrap();
self.row_metas = self.editor.get_row_metas(None).await.unwrap();
self.grid_blocks = self.editor.get_blocks().await.unwrap();
}
EditorScript::AssertRow { changeset } => {
@ -180,7 +186,7 @@ impl GridEditorTest {
}
EditorScript::UpdateCell { changeset } => {
self.editor.update_cell(changeset).await.unwrap();
self.row_metas = self.editor.get_row_metas(&None).await.unwrap();
self.row_metas = self.editor.get_row_metas(None).await.unwrap();
}
EditorScript::AssertRowCount(count) => {
assert_eq!(self.editor.get_rows(None).await.unwrap().len(), count);
@ -195,7 +201,7 @@ impl GridEditorTest {
}
}
pub fn create_text_field() -> Field {
pub fn create_text_field() -> FieldMeta {
FieldBuilder::new(RichTextTypeOptionsBuilder::default())
.name("Name")
.visibility(true)
@ -203,7 +209,7 @@ pub fn create_text_field() -> Field {
.build()
}
pub fn create_single_select_field() -> Field {
pub fn create_single_select_field() -> FieldMeta {
let single_select = SingleSelectTypeOptionsBuilder::default()
.option(SelectOption::new("Done"))
.option(SelectOption::new("Progress"));

View File

@ -308,7 +308,7 @@ impl FolderCouldServiceV1 for LocalServer {
belongings: RepeatedView::default(),
modified_time: time,
create_time: time,
ext_data: params.ext_data,
ext_data: "".to_string(),
thumbnail: params.thumbnail,
plugin_type: params.plugin_type,
};

View File

@ -26,11 +26,11 @@ pub struct ViewTest {
impl ViewTest {
#[allow(dead_code)]
pub async fn new(sdk: &FlowySDKTest, data_type: ViewDataType) -> Self {
pub async fn new(sdk: &FlowySDKTest, data_type: ViewDataType, data: String) -> Self {
let workspace = create_workspace(sdk, "Workspace", "").await;
open_workspace(sdk, &workspace.id).await;
let app = create_app(sdk, "App", "AppFlowy GitHub Project", &workspace.id).await;
let view = create_view(sdk, &app.id, data_type).await;
let view = create_view(sdk, &app.id, data_type, data).await;
Self {
sdk: sdk.clone(),
workspace,
@ -39,14 +39,12 @@ impl ViewTest {
}
}
#[allow(dead_code)]
pub async fn new_grid_view(sdk: &FlowySDKTest) -> Self {
Self::new(sdk, ViewDataType::Grid).await
pub async fn new_grid_view(sdk: &FlowySDKTest, data: String) -> Self {
Self::new(sdk, ViewDataType::Grid, data).await
}
#[allow(dead_code)]
pub async fn new_text_block_view(sdk: &FlowySDKTest) -> Self {
Self::new(sdk, ViewDataType::TextBlock).await
Self::new(sdk, ViewDataType::TextBlock, "".to_owned()).await
}
}
@ -93,15 +91,15 @@ async fn create_app(sdk: &FlowySDKTest, name: &str, desc: &str, workspace_id: &s
app
}
async fn create_view(sdk: &FlowySDKTest, app_id: &str, data_type: ViewDataType) -> View {
async fn create_view(sdk: &FlowySDKTest, app_id: &str, data_type: ViewDataType, data: String) -> View {
let request = CreateViewPayload {
belong_to_id: app_id.to_string(),
name: "View A".to_string(),
desc: "".to_string(),
thumbnail: Some("http://1.png".to_string()),
data_type,
ext_data: "".to_string(),
plugin_type: 0,
data,
};
let view = FolderEventBuilder::new(sdk.clone())