-
-
Notifications
You must be signed in to change notification settings - Fork 4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: support editor to show workspace folder overview #4420
feat: support editor to show workspace folder overview #4420
Conversation
@Jayaprakash-dev have you tested the deletion and update cases? Please include integration tests to cover your feature. If you have any questions about the integration feature, feel free to DM me on Discord or comment here. |
@LucasXu0, I've already included an integration test for the update cases in the PR, I will include a test for deletion cases. |
I meant the insertion and deletion tests when opening the page, and the end of each test should validate the results. Never mind, I will comment directly on the code later. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did a small review on the flutter changes.
Some more test cases would be very nice to have, eg. renaming/changing icon of child of child of parent, whilst parent is open, to ensure that the overview is updated accordingly.
frontend/appflowy_flutter/lib/plugins/document/application/document_data_pb_extension.dart
Outdated
Show resolved
Hide resolved
...er/lib/plugins/document/application/overview_adapter/workspace_to_overview_adapter_bloc.dart
Outdated
Show resolved
Hide resolved
...er/lib/plugins/document/application/overview_adapter/workspace_to_overview_adapter_bloc.dart
Outdated
Show resolved
Hide resolved
...er/lib/plugins/document/application/overview_adapter/workspace_to_overview_adapter_bloc.dart
Outdated
Show resolved
Hide resolved
...er/lib/plugins/document/application/overview_adapter/workspace_to_overview_adapter_bloc.dart
Outdated
Show resolved
Hide resolved
...lugins/document/presentation/editor_plugins/workspace_overview/overview_block_component.dart
Outdated
Show resolved
Hide resolved
...lugins/document/presentation/editor_plugins/workspace_overview/overview_block_component.dart
Outdated
Show resolved
Hide resolved
...lugins/document/presentation/editor_plugins/workspace_overview/overview_block_component.dart
Outdated
Show resolved
Hide resolved
...lugins/document/presentation/editor_plugins/workspace_overview/overview_block_component.dart
Outdated
Show resolved
Hide resolved
...lugins/document/presentation/editor_plugins/workspace_overview/overview_block_component.dart
Outdated
Show resolved
Hide resolved
frontend/appflowy_flutter/integration_test/folder/workspace_overview/overview_test.dart
Outdated
Show resolved
Hide resolved
The analyzer is also failing, check the output of the CI. |
1bbd5c6
to
0f9e7eb
Compare
...lugins/document/presentation/editor_plugins/workspace_overview/overview_block_component.dart
Outdated
Show resolved
Hide resolved
frontend/appflowy_flutter/lib/plugins/document/application/doc_bloc.dart
Outdated
Show resolved
Hide resolved
frontend/appflowy_flutter/lib/plugins/document/application/doc_bloc.dart
Outdated
Show resolved
Hide resolved
frontend/appflowy_flutter/lib/plugins/document/presentation/editor_configuration.dart
Outdated
Show resolved
Hide resolved
...lugins/document/presentation/editor_plugins/workspace_overview/overview_block_component.dart
Outdated
Show resolved
Hide resolved
...lugins/document/presentation/editor_plugins/workspace_overview/overview_block_component.dart
Outdated
Show resolved
Hide resolved
@Jayaprakash-dev Why did you add the |
@LucasXu0, The current implementation of the you can look at here how view changes are notified: @ notify_child_views_changed function:
|
6b172ed
to
0f17e6e
Compare
…evel of child views
…and its handler in rust backend
…s update notification
…OverviewChildViews` notification
0f17e6e
to
3f13a2a
Compare
await tester.hoverOnPageName(firstLevelParentViewName); | ||
await tester.renamePage('View 1'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should never finish tests with "actions", only "expectations", otherwise you're just "doing actions" just to do them, without actually checking if what they did, worked as intended.
@@ -7,7 +7,7 @@ part 'cloud_env_test.g.dart'; | |||
|
|||
/// Follow the guide on https://supabase.com/docs/guides/auth/social-login/auth-google to setup the auth provider. | |||
/// | |||
@Envied(path: '.env.cloud.test') | |||
@Envied(path: '.env.cloud') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why this change?
let mutex_folder = self.mutex_folder.clone(); | ||
let mutex_folder = mutex_folder.lock(); | ||
let mutex_folder = mutex_folder.as_ref(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let mutex_folder = self.mutex_folder.clone(); | |
let mutex_folder = mutex_folder.lock(); | |
let mutex_folder = mutex_folder.as_ref(); | |
let mutex_folder = self.mutex_folder.clone().lock().as_ref(); |
let mutex_folder = self.mutex_folder.clone(); | ||
let mutex_folder = mutex_folder.lock(); | ||
let mutex_folder = mutex_folder.as_ref(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let mutex_folder = self.mutex_folder.clone(); | |
let mutex_folder = mutex_folder.lock(); | |
let mutex_folder = mutex_folder.as_ref(); | |
let mutex_folder = self.mutex_folder.clone().lock().as_ref(); |
let mutex_folder = self.mutex_folder.clone(); | ||
let mutex_folder = mutex_folder.lock(); | ||
let mutex_folder = mutex_folder.as_ref(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let mutex_folder = self.mutex_folder.clone(); | |
let mutex_folder = mutex_folder.lock(); | |
let mutex_folder = mutex_folder.as_ref(); | |
let mutex_folder = self.mutex_folder.clone().lock().as_ref(); |
let ffolder = folder.lock(); | ||
if let Some(folder) = ffolder.as_ref() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let ffolder = folder.lock(); | |
if let Some(folder) = ffolder.as_ref() { | |
if let Some(folder) = folder.lock().as_ref() { |
if let Some(folder) = ffolder.as_ref() { | ||
match value { | ||
ViewChange::DidCreateView { view } => { | ||
if let Some(manager) = workspace_overview_listener_id_manager.upgrade() { | ||
notify_child_views_changed( | ||
view_pb_without_child_views(Arc::new(view.clone())), | ||
ChildViewChangeReason::Create, | ||
manager, | ||
folder, | ||
); | ||
} | ||
notify_parent_view_did_change(folder, vec![view.parent_view_id]); | ||
}, | ||
ViewChange::DidDeleteView { views } => { | ||
for view in views { | ||
if let Some(manager) = workspace_overview_listener_id_manager.upgrade() { | ||
notify_child_views_changed( | ||
view_pb_without_child_views(view.clone()), | ||
ChildViewChangeReason::Delete, | ||
manager, | ||
folder, | ||
); | ||
} | ||
} | ||
}, | ||
ViewChange::DidUpdate { view } => { | ||
notify_view_did_change(view.clone()); | ||
if let Some(manager) = workspace_overview_listener_id_manager.upgrade() { | ||
notify_child_views_changed( | ||
view_pb_without_child_views(Arc::new(view.clone())), | ||
ChildViewChangeReason::Update, | ||
manager, | ||
folder, | ||
); | ||
} | ||
notify_parent_view_did_change(folder, vec![view.parent_view_id.clone()]); | ||
}, | ||
}; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if let Some(folder) = ffolder.as_ref() { | |
match value { | |
ViewChange::DidCreateView { view } => { | |
if let Some(manager) = workspace_overview_listener_id_manager.upgrade() { | |
notify_child_views_changed( | |
view_pb_without_child_views(Arc::new(view.clone())), | |
ChildViewChangeReason::Create, | |
manager, | |
folder, | |
); | |
} | |
notify_parent_view_did_change(folder, vec![view.parent_view_id]); | |
}, | |
ViewChange::DidDeleteView { views } => { | |
for view in views { | |
if let Some(manager) = workspace_overview_listener_id_manager.upgrade() { | |
notify_child_views_changed( | |
view_pb_without_child_views(view.clone()), | |
ChildViewChangeReason::Delete, | |
manager, | |
folder, | |
); | |
} | |
} | |
}, | |
ViewChange::DidUpdate { view } => { | |
notify_view_did_change(view.clone()); | |
if let Some(manager) = workspace_overview_listener_id_manager.upgrade() { | |
notify_child_views_changed( | |
view_pb_without_child_views(Arc::new(view.clone())), | |
ChildViewChangeReason::Update, | |
manager, | |
folder, | |
); | |
} | |
notify_parent_view_did_change(folder, vec![view.parent_view_id.clone()]); | |
}, | |
}; | |
} | |
if let Some(workspace_listener) = workspace_overview_listener_id_manager.upgrade() { | |
if let Some(folder) = folder.lock().as_ref() { | |
match value { | |
ViewChange::DidCreateView { view } => { | |
notify_child_views_changed( | |
view_pb_without_child_views(Arc::new(view.clone())), | |
ChildViewChangeReason::Create, | |
manager, | |
folder, | |
); | |
notify_parent_view_did_change(folder, vec![view.parent_view_id]); | |
}, | |
ViewChange::DidDeleteView { views } => { | |
for view in views { | |
notify_child_views_changed( | |
view_pb_without_child_views(view.clone()), | |
ChildViewChangeReason::Delete, | |
manager, | |
folder, | |
); | |
} | |
}, | |
ViewChange::DidUpdate { view } => { | |
notify_view_did_change(view.clone()); | |
notify_child_views_changed( | |
view_pb_without_child_views(Arc::new(view.clone())), | |
ChildViewChangeReason::Update, | |
manager, | |
folder, | |
); | |
notify_parent_view_did_change(folder, vec![view.parent_view_id.clone()]); | |
}, | |
}; | |
} | |
} |
Description
I've addressed the issue #4282 by implementing the Workspace folder Overview feature, allowing users to create an outline for workspace folder/sub pages structures using the slash commands
/overview
or/workspace overview
. This facilitates easy navigation in nested document structures.Implemented Changes
Added
GetAllLevelOfViews
event in the backend to retrieve all levels of child views. Previously, only theGetView
event returned first-level children.Added a struct
WorkspaceOverviewListenerIdManager
in the Rust backend. This struct stores overview block listener IDs to notify them about updates in child views from all levels. Additionally, a new notification eventDidUpdateWorkspaceOverviewChildViews
has been added to inform overview listener IDs about changes. This ensures that the struct and overview ID listener are specifically designed to handle updates across all child view levels.Implemented navigation to pages from the workspace overview block.
The only issue is that we need to assign the view ID to the editor document in AppFlowy-IO/appflowy-editor repo. This enables us to retrieve the view from the backend using the stored view ID, like this:
In Overview block component widget builder
In
Document
class ofAppflowyEditor
class:Testing
I have tested this implementation thoroughly, ensuring it functions as expected and addressing the outlined issue.
Note
Note: There might be some syntax issues in the Rust code as I am a newbie in Rust programming. I welcome suggestions and feedback to improve the code quality.
Screenshots
appflowy_overview_demo.mp4