浏览代码

chore: date with utc

appflowy 2 年之前
父节点
当前提交
0e137f12f5
共有 15 个文件被更改,包括 114 次插入94 次删除
  1. 3 3
      frontend/app_flowy/lib/plugins/grid/application/cell/cell_service/cell_data_persistence.dart
  2. 16 7
      frontend/rust-lib/flowy-grid/src/event_handler.rs
  3. 10 9
      frontend/rust-lib/flowy-grid/src/services/cell/cell_operation.rs
  4. 2 2
      frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_type_option.rs
  5. 28 1
      frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_tests.rs
  6. 7 14
      frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_type_option.rs
  7. 17 44
      frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_type_option_entities.rs
  8. 2 2
      frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_type_option.rs
  9. 2 2
      frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/multi_select_type_option.rs
  10. 2 2
      frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/single_select_type_option.rs
  11. 2 2
      frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option/text_type_option.rs
  12. 2 2
      frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_type_option.rs
  13. 18 1
      frontend/rust-lib/flowy-grid/src/services/grid_editor.rs
  14. 2 2
      frontend/rust-lib/flowy-grid/tests/grid/block_test/util.rs
  15. 1 1
      frontend/rust-lib/flowy-grid/tests/grid/field_test/util.rs

+ 3 - 3
frontend/app_flowy/lib/plugins/grid/application/cell/cell_service/cell_data_persistence.dart

@@ -42,11 +42,11 @@ class DateCellDataPersistence
 
   @override
   Future<Option<FlowyError>> save(CalendarData data) {
-    var payload = DateChangesetPB.create()
-      ..cellIdentifier = _makeCellIdPayload(cellId);
+    var payload = DateChangesetPB.create()..cellPath = _makeCellPath(cellId);
 
     final date = (data.date.millisecondsSinceEpoch ~/ 1000).toString();
     payload.date = date;
+    payload.isUtc = data.date.isUtc;
 
     if (data.time != null) {
       payload.time = data.time!;
@@ -61,7 +61,7 @@ class DateCellDataPersistence
   }
 }
 
-CellPathPB _makeCellIdPayload(GridCellIdentifier cellId) {
+CellPathPB _makeCellPath(GridCellIdentifier cellId) {
   return CellPathPB.create()
     ..gridId = cellId.gridId
     ..fieldId = cellId.fieldId

+ 16 - 7
frontend/rust-lib/flowy-grid/src/event_handler.rs

@@ -3,7 +3,7 @@ use crate::manager::GridManager;
 use crate::services::cell::AnyCellData;
 use crate::services::field::{
     default_type_option_builder_from_type, select_type_option_from_field_rev, type_option_builder_from_json_str,
-    DateChangesetPB, DateChangesetParams, SelectOptionCellChangeset, SelectOptionCellChangesetPB,
+    DateCellChangeset, DateChangesetPB, SelectOptionCellChangeset, SelectOptionCellChangesetPB,
     SelectOptionCellChangesetParams, SelectOptionCellDataPB, SelectOptionChangeset, SelectOptionChangesetPB,
     SelectOptionPB,
 };
@@ -307,7 +307,7 @@ 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(changeset).await?;
+    let _ = editor.update_cell_with_changeset(changeset).await?;
     Ok(())
 }
 
@@ -372,7 +372,7 @@ pub(crate) async fn update_select_option_handler(
                 };
                 let cloned_editor = editor.clone();
                 tokio::spawn(async move {
-                    match cloned_editor.update_cell(changeset).await {
+                    match cloned_editor.update_cell_with_changeset(changeset).await {
                         Ok(_) => {}
                         Err(e) => tracing::error!("{}", e),
                     }
@@ -421,7 +421,7 @@ 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(&params.cell_identifier.grid_id).await?;
-    let _ = editor.update_cell(params.into()).await?;
+    let _ = editor.update_cell_with_changeset(params.into()).await?;
     Ok(())
 }
 
@@ -430,9 +430,18 @@ pub(crate) async fn update_date_cell_handler(
     data: Data<DateChangesetPB>,
     manager: AppData<Arc<GridManager>>,
 ) -> Result<(), FlowyError> {
-    let params: DateChangesetParams = data.into_inner().try_into()?;
-    let editor = manager.get_grid_editor(&params.cell_identifier.grid_id).await?;
-    let _ = editor.update_cell(params.into()).await?;
+    let data = data.into_inner();
+    let cell_path: CellPathParams = data.cell_path.try_into()?;
+    let content = DateCellChangeset {
+        date: data.date,
+        time: data.time,
+        is_utc: data.is_utc,
+    };
+
+    let editor = manager.get_grid_editor(&cell_path.grid_id).await?;
+    let _ = editor
+        .update_cell(cell_path.grid_id, cell_path.row_id, cell_path.field_id, content)
+        .await?;
     Ok(())
 }
 

+ 10 - 9
frontend/rust-lib/flowy-grid/src/services/cell/cell_operation.rs

@@ -97,7 +97,7 @@ pub trait CellDataOperation<CD, CS> {
     /// For example:
     /// SelectOptionCellChangeset,DateCellChangeset. etc.
     ///  
-    fn apply_changeset(&self, changeset: CellDataChangeset<CS>, cell_rev: Option<CellRevision>) -> FlowyResult<String>;
+    fn apply_changeset(&self, changeset: AnyCellChangeset<CS>, cell_rev: Option<CellRevision>) -> FlowyResult<String>;
 }
 
 /// changeset: It will be deserialized into specific data base on the FieldType.
@@ -276,9 +276,10 @@ pub fn insert_checkbox_cell(is_check: bool, field_rev: &FieldRevision) -> CellRe
 }
 
 pub fn insert_date_cell(timestamp: i64, field_rev: &FieldRevision) -> CellRevision {
-    let cell_data = serde_json::to_string(&DateCellChangesetPB {
+    let cell_data = serde_json::to_string(&DateCellChangeset {
         date: Some(timestamp.to_string()),
         time: None,
+        is_utc: true,
     })
     .unwrap();
     let data = apply_cell_data_changeset(cell_data, None, field_rev).unwrap();
@@ -356,9 +357,9 @@ pub trait FromCellChangeset {
         Self: Sized;
 }
 
-pub struct CellDataChangeset<T>(pub Option<T>);
+pub struct AnyCellChangeset<T>(pub Option<T>);
 
-impl<T> CellDataChangeset<T> {
+impl<T> AnyCellChangeset<T> {
     pub fn try_into_inner(self) -> FlowyResult<T> {
         match self.0 {
             None => Err(ErrorCode::InvalidData.into()),
@@ -367,22 +368,22 @@ impl<T> CellDataChangeset<T> {
     }
 }
 
-impl<T, C: ToString> std::convert::From<C> for CellDataChangeset<T>
+impl<T, C: ToString> std::convert::From<C> for AnyCellChangeset<T>
 where
     T: FromCellChangeset,
 {
     fn from(changeset: C) -> Self {
         match T::from_changeset(changeset.to_string()) {
-            Ok(data) => CellDataChangeset(Some(data)),
+            Ok(data) => AnyCellChangeset(Some(data)),
             Err(e) => {
                 tracing::error!("Deserialize CellDataChangeset failed: {}", e);
-                CellDataChangeset(None)
+                AnyCellChangeset(None)
             }
         }
     }
 }
-impl std::convert::From<String> for CellDataChangeset<String> {
+impl std::convert::From<String> for AnyCellChangeset<String> {
     fn from(s: String) -> Self {
-        CellDataChangeset(Some(s))
+        AnyCellChangeset(Some(s))
     }
 }

+ 2 - 2
frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_type_option.rs

@@ -1,6 +1,6 @@
 use crate::entities::FieldType;
 use crate::impl_type_option;
-use crate::services::cell::{CellBytes, CellData, CellDataChangeset, CellDataOperation, CellDisplayable};
+use crate::services::cell::{AnyCellChangeset, CellBytes, CellData, CellDataOperation, CellDisplayable};
 use crate::services::field::{BoxTypeOptionBuilder, CheckboxCellData, TypeOptionBuilder};
 use bytes::Bytes;
 use flowy_derive::ProtoBuf;
@@ -80,7 +80,7 @@ impl CellDataOperation<CheckboxCellData, String> for CheckboxTypeOptionPB {
 
     fn apply_changeset(
         &self,
-        changeset: CellDataChangeset<String>,
+        changeset: AnyCellChangeset<String>,
         _cell_rev: Option<CellRevision>,
     ) -> Result<String, FlowyError> {
         let changeset = changeset.try_into_inner()?;

+ 28 - 1
frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_tests.rs

@@ -4,6 +4,8 @@ mod tests {
     use crate::services::cell::CellDataOperation;
     use crate::services::field::*;
     // use crate::services::field::{DateCellChangeset, DateCellData, DateFormat, DateTypeOptionPB, TimeFormat};
+    use chrono::format::strftime::StrftimeItems;
+    use chrono::{FixedOffset, NaiveDateTime};
     use grid_rev_model::FieldRevision;
     use strum::IntoEnumIterator;
 
@@ -113,6 +115,30 @@ mod tests {
             &field_rev,
         );
     }
+
+    #[test]
+    fn utc_to_native_test() {
+        let native_timestamp = 1647251762;
+        let native = NaiveDateTime::from_timestamp(native_timestamp, 0);
+
+        let utc = chrono::DateTime::<chrono::Utc>::from_utc(native, chrono::Utc);
+        // utc_timestamp doesn't  carry timezone
+        let utc_timestamp = utc.timestamp();
+        assert_eq!(native_timestamp, utc_timestamp);
+
+        let format = "%m/%d/%Y %I:%M %p".to_string();
+        let native_time_str = format!("{}", native.format_with_items(StrftimeItems::new(&format)));
+        let utc_time_str = format!("{}", utc.format_with_items(StrftimeItems::new(&format)));
+        assert_eq!(native_time_str, utc_time_str);
+
+        // Mon Mar 14 2022 17:56:02 GMT+0800 (China Standard Time)
+        let gmt_8_offset = FixedOffset::east(8 * 3600);
+        let china_local = chrono::DateTime::<chrono::Local>::from_utc(native, gmt_8_offset);
+        let china_local_time = format!("{}", china_local.format_with_items(StrftimeItems::new(&format)));
+
+        assert_eq!(china_local_time, "03/14/2022 05:56 PM");
+    }
+
     fn assert_date<T: ToString>(
         type_option: &DateTypeOptionPB,
         timestamp: T,
@@ -120,9 +146,10 @@ mod tests {
         expected_str: &str,
         field_rev: &FieldRevision,
     ) {
-        let s = serde_json::to_string(&DateCellChangesetPB {
+        let s = serde_json::to_string(&DateCellChangeset {
             date: Some(timestamp.to_string()),
             time: include_time_str,
+            is_utc: false,
         })
         .unwrap();
         let encoded_data = type_option.apply_changeset(s.into(), None).unwrap();

+ 7 - 14
frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_type_option.rs

@@ -1,8 +1,8 @@
 use crate::entities::FieldType;
 use crate::impl_type_option;
-use crate::services::cell::{CellBytes, CellData, CellDataChangeset, CellDataOperation, CellDisplayable};
+use crate::services::cell::{AnyCellChangeset, CellBytes, CellData, CellDataOperation, CellDisplayable};
 use crate::services::field::{
-    BoxTypeOptionBuilder, DateCellChangesetPB, DateCellDataPB, DateFormat, DateTimestamp, TimeFormat, TypeOptionBuilder,
+    BoxTypeOptionBuilder, DateCellChangeset, DateCellDataPB, DateFormat, DateTimestamp, TimeFormat, TypeOptionBuilder,
 };
 use bytes::Bytes;
 use chrono::format::strftime::StrftimeItems;
@@ -35,10 +35,6 @@ impl DateTypeOptionPB {
     fn today_desc_from_timestamp<T: AsRef<i64>>(&self, timestamp: T) -> DateCellDataPB {
         let timestamp = *timestamp.as_ref();
         let native = chrono::NaiveDateTime::from_timestamp(timestamp, 0);
-        self.date_from_native(native)
-    }
-
-    fn date_from_native(&self, native: chrono::NaiveDateTime) -> DateCellDataPB {
         if native.timestamp() == 0 {
             return DateCellDataPB::default();
         }
@@ -106,11 +102,6 @@ impl DateTypeOptionPB {
         Ok(utc.timestamp())
     }
 
-    fn utc_date_time_from_timestamp(&self, timestamp: i64) -> chrono::DateTime<chrono::Utc> {
-        let native = NaiveDateTime::from_timestamp(timestamp, 0);
-        self.utc_date_time_from_native(native)
-    }
-
     fn utc_date_time_from_native(&self, naive: chrono::NaiveDateTime) -> chrono::DateTime<chrono::Utc> {
         chrono::DateTime::<chrono::Utc>::from_utc(naive, chrono::Utc)
     }
@@ -140,7 +131,7 @@ impl CellDisplayable<DateTimestamp> for DateTypeOptionPB {
     }
 }
 
-impl CellDataOperation<DateTimestamp, DateCellChangesetPB> for DateTypeOptionPB {
+impl CellDataOperation<DateTimestamp, DateCellChangeset> for DateTypeOptionPB {
     fn decode_cell_data(
         &self,
         cell_data: CellData<DateTimestamp>,
@@ -159,7 +150,7 @@ impl CellDataOperation<DateTimestamp, DateCellChangesetPB> for DateTypeOptionPB
 
     fn apply_changeset(
         &self,
-        changeset: CellDataChangeset<DateCellChangesetPB>,
+        changeset: AnyCellChangeset<DateCellChangeset>,
         _cell_rev: Option<CellRevision>,
     ) -> Result<String, FlowyError> {
         let changeset = changeset.try_into_inner()?;
@@ -168,7 +159,9 @@ impl CellDataOperation<DateTimestamp, DateCellChangesetPB> for DateTypeOptionPB
             Some(date_timestamp) => match (self.include_time, changeset.time) {
                 (true, Some(time)) => {
                     let time = Some(time.trim().to_uppercase());
-                    let utc = self.utc_date_time_from_timestamp(date_timestamp);
+                    let native = NaiveDateTime::from_timestamp(date_timestamp, 0);
+
+                    let utc = self.utc_date_time_from_native(native);
                     self.timestamp_from_utc_with_time(&utc, &time)?
                 }
                 _ => date_timestamp,

+ 17 - 44
frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_type_option_entities.rs

@@ -1,11 +1,8 @@
-use crate::entities::CellChangesetPB;
-use crate::entities::{CellPathPB, CellPathParams};
+use crate::entities::CellPathPB;
 use crate::services::cell::{CellBytesParser, CellDataIsEmpty, FromCellChangeset, FromCellString};
 use bytes::Bytes;
-
 use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
-use flowy_error::{internal_error, ErrorCode, FlowyResult};
-
+use flowy_error::{internal_error, FlowyResult};
 use serde::{Deserialize, Serialize};
 use strum_macros::EnumIter;
 
@@ -24,57 +21,26 @@ pub struct DateCellDataPB {
 #[derive(Clone, Debug, Default, ProtoBuf)]
 pub struct DateChangesetPB {
     #[pb(index = 1)]
-    pub cell_identifier: CellPathPB,
+    pub cell_path: CellPathPB,
 
     #[pb(index = 2, one_of)]
     pub date: Option<String>,
 
     #[pb(index = 3, one_of)]
     pub time: Option<String>,
-}
 
-pub struct DateChangesetParams {
-    pub cell_identifier: CellPathParams,
-    pub date: Option<String>,
-    pub time: Option<String>,
-}
-
-impl TryInto<DateChangesetParams> for DateChangesetPB {
-    type Error = ErrorCode;
-
-    fn try_into(self) -> Result<DateChangesetParams, Self::Error> {
-        let cell_identifier: CellPathParams = self.cell_identifier.try_into()?;
-        Ok(DateChangesetParams {
-            cell_identifier,
-            date: self.date,
-            time: self.time,
-        })
-    }
-}
-
-impl std::convert::From<DateChangesetParams> for CellChangesetPB {
-    fn from(params: DateChangesetParams) -> Self {
-        let changeset = DateCellChangesetPB {
-            date: params.date,
-            time: params.time,
-        };
-        let content = serde_json::to_string(&changeset).unwrap();
-        CellChangesetPB {
-            grid_id: params.cell_identifier.grid_id,
-            row_id: params.cell_identifier.row_id,
-            field_id: params.cell_identifier.field_id,
-            content,
-        }
-    }
+    #[pb(index = 4)]
+    pub is_utc: bool,
 }
 
 #[derive(Clone, Serialize, Deserialize)]
-pub struct DateCellChangesetPB {
+pub struct DateCellChangeset {
     pub date: Option<String>,
     pub time: Option<String>,
+    pub is_utc: bool,
 }
 
-impl DateCellChangesetPB {
+impl DateCellChangeset {
     pub fn date_timestamp(&self) -> Option<i64> {
         if let Some(date) = &self.date {
             match date.parse::<i64>() {
@@ -87,14 +53,21 @@ impl DateCellChangesetPB {
     }
 }
 
-impl FromCellChangeset for DateCellChangesetPB {
+impl FromCellChangeset for DateCellChangeset {
     fn from_changeset(changeset: String) -> FlowyResult<Self>
     where
         Self: Sized,
     {
-        serde_json::from_str::<DateCellChangesetPB>(&changeset).map_err(internal_error)
+        serde_json::from_str::<DateCellChangeset>(&changeset).map_err(internal_error)
     }
 }
+
+impl ToString for DateCellChangeset {
+    fn to_string(&self) -> String {
+        serde_json::to_string(self).unwrap_or_else(|_| "".to_string())
+    }
+}
+
 pub struct DateTimestamp(i64);
 impl AsRef<i64> for DateTimestamp {
     fn as_ref(&self) -> &i64 {

+ 2 - 2
frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_type_option.rs

@@ -1,6 +1,6 @@
 use crate::entities::FieldType;
 use crate::impl_type_option;
-use crate::services::cell::{CellBytes, CellData, CellDataChangeset, CellDataOperation, CellDisplayable};
+use crate::services::cell::{AnyCellChangeset, CellBytes, CellData, CellDataOperation, CellDisplayable};
 use crate::services::field::type_options::number_type_option::format::*;
 use crate::services::field::{BoxTypeOptionBuilder, NumberCellData, TypeOptionBuilder};
 use bytes::Bytes;
@@ -146,7 +146,7 @@ impl CellDataOperation<String, String> for NumberTypeOptionPB {
 
     fn apply_changeset(
         &self,
-        changeset: CellDataChangeset<String>,
+        changeset: AnyCellChangeset<String>,
         _cell_rev: Option<CellRevision>,
     ) -> Result<String, FlowyError> {
         let changeset = changeset.try_into_inner()?;

+ 2 - 2
frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/multi_select_type_option.rs

@@ -1,6 +1,6 @@
 use crate::entities::FieldType;
 use crate::impl_type_option;
-use crate::services::cell::{CellBytes, CellData, CellDataChangeset, CellDataOperation, CellDisplayable};
+use crate::services::cell::{AnyCellChangeset, CellBytes, CellData, CellDataOperation, CellDisplayable};
 use crate::services::field::selection_type_option::type_option_transform::SelectOptionTypeOptionTransformer;
 use crate::services::field::type_options::util::get_cell_data;
 use crate::services::field::{
@@ -50,7 +50,7 @@ impl CellDataOperation<SelectOptionIds, SelectOptionCellChangeset> for MultiSele
 
     fn apply_changeset(
         &self,
-        changeset: CellDataChangeset<SelectOptionCellChangeset>,
+        changeset: AnyCellChangeset<SelectOptionCellChangeset>,
         cell_rev: Option<CellRevision>,
     ) -> Result<String, FlowyError> {
         let content_changeset = changeset.try_into_inner()?;

+ 2 - 2
frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/single_select_type_option.rs

@@ -1,6 +1,6 @@
 use crate::entities::FieldType;
 use crate::impl_type_option;
-use crate::services::cell::{CellBytes, CellData, CellDataChangeset, CellDataOperation, CellDisplayable};
+use crate::services::cell::{AnyCellChangeset, CellBytes, CellData, CellDataOperation, CellDisplayable};
 use crate::services::field::selection_type_option::type_option_transform::SelectOptionTypeOptionTransformer;
 use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder};
 use crate::services::field::{
@@ -49,7 +49,7 @@ impl CellDataOperation<SelectOptionIds, SelectOptionCellChangeset> for SingleSel
 
     fn apply_changeset(
         &self,
-        changeset: CellDataChangeset<SelectOptionCellChangeset>,
+        changeset: AnyCellChangeset<SelectOptionCellChangeset>,
         _cell_rev: Option<CellRevision>,
     ) -> Result<String, FlowyError> {
         let content_changeset = changeset.try_into_inner()?;

+ 2 - 2
frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option/text_type_option.rs

@@ -1,7 +1,7 @@
 use crate::entities::FieldType;
 use crate::impl_type_option;
 use crate::services::cell::{
-    decode_cell_data_to_string, CellBytes, CellBytesParser, CellData, CellDataChangeset, CellDataIsEmpty,
+    decode_cell_data_to_string, AnyCellChangeset, CellBytes, CellBytesParser, CellData, CellDataIsEmpty,
     CellDataOperation, CellDisplayable, FromCellString,
 };
 use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder};
@@ -83,7 +83,7 @@ impl CellDataOperation<String, String> for RichTextTypeOptionPB {
 
     fn apply_changeset(
         &self,
-        changeset: CellDataChangeset<String>,
+        changeset: AnyCellChangeset<String>,
         _cell_rev: Option<CellRevision>,
     ) -> Result<String, FlowyError> {
         let data = changeset.try_into_inner()?;

+ 2 - 2
frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_type_option.rs

@@ -1,6 +1,6 @@
 use crate::entities::FieldType;
 use crate::impl_type_option;
-use crate::services::cell::{CellBytes, CellData, CellDataChangeset, CellDataOperation, CellDisplayable};
+use crate::services::cell::{AnyCellChangeset, CellBytes, CellData, CellDataOperation, CellDisplayable};
 use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder, URLCellDataPB};
 use bytes::Bytes;
 use fancy_regex::Regex;
@@ -73,7 +73,7 @@ impl CellDataOperation<URLCellDataPB, String> for URLTypeOptionPB {
 
     fn apply_changeset(
         &self,
-        changeset: CellDataChangeset<String>,
+        changeset: AnyCellChangeset<String>,
         _cell_rev: Option<CellRevision>,
     ) -> Result<String, FlowyError> {
         let content = changeset.try_into_inner()?;

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

@@ -472,7 +472,7 @@ impl GridRevisionEditor {
     }
 
     #[tracing::instrument(level = "trace", skip_all, err)]
-    pub async fn update_cell(&self, cell_changeset: CellChangesetPB) -> FlowyResult<()> {
+    pub async fn update_cell_with_changeset(&self, cell_changeset: CellChangesetPB) -> FlowyResult<()> {
         let CellChangesetPB {
             grid_id,
             row_id,
@@ -503,6 +503,23 @@ impl GridRevisionEditor {
         }
     }
 
+    #[tracing::instrument(level = "trace", skip_all, err)]
+    pub async fn update_cell<T: ToString>(
+        &self,
+        grid_id: String,
+        row_id: String,
+        field_id: String,
+        content: T,
+    ) -> FlowyResult<()> {
+        self.update_cell_with_changeset(CellChangesetPB {
+            grid_id,
+            row_id,
+            field_id,
+            content: content.to_string(),
+        })
+        .await
+    }
+
     pub async fn get_block_meta_revs(&self) -> FlowyResult<Vec<Arc<GridBlockMetaRevision>>> {
         let block_meta_revs = self.grid_pad.read().await.get_block_meta_revs();
         Ok(block_meta_revs)

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

@@ -2,7 +2,7 @@ use flowy_grid::entities::FieldType;
 use std::sync::Arc;
 
 use flowy_grid::services::field::{
-    DateCellChangesetPB, MultiSelectTypeOptionPB, SelectOptionPB, SingleSelectTypeOptionPB,
+    DateCellChangeset, MultiSelectTypeOptionPB, SelectOptionPB, SingleSelectTypeOptionPB,
 };
 use flowy_grid::services::row::RowRevisionBuilder;
 use grid_rev_model::{FieldRevision, RowRevision};
@@ -38,7 +38,7 @@ impl<'a> GridRowTestBuilder<'a> {
     }
 
     pub fn insert_date_cell(&mut self, data: &str) -> String {
-        let value = serde_json::to_string(&DateCellChangesetPB {
+        let value = serde_json::to_string(&DateCellChangeset {
             date: Some(data.to_string()),
             time: None,
         })

+ 1 - 1
frontend/rust-lib/flowy-grid/tests/grid/field_test/util.rs

@@ -55,7 +55,7 @@ pub fn create_single_select_field(grid_id: &str) -> (CreateFieldParams, FieldRev
 //  The grid will contains all existing field types and there are three empty rows in this grid.
 
 pub fn make_date_cell_string(s: &str) -> String {
-    serde_json::to_string(&DateCellChangesetPB {
+    serde_json::to_string(&DateCellChangeset {
         date: Some(s.to_string()),
         time: None,
     })