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:
Mathias Mogensen
2024-04-23 15:46:57 +02:00
committed by GitHub
parent bf64b0d2fa
commit 275d0b2ac4
91 changed files with 1057 additions and 848 deletions

View File

@ -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 {

View File

@ -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>,

View File

@ -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,

View File

@ -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
}

View File

@ -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);

View File

@ -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