Browse Source

chore: impl view data processor

appflowy 3 years ago
parent
commit
264166fa29

+ 3 - 3
frontend/app_flowy/lib/workspace/application/doc/doc_bloc.dart

@@ -85,10 +85,10 @@ class DocumentBloc extends Bloc<DocumentEvent, DocumentState> {
     });
 
     listener.start();
-    final result = await service.openDocument(docId: view.id);
+    final result = await service.openDocument(docId: view.id, dataType: view.dataType);
     result.fold(
       (block) {
-        document = _decodeJsonToDocument(block.deltaJson);
+        document = _decodeJsonToDocument(block.deltaStr);
         _subscription = document.changes.listen((event) {
           final delta = event.item2;
           final documentDelta = document.toDelta();
@@ -115,7 +115,7 @@ class DocumentBloc extends Bloc<DocumentEvent, DocumentState> {
 
     result.fold((rustDoc) {
       // final json = utf8.decode(doc.data);
-      final rustDelta = Delta.fromJson(jsonDecode(rustDoc.deltaJson));
+      final rustDelta = Delta.fromJson(jsonDecode(rustDoc.deltaStr));
       if (documentDelta != rustDelta) {
         Log.error("Receive : $rustDelta");
         Log.error("Expected : $documentDelta");

+ 5 - 2
frontend/app_flowy/lib/workspace/application/doc/doc_service.dart

@@ -5,7 +5,10 @@ import 'package:flowy_sdk/protobuf/flowy-folder-data-model/view.pb.dart';
 import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
 
 class DocumentService {
-  Future<Either<BlockDelta, FlowyError>> openDocument({required String docId}) {
+  Future<Either<BlockDelta, FlowyError>> openDocument({
+    required String docId,
+    required ViewDataType dataType,
+  }) {
     final request = ViewId(value: docId);
     return FolderEventOpenView(request).send();
   }
@@ -13,7 +16,7 @@ class DocumentService {
   Future<Either<BlockDelta, FlowyError>> composeDelta({required String docId, required String data}) {
     final request = BlockDelta.create()
       ..blockId = docId
-      ..deltaJson = data;
+      ..deltaStr = data;
     return FolderEventApplyDocDelta(request).send();
   }
 

+ 4 - 1
frontend/app_flowy/lib/workspace/presentation/plugins/grid/grid.dart

@@ -6,7 +6,7 @@ import 'package:flutter/material.dart';
 
 import 'src/grid_page.dart';
 
-class GridPluginBuilder extends PluginBuilder {
+class GridPluginBuilder implements PluginBuilder {
   @override
   Plugin build(dynamic data) {
     if (data is View) {
@@ -21,6 +21,9 @@ class GridPluginBuilder extends PluginBuilder {
 
   @override
   PluginType get pluginType => DefaultPlugin.grid.type();
+
+  @override
+  ViewDataType get dataType => ViewDataType.Grid;
 }
 
 class GridPluginConfig implements PluginConfig {

+ 1 - 2
frontend/rust-lib/Cargo.lock

@@ -986,13 +986,13 @@ dependencies = [
 name = "flowy-folder"
 version = "0.1.0"
 dependencies = [
- "async-trait",
  "bincode",
  "bytes",
  "chrono",
  "crossbeam",
  "crossbeam-utils",
  "dart-notify",
+ "dashmap",
  "derive_more",
  "diesel",
  "diesel_derives",
@@ -1134,7 +1134,6 @@ dependencies = [
 name = "flowy-sdk"
 version = "0.1.0"
 dependencies = [
- "async-trait",
  "bincode",
  "bytes",
  "claim 0.5.0",

+ 1 - 1
frontend/rust-lib/flowy-folder/Cargo.toml

@@ -42,7 +42,7 @@ bytes = { version = "1.0" }
 crossbeam = "0.8"
 crossbeam-utils = "0.8"
 chrono = "0.4"
-async-trait = "0.1.52"
+dashmap = "4.0"
 
 [dev-dependencies]
 serial_test = "0.5.1"

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

@@ -8,17 +8,18 @@ use crate::{
         TrashController, ViewController, WorkspaceController,
     },
 };
-use async_trait::async_trait;
 use bytes::Bytes;
 use chrono::Utc;
-use flowy_block::BlockManager;
-use flowy_collaboration::client_document::default::{initial_quill_delta, initial_quill_delta_string, initial_read_me};
-use flowy_collaboration::entities::revision::{RepeatedRevision, Revision};
+
+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;
 use flowy_folder_data_model::user_default;
 use flowy_sync::RevisionWebSocket;
 use lazy_static::lazy_static;
+use lib_infra::future::FutureResult;
 use std::{collections::HashMap, convert::TryInto, fmt::Formatter, sync::Arc};
 use tokio::sync::RwLock as TokioRwLock;
 lazy_static! {
@@ -62,6 +63,7 @@ pub struct FolderManager {
     pub(crate) trash_controller: Arc<TrashController>,
     web_socket: Arc<dyn RevisionWebSocket>,
     folder_editor: Arc<TokioRwLock<Option<Arc<ClientFolderEditor>>>>,
+    data_processors: ViewDataProcessorMap,
 }
 
 impl FolderManager {
@@ -69,8 +71,7 @@ impl FolderManager {
         user: Arc<dyn WorkspaceUser>,
         cloud_service: Arc<dyn FolderCouldServiceV1>,
         database: Arc<dyn WorkspaceDatabase>,
-        data_processors: DataProcessorMap,
-        block_manager: Arc<BlockManager>,
+        data_processors: ViewDataProcessorMap,
         web_socket: Arc<dyn RevisionWebSocket>,
     ) -> Self {
         if let Ok(user_id) = user.user_id() {
@@ -93,8 +94,7 @@ impl FolderManager {
             persistence.clone(),
             cloud_service.clone(),
             trash_controller.clone(),
-            data_processors,
-            block_manager,
+            data_processors.clone(),
         ));
 
         let app_controller = Arc::new(AppController::new(
@@ -121,6 +121,7 @@ impl FolderManager {
             trash_controller,
             web_socket,
             folder_editor,
+            data_processors,
         }
     }
 
@@ -167,6 +168,11 @@ impl FolderManager {
 
         let _ = self.app_controller.initialize()?;
         let _ = self.view_controller.initialize()?;
+
+        self.data_processors.iter().for_each(|(_, processor)| {
+            processor.initialize();
+        });
+
         write_guard.insert(user_id.to_owned(), true);
         Ok(())
     }
@@ -201,7 +207,9 @@ impl DefaultFolderBuilder {
                     initial_quill_delta_string()
                 };
                 view_controller.set_latest_view(view);
-                let _ = view_controller.create_view(&view.id, Bytes::from(view_data)).await?;
+                let _ = view_controller
+                    .create_view(&view.id, ViewDataType::RichText, Bytes::from(view_data))
+                    .await?;
             }
         }
         let folder = FolderPad::new(vec![workspace.clone()], vec![])?;
@@ -222,13 +230,20 @@ impl FolderManager {
     }
 }
 
-#[async_trait]
 pub trait ViewDataProcessor {
-    async fn create_container(&self, view_id: &str, repeated_revision: RepeatedRevision) -> FlowyResult<()>;
-    async fn delete_container(&self, view_id: &str) -> FlowyResult<()>;
-    async fn close_container(&self, view_id: &str) -> FlowyResult<()>;
-    async fn delta_str(&self, view_id: &str) -> FlowyResult<String>;
+    fn initialize(&self) -> FutureResult<(), FlowyError>;
+
+    fn create_container(&self, view_id: &str, repeated_revision: RepeatedRevision) -> FutureResult<(), FlowyError>;
+
+    fn delete_container(&self, view_id: &str) -> FutureResult<(), FlowyError>;
+
+    fn close_container(&self, view_id: &str) -> FutureResult<(), FlowyError>;
+
+    fn delta_str(&self, view_id: &str) -> FutureResult<String, FlowyError>;
+
+    fn default_view_data(&self) -> String;
+
     fn data_type(&self) -> ViewDataType;
 }
 
-pub type DataProcessorMap = Arc<HashMap<ViewDataType, Arc<dyn ViewDataProcessor + Send + Sync>>>;
+pub type ViewDataProcessorMap = Arc<HashMap<ViewDataType, Arc<dyn ViewDataProcessor + Send + Sync>>>;

+ 105 - 52
frontend/rust-lib/flowy-folder/src/services/view/controller.rs

@@ -1,15 +1,4 @@
-use bytes::Bytes;
-use flowy_collaboration::entities::{
-    document_info::{BlockDelta, BlockId},
-    revision::{RepeatedRevision, Revision},
-};
-
-use flowy_collaboration::client_document::default::initial_quill_delta_string;
-use futures::{FutureExt, StreamExt};
-use std::collections::HashMap;
-use std::{collections::HashSet, sync::Arc};
-
-use crate::manager::DataProcessorMap;
+use crate::manager::{ViewDataProcessor, ViewDataProcessorMap};
 use crate::{
     dart_notification::{send_dart_notification, FolderNotification},
     entities::{
@@ -23,10 +12,16 @@ use crate::{
         TrashController, TrashEvent,
     },
 };
-use flowy_block::BlockManager;
+use bytes::Bytes;
+use flowy_collaboration::entities::{
+    document_info::{BlockDelta, BlockId},
+    revision::{RepeatedRevision, Revision},
+};
 use flowy_database::kv::KV;
 use flowy_folder_data_model::entities::view::ViewDataType;
+use futures::{FutureExt, StreamExt};
 use lib_infra::uuid;
+use std::{collections::HashSet, sync::Arc};
 
 const LATEST_VIEW_ID: &str = "latest_view_id";
 
@@ -35,8 +30,7 @@ pub(crate) struct ViewController {
     cloud_service: Arc<dyn FolderCouldServiceV1>,
     persistence: Arc<FolderPersistence>,
     trash_controller: Arc<TrashController>,
-    data_processors: DataProcessorMap,
-    block_manager: Arc<BlockManager>,
+    data_processors: ViewDataProcessorMap,
 }
 
 impl ViewController {
@@ -45,8 +39,7 @@ impl ViewController {
         persistence: Arc<FolderPersistence>,
         cloud_service: Arc<dyn FolderCouldServiceV1>,
         trash_controller: Arc<TrashController>,
-        data_processors: DataProcessorMap,
-        block_manager: Arc<BlockManager>,
+        data_processors: ViewDataProcessorMap,
     ) -> Self {
         Self {
             user,
@@ -54,38 +47,48 @@ impl ViewController {
             persistence,
             trash_controller,
             data_processors,
-            block_manager,
         }
     }
 
     pub(crate) fn initialize(&self) -> Result<(), FlowyError> {
-        let _ = self.block_manager.init()?;
         self.listen_trash_can_event();
         Ok(())
     }
 
     #[tracing::instrument(level = "trace", skip(self, params), fields(name = %params.name), err)]
-    pub(crate) async fn create_view_from_params(&self, params: CreateViewParams) -> Result<View, FlowyError> {
-        let view_data = if params.data.is_empty() {
-            initial_quill_delta_string()
+    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.data = default_view_data.clone();
+            default_view_data
         } else {
             params.data.clone()
         };
 
-        let _ = self.create_view(&params.view_id, Bytes::from(view_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)
     }
 
     #[tracing::instrument(level = "debug", skip(self, view_id, delta_data), err)]
-    pub(crate) async fn create_view(&self, view_id: &str, delta_data: Bytes) -> Result<(), FlowyError> {
+    pub(crate) async fn create_view(
+        &self,
+        view_id: &str,
+        data_type: ViewDataType,
+        delta_data: Bytes,
+    ) -> Result<(), FlowyError> {
         if delta_data.is_empty() {
             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 _ = self.block_manager.create_block(view_id, repeated_revision).await?;
+        let processor = self.get_data_processor(&data_type)?;
+        let _ = processor.create_container(view_id, repeated_revision).await?;
         Ok(())
     }
 
@@ -132,8 +135,8 @@ impl ViewController {
 
     #[tracing::instrument(level = "debug", skip(self), err)]
     pub(crate) async fn open_view(&self, view_id: &str) -> Result<BlockDelta, FlowyError> {
-        let editor = self.block_manager.open_block(view_id).await?;
-        let delta_str = editor.delta_str().await?;
+        let processor = self.get_data_processor_from_view_id(view_id).await?;
+        let delta_str = processor.delta_str(view_id).await?;
         KV::set_str(LATEST_VIEW_ID, view_id.to_owned());
         Ok(BlockDelta {
             block_id: view_id.to_string(),
@@ -142,8 +145,9 @@ impl ViewController {
     }
 
     #[tracing::instrument(level = "debug", skip(self), err)]
-    pub(crate) async fn close_view(&self, doc_id: &str) -> Result<(), FlowyError> {
-        let _ = self.block_manager.close_block(doc_id)?;
+    pub(crate) async fn close_view(&self, view_id: &str) -> Result<(), FlowyError> {
+        let processor = self.get_data_processor_from_view_id(view_id).await?;
+        let _ = processor.close_container(view_id).await?;
         Ok(())
     }
 
@@ -154,7 +158,8 @@ impl ViewController {
                 let _ = KV::remove(LATEST_VIEW_ID);
             }
         }
-        let _ = self.block_manager.close_block(&params.value)?;
+        let processor = self.get_data_processor_from_view_id(&params.value).await?;
+        let _ = processor.close_container(&params.value).await?;
         Ok(())
     }
 
@@ -165,8 +170,8 @@ impl ViewController {
             .begin_transaction(|transaction| transaction.read_view(view_id))
             .await?;
 
-        let editor = self.block_manager.open_block(view_id).await?;
-        let delta_str = editor.delta_str().await?;
+        let processor = self.get_data_processor(&view.data_type)?;
+        let delta_str = processor.delta_str(view_id).await?;
         let duplicate_params = CreateViewParams {
             belong_to_id: view.belong_to_id.clone(),
             name: format!("{} (copy)", &view.name),
@@ -287,7 +292,7 @@ impl ViewController {
     fn listen_trash_can_event(&self) {
         let mut rx = self.trash_controller.subscribe();
         let persistence = self.persistence.clone();
-        let block_manager = self.block_manager.clone();
+        let data_processors = self.data_processors.clone();
         let trash_controller = self.trash_controller.clone();
         let _ = tokio::spawn(async move {
             loop {
@@ -301,7 +306,7 @@ impl ViewController {
                 if let Some(event) = stream.next().await {
                     handle_trash_event(
                         persistence.clone(),
-                        block_manager.clone(),
+                        data_processors.clone(),
                         trash_controller.clone(),
                         event,
                     )
@@ -310,12 +315,34 @@ impl ViewController {
             }
         });
     }
+
+    async fn get_data_processor_from_view_id(
+        &self,
+        view_id: &str,
+    ) -> FlowyResult<Arc<dyn ViewDataProcessor + Send + Sync>> {
+        let view = self
+            .persistence
+            .begin_transaction(|transaction| transaction.read_view(view_id))
+            .await?;
+        self.get_data_processor(&view.data_type)
+    }
+
+    #[inline]
+    fn get_data_processor(&self, data_type: &ViewDataType) -> FlowyResult<Arc<dyn ViewDataProcessor + Send + Sync>> {
+        match self.data_processors.get(data_type) {
+            None => Err(FlowyError::internal().context(format!(
+                "Get data processor failed. Unknown view data type: {:?}",
+                data_type
+            ))),
+            Some(processor) => Ok(processor.clone()),
+        }
+    }
 }
 
-#[tracing::instrument(level = "trace", skip(persistence, block_manager, trash_can))]
+#[tracing::instrument(level = "trace", skip(persistence, data_processors, trash_can))]
 async fn handle_trash_event(
     persistence: Arc<FolderPersistence>,
-    block_manager: Arc<BlockManager>,
+    data_processors: ViewDataProcessorMap,
     trash_can: Arc<TrashController>,
     event: TrashEvent,
 ) {
@@ -347,28 +374,54 @@ async fn handle_trash_event(
             let _ = ret.send(result).await;
         }
         TrashEvent::Delete(identifiers, ret) => {
-            let result = persistence
-                .begin_transaction(|transaction| {
-                    let mut notify_ids = HashSet::new();
-                    for identifier in identifiers.items {
-                        let view = transaction.read_view(&identifier.id)?;
-                        let _ = transaction.delete_view(&identifier.id)?;
-                        let _ = block_manager.delete_block(&identifier.id)?;
-                        notify_ids.insert(view.belong_to_id);
-                    }
+            let result = || async {
+                let views = persistence
+                    .begin_transaction(|transaction| {
+                        let mut notify_ids = HashSet::new();
+                        let mut views = vec![];
+                        for identifier in identifiers.items {
+                            let view = transaction.read_view(&identifier.id)?;
+                            let _ = transaction.delete_view(&view.id)?;
+                            notify_ids.insert(view.belong_to_id.clone());
+                            views.push(view);
+                        }
+                        for notify_id in notify_ids {
+                            let _ = notify_views_changed(&notify_id, trash_can.clone(), &transaction)?;
+                        }
+                        Ok(views)
+                    })
+                    .await?;
 
-                    for notify_id in notify_ids {
-                        let _ = notify_views_changed(&notify_id, trash_can.clone(), &transaction)?;
+                for view in views {
+                    match get_data_processor(data_processors.clone(), &view.data_type) {
+                        Ok(processor) => {
+                            let _ = processor.close_container(&view.id).await?;
+                        }
+                        Err(e) => {
+                            tracing::error!("{}", e)
+                        }
                     }
-
-                    Ok(())
-                })
-                .await;
-            let _ = ret.send(result).await;
+                }
+                Ok(())
+            };
+            let _ = ret.send(result().await).await;
         }
     }
 }
 
+fn get_data_processor(
+    data_processors: ViewDataProcessorMap,
+    data_type: &ViewDataType,
+) -> FlowyResult<Arc<dyn ViewDataProcessor + Send + Sync>> {
+    match data_processors.get(data_type) {
+        None => Err(FlowyError::internal().context(format!(
+            "Get data processor failed. Unknown view data type: {:?}",
+            data_type
+        ))),
+        Some(processor) => Ok(processor.clone()),
+    }
+}
+
 fn read_local_views_with_transaction<'a>(
     identifiers: RepeatedTrashId,
     transaction: &'a (dyn FolderPersistenceTransaction + 'a),

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

@@ -1,9 +1,6 @@
 use crate::manager::GridManager;
 use flowy_error::FlowyError;
-use flowy_grid_data_model::entities::{
-    CreateGridPayload, Grid, GridId, QueryFieldPayload, QueryRowPayload, RepeatedField, RepeatedFieldOrder,
-    RepeatedRow, RepeatedRowOrder,
-};
+use flowy_grid_data_model::entities::{Grid, GridId, QueryFieldPayload, QueryRowPayload, RepeatedField, RepeatedRow};
 use lib_dispatch::prelude::{data_result, AppData, Data, DataResult};
 use std::sync::Arc;
 

+ 49 - 24
frontend/rust-lib/flowy-grid/src/manager.rs

@@ -1,12 +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::client_grid::{make_grid_delta, make_grid_revisions};
+use flowy_collaboration::client_grid::make_grid_delta;
 use flowy_collaboration::entities::revision::RepeatedRevision;
 use flowy_error::{FlowyError, FlowyResult};
-use flowy_grid_data_model::entities::{
-    Field, FieldOrder, Grid, RawRow, RepeatedField, RepeatedFieldOrder, RepeatedRow, RepeatedRowOrder, Row, RowOrder,
-};
+use flowy_grid_data_model::entities::{Field, FieldOrder, FieldType, Grid, RawRow, RowOrder};
 use flowy_sync::{RevisionManager, RevisionPersistence, RevisionWebSocket};
 use lib_sqlite::ConnectionPool;
 use parking_lot::RwLock;
@@ -21,12 +19,11 @@ pub trait GridUser: Send + Sync {
 pub struct GridManager {
     grid_editors: Arc<GridEditors>,
     grid_user: Arc<dyn GridUser>,
-    rev_web_socket: Arc<dyn RevisionWebSocket>,
     kv_persistence: Arc<RwLock<Option<Arc<GridKVPersistence>>>>,
 }
 
 impl GridManager {
-    pub fn new(grid_user: Arc<dyn GridUser>, rev_web_socket: Arc<dyn RevisionWebSocket>) -> Self {
+    pub fn new(grid_user: Arc<dyn GridUser>, _rev_web_socket: Arc<dyn RevisionWebSocket>) -> Self {
         let grid_editors = Arc::new(GridEditors::new());
 
         // kv_persistence will be initialized after first access.
@@ -35,7 +32,6 @@ impl GridManager {
         Self {
             grid_editors,
             grid_user,
-            rev_web_socket,
             kv_persistence,
         }
     }
@@ -123,28 +119,57 @@ impl GridManager {
     }
 }
 
-pub fn make_grid(
-    user_id: &str,
-    grid_id: &str,
-    fields: Option<Vec<Field>>,
-    rows: Option<Vec<RawRow>>,
-) -> RepeatedRevision {
-    let mut field_orders = vec![];
-    let mut row_orders = vec![];
-    if let Some(fields) = fields {
-        field_orders = fields.iter().map(|field| FieldOrder::from(field)).collect::<Vec<_>>();
-    }
-    if let Some(rows) = rows {
-        row_orders = rows.iter().map(|row| RowOrder::from(row)).collect::<Vec<_>>();
-    }
+use lib_infra::uuid;
+pub fn default_grid() -> String {
+    let grid_id = uuid();
+    let fields = vec![
+        Field {
+            id: uuid(),
+            name: "".to_string(),
+            desc: "".to_string(),
+            field_type: FieldType::RichText,
+            frozen: false,
+            width: 100,
+            type_options: Default::default(),
+        },
+        Field {
+            id: uuid(),
+            name: "".to_string(),
+            desc: "".to_string(),
+            field_type: FieldType::RichText,
+            frozen: false,
+            width: 100,
+            type_options: Default::default(),
+        },
+    ];
+
+    let rows = vec![
+        RawRow {
+            id: uuid(),
+            grid_id: grid_id.clone(),
+            cell_by_field_id: Default::default(),
+        },
+        RawRow {
+            id: uuid(),
+            grid_id: grid_id.clone(),
+            cell_by_field_id: Default::default(),
+        },
+    ];
+
+    make_grid(&grid_id, fields, rows)
+}
+
+pub fn make_grid(grid_id: &str, fields: Vec<Field>, rows: Vec<RawRow>) -> String {
+    let field_orders = fields.iter().map(FieldOrder::from).collect::<Vec<_>>();
+    let row_orders = rows.iter().map(RowOrder::from).collect::<Vec<_>>();
 
     let grid = Grid {
         id: grid_id.to_owned(),
         field_orders: field_orders.into(),
         row_orders: row_orders.into(),
     };
-
-    make_grid_revisions(user_id, &grid)
+    let delta = make_grid_delta(&grid);
+    delta.to_delta_str()
 }
 
 pub struct GridEditors {

+ 5 - 15
frontend/rust-lib/flowy-grid/src/services/cell_data.rs

@@ -1,3 +1,4 @@
+#![allow(clippy::upper_case_acronyms)]
 use crate::impl_any_data;
 use crate::services::util::*;
 use bytes::Bytes;
@@ -12,8 +13,6 @@ use rusty_money::{
     Money,
 };
 use std::str::FromStr;
-
-use strum::IntoEnumIterator;
 use strum_macros::EnumIter;
 
 pub trait StringifyAnyData {
@@ -77,7 +76,7 @@ impl DisplayCell for CheckboxDescription {
 }
 
 // Date
-#[derive(Clone, Debug, ProtoBuf)]
+#[derive(Clone, Debug, ProtoBuf, Default)]
 pub struct DateDescription {
     #[pb(index = 1)]
     pub date_format: DateFormat,
@@ -87,15 +86,6 @@ pub struct DateDescription {
 }
 impl_any_data!(DateDescription, FieldType::DateTime);
 
-impl std::default::Default for DateDescription {
-    fn default() -> Self {
-        DateDescription {
-            date_format: DateFormat::default(),
-            time_format: TimeFormat::default(),
-        }
-    }
-}
-
 impl DateDescription {
     fn date_time_format_str(&self) -> String {
         format!("{} {}", self.date_format.format_str(), self.time_format.format_str())
@@ -134,7 +124,7 @@ impl DisplayCell for DateDescription {
 
 impl StringifyAnyData for DateDescription {
     fn stringify_any_data(&self, data: AnyData) -> String {
-        match String::from_utf8(data.value.clone()) {
+        match String::from_utf8(data.value) {
             Ok(s) => match s.parse::<i64>() {
                 Ok(timestamp) => {
                     let native = NaiveDateTime::from_timestamp(timestamp, 0);
@@ -380,7 +370,7 @@ impl NumberDescription {
 
 impl DisplayCell for NumberDescription {
     fn display_content(&self, s: &str) -> String {
-        match self.money_from_str(&s) {
+        match self.money_from_str(s) {
             Some(money_str) => money_str,
             None => String::default(),
         }
@@ -389,7 +379,7 @@ impl DisplayCell for NumberDescription {
 
 impl StringifyAnyData for NumberDescription {
     fn stringify_any_data(&self, data: AnyData) -> String {
-        match String::from_utf8(data.value.clone()) {
+        match String::from_utf8(data.value) {
             Ok(s) => match self.money_from_str(&s) {
                 Some(money_str) => money_str,
                 None => String::default(),

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

@@ -1,23 +1,20 @@
 use crate::manager::GridUser;
 use crate::services::kv_persistence::{GridKVPersistence, KVTransaction};
 use crate::services::stringify::stringify_deserialize;
-use dashmap::mapref::one::Ref;
+
 use dashmap::DashMap;
 use flowy_collaboration::client_grid::{GridChange, GridPad};
 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, Field, Grid, GridId, RawCell, RawRow, RepeatedField, RepeatedFieldOrder, RepeatedRow, RepeatedRowOrder, Row,
-};
-use flowy_sync::{
-    RevisionCloudService, RevisionCompact, RevisionManager, RevisionObjectBuilder, RevisionPersistence,
-    RevisionWebSocket, RevisionWebSocketManager,
+    Cell, Field, Grid, RawCell, RawRow, RepeatedField, RepeatedFieldOrder, RepeatedRow, RepeatedRowOrder, Row,
 };
+use flowy_sync::{RevisionCloudService, RevisionCompact, RevisionManager, RevisionObjectBuilder};
 use lib_infra::future::FutureResult;
 use lib_infra::uuid;
 use lib_ot::core::PlainTextAttributes;
-use lib_sqlite::ConnectionPool;
+
 use rayon::iter::{IntoParallelIterator, ParallelIterator};
 use std::collections::HashMap;
 use std::sync::Arc;

+ 3 - 3
frontend/rust-lib/flowy-grid/src/services/kv_persistence.rs

@@ -6,9 +6,9 @@ use flowy_database::{
     schema::{kv_table, kv_table::dsl},
 };
 use flowy_error::{FlowyError, FlowyResult};
-use flowy_grid_data_model::entities::{Field, GridIdentifiable, RawRow};
-use lib_infra::future::{BoxResultFuture, FutureResult};
-use lib_sqlite::{ConnectionManager, ConnectionPool};
+use flowy_grid_data_model::entities::GridIdentifiable;
+
+use lib_sqlite::ConnectionPool;
 use std::sync::Arc;
 
 #[derive(PartialEq, Clone, Debug, Queryable, Identifiable, Insertable, Associations)]

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

@@ -3,6 +3,7 @@ use crate::services::util::*;
 use flowy_error::FlowyError;
 use flowy_grid_data_model::entities::{AnyData, Field, FieldType};
 
+#[allow(dead_code)]
 pub fn stringify_serialize(field: &Field, s: &str) -> Result<AnyData, FlowyError> {
     match field.field_type {
         FieldType::RichText => RichTextDescription::from(field).str_to_any_data(s),

+ 0 - 1
frontend/rust-lib/flowy-sdk/Cargo.toml

@@ -23,7 +23,6 @@ color-eyre = { version = "0.5", default-features = false }
 bytes = "1.0"
 tokio = { version = "1", features = ["rt"] }
 parking_lot = "0.11"
-async-trait = "0.1.52"
 
 flowy-collaboration = { path = "../../../shared-lib/flowy-collaboration" }
 lib-ws = { path = "../../../shared-lib/lib-ws" }

+ 83 - 46
frontend/rust-lib/flowy-sdk/src/deps_resolve/folder_deps.rs

@@ -1,17 +1,17 @@
-use async_trait::async_trait;
 use bytes::Bytes;
 use flowy_block::BlockManager;
+use flowy_collaboration::client_document::default::initial_quill_delta_string;
 use flowy_collaboration::entities::revision::RepeatedRevision;
 use flowy_collaboration::entities::ws_data::ClientRevisionWSData;
 use flowy_database::ConnectionPool;
-use flowy_folder::manager::{DataProcessorMap, ViewDataProcessor};
-use flowy_folder::prelude::{FlowyResult, ViewDataType};
+use flowy_folder::manager::{ViewDataProcessor, ViewDataProcessorMap};
+use flowy_folder::prelude::ViewDataType;
 use flowy_folder::{
     errors::{internal_error, FlowyError},
     event_map::{FolderCouldServiceV1, WorkspaceDatabase, WorkspaceUser},
     manager::FolderManager,
 };
-use flowy_grid::manager::GridManager;
+use flowy_grid::manager::{default_grid, GridManager};
 use flowy_net::ClientServerConfiguration;
 use flowy_net::{
     http_server::folder::FolderHttpCloudService, local_server::LocalServer, ws::connection::FlowyWebSocketConnect,
@@ -19,7 +19,7 @@ use flowy_net::{
 use flowy_sync::{RevisionWebSocket, WSStateReceiver};
 use flowy_user::services::UserSession;
 use futures_core::future::BoxFuture;
-use lib_infra::future::BoxResultFuture;
+use lib_infra::future::{BoxResultFuture, FutureResult};
 use lib_ws::{WSChannel, WSMessageReceiver, WebSocketRawMessage};
 use std::collections::HashMap;
 use std::{convert::TryInto, sync::Arc};
@@ -43,17 +43,8 @@ impl FolderDepsResolver {
         };
 
         let view_data_processor = make_view_data_processor(block_manager.clone(), grid_manager.clone());
-        let folder_manager = Arc::new(
-            FolderManager::new(
-                user.clone(),
-                cloud_service,
-                database,
-                view_data_processor,
-                block_manager.clone(),
-                web_socket,
-            )
-            .await,
-        );
+        let folder_manager =
+            Arc::new(FolderManager::new(user.clone(), cloud_service, database, view_data_processor, web_socket).await);
 
         if let (Ok(user_id), Ok(token)) = (user.user_id(), user.token()) {
             match folder_manager.initialize(&user_id, &token).await {
@@ -64,12 +55,11 @@ impl FolderDepsResolver {
 
         let receiver = Arc::new(FolderWSMessageReceiverImpl(folder_manager.clone()));
         ws_conn.add_ws_message_receiver(receiver).unwrap();
-
         folder_manager
     }
 }
 
-fn make_view_data_processor(block_manager: Arc<BlockManager>, grid_manager: Arc<GridManager>) -> DataProcessorMap {
+fn make_view_data_processor(block_manager: Arc<BlockManager>, grid_manager: Arc<GridManager>) -> ViewDataProcessorMap {
     let mut map: HashMap<ViewDataType, Arc<dyn ViewDataProcessor + Send + Sync>> = HashMap::new();
 
     let block_data_impl = BlockManagerViewDataImpl(block_manager);
@@ -140,27 +130,51 @@ impl WSMessageReceiver for FolderWSMessageReceiverImpl {
 }
 
 struct BlockManagerViewDataImpl(Arc<BlockManager>);
-#[async_trait]
 impl ViewDataProcessor for BlockManagerViewDataImpl {
-    async fn create_container(&self, view_id: &str, repeated_revision: RepeatedRevision) -> FlowyResult<()> {
-        let _ = self.0.create_block(view_id, repeated_revision).await?;
-        Ok(())
+    fn initialize(&self) -> FutureResult<(), FlowyError> {
+        let block_manager = self.0.clone();
+        FutureResult::new(async move { block_manager.init() })
+    }
+
+    fn create_container(&self, view_id: &str, repeated_revision: RepeatedRevision) -> FutureResult<(), FlowyError> {
+        let block_manager = self.0.clone();
+        let view_id = view_id.to_string();
+        FutureResult::new(async move {
+            let _ = block_manager.create_block(view_id, repeated_revision).await?;
+            Ok(())
+        })
+    }
+
+    fn delete_container(&self, view_id: &str) -> FutureResult<(), FlowyError> {
+        let block_manager = self.0.clone();
+        let view_id = view_id.to_string();
+        FutureResult::new(async move {
+            let _ = block_manager.delete_block(view_id)?;
+            Ok(())
+        })
     }
 
-    async fn delete_container(&self, view_id: &str) -> FlowyResult<()> {
-        let _ = self.0.delete_block(view_id)?;
-        Ok(())
+    fn close_container(&self, view_id: &str) -> FutureResult<(), FlowyError> {
+        let block_manager = self.0.clone();
+        let view_id = view_id.to_string();
+        FutureResult::new(async move {
+            let _ = block_manager.close_block(view_id)?;
+            Ok(())
+        })
     }
 
-    async fn close_container(&self, view_id: &str) -> FlowyResult<()> {
-        let _ = self.0.close_block(view_id)?;
-        Ok(())
+    fn delta_str(&self, view_id: &str) -> FutureResult<String, FlowyError> {
+        let view_id = view_id.to_string();
+        let block_manager = self.0.clone();
+        FutureResult::new(async move {
+            let editor = block_manager.open_block(view_id).await?;
+            let delta_str = editor.delta_str().await?;
+            Ok(delta_str)
+        })
     }
 
-    async fn delta_str(&self, view_id: &str) -> FlowyResult<String> {
-        let editor = self.0.open_block(view_id).await?;
-        let delta_str = editor.delta_str().await?;
-        Ok(delta_str)
+    fn default_view_data(&self) -> String {
+        initial_quill_delta_string()
     }
 
     fn data_type(&self) -> ViewDataType {
@@ -169,27 +183,50 @@ impl ViewDataProcessor for BlockManagerViewDataImpl {
 }
 
 struct GridManagerViewDataImpl(Arc<GridManager>);
-#[async_trait]
 impl ViewDataProcessor for GridManagerViewDataImpl {
-    async fn create_container(&self, view_id: &str, repeated_revision: RepeatedRevision) -> FlowyResult<()> {
-        let _ = self.0.create_grid(view_id, repeated_revision).await?;
-        Ok(())
+    fn initialize(&self) -> FutureResult<(), FlowyError> {
+        FutureResult::new(async { Ok(()) })
     }
 
-    async fn delete_container(&self, view_id: &str) -> FlowyResult<()> {
-        let _ = self.0.delete_grid(view_id)?;
-        Ok(())
+    fn create_container(&self, view_id: &str, repeated_revision: RepeatedRevision) -> FutureResult<(), FlowyError> {
+        let grid_manager = self.0.clone();
+        let view_id = view_id.to_string();
+        FutureResult::new(async move {
+            let _ = grid_manager.create_grid(view_id, repeated_revision).await?;
+            Ok(())
+        })
+    }
+
+    fn delete_container(&self, view_id: &str) -> FutureResult<(), FlowyError> {
+        let grid_manager = self.0.clone();
+        let view_id = view_id.to_string();
+        FutureResult::new(async move {
+            let _ = grid_manager.delete_grid(view_id)?;
+            Ok(())
+        })
     }
 
-    async fn close_container(&self, view_id: &str) -> FlowyResult<()> {
-        let _ = self.0.close_grid(view_id)?;
-        Ok(())
+    fn close_container(&self, view_id: &str) -> FutureResult<(), FlowyError> {
+        let grid_manager = self.0.clone();
+        let view_id = view_id.to_string();
+        FutureResult::new(async move {
+            let _ = grid_manager.close_grid(view_id)?;
+            Ok(())
+        })
+    }
+
+    fn delta_str(&self, view_id: &str) -> FutureResult<String, FlowyError> {
+        let view_id = view_id.to_string();
+        let grid_manager = self.0.clone();
+        FutureResult::new(async move {
+            let editor = grid_manager.open_grid(view_id).await?;
+            let delta_str = editor.delta_str().await;
+            Ok(delta_str)
+        })
     }
 
-    async fn delta_str(&self, view_id: &str) -> FlowyResult<String> {
-        let editor = self.0.open_grid(view_id).await?;
-        let delta_str = editor.delta_str().await;
-        Ok(delta_str)
+    fn default_view_data(&self) -> String {
+        default_grid()
     }
 
     fn data_type(&self) -> ViewDataType {

+ 2 - 3
frontend/rust-lib/flowy-sdk/src/deps_resolve/grid_deps.rs

@@ -17,9 +17,8 @@ pub struct GridDepsResolver();
 impl GridDepsResolver {
     pub fn resolve(ws_conn: Arc<FlowyWebSocketConnect>, user_session: Arc<UserSession>) -> Arc<GridManager> {
         let user = Arc::new(GridUserImpl(user_session));
-        let rev_web_socket = Arc::new(GridWebSocket(ws_conn.clone()));
-        let manager = Arc::new(GridManager::new(user, rev_web_socket));
-        manager
+        let rev_web_socket = Arc::new(GridWebSocket(ws_conn));
+        Arc::new(GridManager::new(user, rev_web_socket))
     }
 }
 

+ 2 - 1
frontend/rust-lib/flowy-sdk/src/module.rs

@@ -17,7 +17,8 @@ pub fn mk_modules(
     let folder_module = mk_folder_module(folder_manager.clone());
     let network_module = mk_network_module(ws_conn.clone());
     let grid_module = mk_grid_module(grid_manager.clone());
-    vec![user_module, folder_module, network_module, grid_module]
+    let block_module = mk_block_module(block_manager.clone());
+    vec![user_module, folder_module, network_module, grid_module, block_module]
 }
 
 fn mk_user_module(user_session: Arc<UserSession>) -> Module {

+ 1 - 1
shared-lib/flowy-collaboration/src/client_folder/folder_pad.rs

@@ -9,7 +9,7 @@ use crate::{
 };
 use flowy_folder_data_model::entities::{app::App, trash::Trash, view::View, workspace::Workspace};
 use lib_ot::core::*;
-use lib_ot::rich_text::RichTextAttributes;
+
 use serde::{Deserialize, Serialize};
 use std::sync::Arc;
 

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

@@ -1,9 +1,9 @@
 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::{CellChangeset, Field, FieldOrder, Grid, RawRow, RepeatedFieldOrder, RowOrder};
+use flowy_grid_data_model::entities::{Field, FieldOrder, Grid, RawRow, RepeatedFieldOrder, RowOrder};
 use lib_infra::uuid;
-use lib_ot::core::{FlowyStr, OperationTransformable, PlainTextAttributes, PlainTextDelta, PlainTextDeltaBuilder};
+use lib_ot::core::{OperationTransformable, PlainTextAttributes, PlainTextDelta, PlainTextDeltaBuilder};
 use std::sync::Arc;
 
 pub type GridDelta = PlainTextDelta;
@@ -54,7 +54,7 @@ impl GridPad {
         })
     }
 
-    pub fn delete_rows(&mut self, row_ids: &Vec<String>) -> CollaborateResult<Option<GridChange>> {
+    pub fn delete_rows(&mut self, row_ids: &[String]) -> CollaborateResult<Option<GridChange>> {
         self.modify_grid(|grid| {
             grid.row_orders.retain(|row_order| !row_ids.contains(&row_order.row_id));
             Ok(Some(()))
@@ -99,7 +99,7 @@ impl GridPad {
         F: FnOnce(&mut Grid) -> CollaborateResult<Option<()>>,
     {
         let cloned_grid = self.grid.clone();
-        match f(&mut Arc::make_mut(&mut self.grid))? {
+        match f(Arc::make_mut(&mut self.grid))? {
             None => Ok(None),
             Some(_) => {
                 let old = json_from_grid(&cloned_grid)?;

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

@@ -53,6 +53,7 @@ fn create_row_order(grid_id: &str, row_id: &str) -> RowOrder {
     }
 }
 
+#[allow(dead_code)]
 fn uuid() -> String {
     uuid::Uuid::new_v4().to_string()
 }