fix: ref view in document (#2685)

* fix: remove set ref view in document as the current view

* ci: fix tests

* ci: fix tauri build
This commit is contained in:
Nathan.fooo
2023-06-03 13:40:12 +08:00
committed by GitHub
parent 5994cc135f
commit 4fa39f298c
19 changed files with 76 additions and 40 deletions

View File

@ -26,8 +26,6 @@ class DatabaseViewBackendService {
} }
Future<Either<DatabasePB, FlowyError>> openGrid() async { Future<Either<DatabasePB, FlowyError>> openGrid() async {
await FolderEventSetLatestView(ViewIdPB(value: viewId)).send();
final payload = DatabaseViewIdPB(value: viewId); final payload = DatabaseViewIdPB(value: viewId);
return DatabaseEventGetDatabase(payload).send(); return DatabaseEventGetDatabase(payload).send();
} }

View File

@ -38,6 +38,7 @@ class DatabaseViewPlugin extends Plugin {
(updatedView) { (updatedView) {
if (_view.layout != updatedView.layout) { if (_view.layout != updatedView.layout) {
_innerPlugin = _makeInnerPlugin(updatedView); _innerPlugin = _makeInnerPlugin(updatedView);
getIt<HomeStackManager>().setPlugin(_innerPlugin); getIt<HomeStackManager>().setPlugin(_innerPlugin);
} }
_view = updatedView; _view = updatedView;

View File

@ -22,9 +22,6 @@ class DocumentService {
Future<Either<FlowyError, DocumentDataPB>> openDocument({ Future<Either<FlowyError, DocumentDataPB>> openDocument({
required ViewPB view, required ViewPB view,
}) async { }) async {
// set the latest view
await FolderEventSetLatestView(ViewIdPB(value: view.id)).send();
final payload = OpenDocumentPayloadPB()..documentId = view.id; final payload = OpenDocumentPayloadPB()..documentId = view.id;
final result = await DocumentEventOpenDocument(payload).send(); final result = await DocumentEventOpenDocument(payload).send();
return result.swap(); return result.swap();

View File

@ -1,8 +1,6 @@
import 'dart:convert'; // import 'dart:convert';
// import 'package:appflowy_backend/log.dart';
import 'package:appflowy_backend/log.dart'; // const JsonEncoder _encoder = JsonEncoder.withIndent(' ');
const JsonEncoder _encoder = JsonEncoder.withIndent(' ');
void prettyPrintJson(Object? object) { void prettyPrintJson(Object? object) {
Log.debug(_encoder.convert(object)); // Log.trace(_encoder.convert(object));
} }

View File

@ -85,7 +85,7 @@ class MenuBloc extends Bloc<MenuEvent, MenuState> {
// ignore: unused_element // ignore: unused_element
Future<void> _fetchApps(Emitter<MenuState> emit) async { Future<void> _fetchApps(Emitter<MenuState> emit) async {
final appsOrFail = await _workspaceService.getApps(); final appsOrFail = await _workspaceService.getViews();
emit( emit(
appsOrFail.fold( appsOrFail.fold(
(views) => state.copyWith(views: views), (views) => state.copyWith(views: views),

View File

@ -8,11 +8,19 @@ import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
class ViewBackendService { class ViewBackendService {
static Future<Either<ViewPB, FlowyError>> createView({ static Future<Either<ViewPB, FlowyError>> createView({
/// The [layoutType] is the type of the view.
required ViewLayoutPB layoutType, required ViewLayoutPB layoutType,
/// The [parentViewId] is the parent view id.
required String parentViewId, required String parentViewId,
/// The [name] is the name of the view.
required String name, required String name,
String? desc, String? desc,
/// If [openAfterCreate] is true, the view will be opened after created.
bool openAfterCreate = true,
/// The initial data should be a JSON that represent the DocumentDataPB. /// The initial data should be a JSON that represent the DocumentDataPB.
/// Currently, only support create document with initial data. /// Currently, only support create document with initial data.
List<int>? initialDataBytes, List<int>? initialDataBytes,
@ -29,10 +37,11 @@ class ViewBackendService {
..name = name ..name = name
..desc = desc ?? "" ..desc = desc ?? ""
..layout = layoutType ..layout = layoutType
..setAsCurrent = openAfterCreate
..initialData = initialDataBytes ?? []; ..initialData = initialDataBytes ?? [];
if (ext.isNotEmpty) { if (ext.isNotEmpty) {
payload.ext.addAll(ext); payload.meta.addAll(ext);
} }
return FolderEventCreateView(payload).send(); return FolderEventCreateView(payload).send();
@ -48,12 +57,14 @@ class ViewBackendService {
layoutType: layoutType, layoutType: layoutType,
parentViewId: parentViewId, parentViewId: parentViewId,
name: name, name: name,
openAfterCreate: false,
ext: { ext: {
'database_id': databaseId, 'database_id': databaseId,
}, },
); );
} }
/// Returns a list of views that are the children of the given [viewId].
static Future<Either<List<ViewPB>, FlowyError>> getViews({ static Future<Either<List<ViewPB>, FlowyError>> getViews({
required String viewId, required String viewId,
}) { }) {

View File

@ -54,9 +54,9 @@ class WorkspaceService {
}); });
} }
Future<Either<List<ViewPB>, FlowyError>> getApps() { Future<Either<List<ViewPB>, FlowyError>> getViews() {
final payload = WorkspaceIdPB.create()..value = workspaceId; final payload = WorkspaceIdPB.create()..value = workspaceId;
return FolderEventReadWorkspaceApps(payload).send().then((result) { return FolderEventReadWorkspaceViews(payload).send().then((result) {
return result.fold( return result.fold(
(apps) => left(apps.items), (apps) => left(apps.items),
(error) => right(error), (error) => right(error),

View File

@ -5,6 +5,7 @@ import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/workspace/presentation/home/home_sizes.dart'; import 'package:appflowy/workspace/presentation/home/home_sizes.dart';
import 'package:appflowy/workspace/presentation/home/navigation.dart'; import 'package:appflowy/workspace/presentation/home/navigation.dart';
import 'package:appflowy/workspace/presentation/home/toast.dart'; import 'package:appflowy/workspace/presentation/home/toast.dart';
import 'package:appflowy_backend/dispatch/dispatch.dart';
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
import 'package:flowy_infra_ui/style_widget/extension.dart'; import 'package:flowy_infra_ui/style_widget/extension.dart';
import 'package:flowy_infra_ui/widget/spacing.dart'; import 'package:flowy_infra_ui/widget/spacing.dart';
@ -123,6 +124,9 @@ class HomeStackNotifier extends ChangeNotifier {
_plugin.notifier?.isDisplayChanged.addListener(notifyListeners); _plugin.notifier?.isDisplayChanged.addListener(notifyListeners);
_plugin.dispose(); _plugin.dispose();
/// Set the plugin view as the latest view.
FolderEventSetLatestView(ViewIdPB(value: newPlugin.id)).send();
_plugin = newPlugin; _plugin = newPlugin;
_plugin.notifier?.isDisplayChanged.removeListener(notifyListeners); _plugin.notifier?.isDisplayChanged.removeListener(notifyListeners);
notifyListeners(); notifyListeners();

View File

@ -3,6 +3,7 @@ import 'package:appflowy/plugins/document/document.dart';
import 'package:appflowy/workspace/application/app/app_bloc.dart'; import 'package:appflowy/workspace/application/app/app_bloc.dart';
import 'package:appflowy/workspace/application/home/home_bloc.dart'; import 'package:appflowy/workspace/application/home/home_bloc.dart';
import 'package:appflowy_backend/dispatch/dispatch.dart'; import 'package:appflowy_backend/dispatch/dispatch.dart';
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import '../../util.dart'; import '../../util.dart';
@ -47,6 +48,8 @@ void main() {
final latestView = appBloc.state.latestCreatedView!; final latestView = appBloc.state.latestCreatedView!;
final _ = DocumentBloc(view: latestView) final _ = DocumentBloc(view: latestView)
..add(const DocumentEvent.initial()); ..add(const DocumentEvent.initial());
await FolderEventSetLatestView(ViewIdPB(value: latestView.id)).send();
await blocResponseFuture(); await blocResponseFuture();
assert(homeBloc.state.workspaceSetting.latestView.id == latestView.id); assert(homeBloc.state.workspaceSetting.latestView.id == latestView.id);

View File

@ -90,7 +90,7 @@ class AppFlowyUnitTest {
} }
Future<List<ViewPB>> loadApps() async { Future<List<ViewPB>> loadApps() async {
final result = await workspaceService.getApps(); final result = await workspaceService.getViews();
return result.fold( return result.fold(
(apps) => apps, (apps) => apps,

View File

@ -2,7 +2,7 @@ import { Err, Ok } from 'ts-results';
import { import {
FolderEventCreateView, FolderEventCreateView,
FolderEventMoveItem, FolderEventMoveItem,
FolderEventReadWorkspaceApps, FolderEventReadWorkspaceViews,
FolderEventReadWorkspaces, FolderEventReadWorkspaces,
} from '@/services/backend/events/flowy-folder2'; } from '@/services/backend/events/flowy-folder2';
import { import {
@ -52,7 +52,7 @@ export class WorkspaceBackendService {
getApps = () => { getApps = () => {
const payload = WorkspaceIdPB.fromObject({ value: this.workspaceId }); const payload = WorkspaceIdPB.fromObject({ value: this.workspaceId });
return FolderEventReadWorkspaceApps(payload).then((result) => result.map((val) => val.items)); return FolderEventReadWorkspaceViews(payload).then((result) => result.map((val) => val.items));
}; };
moveApp = (params: { appId: string; fromIndex: number; toIndex: number }) => { moveApp = (params: { appId: string; fromIndex: number; toIndex: number }) => {

View File

@ -11,7 +11,7 @@ pub struct AppFlowyEnv {
impl AppFlowyEnv { impl AppFlowyEnv {
pub fn parser(env_str: &str) { pub fn parser(env_str: &str) {
if let Ok(env) = serde_json::from_str::<AppFlowyEnv>(env_str) { if let Ok(env) = serde_json::from_str::<AppFlowyEnv>(env_str) {
dbg!(&env); tracing::trace!("{:?}", env);
env.supabase_config.write_env(); env.supabase_config.write_env();
env.supabase_db_config.write_env(); env.supabase_db_config.write_env();
} }

View File

@ -141,7 +141,11 @@ pub struct CreateViewPayloadPB {
pub initial_data: Vec<u8>, pub initial_data: Vec<u8>,
#[pb(index = 7)] #[pb(index = 7)]
pub ext: HashMap<String, String>, pub meta: HashMap<String, String>,
/// Mark the view as current view after creation.
#[pb(index = 8)]
pub set_as_current: bool,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -153,6 +157,8 @@ pub struct CreateViewParams {
pub view_id: String, pub view_id: String,
pub initial_data: Vec<u8>, pub initial_data: Vec<u8>,
pub meta: HashMap<String, String>, pub meta: HashMap<String, String>,
/// Mark the view as current view after creation.
pub set_as_current: bool,
} }
impl TryInto<CreateViewParams> for CreateViewPayloadPB { impl TryInto<CreateViewParams> for CreateViewPayloadPB {
@ -170,7 +176,8 @@ impl TryInto<CreateViewParams> for CreateViewPayloadPB {
layout: self.layout, layout: self.layout,
view_id, view_id,
initial_data: self.initial_data, initial_data: self.initial_data,
meta: self.ext, meta: self.meta,
set_as_current: self.set_as_current,
}) })
} }
} }

View File

@ -23,7 +23,7 @@ pub(crate) async fn create_workspace_handler(
} }
#[tracing::instrument(level = "debug", skip(folder), err)] #[tracing::instrument(level = "debug", skip(folder), err)]
pub(crate) async fn read_workspace_apps_handler( pub(crate) async fn read_workspace_views_handler(
folder: AFPluginState<Arc<Folder2Manager>>, folder: AFPluginState<Arc<Folder2Manager>>,
) -> DataResult<RepeatedViewPB, FlowyError> { ) -> DataResult<RepeatedViewPB, FlowyError> {
let child_views = folder.get_current_workspace_views().await?; let child_views = folder.get_current_workspace_views().await?;
@ -85,8 +85,11 @@ pub(crate) async fn create_view_handler(
folder: AFPluginState<Arc<Folder2Manager>>, folder: AFPluginState<Arc<Folder2Manager>>,
) -> DataResult<ViewPB, FlowyError> { ) -> DataResult<ViewPB, FlowyError> {
let params: CreateViewParams = data.into_inner().try_into()?; let params: CreateViewParams = data.into_inner().try_into()?;
let set_as_current = params.set_as_current;
let view = folder.create_view_with_params(params).await?; let view = folder.create_view_with_params(params).await?;
let _ = folder.set_current_view(&view.id).await; if set_as_current {
let _ = folder.set_current_view(&view.id).await;
}
data_result_ok(view_pb_without_child_views(view)) data_result_ok(view_pb_without_child_views(view))
} }

View File

@ -17,7 +17,7 @@ pub fn init(folder: Arc<Folder2Manager>) -> AFPlugin {
) )
.event(FolderEvent::ReadWorkspaces, read_workspaces_handler) .event(FolderEvent::ReadWorkspaces, read_workspaces_handler)
.event(FolderEvent::OpenWorkspace, open_workspace_handler) .event(FolderEvent::OpenWorkspace, open_workspace_handler)
.event(FolderEvent::ReadWorkspaceApps, read_workspace_apps_handler) .event(FolderEvent::ReadWorkspaceViews, read_workspace_views_handler)
// View // View
.event(FolderEvent::CreateView, create_view_handler) .event(FolderEvent::CreateView, create_view_handler)
.event(FolderEvent::ReadView, read_view_handler) .event(FolderEvent::ReadView, read_view_handler)
@ -43,11 +43,11 @@ pub enum FolderEvent {
#[event(input = "CreateWorkspacePayloadPB", output = "WorkspacePB")] #[event(input = "CreateWorkspacePayloadPB", output = "WorkspacePB")]
CreateWorkspace = 0, CreateWorkspace = 0,
/// Read the current opening workspace /// Read the current opening workspace. Currently, we only support one workspace
#[event(output = "WorkspaceSettingPB")] #[event(output = "WorkspaceSettingPB")]
ReadCurrentWorkspace = 1, ReadCurrentWorkspace = 1,
/// Open the workspace and mark it as the current workspace /// Return a list of workspaces that the current user can access
#[event(input = "WorkspaceIdPB", output = "RepeatedWorkspacePB")] #[event(input = "WorkspaceIdPB", output = "RepeatedWorkspacePB")]
ReadWorkspaces = 2, ReadWorkspaces = 2,
@ -59,9 +59,9 @@ pub enum FolderEvent {
#[event(input = "WorkspaceIdPB", output = "WorkspacePB")] #[event(input = "WorkspaceIdPB", output = "WorkspacePB")]
OpenWorkspace = 4, OpenWorkspace = 4,
/// Return a list of apps that belong to this workspace /// Return a list of views that belong to this workspace.
#[event(input = "WorkspaceIdPB", output = "RepeatedViewPB")] #[event(input = "WorkspaceIdPB", output = "RepeatedViewPB")]
ReadWorkspaceApps = 5, ReadWorkspaceViews = 5,
/// Create a new view in the corresponding app /// Create a new view in the corresponding app
#[event(input = "CreateViewPayloadPB", output = "ViewPB")] #[event(input = "CreateViewPayloadPB", output = "ViewPB")]

View File

@ -267,6 +267,9 @@ impl Folder2Manager {
Ok(()) Ok(())
} }
/// Returns the view with the given view id.
/// The child views of the view will only access the first. So if you want to get the child view's
/// child view, you need to call this method again.
#[tracing::instrument(level = "debug", skip(self, view_id), err)] #[tracing::instrument(level = "debug", skip(self, view_id), err)]
pub async fn get_view(&self, view_id: &str) -> FlowyResult<ViewPB> { pub async fn get_view(&self, view_id: &str) -> FlowyResult<ViewPB> {
let view_id = view_id.to_string(); let view_id = view_id.to_string();
@ -305,6 +308,8 @@ impl Folder2Manager {
Ok(()) Ok(())
} }
/// Move the view to trash. If the view is the current view, then set the current view to empty.
/// When the view is moved to trash, all the child views will be moved to trash as well.
#[tracing::instrument(level = "debug", skip(self), err)] #[tracing::instrument(level = "debug", skip(self), err)]
pub async fn move_view_to_trash(&self, view_id: &str) -> FlowyResult<()> { pub async fn move_view_to_trash(&self, view_id: &str) -> FlowyResult<()> {
self.with_folder((), |folder| { self.with_folder((), |folder| {
@ -323,6 +328,7 @@ impl Folder2Manager {
Ok(()) Ok(())
} }
/// Move the view from one position to another position.
#[tracing::instrument(level = "debug", skip(self), err)] #[tracing::instrument(level = "debug", skip(self), err)]
pub async fn move_view(&self, view_id: &str, from: usize, to: usize) -> FlowyResult<()> { pub async fn move_view(&self, view_id: &str, from: usize, to: usize) -> FlowyResult<()> {
let view = self.with_folder(None, |folder| { let view = self.with_folder(None, |folder| {
@ -338,12 +344,16 @@ impl Folder2Manager {
Ok(()) Ok(())
} }
#[tracing::instrument(level = "debug", skip(self, bid), err)] /// Return a list of views that belong to the given parent view id.
pub async fn get_views_belong_to(&self, bid: &str) -> FlowyResult<Vec<View>> { #[tracing::instrument(level = "debug", skip(self, parent_view_id), err)]
let views = self.with_folder(vec![], |folder| folder.views.get_views_belong_to(bid)); pub async fn get_views_belong_to(&self, parent_view_id: &str) -> FlowyResult<Vec<View>> {
let views = self.with_folder(vec![], |folder| {
folder.views.get_views_belong_to(parent_view_id)
});
Ok(views) Ok(views)
} }
/// Update the view with the given params.
#[tracing::instrument(level = "trace", skip(self), err)] #[tracing::instrument(level = "trace", skip(self), err)]
pub async fn update_view_with_params(&self, params: UpdateViewParams) -> FlowyResult<()> { pub async fn update_view_with_params(&self, params: UpdateViewParams) -> FlowyResult<()> {
let value = self.with_folder(None, |folder| { let value = self.with_folder(None, |folder| {
@ -376,6 +386,7 @@ impl Folder2Manager {
Ok(()) Ok(())
} }
/// Duplicate the view with the given view id.
#[tracing::instrument(level = "debug", skip(self), err)] #[tracing::instrument(level = "debug", skip(self), err)]
pub(crate) async fn duplicate_view(&self, view_id: &str) -> Result<(), FlowyError> { pub(crate) async fn duplicate_view(&self, view_id: &str) -> Result<(), FlowyError> {
let view = self let view = self
@ -384,10 +395,6 @@ impl Folder2Manager {
let handler = self.get_handler(&view.layout)?; let handler = self.get_handler(&view.layout)?;
let view_data = handler.duplicate_view(&view.id).await?; let view_data = handler.duplicate_view(&view.id).await?;
let meta = HashMap::new();
// if let Some(database_id) = view.database_id {
// meta.insert("database_id".to_string(), database_id);
// }
let duplicate_params = CreateViewParams { let duplicate_params = CreateViewParams {
parent_view_id: view.parent_view_id.clone(), parent_view_id: view.parent_view_id.clone(),
name: format!("{} (copy)", &view.name), name: format!("{} (copy)", &view.name),
@ -395,7 +402,8 @@ impl Folder2Manager {
layout: view.layout.into(), layout: view.layout.into(),
initial_data: view_data.to_vec(), initial_data: view_data.to_vec(),
view_id: gen_view_id(), view_id: gen_view_id(),
meta, meta: Default::default(),
set_as_current: true,
}; };
let _ = self.create_view_with_params(duplicate_params).await?; let _ = self.create_view_with_params(duplicate_params).await?;
@ -496,6 +504,7 @@ impl Folder2Manager {
initial_data: vec![], initial_data: vec![],
view_id, view_id,
meta: Default::default(), meta: Default::default(),
set_as_current: false,
}; };
let view = create_view(params, import_data.view_layout); let view = create_view(params, import_data.view_layout);

View File

@ -43,6 +43,7 @@ impl Folder2Manager {
view_id: view_id.clone(), view_id: view_id.clone(),
initial_data: vec![], initial_data: vec![],
meta: ext, meta: ext,
set_as_current: true,
}; };
self.create_view_with_params(params).await.unwrap(); self.create_view_with_params(params).await.unwrap();
view_id view_id

View File

@ -218,7 +218,8 @@ pub async fn create_app(sdk: &FlowyCoreTest, workspace_id: &str, name: &str, des
thumbnail: None, thumbnail: None,
layout: ViewLayout::Document.into(), layout: ViewLayout::Document.into(),
initial_data: vec![], initial_data: vec![],
ext: Default::default(), meta: Default::default(),
set_as_current: true,
}; };
EventBuilder::new(sdk.clone()) EventBuilder::new(sdk.clone())
@ -243,7 +244,8 @@ pub async fn create_view(
thumbnail: None, thumbnail: None,
layout: layout.into(), layout: layout.into(),
initial_data: vec![], initial_data: vec![],
ext: Default::default(), meta: Default::default(),
set_as_current: true,
}; };
EventBuilder::new(sdk.clone()) EventBuilder::new(sdk.clone())
.event(CreateView) .event(CreateView)

View File

@ -75,7 +75,8 @@ async fn create_app(sdk: &FlowyCoreTest, name: &str, desc: &str, workspace_id: &
thumbnail: None, thumbnail: None,
layout: ViewLayoutPB::Document, layout: ViewLayoutPB::Document,
initial_data: vec![], initial_data: vec![],
ext: Default::default(), meta: Default::default(),
set_as_current: true,
}; };
EventBuilder::new(sdk.clone()) EventBuilder::new(sdk.clone())
@ -99,7 +100,8 @@ async fn create_view(
thumbnail: Some("http://1.png".to_string()), thumbnail: Some("http://1.png".to_string()),
layout, layout,
initial_data: data, initial_data: data,
ext: Default::default(), meta: Default::default(),
set_as_current: true,
}; };
EventBuilder::new(sdk.clone()) EventBuilder::new(sdk.clone())