Browse Source

chore: insert cell content when creating card

appflowy 3 năm trước cách đây
mục cha
commit
43eaa2748d

+ 3 - 3
frontend/app_flowy/lib/plugins/board/application/board_bloc.dart

@@ -52,8 +52,8 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
             _startListening();
             await _loadGrid(emit);
           },
-          createRow: () async {
-            final result = await _dataController.createRow();
+          createRow: (groupId) async {
+            final result = await _dataController.createBoardCard(groupId);
             result.fold(
               (rowPB) {
                 emit(state.copyWith(editingRow: some(rowPB)));
@@ -153,7 +153,7 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
 @freezed
 class BoardEvent with _$BoardEvent {
   const factory BoardEvent.initial() = InitialGrid;
-  const factory BoardEvent.createRow() = _CreateRow;
+  const factory BoardEvent.createRow(String groupId) = _CreateRow;
   const factory BoardEvent.endEditRow(String rowId) = _EndEditRow;
   const factory BoardEvent.didReceiveGroups(List<GroupPB> groups) =
       _DidReceiveGroup;

+ 4 - 4
frontend/app_flowy/lib/plugins/board/application/board_data_controller.dart

@@ -21,7 +21,7 @@ typedef OnError = void Function(FlowyError);
 
 class BoardDataController {
   final String gridId;
-  final GridService _gridFFIService;
+  final GridFFIService _gridFFIService;
   final GridFieldCache fieldCache;
 
   // key: the block id
@@ -45,7 +45,7 @@ class BoardDataController {
   BoardDataController({required ViewPB view})
       : gridId = view.id,
         _blocks = LinkedHashMap.new(),
-        _gridFFIService = GridService(gridId: view.id),
+        _gridFFIService = GridFFIService(gridId: view.id),
         fieldCache = GridFieldCache(gridId: view.id);
 
   void addListener({
@@ -88,8 +88,8 @@ class BoardDataController {
     );
   }
 
-  Future<Either<RowPB, FlowyError>> createRow() {
-    return _gridFFIService.createRow();
+  Future<Either<RowPB, FlowyError>> createBoardCard(String groupId) {
+    return _gridFFIService.createBoardCard(groupId);
   }
 
   Future<void> dispose() async {

+ 1 - 1
frontend/app_flowy/lib/plugins/board/presentation/board_page.dart

@@ -88,7 +88,7 @@ class BoardContent extends StatelessWidget {
         height: 50,
         margin: config.columnItemPadding,
         onAddButtonClick: () {
-          context.read<BoardBloc>().add(const BoardEvent.createRow());
+          context.read<BoardBloc>().add(BoardEvent.createRow(columnData.id));
         });
   }
 

+ 2 - 2
frontend/app_flowy/lib/plugins/grid/application/grid_data_controller.dart

@@ -24,7 +24,7 @@ typedef ListenOnRowChangedCondition = bool Function();
 
 class GridDataController {
   final String gridId;
-  final GridService _gridFFIService;
+  final GridFFIService _gridFFIService;
   final GridFieldCache fieldCache;
 
   // key: the block id
@@ -47,7 +47,7 @@ class GridDataController {
   GridDataController({required ViewPB view})
       : gridId = view.id,
         _blocks = LinkedHashMap.new(),
-        _gridFFIService = GridService(gridId: view.id),
+        _gridFFIService = GridFFIService(gridId: view.id),
         fieldCache = GridFieldCache(gridId: view.id);
 
   void addListener({

+ 10 - 2
frontend/app_flowy/lib/plugins/grid/application/grid_service.dart

@@ -3,14 +3,15 @@ import 'package:flowy_sdk/dispatch/dispatch.dart';
 import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
 import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart';
 import 'package:flowy_sdk/protobuf/flowy-grid/block_entities.pb.dart';
+import 'package:flowy_sdk/protobuf/flowy-grid/board_card.pb.dart';
 import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
 import 'package:flowy_sdk/protobuf/flowy-grid/grid_entities.pb.dart';
 import 'package:flowy_sdk/protobuf/flowy-grid/group.pb.dart';
 import 'package:flowy_sdk/protobuf/flowy-grid/row_entities.pb.dart';
 
-class GridService {
+class GridFFIService {
   final String gridId;
-  GridService({
+  GridFFIService({
     required this.gridId,
   });
 
@@ -27,6 +28,13 @@ class GridService {
     return GridEventCreateRow(payload).send();
   }
 
+  Future<Either<RowPB, FlowyError>> createBoardCard(String groupId) {
+    CreateBoardCardPayloadPB payload = CreateBoardCardPayloadPB.create()
+      ..gridId = gridId
+      ..groupId = groupId;
+    return GridEventCreateBoardCard(payload).send();
+  }
+
   Future<Either<RepeatedFieldPB, FlowyError>> getFields(
       {required List<FieldIdPB> fieldIds}) {
     final payload = QueryFieldPayloadPB.create()

+ 41 - 0
frontend/rust-lib/flowy-grid/src/entities/group_entities/board_card.rs

@@ -1,3 +1,4 @@
+use crate::entities::RowPB;
 use flowy_derive::ProtoBuf;
 use flowy_error::ErrorCode;
 use flowy_grid_data_model::parser::NotEmptyStr;
@@ -27,3 +28,43 @@ impl TryInto<CreateBoardCardParams> for CreateBoardCardPayloadPB {
         })
     }
 }
+
+#[derive(Debug, Default, ProtoBuf)]
+pub struct BoardCardChangesetPB {
+    #[pb(index = 1)]
+    pub group_id: String,
+
+    #[pb(index = 2)]
+    pub inserted_cards: Vec<RowPB>,
+
+    #[pb(index = 3)]
+    pub deleted_cards: Vec<String>,
+
+    #[pb(index = 4)]
+    pub updated_cards: Vec<RowPB>,
+}
+impl BoardCardChangesetPB {
+    pub fn insert(group_id: String, inserted_cards: Vec<RowPB>) -> Self {
+        Self {
+            group_id,
+            inserted_cards,
+            ..Default::default()
+        }
+    }
+
+    pub fn delete(group_id: String, deleted_cards: Vec<String>) -> Self {
+        Self {
+            group_id,
+            deleted_cards,
+            ..Default::default()
+        }
+    }
+
+    pub fn update(group_id: String, updated_cards: Vec<RowPB>) -> Self {
+        Self {
+            group_id,
+            updated_cards,
+            ..Default::default()
+        }
+    }
+}

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

@@ -424,6 +424,6 @@ pub(crate) async fn create_board_card_handler(
 ) -> DataResult<RowPB, FlowyError> {
     let params: CreateBoardCardParams = data.into_inner().try_into()?;
     let editor = manager.get_grid_editor(params.grid_id.as_ref())?;
-    let row = editor.create_board_card().await?;
+    let row = editor.create_board_card(&params.group_id).await?;
     data_result(row)
 }

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

@@ -39,7 +39,7 @@ pub fn create(grid_manager: Arc<GridManager>) -> Module {
         // Date
         .event(GridEvent::UpdateDateCell, update_date_cell_handler)
         // Group
-        .event(GridEvent::CreateBoardCard, create_row_handler)
+        .event(GridEvent::CreateBoardCard, create_board_card_handler)
         .event(GridEvent::GetGroup, get_groups_handler);
 
     module

+ 41 - 0
frontend/rust-lib/flowy-grid/src/services/cell/cell_operation.rs

@@ -135,6 +135,47 @@ pub fn try_decode_cell_data(
     }
 }
 
+pub fn insert_text_cell(s: String, field_rev: &FieldRevision) -> CellRevision {
+    let data = apply_cell_data_changeset(s, None, field_rev).unwrap();
+    CellRevision::new(data)
+}
+
+pub fn insert_number_cell(num: i64, field_rev: &FieldRevision) -> CellRevision {
+    let data = apply_cell_data_changeset(num, None, field_rev).unwrap();
+    CellRevision::new(data)
+}
+
+pub fn insert_url_cell(url: String, field_rev: &FieldRevision) -> CellRevision {
+    let data = apply_cell_data_changeset(url, None, field_rev).unwrap();
+    CellRevision::new(data)
+}
+
+pub fn insert_checkbox_cell(is_check: bool, field_rev: &FieldRevision) -> CellRevision {
+    let s = if is_check {
+        CHECK.to_string()
+    } else {
+        UNCHECK.to_string()
+    };
+    let data = apply_cell_data_changeset(s, None, field_rev).unwrap();
+    CellRevision::new(data)
+}
+
+pub fn insert_date_cell(timestamp: i64, field_rev: &FieldRevision) -> CellRevision {
+    let cell_data = serde_json::to_string(&DateCellChangesetPB {
+        date: Some(timestamp.to_string()),
+        time: None,
+    })
+    .unwrap();
+    let data = apply_cell_data_changeset(cell_data, None, field_rev).unwrap();
+    CellRevision::new(data)
+}
+
+pub fn insert_select_option_cell(option_id: String, field_rev: &FieldRevision) -> CellRevision {
+    let cell_data = SelectOptionCellChangeset::from_insert(&option_id).to_str();
+    let data = apply_cell_data_changeset(cell_data, None, field_rev).unwrap();
+    CellRevision::new(data)
+}
+
 /// If the cell data is not String type, it should impl this trait.
 /// Deserialize the String into cell specific data type.  
 pub trait FromCellString {

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

@@ -552,9 +552,15 @@ impl GridRevisionEditor {
         })
     }
 
-    pub async fn create_board_card(&self) -> FlowyResult<RowPB> {
+    pub async fn create_board_card(&self, group_id: &str) -> FlowyResult<RowPB> {
         let mut row_rev = self.create_row_rev().await?;
-        let _ = self.group_service.write().await.create_board_card(&mut row_rev).await;
+        let _ = self
+            .group_service
+            .write()
+            .await
+            .create_board_card(&mut row_rev, group_id)
+            .await;
+
         self.create_row_pb(row_rev, None).await
     }
 
@@ -573,6 +579,7 @@ impl GridRevisionEditor {
         Ok(row_rev)
     }
 
+    #[tracing::instrument(level = "trace", skip_all, err)]
     async fn create_row_pb(&self, row_rev: RowRevision, start_row_id: Option<String>) -> FlowyResult<RowPB> {
         let row_pb = RowPB::from(&row_rev);
         let block_id = row_rev.block_id.clone();

+ 10 - 5
frontend/rust-lib/flowy-grid/src/services/group/group_generator/checkbox_group.rs

@@ -1,6 +1,7 @@
 use crate::entities::{CheckboxGroupConfigurationPB, RowPB};
 use flowy_error::FlowyResult;
-use flowy_grid_data_model::revision::RowRevision;
+use flowy_grid_data_model::revision::{FieldRevision, RowRevision};
+use std::sync::Arc;
 
 use crate::services::field::{CheckboxCellData, CheckboxCellDataParser, CheckboxTypeOptionPB, CHECK, UNCHECK};
 use crate::services::group::{
@@ -19,15 +20,19 @@ impl Groupable for CheckboxGroupController {
 }
 
 impl GroupActionHandler for CheckboxGroupController {
+    fn field_id(&self) -> &str {
+        &self.field_id
+    }
+
     fn get_groups(&self) -> Vec<Group> {
-        self.groups()
+        self.make_groups()
     }
 
-    fn group_row(&mut self, row_rev: &RowRevision) -> FlowyResult<()> {
-        self.handle_row(row_rev)
+    fn group_rows(&mut self, row_revs: &[Arc<RowRevision>], field_rev: &FieldRevision) -> FlowyResult<()> {
+        self.handle_rows(row_revs, field_rev)
     }
 
-    fn create_card(&self, row_rev: &mut RowRevision) {
+    fn create_card(&self, row_rev: &mut RowRevision, field_rev: &FieldRevision, group_id: &str) {
         todo!()
     }
 }

+ 42 - 37
frontend/rust-lib/flowy-grid/src/services/group/group_generator/generator.rs

@@ -1,11 +1,13 @@
 use crate::entities::{GroupPB, RowPB};
 use crate::services::cell::{decode_any_cell_data, CellBytesParser};
 use bytes::Bytes;
-use flowy_error::FlowyResult;
+use flowy_error::{FlowyError, FlowyResult};
 use flowy_grid_data_model::revision::{
     FieldRevision, GroupConfigurationRevision, RowRevision, TypeOptionDataDeserializer,
 };
+use futures::future::BoxFuture;
 use indexmap::IndexMap;
+use lib_infra::future::{BoxResultFuture, FutureResult};
 use std::marker::PhantomData;
 use std::sync::Arc;
 
@@ -34,15 +36,14 @@ pub trait Groupable {
 }
 
 pub trait GroupActionHandler: Send + Sync {
+    fn field_id(&self) -> &str;
     fn get_groups(&self) -> Vec<Group>;
-    fn group_row(&mut self, row_rev: &RowRevision) -> FlowyResult<()>;
-    fn group_rows(&mut self, row_revs: &[Arc<RowRevision>]) -> FlowyResult<()> {
-        for row_rev in row_revs {
-            let _ = self.group_row(row_rev)?;
-        }
-        Ok(())
-    }
-    fn create_card(&self, row_rev: &mut RowRevision);
+    fn group_rows(&mut self, row_revs: &[Arc<RowRevision>], field_rev: &FieldRevision) -> FlowyResult<()>;
+    fn create_card(&self, row_rev: &mut RowRevision, field_rev: &FieldRevision, group_id: &str);
+}
+
+pub trait GroupActionHandler2: Send + Sync {
+    fn create_card(&self, row_rev: &mut RowRevision, field_rev: &FieldRevision, group_id: &str);
 }
 
 const DEFAULT_GROUP_ID: &str = "default_group";
@@ -52,8 +53,8 @@ const DEFAULT_GROUP_ID: &str = "default_group";
 /// G: the group container generator
 /// P: the parser that impl [CellBytesParser] for the CellBytes
 pub struct GroupController<C, T, G, P> {
-    pub field_rev: Arc<FieldRevision>,
-    groups: IndexMap<String, Group>,
+    pub field_id: String,
+    pub groups_map: IndexMap<String, Group>,
     default_group: Group,
     pub type_option: Option<T>,
     pub configuration: Option<C>,
@@ -86,7 +87,7 @@ where
     G: GroupGenerator<ConfigurationType = C, TypeOptionType = T>,
 {
     pub fn new(
-        field_rev: Arc<FieldRevision>,
+        field_rev: &Arc<FieldRevision>,
         configuration: GroupConfigurationRevision,
         cell_content_provider: &dyn GroupCellContentProvider,
     ) -> FlowyResult<Self> {
@@ -106,8 +107,8 @@ where
         };
 
         Ok(Self {
-            field_rev,
-            groups: groups.into_iter().map(|group| (group.id.clone(), group)).collect(),
+            field_id: field_rev.id.clone(),
+            groups_map: groups.into_iter().map(|group| (group.id.clone(), group)).collect(),
             default_group,
             type_option,
             configuration,
@@ -116,9 +117,9 @@ where
         })
     }
 
-    pub fn groups(&self) -> Vec<Group> {
+    pub fn make_groups(&self) -> Vec<Group> {
         let default_group = self.default_group.clone();
-        let mut groups: Vec<Group> = self.groups.values().cloned().collect();
+        let mut groups: Vec<Group> = self.groups_map.values().cloned().collect();
         if !default_group.rows.is_empty() {
             groups.push(default_group);
         }
@@ -131,34 +132,38 @@ where
     P: CellBytesParser,
     Self: Groupable<CellDataType = P::Object>,
 {
-    pub fn handle_row(&mut self, row: &RowRevision) -> FlowyResult<()> {
+    pub fn handle_rows(&mut self, rows: &[Arc<RowRevision>], field_rev: &FieldRevision) -> FlowyResult<()> {
+        // The field_rev might be None if corresponding field_rev is deleted.
         if self.configuration.is_none() {
             return Ok(());
         }
-        if let Some(cell_rev) = row.cells.get(&self.field_rev.id) {
-            let mut records: Vec<GroupRecord> = vec![];
-            let cell_bytes = decode_any_cell_data(cell_rev.data.clone(), &self.field_rev);
-            let cell_data = cell_bytes.parser::<P>()?;
-            for group in self.groups.values() {
-                if self.can_group(&group.content, &cell_data) {
-                    records.push(GroupRecord {
-                        row: row.into(),
-                        group_id: group.id.clone(),
-                    });
+
+        for row in rows {
+            if let Some(cell_rev) = row.cells.get(&self.field_id) {
+                let mut records: Vec<GroupRecord> = vec![];
+                let cell_bytes = decode_any_cell_data(cell_rev.data.clone(), &field_rev);
+                let cell_data = cell_bytes.parser::<P>()?;
+                for group in self.groups_map.values() {
+                    if self.can_group(&group.content, &cell_data) {
+                        records.push(GroupRecord {
+                            row: row.into(),
+                            group_id: group.id.clone(),
+                        });
+                    }
                 }
-            }
 
-            if records.is_empty() {
-                self.default_group.rows.push(row.into());
-            } else {
-                for record in records {
-                    if let Some(group) = self.groups.get_mut(&record.group_id) {
-                        group.rows.push(record.row);
+                if records.is_empty() {
+                    self.default_group.rows.push(row.into());
+                } else {
+                    for record in records {
+                        if let Some(group) = self.groups_map.get_mut(&record.group_id) {
+                            group.rows.push(record.row);
+                        }
                     }
                 }
+            } else {
+                self.default_group.rows.push(row.into());
             }
-        } else {
-            self.default_group.rows.push(row.into());
         }
 
         Ok(())
@@ -166,7 +171,7 @@ where
 
     pub fn group_rows(&mut self, rows: &[Arc<RowRevision>]) -> FlowyResult<()> {
         for row in rows {
-            let _ = self.handle_row(row)?;
+            // let _ = self.handle_row(row)?;
         }
         Ok(())
     }

+ 37 - 12
frontend/rust-lib/flowy-grid/src/services/group/group_generator/select_option_group.rs

@@ -1,6 +1,9 @@
 use crate::entities::{RowPB, SelectOptionGroupConfigurationPB};
-use flowy_error::FlowyResult;
-use flowy_grid_data_model::revision::RowRevision;
+use crate::services::cell::insert_select_option_cell;
+use flowy_error::{FlowyError, FlowyResult};
+use flowy_grid_data_model::revision::{FieldRevision, RowRevision};
+use lib_infra::future::FutureResult;
+use std::sync::Arc;
 
 use crate::services::field::{
     MultiSelectTypeOptionPB, SelectOptionCellDataPB, SelectOptionCellDataParser, SingleSelectTypeOptionPB,
@@ -25,16 +28,27 @@ impl Groupable for SingleSelectGroupController {
 }
 
 impl GroupActionHandler for SingleSelectGroupController {
+    fn field_id(&self) -> &str {
+        &self.field_id
+    }
+
     fn get_groups(&self) -> Vec<Group> {
-        self.groups()
+        self.make_groups()
     }
 
-    fn group_row(&mut self, row_rev: &RowRevision) -> FlowyResult<()> {
-        self.handle_row(row_rev)
+    fn group_rows(&mut self, row_revs: &[Arc<RowRevision>], field_rev: &FieldRevision) -> FlowyResult<()> {
+        self.handle_rows(row_revs, field_rev)
     }
 
-    fn create_card(&self, row_rev: &mut RowRevision) {
-        todo!()
+    fn create_card(&self, row_rev: &mut RowRevision, field_rev: &FieldRevision, group_id: &str) {
+        let group: Option<&Group> = self.groups_map.get(group_id);
+        match group {
+            None => {}
+            Some(group) => {
+                let cell_rev = insert_select_option_cell(group.id.clone(), field_rev);
+                row_rev.cells.insert(field_rev.id.clone(), cell_rev);
+            }
+        }
     }
 }
 
@@ -79,16 +93,27 @@ impl Groupable for MultiSelectGroupController {
 }
 
 impl GroupActionHandler for MultiSelectGroupController {
+    fn field_id(&self) -> &str {
+        &self.field_id
+    }
+
     fn get_groups(&self) -> Vec<Group> {
-        self.groups()
+        self.make_groups()
     }
 
-    fn group_row(&mut self, row_rev: &RowRevision) -> FlowyResult<()> {
-        self.handle_row(row_rev)
+    fn group_rows(&mut self, row_revs: &[Arc<RowRevision>], field_rev: &FieldRevision) -> FlowyResult<()> {
+        self.handle_rows(row_revs, field_rev)
     }
 
-    fn create_card(&self, row_rev: &mut RowRevision) {
-        todo!()
+    fn create_card(&self, row_rev: &mut RowRevision, field_rev: &FieldRevision, group_id: &str) {
+        let group: Option<&Group> = self.groups_map.get(group_id);
+        match group {
+            None => tracing::warn!("Can not find the group: {}", group_id),
+            Some(group) => {
+                let cell_rev = insert_select_option_cell(group.id.clone(), field_rev);
+                row_rev.cells.insert(field_rev.id.clone(), cell_rev);
+            }
+        }
     }
 }
 

+ 22 - 6
frontend/rust-lib/flowy-grid/src/services/group/group_service.rs

@@ -14,6 +14,7 @@ use bytes::Bytes;
 use flowy_error::FlowyResult;
 use flowy_grid_data_model::revision::{gen_grid_group_id, FieldRevision, GroupConfigurationRevision, RowRevision};
 use flowy_sync::client_grid::GridRevisionPad;
+use futures::future::BoxFuture;
 use std::sync::Arc;
 use tokio::sync::RwLock;
 
@@ -61,9 +62,24 @@ impl GridGroupService {
         }
     }
 
-    pub(crate) async fn create_board_card(&self, row_rev: &mut RowRevision) {
+    #[tracing::instrument(level = "debug", skip(self, row_rev))]
+    pub(crate) async fn create_board_card(&self, row_rev: &mut RowRevision, group_id: &str) {
         if let Some(group_action_handler) = self.group_action_handler.as_ref() {
-            group_action_handler.write().await.create_card(row_rev);
+            match self
+                .grid_pad
+                .read()
+                .await
+                .get_field_rev(group_action_handler.read().await.field_id())
+            {
+                None => tracing::warn!("Fail to create card because the field does not exist"),
+                Some((_, field_rev)) => {
+                    tracing::trace!("Create card");
+                    group_action_handler
+                        .write()
+                        .await
+                        .create_card(row_rev, field_rev, group_id);
+                }
+            }
         }
     }
 
@@ -100,15 +116,15 @@ impl GridGroupService {
                 // let generator = GroupGenerator::<DateGroupConfigurationPB>::from_configuration(configuration);
             }
             FieldType::SingleSelect => {
-                let controller = SingleSelectGroupController::new(field_rev.clone(), configuration, &self.grid_pad)?;
+                let controller = SingleSelectGroupController::new(field_rev, configuration, &self.grid_pad)?;
                 self.group_action_handler = Some(Arc::new(RwLock::new(controller)));
             }
             FieldType::MultiSelect => {
-                let controller = MultiSelectGroupController::new(field_rev.clone(), configuration, &self.grid_pad)?;
+                let controller = MultiSelectGroupController::new(field_rev, configuration, &self.grid_pad)?;
                 self.group_action_handler = Some(Arc::new(RwLock::new(controller)));
             }
             FieldType::Checkbox => {
-                let controller = CheckboxGroupController::new(field_rev.clone(), configuration, &self.grid_pad)?;
+                let controller = CheckboxGroupController::new(field_rev, configuration, &self.grid_pad)?;
                 self.group_action_handler = Some(Arc::new(RwLock::new(controller)));
             }
             FieldType::URL => {
@@ -119,7 +135,7 @@ impl GridGroupService {
         let mut groups = vec![];
         if let Some(group_action_handler) = self.group_action_handler.as_ref() {
             let mut write_guard = group_action_handler.write().await;
-            let _ = write_guard.group_rows(&row_revs)?;
+            let _ = write_guard.group_rows(&row_revs, field_rev)?;
             groups = write_guard.get_groups();
             drop(write_guard);
         }

+ 49 - 25
frontend/rust-lib/flowy-grid/src/services/row/row_builder.rs

@@ -1,4 +1,7 @@
-use crate::services::cell::apply_cell_data_changeset;
+use crate::services::cell::{
+    apply_cell_data_changeset, insert_checkbox_cell, insert_date_cell, insert_number_cell, insert_select_option_cell,
+    insert_text_cell, insert_url_cell,
+};
 use crate::services::field::{DateCellChangesetPB, SelectOptionCellChangeset};
 use flowy_grid_data_model::revision::{gen_row_id, CellRevision, FieldRevision, RowRevision, DEFAULT_ROW_HEIGHT};
 use indexmap::IndexMap;
@@ -34,47 +37,68 @@ impl<'a> RowRevisionBuilder<'a> {
         }
     }
 
-    pub fn insert_cell(&mut self, field_id: &str, data: String) {
+    pub fn insert_text_cell(&mut self, field_id: &str, data: String) {
         match self.field_rev_map.get(&field_id.to_owned()) {
-            None => {
-                tracing::warn!("Can't find the field with id: {}", field_id);
+            None => tracing::warn!("Can't find the text field with id: {}", field_id),
+            Some(field_rev) => {
+                self.payload
+                    .cell_by_field_id
+                    .insert(field_id.to_owned(), insert_text_cell(data, field_rev));
             }
+        }
+    }
+
+    pub fn insert_url_cell(&mut self, field_id: &str, data: String) {
+        match self.field_rev_map.get(&field_id.to_owned()) {
+            None => tracing::warn!("Can't find the url field with id: {}", field_id),
             Some(field_rev) => {
-                let data = apply_cell_data_changeset(data, None, field_rev).unwrap();
-                let cell = CellRevision::new(data);
-                self.payload.cell_by_field_id.insert(field_id.to_owned(), cell);
+                self.payload
+                    .cell_by_field_id
+                    .insert(field_id.to_owned(), insert_url_cell(data, field_rev));
             }
         }
     }
 
-    pub fn insert_date_cell(&mut self, field_id: &str, timestamp: i64) {
+    pub fn insert_number_cell(&mut self, field_id: &str, num: i64) {
         match self.field_rev_map.get(&field_id.to_owned()) {
-            None => {
-                tracing::warn!("Invalid field_id: {}", field_id);
+            None => tracing::warn!("Can't find the number field with id: {}", field_id),
+            Some(field_rev) => {
+                self.payload
+                    .cell_by_field_id
+                    .insert(field_id.to_owned(), insert_number_cell(num, field_rev));
             }
+        }
+    }
+
+    pub fn insert_checkbox_cell(&mut self, field_id: &str, is_check: bool) {
+        match self.field_rev_map.get(&field_id.to_owned()) {
+            None => tracing::warn!("Can't find the checkbox field with id: {}", field_id),
             Some(field_rev) => {
-                let cell_data = serde_json::to_string(&DateCellChangesetPB {
-                    date: Some(timestamp.to_string()),
-                    time: None,
-                })
-                .unwrap();
-                let data = apply_cell_data_changeset(cell_data, None, field_rev).unwrap();
-                let cell = CellRevision::new(data);
-                self.payload.cell_by_field_id.insert(field_id.to_owned(), cell);
+                self.payload
+                    .cell_by_field_id
+                    .insert(field_id.to_owned(), insert_checkbox_cell(is_check, field_rev));
             }
         }
     }
 
-    pub fn insert_select_option_cell(&mut self, field_id: &str, data: String) {
+    pub fn insert_date_cell(&mut self, field_id: &str, timestamp: i64) {
         match self.field_rev_map.get(&field_id.to_owned()) {
-            None => {
-                tracing::warn!("Invalid field_id: {}", field_id);
+            None => tracing::warn!("Can't find the date field with id: {}", field_id),
+            Some(field_rev) => {
+                self.payload
+                    .cell_by_field_id
+                    .insert(field_id.to_owned(), insert_date_cell(timestamp, field_rev));
             }
+        }
+    }
+
+    pub fn insert_select_option_cell(&mut self, field_id: &str, data: String) {
+        match self.field_rev_map.get(&field_id.to_owned()) {
+            None => tracing::warn!("Can't find the select option field with id: {}", field_id),
             Some(field_rev) => {
-                let cell_data = SelectOptionCellChangeset::from_insert(&data).to_str();
-                let data = apply_cell_data_changeset(cell_data, None, field_rev).unwrap();
-                let cell = CellRevision::new(data);
-                self.payload.cell_by_field_id.insert(field_id.to_owned(), cell);
+                self.payload
+                    .cell_by_field_id
+                    .insert(field_id.to_owned(), insert_select_option_cell(data, field_rev));
             }
         }
     }

+ 4 - 9
frontend/rust-lib/flowy-grid/src/util.rs

@@ -114,20 +114,15 @@ pub fn make_default_board() -> BuildGridContext {
         row_builder.insert_select_option_cell(&multi_select_field_id, apple_option.id.clone());
         row_builder.insert_select_option_cell(&multi_select_field_id, banana_option.id.clone());
         // insert text
-        row_builder.insert_cell(&text_field_id, format!("Card {}", i));
+        row_builder.insert_text_cell(&text_field_id, format!("Card {}", i));
         // insert date
         row_builder.insert_date_cell(&date_field_id, timestamp);
         // number
-        row_builder.insert_cell(&number_field_id, format!("{}", i));
+        row_builder.insert_number_cell(&number_field_id, i);
         // checkbox
-        let is_check = if i % 2 == 0 {
-            CHECK.to_string()
-        } else {
-            UNCHECK.to_string()
-        };
-        row_builder.insert_cell(&checkbox_field_id, is_check);
+        row_builder.insert_checkbox_cell(&checkbox_field_id, i % 2 == 0);
         // url
-        row_builder.insert_cell(&url_field_id, "https://appflowy.io".to_string());
+        row_builder.insert_url_cell(&url_field_id, "https://appflowy.io".to_string());
 
         let row = row_builder.build();
         grid_builder.add_row(row);

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

@@ -26,14 +26,14 @@ impl<'a> GridRowTestBuilder<'a> {
 
     pub fn insert_text_cell(&mut self, data: &str) -> String {
         let text_field = self.field_rev_with_type(&FieldType::RichText);
-        self.inner_builder.insert_cell(&text_field.id, data.to_string());
+        self.inner_builder.insert_text_cell(&text_field.id, data.to_string());
 
         text_field.id.clone()
     }
 
     pub fn insert_number_cell(&mut self, data: &str) -> String {
         let number_field = self.field_rev_with_type(&FieldType::Number);
-        self.inner_builder.insert_cell(&number_field.id, data.to_string());
+        self.inner_builder.insert_text_cell(&number_field.id, data.to_string());
         number_field.id.clone()
     }
 
@@ -44,20 +44,21 @@ impl<'a> GridRowTestBuilder<'a> {
         })
         .unwrap();
         let date_field = self.field_rev_with_type(&FieldType::DateTime);
-        self.inner_builder.insert_cell(&date_field.id, value);
+        self.inner_builder.insert_text_cell(&date_field.id, value);
         date_field.id.clone()
     }
 
     pub fn insert_checkbox_cell(&mut self, data: &str) -> String {
         let checkbox_field = self.field_rev_with_type(&FieldType::Checkbox);
-        self.inner_builder.insert_cell(&checkbox_field.id, data.to_string());
+        self.inner_builder
+            .insert_text_cell(&checkbox_field.id, data.to_string());
 
         checkbox_field.id.clone()
     }
 
     pub fn insert_url_cell(&mut self, data: &str) -> String {
         let url_field = self.field_rev_with_type(&FieldType::URL);
-        self.inner_builder.insert_cell(&url_field.id, data.to_string());
+        self.inner_builder.insert_text_cell(&url_field.id, data.to_string());
         url_field.id.clone()
     }
 

+ 1 - 1
shared-lib/flowy-sync/src/client_grid/grid_revision_pad.rs

@@ -44,7 +44,7 @@ impl GridRevisionPad {
             .blocks
             .iter()
             .map(|block| {
-                let mut duplicated_block = (&*block.clone()).clone();
+                let mut duplicated_block = (&**block).clone();
                 duplicated_block.block_id = gen_block_id();
                 duplicated_block
             })