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:
@ -1,2 +1,2 @@
|
||||
proto_input = ["src/event_map.rs", "src/entities.rs"]
|
||||
proto_input = ["src/event_map.rs", "src/entities"]
|
||||
event_files = ["src/event_map.rs"]
|
||||
|
30
frontend/rust-lib/flowy-search/src/entities/index_type.rs
Normal file
30
frontend/rust-lib/flowy-search/src/entities/index_type.rs
Normal file
@ -0,0 +1,30 @@
|
||||
use flowy_derive::ProtoBuf_Enum;
|
||||
|
||||
#[derive(ProtoBuf_Enum, Eq, PartialEq, Debug, Clone)]
|
||||
pub enum IndexTypePB {
|
||||
View = 0,
|
||||
DocumentBlock = 1,
|
||||
DatabaseRow = 2,
|
||||
}
|
||||
|
||||
impl Default for IndexTypePB {
|
||||
fn default() -> Self {
|
||||
Self::View
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<IndexTypePB> for i32 {
|
||||
fn from(notification: IndexTypePB) -> Self {
|
||||
notification as i32
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<i32> for IndexTypePB {
|
||||
fn from(notification: i32) -> Self {
|
||||
match notification {
|
||||
1 => IndexTypePB::View,
|
||||
2 => IndexTypePB::DocumentBlock,
|
||||
_ => IndexTypePB::DatabaseRow,
|
||||
}
|
||||
}
|
||||
}
|
11
frontend/rust-lib/flowy-search/src/entities/mod.rs
Normal file
11
frontend/rust-lib/flowy-search/src/entities/mod.rs
Normal file
@ -0,0 +1,11 @@
|
||||
mod index_type;
|
||||
mod notification;
|
||||
mod query;
|
||||
mod result;
|
||||
mod search_filter;
|
||||
|
||||
pub use index_type::*;
|
||||
pub use notification::*;
|
||||
pub use query::*;
|
||||
pub use result::*;
|
||||
pub use search_filter::*;
|
39
frontend/rust-lib/flowy-search/src/entities/notification.rs
Normal file
39
frontend/rust-lib/flowy-search/src/entities/notification.rs
Normal file
@ -0,0 +1,39 @@
|
||||
use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
|
||||
|
||||
use super::SearchResultPB;
|
||||
|
||||
#[derive(ProtoBuf, Default, Debug, Clone)]
|
||||
pub struct SearchResultNotificationPB {
|
||||
#[pb(index = 1)]
|
||||
pub items: Vec<SearchResultPB>,
|
||||
|
||||
#[pb(index = 2)]
|
||||
pub closed: bool,
|
||||
|
||||
#[pb(index = 3, one_of)]
|
||||
pub channel: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(ProtoBuf_Enum, Debug, Default)]
|
||||
pub enum SearchNotification {
|
||||
#[default]
|
||||
Unknown = 0,
|
||||
DidUpdateResults = 1,
|
||||
DidCloseResults = 2,
|
||||
}
|
||||
|
||||
impl std::convert::From<SearchNotification> for i32 {
|
||||
fn from(notification: SearchNotification) -> Self {
|
||||
notification as i32
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<i32> for SearchNotification {
|
||||
fn from(notification: i32) -> Self {
|
||||
match notification {
|
||||
1 => SearchNotification::DidUpdateResults,
|
||||
2 => SearchNotification::DidCloseResults,
|
||||
_ => SearchNotification::Unknown,
|
||||
}
|
||||
}
|
||||
}
|
25
frontend/rust-lib/flowy-search/src/entities/query.rs
Normal file
25
frontend/rust-lib/flowy-search/src/entities/query.rs
Normal file
@ -0,0 +1,25 @@
|
||||
use flowy_derive::ProtoBuf;
|
||||
|
||||
use super::SearchFilterPB;
|
||||
|
||||
#[derive(Eq, PartialEq, ProtoBuf, Default, Debug, Clone)]
|
||||
pub struct SearchQueryPB {
|
||||
#[pb(index = 1)]
|
||||
pub search: String,
|
||||
|
||||
#[pb(index = 2, one_of)]
|
||||
pub limit: Option<i64>,
|
||||
|
||||
#[pb(index = 3, one_of)]
|
||||
pub filter: Option<SearchFilterPB>,
|
||||
|
||||
/// Used to identify the channel of the search
|
||||
///
|
||||
/// This can be used to have multiple search notification listeners in place.
|
||||
/// It is up to the client to decide how to handle this.
|
||||
///
|
||||
/// If not set, then no channel is used.
|
||||
///
|
||||
#[pb(index = 4, one_of)]
|
||||
pub channel: Option<String>,
|
||||
}
|
@ -1,14 +1,7 @@
|
||||
use collab_folder::{IconType, ViewIcon};
|
||||
use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
|
||||
|
||||
#[derive(Eq, PartialEq, ProtoBuf, Default, Debug, Clone)]
|
||||
pub struct SearchQueryPB {
|
||||
#[pb(index = 1)]
|
||||
pub search: String,
|
||||
|
||||
#[pb(index = 2, one_of)]
|
||||
pub limit: Option<i64>,
|
||||
}
|
||||
use super::IndexTypePB;
|
||||
|
||||
#[derive(Debug, Default, ProtoBuf, Clone)]
|
||||
pub struct RepeatedSearchResultPB {
|
||||
@ -35,6 +28,9 @@ pub struct SearchResultPB {
|
||||
|
||||
#[pb(index = 6)]
|
||||
pub score: f64,
|
||||
|
||||
#[pb(index = 7)]
|
||||
pub workspace_id: String,
|
||||
}
|
||||
|
||||
impl SearchResultPB {
|
||||
@ -46,6 +42,7 @@ impl SearchResultPB {
|
||||
data: self.data.clone(),
|
||||
icon: self.icon.clone(),
|
||||
score,
|
||||
workspace_id: self.workspace_id.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -125,65 +122,3 @@ impl From<ViewIcon> for ResultIconPB {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(ProtoBuf_Enum, Eq, PartialEq, Debug, Clone)]
|
||||
pub enum IndexTypePB {
|
||||
View = 0,
|
||||
DocumentBlock = 1,
|
||||
DatabaseRow = 2,
|
||||
}
|
||||
|
||||
impl Default for IndexTypePB {
|
||||
fn default() -> Self {
|
||||
Self::View
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<IndexTypePB> for i32 {
|
||||
fn from(notification: IndexTypePB) -> Self {
|
||||
notification as i32
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<i32> for IndexTypePB {
|
||||
fn from(notification: i32) -> Self {
|
||||
match notification {
|
||||
1 => IndexTypePB::View,
|
||||
2 => IndexTypePB::DocumentBlock,
|
||||
_ => IndexTypePB::DatabaseRow,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(ProtoBuf, Default, Debug, Clone)]
|
||||
pub struct SearchResultNotificationPB {
|
||||
#[pb(index = 1)]
|
||||
pub items: Vec<SearchResultPB>,
|
||||
|
||||
#[pb(index = 2)]
|
||||
pub closed: bool,
|
||||
}
|
||||
|
||||
#[derive(ProtoBuf_Enum, Debug, Default)]
|
||||
pub enum SearchNotification {
|
||||
#[default]
|
||||
Unknown = 0,
|
||||
DidUpdateResults = 1,
|
||||
DidCloseResults = 2,
|
||||
}
|
||||
|
||||
impl std::convert::From<SearchNotification> for i32 {
|
||||
fn from(notification: SearchNotification) -> Self {
|
||||
notification as i32
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<i32> for SearchNotification {
|
||||
fn from(notification: i32) -> Self {
|
||||
match notification {
|
||||
1 => SearchNotification::DidUpdateResults,
|
||||
2 => SearchNotification::DidCloseResults,
|
||||
_ => SearchNotification::Unknown,
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
use flowy_derive::ProtoBuf;
|
||||
|
||||
#[derive(Eq, PartialEq, ProtoBuf, Default, Debug, Clone)]
|
||||
pub struct SearchFilterPB {
|
||||
#[pb(index = 1, one_of)]
|
||||
pub workspace_id: Option<String>,
|
||||
}
|
@ -21,7 +21,7 @@ pub(crate) async fn search_handler(
|
||||
) -> Result<(), FlowyError> {
|
||||
let query = data.into_inner();
|
||||
let manager = upgrade_manager(manager)?;
|
||||
manager.perform_search(query.search);
|
||||
manager.perform_search(query.search, query.filter, query.channel);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ pub struct FolderIndexData {
|
||||
pub title: String,
|
||||
pub icon: String,
|
||||
pub icon_ty: i64,
|
||||
pub workspace_id: String,
|
||||
}
|
||||
|
||||
impl From<FolderIndexData> for SearchResultPB {
|
||||
@ -28,6 +29,7 @@ impl From<FolderIndexData> for SearchResultPB {
|
||||
data: data.title,
|
||||
score: 0.0,
|
||||
icon,
|
||||
workspace_id: data.workspace_id,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
use crate::entities::SearchResultPB;
|
||||
use crate::services::manager::{SearchHandler, SearchType};
|
||||
use crate::{
|
||||
entities::{SearchFilterPB, SearchResultPB},
|
||||
services::manager::{SearchHandler, SearchType},
|
||||
};
|
||||
use flowy_error::FlowyResult;
|
||||
use std::sync::Arc;
|
||||
|
||||
@ -20,8 +22,20 @@ impl SearchHandler for FolderSearchHandler {
|
||||
SearchType::Folder
|
||||
}
|
||||
|
||||
fn perform_search(&self, query: String) -> FlowyResult<Vec<SearchResultPB>> {
|
||||
self.index_manager.search(query)
|
||||
fn perform_search(
|
||||
&self,
|
||||
query: String,
|
||||
filter: Option<SearchFilterPB>,
|
||||
) -> FlowyResult<Vec<SearchResultPB>> {
|
||||
let mut results = self.index_manager.search(query, filter.clone())?;
|
||||
if let Some(filter) = filter {
|
||||
if let Some(workspace_id) = filter.workspace_id {
|
||||
// Filter results by workspace ID
|
||||
results.retain(|result| result.workspace_id == workspace_id);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(results)
|
||||
}
|
||||
|
||||
fn index_count(&self) -> u64 {
|
||||
|
@ -8,8 +8,11 @@ use std::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
entities::ResultIconTypePB,
|
||||
folder::schema::{FolderSchema, FOLDER_ICON_FIELD_NAME, FOLDER_TITLE_FIELD_NAME},
|
||||
entities::{ResultIconTypePB, SearchFilterPB, SearchResultPB},
|
||||
folder::schema::{
|
||||
FolderSchema, FOLDER_ICON_FIELD_NAME, FOLDER_ICON_TY_FIELD_NAME, FOLDER_ID_FIELD_NAME,
|
||||
FOLDER_TITLE_FIELD_NAME, FOLDER_WORKSPACE_ID_FIELD_NAME,
|
||||
},
|
||||
};
|
||||
use collab::core::collab::{IndexContent, IndexContentReceiver};
|
||||
use collab_folder::{View, ViewIcon, ViewIndexContent, ViewLayout};
|
||||
@ -23,12 +26,7 @@ use tantivy::{
|
||||
IndexWriter, Term,
|
||||
};
|
||||
|
||||
use crate::entities::SearchResultPB;
|
||||
|
||||
use super::{
|
||||
entities::FolderIndexData,
|
||||
schema::{FOLDER_ICON_TY_FIELD_NAME, FOLDER_ID_FIELD_NAME},
|
||||
};
|
||||
use super::entities::FolderIndexData;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct FolderIndexManagerImpl {
|
||||
@ -41,7 +39,15 @@ pub struct FolderIndexManagerImpl {
|
||||
const FOLDER_INDEX_DIR: &str = "folder_index";
|
||||
|
||||
impl FolderIndexManagerImpl {
|
||||
pub fn new(auth_user: Weak<AuthenticateUser>) -> Self {
|
||||
pub fn new(auth_user: Option<Weak<AuthenticateUser>>) -> Self {
|
||||
// TODO(Mathias): Temporarily disable seaerch
|
||||
let auth_user = match auth_user {
|
||||
Some(auth_user) => auth_user,
|
||||
None => {
|
||||
return FolderIndexManagerImpl::empty();
|
||||
},
|
||||
};
|
||||
|
||||
// AuthenticateUser is required to get the index path
|
||||
let authenticate_user = auth_user.upgrade();
|
||||
|
||||
@ -130,15 +136,19 @@ impl FolderIndexManagerImpl {
|
||||
let title_field = folder_schema.schema.get_field(FOLDER_TITLE_FIELD_NAME)?;
|
||||
let icon_field = folder_schema.schema.get_field(FOLDER_ICON_FIELD_NAME)?;
|
||||
let icon_ty_field = folder_schema.schema.get_field(FOLDER_ICON_TY_FIELD_NAME)?;
|
||||
let workspace_id_field = folder_schema
|
||||
.schema
|
||||
.get_field(FOLDER_WORKSPACE_ID_FIELD_NAME)?;
|
||||
|
||||
for data in indexes {
|
||||
let (icon, icon_ty) = self.extract_icon(data.icon, data.layout);
|
||||
|
||||
let _ = index_writer.add_document(doc![
|
||||
id_field => data.id.clone(),
|
||||
title_field => data.data.clone(),
|
||||
icon_field => icon.unwrap_or_default(),
|
||||
icon_ty_field => icon_ty,
|
||||
id_field => data.id.clone(),
|
||||
title_field => data.data.clone(),
|
||||
icon_field => icon.unwrap_or_default(),
|
||||
icon_ty_field => icon_ty,
|
||||
workspace_id_field => data.workspace_id.clone(),
|
||||
]);
|
||||
}
|
||||
|
||||
@ -206,7 +216,11 @@ impl FolderIndexManagerImpl {
|
||||
(icon, icon_ty)
|
||||
}
|
||||
|
||||
pub fn search(&self, query: String) -> Result<Vec<SearchResultPB>, FlowyError> {
|
||||
pub fn search(
|
||||
&self,
|
||||
query: String,
|
||||
_filter: Option<SearchFilterPB>,
|
||||
) -> Result<Vec<SearchResultPB>, FlowyError> {
|
||||
let folder_schema = self.get_folder_schema()?;
|
||||
|
||||
let index = match &self.index {
|
||||
@ -222,11 +236,7 @@ impl FolderIndexManagerImpl {
|
||||
let title_field = folder_schema.schema.get_field(FOLDER_TITLE_FIELD_NAME)?;
|
||||
|
||||
let length = query.len();
|
||||
let distance: u8 = match length {
|
||||
_ if length > 4 => 2,
|
||||
_ if length > 2 => 1,
|
||||
_ => 0,
|
||||
};
|
||||
let distance: u8 = if length >= 2 { 2 } else { 1 };
|
||||
|
||||
let mut query_parser = QueryParser::for_index(&index.clone(), vec![title_field]);
|
||||
query_parser.set_field_fuzzy(title_field, true, distance, true);
|
||||
@ -273,8 +283,9 @@ impl IndexManager for FolderIndexManagerImpl {
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
fn set_index_content_receiver(&self, mut rx: IndexContentReceiver) {
|
||||
fn set_index_content_receiver(&self, mut rx: IndexContentReceiver, workspace_id: String) {
|
||||
let indexer = self.clone();
|
||||
let wid = workspace_id.clone();
|
||||
af_spawn(async move {
|
||||
while let Ok(msg) = rx.recv().await {
|
||||
match msg {
|
||||
@ -285,6 +296,7 @@ impl IndexManager for FolderIndexManagerImpl {
|
||||
data: view.name,
|
||||
icon: view.icon,
|
||||
layout: view.layout,
|
||||
workspace_id: wid.clone(),
|
||||
});
|
||||
},
|
||||
Err(err) => tracing::error!("FolderIndexManager error deserialize: {:?}", err),
|
||||
@ -296,6 +308,7 @@ impl IndexManager for FolderIndexManagerImpl {
|
||||
data: view.name,
|
||||
icon: view.icon,
|
||||
layout: view.layout,
|
||||
workspace_id: wid.clone(),
|
||||
});
|
||||
},
|
||||
Err(err) => tracing::error!("FolderIndexManager error deserialize: {:?}", err),
|
||||
@ -317,7 +330,11 @@ impl IndexManager for FolderIndexManagerImpl {
|
||||
let id_field = folder_schema.schema.get_field(FOLDER_ID_FIELD_NAME)?;
|
||||
let title_field = folder_schema.schema.get_field(FOLDER_TITLE_FIELD_NAME)?;
|
||||
let icon_field = folder_schema.schema.get_field(FOLDER_ICON_FIELD_NAME)?;
|
||||
let icon_ty_field = folder_schema.schema.get_field(FOLDER_ICON_TY_FIELD_NAME)?;
|
||||
let icon_ty_field: tantivy::schema::Field =
|
||||
folder_schema.schema.get_field(FOLDER_ICON_TY_FIELD_NAME)?;
|
||||
let workspace_id_field = folder_schema
|
||||
.schema
|
||||
.get_field(FOLDER_WORKSPACE_ID_FIELD_NAME)?;
|
||||
|
||||
let delete_term = Term::from_field_text(id_field, &data.id.clone());
|
||||
|
||||
@ -332,6 +349,7 @@ impl IndexManager for FolderIndexManagerImpl {
|
||||
title_field => data.data,
|
||||
icon_field => icon.unwrap_or_default(),
|
||||
icon_ty_field => icon_ty,
|
||||
workspace_id_field => data.workspace_id.clone(),
|
||||
]);
|
||||
|
||||
index_writer.commit()?;
|
||||
@ -364,6 +382,9 @@ impl IndexManager for FolderIndexManagerImpl {
|
||||
let title_field = folder_schema.schema.get_field(FOLDER_TITLE_FIELD_NAME)?;
|
||||
let icon_field = folder_schema.schema.get_field(FOLDER_ICON_FIELD_NAME)?;
|
||||
let icon_ty_field = folder_schema.schema.get_field(FOLDER_ICON_TY_FIELD_NAME)?;
|
||||
let workspace_id_field = folder_schema
|
||||
.schema
|
||||
.get_field(FOLDER_WORKSPACE_ID_FIELD_NAME)?;
|
||||
|
||||
let (icon, icon_ty) = self.extract_icon(data.icon, data.layout);
|
||||
|
||||
@ -373,6 +394,7 @@ impl IndexManager for FolderIndexManagerImpl {
|
||||
title_field => data.data,
|
||||
icon_field => icon.unwrap_or_default(),
|
||||
icon_ty_field => icon_ty,
|
||||
workspace_id_field => data.workspace_id,
|
||||
]);
|
||||
|
||||
index_writer.commit()?;
|
||||
@ -386,7 +408,7 @@ impl IndexManager for FolderIndexManagerImpl {
|
||||
}
|
||||
|
||||
impl FolderIndexManager for FolderIndexManagerImpl {
|
||||
fn index_all_views(&self, views: Vec<View>) {
|
||||
fn index_all_views(&self, views: Vec<View>, workspace_id: String) {
|
||||
let indexable_data = views
|
||||
.into_iter()
|
||||
.map(|view| IndexableData {
|
||||
@ -394,6 +416,7 @@ impl FolderIndexManager for FolderIndexManagerImpl {
|
||||
data: view.name,
|
||||
icon: view.icon,
|
||||
layout: view.layout,
|
||||
workspace_id: workspace_id.clone(),
|
||||
})
|
||||
.collect();
|
||||
|
||||
|
@ -4,6 +4,7 @@ pub const FOLDER_ID_FIELD_NAME: &str = "id";
|
||||
pub const FOLDER_TITLE_FIELD_NAME: &str = "title";
|
||||
pub const FOLDER_ICON_FIELD_NAME: &str = "icon";
|
||||
pub const FOLDER_ICON_TY_FIELD_NAME: &str = "icon_ty";
|
||||
pub const FOLDER_WORKSPACE_ID_FIELD_NAME: &str = "workspace_id";
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct FolderSchema {
|
||||
@ -33,6 +34,10 @@ impl FolderSchema {
|
||||
tantivy::schema::TEXT | tantivy::schema::STORED,
|
||||
);
|
||||
schema_builder.add_i64_field(FOLDER_ICON_TY_FIELD_NAME, tantivy::schema::STORED);
|
||||
schema_builder.add_text_field(
|
||||
FOLDER_WORKSPACE_ID_FIELD_NAME,
|
||||
tantivy::schema::TEXT | tantivy::schema::STORED,
|
||||
);
|
||||
|
||||
let schema = schema_builder.build();
|
||||
|
||||
|
@ -5,7 +5,7 @@ use flowy_error::FlowyResult;
|
||||
use lib_dispatch::prelude::af_spawn;
|
||||
use tokio::{sync::broadcast, task::spawn_blocking};
|
||||
|
||||
use crate::entities::{SearchResultNotificationPB, SearchResultPB};
|
||||
use crate::entities::{SearchFilterPB, SearchResultNotificationPB, SearchResultPB};
|
||||
|
||||
use super::notifier::{SearchNotifier, SearchResultChanged, SearchResultReceiverRunner};
|
||||
|
||||
@ -18,7 +18,11 @@ pub trait SearchHandler: Send + Sync + 'static {
|
||||
/// returns the type of search this handler is responsible for
|
||||
fn search_type(&self) -> SearchType;
|
||||
/// performs a search and returns the results
|
||||
fn perform_search(&self, query: String) -> FlowyResult<Vec<SearchResultPB>>;
|
||||
fn perform_search(
|
||||
&self,
|
||||
query: String,
|
||||
filter: Option<SearchFilterPB>,
|
||||
) -> FlowyResult<Vec<SearchResultPB>>;
|
||||
/// returns the number of indexed objects
|
||||
fn index_count(&self) -> u64;
|
||||
}
|
||||
@ -50,17 +54,24 @@ impl SearchManager {
|
||||
self.handlers.get(&search_type)
|
||||
}
|
||||
|
||||
pub fn perform_search(&self, query: String) {
|
||||
pub fn perform_search(
|
||||
&self,
|
||||
query: String,
|
||||
filter: Option<SearchFilterPB>,
|
||||
channel: Option<String>,
|
||||
) {
|
||||
let mut sends: usize = 0;
|
||||
let max: usize = self.handlers.len();
|
||||
let handlers = self.handlers.clone();
|
||||
|
||||
for (_, handler) in handlers {
|
||||
let q = query.clone();
|
||||
let f = filter.clone();
|
||||
let ch = channel.clone();
|
||||
let notifier = self.notifier.clone();
|
||||
|
||||
spawn_blocking(move || {
|
||||
let res = handler.perform_search(q);
|
||||
let res = handler.perform_search(q, f);
|
||||
sends += 1;
|
||||
|
||||
let close = sends == max;
|
||||
@ -68,6 +79,7 @@ impl SearchManager {
|
||||
let notification = SearchResultNotificationPB {
|
||||
items,
|
||||
closed: close,
|
||||
channel: ch,
|
||||
};
|
||||
|
||||
let _ = notifier.send(SearchResultChanged::SearchResultUpdate(notification));
|
||||
|
@ -37,7 +37,7 @@ impl SearchResultReceiverRunner {
|
||||
SearchNotification::DidUpdateResults
|
||||
};
|
||||
|
||||
send_notification(SEARCH_ID, ty)
|
||||
send_notification(SEARCH_ID, ty, notification.channel.clone())
|
||||
.payload(notification)
|
||||
.send();
|
||||
},
|
||||
@ -48,6 +48,16 @@ impl SearchResultReceiverRunner {
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "trace")]
|
||||
pub fn send_notification(id: &str, ty: SearchNotification) -> NotificationBuilder {
|
||||
NotificationBuilder::new(id, ty, SEARCH_OBSERVABLE_SOURCE)
|
||||
pub fn send_notification(
|
||||
id: &str,
|
||||
ty: SearchNotification,
|
||||
channel: Option<String>,
|
||||
) -> NotificationBuilder {
|
||||
let observable_source = &format!(
|
||||
"{}{}",
|
||||
SEARCH_OBSERVABLE_SOURCE,
|
||||
channel.unwrap_or_default()
|
||||
);
|
||||
|
||||
NotificationBuilder::new(id, ty, observable_source)
|
||||
}
|
||||
|
Reference in New Issue
Block a user