Selaa lähdekoodia

chore: config update cell

appflowy 3 vuotta sitten
vanhempi
commit
46be04f94e
18 muutettua tiedostoa jossa 486 lisäystä ja 294 poistoa
  1. 8 8
      frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/number_description.pb.dart
  2. 11 9
      frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/number_description.pbenum.dart
  3. 11 10
      frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/number_description.pbjson.dart
  4. 46 43
      frontend/rust-lib/flowy-grid/src/protobuf/model/number_description.rs
  5. 6 5
      frontend/rust-lib/flowy-grid/src/protobuf/proto/number_description.proto
  6. 3 5
      frontend/rust-lib/flowy-grid/src/services/block_meta_editor.rs
  7. 2 2
      frontend/rust-lib/flowy-grid/src/services/cell/builder/mod.rs
  8. 21 1
      frontend/rust-lib/flowy-grid/src/services/cell/description/checkbox_description.rs
  9. 108 11
      frontend/rust-lib/flowy-grid/src/services/cell/description/date_description.rs
  10. 171 79
      frontend/rust-lib/flowy-grid/src/services/cell/description/number_description.rs
  11. 30 3
      frontend/rust-lib/flowy-grid/src/services/cell/description/selection_description.rs
  12. 2 2
      frontend/rust-lib/flowy-grid/src/services/cell/description/text_description.rs
  13. 1 1
      frontend/rust-lib/flowy-grid/src/services/grid_editor.rs
  14. 1 1
      frontend/rust-lib/flowy-grid/src/services/mod.rs
  15. 1 1
      frontend/rust-lib/flowy-grid/src/services/row/row_loader.rs
  16. 32 100
      frontend/rust-lib/flowy-grid/src/services/util.rs
  17. 30 11
      frontend/rust-lib/flowy-grid/tests/grid/grid_test.rs
  18. 2 2
      frontend/rust-lib/flowy-grid/tests/grid/script.rs

+ 8 - 8
frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/number_description.pb.dart

@@ -15,7 +15,7 @@ export 'number_description.pbenum.dart';
 
 class NumberDescription extends $pb.GeneratedMessage {
   static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'NumberDescription', createEmptyInstance: create)
-    ..e<MoneySymbol>(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'money', $pb.PbFieldType.OE, defaultOrMaker: MoneySymbol.CNY, valueOf: MoneySymbol.valueOf, enumValues: MoneySymbol.values)
+    ..e<NumberFormat>(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'format', $pb.PbFieldType.OE, defaultOrMaker: NumberFormat.Number, valueOf: NumberFormat.valueOf, enumValues: NumberFormat.values)
     ..a<$core.int>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'scale', $pb.PbFieldType.OU3)
     ..aOS(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'symbol')
     ..aOB(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'signPositive')
@@ -25,15 +25,15 @@ class NumberDescription extends $pb.GeneratedMessage {
 
   NumberDescription._() : super();
   factory NumberDescription({
-    MoneySymbol? money,
+    NumberFormat? format,
     $core.int? scale,
     $core.String? symbol,
     $core.bool? signPositive,
     $core.String? name,
   }) {
     final _result = create();
-    if (money != null) {
-      _result.money = money;
+    if (format != null) {
+      _result.format = format;
     }
     if (scale != null) {
       _result.scale = scale;
@@ -71,13 +71,13 @@ class NumberDescription extends $pb.GeneratedMessage {
   static NumberDescription? _defaultInstance;
 
   @$pb.TagNumber(1)
-  MoneySymbol get money => $_getN(0);
+  NumberFormat get format => $_getN(0);
   @$pb.TagNumber(1)
-  set money(MoneySymbol v) { setField(1, v); }
+  set format(NumberFormat v) { setField(1, v); }
   @$pb.TagNumber(1)
-  $core.bool hasMoney() => $_has(0);
+  $core.bool hasFormat() => $_has(0);
   @$pb.TagNumber(1)
-  void clearMoney() => clearField(1);
+  void clearFormat() => clearField(1);
 
   @$pb.TagNumber(2)
   $core.int get scale => $_getIZ(1);

+ 11 - 9
frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/number_description.pbenum.dart

@@ -9,20 +9,22 @@
 import 'dart:core' as $core;
 import 'package:protobuf/protobuf.dart' as $pb;
 
-class MoneySymbol extends $pb.ProtobufEnum {
-  static const MoneySymbol CNY = MoneySymbol._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'CNY');
-  static const MoneySymbol EUR = MoneySymbol._(1, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'EUR');
-  static const MoneySymbol USD = MoneySymbol._(2, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'USD');
+class NumberFormat extends $pb.ProtobufEnum {
+  static const NumberFormat Number = NumberFormat._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Number');
+  static const NumberFormat USD = NumberFormat._(1, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'USD');
+  static const NumberFormat CNY = NumberFormat._(2, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'CNY');
+  static const NumberFormat EUR = NumberFormat._(3, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'EUR');
 
-  static const $core.List<MoneySymbol> values = <MoneySymbol> [
+  static const $core.List<NumberFormat> values = <NumberFormat> [
+    Number,
+    USD,
     CNY,
     EUR,
-    USD,
   ];
 
-  static final $core.Map<$core.int, MoneySymbol> _byValue = $pb.ProtobufEnum.initByValue(values);
-  static MoneySymbol? valueOf($core.int value) => _byValue[value];
+  static final $core.Map<$core.int, NumberFormat> _byValue = $pb.ProtobufEnum.initByValue(values);
+  static NumberFormat? valueOf($core.int value) => _byValue[value];
 
-  const MoneySymbol._($core.int v, $core.String n) : super(v, n);
+  const NumberFormat._($core.int v, $core.String n) : super(v, n);
 }
 

+ 11 - 10
frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/number_description.pbjson.dart

@@ -8,23 +8,24 @@
 import 'dart:core' as $core;
 import 'dart:convert' as $convert;
 import 'dart:typed_data' as $typed_data;
-@$core.Deprecated('Use moneySymbolDescriptor instead')
-const MoneySymbol$json = const {
-  '1': 'MoneySymbol',
+@$core.Deprecated('Use numberFormatDescriptor instead')
+const NumberFormat$json = const {
+  '1': 'NumberFormat',
   '2': const [
-    const {'1': 'CNY', '2': 0},
-    const {'1': 'EUR', '2': 1},
-    const {'1': 'USD', '2': 2},
+    const {'1': 'Number', '2': 0},
+    const {'1': 'USD', '2': 1},
+    const {'1': 'CNY', '2': 2},
+    const {'1': 'EUR', '2': 3},
   ],
 };
 
-/// Descriptor for `MoneySymbol`. Decode as a `google.protobuf.EnumDescriptorProto`.
-final $typed_data.Uint8List moneySymbolDescriptor = $convert.base64Decode('CgtNb25leVN5bWJvbBIHCgNDTlkQABIHCgNFVVIQARIHCgNVU0QQAg==');
+/// Descriptor for `NumberFormat`. Decode as a `google.protobuf.EnumDescriptorProto`.
+final $typed_data.Uint8List numberFormatDescriptor = $convert.base64Decode('CgxOdW1iZXJGb3JtYXQSCgoGTnVtYmVyEAASBwoDVVNEEAESBwoDQ05ZEAISBwoDRVVSEAM=');
 @$core.Deprecated('Use numberDescriptionDescriptor instead')
 const NumberDescription$json = const {
   '1': 'NumberDescription',
   '2': const [
-    const {'1': 'money', '3': 1, '4': 1, '5': 14, '6': '.MoneySymbol', '10': 'money'},
+    const {'1': 'format', '3': 1, '4': 1, '5': 14, '6': '.NumberFormat', '10': 'format'},
     const {'1': 'scale', '3': 2, '4': 1, '5': 13, '10': 'scale'},
     const {'1': 'symbol', '3': 3, '4': 1, '5': 9, '10': 'symbol'},
     const {'1': 'sign_positive', '3': 4, '4': 1, '5': 8, '10': 'signPositive'},
@@ -33,4 +34,4 @@ const NumberDescription$json = const {
 };
 
 /// Descriptor for `NumberDescription`. Decode as a `google.protobuf.DescriptorProto`.
-final $typed_data.Uint8List numberDescriptionDescriptor = $convert.base64Decode('ChFOdW1iZXJEZXNjcmlwdGlvbhIiCgVtb25leRgBIAEoDjIMLk1vbmV5U3ltYm9sUgVtb25leRIUCgVzY2FsZRgCIAEoDVIFc2NhbGUSFgoGc3ltYm9sGAMgASgJUgZzeW1ib2wSIwoNc2lnbl9wb3NpdGl2ZRgEIAEoCFIMc2lnblBvc2l0aXZlEhIKBG5hbWUYBSABKAlSBG5hbWU=');
+final $typed_data.Uint8List numberDescriptionDescriptor = $convert.base64Decode('ChFOdW1iZXJEZXNjcmlwdGlvbhIlCgZmb3JtYXQYASABKA4yDS5OdW1iZXJGb3JtYXRSBmZvcm1hdBIUCgVzY2FsZRgCIAEoDVIFc2NhbGUSFgoGc3ltYm9sGAMgASgJUgZzeW1ib2wSIwoNc2lnbl9wb3NpdGl2ZRgEIAEoCFIMc2lnblBvc2l0aXZlEhIKBG5hbWUYBSABKAlSBG5hbWU=');

+ 46 - 43
frontend/rust-lib/flowy-grid/src/protobuf/model/number_description.rs

@@ -26,7 +26,7 @@
 #[derive(PartialEq,Clone,Default)]
 pub struct NumberDescription {
     // message fields
-    pub money: MoneySymbol,
+    pub format: NumberFormat,
     pub scale: u32,
     pub symbol: ::std::string::String,
     pub sign_positive: bool,
@@ -47,19 +47,19 @@ impl NumberDescription {
         ::std::default::Default::default()
     }
 
-    // .MoneySymbol money = 1;
+    // .NumberFormat format = 1;
 
 
-    pub fn get_money(&self) -> MoneySymbol {
-        self.money
+    pub fn get_format(&self) -> NumberFormat {
+        self.format
     }
-    pub fn clear_money(&mut self) {
-        self.money = MoneySymbol::CNY;
+    pub fn clear_format(&mut self) {
+        self.format = NumberFormat::Number;
     }
 
     // Param is passed by value, moved
-    pub fn set_money(&mut self, v: MoneySymbol) {
-        self.money = v;
+    pub fn set_format(&mut self, v: NumberFormat) {
+        self.format = v;
     }
 
     // uint32 scale = 2;
@@ -155,7 +155,7 @@ impl ::protobuf::Message for NumberDescription {
             let (field_number, wire_type) = is.read_tag_unpack()?;
             match field_number {
                 1 => {
-                    ::protobuf::rt::read_proto3_enum_with_unknown_fields_into(wire_type, is, &mut self.money, 1, &mut self.unknown_fields)?
+                    ::protobuf::rt::read_proto3_enum_with_unknown_fields_into(wire_type, is, &mut self.format, 1, &mut self.unknown_fields)?
                 },
                 2 => {
                     if wire_type != ::protobuf::wire_format::WireTypeVarint {
@@ -189,8 +189,8 @@ impl ::protobuf::Message for NumberDescription {
     #[allow(unused_variables)]
     fn compute_size(&self) -> u32 {
         let mut my_size = 0;
-        if self.money != MoneySymbol::CNY {
-            my_size += ::protobuf::rt::enum_size(1, self.money);
+        if self.format != NumberFormat::Number {
+            my_size += ::protobuf::rt::enum_size(1, self.format);
         }
         if self.scale != 0 {
             my_size += ::protobuf::rt::value_size(2, self.scale, ::protobuf::wire_format::WireTypeVarint);
@@ -210,8 +210,8 @@ impl ::protobuf::Message for NumberDescription {
     }
 
     fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> {
-        if self.money != MoneySymbol::CNY {
-            os.write_enum(1, ::protobuf::ProtobufEnum::value(&self.money))?;
+        if self.format != NumberFormat::Number {
+            os.write_enum(1, ::protobuf::ProtobufEnum::value(&self.format))?;
         }
         if self.scale != 0 {
             os.write_uint32(2, self.scale)?;
@@ -263,10 +263,10 @@ impl ::protobuf::Message for NumberDescription {
         static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT;
         descriptor.get(|| {
             let mut fields = ::std::vec::Vec::new();
-            fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeEnum<MoneySymbol>>(
-                "money",
-                |m: &NumberDescription| { &m.money },
-                |m: &mut NumberDescription| { &mut m.money },
+            fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeEnum<NumberFormat>>(
+                "format",
+                |m: &NumberDescription| { &m.format },
+                |m: &mut NumberDescription| { &mut m.format },
             ));
             fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeUint32>(
                 "scale",
@@ -304,7 +304,7 @@ impl ::protobuf::Message for NumberDescription {
 
 impl ::protobuf::Clear for NumberDescription {
     fn clear(&mut self) {
-        self.money = MoneySymbol::CNY;
+        self.format = NumberFormat::Number;
         self.scale = 0;
         self.symbol.clear();
         self.sign_positive = false;
@@ -326,31 +326,34 @@ impl ::protobuf::reflect::ProtobufValue for NumberDescription {
 }
 
 #[derive(Clone,PartialEq,Eq,Debug,Hash)]
-pub enum MoneySymbol {
-    CNY = 0,
-    EUR = 1,
-    USD = 2,
+pub enum NumberFormat {
+    Number = 0,
+    USD = 1,
+    CNY = 2,
+    EUR = 3,
 }
 
-impl ::protobuf::ProtobufEnum for MoneySymbol {
+impl ::protobuf::ProtobufEnum for NumberFormat {
     fn value(&self) -> i32 {
         *self as i32
     }
 
-    fn from_i32(value: i32) -> ::std::option::Option<MoneySymbol> {
+    fn from_i32(value: i32) -> ::std::option::Option<NumberFormat> {
         match value {
-            0 => ::std::option::Option::Some(MoneySymbol::CNY),
-            1 => ::std::option::Option::Some(MoneySymbol::EUR),
-            2 => ::std::option::Option::Some(MoneySymbol::USD),
+            0 => ::std::option::Option::Some(NumberFormat::Number),
+            1 => ::std::option::Option::Some(NumberFormat::USD),
+            2 => ::std::option::Option::Some(NumberFormat::CNY),
+            3 => ::std::option::Option::Some(NumberFormat::EUR),
             _ => ::std::option::Option::None
         }
     }
 
     fn values() -> &'static [Self] {
-        static values: &'static [MoneySymbol] = &[
-            MoneySymbol::CNY,
-            MoneySymbol::EUR,
-            MoneySymbol::USD,
+        static values: &'static [NumberFormat] = &[
+            NumberFormat::Number,
+            NumberFormat::USD,
+            NumberFormat::CNY,
+            NumberFormat::EUR,
         ];
         values
     }
@@ -358,34 +361,34 @@ impl ::protobuf::ProtobufEnum for MoneySymbol {
     fn enum_descriptor_static() -> &'static ::protobuf::reflect::EnumDescriptor {
         static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::EnumDescriptor> = ::protobuf::rt::LazyV2::INIT;
         descriptor.get(|| {
-            ::protobuf::reflect::EnumDescriptor::new_pb_name::<MoneySymbol>("MoneySymbol", file_descriptor_proto())
+            ::protobuf::reflect::EnumDescriptor::new_pb_name::<NumberFormat>("NumberFormat", file_descriptor_proto())
         })
     }
 }
 
-impl ::std::marker::Copy for MoneySymbol {
+impl ::std::marker::Copy for NumberFormat {
 }
 
-impl ::std::default::Default for MoneySymbol {
+impl ::std::default::Default for NumberFormat {
     fn default() -> Self {
-        MoneySymbol::CNY
+        NumberFormat::Number
     }
 }
 
-impl ::protobuf::reflect::ProtobufValue for MoneySymbol {
+impl ::protobuf::reflect::ProtobufValue for NumberFormat {
     fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
         ::protobuf::reflect::ReflectValueRef::Enum(::protobuf::ProtobufEnum::descriptor(self))
     }
 }
 
 static file_descriptor_proto_data: &'static [u8] = b"\
-    \n\x18number_description.proto\"\x9e\x01\n\x11NumberDescription\x12\"\n\
-    \x05money\x18\x01\x20\x01(\x0e2\x0c.MoneySymbolR\x05money\x12\x14\n\x05s\
-    cale\x18\x02\x20\x01(\rR\x05scale\x12\x16\n\x06symbol\x18\x03\x20\x01(\t\
-    R\x06symbol\x12#\n\rsign_positive\x18\x04\x20\x01(\x08R\x0csignPositive\
-    \x12\x12\n\x04name\x18\x05\x20\x01(\tR\x04name*(\n\x0bMoneySymbol\x12\
-    \x07\n\x03CNY\x10\0\x12\x07\n\x03EUR\x10\x01\x12\x07\n\x03USD\x10\x02b\
-    \x06proto3\
+    \n\x18number_description.proto\"\xa1\x01\n\x11NumberDescription\x12%\n\
+    \x06format\x18\x01\x20\x01(\x0e2\r.NumberFormatR\x06format\x12\x14\n\x05\
+    scale\x18\x02\x20\x01(\rR\x05scale\x12\x16\n\x06symbol\x18\x03\x20\x01(\
+    \tR\x06symbol\x12#\n\rsign_positive\x18\x04\x20\x01(\x08R\x0csignPositiv\
+    e\x12\x12\n\x04name\x18\x05\x20\x01(\tR\x04name*5\n\x0cNumberFormat\x12\
+    \n\n\x06Number\x10\0\x12\x07\n\x03USD\x10\x01\x12\x07\n\x03CNY\x10\x02\
+    \x12\x07\n\x03EUR\x10\x03b\x06proto3\
 ";
 
 static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;

+ 6 - 5
frontend/rust-lib/flowy-grid/src/protobuf/proto/number_description.proto

@@ -1,14 +1,15 @@
 syntax = "proto3";
 
 message NumberDescription {
-    MoneySymbol money = 1;
+    NumberFormat format = 1;
     uint32 scale = 2;
     string symbol = 3;
     bool sign_positive = 4;
     string name = 5;
 }
-enum MoneySymbol {
-    CNY = 0;
-    EUR = 1;
-    USD = 2;
+enum NumberFormat {
+    Number = 0;
+    USD = 1;
+    CNY = 2;
+    EUR = 3;
 }

+ 3 - 5
frontend/rust-lib/flowy-grid/src/services/grid_meta_editor.rs → frontend/rust-lib/flowy-grid/src/services/block_meta_editor.rs

@@ -19,7 +19,6 @@ use lib_ot::core::PlainTextAttributes;
 
 use std::collections::HashMap;
 
-use dashmap::mapref::one::Ref;
 use std::sync::Arc;
 use tokio::sync::RwLock;
 
@@ -84,12 +83,11 @@ impl GridBlockMetaEditorManager {
     pub(crate) async fn delete_rows(&self, row_ids: Vec<String>) -> FlowyResult<Vec<GridBlockChangeset>> {
         let row_orders = row_ids
             .into_iter()
-            .flat_map(|row_id| match self.block_id_by_row_id.get(&row_id) {
-                None => None,
-                Some(block_id) => Some(RowOrder {
+            .flat_map(|row_id| {
+                self.block_id_by_row_id.get(&row_id).map(|block_id| RowOrder {
                     row_id,
                     block_id: block_id.clone(),
-                }),
+                })
             })
             .collect::<Vec<RowOrder>>();
         let mut changesets = vec![];

+ 2 - 2
frontend/rust-lib/flowy-grid/src/services/cell/builder/mod.rs

@@ -26,8 +26,8 @@ impl NumberTypeOptionsBuilder {
         self
     }
 
-    pub fn set_money_symbol(mut self, money_symbol: MoneySymbol) -> Self {
-        self.0.set_money_symbol(money_symbol);
+    pub fn set_format(mut self, format: NumberFormat) -> Self {
+        self.0.set_format(format);
         self
     }
 

+ 21 - 1
frontend/rust-lib/flowy-grid/src/services/cell/description/checkbox_description.rs

@@ -1,6 +1,6 @@
 use crate::impl_from_and_to_type_option;
 use crate::services::row::StringifyCellData;
-use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
+use flowy_derive::ProtoBuf;
 use flowy_error::FlowyError;
 use flowy_grid_data_model::entities::{Field, FieldType};
 use serde::{Deserialize, Serialize};
@@ -38,3 +38,23 @@ fn string_to_bool(bool_str: &str) -> bool {
         _ => false,
     }
 }
+
+#[cfg(test)]
+mod tests {
+    use crate::services::cell::CheckboxDescription;
+    use crate::services::row::StringifyCellData;
+
+    #[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.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.str_from_cell_data("1".to_owned()), "1".to_owned());
+    }
+}

+ 108 - 11
frontend/rust-lib/flowy-grid/src/services/cell/description/date_description.rs

@@ -1,6 +1,6 @@
 use crate::impl_from_and_to_type_option;
 use crate::services::row::StringifyCellData;
-use crate::services::util::*;
+
 use chrono::format::strftime::StrftimeItems;
 use chrono::NaiveDateTime;
 use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
@@ -8,6 +8,8 @@ use flowy_error::FlowyError;
 use flowy_grid_data_model::entities::{Field, FieldType};
 use serde::{Deserialize, Serialize};
 
+use strum_macros::EnumIter;
+
 // Date
 #[derive(Clone, Debug, Default, Serialize, Deserialize, ProtoBuf)]
 pub struct DateDescription {
@@ -20,10 +22,6 @@ pub struct DateDescription {
 impl_from_and_to_type_option!(DateDescription, FieldType::DateTime);
 
 impl DateDescription {
-    fn date_time_format_str(&self) -> String {
-        format!("{} {}", self.date_format.format_str(), self.time_format.format_str())
-    }
-
     #[allow(dead_code)]
     fn today_from_timestamp(&self, timestamp: i64) -> String {
         let native = chrono::NaiveDateTime::from_timestamp(timestamp, 0);
@@ -34,7 +32,7 @@ impl DateDescription {
         let utc: chrono::DateTime<chrono::Utc> = chrono::DateTime::from_utc(naive, chrono::Utc);
         let local: chrono::DateTime<chrono::Local> = chrono::DateTime::from(utc);
 
-        let fmt_str = self.date_time_format_str();
+        let fmt_str = format!("{} {}", self.date_format.format_str(), self.time_format.format_str());
         let output = format!("{}", local.format_with_items(StrftimeItems::new(&fmt_str)));
         output
     }
@@ -55,14 +53,18 @@ impl StringifyCellData for DateDescription {
     }
 
     fn str_to_cell_data(&self, s: &str) -> Result<String, FlowyError> {
-        let timestamp = s
-            .parse::<i64>()
-            .map_err(|e| FlowyError::internal().context(format!("Parse {} to i64 failed: {}", s, e)))?;
+        let timestamp = match s.parse::<i64>() {
+            Ok(timestamp) => timestamp,
+            Err(e) => {
+                tracing::error!("Parse {} to i64 failed: {}", s, e);
+                chrono::Utc::now().timestamp()
+            }
+        };
         Ok(format!("{}", timestamp))
     }
 }
 
-#[derive(Clone, Debug, Copy, Serialize, Deserialize, ProtoBuf_Enum)]
+#[derive(Clone, Debug, Copy, EnumIter, Serialize, Deserialize, ProtoBuf_Enum)]
 pub enum DateFormat {
     Local = 0,
     US = 1,
@@ -105,7 +107,7 @@ impl DateFormat {
     }
 }
 
-#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, Serialize, Deserialize, ProtoBuf_Enum)]
+#[derive(Clone, Copy, PartialEq, Eq, EnumIter, Debug, Hash, Serialize, Deserialize, ProtoBuf_Enum)]
 pub enum TimeFormat {
     TwelveHour = 0,
     TwentyFourHour = 1,
@@ -143,3 +145,98 @@ impl std::default::Default for TimeFormat {
         TimeFormat::TwentyFourHour
     }
 }
+
+#[cfg(test)]
+mod tests {
+    use crate::services::cell::{DateDescription, DateFormat, TimeFormat};
+    use crate::services::row::StringifyCellData;
+    use strum::IntoEnumIterator;
+
+    #[test]
+    fn date_description_date_format_test() {
+        let mut description = DateDescription::default();
+        let _timestamp = 1647251762;
+
+        for date_format in DateFormat::iter() {
+            description.date_format = date_format;
+            match date_format {
+                DateFormat::Friendly => {
+                    assert_eq!(
+                        "Mar 14,2022 17:56".to_owned(),
+                        description.today_from_timestamp(1647251762)
+                    );
+                    assert_eq!(
+                        "Mar 14,2022 17:56".to_owned(),
+                        description.str_from_cell_data("1647251762".to_owned())
+                    );
+                }
+                DateFormat::US => {
+                    assert_eq!(
+                        "2022/03/14 17:56".to_owned(),
+                        description.today_from_timestamp(1647251762)
+                    );
+                    assert_eq!(
+                        "2022/03/14 17:56".to_owned(),
+                        description.str_from_cell_data("1647251762".to_owned())
+                    );
+                }
+                DateFormat::ISO => {
+                    assert_eq!(
+                        "2022-03-14 17:56".to_owned(),
+                        description.today_from_timestamp(1647251762)
+                    );
+                    assert_eq!(
+                        "2022-03-14 17:56".to_owned(),
+                        description.str_from_cell_data("1647251762".to_owned())
+                    );
+                }
+                DateFormat::Local => {
+                    assert_eq!(
+                        "2022/03/14 17:56".to_owned(),
+                        description.today_from_timestamp(1647251762)
+                    );
+                    assert_eq!(
+                        "2022/03/14 17:56".to_owned(),
+                        description.str_from_cell_data("1647251762".to_owned())
+                    );
+                }
+            }
+        }
+    }
+
+    #[test]
+    fn date_description_time_format_test() {
+        let mut description = DateDescription::default();
+        for time_format in TimeFormat::iter() {
+            description.time_format = time_format;
+            match time_format {
+                TimeFormat::TwentyFourHour => {
+                    assert_eq!(
+                        "Mar 14,2022 17:56".to_owned(),
+                        description.today_from_timestamp(1647251762)
+                    );
+                    assert_eq!(
+                        "Mar 14,2022 17:56".to_owned(),
+                        description.str_from_cell_data("1647251762".to_owned())
+                    );
+                }
+                TimeFormat::TwelveHour => {
+                    assert_eq!(
+                        "Mar 14,2022 05:56:02 PM".to_owned(),
+                        description.today_from_timestamp(1647251762)
+                    );
+                    assert_eq!(
+                        "Mar 14,2022 05:56:02 PM".to_owned(),
+                        description.str_from_cell_data("1647251762".to_owned())
+                    );
+                }
+            }
+        }
+    }
+
+    #[test]
+    fn date_description_invalid_data_test() {
+        let description = DateDescription::default();
+        description.str_to_cell_data("he").unwrap();
+    }
+}

+ 171 - 79
frontend/rust-lib/flowy-grid/src/services/cell/description/number_description.rs

@@ -1,25 +1,62 @@
 use crate::impl_from_and_to_type_option;
 use crate::services::row::StringifyCellData;
-use crate::services::util::*;
-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 lazy_static::lazy_static;
+use rust_decimal::prelude::Zero;
 use rust_decimal::Decimal;
-use rusty_money::{
-    iso::{Currency, CNY, EUR, USD},
-    Money,
-};
+use rusty_money::iso::{Currency, CNY, EUR, USD};
 use serde::{Deserialize, Serialize};
+
 use std::str::FromStr;
+use strum::IntoEnumIterator;
 use strum_macros::EnumIter;
 
+lazy_static! {
+    static ref STRIP_SYMBOL: Vec<String> = make_strip_symbol();
+}
+
+#[derive(Clone, Copy, Debug, EnumIter, Serialize, Deserialize, ProtoBuf_Enum)]
+pub enum NumberFormat {
+    Number = 0,
+    USD = 1,
+    CNY = 2,
+    EUR = 3,
+}
+
+impl std::default::Default for NumberFormat {
+    fn default() -> Self {
+        NumberFormat::Number
+    }
+}
+
+impl NumberFormat {
+    pub fn symbol(&self) -> String {
+        match self {
+            NumberFormat::Number => "".to_string(),
+            NumberFormat::USD => USD.symbol.to_string(),
+            NumberFormat::CNY => CNY.symbol.to_string(),
+            NumberFormat::EUR => EUR.symbol.to_string(),
+        }
+    }
+
+    #[allow(dead_code)]
+    pub fn code(&self) -> String {
+        match self {
+            NumberFormat::Number => "".to_string(),
+            NumberFormat::USD => USD.iso_alpha_code.to_string(),
+            NumberFormat::CNY => CNY.iso_alpha_code.to_string(),
+            NumberFormat::EUR => EUR.iso_alpha_code.to_string(),
+        }
+    }
+}
+
 // Number
 #[derive(Clone, Debug, Serialize, Deserialize, ProtoBuf)]
 pub struct NumberDescription {
     #[pb(index = 1)]
-    pub money: MoneySymbol,
+    pub format: NumberFormat,
 
     #[pb(index = 2)]
     pub scale: u32,
@@ -37,10 +74,10 @@ impl_from_and_to_type_option!(NumberDescription, FieldType::Number);
 
 impl std::default::Default for NumberDescription {
     fn default() -> Self {
-        let money = MoneySymbol::default();
-        let symbol = money.symbol_str();
+        let format = NumberFormat::default();
+        let symbol = format.symbol();
         NumberDescription {
-            money,
+            format,
             scale: 0,
             symbol,
             sign_positive: true,
@@ -50,101 +87,156 @@ impl std::default::Default for NumberDescription {
 }
 
 impl NumberDescription {
-    pub fn set_money_symbol(&mut self, money_symbol: MoneySymbol) {
-        self.money = money_symbol;
-        self.symbol = money_symbol.symbol_str();
+    pub fn set_format(&mut self, format: NumberFormat) {
+        self.format = format;
+        self.symbol = format.symbol();
     }
 
-    fn money_from_str(&self, s: &str) -> Option<String> {
-        match Decimal::from_str(s) {
-            Ok(mut decimal) => {
-                match decimal.set_scale(self.scale) {
-                    Ok(_) => {}
-                    Err(e) => {
-                        tracing::error!("Set decimal scale failed: {:?}", e);
-                    }
-                }
-                decimal.set_sign_positive(self.sign_positive);
-                Some(self.money.with_decimal(decimal).to_string())
-            }
+    fn decimal_from_str(&self, s: &str) -> Decimal {
+        let mut decimal = Decimal::from_str(s).unwrap_or(Decimal::zero());
+        match decimal.set_scale(self.scale) {
+            Ok(_) => {}
             Err(e) => {
-                tracing::error!("Parser money from {} failed: {:?}", s, e);
-                None
+                tracing::error!("Set decimal scale failed: {:?}", e);
             }
         }
+        decimal.set_sign_positive(self.sign_positive);
+        decimal
+    }
+
+    fn money_from_str(&self, s: &str, currency: &'static Currency) -> String {
+        let decimal = self.decimal_from_str(s);
+        let money = rusty_money::Money::from_decimal(decimal, currency);
+        money.to_string()
+    }
+
+    fn strip_symbol(&self, s: &str) -> String {
+        let mut s = String::from(s);
+        if !s.chars().all(char::is_numeric) {
+            s.retain(|c| !STRIP_SYMBOL.contains(&c.to_string()));
+        }
+        s
     }
 }
 
 impl StringifyCellData for NumberDescription {
     fn str_from_cell_data(&self, data: String) -> String {
-        match self.money_from_str(&data) {
-            Some(money_str) => money_str,
-            None => String::default(),
+        match self.format {
+            NumberFormat::Number => data,
+            NumberFormat::USD => self.money_from_str(&data, USD),
+            NumberFormat::CNY => self.money_from_str(&data, CNY),
+            NumberFormat::EUR => self.money_from_str(&data, EUR),
         }
     }
 
     fn str_to_cell_data(&self, s: &str) -> Result<String, FlowyError> {
-        let strip_symbol_money = strip_money_symbol(s);
-        let decimal = Decimal::from_str(&strip_symbol_money).map_err(|err| FlowyError::internal().context(err))?;
-        Ok(decimal.to_string())
+        Ok(self.strip_symbol(s))
     }
 }
 
-#[derive(Clone, Copy, Debug, EnumIter, Serialize, Deserialize, ProtoBuf_Enum)]
-pub enum MoneySymbol {
-    CNY = 0,
-    EUR = 1,
-    USD = 2,
-}
-
-impl std::default::Default for MoneySymbol {
-    fn default() -> Self {
-        MoneySymbol::USD
+fn make_strip_symbol() -> Vec<String> {
+    let mut symbols = vec![",".to_owned(), ".".to_owned()];
+    for format in NumberFormat::iter() {
+        symbols.push(format.symbol());
     }
+    symbols
 }
 
-impl MoneySymbol {
-    // Currency list https://docs.rs/rusty-money/0.4.0/rusty_money/iso/index.html
-    pub fn from_symbol_str(s: &str) -> MoneySymbol {
-        match s {
-            "CNY" => MoneySymbol::CNY,
-            "EUR" => MoneySymbol::EUR,
-            "USD" => MoneySymbol::USD,
-            _ => MoneySymbol::CNY,
+#[cfg(test)]
+mod tests {
+    use crate::services::cell::{NumberDescription, NumberFormat};
+    use crate::services::row::StringifyCellData;
+    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());
+
+        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());
+                }
+                NumberFormat::USD => {
+                    assert_eq!(description.str_from_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());
+                }
+                NumberFormat::EUR => {
+                    assert_eq!(description.str_from_cell_data("18443".to_owned()), "€18.443".to_owned());
+                }
+            }
         }
     }
 
-    pub fn from_money(money: &rusty_money::Money<Currency>) -> MoneySymbol {
-        MoneySymbol::from_symbol_str(&money.currency().symbol.to_string())
-    }
+    #[test]
+    fn number_description_scale_test() {
+        let mut description = NumberDescription::default();
+        description.scale = 1;
 
-    pub fn currency(&self) -> &'static Currency {
-        match self {
-            MoneySymbol::CNY => CNY,
-            MoneySymbol::EUR => EUR,
-            MoneySymbol::USD => USD,
+        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());
+                }
+                NumberFormat::USD => {
+                    assert_eq!(
+                        description.str_from_cell_data("18443".to_owned()),
+                        "$1,844.3".to_owned()
+                    );
+                }
+                NumberFormat::CNY => {
+                    assert_eq!(
+                        description.str_from_cell_data("18443".to_owned()),
+                        "¥1,844.3".to_owned()
+                    );
+                }
+                NumberFormat::EUR => {
+                    assert_eq!(
+                        description.str_from_cell_data("18443".to_owned()),
+                        "€1.844,3".to_owned()
+                    );
+                }
+            }
         }
     }
 
-    // string_to_money("¥18,443").unwrap();
-    // string_to_money("$18,443").unwrap();
-    // string_to_money("€18,443").unwrap();
-    pub fn code(&self) -> String {
-        self.currency().iso_alpha_code.to_string()
-    }
-
-    pub fn symbol_str(&self) -> String {
-        self.currency().symbol.to_string()
-    }
-
-    pub fn zero(&self) -> Money<Currency> {
-        let mut decimal = Decimal::new(0, 0);
-        decimal.set_sign_positive(true);
-        self.with_decimal(decimal)
-    }
+    #[test]
+    fn number_description_sign_test() {
+        let mut description = NumberDescription::default();
+        description.sign_positive = false;
 
-    pub fn with_decimal(&self, decimal: Decimal) -> Money<Currency> {
-        let money = rusty_money::Money::from_decimal(decimal, self.currency());
-        money
+        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());
+                }
+                NumberFormat::USD => {
+                    assert_eq!(
+                        description.str_from_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()
+                    );
+                }
+                NumberFormat::EUR => {
+                    assert_eq!(
+                        description.str_from_cell_data("18443".to_owned()),
+                        "-€18.443".to_owned()
+                    );
+                }
+            }
+        }
     }
 }

+ 30 - 3
frontend/rust-lib/flowy-grid/src/services/cell/description/selection_description.rs

@@ -1,7 +1,7 @@
 use crate::impl_from_and_to_type_option;
 use crate::services::row::StringifyCellData;
 use crate::services::util::*;
-use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
+use flowy_derive::ProtoBuf;
 use flowy_error::FlowyError;
 use flowy_grid_data_model::entities::{Field, FieldType};
 use serde::{Deserialize, Serialize};
@@ -23,7 +23,7 @@ impl StringifyCellData for SingleSelectDescription {
     }
 
     fn str_to_cell_data(&self, s: &str) -> Result<String, FlowyError> {
-        Ok(s.to_owned())
+        Ok(select_option_id_from_data(s.to_owned(), true))
     }
 }
 
@@ -43,10 +43,22 @@ impl StringifyCellData for MultiSelectDescription {
     }
 
     fn str_to_cell_data(&self, s: &str) -> Result<String, FlowyError> {
-        Ok(s.to_owned())
+        Ok(select_option_id_from_data(s.to_owned(), false))
     }
 }
 
+fn select_option_id_from_data(data: String, is_single_select: bool) -> String {
+    if !is_single_select {
+        return data;
+    }
+    let select_option_ids = data.split(',').collect::<Vec<&str>>();
+    if select_option_ids.is_empty() {
+        return "".to_owned();
+    }
+
+    select_option_ids.split_first().unwrap().0.to_string()
+}
+
 #[derive(Clone, Debug, Default, Serialize, Deserialize, ProtoBuf)]
 pub struct SelectOption {
     #[pb(index = 1)]
@@ -68,3 +80,18 @@ impl SelectOption {
         }
     }
 }
+
+#[cfg(test)]
+mod tests {
+    use crate::services::cell::{MultiSelectDescription, SingleSelectDescription};
+    use crate::services::row::StringifyCellData;
+
+    #[test]
+    fn selection_description_test() {
+        let description = SingleSelectDescription::default();
+        assert_eq!(description.str_to_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());
+    }
+}

+ 2 - 2
frontend/rust-lib/flowy-grid/src/services/cell/description/text_description.rs

@@ -1,7 +1,7 @@
 use crate::impl_from_and_to_type_option;
 use crate::services::row::StringifyCellData;
-use crate::services::util::*;
-use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
+
+use flowy_derive::ProtoBuf;
 use flowy_error::FlowyError;
 use flowy_grid_data_model::entities::{Field, FieldType};
 use serde::{Deserialize, Serialize};

+ 1 - 1
frontend/rust-lib/flowy-grid/src/services/grid_editor.rs

@@ -1,5 +1,5 @@
 use crate::manager::GridUser;
-use crate::services::grid_meta_editor::GridBlockMetaEditorManager;
+use crate::services::block_meta_editor::GridBlockMetaEditorManager;
 use crate::services::kv_persistence::{GridKVPersistence, KVTransaction};
 use bytes::Bytes;
 use flowy_collaboration::client_grid::{GridChange, GridMetaPad};

+ 1 - 1
frontend/rust-lib/flowy-grid/src/services/mod.rs

@@ -1,8 +1,8 @@
 mod util;
 
+pub mod block_meta_editor;
 pub mod cell;
 pub mod field;
 pub mod grid_editor;
-pub mod grid_meta_editor;
 pub mod kv_persistence;
 pub mod row;

+ 1 - 1
frontend/rust-lib/flowy-grid/src/services/row/row_loader.rs

@@ -1,5 +1,5 @@
 use crate::services::row::stringify_deserialize;
-use flowy_grid_data_model::entities::{Cell, CellMeta, Field, RepeatedRowOrder, Row, RowMeta, RowOrder};
+use flowy_grid_data_model::entities::{Cell, CellMeta, Field, Row, RowMeta, RowOrder};
 use rayon::iter::{IntoParallelIterator, ParallelIterator};
 use std::collections::HashMap;
 

+ 32 - 100
frontend/rust-lib/flowy-grid/src/services/util.rs

@@ -1,103 +1,35 @@
-use crate::services::cell::MoneySymbol;
-use flowy_error::FlowyError;
-use flowy_grid_data_model::entities::{AnyData, Field, FieldType};
-use lazy_static::lazy_static;
-use rust_decimal::Decimal;
-use rusty_money::{iso::Currency, Money};
-use std::collections::HashMap;
-use std::str::FromStr;
-use strum::IntoEnumIterator;
-
-lazy_static! {
-    static ref CURRENCIES_BY_SYMBOL: HashMap<String, &'static Currency> = generate_currency_by_symbol();
-}
-
-#[allow(dead_code)]
-fn generate_currency_by_symbol() -> HashMap<String, &'static Currency> {
-    let mut map: HashMap<String, &'static Currency> = HashMap::new();
-
-    for money in MoneySymbol::iter() {
-        map.insert(money.symbol_str(), money.currency());
-    }
-    map
-}
-
-#[allow(dead_code)]
-pub fn string_to_money(money_str: &str) -> Option<Money<Currency>> {
-    let mut process_money_str = String::from(money_str);
-    let default_currency = MoneySymbol::from_symbol_str("CNY").currency();
-
-    if process_money_str.is_empty() {
-        return None;
-    }
-
-    return if process_money_str.chars().all(char::is_numeric) {
-        match Money::from_str(&process_money_str, default_currency) {
-            Ok(money) => Some(money),
-            Err(_) => None,
-        }
-    } else {
-        let symbol = process_money_str.chars().next().unwrap().to_string();
-        let mut currency = default_currency;
-
-        for key in CURRENCIES_BY_SYMBOL.keys() {
-            if symbol.eq(key) {
-                currency = CURRENCIES_BY_SYMBOL.get(key).unwrap();
-                crop_letters(&mut process_money_str, 1);
-            }
-        }
-
-        match Money::from_str(&process_money_str, currency) {
-            Ok(money) => Some(money),
-            Err(_) => None,
-        }
-    };
-}
-
-#[allow(dead_code)]
-pub fn money_from_str(s: &str) -> Option<String> {
-    match Decimal::from_str(s) {
-        Ok(mut decimal) => {
-            match decimal.set_scale(0) {
-                Ok(_) => {}
-                Err(e) => {
-                    tracing::error!("Set scale failed. {:?}", e);
-                }
-            }
-            decimal.set_sign_positive(true);
-            Some(MoneySymbol::USD.with_decimal(decimal).to_string())
-        }
-        Err(e) => {
-            tracing::debug!("Format {} to money failed, {:?}", s, e);
-            None
-        }
-    }
-}
-
-pub fn strip_money_symbol(money_str: &str) -> String {
-    let mut process_money_str = String::from(money_str);
-
-    if !process_money_str.chars().all(char::is_numeric) {
-        let symbol = process_money_str.chars().next().unwrap().to_string();
-        for key in CURRENCIES_BY_SYMBOL.keys() {
-            if symbol.eq(key) {
-                crop_letters(&mut process_money_str, 1);
-            }
-        }
-    }
-    process_money_str
-}
-
-fn crop_letters(s: &mut String, pos: usize) {
-    match s.char_indices().nth(pos) {
-        Some((pos, _)) => {
-            s.drain(..pos);
-        }
-        None => {
-            s.clear();
-        }
-    }
-}
+//
+// #[allow(dead_code)]
+// pub fn string_to_money(money_str: &str) -> Option<Money<Currency>> {
+//     let mut process_money_str = String::from(money_str);
+//     let default_currency = MoneySymbol::from_symbol_str("CNY").currency();
+//
+//     if process_money_str.is_empty() {
+//         return None;
+//     }
+//
+//     return if process_money_str.chars().all(char::is_numeric) {
+//         match Money::from_str(&process_money_str, default_currency) {
+//             Ok(money) => Some(money),
+//             Err(_) => None,
+//         }
+//     } else {
+//         let symbol = process_money_str.chars().next().unwrap().to_string();
+//         let mut currency = default_currency;
+//
+//         for key in CURRENCIES_BY_SYMBOL.keys() {
+//             if symbol.eq(key) {
+//                 currency = CURRENCIES_BY_SYMBOL.get(key).unwrap();
+//                 crop_letters(&mut process_money_str, 1);
+//             }
+//         }
+//
+//         match Money::from_str(&process_money_str, currency) {
+//             Ok(money) => Some(money),
+//             Err(_) => None,
+//         }
+//     };
+// }
 
 pub fn uuid() -> String {
     uuid::Uuid::new_v4().to_string()

+ 30 - 11
frontend/rust-lib/flowy-grid/tests/grid/grid_test.rs

@@ -1,10 +1,8 @@
 use crate::grid::script::EditorScript::*;
 use crate::grid::script::*;
-use flowy_grid::services::field::{SelectOption, SingleSelectDescription};
-use flowy_grid::services::row::CreateRowContextBuilder;
-use flowy_grid_data_model::entities::{
-    FieldChangeset, FieldType, GridBlock, GridBlockChangeset, Row, RowMetaChangeset,
-};
+use flowy_grid::services::cell::*;
+use flowy_grid::services::row::{CreateRowContextBuilder, StringifyCellData};
+use flowy_grid_data_model::entities::{FieldChangeset, FieldType, GridBlock, GridBlockChangeset, RowMetaChangeset};
 
 #[tokio::test]
 async fn default_grid_test() {
@@ -249,19 +247,40 @@ async fn grid_update_cell() {
                 builder = builder.add_cell(&field.id, "hello world".to_owned());
             }
             FieldType::Number => {
-                builder = builder.add_cell(&field.id, "123".to_owned());
+                let description = NumberDescription::from(field);
+                let data = description.str_to_cell_data("¥18,443").unwrap();
+                builder = builder.add_cell(&field.id, data);
             }
             FieldType::DateTime => {
-                builder = builder.add_cell(&field.id, "March 8, 2022".to_owned());
+                let description = DateDescription::from(field);
+                let data = description.str_to_cell_data("1647251762").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();
+                builder = builder.add_cell(&field.id, data);
+            }
+            FieldType::MultiSelect => {
+                let description = MultiSelectDescription::from(field);
+                let options = description
+                    .options
+                    .iter()
+                    .map(|option| option.id.clone())
+                    .collect::<Vec<_>>()
+                    .join(",");
+                let data = description.str_to_cell_data(&options).unwrap();
+                builder = builder.add_cell(&field.id, data);
             }
-            FieldType::SingleSelect => {}
-            FieldType::MultiSelect => {}
             FieldType::Checkbox => {
-                builder = builder.add_cell(&field.id, "1".to_owned());
+                let description = CheckboxDescription::from(field);
+                let data = description.str_to_cell_data("false").unwrap();
+                builder = builder.add_cell(&field.id, data);
             }
         }
     }
     let context = builder.build();
-    let scripts = vec![AssertRowCount(3), CreateRow { context }];
+    let scripts = vec![AssertRowCount(3), CreateRow { context }, AssertGridMetaPad];
     test.run_scripts(scripts).await;
 }

+ 2 - 2
frontend/rust-lib/flowy-grid/tests/grid/script.rs

@@ -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, Row, RowMeta, RowMetaChangeset,
+    CellMetaChangeset, Field, FieldChangeset, FieldType, GridBlock, GridBlockChangeset, RowMeta, RowMetaChangeset,
 };
 use flowy_sync::REVISION_WRITE_INTERVAL_IN_MILLIS;
 use flowy_test::helper::ViewTest;
@@ -104,7 +104,7 @@ impl GridEditorTest {
         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 _cache = rev_manager.revision_cache().await;
 
         match script {
             EditorScript::CreateField { field } => {