Przeglądaj źródła

chore: create default grid

appflowy 3 lat temu
rodzic
commit
6579940dc8
42 zmienionych plików z 410 dodań i 291 usunięć
  1. 3 3
      frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-folder-data-model/view.pb.dart
  2. 2 2
      frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-folder-data-model/view.pbenum.dart
  3. 2 2
      frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-folder-data-model/view.pbjson.dart
  4. 3 4
      frontend/rust-lib/flowy-block/src/editor.rs
  5. 0 1
      frontend/rust-lib/flowy-block/src/queue.rs
  6. 1 1
      frontend/rust-lib/flowy-block/tests/document/document_test.rs
  7. 1 1
      frontend/rust-lib/flowy-block/tests/document/edit_script.rs
  8. 5 5
      frontend/rust-lib/flowy-folder/src/manager.rs
  9. 5 5
      frontend/rust-lib/flowy-folder/src/services/folder_editor.rs
  10. 1 1
      frontend/rust-lib/flowy-folder/src/services/persistence/migration.rs
  11. 2 2
      frontend/rust-lib/flowy-folder/src/services/persistence/version_1/view_sql.rs
  12. 11 15
      frontend/rust-lib/flowy-folder/src/services/view/controller.rs
  13. 2 11
      frontend/rust-lib/flowy-folder/tests/workspace/folder_test.rs
  14. 2 1
      frontend/rust-lib/flowy-folder/tests/workspace/helper.rs
  15. 11 12
      frontend/rust-lib/flowy-folder/tests/workspace/script.rs
  16. 2 2
      frontend/rust-lib/flowy-grid/src/event_handler.rs
  17. 27 5
      frontend/rust-lib/flowy-grid/src/manager.rs
  18. 0 77
      frontend/rust-lib/flowy-grid/src/services/grid_builder.rs
  19. 41 27
      frontend/rust-lib/flowy-grid/src/services/grid_editor.rs
  20. 16 14
      frontend/rust-lib/flowy-grid/src/services/grid_meta_editor.rs
  21. 0 1
      frontend/rust-lib/flowy-grid/src/services/mod.rs
  22. 0 0
      frontend/rust-lib/flowy-grid/tests/grid_test.rs
  23. 14 11
      frontend/rust-lib/flowy-net/src/local_server/persistence.rs
  24. 2 2
      frontend/rust-lib/flowy-net/src/local_server/server.rs
  25. 41 11
      frontend/rust-lib/flowy-sdk/src/deps_resolve/folder_deps.rs
  26. 2 2
      frontend/rust-lib/flowy-sync/src/cache/disk/grid_meta_rev_impl.rs
  27. 2 2
      frontend/rust-lib/flowy-sync/src/cache/disk/grid_rev_impl.rs
  28. 0 2
      frontend/rust-lib/flowy-sync/src/cache/disk/mod.rs
  29. 2 2
      frontend/rust-lib/flowy-sync/src/cache/disk/text_rev_impl.rs
  30. 0 1
      frontend/rust-lib/flowy-sync/src/rev_manager.rs
  31. 1 1
      frontend/rust-lib/flowy-test/src/helper.rs
  32. 25 12
      shared-lib/flowy-collaboration/src/client_grid/block_pad.rs
  33. 114 0
      shared-lib/flowy-collaboration/src/client_grid/grid_builder.rs
  34. 12 9
      shared-lib/flowy-collaboration/src/client_grid/grid_pad.rs
  35. 2 0
      shared-lib/flowy-collaboration/src/client_grid/mod.rs
  36. 16 15
      shared-lib/flowy-collaboration/src/server_document/document_manager.rs
  37. 4 4
      shared-lib/flowy-folder-data-model/src/entities/view.rs
  38. 18 18
      shared-lib/flowy-folder-data-model/src/protobuf/model/view.rs
  39. 1 1
      shared-lib/flowy-folder-data-model/src/protobuf/proto/view.proto
  40. 1 1
      shared-lib/flowy-folder-data-model/src/user_default.rs
  41. 13 4
      shared-lib/flowy-grid-data-model/src/entities/meta.rs
  42. 3 1
      shared-lib/flowy-grid-data-model/tests/serde_test.rs

+ 3 - 3
frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-folder-data-model/view.pb.dart

@@ -20,7 +20,7 @@ class View extends $pb.GeneratedMessage {
     ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'belongToId')
     ..aOS(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'name')
     ..aOS(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'desc')
-    ..e<ViewDataType>(5, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'dataType', $pb.PbFieldType.OE, defaultOrMaker: ViewDataType.Block, valueOf: ViewDataType.valueOf, enumValues: ViewDataType.values)
+    ..e<ViewDataType>(5, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'dataType', $pb.PbFieldType.OE, defaultOrMaker: ViewDataType.TextBlock, valueOf: ViewDataType.valueOf, enumValues: ViewDataType.values)
     ..aInt64(6, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'version')
     ..aOM<RepeatedView>(7, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'belongings', subBuilder: RepeatedView.create)
     ..aInt64(8, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'modifiedTime')
@@ -274,7 +274,7 @@ class CreateViewPayload extends $pb.GeneratedMessage {
     ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'name')
     ..aOS(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'desc')
     ..aOS(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'thumbnail')
-    ..e<ViewDataType>(5, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'dataType', $pb.PbFieldType.OE, defaultOrMaker: ViewDataType.Block, valueOf: ViewDataType.valueOf, enumValues: ViewDataType.values)
+    ..e<ViewDataType>(5, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'dataType', $pb.PbFieldType.OE, defaultOrMaker: ViewDataType.TextBlock, valueOf: ViewDataType.valueOf, enumValues: ViewDataType.values)
     ..aOS(6, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'extData')
     ..a<$core.int>(7, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'pluginType', $pb.PbFieldType.O3)
     ..hasRequiredFields = false
@@ -408,7 +408,7 @@ class CreateViewParams extends $pb.GeneratedMessage {
     ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'name')
     ..aOS(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'desc')
     ..aOS(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'thumbnail')
-    ..e<ViewDataType>(5, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'dataType', $pb.PbFieldType.OE, defaultOrMaker: ViewDataType.Block, valueOf: ViewDataType.valueOf, enumValues: ViewDataType.values)
+    ..e<ViewDataType>(5, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'dataType', $pb.PbFieldType.OE, defaultOrMaker: ViewDataType.TextBlock, valueOf: ViewDataType.valueOf, enumValues: ViewDataType.values)
     ..aOS(6, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'extData')
     ..aOS(7, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'viewId')
     ..aOS(8, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'data')

+ 2 - 2
frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-folder-data-model/view.pbenum.dart

@@ -10,11 +10,11 @@ import 'dart:core' as $core;
 import 'package:protobuf/protobuf.dart' as $pb;
 
 class ViewDataType extends $pb.ProtobufEnum {
-  static const ViewDataType Block = ViewDataType._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Block');
+  static const ViewDataType TextBlock = ViewDataType._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'TextBlock');
   static const ViewDataType Grid = ViewDataType._(1, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Grid');
 
   static const $core.List<ViewDataType> values = <ViewDataType> [
-    Block,
+    TextBlock,
     Grid,
   ];
 

+ 2 - 2
frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-folder-data-model/view.pbjson.dart

@@ -12,13 +12,13 @@ import 'dart:typed_data' as $typed_data;
 const ViewDataType$json = const {
   '1': 'ViewDataType',
   '2': const [
-    const {'1': 'Block', '2': 0},
+    const {'1': 'TextBlock', '2': 0},
     const {'1': 'Grid', '2': 1},
   ],
 };
 
 /// Descriptor for `ViewDataType`. Decode as a `google.protobuf.EnumDescriptorProto`.
-final $typed_data.Uint8List viewDataTypeDescriptor = $convert.base64Decode('CgxWaWV3RGF0YVR5cGUSCQoFQmxvY2sQABIICgRHcmlkEAE=');
+final $typed_data.Uint8List viewDataTypeDescriptor = $convert.base64Decode('CgxWaWV3RGF0YVR5cGUSDQoJVGV4dEJsb2NrEAASCAoER3JpZBAB');
 @$core.Deprecated('Use viewDescriptor instead')
 const View$json = const {
   '1': 'View',

+ 3 - 4
frontend/rust-lib/flowy-block/src/editor.rs

@@ -1,4 +1,3 @@
-use crate::queue::TextBlockRevisionCompactor;
 use crate::web_socket::{make_block_ws_manager, EditorCommandSender};
 use crate::{
     errors::FlowyError,
@@ -40,7 +39,7 @@ impl ClientTextBlockEditor {
         rev_web_socket: Arc<dyn RevisionWebSocket>,
         cloud_service: Arc<dyn RevisionCloudService>,
     ) -> FlowyResult<Arc<Self>> {
-        let document_info = rev_manager.load::<BlockInfoBuilder>(cloud_service).await?;
+        let document_info = rev_manager.load::<TextBlockInfoBuilder>(cloud_service).await?;
         let delta = document_info.delta()?;
         let rev_manager = Arc::new(rev_manager);
         let doc_id = doc_id.to_string();
@@ -213,8 +212,8 @@ impl ClientTextBlockEditor {
     }
 }
 
-struct BlockInfoBuilder();
-impl RevisionObjectBuilder for BlockInfoBuilder {
+struct TextBlockInfoBuilder();
+impl RevisionObjectBuilder for TextBlockInfoBuilder {
     type Output = TextBlockInfo;
 
     fn build_object(object_id: &str, revisions: Vec<Revision>) -> FlowyResult<Self::Output> {

+ 0 - 1
frontend/rust-lib/flowy-block/src/queue.rs

@@ -11,7 +11,6 @@ use flowy_collaboration::{
 use flowy_error::{FlowyError, FlowyResult};
 use flowy_sync::{DeltaMD5, RevisionCompactor, RevisionManager, RichTextTransformDeltas, TransformDeltas};
 use futures::stream::StreamExt;
-use lib_ot::core::{Attributes, Delta};
 use lib_ot::{
     core::{Interval, OperationTransformable},
     rich_text::{RichTextAttribute, RichTextAttributes, RichTextDelta},

+ 1 - 1
frontend/rust-lib/flowy-block/tests/document/document_test.rs

@@ -1,5 +1,5 @@
 use crate::document::edit_script::{EditorScript::*, *};
-use flowy_collaboration::entities::revision::RevisionState;
+use flowy_sync::disk::RevisionState;
 use lib_ot::core::{count_utf16_code_units, Interval};
 
 #[tokio::test]

+ 1 - 1
frontend/rust-lib/flowy-block/tests/document/edit_script.rs

@@ -1,6 +1,6 @@
 use flowy_block::editor::ClientTextBlockEditor;
 use flowy_block::DOCUMENT_SYNC_INTERVAL_IN_MILLIS;
-use flowy_collaboration::entities::revision::RevisionState;
+use flowy_sync::disk::RevisionState;
 use flowy_test::{helper::ViewTest, FlowySDKTest};
 use lib_ot::{core::Interval, rich_text::RichTextDelta};
 use std::sync::Arc;

+ 5 - 5
frontend/rust-lib/flowy-folder/src/manager.rs

@@ -12,7 +12,7 @@ use bytes::Bytes;
 use chrono::Utc;
 
 use flowy_collaboration::client_document::default::{initial_quill_delta_string, initial_read_me};
-use flowy_collaboration::entities::revision::RepeatedRevision;
+
 use flowy_collaboration::{client_folder::FolderPad, entities::ws_data::ServerRevisionWSData};
 use flowy_error::FlowyError;
 use flowy_folder_data_model::entities::view::ViewDataType;
@@ -164,7 +164,7 @@ impl FolderManager {
         let _ = self.persistence.initialize(user_id, &folder_id).await?;
 
         let pool = self.persistence.db_pool()?;
-        let disk_cache = Arc::new(SQLiteTextBlockRevisionPersistence::new(&user_id, pool));
+        let disk_cache = Arc::new(SQLiteTextBlockRevisionPersistence::new(user_id, pool));
         let rev_persistence = Arc::new(RevisionPersistence::new(user_id, folder_id.as_ref(), disk_cache));
         let rev_manager = RevisionManager::new(user_id, folder_id.as_ref(), rev_persistence);
 
@@ -214,7 +214,7 @@ impl DefaultFolderBuilder {
                 };
                 let _ = view_controller.set_latest_view(&view.id);
                 let _ = view_controller
-                    .create_view(&view.id, ViewDataType::Block, Bytes::from(view_data))
+                    .create_view(&view.id, ViewDataType::TextBlock, Bytes::from(view_data))
                     .await?;
             }
         }
@@ -239,7 +239,7 @@ impl FolderManager {
 pub trait ViewDataProcessor {
     fn initialize(&self) -> FutureResult<(), FlowyError>;
 
-    fn create_container(&self, view_id: &str, repeated_revision: RepeatedRevision) -> FutureResult<(), FlowyError>;
+    fn create_container(&self, user_id: &str, view_id: &str, delta_data: Bytes) -> FutureResult<(), FlowyError>;
 
     fn delete_container(&self, view_id: &str) -> FutureResult<(), FlowyError>;
 
@@ -247,7 +247,7 @@ pub trait ViewDataProcessor {
 
     fn delta_str(&self, view_id: &str) -> FutureResult<String, FlowyError>;
 
-    fn default_view_data(&self, view_id: &str) -> String;
+    fn create_default_view(&self, user_id: &str, view_id: &str) -> FutureResult<String, FlowyError>;
 
     fn data_type(&self) -> ViewDataType;
 }

+ 5 - 5
frontend/rust-lib/flowy-folder/src/services/folder_editor.rs

@@ -8,14 +8,14 @@ use crate::manager::FolderId;
 use bytes::Bytes;
 use flowy_collaboration::util::make_delta_from_revisions;
 use flowy_error::{FlowyError, FlowyResult};
-use flowy_sync::disk::RevisionDiskCache;
+
 use flowy_sync::{
-    RevisionCloudService, RevisionCompactor, RevisionManager, RevisionObjectBuilder, RevisionPersistence,
-    RevisionWebSocket, RevisionWebSocketManager,
+    RevisionCloudService, RevisionCompactor, RevisionManager, RevisionObjectBuilder, RevisionWebSocket,
+    RevisionWebSocketManager,
 };
 use lib_infra::future::FutureResult;
-use lib_ot::core::{Delta, PlainTextAttributes};
-use lib_sqlite::ConnectionPool;
+use lib_ot::core::PlainTextAttributes;
+
 use parking_lot::RwLock;
 use std::sync::Arc;
 

+ 1 - 1
frontend/rust-lib/flowy-folder/src/services/persistence/migration.rs

@@ -88,7 +88,7 @@ impl FolderMigration {
             return Ok(None);
         }
         let pool = self.database.db_pool()?;
-        let disk_cache = Arc::new(SQLiteTextBlockRevisionPersistence::new(&user_id, pool));
+        let disk_cache = Arc::new(SQLiteTextBlockRevisionPersistence::new(user_id, pool));
         let rev_persistence = Arc::new(RevisionPersistence::new(user_id, folder_id.as_ref(), disk_cache));
         let (revisions, _) = RevisionLoader {
             object_id: folder_id.as_ref().to_owned(),

+ 2 - 2
frontend/rust-lib/flowy-folder/src/services/persistence/version_1/view_sql.rs

@@ -84,7 +84,7 @@ pub(crate) struct ViewTable {
 impl ViewTable {
     pub fn new(view: View) -> Self {
         let data_type = match view.data_type {
-            ViewDataType::Block => SqlViewDataType::Block,
+            ViewDataType::TextBlock => SqlViewDataType::Block,
             ViewDataType::Grid => SqlViewDataType::Grid,
         };
 
@@ -106,7 +106,7 @@ impl ViewTable {
 impl std::convert::From<ViewTable> for View {
     fn from(table: ViewTable) -> Self {
         let data_type = match table.view_type {
-            SqlViewDataType::Block => ViewDataType::Block,
+            SqlViewDataType::Block => ViewDataType::TextBlock,
             SqlViewDataType::Grid => ViewDataType::Grid,
         };
 

+ 11 - 15
frontend/rust-lib/flowy-folder/src/services/view/controller.rs

@@ -13,10 +13,7 @@ use crate::{
     },
 };
 use bytes::Bytes;
-use flowy_collaboration::entities::{
-    revision::{RepeatedRevision, Revision},
-    text_block_info::TextBlockId,
-};
+use flowy_collaboration::entities::text_block_info::TextBlockId;
 use flowy_database::kv::KV;
 use flowy_folder_data_model::entities::view::ViewDataType;
 use futures::{FutureExt, StreamExt};
@@ -58,18 +55,18 @@ impl ViewController {
     #[tracing::instrument(level = "trace", skip(self, params), fields(name = %params.name), err)]
     pub(crate) async fn create_view_from_params(&self, mut params: CreateViewParams) -> Result<View, FlowyError> {
         let processor = self.get_data_processor(&params.data_type)?;
-        let content = if params.data.is_empty() {
-            let default_view_data = processor.default_view_data(&params.view_id);
-            params.data = default_view_data.clone();
-            default_view_data
+
+        if params.data.is_empty() {
+            let user_id = self.user.user_id()?;
+            let view_data = processor.create_default_view(&user_id, &params.view_id).await?;
+            params.data = view_data;
         } else {
-            params.data.clone()
+            let delta_data = Bytes::from(params.data.clone());
+            let _ = self
+                .create_view(&params.view_id, params.data_type.clone(), delta_data)
+                .await?;
         };
 
-        let delta_data = Bytes::from(content);
-        let _ = self
-            .create_view(&params.view_id, params.data_type.clone(), delta_data)
-            .await?;
         let view = self.create_view_on_server(params).await?;
         let _ = self.create_view_on_local(view.clone()).await?;
         Ok(view)
@@ -86,9 +83,8 @@ impl ViewController {
             return Err(FlowyError::internal().context("The content of the view should not be empty"));
         }
         let user_id = self.user.user_id()?;
-        let repeated_revision: RepeatedRevision = Revision::initial_revision(&user_id, view_id, delta_data).into();
         let processor = self.get_data_processor(&data_type)?;
-        let _ = processor.create_container(view_id, repeated_revision).await?;
+        let _ = processor.create_container(&user_id, view_id, delta_data).await?;
         Ok(())
     }
 

+ 2 - 11
frontend/rust-lib/flowy-folder/tests/workspace/folder_test.rs

@@ -1,6 +1,7 @@
 use crate::script::{invalid_workspace_name_test_case, FolderScript::*, FolderTest};
-use flowy_collaboration::{client_document::default::initial_quill_delta_string, entities::revision::RevisionState};
+
 use flowy_folder::entities::workspace::CreateWorkspacePayload;
+use flowy_sync::disk::RevisionState;
 use flowy_test::{event_builder::*, FlowySDKTest};
 
 #[tokio::test]
@@ -168,16 +169,6 @@ async fn view_update() {
     assert_eq!(test.view.name, new_name);
 }
 
-#[tokio::test]
-async fn open_document_view() {
-    let mut test = FolderTest::new().await;
-    assert_eq!(test.document_info, None);
-
-    test.run_scripts(vec![OpenDocument]).await;
-    let document_info = test.document_info.unwrap();
-    assert_eq!(document_info.text, initial_quill_delta_string());
-}
-
 #[tokio::test]
 #[should_panic]
 async fn view_delete() {

+ 2 - 1
frontend/rust-lib/flowy-folder/tests/workspace/helper.rs

@@ -161,7 +161,8 @@ pub async fn delete_view(sdk: &FlowySDKTest, view_ids: Vec<String>) {
         .await;
 }
 
-pub async fn open_document(sdk: &FlowySDKTest, view_id: &str) -> TextBlockInfo {
+#[allow(dead_code)]
+pub async fn set_latest_view(sdk: &FlowySDKTest, view_id: &str) -> TextBlockInfo {
     let view_id: ViewId = view_id.into();
     FolderEventBuilder::new(sdk.clone())
         .event(SetLatestView)

+ 11 - 12
frontend/rust-lib/flowy-folder/tests/workspace/script.rs

@@ -1,5 +1,5 @@
 use crate::helper::*;
-use flowy_collaboration::entities::{revision::RevisionState, text_block_info::TextBlockInfo};
+
 use flowy_folder::{errors::ErrorCode, services::folder_editor::ClientFolderEditor};
 use flowy_folder_data_model::entities::{
     app::{App, RepeatedApp},
@@ -7,6 +7,7 @@ use flowy_folder_data_model::entities::{
     view::{RepeatedView, View, ViewDataType},
     workspace::Workspace,
 };
+use flowy_sync::disk::RevisionState;
 use flowy_sync::REVISION_WRITE_INTERVAL_IN_MILLIS;
 use flowy_test::FlowySDKTest;
 use std::{sync::Arc, time::Duration};
@@ -42,9 +43,6 @@ pub enum FolderScript {
     ReadTrash,
     DeleteAllTrash,
 
-    // Document
-    OpenDocument,
-
     // Sync
     AssertCurrentRevId(i64),
     AssertNextSyncRevId(Option<i64>),
@@ -58,7 +56,6 @@ pub struct FolderTest {
     pub app: App,
     pub view: View,
     pub trash: Vec<Trash>,
-    pub document_info: Option<TextBlockInfo>,
     // pub folder_editor:
 }
 
@@ -68,7 +65,14 @@ impl FolderTest {
         let _ = sdk.init_user().await;
         let mut workspace = create_workspace(&sdk, "FolderWorkspace", "Folder test workspace").await;
         let mut app = create_app(&sdk, &workspace.id, "Folder App", "Folder test app").await;
-        let view = create_view(&sdk, &app.id, "Folder View", "Folder test view", ViewDataType::Block).await;
+        let view = create_view(
+            &sdk,
+            &app.id,
+            "Folder View",
+            "Folder test view",
+            ViewDataType::TextBlock,
+        )
+        .await;
         app.belongings = RepeatedView {
             items: vec![view.clone()],
         };
@@ -83,7 +87,6 @@ impl FolderTest {
             app,
             view,
             trash: vec![],
-            document_info: None,
         }
     }
 
@@ -146,7 +149,7 @@ impl FolderTest {
             }
 
             FolderScript::CreateView { name, desc } => {
-                let view = create_view(sdk, &self.app.id, &name, &desc, ViewDataType::Block).await;
+                let view = create_view(sdk, &self.app.id, &name, &desc, ViewDataType::TextBlock).await;
                 self.view = view;
             }
             FolderScript::AssertView(view) => {
@@ -179,10 +182,6 @@ impl FolderTest {
                 delete_all_trash(sdk).await;
                 self.trash = vec![];
             }
-            FolderScript::OpenDocument => {
-                let document_info = open_document(sdk, &self.view.id).await;
-                self.document_info = Some(document_info);
-            }
             FolderScript::AssertRevisionState { rev_id, state } => {
                 let record = cache.get(rev_id).await.unwrap();
                 assert_eq!(record.state, state);

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

@@ -46,7 +46,7 @@ pub(crate) async fn create_row_handler(
 ) -> Result<(), FlowyError> {
     let id: GridId = data.into_inner();
     let editor = manager.get_grid_editor(id.as_ref())?;
-    let _ = editor.create_empty_row().await?;
+    let _ = editor.create_row().await?;
     Ok(())
 }
 
@@ -55,7 +55,7 @@ pub(crate) async fn update_cell_handler(
     data: Data<Cell>,
     manager: AppData<Arc<GridManager>>,
 ) -> Result<(), FlowyError> {
-    let cell: Cell = data.into_inner();
+    let _cell: Cell = data.into_inner();
     // let editor = manager.get_grid_editor(id.as_ref())?;
     // let _ = editor.create_empty_row().await?;
     Ok(())

+ 27 - 5
frontend/rust-lib/flowy-grid/src/manager.rs

@@ -1,13 +1,10 @@
 use crate::services::grid_editor::ClientGridEditor;
-use crate::services::kv_persistence::{GridKVPersistence, KVTransaction};
+use crate::services::kv_persistence::GridKVPersistence;
 use dashmap::DashMap;
-
 use flowy_collaboration::entities::revision::RepeatedRevision;
 use flowy_error::{FlowyError, FlowyResult};
-use flowy_grid_data_model::entities::{Field, RowMeta};
+use flowy_sync::disk::{SQLiteGridBlockMetaRevisionPersistence, SQLiteGridRevisionPersistence};
 use flowy_sync::{RevisionManager, RevisionPersistence, RevisionWebSocket};
-
-use flowy_sync::disk::SQLiteGridRevisionPersistence;
 use lib_sqlite::ConnectionPool;
 use parking_lot::RwLock;
 use std::sync::Arc;
@@ -47,6 +44,19 @@ impl GridManager {
         Ok(())
     }
 
+    #[tracing::instrument(level = "debug", skip_all, err)]
+    pub async fn create_grid_block_meta<T: AsRef<str>>(
+        &self,
+        block_id: T,
+        revisions: RepeatedRevision,
+    ) -> FlowyResult<()> {
+        let block_id = block_id.as_ref();
+        let db_pool = self.grid_user.db_pool()?;
+        let rev_manager = self.make_grid_block_meta_rev_manager(block_id, db_pool)?;
+        let _ = rev_manager.reset_object(revisions).await?;
+        Ok(())
+    }
+
     #[tracing::instrument(level = "debug", skip_all, fields(grid_id), err)]
     pub async fn open_grid<T: AsRef<str>>(&self, grid_id: T) -> FlowyResult<Arc<ClientGridEditor>> {
         let grid_id = grid_id.as_ref();
@@ -112,6 +122,18 @@ impl GridManager {
         Ok(rev_manager)
     }
 
+    fn make_grid_block_meta_rev_manager(
+        &self,
+        block_d: &str,
+        pool: Arc<ConnectionPool>,
+    ) -> FlowyResult<RevisionManager> {
+        let user_id = self.grid_user.user_id()?;
+        let disk_cache = Arc::new(SQLiteGridBlockMetaRevisionPersistence::new(&user_id, pool));
+        let rev_persistence = Arc::new(RevisionPersistence::new(&user_id, block_d, disk_cache));
+        let rev_manager = RevisionManager::new(&user_id, block_d, rev_persistence);
+        Ok(rev_manager)
+    }
+
     fn get_kv_persistence(&self) -> FlowyResult<Arc<GridKVPersistence>> {
         let read_guard = self.kv_persistence.read();
         if read_guard.is_some() {

+ 0 - 77
frontend/rust-lib/flowy-grid/src/services/grid_builder.rs

@@ -1,77 +0,0 @@
-use crate::manager::GridManager;
-use flowy_collaboration::client_grid::make_grid_delta;
-use flowy_error::{FlowyError, FlowyResult};
-use flowy_grid_data_model::entities::{CellMeta, Field, FieldType, Grid, GridMeta, RowMeta, RowOrder};
-use lib_infra::uuid;
-use std::sync::Arc;
-
-pub struct GridBuilder {
-    grid_manager: Arc<GridManager>,
-    grid_id: String,
-    fields: Vec<Field>,
-    rows: Vec<RowMeta>,
-}
-
-impl GridBuilder {
-    pub fn new(grid_id: &str, grid_manager: Arc<GridManager>) -> Self {
-        Self {
-            grid_manager,
-            grid_id: grid_id.to_owned(),
-            fields: vec![],
-            rows: vec![],
-        }
-    }
-
-    pub fn add_field(mut self, name: &str, desc: &str, field_type: FieldType) -> Self {
-        let field = Field::new(&uuid(), name, desc, field_type);
-        self.fields.push(field);
-        self
-    }
-
-    pub fn add_empty_row(mut self) -> Self {
-        let row = RowMeta::new(&uuid(), &self.grid_id, vec![]);
-        self.rows.push(row);
-        self
-    }
-
-    pub fn add_row(mut self, cells: Vec<CellMeta>) -> Self {
-        let row = RowMeta::new(&uuid(), &self.grid_id, cells);
-        self.rows.push(row);
-        self
-    }
-
-    pub fn build(self) -> FlowyResult<String> {
-        let grid_meta = GridMeta {
-            grid_id: self.grid_id,
-            fields: self.fields,
-            blocks: vec![],
-        };
-
-        // let _ = check_rows(&self.fields, &self.rows)?;
-        let delta = make_grid_delta(&grid_meta);
-        Ok(delta.to_delta_str())
-    }
-}
-
-#[allow(dead_code)]
-fn check_rows(fields: &[Field], rows: &[RowMeta]) -> FlowyResult<()> {
-    let field_ids = fields.iter().map(|field| &field.id).collect::<Vec<&String>>();
-    for row in rows {
-        let cell_field_ids = row.cell_by_field_id.keys().into_iter().collect::<Vec<&String>>();
-        if cell_field_ids != field_ids {
-            let msg = format!("{:?} contains invalid cells", row);
-            return Err(FlowyError::internal().context(msg));
-        }
-    }
-    Ok(())
-}
-
-pub fn make_default_grid(grid_id: &str, grid_manager: Arc<GridManager>) -> String {
-    GridBuilder::new(grid_id, grid_manager)
-        .add_field("Name", "", FieldType::RichText)
-        .add_field("Tags", "", FieldType::SingleSelect)
-        .add_empty_row()
-        .add_empty_row()
-        .build()
-        .unwrap()
-}

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

@@ -1,6 +1,5 @@
 use crate::manager::GridUser;
 use crate::services::kv_persistence::{GridKVPersistence, KVTransaction};
-use crate::services::stringify::stringify_deserialize;
 
 use crate::services::grid_meta_editor::ClientGridBlockMetaEditor;
 use bytes::Bytes;
@@ -10,14 +9,14 @@ use flowy_collaboration::entities::revision::Revision;
 use flowy_collaboration::util::make_delta_from_revisions;
 use flowy_error::{FlowyError, FlowyResult};
 use flowy_grid_data_model::entities::{
-    Cell, CellMeta, Field, Grid, RepeatedField, RepeatedFieldOrder, RepeatedRow, RepeatedRowOrder, Row, RowMeta,
+    Field, Grid, GridBlock, RepeatedField, RepeatedFieldOrder, RepeatedRow, RepeatedRowOrder,
+};
+use flowy_sync::disk::SQLiteGridBlockMetaRevisionPersistence;
+use flowy_sync::{
+    RevisionCloudService, RevisionCompactor, RevisionManager, RevisionObjectBuilder, RevisionPersistence,
 };
-use flowy_sync::{RevisionCloudService, RevisionCompactor, RevisionManager, RevisionObjectBuilder};
 use lib_infra::future::FutureResult;
-use lib_infra::uuid;
-use lib_ot::core::{Delta, PlainTextAttributes};
-use rayon::iter::{IntoParallelIterator, ParallelIterator};
-use std::collections::HashMap;
+use lib_ot::core::PlainTextAttributes;
 use std::sync::Arc;
 use tokio::sync::RwLock;
 
@@ -40,10 +39,11 @@ impl ClientGridEditor {
         let token = user.token()?;
         let cloud = Arc::new(GridRevisionCloudService { token });
         let grid_pad = rev_manager.load::<GridPadBuilder>(cloud).await?;
-
         let rev_manager = Arc::new(rev_manager);
         let grid_meta_pad = Arc::new(RwLock::new(grid_pad));
-        let block_meta_manager = Arc::new(GridBlockMetaEditorManager::new());
+
+        let block_meta_manager =
+            Arc::new(GridBlockMetaEditorManager::new(&user, grid_meta_pad.read().await.get_blocks()).await?);
 
         Ok(Arc::new(Self {
             grid_id: grid_id.to_owned(),
@@ -65,25 +65,15 @@ impl ClientGridEditor {
         Ok(())
     }
 
-    pub async fn create_empty_row(&self) -> FlowyResult<()> {
-        // let _ = self.modify(|grid| {
-        //
-        //
-        //     grid.blocks
-        //
-        // }).await?;
-        todo!()
-    }
-
-    async fn create_row(&self, row: RowMeta) -> FlowyResult<()> {
+    pub async fn create_row(&self) -> FlowyResult<()> {
         todo!()
     }
 
-    pub async fn get_rows(&self, row_orders: RepeatedRowOrder) -> FlowyResult<RepeatedRow> {
+    pub async fn get_rows(&self, _row_orders: RepeatedRowOrder) -> FlowyResult<RepeatedRow> {
         todo!()
     }
 
-    pub async fn delete_rows(&self, ids: Vec<String>) -> FlowyResult<()> {
+    pub async fn delete_rows(&self, _ids: Vec<String>) -> FlowyResult<()> {
         todo!()
     }
 
@@ -188,13 +178,17 @@ struct GridBlockMetaEditorManager {
 }
 
 impl GridBlockMetaEditorManager {
-    fn new() -> Self {
-        Self {
-            editor_map: DashMap::new(),
-        }
+    async fn new(user: &Arc<dyn GridUser>, blocks: Vec<GridBlock>) -> FlowyResult<Self> {
+        let editor_map = make_block_meta_editor_map(user, blocks).await?;
+        let manager = Self { editor_map };
+        Ok(manager)
     }
 
-    pub async fn get_rows(&self, row_orders: RepeatedRowOrder) -> FlowyResult<RepeatedRow> {
+    async fn get_editor(&self, _block_id: &str) -> Arc<ClientGridBlockMetaEditor> {
+        todo!()
+    }
+
+    pub async fn get_rows(&self, _row_orders: RepeatedRowOrder) -> FlowyResult<RepeatedRow> {
         // let ids = row_orders
         //     .items
         //     .into_iter()
@@ -245,3 +239,23 @@ impl GridBlockMetaEditorManager {
         todo!()
     }
 }
+
+async fn make_block_meta_editor_map(
+    user: &Arc<dyn GridUser>,
+    blocks: Vec<GridBlock>,
+) -> FlowyResult<DashMap<String, Arc<ClientGridBlockMetaEditor>>> {
+    let token = user.token()?;
+    let user_id = user.user_id()?;
+    let pool = user.db_pool()?;
+
+    let editor_map = DashMap::new();
+    for block in blocks {
+        let disk_cache = Arc::new(SQLiteGridBlockMetaRevisionPersistence::new(&user_id, pool.clone()));
+        let rev_persistence = Arc::new(RevisionPersistence::new(&user_id, &block.id, disk_cache));
+        let rev_manager = RevisionManager::new(&user_id, &block.id, rev_persistence);
+        let editor = ClientGridBlockMetaEditor::new(&user_id, &token, &block.id, rev_manager).await?;
+        editor_map.insert(block.id, Arc::new(editor));
+    }
+
+    Ok(editor_map)
+}

+ 16 - 14
frontend/rust-lib/flowy-grid/src/services/grid_meta_editor.rs

@@ -3,17 +3,16 @@ use flowy_collaboration::client_grid::{GridBlockMetaChange, GridBlockMetaPad};
 use flowy_collaboration::entities::revision::Revision;
 use flowy_collaboration::util::make_delta_from_revisions;
 use flowy_error::{FlowyError, FlowyResult};
-use flowy_grid_data_model::entities::RowMeta;
+use flowy_grid_data_model::entities::{RowMeta, RowMetaChangeset};
 use flowy_sync::{RevisionCloudService, RevisionCompactor, RevisionManager, RevisionObjectBuilder};
 use lib_infra::future::FutureResult;
-use lib_infra::uuid;
 use lib_ot::core::PlainTextAttributes;
 use std::sync::Arc;
 use tokio::sync::RwLock;
 
 pub struct ClientGridBlockMetaEditor {
     user_id: String,
-    block_id: String,
+    pub block_id: String,
     meta_pad: Arc<RwLock<GridBlockMetaPad>>,
     rev_manager: Arc<RevisionManager>,
 }
@@ -22,7 +21,7 @@ impl ClientGridBlockMetaEditor {
     pub async fn new(
         user_id: &str,
         token: &str,
-        block_id: String,
+        block_id: &str,
         mut rev_manager: RevisionManager,
     ) -> FlowyResult<Self> {
         let cloud = Arc::new(GridBlockMetaRevisionCloudService {
@@ -32,6 +31,7 @@ impl ClientGridBlockMetaEditor {
         let meta_pad = Arc::new(RwLock::new(block_meta_pad));
         let rev_manager = Arc::new(rev_manager);
         let user_id = user_id.to_owned();
+        let block_id = block_id.to_owned();
         Ok(Self {
             user_id,
             block_id,
@@ -40,25 +40,27 @@ impl ClientGridBlockMetaEditor {
         })
     }
 
-    pub async fn create_empty_row(&self) -> FlowyResult<()> {
-        let row = RowMeta::new(&uuid(), &self.block_id, vec![]);
-        self.create_row(row).await?;
+    async fn create_row(&self) -> FlowyResult<()> {
+        let row = RowMeta::new(&self.block_id, vec![]);
+        let _ = self.modify(|pad| Ok(pad.add_row(row)?)).await?;
         Ok(())
     }
 
-    async fn create_row(&self, row: RowMeta) -> FlowyResult<()> {
-        // let _ = self.modify(|grid| Ok(grid.create_row(row)?)).await?;
-        // self.cell_map.insert(row.id.clone(), row.clone());
-        // let _ = self.kv_persistence.set(row)?;
+    pub async fn delete_rows(&self, ids: Vec<String>) -> FlowyResult<()> {
+        let _ = self.modify(|pad| Ok(pad.delete_rows(&ids)?)).await?;
         Ok(())
     }
 
-    pub async fn delete_rows(&self, ids: Vec<String>) -> FlowyResult<()> {
-        // let _ = self.modify(|grid| Ok(grid.delete_rows(&ids)?)).await?;
-        // let _ = self.kv.batch_delete(ids)?;
+    pub async fn update_row(&self, changeset: RowMetaChangeset) -> FlowyResult<()> {
+        let _ = self.modify(|pad| Ok(pad.update_row(changeset)?)).await?;
         Ok(())
     }
 
+    pub async fn get_rows(&self, row_ids: Vec<String>) -> FlowyResult<Vec<RowMeta>> {
+        let rows = self.meta_pad.read().await.get_rows(row_ids)?;
+        Ok(rows)
+    }
+
     async fn modify<F>(&self, f: F) -> FlowyResult<()>
     where
         F: for<'a> FnOnce(&'a mut GridBlockMetaPad) -> FlowyResult<Option<GridBlockMetaChange>>,

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

@@ -1,7 +1,6 @@
 mod util;
 
 pub mod cell_data;
-pub mod grid_builder;
 pub mod grid_editor;
 pub mod grid_meta_editor;
 pub mod kv_persistence;

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


+ 14 - 11
frontend/rust-lib/flowy-net/src/local_server/persistence.rs

@@ -29,25 +29,25 @@ pub trait RevisionCloudStorage: Send + Sync {
     ) -> BoxResultFuture<(), CollaborateError>;
 }
 
-pub(crate) struct LocalDocumentCloudPersistence {
+pub(crate) struct LocalTextBlockCloudPersistence {
     storage: Arc<dyn RevisionCloudStorage>,
 }
 
-impl Debug for LocalDocumentCloudPersistence {
+impl Debug for LocalTextBlockCloudPersistence {
     fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
         f.write_str("LocalRevisionCloudPersistence")
     }
 }
 
-impl std::default::Default for LocalDocumentCloudPersistence {
+impl std::default::Default for LocalTextBlockCloudPersistence {
     fn default() -> Self {
-        LocalDocumentCloudPersistence {
+        LocalTextBlockCloudPersistence {
             storage: Arc::new(MemoryDocumentCloudStorage::default()),
         }
     }
 }
 
-impl FolderCloudPersistence for LocalDocumentCloudPersistence {
+impl FolderCloudPersistence for LocalTextBlockCloudPersistence {
     fn read_folder(&self, _user_id: &str, folder_id: &str) -> BoxResultFuture<FolderInfo, CollaborateError> {
         let storage = self.storage.clone();
         let folder_id = folder_id.to_owned();
@@ -110,8 +110,8 @@ impl FolderCloudPersistence for LocalDocumentCloudPersistence {
     }
 }
 
-impl DocumentCloudPersistence for LocalDocumentCloudPersistence {
-    fn read_document(&self, doc_id: &str) -> BoxResultFuture<TextBlockInfo, CollaborateError> {
+impl TextBlockCloudPersistence for LocalTextBlockCloudPersistence {
+    fn read_text_block(&self, doc_id: &str) -> BoxResultFuture<TextBlockInfo, CollaborateError> {
         let storage = self.storage.clone();
         let doc_id = doc_id.to_owned();
         Box::pin(async move {
@@ -123,7 +123,7 @@ impl DocumentCloudPersistence for LocalDocumentCloudPersistence {
         })
     }
 
-    fn create_document(
+    fn create_text_block(
         &self,
         doc_id: &str,
         repeated_revision: RepeatedRevisionPB,
@@ -136,7 +136,7 @@ impl DocumentCloudPersistence for LocalDocumentCloudPersistence {
         })
     }
 
-    fn read_document_revisions(
+    fn read_text_block_revisions(
         &self,
         doc_id: &str,
         rev_ids: Option<Vec<i64>>,
@@ -150,7 +150,10 @@ impl DocumentCloudPersistence for LocalDocumentCloudPersistence {
         })
     }
 
-    fn save_document_revisions(&self, repeated_revision: RepeatedRevisionPB) -> BoxResultFuture<(), CollaborateError> {
+    fn save_text_block_revisions(
+        &self,
+        repeated_revision: RepeatedRevisionPB,
+    ) -> BoxResultFuture<(), CollaborateError> {
         let storage = self.storage.clone();
         Box::pin(async move {
             let _ = storage.set_revisions(repeated_revision).await?;
@@ -158,7 +161,7 @@ impl DocumentCloudPersistence for LocalDocumentCloudPersistence {
         })
     }
 
-    fn reset_document(&self, doc_id: &str, revisions: RepeatedRevisionPB) -> BoxResultFuture<(), CollaborateError> {
+    fn reset_text_block(&self, doc_id: &str, revisions: RepeatedRevisionPB) -> BoxResultFuture<(), CollaborateError> {
         let storage = self.storage.clone();
         let doc_id = doc_id.to_owned();
         Box::pin(async move {

+ 2 - 2
frontend/rust-lib/flowy-net/src/local_server/server.rs

@@ -1,4 +1,4 @@
-use crate::local_server::persistence::LocalDocumentCloudPersistence;
+use crate::local_server::persistence::LocalTextBlockCloudPersistence;
 use async_stream::stream;
 use bytes::Bytes;
 use flowy_collaboration::{
@@ -38,7 +38,7 @@ impl LocalServer {
         client_ws_sender: mpsc::UnboundedSender<WebSocketRawMessage>,
         client_ws_receiver: broadcast::Sender<WebSocketRawMessage>,
     ) -> Self {
-        let persistence = Arc::new(LocalDocumentCloudPersistence::default());
+        let persistence = Arc::new(LocalTextBlockCloudPersistence::default());
         let doc_manager = Arc::new(ServerDocumentManager::new(persistence.clone()));
         let folder_manager = Arc::new(ServerFolderManager::new(persistence));
         let stop_tx = RwLock::new(None);

+ 41 - 11
frontend/rust-lib/flowy-sdk/src/deps_resolve/folder_deps.rs

@@ -1,7 +1,8 @@
 use bytes::Bytes;
 use flowy_block::TextBlockManager;
 use flowy_collaboration::client_document::default::initial_quill_delta_string;
-use flowy_collaboration::entities::revision::RepeatedRevision;
+use flowy_collaboration::client_grid::make_default_grid;
+use flowy_collaboration::entities::revision::{RepeatedRevision, Revision};
 use flowy_collaboration::entities::ws_data::ClientRevisionWSData;
 use flowy_database::ConnectionPool;
 use flowy_folder::manager::{ViewDataProcessor, ViewDataProcessorMap};
@@ -12,7 +13,6 @@ use flowy_folder::{
     manager::FolderManager,
 };
 use flowy_grid::manager::GridManager;
-use flowy_grid::services::grid_builder::make_default_grid;
 use flowy_net::ClientServerConfiguration;
 use flowy_net::{
     http_server::folder::FolderHttpCloudService, local_server::LocalServer, ws::connection::FlowyWebSocketConnect,
@@ -140,9 +140,10 @@ impl ViewDataProcessor for TextBlockViewDataProcessor {
         FutureResult::new(async move { manager.init() })
     }
 
-    fn create_container(&self, view_id: &str, repeated_revision: RepeatedRevision) -> FutureResult<(), FlowyError> {
-        let manager = self.0.clone();
+    fn create_container(&self, user_id: &str, view_id: &str, delta_data: Bytes) -> FutureResult<(), FlowyError> {
+        let repeated_revision: RepeatedRevision = Revision::initial_revision(user_id, view_id, delta_data).into();
         let view_id = view_id.to_string();
+        let manager = self.0.clone();
         FutureResult::new(async move {
             let _ = manager.create_block(view_id, repeated_revision).await?;
             Ok(())
@@ -177,12 +178,21 @@ impl ViewDataProcessor for TextBlockViewDataProcessor {
         })
     }
 
-    fn default_view_data(&self, _view_id: &str) -> String {
-        initial_quill_delta_string()
+    fn create_default_view(&self, user_id: &str, view_id: &str) -> FutureResult<String, FlowyError> {
+        let user_id = user_id.to_string();
+        let view_id = view_id.to_string();
+        let manager = self.0.clone();
+        FutureResult::new(async move {
+            let view_data = initial_quill_delta_string();
+            let delta_data = Bytes::from(view_data.clone());
+            let repeated_revision: RepeatedRevision = Revision::initial_revision(&user_id, &view_id, delta_data).into();
+            let _ = manager.create_block(view_id, repeated_revision).await?;
+            Ok(view_data)
+        })
     }
 
     fn data_type(&self) -> ViewDataType {
-        ViewDataType::Block
+        ViewDataType::TextBlock
     }
 }
 
@@ -192,9 +202,10 @@ impl ViewDataProcessor for GridViewDataProcessor {
         FutureResult::new(async { Ok(()) })
     }
 
-    fn create_container(&self, view_id: &str, repeated_revision: RepeatedRevision) -> FutureResult<(), FlowyError> {
-        let grid_manager = self.0.clone();
+    fn create_container(&self, user_id: &str, view_id: &str, delta_data: Bytes) -> FutureResult<(), FlowyError> {
+        let repeated_revision: RepeatedRevision = Revision::initial_revision(user_id, view_id, delta_data).into();
         let view_id = view_id.to_string();
+        let grid_manager = self.0.clone();
         FutureResult::new(async move {
             let _ = grid_manager.create_grid(view_id, repeated_revision).await?;
             Ok(())
@@ -229,8 +240,27 @@ impl ViewDataProcessor for GridViewDataProcessor {
         })
     }
 
-    fn default_view_data(&self, view_id: &str) -> String {
-        make_default_grid(view_id, self.0.clone())
+    fn create_default_view(&self, user_id: &str, view_id: &str) -> FutureResult<String, FlowyError> {
+        let info = make_default_grid(view_id);
+        let user_id = user_id.to_string();
+        let view_id = view_id.to_string();
+        let grid_manager = self.0.clone();
+
+        FutureResult::new(async move {
+            let grid_delta_data = Bytes::from(info.grid_delta.to_delta_str());
+            let repeated_revision: RepeatedRevision =
+                Revision::initial_revision(&user_id, &view_id, grid_delta_data).into();
+            let _ = grid_manager.create_grid(&view_id, repeated_revision).await?;
+
+            let block_meta_delta_data = Bytes::from(info.grid_block_meta_delta.to_delta_str());
+            let repeated_revision: RepeatedRevision =
+                Revision::initial_revision(&user_id, &info.block_id, block_meta_delta_data).into();
+            let _ = grid_manager
+                .create_grid_block_meta(&info.block_id, repeated_revision)
+                .await?;
+
+            Ok(info.grid_delta.to_delta_str())
+        })
     }
 
     fn data_type(&self) -> ViewDataType {

+ 2 - 2
frontend/rust-lib/flowy-sync/src/cache/disk/grid_meta_rev_impl.rs

@@ -1,10 +1,10 @@
 use crate::cache::disk::RevisionDiskCache;
 use crate::disk::{RevisionChangeset, RevisionRecord, RevisionState};
-use crate::memory::RevisionMemoryCacheDelegate;
+
 use bytes::Bytes;
 use diesel::{sql_types::Integer, update, SqliteConnection};
 use flowy_collaboration::{
-    entities::revision::{RevId, RevType, Revision, RevisionRange},
+    entities::revision::{Revision, RevisionRange},
     util::md5,
 };
 use flowy_database::{

+ 2 - 2
frontend/rust-lib/flowy-sync/src/cache/disk/grid_rev_impl.rs

@@ -1,10 +1,10 @@
 use crate::cache::disk::RevisionDiskCache;
 use crate::disk::{RevisionChangeset, RevisionRecord, RevisionState};
-use crate::memory::RevisionMemoryCacheDelegate;
+
 use bytes::Bytes;
 use diesel::{sql_types::Integer, update, SqliteConnection};
 use flowy_collaboration::{
-    entities::revision::{RevId, RevType, Revision, RevisionRange},
+    entities::revision::{Revision, RevisionRange},
     util::md5,
 };
 use flowy_database::{

+ 0 - 2
frontend/rust-lib/flowy-sync/src/cache/disk/mod.rs

@@ -8,8 +8,6 @@ pub use grid_meta_rev_impl::*;
 pub use grid_rev_impl::*;
 pub use text_rev_impl::*;
 
-use crate::memory::RevisionMemoryCacheDelegate;
-use diesel::SqliteConnection;
 use flowy_collaboration::entities::revision::{RevId, Revision, RevisionRange};
 use flowy_error::FlowyResult;
 use std::fmt::Debug;

+ 2 - 2
frontend/rust-lib/flowy-sync/src/cache/disk/text_rev_impl.rs

@@ -1,10 +1,10 @@
 use crate::cache::disk::RevisionDiskCache;
 use crate::disk::{RevisionChangeset, RevisionRecord, RevisionState};
-use crate::memory::RevisionMemoryCacheDelegate;
+
 use bytes::Bytes;
 use diesel::{sql_types::Integer, update, SqliteConnection};
 use flowy_collaboration::{
-    entities::revision::{RevId, RevType, Revision, RevisionRange},
+    entities::revision::{RevType, Revision, RevisionRange},
     util::md5,
 };
 use flowy_database::{

+ 0 - 1
frontend/rust-lib/flowy-sync/src/rev_manager.rs

@@ -7,7 +7,6 @@ use flowy_collaboration::{
 };
 use flowy_error::{FlowyError, FlowyResult};
 use lib_infra::future::FutureResult;
-use lib_ot::core::{Attributes, Delta};
 use std::sync::Arc;
 
 pub trait RevisionCloudService: Send + Sync {

+ 1 - 1
frontend/rust-lib/flowy-test/src/helper.rs

@@ -88,7 +88,7 @@ async fn create_view(sdk: &FlowySDKTest, app_id: &str) -> View {
         name: "View A".to_string(),
         desc: "".to_string(),
         thumbnail: Some("http://1.png".to_string()),
-        data_type: ViewDataType::Block,
+        data_type: ViewDataType::TextBlock,
         ext_data: "".to_string(),
         plugin_type: 0,
     };

+ 25 - 12
shared-lib/flowy-collaboration/src/client_grid/block_pad.rs

@@ -1,10 +1,11 @@
 use crate::entities::revision::{md5, RepeatedRevision, Revision};
 use crate::errors::{internal_error, CollaborateError, CollaborateResult};
 use crate::util::{cal_diff, make_delta_from_revisions};
-use flowy_grid_data_model::entities::{GridBlockMeta, RowMeta, RowMetaChangeset, RowOrder};
+use flowy_grid_data_model::entities::{GridBlockMeta, RowMeta, RowMetaChangeset};
 use lib_infra::uuid;
 use lib_ot::core::{OperationTransformable, PlainTextAttributes, PlainTextDelta, PlainTextDeltaBuilder};
 use serde::{Deserialize, Serialize};
+use std::collections::HashMap;
 use std::sync::Arc;
 
 pub type GridBlockMetaDelta = PlainTextDelta;
@@ -49,6 +50,25 @@ impl GridBlockMetaPad {
         })
     }
 
+    pub fn get_rows(&self, row_ids: Vec<String>) -> CollaborateResult<Vec<RowMeta>> {
+        let row_map = self
+            .rows
+            .iter()
+            .map(|row| (&row.id, row.clone()))
+            .collect::<HashMap<&String, Arc<RowMeta>>>();
+
+        Ok(row_ids
+            .iter()
+            .flat_map(|row_id| match row_map.get(row_id) {
+                None => {
+                    tracing::error!("Can't find the row with id: {}", row_id);
+                    None
+                }
+                Some(row) => Some((**row).clone()),
+            })
+            .collect::<Vec<RowMeta>>())
+    }
+
     pub fn update_row(&mut self, changeset: RowMetaChangeset) -> CollaborateResult<Option<GridBlockMetaChange>> {
         let row_id = changeset.row_id.clone();
         self.modify_row(&row_id, |row| {
@@ -123,12 +143,6 @@ impl GridBlockMetaPad {
     }
 }
 
-fn json_from_grid(block_meta: &Arc<GridBlockMeta>) -> CollaborateResult<String> {
-    let json = serde_json::to_string(block_meta)
-        .map_err(|err| internal_error(format!("Serialize grid to json str failed. {:?}", err)))?;
-    Ok(json)
-}
-
 pub struct GridBlockMetaChange {
     pub delta: GridBlockMetaDelta,
     /// md5: the md5 of the grid after applying the change.
@@ -165,9 +179,8 @@ impl std::default::Default for GridBlockMetaPad {
 
 #[cfg(test)]
 mod tests {
-    use crate::client_grid::{GridBlockMetaDelta, GridMetaPad};
+    use crate::client_grid::{GridBlockMetaDelta, GridBlockMetaPad};
     use flowy_grid_data_model::entities::{RowMeta, RowMetaChangeset};
-    use std::str::FromStr;
 
     #[test]
     fn block_meta_add_row() {
@@ -227,7 +240,7 @@ mod tests {
             cell_by_field_id: Default::default(),
         };
 
-        let _ = pad.add_row(row.clone()).unwrap().unwrap();
+        let _ = pad.add_row(row).unwrap().unwrap();
         let change = pad.update_row(changeset).unwrap().unwrap();
 
         assert_eq!(
@@ -241,8 +254,8 @@ mod tests {
         );
     }
 
-    fn test_pad() -> GridMetaPad {
+    fn test_pad() -> GridBlockMetaPad {
         let delta = GridBlockMetaDelta::from_delta_str(r#"[{"insert":"{\"block_id\":\"1\",\"rows\":[]}"}]"#).unwrap();
-        GridMetaPad::from_delta(delta).unwrap()
+        GridBlockMetaPad::from_delta(delta).unwrap()
     }
 }

+ 114 - 0
shared-lib/flowy-collaboration/src/client_grid/grid_builder.rs

@@ -0,0 +1,114 @@
+use crate::client_grid::{make_block_meta_delta, make_grid_delta, GridBlockMetaDelta, GridMetaDelta};
+use crate::errors::{CollaborateError, CollaborateResult};
+use flowy_grid_data_model::entities::{Field, FieldType, GridBlock, GridBlockMeta, GridMeta, RowMeta};
+
+pub struct GridBuilder {
+    grid_id: String,
+    fields: Vec<Field>,
+    grid_block: GridBlock,
+    grid_block_meta: GridBlockMeta,
+}
+
+impl GridBuilder {
+    pub fn new(grid_id: &str) -> Self {
+        let grid_block = GridBlock::new();
+        let grid_block_meta = GridBlockMeta {
+            block_id: grid_block.id.clone(),
+            rows: vec![],
+        };
+
+        Self {
+            grid_id: grid_id.to_owned(),
+            fields: vec![],
+            grid_block,
+            grid_block_meta,
+        }
+    }
+
+    pub fn add_field(mut self, name: &str, desc: &str, field_type: FieldType) -> Self {
+        let field = Field::new(name, desc, field_type);
+        self.fields.push(field);
+        self
+    }
+
+    pub fn add_empty_row(mut self) -> Self {
+        let row = RowMeta::new(&self.grid_block.id, vec![]);
+        self.grid_block_meta.rows.push(row);
+        self
+    }
+
+    pub fn build(self) -> CollaborateResult<BuildGridInfo> {
+        let block_id = self.grid_block.id.clone();
+        let grid_meta = GridMeta {
+            grid_id: self.grid_id,
+            fields: self.fields,
+            blocks: vec![self.grid_block],
+        };
+        // let _ = check_rows(&self.fields, &self.rows)?;
+        let grid_delta = make_grid_delta(&grid_meta);
+        let grid_block_meta_delta = make_block_meta_delta(&self.grid_block_meta);
+        Ok(BuildGridInfo {
+            grid_delta,
+            block_id,
+            grid_block_meta_delta,
+        })
+    }
+}
+
+pub struct BuildGridInfo {
+    pub grid_delta: GridMetaDelta,
+    pub block_id: String,
+    pub grid_block_meta_delta: GridBlockMetaDelta,
+}
+
+#[allow(dead_code)]
+fn check_rows(fields: &[Field], rows: &[RowMeta]) -> CollaborateResult<()> {
+    let field_ids = fields.iter().map(|field| &field.id).collect::<Vec<&String>>();
+    for row in rows {
+        let cell_field_ids = row.cell_by_field_id.keys().into_iter().collect::<Vec<&String>>();
+        if cell_field_ids != field_ids {
+            let msg = format!("{:?} contains invalid cells", row);
+            return Err(CollaborateError::internal().context(msg));
+        }
+    }
+    Ok(())
+}
+
+pub fn make_default_grid(grid_id: &str) -> BuildGridInfo {
+    GridBuilder::new(grid_id)
+        .add_field("Name", "", FieldType::RichText)
+        .add_field("Tags", "", FieldType::SingleSelect)
+        .add_empty_row()
+        .add_empty_row()
+        .add_empty_row()
+        .build()
+        .unwrap()
+}
+
+#[cfg(test)]
+mod tests {
+    use crate::client_grid::GridBuilder;
+    use flowy_grid_data_model::entities::{FieldType, GridBlockMeta, GridMeta};
+
+    #[test]
+    fn create_default_grid_test() {
+        let info = GridBuilder::new("1")
+            .add_field("Name", "", FieldType::RichText)
+            .add_field("Tags", "", FieldType::SingleSelect)
+            .add_empty_row()
+            .add_empty_row()
+            .add_empty_row()
+            .build()
+            .unwrap();
+
+        let grid_meta: GridMeta = serde_json::from_str(&info.grid_delta.to_str().unwrap()).unwrap();
+        assert_eq!(grid_meta.fields.len(), 2);
+        assert_eq!(grid_meta.blocks.len(), 1);
+
+        let grid_block_meta: GridBlockMeta =
+            serde_json::from_str(&info.grid_block_meta_delta.to_str().unwrap()).unwrap();
+        assert_eq!(grid_block_meta.rows.len(), 3);
+
+        assert_eq!(grid_meta.blocks[0].id, grid_block_meta.block_id);
+    }
+}

+ 12 - 9
shared-lib/flowy-collaboration/src/client_grid/grid_pad.rs

@@ -2,24 +2,23 @@ use crate::entities::revision::{md5, RepeatedRevision, Revision};
 use crate::errors::{internal_error, CollaborateError, CollaborateResult};
 use crate::util::{cal_diff, make_delta_from_revisions};
 use flowy_grid_data_model::entities::{
-    Field, FieldChangeset, FieldOrder, Grid, GridBlock, GridBlockChangeset, GridMeta, RepeatedField,
-    RepeatedFieldOrder, RowMeta, RowOrder,
+    Field, FieldChangeset, GridBlock, GridBlockChangeset, GridMeta, RepeatedField, RepeatedFieldOrder,
 };
 use lib_infra::uuid;
 use lib_ot::core::{OperationTransformable, PlainTextAttributes, PlainTextDelta, PlainTextDeltaBuilder};
 use std::collections::HashMap;
 use std::sync::Arc;
 
-pub type GridDelta = PlainTextDelta;
+pub type GridMetaDelta = PlainTextDelta;
 pub type GridDeltaBuilder = PlainTextDeltaBuilder;
 
 pub struct GridMetaPad {
     pub(crate) grid_meta: Arc<GridMeta>,
-    pub(crate) delta: GridDelta,
+    pub(crate) delta: GridMetaDelta,
 }
 
 impl GridMetaPad {
-    pub fn from_delta(delta: GridDelta) -> CollaborateResult<Self> {
+    pub fn from_delta(delta: GridMetaDelta) -> CollaborateResult<Self> {
         let s = delta.to_str()?;
         let grid: GridMeta = serde_json::from_str(&s)
             .map_err(|e| CollaborateError::internal().context(format!("Deserialize delta to grid failed: {}", e)))?;
@@ -31,7 +30,7 @@ impl GridMetaPad {
     }
 
     pub fn from_revisions(_grid_id: &str, revisions: Vec<Revision>) -> CollaborateResult<Self> {
-        let grid_delta: GridDelta = make_delta_from_revisions::<PlainTextAttributes>(revisions)?;
+        let grid_delta: GridMetaDelta = make_delta_from_revisions::<PlainTextAttributes>(revisions)?;
         Self::from_delta(grid_delta)
     }
 
@@ -64,7 +63,7 @@ impl GridMetaPad {
             .iter()
             .flat_map(|field_order| match field_by_field_id.get(&field_order.field_id) {
                 None => {
-                    tracing::error!("Can't find the field with {}", field_order.field_id);
+                    tracing::error!("Can't find the field with id: {}", field_order.field_id);
                     None
                 }
                 Some(field) => Some((*field).clone()),
@@ -123,6 +122,10 @@ impl GridMetaPad {
         })
     }
 
+    pub fn get_blocks(&self) -> Vec<GridBlock> {
+        self.grid_meta.blocks.clone()
+    }
+
     pub fn update_block(&mut self, change: GridBlockChangeset) -> CollaborateResult<Option<GridChange>> {
         let block_id = change.block_id.clone();
         self.modify_block(&block_id, |block| {
@@ -204,12 +207,12 @@ fn json_from_grid(grid: &Arc<GridMeta>) -> CollaborateResult<String> {
 }
 
 pub struct GridChange {
-    pub delta: GridDelta,
+    pub delta: GridMetaDelta,
     /// md5: the md5 of the grid after applying the change.
     pub md5: String,
 }
 
-pub fn make_grid_delta(grid_meta: &GridMeta) -> GridDelta {
+pub fn make_grid_delta(grid_meta: &GridMeta) -> GridMetaDelta {
     let json = serde_json::to_string(&grid_meta).unwrap();
     PlainTextDeltaBuilder::new().insert(&json).build()
 }

+ 2 - 0
shared-lib/flowy-collaboration/src/client_grid/mod.rs

@@ -1,5 +1,7 @@
 mod block_pad;
+mod grid_builder;
 mod grid_pad;
 
 pub use block_pad::*;
+pub use grid_builder::*;
 pub use grid_pad::*;

+ 16 - 15
shared-lib/flowy-collaboration/src/server_document/document_manager.rs

@@ -17,41 +17,42 @@ use tokio::{
     task::spawn_blocking,
 };
 
-pub trait DocumentCloudPersistence: Send + Sync + Debug {
-    fn read_document(&self, doc_id: &str) -> BoxResultFuture<TextBlockInfo, CollaborateError>;
+pub trait TextBlockCloudPersistence: Send + Sync + Debug {
+    fn read_text_block(&self, doc_id: &str) -> BoxResultFuture<TextBlockInfo, CollaborateError>;
 
-    fn create_document(
+    fn create_text_block(
         &self,
         doc_id: &str,
         repeated_revision: RepeatedRevisionPB,
     ) -> BoxResultFuture<Option<TextBlockInfo>, CollaborateError>;
 
-    fn read_document_revisions(
+    fn read_text_block_revisions(
         &self,
         doc_id: &str,
         rev_ids: Option<Vec<i64>>,
     ) -> BoxResultFuture<Vec<RevisionPB>, CollaborateError>;
 
-    fn save_document_revisions(&self, repeated_revision: RepeatedRevisionPB) -> BoxResultFuture<(), CollaborateError>;
+    fn save_text_block_revisions(&self, repeated_revision: RepeatedRevisionPB)
+        -> BoxResultFuture<(), CollaborateError>;
 
-    fn reset_document(
+    fn reset_text_block(
         &self,
         doc_id: &str,
         repeated_revision: RepeatedRevisionPB,
     ) -> BoxResultFuture<(), CollaborateError>;
 }
 
-impl RevisionSyncPersistence for Arc<dyn DocumentCloudPersistence> {
+impl RevisionSyncPersistence for Arc<dyn TextBlockCloudPersistence> {
     fn read_revisions(
         &self,
         object_id: &str,
         rev_ids: Option<Vec<i64>>,
     ) -> BoxResultFuture<Vec<RevisionPB>, CollaborateError> {
-        (**self).read_document_revisions(object_id, rev_ids)
+        (**self).read_text_block_revisions(object_id, rev_ids)
     }
 
     fn save_revisions(&self, repeated_revision: RepeatedRevisionPB) -> BoxResultFuture<(), CollaborateError> {
-        (**self).save_document_revisions(repeated_revision)
+        (**self).save_text_block_revisions(repeated_revision)
     }
 
     fn reset_object(
@@ -59,17 +60,17 @@ impl RevisionSyncPersistence for Arc<dyn DocumentCloudPersistence> {
         object_id: &str,
         repeated_revision: RepeatedRevisionPB,
     ) -> BoxResultFuture<(), CollaborateError> {
-        (**self).reset_document(object_id, repeated_revision)
+        (**self).reset_text_block(object_id, repeated_revision)
     }
 }
 
 pub struct ServerDocumentManager {
     document_handlers: Arc<RwLock<HashMap<String, Arc<OpenDocumentHandler>>>>,
-    persistence: Arc<dyn DocumentCloudPersistence>,
+    persistence: Arc<dyn TextBlockCloudPersistence>,
 }
 
 impl ServerDocumentManager {
-    pub fn new(persistence: Arc<dyn DocumentCloudPersistence>) -> Self {
+    pub fn new(persistence: Arc<dyn TextBlockCloudPersistence>) -> Self {
         Self {
             document_handlers: Arc::new(RwLock::new(HashMap::new())),
             persistence,
@@ -151,7 +152,7 @@ impl ServerDocumentManager {
         }
 
         let mut write_guard = self.document_handlers.write().await;
-        match self.persistence.read_document(doc_id).await {
+        match self.persistence.read_text_block(doc_id).await {
             Ok(doc) => {
                 let handler = self.create_document_handler(doc).await.map_err(internal_error).unwrap();
                 write_guard.insert(doc_id.to_owned(), handler.clone());
@@ -168,7 +169,7 @@ impl ServerDocumentManager {
         doc_id: &str,
         repeated_revision: RepeatedRevisionPB,
     ) -> Result<Arc<OpenDocumentHandler>, CollaborateError> {
-        match self.persistence.create_document(doc_id, repeated_revision).await? {
+        match self.persistence.create_text_block(doc_id, repeated_revision).await? {
             None => Err(CollaborateError::internal().context("Create document info from revisions failed")),
             Some(doc) => {
                 let handler = self.create_document_handler(doc).await?;
@@ -205,7 +206,7 @@ struct OpenDocumentHandler {
 }
 
 impl OpenDocumentHandler {
-    fn new(doc: TextBlockInfo, persistence: Arc<dyn DocumentCloudPersistence>) -> Result<Self, CollaborateError> {
+    fn new(doc: TextBlockInfo, persistence: Arc<dyn TextBlockCloudPersistence>) -> Result<Self, CollaborateError> {
         let doc_id = doc.block_id.clone();
         let (sender, receiver) = mpsc::channel(1000);
         let users = DashMap::new();

+ 4 - 4
shared-lib/flowy-folder-data-model/src/entities/view.rs

@@ -83,24 +83,24 @@ impl std::convert::From<View> for Trash {
 #[derive(Eq, PartialEq, Hash, Debug, ProtoBuf_Enum, Clone, Serialize_repr, Deserialize_repr)]
 #[repr(u8)]
 pub enum ViewDataType {
-    Block = 0,
+    TextBlock = 0,
     Grid = 1,
 }
 
 impl std::default::Default for ViewDataType {
     fn default() -> Self {
-        ViewDataType::Block
+        ViewDataType::TextBlock
     }
 }
 
 impl std::convert::From<i32> for ViewDataType {
     fn from(val: i32) -> Self {
         match val {
-            0 => ViewDataType::Block,
+            0 => ViewDataType::TextBlock,
             1 => ViewDataType::Grid,
             _ => {
                 log::error!("Invalid view type: {}", val);
-                ViewDataType::Block
+                ViewDataType::TextBlock
             }
         }
     }

+ 18 - 18
shared-lib/flowy-folder-data-model/src/protobuf/model/view.rs

@@ -165,7 +165,7 @@ impl View {
         self.data_type
     }
     pub fn clear_data_type(&mut self) {
-        self.data_type = ViewDataType::Block;
+        self.data_type = ViewDataType::TextBlock;
     }
 
     // Param is passed by value, moved
@@ -409,7 +409,7 @@ impl ::protobuf::Message for View {
         if !self.desc.is_empty() {
             my_size += ::protobuf::rt::string_size(4, &self.desc);
         }
-        if self.data_type != ViewDataType::Block {
+        if self.data_type != ViewDataType::TextBlock {
             my_size += ::protobuf::rt::enum_size(5, self.data_type);
         }
         if self.version != 0 {
@@ -452,7 +452,7 @@ impl ::protobuf::Message for View {
         if !self.desc.is_empty() {
             os.write_string(4, &self.desc)?;
         }
-        if self.data_type != ViewDataType::Block {
+        if self.data_type != ViewDataType::TextBlock {
             os.write_enum(5, ::protobuf::ProtobufEnum::value(&self.data_type))?;
         }
         if self.version != 0 {
@@ -596,7 +596,7 @@ impl ::protobuf::Clear for View {
         self.belong_to_id.clear();
         self.name.clear();
         self.desc.clear();
-        self.data_type = ViewDataType::Block;
+        self.data_type = ViewDataType::TextBlock;
         self.version = 0;
         self.belongings.clear();
         self.modified_time = 0;
@@ -952,7 +952,7 @@ impl CreateViewPayload {
         self.data_type
     }
     pub fn clear_data_type(&mut self) {
-        self.data_type = ViewDataType::Block;
+        self.data_type = ViewDataType::TextBlock;
     }
 
     // Param is passed by value, moved
@@ -1060,7 +1060,7 @@ impl ::protobuf::Message for CreateViewPayload {
         if !self.desc.is_empty() {
             my_size += ::protobuf::rt::string_size(3, &self.desc);
         }
-        if self.data_type != ViewDataType::Block {
+        if self.data_type != ViewDataType::TextBlock {
             my_size += ::protobuf::rt::enum_size(5, self.data_type);
         }
         if !self.ext_data.is_empty() {
@@ -1091,7 +1091,7 @@ impl ::protobuf::Message for CreateViewPayload {
         if !self.desc.is_empty() {
             os.write_string(3, &self.desc)?;
         }
-        if self.data_type != ViewDataType::Block {
+        if self.data_type != ViewDataType::TextBlock {
             os.write_enum(5, ::protobuf::ProtobufEnum::value(&self.data_type))?;
         }
         if !self.ext_data.is_empty() {
@@ -1200,7 +1200,7 @@ impl ::protobuf::Clear for CreateViewPayload {
         self.name.clear();
         self.desc.clear();
         self.one_of_thumbnail = ::std::option::Option::None;
-        self.data_type = ViewDataType::Block;
+        self.data_type = ViewDataType::TextBlock;
         self.ext_data.clear();
         self.plugin_type = 0;
         self.unknown_fields.clear();
@@ -1358,7 +1358,7 @@ impl CreateViewParams {
         self.data_type
     }
     pub fn clear_data_type(&mut self) {
-        self.data_type = ViewDataType::Block;
+        self.data_type = ViewDataType::TextBlock;
     }
 
     // Param is passed by value, moved
@@ -1524,7 +1524,7 @@ impl ::protobuf::Message for CreateViewParams {
         if !self.thumbnail.is_empty() {
             my_size += ::protobuf::rt::string_size(4, &self.thumbnail);
         }
-        if self.data_type != ViewDataType::Block {
+        if self.data_type != ViewDataType::TextBlock {
             my_size += ::protobuf::rt::enum_size(5, self.data_type);
         }
         if !self.ext_data.is_empty() {
@@ -1557,7 +1557,7 @@ impl ::protobuf::Message for CreateViewParams {
         if !self.thumbnail.is_empty() {
             os.write_string(4, &self.thumbnail)?;
         }
-        if self.data_type != ViewDataType::Block {
+        if self.data_type != ViewDataType::TextBlock {
             os.write_enum(5, ::protobuf::ProtobufEnum::value(&self.data_type))?;
         }
         if !self.ext_data.is_empty() {
@@ -1675,7 +1675,7 @@ impl ::protobuf::Clear for CreateViewParams {
         self.name.clear();
         self.desc.clear();
         self.thumbnail.clear();
-        self.data_type = ViewDataType::Block;
+        self.data_type = ViewDataType::TextBlock;
         self.ext_data.clear();
         self.view_id.clear();
         self.data.clear();
@@ -2821,7 +2821,7 @@ impl ::protobuf::reflect::ProtobufValue for UpdateViewParams {
 
 #[derive(Clone,PartialEq,Eq,Debug,Hash)]
 pub enum ViewDataType {
-    Block = 0,
+    TextBlock = 0,
     Grid = 1,
 }
 
@@ -2832,7 +2832,7 @@ impl ::protobuf::ProtobufEnum for ViewDataType {
 
     fn from_i32(value: i32) -> ::std::option::Option<ViewDataType> {
         match value {
-            0 => ::std::option::Option::Some(ViewDataType::Block),
+            0 => ::std::option::Option::Some(ViewDataType::TextBlock),
             1 => ::std::option::Option::Some(ViewDataType::Grid),
             _ => ::std::option::Option::None
         }
@@ -2840,7 +2840,7 @@ impl ::protobuf::ProtobufEnum for ViewDataType {
 
     fn values() -> &'static [Self] {
         static values: &'static [ViewDataType] = &[
-            ViewDataType::Block,
+            ViewDataType::TextBlock,
             ViewDataType::Grid,
         ];
         values
@@ -2859,7 +2859,7 @@ impl ::std::marker::Copy for ViewDataType {
 
 impl ::std::default::Default for ViewDataType {
     fn default() -> Self {
-        ViewDataType::Block
+        ViewDataType::TextBlock
     }
 }
 
@@ -2904,8 +2904,8 @@ static file_descriptor_proto_data: &'static [u8] = b"\
     \x17\n\x07view_id\x18\x01\x20\x01(\tR\x06viewId\x12\x14\n\x04name\x18\
     \x02\x20\x01(\tH\0R\x04name\x12\x14\n\x04desc\x18\x03\x20\x01(\tH\x01R\
     \x04desc\x12\x1e\n\tthumbnail\x18\x04\x20\x01(\tH\x02R\tthumbnailB\r\n\
-    \x0bone_of_nameB\r\n\x0bone_of_descB\x12\n\x10one_of_thumbnail*#\n\x0cVi\
-    ewDataType\x12\t\n\x05Block\x10\0\x12\x08\n\x04Grid\x10\x01b\x06proto3\
+    \x0bone_of_nameB\r\n\x0bone_of_descB\x12\n\x10one_of_thumbnail*'\n\x0cVi\
+    ewDataType\x12\r\n\tTextBlock\x10\0\x12\x08\n\x04Grid\x10\x01b\x06proto3\
 ";
 
 static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;

+ 1 - 1
shared-lib/flowy-folder-data-model/src/protobuf/proto/view.proto

@@ -56,6 +56,6 @@ message UpdateViewParams {
     oneof one_of_thumbnail { string thumbnail = 4; };
 }
 enum ViewDataType {
-    Block = 0;
+    TextBlock = 0;
     Grid = 1;
 }

+ 1 - 1
shared-lib/flowy-folder-data-model/src/user_default.rs

@@ -49,7 +49,7 @@ fn create_default_view(app_id: String, time: chrono::DateTime<Utc>) -> View {
     let view_id = uuid::Uuid::new_v4();
     let name = "Read me".to_string();
     let desc = "".to_string();
-    let data_type = ViewDataType::Block;
+    let data_type = ViewDataType::TextBlock;
 
     View {
         id: view_id.to_string(),

+ 13 - 4
shared-lib/flowy-grid-data-model/src/entities/meta.rs

@@ -30,6 +30,15 @@ pub struct GridBlock {
     pub row_count: i32,
 }
 
+impl GridBlock {
+    pub fn new() -> Self {
+        GridBlock {
+            id: uuid::Uuid::new_v4().to_string(),
+            ..Default::default()
+        }
+    }
+}
+
 pub struct GridBlockChangeset {
     pub block_id: String,
     pub start_row_index: Option<i32>,
@@ -73,9 +82,9 @@ pub struct Field {
 }
 
 impl Field {
-    pub fn new(id: &str, name: &str, desc: &str, field_type: FieldType) -> Self {
+    pub fn new(name: &str, desc: &str, field_type: FieldType) -> Self {
         Self {
-            id: id.to_owned(),
+            id: uuid::Uuid::new_v4().to_string(),
             name: name.to_string(),
             desc: desc.to_string(),
             field_type,
@@ -224,14 +233,14 @@ pub struct RowMeta {
 }
 
 impl RowMeta {
-    pub fn new(id: &str, block_id: &str, cells: Vec<CellMeta>) -> Self {
+    pub fn new(block_id: &str, cells: Vec<CellMeta>) -> Self {
         let cell_by_field_id = cells
             .into_iter()
             .map(|cell| (cell.id.clone(), cell))
             .collect::<HashMap<String, CellMeta>>();
 
         Self {
-            id: id.to_owned(),
+            id: uuid::Uuid::new_v4().to_string(),
             block_id: block_id.to_owned(),
             cell_by_field_id,
             height: DEFAULT_ROW_HEIGHT,

+ 3 - 1
shared-lib/flowy-grid-data-model/tests/serde_test.rs

@@ -32,7 +32,9 @@ fn grid_default_serde_test() {
 }
 
 fn create_field(field_id: &str) -> Field {
-    Field::new(field_id, "Text Field", "", FieldType::RichText)
+    let mut field = Field::new("Text Field", "", FieldType::RichText);
+    field.id = field_id.to_string();
+    field
 }
 
 #[allow(dead_code)]