mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
chore: impl handler logic
This commit is contained in:
parent
d0b457c007
commit
8029f1035d
@ -10,7 +10,7 @@ import 'package:flutter/widgets.dart';
|
|||||||
export "./src/sandbox.dart";
|
export "./src/sandbox.dart";
|
||||||
|
|
||||||
enum DefaultPlugin {
|
enum DefaultPlugin {
|
||||||
quillEditor,
|
quill,
|
||||||
blank,
|
blank,
|
||||||
trash,
|
trash,
|
||||||
grid,
|
grid,
|
||||||
@ -19,7 +19,7 @@ enum DefaultPlugin {
|
|||||||
extension FlowyDefaultPluginExt on DefaultPlugin {
|
extension FlowyDefaultPluginExt on DefaultPlugin {
|
||||||
int type() {
|
int type() {
|
||||||
switch (this) {
|
switch (this) {
|
||||||
case DefaultPlugin.quillEditor:
|
case DefaultPlugin.quill:
|
||||||
return 0;
|
return 0;
|
||||||
case DefaultPlugin.blank:
|
case DefaultPlugin.blank:
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -47,7 +47,7 @@ class DocumentPluginBuilder extends PluginBuilder {
|
|||||||
String get menuName => "Doc";
|
String get menuName => "Doc";
|
||||||
|
|
||||||
@override
|
@override
|
||||||
PluginType get pluginType => DefaultPlugin.quillEditor.type();
|
PluginType get pluginType => DefaultPlugin.quill.type();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
ViewDataType get dataType => ViewDataType.RichText;
|
ViewDataType get dataType => ViewDataType.RichText;
|
||||||
|
@ -1,23 +1,6 @@
|
|||||||
|
|
||||||
/// Auto generate. Do not edit
|
/// Auto generate. Do not edit
|
||||||
part of '../../dispatch.dart';
|
part of '../../dispatch.dart';
|
||||||
class GridEventCreateGrid {
|
|
||||||
CreateGridPayload request;
|
|
||||||
GridEventCreateGrid(this.request);
|
|
||||||
|
|
||||||
Future<Either<Grid, FlowyError>> send() {
|
|
||||||
final request = FFIRequest.create()
|
|
||||||
..event = GridEvent.CreateGrid.toString()
|
|
||||||
..payload = requestToBytes(this.request);
|
|
||||||
|
|
||||||
return Dispatch.asyncRequest(request)
|
|
||||||
.then((bytesResult) => bytesResult.fold(
|
|
||||||
(okBytes) => left(Grid.fromBuffer(okBytes)),
|
|
||||||
(errBytes) => right(FlowyError.fromBuffer(errBytes)),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class GridEventOpenGrid {
|
class GridEventOpenGrid {
|
||||||
GridId request;
|
GridId request;
|
||||||
GridEventOpenGrid(this.request);
|
GridEventOpenGrid(this.request);
|
||||||
|
@ -12,10 +12,12 @@ import 'package:protobuf/protobuf.dart' as $pb;
|
|||||||
class ViewDataType extends $pb.ProtobufEnum {
|
class ViewDataType extends $pb.ProtobufEnum {
|
||||||
static const ViewDataType RichText = ViewDataType._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'RichText');
|
static const ViewDataType RichText = ViewDataType._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'RichText');
|
||||||
static const ViewDataType PlainText = ViewDataType._(1, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'PlainText');
|
static const ViewDataType PlainText = ViewDataType._(1, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'PlainText');
|
||||||
|
static const ViewDataType Grid = ViewDataType._(2, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Grid');
|
||||||
|
|
||||||
static const $core.List<ViewDataType> values = <ViewDataType> [
|
static const $core.List<ViewDataType> values = <ViewDataType> [
|
||||||
RichText,
|
RichText,
|
||||||
PlainText,
|
PlainText,
|
||||||
|
Grid,
|
||||||
];
|
];
|
||||||
|
|
||||||
static final $core.Map<$core.int, ViewDataType> _byValue = $pb.ProtobufEnum.initByValue(values);
|
static final $core.Map<$core.int, ViewDataType> _byValue = $pb.ProtobufEnum.initByValue(values);
|
||||||
|
@ -14,11 +14,12 @@ const ViewDataType$json = const {
|
|||||||
'2': const [
|
'2': const [
|
||||||
const {'1': 'RichText', '2': 0},
|
const {'1': 'RichText', '2': 0},
|
||||||
const {'1': 'PlainText', '2': 1},
|
const {'1': 'PlainText', '2': 1},
|
||||||
|
const {'1': 'Grid', '2': 2},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Descriptor for `ViewDataType`. Decode as a `google.protobuf.EnumDescriptorProto`.
|
/// Descriptor for `ViewDataType`. Decode as a `google.protobuf.EnumDescriptorProto`.
|
||||||
final $typed_data.Uint8List viewDataTypeDescriptor = $convert.base64Decode('CgxWaWV3RGF0YVR5cGUSDAoIUmljaFRleHQQABINCglQbGFpblRleHQQAQ==');
|
final $typed_data.Uint8List viewDataTypeDescriptor = $convert.base64Decode('CgxWaWV3RGF0YVR5cGUSDAoIUmljaFRleHQQABINCglQbGFpblRleHQQARIICgRHcmlkEAI=');
|
||||||
@$core.Deprecated('Use viewDescriptor instead')
|
@$core.Deprecated('Use viewDescriptor instead')
|
||||||
const View$json = const {
|
const View$json = const {
|
||||||
'1': 'View',
|
'1': 'View',
|
||||||
|
@ -10,14 +10,12 @@ import 'dart:core' as $core;
|
|||||||
import 'package:protobuf/protobuf.dart' as $pb;
|
import 'package:protobuf/protobuf.dart' as $pb;
|
||||||
|
|
||||||
class GridEvent extends $pb.ProtobufEnum {
|
class GridEvent extends $pb.ProtobufEnum {
|
||||||
static const GridEvent CreateGrid = GridEvent._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'CreateGrid');
|
static const GridEvent OpenGrid = GridEvent._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'OpenGrid');
|
||||||
static const GridEvent OpenGrid = GridEvent._(1, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'OpenGrid');
|
static const GridEvent GetRows = GridEvent._(1, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'GetRows');
|
||||||
static const GridEvent GetRows = GridEvent._(2, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'GetRows');
|
static const GridEvent GetFields = GridEvent._(2, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'GetFields');
|
||||||
static const GridEvent GetFields = GridEvent._(3, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'GetFields');
|
static const GridEvent CreateRow = GridEvent._(3, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'CreateRow');
|
||||||
static const GridEvent CreateRow = GridEvent._(4, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'CreateRow');
|
|
||||||
|
|
||||||
static const $core.List<GridEvent> values = <GridEvent> [
|
static const $core.List<GridEvent> values = <GridEvent> [
|
||||||
CreateGrid,
|
|
||||||
OpenGrid,
|
OpenGrid,
|
||||||
GetRows,
|
GetRows,
|
||||||
GetFields,
|
GetFields,
|
||||||
|
@ -12,13 +12,12 @@ import 'dart:typed_data' as $typed_data;
|
|||||||
const GridEvent$json = const {
|
const GridEvent$json = const {
|
||||||
'1': 'GridEvent',
|
'1': 'GridEvent',
|
||||||
'2': const [
|
'2': const [
|
||||||
const {'1': 'CreateGrid', '2': 0},
|
const {'1': 'OpenGrid', '2': 0},
|
||||||
const {'1': 'OpenGrid', '2': 1},
|
const {'1': 'GetRows', '2': 1},
|
||||||
const {'1': 'GetRows', '2': 2},
|
const {'1': 'GetFields', '2': 2},
|
||||||
const {'1': 'GetFields', '2': 3},
|
const {'1': 'CreateRow', '2': 3},
|
||||||
const {'1': 'CreateRow', '2': 4},
|
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Descriptor for `GridEvent`. Decode as a `google.protobuf.EnumDescriptorProto`.
|
/// Descriptor for `GridEvent`. Decode as a `google.protobuf.EnumDescriptorProto`.
|
||||||
final $typed_data.Uint8List gridEventDescriptor = $convert.base64Decode('CglHcmlkRXZlbnQSDgoKQ3JlYXRlR3JpZBAAEgwKCE9wZW5HcmlkEAESCwoHR2V0Um93cxACEg0KCUdldEZpZWxkcxADEg0KCUNyZWF0ZVJvdxAE');
|
final $typed_data.Uint8List gridEventDescriptor = $convert.base64Decode('CglHcmlkRXZlbnQSDAoIT3BlbkdyaWQQABILCgdHZXRSb3dzEAESDQoJR2V0RmllbGRzEAISDQoJQ3JlYXRlUm93EAM=');
|
||||||
|
1
frontend/rust-lib/Cargo.lock
generated
1
frontend/rust-lib/Cargo.lock
generated
@ -1071,6 +1071,7 @@ dependencies = [
|
|||||||
"rusty-money",
|
"rusty-money",
|
||||||
"strum",
|
"strum",
|
||||||
"strum_macros",
|
"strum_macros",
|
||||||
|
"tokio",
|
||||||
"tracing",
|
"tracing",
|
||||||
"uuid",
|
"uuid",
|
||||||
]
|
]
|
||||||
|
@ -85,7 +85,7 @@ impl BlockManager {
|
|||||||
let doc_id = doc_id.as_ref().to_owned();
|
let doc_id = doc_id.as_ref().to_owned();
|
||||||
let db_pool = self.block_user.db_pool()?;
|
let db_pool = self.block_user.db_pool()?;
|
||||||
// Maybe we could save the block to disk without creating the RevisionManager
|
// Maybe we could save the block to disk without creating the RevisionManager
|
||||||
let rev_manager = self.make_rev_manager(&doc_id, db_pool)?;
|
let rev_manager = self.make_block_rev_manager(&doc_id, db_pool)?;
|
||||||
let _ = rev_manager.reset_object(revisions).await?;
|
let _ = rev_manager.reset_object(revisions).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -125,7 +125,7 @@ impl BlockManager {
|
|||||||
) -> Result<Arc<ClientBlockEditor>, FlowyError> {
|
) -> Result<Arc<ClientBlockEditor>, FlowyError> {
|
||||||
let user = self.block_user.clone();
|
let user = self.block_user.clone();
|
||||||
let token = self.block_user.token()?;
|
let token = self.block_user.token()?;
|
||||||
let rev_manager = self.make_rev_manager(block_id, pool.clone())?;
|
let rev_manager = self.make_block_rev_manager(block_id, pool.clone())?;
|
||||||
let cloud_service = Arc::new(BlockRevisionCloudService {
|
let cloud_service = Arc::new(BlockRevisionCloudService {
|
||||||
token,
|
token,
|
||||||
server: self.cloud_service.clone(),
|
server: self.cloud_service.clone(),
|
||||||
@ -136,7 +136,7 @@ impl BlockManager {
|
|||||||
Ok(doc_editor)
|
Ok(doc_editor)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_rev_manager(&self, doc_id: &str, pool: Arc<ConnectionPool>) -> Result<RevisionManager, FlowyError> {
|
fn make_block_rev_manager(&self, doc_id: &str, pool: Arc<ConnectionPool>) -> Result<RevisionManager, FlowyError> {
|
||||||
let user_id = self.block_user.user_id()?;
|
let user_id = self.block_user.user_id()?;
|
||||||
let rev_persistence = Arc::new(RevisionPersistence::new(&user_id, doc_id, pool));
|
let rev_persistence = Arc::new(RevisionPersistence::new(&user_id, doc_id, pool));
|
||||||
Ok(RevisionManager::new(&user_id, doc_id, rev_persistence))
|
Ok(RevisionManager::new(&user_id, doc_id, rev_persistence))
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use chrono::Utc;
|
use chrono::Utc;
|
||||||
use flowy_collaboration::client_document::default::{initial_delta, initial_read_me};
|
use flowy_collaboration::client_document::default::{initial_quill_delta, initial_quill_delta_string, initial_read_me};
|
||||||
use flowy_folder_data_model::user_default;
|
use flowy_folder_data_model::user_default;
|
||||||
use flowy_sync::RevisionWebSocket;
|
use flowy_sync::RevisionWebSocket;
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
@ -199,13 +199,10 @@ impl DefaultFolderBuilder {
|
|||||||
let view_data = if index == 0 {
|
let view_data = if index == 0 {
|
||||||
initial_read_me().to_delta_json()
|
initial_read_me().to_delta_json()
|
||||||
} else {
|
} else {
|
||||||
initial_delta().to_delta_json()
|
initial_quill_delta_string()
|
||||||
};
|
};
|
||||||
view_controller.set_latest_view(view);
|
view_controller.set_latest_view(view);
|
||||||
let delta_data = Bytes::from(view_data);
|
let _ = view_controller.create_view(&view.id, Bytes::from(view_data)).await?;
|
||||||
let repeated_revision: RepeatedRevision =
|
|
||||||
Revision::initial_revision(user_id, &view.id, delta_data).into();
|
|
||||||
let _ = view_controller.create_view(&view.id, repeated_revision).await?;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let folder = FolderPad::new(vec![workspace.clone()], vec![])?;
|
let folder = FolderPad::new(vec![workspace.clone()], vec![])?;
|
||||||
|
@ -86,6 +86,7 @@ impl ViewTable {
|
|||||||
let data_type = match view.data_type {
|
let data_type = match view.data_type {
|
||||||
ViewDataType::RichText => SqlViewDataType::RichText,
|
ViewDataType::RichText => SqlViewDataType::RichText,
|
||||||
ViewDataType::PlainText => SqlViewDataType::PlainText,
|
ViewDataType::PlainText => SqlViewDataType::PlainText,
|
||||||
|
ViewDataType::Grid => SqlViewDataType::Grid,
|
||||||
};
|
};
|
||||||
|
|
||||||
ViewTable {
|
ViewTable {
|
||||||
@ -108,6 +109,7 @@ impl std::convert::From<ViewTable> for View {
|
|||||||
let data_type = match table.view_type {
|
let data_type = match table.view_type {
|
||||||
SqlViewDataType::RichText => ViewDataType::RichText,
|
SqlViewDataType::RichText => ViewDataType::RichText,
|
||||||
SqlViewDataType::PlainText => ViewDataType::PlainText,
|
SqlViewDataType::PlainText => ViewDataType::PlainText,
|
||||||
|
SqlViewDataType::Grid => ViewDataType::Grid,
|
||||||
};
|
};
|
||||||
|
|
||||||
View {
|
View {
|
||||||
@ -179,6 +181,7 @@ impl ViewChangeset {
|
|||||||
pub enum SqlViewDataType {
|
pub enum SqlViewDataType {
|
||||||
RichText = 0,
|
RichText = 0,
|
||||||
PlainText = 1,
|
PlainText = 1,
|
||||||
|
Grid = 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::default::Default for SqlViewDataType {
|
impl std::default::Default for SqlViewDataType {
|
||||||
@ -192,6 +195,7 @@ impl std::convert::From<i32> for SqlViewDataType {
|
|||||||
match value {
|
match value {
|
||||||
0 => SqlViewDataType::RichText,
|
0 => SqlViewDataType::RichText,
|
||||||
1 => SqlViewDataType::PlainText,
|
1 => SqlViewDataType::PlainText,
|
||||||
|
2 => SqlViewDataType::Grid,
|
||||||
o => {
|
o => {
|
||||||
log::error!("Unsupported view type {}, fallback to ViewType::Docs", o);
|
log::error!("Unsupported view type {}, fallback to ViewType::Docs", o);
|
||||||
SqlViewDataType::PlainText
|
SqlViewDataType::PlainText
|
||||||
|
@ -4,7 +4,7 @@ use flowy_collaboration::entities::{
|
|||||||
revision::{RepeatedRevision, Revision},
|
revision::{RepeatedRevision, Revision},
|
||||||
};
|
};
|
||||||
|
|
||||||
use flowy_collaboration::client_document::default::initial_delta_string;
|
use flowy_collaboration::client_document::default::initial_quill_delta_string;
|
||||||
use futures::{FutureExt, StreamExt};
|
use futures::{FutureExt, StreamExt};
|
||||||
use std::{collections::HashSet, sync::Arc};
|
use std::{collections::HashSet, sync::Arc};
|
||||||
|
|
||||||
@ -63,30 +63,24 @@ impl ViewController {
|
|||||||
#[tracing::instrument(level = "trace", skip(self, params), fields(name = %params.name), err)]
|
#[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> {
|
pub(crate) async fn create_view_from_params(&self, params: CreateViewParams) -> Result<View, FlowyError> {
|
||||||
let view_data = if params.data.is_empty() {
|
let view_data = if params.data.is_empty() {
|
||||||
initial_delta_string()
|
initial_quill_delta_string()
|
||||||
} else {
|
} else {
|
||||||
params.data.clone()
|
params.data.clone()
|
||||||
};
|
};
|
||||||
|
|
||||||
let delta_data = Bytes::from(view_data);
|
let _ = self.create_view(¶ms.view_id, Bytes::from(view_data)).await?;
|
||||||
let user_id = self.user.user_id()?;
|
|
||||||
let repeated_revision: RepeatedRevision =
|
|
||||||
Revision::initial_revision(&user_id, ¶ms.view_id, delta_data).into();
|
|
||||||
let _ = self.create_view(¶ms.view_id, repeated_revision).await?;
|
|
||||||
let view = self.create_view_on_server(params).await?;
|
let view = self.create_view_on_server(params).await?;
|
||||||
let _ = self.create_view_on_local(view.clone()).await?;
|
let _ = self.create_view_on_local(view.clone()).await?;
|
||||||
Ok(view)
|
Ok(view)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(level = "debug", skip(self, view_id, repeated_revision), err)]
|
#[tracing::instrument(level = "debug", skip(self, view_id, delta_data), err)]
|
||||||
pub(crate) async fn create_view(
|
pub(crate) async fn create_view(&self, view_id: &str, delta_data: Bytes) -> Result<(), FlowyError> {
|
||||||
&self,
|
if delta_data.is_empty() {
|
||||||
view_id: &str,
|
|
||||||
repeated_revision: RepeatedRevision,
|
|
||||||
) -> Result<(), FlowyError> {
|
|
||||||
if repeated_revision.is_empty() {
|
|
||||||
return Err(FlowyError::internal().context("The content of the view should not be 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 _ = self.block_manager.create_block(view_id, repeated_revision).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -304,7 +298,7 @@ impl ViewController {
|
|||||||
fn listen_trash_can_event(&self) {
|
fn listen_trash_can_event(&self) {
|
||||||
let mut rx = self.trash_controller.subscribe();
|
let mut rx = self.trash_controller.subscribe();
|
||||||
let persistence = self.persistence.clone();
|
let persistence = self.persistence.clone();
|
||||||
let document_manager = self.block_manager.clone();
|
let block_manager = self.block_manager.clone();
|
||||||
let trash_controller = self.trash_controller.clone();
|
let trash_controller = self.trash_controller.clone();
|
||||||
let _ = tokio::spawn(async move {
|
let _ = tokio::spawn(async move {
|
||||||
loop {
|
loop {
|
||||||
@ -318,7 +312,7 @@ impl ViewController {
|
|||||||
if let Some(event) = stream.next().await {
|
if let Some(event) = stream.next().await {
|
||||||
handle_trash_event(
|
handle_trash_event(
|
||||||
persistence.clone(),
|
persistence.clone(),
|
||||||
document_manager.clone(),
|
block_manager.clone(),
|
||||||
trash_controller.clone(),
|
trash_controller.clone(),
|
||||||
event,
|
event,
|
||||||
)
|
)
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use crate::script::{invalid_workspace_name_test_case, FolderScript::*, FolderTest};
|
use crate::script::{invalid_workspace_name_test_case, FolderScript::*, FolderTest};
|
||||||
use flowy_collaboration::{client_document::default::initial_delta_string, entities::revision::RevisionState};
|
use flowy_collaboration::{client_document::default::initial_quill_delta_string, entities::revision::RevisionState};
|
||||||
use flowy_folder::entities::workspace::CreateWorkspacePayload;
|
use flowy_folder::entities::workspace::CreateWorkspacePayload;
|
||||||
use flowy_test::{event_builder::*, FlowySDKTest};
|
use flowy_test::{event_builder::*, FlowySDKTest};
|
||||||
|
|
||||||
@ -175,7 +175,7 @@ async fn open_document_view() {
|
|||||||
|
|
||||||
test.run_scripts(vec![OpenDocument]).await;
|
test.run_scripts(vec![OpenDocument]).await;
|
||||||
let document_info = test.document_info.unwrap();
|
let document_info = test.document_info.unwrap();
|
||||||
assert_eq!(document_info.text, initial_delta_string());
|
assert_eq!(document_info.text, initial_quill_delta_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
@ -30,7 +30,7 @@ uuid = { version = "0.8", features = ["serde", "v4"] }
|
|||||||
bytes = { version = "1.0" }
|
bytes = { version = "1.0" }
|
||||||
diesel = {version = "1.4.8", features = ["sqlite"]}
|
diesel = {version = "1.4.8", features = ["sqlite"]}
|
||||||
dashmap = "4.0"
|
dashmap = "4.0"
|
||||||
|
tokio = {version = "1", features = ["sync"]}
|
||||||
|
|
||||||
parking_lot = "0.11"
|
parking_lot = "0.11"
|
||||||
|
|
||||||
|
@ -3,53 +3,47 @@ use flowy_error::FlowyError;
|
|||||||
use flowy_grid_data_model::entities::{
|
use flowy_grid_data_model::entities::{
|
||||||
CreateGridPayload, Grid, GridId, RepeatedField, RepeatedFieldOrder, RepeatedRow, RepeatedRowOrder,
|
CreateGridPayload, Grid, GridId, RepeatedField, RepeatedFieldOrder, RepeatedRow, RepeatedRowOrder,
|
||||||
};
|
};
|
||||||
use lib_dispatch::prelude::{AppData, Data, DataResult};
|
use lib_dispatch::prelude::{data_result, AppData, Data, DataResult};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
#[tracing::instrument(skip(data, controller), err)]
|
#[tracing::instrument(skip(data, manager), err)]
|
||||||
pub(crate) async fn create_grid_handler(
|
|
||||||
data: Data<CreateGridPayload>,
|
|
||||||
controller: AppData<Arc<GridManager>>,
|
|
||||||
) -> DataResult<Grid, FlowyError> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tracing::instrument(skip(data, controller), err)]
|
|
||||||
pub(crate) async fn open_grid_handler(
|
pub(crate) async fn open_grid_handler(
|
||||||
data: Data<GridId>,
|
data: Data<GridId>,
|
||||||
controller: AppData<Arc<GridManager>>,
|
manager: AppData<Arc<GridManager>>,
|
||||||
) -> DataResult<Grid, FlowyError> {
|
) -> DataResult<Grid, FlowyError> {
|
||||||
let _params: GridId = data.into_inner();
|
let grid_id: GridId = data.into_inner();
|
||||||
|
let editor = manager.open_grid(grid_id).await?;
|
||||||
todo!()
|
let grid = editor.grid_data().await;
|
||||||
|
data_result(grid)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip(data, controller), err)]
|
#[tracing::instrument(skip(data, manager), err)]
|
||||||
pub(crate) async fn get_rows_handler(
|
pub(crate) async fn get_rows_handler(
|
||||||
data: Data<RepeatedRowOrder>,
|
data: Data<RepeatedRowOrder>,
|
||||||
controller: AppData<Arc<GridManager>>,
|
manager: AppData<Arc<GridManager>>,
|
||||||
) -> DataResult<RepeatedRow, FlowyError> {
|
) -> DataResult<RepeatedRow, FlowyError> {
|
||||||
let row_orders: RepeatedRowOrder = data.into_inner();
|
let row_orders: RepeatedRowOrder = data.into_inner();
|
||||||
|
let repeated_row = manager.get_rows(row_orders).await;
|
||||||
todo!()
|
data_result(repeated_row)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip(data, controller), err)]
|
#[tracing::instrument(skip(data, manager), err)]
|
||||||
pub(crate) async fn get_fields_handler(
|
pub(crate) async fn get_fields_handler(
|
||||||
data: Data<RepeatedFieldOrder>,
|
data: Data<RepeatedFieldOrder>,
|
||||||
controller: AppData<Arc<GridManager>>,
|
manager: AppData<Arc<GridManager>>,
|
||||||
) -> DataResult<RepeatedField, FlowyError> {
|
) -> DataResult<RepeatedField, FlowyError> {
|
||||||
let field_orders: RepeatedFieldOrder = data.into_inner();
|
let field_orders: RepeatedFieldOrder = data.into_inner();
|
||||||
|
let repeated_field = manager.get_fields(field_orders).await;
|
||||||
todo!()
|
data_result(repeated_field)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip(data, controller), err)]
|
#[tracing::instrument(skip(data, manager), err)]
|
||||||
pub(crate) async fn create_row_handler(
|
pub(crate) async fn create_row_handler(
|
||||||
data: Data<GridId>,
|
data: Data<GridId>,
|
||||||
controller: AppData<Arc<GridManager>>,
|
manager: AppData<Arc<GridManager>>,
|
||||||
) -> Result<(), FlowyError> {
|
) -> Result<(), FlowyError> {
|
||||||
let id: GridId = data.into_inner();
|
let id: GridId = data.into_inner();
|
||||||
|
let editor = manager.get_grid_editor(id.as_ref())?;
|
||||||
|
let _ = editor.create_empty_row().await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,6 @@ use strum_macros::Display;
|
|||||||
pub fn create(grid_manager: Arc<GridManager>) -> Module {
|
pub fn create(grid_manager: Arc<GridManager>) -> Module {
|
||||||
let mut module = Module::new().name(env!("CARGO_PKG_NAME")).data(grid_manager);
|
let mut module = Module::new().name(env!("CARGO_PKG_NAME")).data(grid_manager);
|
||||||
module = module
|
module = module
|
||||||
.event(GridEvent::CreateGrid, create_grid_handler)
|
|
||||||
.event(GridEvent::OpenGrid, open_grid_handler)
|
.event(GridEvent::OpenGrid, open_grid_handler)
|
||||||
.event(GridEvent::GetRows, get_rows_handler)
|
.event(GridEvent::GetRows, get_rows_handler)
|
||||||
.event(GridEvent::GetFields, get_fields_handler)
|
.event(GridEvent::GetFields, get_fields_handler)
|
||||||
@ -20,18 +19,15 @@ pub fn create(grid_manager: Arc<GridManager>) -> Module {
|
|||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Display, Hash, ProtoBuf_Enum, Flowy_Event)]
|
#[derive(Clone, Copy, PartialEq, Eq, Debug, Display, Hash, ProtoBuf_Enum, Flowy_Event)]
|
||||||
#[event_err = "FlowyError"]
|
#[event_err = "FlowyError"]
|
||||||
pub enum GridEvent {
|
pub enum GridEvent {
|
||||||
#[event(input = "CreateGridPayload", output = "Grid")]
|
|
||||||
CreateGrid = 0,
|
|
||||||
|
|
||||||
#[event(input = "GridId", output = "Grid")]
|
#[event(input = "GridId", output = "Grid")]
|
||||||
OpenGrid = 1,
|
OpenGrid = 0,
|
||||||
|
|
||||||
#[event(input = "RepeatedRowOrder", output = "RepeatedRow")]
|
#[event(input = "RepeatedRowOrder", output = "RepeatedRow")]
|
||||||
GetRows = 2,
|
GetRows = 1,
|
||||||
|
|
||||||
#[event(input = "RepeatedFieldOrder", output = "RepeatedField")]
|
#[event(input = "RepeatedFieldOrder", output = "RepeatedField")]
|
||||||
GetFields = 3,
|
GetFields = 2,
|
||||||
|
|
||||||
#[event(input = "GridId")]
|
#[event(input = "GridId")]
|
||||||
CreateRow = 4,
|
CreateRow = 3,
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,15 @@
|
|||||||
use crate::services::grid_editor::ClientGridEditor;
|
use crate::services::grid_editor::ClientGridEditor;
|
||||||
|
use crate::services::kv_persistence::GridKVPersistence;
|
||||||
use dashmap::DashMap;
|
use dashmap::DashMap;
|
||||||
|
use flowy_collaboration::client_grid::{make_grid_delta, make_grid_revisions};
|
||||||
|
use flowy_collaboration::entities::revision::RepeatedRevision;
|
||||||
use flowy_error::{FlowyError, FlowyResult};
|
use flowy_error::{FlowyError, FlowyResult};
|
||||||
|
use flowy_grid_data_model::entities::{
|
||||||
|
Field, FieldOrder, Grid, RawRow, RepeatedField, RepeatedFieldOrder, RepeatedRow, RepeatedRowOrder, RowOrder,
|
||||||
|
};
|
||||||
use flowy_sync::{RevisionManager, RevisionPersistence, RevisionWebSocket};
|
use flowy_sync::{RevisionManager, RevisionPersistence, RevisionWebSocket};
|
||||||
use lib_sqlite::ConnectionPool;
|
use lib_sqlite::ConnectionPool;
|
||||||
|
use parking_lot::RwLock;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
pub trait GridUser: Send + Sync {
|
pub trait GridUser: Send + Sync {
|
||||||
@ -15,27 +22,63 @@ pub struct GridManager {
|
|||||||
grid_editors: Arc<GridEditors>,
|
grid_editors: Arc<GridEditors>,
|
||||||
grid_user: Arc<dyn GridUser>,
|
grid_user: Arc<dyn GridUser>,
|
||||||
rev_web_socket: Arc<dyn RevisionWebSocket>,
|
rev_web_socket: Arc<dyn RevisionWebSocket>,
|
||||||
|
kv_persistence: Arc<RwLock<Option<Arc<GridKVPersistence>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GridManager {
|
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());
|
let grid_editors = Arc::new(GridEditors::new());
|
||||||
|
|
||||||
|
// kv_persistence will be initialized after first access.
|
||||||
|
// See get_kv_persistence function below
|
||||||
|
let kv_persistence = Arc::new(RwLock::new(None));
|
||||||
Self {
|
Self {
|
||||||
grid_editors,
|
grid_editors,
|
||||||
grid_user,
|
grid_user,
|
||||||
rev_web_socket,
|
rev_web_socket,
|
||||||
|
kv_persistence,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(level = "debug", skip(self, grid_id), fields(grid_id), err)]
|
#[tracing::instrument(level = "debug", skip_all, err)]
|
||||||
pub async fn open_grid<T: AsRef<str>>(&self, grid_id: T) -> Result<Arc<ClientGridEditor>, FlowyError> {
|
pub async fn create_grid<T: AsRef<str>>(
|
||||||
|
&self,
|
||||||
|
grid_id: T,
|
||||||
|
fields: Option<Vec<Field>>,
|
||||||
|
rows: Option<Vec<RawRow>>,
|
||||||
|
) -> FlowyResult<()> {
|
||||||
let grid_id = grid_id.as_ref();
|
let grid_id = grid_id.as_ref();
|
||||||
tracing::Span::current().record("grid_id", &grid_id);
|
let user_id = self.grid_user.user_id()?;
|
||||||
self.get_grid_editor(grid_id).await
|
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<_>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
let grid = Grid {
|
||||||
|
id: grid_id.to_owned(),
|
||||||
|
field_orders: field_orders.into(),
|
||||||
|
row_orders: row_orders.into(),
|
||||||
|
};
|
||||||
|
let revisions = make_grid_revisions(&user_id, &grid);
|
||||||
|
let db_pool = self.grid_user.db_pool()?;
|
||||||
|
let rev_manager = self.make_grid_rev_manager(grid_id, db_pool)?;
|
||||||
|
let _ = rev_manager.reset_object(revisions).await?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(level = "trace", skip(self, grid_id), fields(grid_id), err)]
|
#[tracing::instrument(level = "debug", skip_all, fields(grid_id), err)]
|
||||||
pub fn close_grid<T: AsRef<str>>(&self, grid_id: T) -> Result<(), FlowyError> {
|
pub async fn open_grid<T: AsRef<str>>(&self, grid_id: T) -> FlowyResult<Arc<ClientGridEditor>> {
|
||||||
|
let grid_id = grid_id.as_ref();
|
||||||
|
tracing::Span::current().record("grid_id", &grid_id);
|
||||||
|
self.get_or_create_grid_editor(grid_id).await
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(level = "trace", skip_all, fields(grid_id), err)]
|
||||||
|
pub fn close_grid<T: AsRef<str>>(&self, grid_id: T) -> FlowyResult<()> {
|
||||||
let grid_id = grid_id.as_ref();
|
let grid_id = grid_id.as_ref();
|
||||||
tracing::Span::current().record("grid_id", &grid_id);
|
tracing::Span::current().record("grid_id", &grid_id);
|
||||||
self.grid_editors.remove(grid_id);
|
self.grid_editors.remove(grid_id);
|
||||||
@ -43,14 +86,29 @@ impl GridManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(level = "debug", skip(self, grid_id), fields(doc_id), err)]
|
#[tracing::instrument(level = "debug", skip(self, grid_id), fields(doc_id), err)]
|
||||||
pub fn delete_grid<T: AsRef<str>>(&self, grid_id: T) -> Result<(), FlowyError> {
|
pub fn delete_grid<T: AsRef<str>>(&self, grid_id: T) -> FlowyResult<()> {
|
||||||
let grid_id = grid_id.as_ref();
|
let grid_id = grid_id.as_ref();
|
||||||
tracing::Span::current().record("grid_id", &grid_id);
|
tracing::Span::current().record("grid_id", &grid_id);
|
||||||
self.grid_editors.remove(grid_id);
|
self.grid_editors.remove(grid_id);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_grid_editor(&self, grid_id: &str) -> FlowyResult<Arc<ClientGridEditor>> {
|
pub async fn get_rows(&self, row_orders: RepeatedRowOrder) -> RepeatedRow {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_fields(&self, field_orders: RepeatedFieldOrder) -> RepeatedField {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_grid_editor(&self, grid_id: &str) -> FlowyResult<Arc<ClientGridEditor>> {
|
||||||
|
match self.grid_editors.get(grid_id) {
|
||||||
|
None => Err(FlowyError::internal().context("Should call open_grid function first")),
|
||||||
|
Some(editor) => Ok(editor),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_or_create_grid_editor(&self, grid_id: &str) -> FlowyResult<Arc<ClientGridEditor>> {
|
||||||
match self.grid_editors.get(grid_id) {
|
match self.grid_editors.get(grid_id) {
|
||||||
None => {
|
None => {
|
||||||
let db_pool = self.grid_user.db_pool()?;
|
let db_pool = self.grid_user.db_pool()?;
|
||||||
@ -65,12 +123,33 @@ impl GridManager {
|
|||||||
grid_id: &str,
|
grid_id: &str,
|
||||||
pool: Arc<ConnectionPool>,
|
pool: Arc<ConnectionPool>,
|
||||||
) -> Result<Arc<ClientGridEditor>, FlowyError> {
|
) -> Result<Arc<ClientGridEditor>, FlowyError> {
|
||||||
let token = self.grid_user.token()?;
|
let user = self.grid_user.clone();
|
||||||
let user_id = self.grid_user.user_id()?;
|
let rev_manager = self.make_grid_rev_manager(grid_id, pool.clone())?;
|
||||||
let grid_editor = ClientGridEditor::new(&user_id, grid_id, &token, pool, self.rev_web_socket.clone()).await?;
|
let kv_persistence = self.get_kv_persistence()?;
|
||||||
|
let grid_editor = ClientGridEditor::new(grid_id, user, rev_manager, kv_persistence).await?;
|
||||||
self.grid_editors.insert(grid_id, &grid_editor);
|
self.grid_editors.insert(grid_id, &grid_editor);
|
||||||
Ok(grid_editor)
|
Ok(grid_editor)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn make_grid_rev_manager(&self, grid_id: &str, pool: Arc<ConnectionPool>) -> FlowyResult<RevisionManager> {
|
||||||
|
let user_id = self.grid_user.user_id()?;
|
||||||
|
let rev_persistence = Arc::new(RevisionPersistence::new(&user_id, grid_id, pool));
|
||||||
|
let rev_manager = RevisionManager::new(&user_id, grid_id, 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() {
|
||||||
|
return Ok(read_guard.clone().unwrap());
|
||||||
|
}
|
||||||
|
drop(read_guard);
|
||||||
|
|
||||||
|
let pool = self.grid_user.db_pool()?;
|
||||||
|
let kv_persistence = Arc::new(GridKVPersistence::new(pool));
|
||||||
|
*self.kv_persistence.write() = Some(kv_persistence.clone());
|
||||||
|
Ok(kv_persistence)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct GridEditors {
|
pub struct GridEditors {
|
||||||
|
@ -25,11 +25,10 @@
|
|||||||
|
|
||||||
#[derive(Clone,PartialEq,Eq,Debug,Hash)]
|
#[derive(Clone,PartialEq,Eq,Debug,Hash)]
|
||||||
pub enum GridEvent {
|
pub enum GridEvent {
|
||||||
CreateGrid = 0,
|
OpenGrid = 0,
|
||||||
OpenGrid = 1,
|
GetRows = 1,
|
||||||
GetRows = 2,
|
GetFields = 2,
|
||||||
GetFields = 3,
|
CreateRow = 3,
|
||||||
CreateRow = 4,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ::protobuf::ProtobufEnum for GridEvent {
|
impl ::protobuf::ProtobufEnum for GridEvent {
|
||||||
@ -39,18 +38,16 @@ impl ::protobuf::ProtobufEnum for GridEvent {
|
|||||||
|
|
||||||
fn from_i32(value: i32) -> ::std::option::Option<GridEvent> {
|
fn from_i32(value: i32) -> ::std::option::Option<GridEvent> {
|
||||||
match value {
|
match value {
|
||||||
0 => ::std::option::Option::Some(GridEvent::CreateGrid),
|
0 => ::std::option::Option::Some(GridEvent::OpenGrid),
|
||||||
1 => ::std::option::Option::Some(GridEvent::OpenGrid),
|
1 => ::std::option::Option::Some(GridEvent::GetRows),
|
||||||
2 => ::std::option::Option::Some(GridEvent::GetRows),
|
2 => ::std::option::Option::Some(GridEvent::GetFields),
|
||||||
3 => ::std::option::Option::Some(GridEvent::GetFields),
|
3 => ::std::option::Option::Some(GridEvent::CreateRow),
|
||||||
4 => ::std::option::Option::Some(GridEvent::CreateRow),
|
|
||||||
_ => ::std::option::Option::None
|
_ => ::std::option::Option::None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn values() -> &'static [Self] {
|
fn values() -> &'static [Self] {
|
||||||
static values: &'static [GridEvent] = &[
|
static values: &'static [GridEvent] = &[
|
||||||
GridEvent::CreateGrid,
|
|
||||||
GridEvent::OpenGrid,
|
GridEvent::OpenGrid,
|
||||||
GridEvent::GetRows,
|
GridEvent::GetRows,
|
||||||
GridEvent::GetFields,
|
GridEvent::GetFields,
|
||||||
@ -72,7 +69,7 @@ impl ::std::marker::Copy for GridEvent {
|
|||||||
|
|
||||||
impl ::std::default::Default for GridEvent {
|
impl ::std::default::Default for GridEvent {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
GridEvent::CreateGrid
|
GridEvent::OpenGrid
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,9 +80,9 @@ impl ::protobuf::reflect::ProtobufValue for GridEvent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static file_descriptor_proto_data: &'static [u8] = b"\
|
static file_descriptor_proto_data: &'static [u8] = b"\
|
||||||
\n\x0fevent_map.proto*T\n\tGridEvent\x12\x0e\n\nCreateGrid\x10\0\x12\x0c\
|
\n\x0fevent_map.proto*D\n\tGridEvent\x12\x0c\n\x08OpenGrid\x10\0\x12\x0b\
|
||||||
\n\x08OpenGrid\x10\x01\x12\x0b\n\x07GetRows\x10\x02\x12\r\n\tGetFields\
|
\n\x07GetRows\x10\x01\x12\r\n\tGetFields\x10\x02\x12\r\n\tCreateRow\x10\
|
||||||
\x10\x03\x12\r\n\tCreateRow\x10\x04b\x06proto3\
|
\x03b\x06proto3\
|
||||||
";
|
";
|
||||||
|
|
||||||
static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;
|
static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
syntax = "proto3";
|
syntax = "proto3";
|
||||||
|
|
||||||
enum GridEvent {
|
enum GridEvent {
|
||||||
CreateGrid = 0;
|
OpenGrid = 0;
|
||||||
OpenGrid = 1;
|
GetRows = 1;
|
||||||
GetRows = 2;
|
GetFields = 2;
|
||||||
GetFields = 3;
|
CreateRow = 3;
|
||||||
CreateRow = 4;
|
|
||||||
}
|
}
|
||||||
|
@ -1,60 +1,64 @@
|
|||||||
|
use crate::manager::GridUser;
|
||||||
use crate::services::kv_persistence::{GridKVPersistence, KVTransaction};
|
use crate::services::kv_persistence::{GridKVPersistence, KVTransaction};
|
||||||
use flowy_collaboration::client_grid::{GridChange, GridPad};
|
use flowy_collaboration::client_grid::{GridChange, GridPad};
|
||||||
use flowy_collaboration::entities::revision::Revision;
|
use flowy_collaboration::entities::revision::Revision;
|
||||||
use flowy_collaboration::util::make_delta_from_revisions;
|
use flowy_collaboration::util::make_delta_from_revisions;
|
||||||
use flowy_error::{FlowyError, FlowyResult};
|
use flowy_error::{FlowyError, FlowyResult};
|
||||||
use flowy_grid_data_model::entities::{Field, GridId, RawRow};
|
use flowy_grid_data_model::entities::{Field, Grid, GridId, RawRow};
|
||||||
use flowy_sync::{
|
use flowy_sync::{
|
||||||
RevisionCloudService, RevisionCompact, RevisionManager, RevisionObjectBuilder, RevisionPersistence,
|
RevisionCloudService, RevisionCompact, RevisionManager, RevisionObjectBuilder, RevisionPersistence,
|
||||||
RevisionWebSocket, RevisionWebSocketManager,
|
RevisionWebSocket, RevisionWebSocketManager,
|
||||||
};
|
};
|
||||||
use lib_infra::future::FutureResult;
|
use lib_infra::future::FutureResult;
|
||||||
|
use lib_infra::uuid;
|
||||||
use lib_ot::core::PlainTextAttributes;
|
use lib_ot::core::PlainTextAttributes;
|
||||||
use lib_sqlite::ConnectionPool;
|
use lib_sqlite::ConnectionPool;
|
||||||
use parking_lot::RwLock;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use tokio::sync::RwLock;
|
||||||
|
|
||||||
pub struct ClientGridEditor {
|
pub struct ClientGridEditor {
|
||||||
user_id: String,
|
|
||||||
grid_id: String,
|
grid_id: String,
|
||||||
grid: Arc<RwLock<GridPad>>,
|
user: Arc<dyn GridUser>,
|
||||||
|
grid_pad: Arc<RwLock<GridPad>>,
|
||||||
rev_manager: Arc<RevisionManager>,
|
rev_manager: Arc<RevisionManager>,
|
||||||
kv: Arc<GridKVPersistence>,
|
kv_persistence: Arc<GridKVPersistence>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ClientGridEditor {
|
impl ClientGridEditor {
|
||||||
pub async fn new(
|
pub async fn new(
|
||||||
user_id: &str,
|
|
||||||
grid_id: &str,
|
grid_id: &str,
|
||||||
token: &str,
|
user: Arc<dyn GridUser>,
|
||||||
pool: Arc<ConnectionPool>,
|
mut rev_manager: RevisionManager,
|
||||||
_web_socket: Arc<dyn RevisionWebSocket>,
|
kv_persistence: Arc<GridKVPersistence>,
|
||||||
) -> FlowyResult<Arc<Self>> {
|
) -> FlowyResult<Arc<Self>> {
|
||||||
let rev_persistence = Arc::new(RevisionPersistence::new(user_id, grid_id, pool.clone()));
|
let token = user.token()?;
|
||||||
let mut rev_manager = RevisionManager::new(user_id, grid_id, rev_persistence);
|
let cloud = Arc::new(GridRevisionCloudService { token });
|
||||||
let cloud = Arc::new(GridRevisionCloudService {
|
let grid_pad = Arc::new(RwLock::new(
|
||||||
token: token.to_string(),
|
|
||||||
});
|
|
||||||
let grid = Arc::new(RwLock::new(
|
|
||||||
rev_manager.load::<GridPadBuilder, GridRevisionCompact>(cloud).await?,
|
rev_manager.load::<GridPadBuilder, GridRevisionCompact>(cloud).await?,
|
||||||
));
|
));
|
||||||
let rev_manager = Arc::new(rev_manager);
|
let rev_manager = Arc::new(rev_manager);
|
||||||
let kv = Arc::new(GridKVPersistence::new(pool));
|
|
||||||
|
|
||||||
let user_id = user_id.to_owned();
|
|
||||||
let grid_id = grid_id.to_owned();
|
|
||||||
Ok(Arc::new(Self {
|
Ok(Arc::new(Self {
|
||||||
user_id,
|
grid_id: grid_id.to_owned(),
|
||||||
grid_id,
|
user,
|
||||||
grid,
|
grid_pad,
|
||||||
rev_manager,
|
rev_manager,
|
||||||
kv,
|
kv_persistence,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn create_row(&self, row: RawRow) -> FlowyResult<()> {
|
pub async fn create_empty_row(&self) -> FlowyResult<()> {
|
||||||
|
let row = RawRow {
|
||||||
|
id: uuid(),
|
||||||
|
grid_id: self.grid_id.clone(),
|
||||||
|
cell_by_field_id: Default::default(),
|
||||||
|
};
|
||||||
|
self.create_row(row).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn create_row(&self, row: RawRow) -> FlowyResult<()> {
|
||||||
let _ = self.modify(|grid| Ok(grid.create_row(&row)?)).await?;
|
let _ = self.modify(|grid| Ok(grid.create_row(&row)?)).await?;
|
||||||
let _ = self.kv.set(row)?;
|
let _ = self.kv_persistence.set(row)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,7 +70,7 @@ impl ClientGridEditor {
|
|||||||
|
|
||||||
pub async fn create_field(&mut self, field: Field) -> FlowyResult<()> {
|
pub async fn create_field(&mut self, field: Field) -> FlowyResult<()> {
|
||||||
let _ = self.modify(|grid| Ok(grid.create_field(&field)?)).await?;
|
let _ = self.modify(|grid| Ok(grid.create_field(&field)?)).await?;
|
||||||
let _ = self.kv.set(field)?;
|
let _ = self.kv_persistence.set(field)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,11 +80,15 @@ impl ClientGridEditor {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn grid_data(&self) -> Grid {
|
||||||
|
self.grid_pad.read().await.grid_data()
|
||||||
|
}
|
||||||
|
|
||||||
async fn modify<F>(&self, f: F) -> FlowyResult<()>
|
async fn modify<F>(&self, f: F) -> FlowyResult<()>
|
||||||
where
|
where
|
||||||
F: FnOnce(&mut GridPad) -> FlowyResult<Option<GridChange>>,
|
F: for<'a> FnOnce(&'a mut GridPad) -> FlowyResult<Option<GridChange>>,
|
||||||
{
|
{
|
||||||
let mut write_guard = self.grid.write();
|
let mut write_guard = self.grid_pad.write().await;
|
||||||
match f(&mut *write_guard)? {
|
match f(&mut *write_guard)? {
|
||||||
None => {}
|
None => {}
|
||||||
Some(change) => {
|
Some(change) => {
|
||||||
@ -92,6 +100,7 @@ impl ClientGridEditor {
|
|||||||
|
|
||||||
async fn apply_change(&self, change: GridChange) -> FlowyResult<()> {
|
async fn apply_change(&self, change: GridChange) -> FlowyResult<()> {
|
||||||
let GridChange { delta, md5 } = change;
|
let GridChange { delta, md5 } = change;
|
||||||
|
let user_id = self.user.user_id()?;
|
||||||
let (base_rev_id, rev_id) = self.rev_manager.next_rev_id_pair();
|
let (base_rev_id, rev_id) = self.rev_manager.next_rev_id_pair();
|
||||||
let delta_data = delta.to_bytes();
|
let delta_data = delta.to_bytes();
|
||||||
let revision = Revision::new(
|
let revision = Revision::new(
|
||||||
@ -99,7 +108,7 @@ impl ClientGridEditor {
|
|||||||
base_rev_id,
|
base_rev_id,
|
||||||
rev_id,
|
rev_id,
|
||||||
delta_data,
|
delta_data,
|
||||||
&self.user_id,
|
&user_id,
|
||||||
md5,
|
md5,
|
||||||
);
|
);
|
||||||
let _ = self
|
let _ = self
|
||||||
@ -114,8 +123,8 @@ struct GridPadBuilder();
|
|||||||
impl RevisionObjectBuilder for GridPadBuilder {
|
impl RevisionObjectBuilder for GridPadBuilder {
|
||||||
type Output = GridPad;
|
type Output = GridPad;
|
||||||
|
|
||||||
fn build_object(_object_id: &str, revisions: Vec<Revision>) -> FlowyResult<Self::Output> {
|
fn build_object(object_id: &str, revisions: Vec<Revision>) -> FlowyResult<Self::Output> {
|
||||||
let pad = GridPad::from_revisions(revisions)?;
|
let pad = GridPad::from_revisions(object_id, revisions)?;
|
||||||
Ok(pad)
|
Ok(pad)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,6 @@ mod util;
|
|||||||
|
|
||||||
pub mod cell_data;
|
pub mod cell_data;
|
||||||
pub mod grid_editor;
|
pub mod grid_editor;
|
||||||
mod kv_persistence;
|
pub mod kv_persistence;
|
||||||
|
|
||||||
pub use stringify::*;
|
pub use stringify::*;
|
||||||
|
@ -2,7 +2,7 @@ use crate::local_server::persistence::LocalDocumentCloudPersistence;
|
|||||||
use async_stream::stream;
|
use async_stream::stream;
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use flowy_collaboration::{
|
use flowy_collaboration::{
|
||||||
client_document::default::initial_delta_string,
|
client_document::default::initial_quill_delta_string,
|
||||||
entities::{
|
entities::{
|
||||||
document_info::{BlockId, BlockInfo, CreateBlockParams, ResetBlockParams},
|
document_info::{BlockId, BlockInfo, CreateBlockParams, ResetBlockParams},
|
||||||
ws_data::{ClientRevisionWSData, ClientRevisionWSDataType},
|
ws_data::{ClientRevisionWSData, ClientRevisionWSDataType},
|
||||||
@ -420,7 +420,7 @@ impl BlockCloudService for LocalServer {
|
|||||||
fn read_block(&self, _token: &str, params: BlockId) -> FutureResult<Option<BlockInfo>, FlowyError> {
|
fn read_block(&self, _token: &str, params: BlockId) -> FutureResult<Option<BlockInfo>, FlowyError> {
|
||||||
let doc = BlockInfo {
|
let doc = BlockInfo {
|
||||||
block_id: params.value,
|
block_id: params.value,
|
||||||
text: initial_delta_string(),
|
text: initial_quill_delta_string(),
|
||||||
rev_id: 0,
|
rev_id: 0,
|
||||||
base_rev_id: 0,
|
base_rev_id: 0,
|
||||||
};
|
};
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
use lib_ot::{core::DeltaBuilder, rich_text::RichTextDelta};
|
use lib_ot::{core::DeltaBuilder, rich_text::RichTextDelta};
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn initial_delta() -> RichTextDelta {
|
pub fn initial_quill_delta() -> RichTextDelta {
|
||||||
DeltaBuilder::new().insert("\n").build()
|
DeltaBuilder::new().insert("\n").build()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn initial_delta_string() -> String {
|
pub fn initial_quill_delta_string() -> String {
|
||||||
initial_delta().to_delta_json()
|
initial_quill_delta().to_delta_json()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
client_document::{
|
client_document::{
|
||||||
default::initial_delta,
|
default::initial_quill_delta,
|
||||||
history::{History, UndoResult},
|
history::{History, UndoResult},
|
||||||
view::{ViewExtensions, RECORD_THRESHOLD},
|
view::{ViewExtensions, RECORD_THRESHOLD},
|
||||||
},
|
},
|
||||||
@ -26,7 +26,7 @@ impl InitialDocumentText for PlainDoc {
|
|||||||
pub struct NewlineDoc();
|
pub struct NewlineDoc();
|
||||||
impl InitialDocumentText for NewlineDoc {
|
impl InitialDocumentText for NewlineDoc {
|
||||||
fn initial_delta() -> RichTextDelta {
|
fn initial_delta() -> RichTextDelta {
|
||||||
initial_delta()
|
initial_quill_delta()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use crate::entities::revision::{md5, Revision};
|
use crate::entities::revision::{md5, RepeatedRevision, Revision};
|
||||||
use crate::errors::{internal_error, CollaborateError, CollaborateResult};
|
use crate::errors::{internal_error, CollaborateError, CollaborateResult};
|
||||||
use crate::util::{cal_diff, make_delta_from_revisions};
|
use crate::util::{cal_diff, make_delta_from_revisions};
|
||||||
use flowy_grid_data_model::entities::{CellChangeset, Field, FieldOrder, Grid, RawRow, RowOrder};
|
use flowy_grid_data_model::entities::{CellChangeset, Field, FieldOrder, Grid, RawRow, RowOrder};
|
||||||
@ -26,7 +26,7 @@ impl GridPad {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_revisions(revisions: Vec<Revision>) -> CollaborateResult<Self> {
|
pub fn from_revisions(_grid_id: &str, revisions: Vec<Revision>) -> CollaborateResult<Self> {
|
||||||
let folder_delta: GridDelta = make_delta_from_revisions::<PlainTextAttributes>(revisions)?;
|
let folder_delta: GridDelta = make_delta_from_revisions::<PlainTextAttributes>(revisions)?;
|
||||||
Self::from_delta(folder_delta)
|
Self::from_delta(folder_delta)
|
||||||
}
|
}
|
||||||
@ -81,6 +81,11 @@ impl GridPad {
|
|||||||
md5(&self.delta.to_bytes())
|
md5(&self.delta.to_bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn grid_data(&self) -> Grid {
|
||||||
|
let grid_ref: &Grid = &self.grid;
|
||||||
|
grid_ref.clone()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn modify_grid<F>(&mut self, f: F) -> CollaborateResult<Option<GridChange>>
|
pub fn modify_grid<F>(&mut self, f: F) -> CollaborateResult<Option<GridChange>>
|
||||||
where
|
where
|
||||||
F: FnOnce(&mut Grid) -> CollaborateResult<Option<()>>,
|
F: FnOnce(&mut Grid) -> CollaborateResult<Option<()>>,
|
||||||
@ -115,11 +120,18 @@ pub struct GridChange {
|
|||||||
pub md5: String,
|
pub md5: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn default_grid_delta(grid: &Grid) -> GridDelta {
|
pub fn make_grid_delta(grid: &Grid) -> GridDelta {
|
||||||
let json = serde_json::to_string(&grid).unwrap();
|
let json = serde_json::to_string(&grid).unwrap();
|
||||||
PlainTextDeltaBuilder::new().insert(&json).build()
|
PlainTextDeltaBuilder::new().insert(&json).build()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn make_grid_revisions(user_id: &str, grid: &Grid) -> RepeatedRevision {
|
||||||
|
let delta = make_grid_delta(grid);
|
||||||
|
let bytes = delta.to_bytes();
|
||||||
|
let revision = Revision::initial_revision(user_id, &grid.id, bytes);
|
||||||
|
revision.into()
|
||||||
|
}
|
||||||
|
|
||||||
impl std::default::Default for GridPad {
|
impl std::default::Default for GridPad {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
let grid = Grid {
|
let grid = Grid {
|
||||||
@ -127,7 +139,7 @@ impl std::default::Default for GridPad {
|
|||||||
field_orders: Default::default(),
|
field_orders: Default::default(),
|
||||||
row_orders: Default::default(),
|
row_orders: Default::default(),
|
||||||
};
|
};
|
||||||
let delta = default_grid_delta(&grid);
|
let delta = make_grid_delta(&grid);
|
||||||
GridPad {
|
GridPad {
|
||||||
grid: Arc::new(grid),
|
grid: Arc::new(grid),
|
||||||
delta,
|
delta,
|
||||||
|
@ -82,12 +82,6 @@ impl Revision {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::convert::From<Revision> for RepeatedRevision {
|
|
||||||
fn from(revision: Revision) -> Self {
|
|
||||||
RepeatedRevision { items: vec![revision] }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::fmt::Debug for Revision {
|
impl std::fmt::Debug for Revision {
|
||||||
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
||||||
let _ = f.write_fmt(format_args!("object_id {}, ", self.object_id))?;
|
let _ = f.write_fmt(format_args!("object_id {}, ", self.object_id))?;
|
||||||
@ -125,6 +119,12 @@ impl std::ops::DerefMut for RepeatedRevision {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl std::convert::From<Revision> for RepeatedRevision {
|
||||||
|
fn from(revision: Revision) -> Self {
|
||||||
|
Self { items: vec![revision] }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl RepeatedRevision {
|
impl RepeatedRevision {
|
||||||
pub fn new(mut items: Vec<Revision>) -> Self {
|
pub fn new(mut items: Vec<Revision>) -> Self {
|
||||||
items.sort_by(|a, b| a.rev_id.cmp(&b.rev_id));
|
items.sort_by(|a, b| a.rev_id.cmp(&b.rev_id));
|
||||||
|
@ -85,6 +85,7 @@ impl std::convert::From<View> for Trash {
|
|||||||
pub enum ViewDataType {
|
pub enum ViewDataType {
|
||||||
RichText = 0,
|
RichText = 0,
|
||||||
PlainText = 1,
|
PlainText = 1,
|
||||||
|
Grid = 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::default::Default for ViewDataType {
|
impl std::default::Default for ViewDataType {
|
||||||
@ -98,6 +99,7 @@ impl std::convert::From<i32> for ViewDataType {
|
|||||||
match val {
|
match val {
|
||||||
0 => ViewDataType::RichText,
|
0 => ViewDataType::RichText,
|
||||||
1 => ViewDataType::PlainText,
|
1 => ViewDataType::PlainText,
|
||||||
|
2 => ViewDataType::Grid,
|
||||||
_ => {
|
_ => {
|
||||||
log::error!("Invalid view type: {}", val);
|
log::error!("Invalid view type: {}", val);
|
||||||
ViewDataType::PlainText
|
ViewDataType::PlainText
|
||||||
|
@ -2823,6 +2823,7 @@ impl ::protobuf::reflect::ProtobufValue for UpdateViewParams {
|
|||||||
pub enum ViewDataType {
|
pub enum ViewDataType {
|
||||||
RichText = 0,
|
RichText = 0,
|
||||||
PlainText = 1,
|
PlainText = 1,
|
||||||
|
Grid = 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ::protobuf::ProtobufEnum for ViewDataType {
|
impl ::protobuf::ProtobufEnum for ViewDataType {
|
||||||
@ -2834,6 +2835,7 @@ impl ::protobuf::ProtobufEnum for ViewDataType {
|
|||||||
match value {
|
match value {
|
||||||
0 => ::std::option::Option::Some(ViewDataType::RichText),
|
0 => ::std::option::Option::Some(ViewDataType::RichText),
|
||||||
1 => ::std::option::Option::Some(ViewDataType::PlainText),
|
1 => ::std::option::Option::Some(ViewDataType::PlainText),
|
||||||
|
2 => ::std::option::Option::Some(ViewDataType::Grid),
|
||||||
_ => ::std::option::Option::None
|
_ => ::std::option::Option::None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2842,6 +2844,7 @@ impl ::protobuf::ProtobufEnum for ViewDataType {
|
|||||||
static values: &'static [ViewDataType] = &[
|
static values: &'static [ViewDataType] = &[
|
||||||
ViewDataType::RichText,
|
ViewDataType::RichText,
|
||||||
ViewDataType::PlainText,
|
ViewDataType::PlainText,
|
||||||
|
ViewDataType::Grid,
|
||||||
];
|
];
|
||||||
values
|
values
|
||||||
}
|
}
|
||||||
@ -2904,9 +2907,9 @@ static file_descriptor_proto_data: &'static [u8] = b"\
|
|||||||
\x17\n\x07view_id\x18\x01\x20\x01(\tR\x06viewId\x12\x14\n\x04name\x18\
|
\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\
|
\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\
|
\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\
|
\x0bone_of_nameB\r\n\x0bone_of_descB\x12\n\x10one_of_thumbnail*5\n\x0cVi\
|
||||||
ewDataType\x12\x0c\n\x08RichText\x10\0\x12\r\n\tPlainText\x10\x01b\x06pr\
|
ewDataType\x12\x0c\n\x08RichText\x10\0\x12\r\n\tPlainText\x10\x01\x12\
|
||||||
oto3\
|
\x08\n\x04Grid\x10\x02b\x06proto3\
|
||||||
";
|
";
|
||||||
|
|
||||||
static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;
|
static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;
|
||||||
|
@ -58,4 +58,5 @@ message UpdateViewParams {
|
|||||||
enum ViewDataType {
|
enum ViewDataType {
|
||||||
RichText = 0;
|
RichText = 0;
|
||||||
PlainText = 1;
|
PlainText = 1;
|
||||||
|
Grid = 2;
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,15 @@ pub struct FieldOrder {
|
|||||||
pub visibility: bool,
|
pub visibility: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl std::convert::From<&Field> for FieldOrder {
|
||||||
|
fn from(field: &Field) -> Self {
|
||||||
|
Self {
|
||||||
|
field_id: field.id.clone(),
|
||||||
|
visibility: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize, ProtoBuf)]
|
#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize, ProtoBuf)]
|
||||||
pub struct RepeatedFieldOrder {
|
pub struct RepeatedFieldOrder {
|
||||||
#[pb(index = 1)]
|
#[pb(index = 1)]
|
||||||
@ -33,6 +42,12 @@ pub struct RepeatedFieldOrder {
|
|||||||
pub items: Vec<FieldOrder>,
|
pub items: Vec<FieldOrder>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl std::convert::From<Vec<FieldOrder>> for RepeatedFieldOrder {
|
||||||
|
fn from(items: Vec<FieldOrder>) -> Self {
|
||||||
|
Self { items }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl std::ops::Deref for RepeatedFieldOrder {
|
impl std::ops::Deref for RepeatedFieldOrder {
|
||||||
type Target = Vec<FieldOrder>;
|
type Target = Vec<FieldOrder>;
|
||||||
|
|
||||||
@ -76,6 +91,18 @@ pub struct RepeatedField {
|
|||||||
#[pb(index = 1)]
|
#[pb(index = 1)]
|
||||||
pub items: Vec<Field>,
|
pub items: Vec<Field>,
|
||||||
}
|
}
|
||||||
|
impl std::ops::Deref for RepeatedField {
|
||||||
|
type Target = Vec<Field>;
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.items
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::DerefMut for RepeatedField {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut self.items
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, ProtoBuf_Enum, EnumString, EnumIter, Display, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, ProtoBuf_Enum, EnumString, EnumIter, Display, Serialize, Deserialize)]
|
||||||
pub enum FieldType {
|
pub enum FieldType {
|
||||||
@ -156,6 +183,16 @@ pub struct RowOrder {
|
|||||||
pub visibility: bool,
|
pub visibility: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl std::convert::From<&RawRow> for RowOrder {
|
||||||
|
fn from(row: &RawRow) -> Self {
|
||||||
|
Self {
|
||||||
|
grid_id: row.grid_id.clone(),
|
||||||
|
row_id: row.id.clone(),
|
||||||
|
visibility: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, ProtoBuf)]
|
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, ProtoBuf)]
|
||||||
pub struct RepeatedRowOrder {
|
pub struct RepeatedRowOrder {
|
||||||
#[pb(index = 1)]
|
#[pb(index = 1)]
|
||||||
@ -163,9 +200,14 @@ pub struct RepeatedRowOrder {
|
|||||||
pub items: Vec<RowOrder>,
|
pub items: Vec<RowOrder>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl std::convert::From<Vec<RowOrder>> for RepeatedRowOrder {
|
||||||
|
fn from(items: Vec<RowOrder>) -> Self {
|
||||||
|
Self { items }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl std::ops::Deref for RepeatedRowOrder {
|
impl std::ops::Deref for RepeatedRowOrder {
|
||||||
type Target = Vec<RowOrder>;
|
type Target = Vec<RowOrder>;
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
&self.items
|
&self.items
|
||||||
}
|
}
|
||||||
@ -210,6 +252,19 @@ pub struct RepeatedRow {
|
|||||||
pub items: Vec<Row>,
|
pub items: Vec<Row>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl std::ops::Deref for RepeatedRow {
|
||||||
|
type Target = Vec<Row>;
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.items
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::DerefMut for RepeatedRow {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut self.items
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default, ProtoBuf)]
|
#[derive(Debug, Default, ProtoBuf)]
|
||||||
pub struct Row {
|
pub struct Row {
|
||||||
#[pb(index = 1)]
|
#[pb(index = 1)]
|
||||||
|
Loading…
Reference in New Issue
Block a user