mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
fix: search launch review (#5169)
* fix: support filtering results by workspace * feat: add search button to sidebar * fix: reduce view/recent view fetching across application * feat: add channel to search listener * feat: clean + localization * chore: remove redundant code * fix: disable search * chore: trigger ci * chore: disable search in backend * test: disable search tests for now * feat: temp disable reliance on folder search * fix: add debounce to inline actions * chore: complete future if disposed * fix: clean code * chore: disable unused bloc with feature flag * fix: recent views lazy read * chore: revert podilfe change * chore: update logs * chore: update client api and collab * chore: fix tst * chore: fix test & update collab commit * chore: update collab commit * test: fix unit tests * chore: update rust toolchain 1.77 * chore: use opt-level 1 * fix: code review * chore: clippy --------- Co-authored-by: nathan <nathan@appflowy.io> Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
This commit is contained in:
@ -72,6 +72,19 @@ pub fn view_pb_without_child_views(view: View) -> ViewPB {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn view_pb_without_child_views_from_arc(view: Arc<View>) -> ViewPB {
|
||||
ViewPB {
|
||||
id: view.id.clone(),
|
||||
parent_view_id: view.parent_view_id.clone(),
|
||||
name: view.name.clone(),
|
||||
create_time: view.created_at,
|
||||
child_views: Default::default(),
|
||||
layout: view.layout.clone().into(),
|
||||
icon: view.icon.clone().map(|icon| icon.into()),
|
||||
is_favorite: view.is_favorite,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a ViewPB with child views. Only the first level of child views are included.
|
||||
pub fn view_pb_with_child_views(view: Arc<View>, child_views: Vec<Arc<View>>) -> ViewPB {
|
||||
ViewPB {
|
||||
|
@ -138,6 +138,16 @@ pub(crate) async fn get_view_handler(
|
||||
data_result_ok(view_pb)
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip(folder), err)]
|
||||
pub(crate) async fn get_all_views_handler(
|
||||
folder: AFPluginState<Weak<FolderManager>>,
|
||||
) -> DataResult<RepeatedViewPB, FlowyError> {
|
||||
let folder = upgrade_folder(folder)?;
|
||||
let view_pbs = folder.get_all_views_pb().await?;
|
||||
|
||||
data_result_ok(RepeatedViewPB::from(view_pbs))
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip(data, folder), err)]
|
||||
pub(crate) async fn get_view_ancestors_handler(
|
||||
data: AFPluginData<ViewIdPB>,
|
||||
|
@ -18,6 +18,7 @@ pub fn init(folder: Weak<FolderManager>) -> AFPlugin {
|
||||
.event(FolderEvent::CreateView, create_view_handler)
|
||||
.event(FolderEvent::CreateOrphanView, create_orphan_view_handler)
|
||||
.event(FolderEvent::GetView, get_view_handler)
|
||||
.event(FolderEvent::GetAllViews, get_all_views_handler)
|
||||
.event(FolderEvent::UpdateView, update_view_handler)
|
||||
.event(FolderEvent::DeleteView, delete_view_handler)
|
||||
.event(FolderEvent::DuplicateView, duplicate_view_handler)
|
||||
@ -97,6 +98,10 @@ pub enum FolderEvent {
|
||||
#[event(input = "CreateOrphanViewPayloadPB", output = "ViewPB")]
|
||||
CreateOrphanView = 16,
|
||||
|
||||
/// Return the view info
|
||||
#[event(output = "RepeatedViewPB")]
|
||||
GetAllViews = 17,
|
||||
|
||||
#[event()]
|
||||
CopyLink = 20,
|
||||
|
||||
|
@ -1,8 +1,9 @@
|
||||
use crate::entities::icon::UpdateViewIconParams;
|
||||
use crate::entities::{
|
||||
view_pb_with_child_views, view_pb_without_child_views, CreateViewParams, CreateWorkspaceParams,
|
||||
DeletedViewPB, FolderSnapshotPB, MoveNestedViewParams, RepeatedTrashPB, RepeatedViewIdPB,
|
||||
RepeatedViewPB, UpdateViewParams, ViewPB, ViewSectionPB, WorkspacePB, WorkspaceSettingPB,
|
||||
view_pb_with_child_views, view_pb_without_child_views, view_pb_without_child_views_from_arc,
|
||||
CreateViewParams, CreateWorkspaceParams, DeletedViewPB, FolderSnapshotPB, MoveNestedViewParams,
|
||||
RepeatedTrashPB, RepeatedViewIdPB, RepeatedViewPB, UpdateViewParams, ViewPB, ViewSectionPB,
|
||||
WorkspacePB, WorkspaceSettingPB,
|
||||
};
|
||||
use crate::manager_observer::{
|
||||
notify_child_views_changed, notify_did_update_workspace, notify_parent_view_did_change,
|
||||
@ -30,11 +31,11 @@ use flowy_folder_pub::cloud::{gen_view_id, FolderCloudService};
|
||||
use flowy_folder_pub::folder_builder::ParentChildViews;
|
||||
use flowy_search_pub::entities::FolderIndexManager;
|
||||
use lib_infra::conditional_send_sync_trait;
|
||||
use parking_lot::{Mutex, RwLock};
|
||||
use parking_lot::RwLock;
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::ops::Deref;
|
||||
use std::sync::{Arc, Weak};
|
||||
use tracing::{error, info, instrument};
|
||||
use tracing::{error, info, instrument, trace};
|
||||
|
||||
conditional_send_sync_trait! {
|
||||
"[crate::manager::FolderUser] represents the user for folder.";
|
||||
@ -134,7 +135,7 @@ impl FolderManager {
|
||||
pub async fn get_current_workspace_public_views(&self) -> FlowyResult<Vec<ViewPB>> {
|
||||
let workspace_id = self
|
||||
.mutex_folder
|
||||
.lock()
|
||||
.read()
|
||||
.as_ref()
|
||||
.map(|folder| folder.get_workspace_id());
|
||||
|
||||
@ -367,7 +368,7 @@ impl FolderManager {
|
||||
|
||||
pub async fn get_workspace_pb(&self) -> FlowyResult<WorkspacePB> {
|
||||
let workspace_pb = {
|
||||
let guard = self.mutex_folder.lock();
|
||||
let guard = self.mutex_folder.read();
|
||||
let folder = guard
|
||||
.as_ref()
|
||||
.ok_or(FlowyError::internal().with_context("folder is not initialized"))?;
|
||||
@ -396,7 +397,7 @@ impl FolderManager {
|
||||
async fn get_current_workspace_id(&self) -> FlowyResult<String> {
|
||||
self
|
||||
.mutex_folder
|
||||
.lock()
|
||||
.read()
|
||||
.as_ref()
|
||||
.map(|folder| folder.get_workspace_id())
|
||||
.ok_or(FlowyError::internal().with_context("Unexpected empty workspace id"))
|
||||
@ -409,12 +410,13 @@ impl FolderManager {
|
||||
///
|
||||
/// * `none_callback`: A callback function that is invoked when `mutex_folder` contains `None`.
|
||||
/// * `f2`: A callback function that is invoked when `mutex_folder` contains a `Some` value. The contained folder is passed as an argument to this callback.
|
||||
#[instrument(level = "debug", skip_all)]
|
||||
fn with_folder<F1, F2, Output>(&self, none_callback: F1, f2: F2) -> Output
|
||||
where
|
||||
F1: FnOnce() -> Output,
|
||||
F2: FnOnce(&Folder) -> Output,
|
||||
{
|
||||
let folder = self.mutex_folder.lock();
|
||||
let folder = self.mutex_folder.read();
|
||||
match &*folder {
|
||||
None => none_callback(),
|
||||
Some(folder) => f2(folder),
|
||||
@ -471,7 +473,7 @@ impl FolderManager {
|
||||
);
|
||||
|
||||
if let Ok(workspace_id) = self.get_current_workspace_id().await {
|
||||
let folder = &self.mutex_folder.lock();
|
||||
let folder = &self.mutex_folder.read();
|
||||
if let Some(folder) = folder.as_ref() {
|
||||
notify_did_update_workspace(&workspace_id, folder);
|
||||
}
|
||||
@ -523,8 +525,10 @@ impl FolderManager {
|
||||
/// again using the ID of the child view you wish to access.
|
||||
#[tracing::instrument(level = "debug", skip(self))]
|
||||
pub async fn get_view_pb(&self, view_id: &str) -> FlowyResult<ViewPB> {
|
||||
trace!("Get view pb with id: {}", view_id);
|
||||
let view_id = view_id.to_string();
|
||||
let folder = self.mutex_folder.lock();
|
||||
|
||||
let folder = self.mutex_folder.read();
|
||||
let folder = folder.as_ref().ok_or_else(folder_not_init_error)?;
|
||||
|
||||
// trash views and other private views should not be accessed
|
||||
@ -555,6 +559,30 @@ impl FolderManager {
|
||||
}
|
||||
}
|
||||
|
||||
/// Retrieves all views.
|
||||
///
|
||||
/// It is important to note that this will return a flat map of all views,
|
||||
/// excluding all child views themselves, as they are all at the same level in this
|
||||
/// map.
|
||||
///
|
||||
#[tracing::instrument(level = "debug", skip(self))]
|
||||
pub async fn get_all_views_pb(&self) -> FlowyResult<Vec<ViewPB>> {
|
||||
let folder = self.mutex_folder.read();
|
||||
let folder = folder.as_ref().ok_or_else(folder_not_init_error)?;
|
||||
|
||||
// trash views and other private views should not be accessed
|
||||
let view_ids_should_be_filtered = self.get_view_ids_should_be_filtered(folder);
|
||||
|
||||
let all_views = folder.views.get_all_views();
|
||||
let views = all_views
|
||||
.into_iter()
|
||||
.filter(|view| !view_ids_should_be_filtered.contains(&view.id))
|
||||
.map(view_pb_without_child_views_from_arc)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
Ok(views)
|
||||
}
|
||||
|
||||
/// Retrieves the ancestors of the view corresponding to the specified view ID, including the view itself.
|
||||
///
|
||||
/// For example, if the view hierarchy is as follows:
|
||||
@ -1063,7 +1091,7 @@ impl FolderManager {
|
||||
.send();
|
||||
|
||||
if let Ok(workspace_id) = self.get_current_workspace_id().await {
|
||||
let folder = &self.mutex_folder.lock();
|
||||
let folder = &self.mutex_folder.read();
|
||||
if let Some(folder) = folder.as_ref() {
|
||||
notify_did_update_workspace(&workspace_id, folder);
|
||||
}
|
||||
@ -1318,9 +1346,9 @@ pub(crate) fn get_workspace_private_view_pbs(_workspace_id: &str, folder: &Folde
|
||||
/// The MutexFolder is a wrapper of the [Folder] that is used to share the folder between different
|
||||
/// threads.
|
||||
#[derive(Clone, Default)]
|
||||
pub struct MutexFolder(Arc<Mutex<Option<Folder>>>);
|
||||
pub struct MutexFolder(Arc<RwLock<Option<Folder>>>);
|
||||
impl Deref for MutexFolder {
|
||||
type Target = Arc<Mutex<Option<Folder>>>;
|
||||
type Target = Arc<RwLock<Option<Folder>>>;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
|
@ -133,7 +133,7 @@ impl FolderManager {
|
||||
let index_content_rx = folder.subscribe_index_content();
|
||||
self
|
||||
.folder_indexer
|
||||
.set_index_content_receiver(index_content_rx);
|
||||
.set_index_content_receiver(index_content_rx, workspace_id.clone());
|
||||
|
||||
// Index all views in the folder if needed
|
||||
if !self.folder_indexer.is_indexed() {
|
||||
@ -141,12 +141,13 @@ impl FolderManager {
|
||||
let folder_indexer = self.folder_indexer.clone();
|
||||
|
||||
// We spawn a blocking task to index all views in the folder
|
||||
let wid = workspace_id.clone();
|
||||
spawn_blocking(move || {
|
||||
folder_indexer.index_all_views(views);
|
||||
folder_indexer.index_all_views(views, wid);
|
||||
});
|
||||
}
|
||||
|
||||
*self.mutex_folder.lock() = Some(folder);
|
||||
*self.mutex_folder.write() = Some(folder);
|
||||
|
||||
let weak_mutex_folder = Arc::downgrade(&self.mutex_folder);
|
||||
subscribe_folder_sync_state_changed(workspace_id.clone(), folder_state_rx, &weak_mutex_folder);
|
||||
|
@ -67,7 +67,7 @@ pub(crate) fn subscribe_folder_snapshot_state_changed(
|
||||
af_spawn(async move {
|
||||
if let Some(mutex_folder) = weak_mutex_folder.upgrade() {
|
||||
let stream = mutex_folder
|
||||
.lock()
|
||||
.read()
|
||||
.as_ref()
|
||||
.map(|folder| folder.subscribe_snapshot_state());
|
||||
if let Some(mut state_stream) = stream {
|
||||
@ -119,7 +119,7 @@ pub(crate) fn subscribe_folder_trash_changed(
|
||||
TrashSectionChange::TrashItemAdded { ids } => ids,
|
||||
TrashSectionChange::TrashItemRemoved { ids } => ids,
|
||||
};
|
||||
if let Some(folder) = folder.lock().as_ref() {
|
||||
if let Some(folder) = folder.read().as_ref() {
|
||||
let views = folder.views.get_views(&ids);
|
||||
for view in views {
|
||||
unique_ids.insert(view.parent_view_id.clone());
|
||||
@ -146,7 +146,7 @@ pub(crate) fn notify_parent_view_did_change<T: AsRef<str>>(
|
||||
folder: Arc<MutexFolder>,
|
||||
parent_view_ids: Vec<T>,
|
||||
) -> Option<()> {
|
||||
let folder = folder.lock();
|
||||
let folder = folder.read();
|
||||
let folder = folder.as_ref()?;
|
||||
let workspace_id = folder.get_workspace_id();
|
||||
let trash_ids = folder
|
||||
|
Reference in New Issue
Block a user