feat: support create document with initial data (#1841)

This commit is contained in:
Nathan.fooo 2023-02-10 22:24:34 +08:00 committed by GitHub
parent 1ad08ba59d
commit 8588afcda6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 49 additions and 128 deletions

View File

@ -75,8 +75,8 @@ class DocumentBloc extends Bloc<DocumentEvent, DocumentState> {
Future<void> _initial(Initial value, Emitter<DocumentState> emit) async {
final result = await _documentService.openDocument(view: view);
result.fold(
(block) {
final document = Document.fromJson(jsonDecode(block.snapshot));
(documentData) {
final document = Document.fromJson(jsonDecode(documentData.content));
editorState = EditorState(document: document);
_listenOnDocumentChange();
emit(

View File

@ -6,14 +6,14 @@ import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-document/entities.pb.dart';
class DocumentService {
Future<Either<DocumentSnapshotPB, FlowyError>> openDocument({
Future<Either<DocumentDataPB, FlowyError>> openDocument({
required ViewPB view,
}) async {
await FolderEventSetLatestView(ViewIdPB(value: view.id)).send();
final payload = OpenDocumentContextPB()
final payload = OpenDocumentPayloadPB()
..documentId = view.id
..documentVersion = DocumentVersionPB.V1;
..version = DocumentVersionPB.V1;
// switch (view.dataFormat) {
// case ViewDataFormatPB.DeltaFormat:
// payload.documentVersion = DocumentVersionPB.V0;

View File

@ -1,46 +0,0 @@
import 'package:app_flowy/core/grid_notification.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-database/notification.pb.dart';
import 'package:flowy_infra/notifier.dart';
import 'dart:async';
import 'dart:typed_data';
import 'package:dartz/dartz.dart';
import 'package:appflowy_backend/protobuf/flowy-database/field_entities.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-database/row_entities.pb.dart';
typedef UpdateRowNotifiedValue = Either<RowPB, FlowyError>;
typedef UpdateFieldNotifiedValue = Either<List<FieldPB>, FlowyError>;
class RowListener {
final String rowId;
PublishNotifier<UpdateRowNotifiedValue>? updateRowNotifier =
PublishNotifier();
DatabaseNotificationListener? _listener;
RowListener({required this.rowId});
void start() {
_listener =
DatabaseNotificationListener(objectId: rowId, handler: _handler);
}
void _handler(DatabaseNotification ty, Either<Uint8List, FlowyError> result) {
switch (ty) {
case DatabaseNotification.DidUpdateRow:
result.fold(
(payload) =>
updateRowNotifier?.value = left(RowPB.fromBuffer(payload)),
(error) => updateRowNotifier?.value = right(error),
);
break;
default:
break;
}
}
Future<void> stop() async {
await _listener?.stop();
updateRowNotifier?.dispose();
updateRowNotifier = null;
}
}

View File

@ -1,4 +1,5 @@
import 'dart:async';
import 'dart:convert';
import 'package:appflowy_backend/protobuf/flowy-folder/workspace.pb.dart';
import 'package:dartz/dartz.dart';
@ -23,13 +24,18 @@ class AppService {
required ViewDataFormatPB dataFormatType,
required PluginType pluginType,
required ViewLayoutTypePB layoutType,
/// The initial data should be the JSON of the doucment
/// For example: {"document":{"type":"editor","children":[]}}
String? initialData,
}) {
var payload = CreateViewPayloadPB.create()
final payload = CreateViewPayloadPB.create()
..belongToId = appId
..name = name
..desc = desc ?? ""
..dataFormat = dataFormatType
..layout = layoutType;
..layout = layoutType
..initialData = utf8.encode(initialData ?? "");
return FolderEventCreateView(payload).send();
}
@ -118,54 +124,6 @@ class AppService {
}
}
extension AppFlowy on Either {
T? getLeftOrNull<T>() {
if (isLeft()) {
final result = fold<T?>((l) => l, (r) => null);
return result;
}
return null;
}
Future<List<Tuple2<AppPB, List<ViewPB>>>> fetchViews(
ViewLayoutTypePB layoutType) async {
final result = <Tuple2<AppPB, List<ViewPB>>>[];
return FolderEventReadCurrentWorkspace().send().then((value) async {
final workspaces = value.getLeftOrNull<WorkspaceSettingPB>();
if (workspaces != null) {
final apps = workspaces.workspace.apps.items;
for (var app in apps) {
final views = await getViews(appId: app.id).then(
(value) => value
.getLeftOrNull<List<ViewPB>>()
?.where((e) => e.layout == layoutType)
.toList(),
);
if (views != null && views.isNotEmpty) {
result.add(Tuple2(app, views));
}
}
}
return result;
});
}
Future<Either<ViewPB, FlowyError>> getView(
String appID,
String viewID,
) async {
final payload = AppIdPB.create()..value = appID;
return FolderEventReadApp(payload).send().then((result) {
return result.fold(
(app) => left(
app.belongings.items.firstWhere((e) => e.id == viewID),
),
(error) => right(error),
);
});
}
}
extension AppFlowy on Either {
T? getLeftOrNull<T>() {
if (isLeft()) {

View File

@ -5,6 +5,7 @@ use flowy_client_ws::FlowyWebSocketConnect;
use flowy_database::entities::LayoutTypePB;
use flowy_database::manager::{make_database_view_data, DatabaseManager};
use flowy_database::util::{make_default_board, make_default_calendar, make_default_grid};
use flowy_document::editor::make_transaction_from_document_content;
use flowy_document::DocumentManager;
use flowy_folder::entities::{ViewDataFormatPB, ViewLayoutTypePB, ViewPB};
use flowy_folder::manager::{ViewDataProcessor, ViewDataProcessorMap};
@ -150,7 +151,15 @@ impl ViewDataProcessor for DocumentViewDataProcessor {
) -> FutureResult<(), FlowyError> {
// Only accept Document type
debug_assert_eq!(layout, ViewLayoutTypePB::Document);
let revision = Revision::initial_revision(view_id, view_data);
let view_data = match String::from_utf8(view_data.to_vec()) {
Ok(content) => match make_transaction_from_document_content(&content) {
Ok(transaction) => transaction.to_bytes().unwrap_or(vec![]),
Err(_) => vec![],
},
Err(_) => vec![],
};
let revision = Revision::initial_revision(view_id, Bytes::from(view_data));
let view_id = view_id.to_string();
let manager = self.0.clone();
@ -199,7 +208,7 @@ impl ViewDataProcessor for DocumentViewDataProcessor {
})
}
fn create_view_from_delta_data(
fn create_view_with_data(
&self,
_user_id: &str,
_view_id: &str,
@ -279,7 +288,7 @@ impl ViewDataProcessor for GridViewDataProcessor {
})
}
fn create_view_from_delta_data(
fn create_view_with_data(
&self,
user_id: &str,
view_id: &str,

View File

@ -58,13 +58,13 @@ impl TryInto<EditParams> for EditPayloadPB {
}
#[derive(Default, ProtoBuf)]
pub struct DocumentSnapshotPB {
pub struct DocumentDataPB {
#[pb(index = 1)]
pub doc_id: String,
/// Encode in JSON format
#[pb(index = 2)]
pub snapshot: String,
pub content: String,
}
#[derive(Default, ProtoBuf)]
@ -96,12 +96,12 @@ impl std::default::Default for DocumentVersionPB {
}
#[derive(Default, ProtoBuf)]
pub struct OpenDocumentContextPB {
pub struct OpenDocumentPayloadPB {
#[pb(index = 1)]
pub document_id: String,
#[pb(index = 2)]
pub document_version: DocumentVersionPB,
pub version: DocumentVersionPB,
}
#[derive(Default, Debug)]

View File

@ -1,5 +1,5 @@
use crate::entities::{
DocumentSnapshotPB, EditParams, EditPayloadPB, ExportDataPB, ExportParams, ExportPayloadPB, OpenDocumentContextPB,
DocumentDataPB, EditParams, EditPayloadPB, ExportDataPB, ExportParams, ExportPayloadPB, OpenDocumentPayloadPB,
};
use crate::DocumentManager;
use flowy_error::FlowyError;
@ -9,15 +9,15 @@ use std::convert::TryInto;
use std::sync::Arc;
pub(crate) async fn get_document_handler(
data: AFPluginData<OpenDocumentContextPB>,
data: AFPluginData<OpenDocumentPayloadPB>,
manager: AFPluginState<Arc<DocumentManager>>,
) -> DataResult<DocumentSnapshotPB, FlowyError> {
let context: OpenDocumentContextPB = data.into_inner();
) -> DataResult<DocumentDataPB, FlowyError> {
let context: OpenDocumentPayloadPB = data.into_inner();
let editor = manager.open_document_editor(&context.document_id).await?;
let document_data = editor.export().await?;
data_result(DocumentSnapshotPB {
data_result(DocumentDataPB {
doc_id: context.document_id,
snapshot: document_data,
content: document_data,
})
}

View File

@ -19,7 +19,7 @@ pub fn init(document_manager: Arc<DocumentManager>) -> AFPlugin {
#[derive(Clone, Copy, PartialEq, Eq, Debug, Display, Hash, ProtoBuf_Enum, Flowy_Event)]
#[event_err = "FlowyError"]
pub enum DocumentEvent {
#[event(input = "OpenDocumentContextPB", output = "DocumentSnapshotPB")]
#[event(input = "OpenDocumentPayloadPB", output = "DocumentDataPB")]
GetDocument = 0,
#[event(input = "EditPayloadPB")]

View File

@ -162,7 +162,7 @@ pub struct CreateViewPayloadPB {
pub layout: ViewLayoutTypePB,
#[pb(index = 7)]
pub view_content_data: Vec<u8>,
pub initial_data: Vec<u8>,
}
#[derive(Debug, Clone)]
@ -174,7 +174,7 @@ pub struct CreateViewParams {
pub data_format: ViewDataFormatPB,
pub layout: ViewLayoutTypePB,
pub view_id: String,
pub view_content_data: Vec<u8>,
pub initial_data: Vec<u8>,
}
impl TryInto<CreateViewParams> for CreateViewPayloadPB {
@ -197,7 +197,7 @@ impl TryInto<CreateViewParams> for CreateViewPayloadPB {
layout: self.layout,
thumbnail,
view_id,
view_content_data: self.view_content_data,
initial_data: self.initial_data,
})
}
}

View File

@ -282,7 +282,7 @@ pub trait ViewDataProcessor {
data_format: ViewDataFormatPB,
) -> FutureResult<Bytes, FlowyError>;
fn create_view_from_delta_data(
fn create_view_with_data(
&self,
user_id: &str,
view_id: &str,

View File

@ -59,7 +59,7 @@ impl ViewController {
) -> Result<ViewRevision, FlowyError> {
let processor = self.get_data_processor(params.data_format.clone())?;
let user_id = self.user.user_id()?;
if params.view_content_data.is_empty() {
if params.initial_data.is_empty() {
tracing::trace!("Create view with build-in data");
let view_data = processor
.create_default_view(
@ -69,14 +69,14 @@ impl ViewController {
params.data_format.clone(),
)
.await?;
params.view_content_data = view_data.to_vec();
params.initial_data = view_data.to_vec();
} else {
tracing::trace!("Create view with view data");
let delta_data = processor
.create_view_from_delta_data(
let view_data = processor
.create_view_with_data(
&user_id,
&params.view_id,
params.view_content_data.clone(),
params.initial_data.clone(),
params.layout.clone(),
)
.await?;
@ -84,7 +84,7 @@ impl ViewController {
&params.view_id,
params.data_format.clone(),
params.layout.clone(),
delta_data,
view_data,
)
.await?;
};
@ -232,7 +232,7 @@ impl ViewController {
thumbnail: view_rev.thumbnail,
data_format: view_rev.data_format.into(),
layout: view_rev.layout.into(),
view_content_data: view_data.to_vec(),
initial_data: view_data.to_vec(),
view_id: gen_view_id(),
};

View File

@ -363,7 +363,7 @@ pub async fn create_view(
thumbnail: None,
data_format: data_type,
layout,
view_content_data: vec![],
initial_data: vec![],
};
FolderEventBuilder::new(sdk.clone())
.event(CreateView)

View File

@ -119,7 +119,7 @@ async fn create_view(
thumbnail: Some("http://1.png".to_string()),
data_format,
layout,
view_content_data: data,
initial_data: data,
};
FolderEventBuilder::new(sdk.clone())