mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
feat: support create document with initial data (#1841)
This commit is contained in:
parent
1ad08ba59d
commit
8588afcda6
@ -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(
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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()) {
|
||||
|
@ -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,
|
||||
|
@ -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)]
|
||||
|
@ -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,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -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")]
|
||||
|
@ -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,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
¶ms.view_id,
|
||||
params.view_content_data.clone(),
|
||||
params.initial_data.clone(),
|
||||
params.layout.clone(),
|
||||
)
|
||||
.await?;
|
||||
@ -84,7 +84,7 @@ impl ViewController {
|
||||
¶ms.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(),
|
||||
};
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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())
|
||||
|
Loading…
Reference in New Issue
Block a user