diff --git a/frontend/appflowy_flutter/lib/workspace/presentation/command_palette/widgets/search_field.dart b/frontend/appflowy_flutter/lib/workspace/presentation/command_palette/widgets/search_field.dart index d171123e7d..545905d918 100644 --- a/frontend/appflowy_flutter/lib/workspace/presentation/command_palette/widgets/search_field.dart +++ b/frontend/appflowy_flutter/lib/workspace/presentation/command_palette/widgets/search_field.dart @@ -12,12 +12,37 @@ import 'package:flowy_infra_ui/widget/flowy_tooltip.dart'; import 'package:flowy_infra_ui/widget/spacing.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -class SearchField extends StatelessWidget { +class SearchField extends StatefulWidget { const SearchField({super.key, this.query, this.isLoading = false}); final String? query; final bool isLoading; + @override + State createState() => _SearchFieldState(); +} + +class _SearchFieldState extends State { + final focusNode = FocusNode(); + late final controller = TextEditingController(text: widget.query); + + @override + void initState() { + super.initState(); + focusNode.requestFocus(); + controller.selection = TextSelection( + baseOffset: 0, + extentOffset: controller.text.length, + ); + } + + @override + void dispose() { + focusNode.dispose(); + controller.dispose(); + super.dispose(); + } + @override Widget build(BuildContext context) { return Row( @@ -29,7 +54,8 @@ class SearchField extends StatelessWidget { ), Expanded( child: FlowyTextField( - controller: TextEditingController(text: query), + focusNode: focusNode, + controller: controller, textStyle: Theme.of(context).textTheme.bodySmall?.copyWith(fontSize: 14), decoration: InputDecoration( @@ -84,7 +110,7 @@ class SearchField extends StatelessWidget { .add(CommandPaletteEvent.searchChanged(search: value)), ), ), - if (isLoading) ...[ + if (widget.isLoading) ...[ const HSpace(12), FlowyTooltip( message: LocaleKeys.commandPalette_loadingTooltip.tr(), diff --git a/frontend/appflowy_tauri/src-tauri/Cargo.toml b/frontend/appflowy_tauri/src-tauri/Cargo.toml index 5f9b079392..ea09264aad 100644 --- a/frontend/appflowy_tauri/src-tauri/Cargo.toml +++ b/frontend/appflowy_tauri/src-tauri/Cargo.toml @@ -112,4 +112,4 @@ collab-folder = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlow collab-document = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6febf0397e66ebf0a281980a2e7602d7af00c975" } collab-database = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6febf0397e66ebf0a281980a2e7602d7af00c975" } collab-plugins = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6febf0397e66ebf0a281980a2e7602d7af00c975" } -collab-user = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6febf0397e66ebf0a281980a2e7602d7af00c975" } \ No newline at end of file +collab-user = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6febf0397e66ebf0a281980a2e7602d7af00c975" } diff --git a/frontend/appflowy_web/wasm-libs/Cargo.toml b/frontend/appflowy_web/wasm-libs/Cargo.toml index 225c339b1c..2f0c25023a 100644 --- a/frontend/appflowy_web/wasm-libs/Cargo.toml +++ b/frontend/appflowy_web/wasm-libs/Cargo.toml @@ -76,4 +76,4 @@ collab-folder = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlow collab-document = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6febf0397e66ebf0a281980a2e7602d7af00c975" } collab-database = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6febf0397e66ebf0a281980a2e7602d7af00c975" } collab-plugins = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6febf0397e66ebf0a281980a2e7602d7af00c975" } -collab-user = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6febf0397e66ebf0a281980a2e7602d7af00c975" } \ No newline at end of file +collab-user = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6febf0397e66ebf0a281980a2e7602d7af00c975" } diff --git a/frontend/appflowy_web_app/src-tauri/Cargo.lock b/frontend/appflowy_web_app/src-tauri/Cargo.lock index 2ba17e8683..43806f61fb 100644 --- a/frontend/appflowy_web_app/src-tauri/Cargo.lock +++ b/frontend/appflowy_web_app/src-tauri/Cargo.lock @@ -2173,6 +2173,7 @@ dependencies = [ "nanoid", "parking_lot 0.12.1", "protobuf", + "serde", "serde_json", "strum_macros 0.21.1", "tokio", diff --git a/frontend/appflowy_web_app/src-tauri/Cargo.toml b/frontend/appflowy_web_app/src-tauri/Cargo.toml index 21df3b1bbc..8625530b8c 100644 --- a/frontend/appflowy_web_app/src-tauri/Cargo.toml +++ b/frontend/appflowy_web_app/src-tauri/Cargo.toml @@ -113,4 +113,4 @@ collab-folder = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlow collab-document = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6febf0397e66ebf0a281980a2e7602d7af00c975" } collab-database = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6febf0397e66ebf0a281980a2e7602d7af00c975" } collab-plugins = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6febf0397e66ebf0a281980a2e7602d7af00c975" } -collab-user = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6febf0397e66ebf0a281980a2e7602d7af00c975" } \ No newline at end of file +collab-user = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "6febf0397e66ebf0a281980a2e7602d7af00c975" } diff --git a/frontend/rust-lib/flowy-core/src/deps_resolve/folder_deps.rs b/frontend/rust-lib/flowy-core/src/deps_resolve/folder_deps.rs index e826a3f4c4..5c383d204a 100644 --- a/frontend/rust-lib/flowy-core/src/deps_resolve/folder_deps.rs +++ b/frontend/rust-lib/flowy-core/src/deps_resolve/folder_deps.rs @@ -33,28 +33,21 @@ pub struct FolderDepsResolver(); impl FolderDepsResolver { pub async fn resolve( authenticate_user: Weak, - document_manager: &Arc, - database_manager: &Arc, collab_builder: Arc, server_provider: Arc, folder_indexer: Arc, store_preferences: Arc, - chat_manager: &Arc, + operation_handlers: FolderOperationHandlers, ) -> Arc { let user: Arc = Arc::new(FolderUserImpl { authenticate_user: authenticate_user.clone(), }); - let handlers = folder_operation_handlers( - document_manager.clone(), - database_manager.clone(), - chat_manager.clone(), - ); Arc::new( FolderManager::new( user.clone(), collab_builder, - handlers, + operation_handlers, server_provider.clone(), folder_indexer, store_preferences, @@ -64,7 +57,7 @@ impl FolderDepsResolver { } } -fn folder_operation_handlers( +pub fn folder_operation_handlers( document_manager: Arc, database_manager: Arc, chat_manager: Arc, diff --git a/frontend/rust-lib/flowy-core/src/deps_resolve/user_deps.rs b/frontend/rust-lib/flowy-core/src/deps_resolve/user_deps.rs index b8d18af390..1d580e6cee 100644 --- a/frontend/rust-lib/flowy-core/src/deps_resolve/user_deps.rs +++ b/frontend/rust-lib/flowy-core/src/deps_resolve/user_deps.rs @@ -59,4 +59,12 @@ impl UserWorkspaceService for UserWorkspaceServiceImpl { .await?; Ok(()) } + + fn did_delete_workspace(&self, workspace_id: String) -> FlowyResult<()> { + self + .folder_manager + .remove_indices_for_workspace(workspace_id)?; + + Ok(()) + } } diff --git a/frontend/rust-lib/flowy-core/src/lib.rs b/frontend/rust-lib/flowy-core/src/lib.rs index 02f63c6f1d..c0cf2b9491 100644 --- a/frontend/rust-lib/flowy-core/src/lib.rs +++ b/frontend/rust-lib/flowy-core/src/lib.rs @@ -173,15 +173,20 @@ impl AppFlowyCore { let folder_indexer = Arc::new(FolderIndexManagerImpl::new(Some(Arc::downgrade( &authenticate_user, )))); + + let folder_operation_handlers = folder_operation_handlers( + document_manager.clone(), + database_manager.clone(), + chat_manager.clone(), + ); + let folder_manager = FolderDepsResolver::resolve( Arc::downgrade(&authenticate_user), - &document_manager, - &database_manager, collab_builder.clone(), server_provider.clone(), folder_indexer.clone(), store_preference.clone(), - &chat_manager, + folder_operation_handlers, ) .await; diff --git a/frontend/rust-lib/flowy-folder/src/entities/workspace.rs b/frontend/rust-lib/flowy-folder/src/entities/workspace.rs index e78eb6e307..21ff046226 100644 --- a/frontend/rust-lib/flowy-folder/src/entities/workspace.rs +++ b/frontend/rust-lib/flowy-folder/src/entities/workspace.rs @@ -232,8 +232,3 @@ pub struct UserFolderPB { #[pb(index = 2)] pub workspace_id: String, } - -#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, Eq, PartialEq)] -pub struct IndexedWorkspaceIds { - pub workspace_ids: Vec, -} diff --git a/frontend/rust-lib/flowy-folder/src/manager.rs b/frontend/rust-lib/flowy-folder/src/manager.rs index 71be3778ee..265fa5118b 100644 --- a/frontend/rust-lib/flowy-folder/src/manager.rs +++ b/frontend/rust-lib/flowy-folder/src/manager.rs @@ -1201,6 +1201,14 @@ impl FolderManager { .filter(|id| !my_private_view_ids.contains(id)) .collect() } + + pub fn remove_indices_for_workspace(&self, workspace_id: String) -> FlowyResult<()> { + self + .folder_indexer + .remove_indices_for_workspace(workspace_id)?; + + Ok(()) + } } /// Return the views that belong to the workspace. The views are filtered by the trash and all the private views. diff --git a/frontend/rust-lib/flowy-folder/src/manager_init.rs b/frontend/rust-lib/flowy-folder/src/manager_init.rs index 07fc973f05..d1266a146e 100644 --- a/frontend/rust-lib/flowy-folder/src/manager_init.rs +++ b/frontend/rust-lib/flowy-folder/src/manager_init.rs @@ -1,9 +1,8 @@ -use crate::entities::IndexedWorkspaceIds; use crate::manager::{FolderInitDataSource, FolderManager}; use crate::manager_observer::*; use crate::user_default::DefaultFolderBuilder; use collab::core::collab::DataSource; -use collab_entity::CollabType; +use collab_entity::{CollabType, EncodedCollab}; use collab_folder::{Folder, FolderNotify, UserId}; use collab_integrate::CollabKVDB; use flowy_error::{FlowyError, FlowyResult}; @@ -11,8 +10,6 @@ use std::sync::{Arc, Weak}; use tokio::task::spawn_blocking; use tracing::{event, info, Level}; -pub const INDEXED_WORKSPACE_KEY: &str = "indexed-workspace-ids"; - impl FolderManager { /// Called immediately after the application launched if the user already sign in/sign up. #[tracing::instrument(level = "info", skip(self, initial_data), err)] @@ -187,28 +184,27 @@ impl FolderManager { } fn handle_index_folder(&self, workspace_id: String, folder: &Folder) { - let index_all; - if self.folder_indexer.is_indexed() { - // If indexes already exist, we check if the workspace was - // previously indexed, if it wasn't we index all - let indexed_ids = self - .store_preferences - .get_object::(INDEXED_WORKSPACE_KEY); - if let Some(indexed_ids) = indexed_ids { - index_all = !indexed_ids.workspace_ids.contains(&workspace_id.clone()); - if !index_all { - let mut workspace_ids = indexed_ids.workspace_ids.clone(); - workspace_ids.push(workspace_id.clone()); - let _ = self - .store_preferences - .set_object(INDEXED_WORKSPACE_KEY, IndexedWorkspaceIds { workspace_ids }); + let mut index_all = true; + + let encoded_collab = self + .store_preferences + .get_object::(&workspace_id); + + if let Some(encoded_collab) = encoded_collab { + if let Ok(changes) = folder.calculate_view_changes(encoded_collab) { + let folder_indexer = self.folder_indexer.clone(); + + let views = folder.views.get_all_views(); + let wid = workspace_id.clone(); + + if !changes.is_empty() && !views.is_empty() { + spawn_blocking(move || { + // We index the changes + folder_indexer.index_view_changes(views, changes, wid); + }); + index_all = false; } - } else { - index_all = true; } - } else { - // If there exists no indexes, we index all views in workspace - index_all = true; } if index_all { @@ -218,8 +214,24 @@ impl FolderManager { // We spawn a blocking task to index all views in the folder spawn_blocking(move || { + // We remove old indexes just in case + let _ = folder_indexer.remove_indices_for_workspace(wid.clone()); + + // We index all views from the workspace folder_indexer.index_all_views(views, wid); }); } + + self.save_collab_to_preferences(folder); + } + + fn save_collab_to_preferences(&self, folder: &Folder) { + let encoded_collab = folder.encode_collab_v1(); + + if let Ok(encoded) = encoded_collab { + let _ = self + .store_preferences + .set_object(&folder.get_workspace_id(), encoded); + } } } diff --git a/frontend/rust-lib/flowy-search-pub/src/entities.rs b/frontend/rust-lib/flowy-search-pub/src/entities.rs index 8b9b4a3cb6..65e23a9ddb 100644 --- a/frontend/rust-lib/flowy-search-pub/src/entities.rs +++ b/frontend/rust-lib/flowy-search-pub/src/entities.rs @@ -2,7 +2,7 @@ use std::any::Any; use std::sync::Arc; use collab::core::collab::IndexContentReceiver; -use collab_folder::{View, ViewIcon, ViewLayout}; +use collab_folder::{folder_diff::FolderViewChange, View, ViewIcon, ViewLayout}; use flowy_error::FlowyError; pub struct IndexableData { @@ -30,6 +30,7 @@ pub trait IndexManager: Send + Sync { fn add_index(&self, data: IndexableData) -> Result<(), FlowyError>; fn update_index(&self, data: IndexableData) -> Result<(), FlowyError>; fn remove_indices(&self, ids: Vec) -> Result<(), FlowyError>; + fn remove_indices_for_workspace(&self, workspace_id: String) -> Result<(), FlowyError>; fn is_indexed(&self) -> bool; fn as_any(&self) -> &dyn Any; @@ -37,4 +38,10 @@ pub trait IndexManager: Send + Sync { pub trait FolderIndexManager: IndexManager { fn index_all_views(&self, views: Vec>, workspace_id: String); + fn index_view_changes( + &self, + views: Vec>, + changes: Vec, + workspace_id: String, + ); } diff --git a/frontend/rust-lib/flowy-search/src/folder/indexer.rs b/frontend/rust-lib/flowy-search/src/folder/indexer.rs index 39192806b8..146da46a49 100644 --- a/frontend/rust-lib/flowy-search/src/folder/indexer.rs +++ b/frontend/rust-lib/flowy-search/src/folder/indexer.rs @@ -15,15 +15,15 @@ use crate::{ }, }; use collab::core::collab::{IndexContent, IndexContentReceiver}; -use collab_folder::{View, ViewIcon, ViewIndexContent, ViewLayout}; +use collab_folder::{folder_diff::FolderViewChange, View, ViewIcon, ViewIndexContent, ViewLayout}; use flowy_error::{FlowyError, FlowyResult}; use flowy_search_pub::entities::{FolderIndexManager, IndexManager, IndexableData}; use flowy_user::services::authenticate_user::AuthenticateUser; use lib_dispatch::prelude::af_spawn; use strsim::levenshtein; use tantivy::{ - collector::TopDocs, directory::MmapDirectory, doc, query::QueryParser, Index, IndexReader, - IndexWriter, Term, + collector::TopDocs, directory::MmapDirectory, doc, query::QueryParser, schema::Field, Index, + IndexReader, IndexWriter, Term, }; use super::entities::FolderIndexData; @@ -40,7 +40,6 @@ const FOLDER_INDEX_DIR: &str = "folder_index"; impl FolderIndexManagerImpl { pub fn new(auth_user: Option>) -> Self { - // TODO(Mathias): Temporarily disable seaerch let auth_user = match auth_user { Some(auth_user) => auth_user, None => { @@ -74,52 +73,45 @@ impl FolderIndexManagerImpl { } } - // We open the existing or newly created folder_index directory - // This is required by the Tantivy Index, as it will use it to store - // and read index data - let dir = MmapDirectory::open(index_path); - if let Err(e) = dir { - tracing::error!("FolderIndexManager failed to open index directory: {:?}", e); - return FolderIndexManagerImpl::empty(); - } - // The folder schema is used to define the fields of the index along // with how they are stored and if the field is indexed let folder_schema = FolderSchema::new(); - // We open or create an index that takes the directory r/w and the schema. - let index_res = Index::open_or_create(dir.unwrap(), folder_schema.schema.clone()); - if let Err(e) = index_res { - tracing::error!("FolderIndexManager failed to open index: {:?}", e); - return FolderIndexManagerImpl::empty(); - } + // We open the existing or newly created folder_index directory + // This is required by the Tantivy Index, as it will use it to store + // and read index data + let index = match MmapDirectory::open(index_path) { + // We open or create an index that takes the directory r/w and the schema. + Ok(dir) => match Index::open_or_create(dir, folder_schema.schema.clone()) { + Ok(index) => index, + Err(e) => { + tracing::error!("FolderIndexManager failed to open index: {:?}", e); + return FolderIndexManagerImpl::empty(); + }, + }, + Err(e) => { + tracing::error!("FolderIndexManager failed to open index directory: {:?}", e); + return FolderIndexManagerImpl::empty(); + }, + }; - let index = index_res.unwrap(); - - // We read the index reader, we only need one IndexReader per index + // We only need one IndexReader per index let index_reader = index.reader(); - if let Err(e) = index_reader { - tracing::error!( - "FolderIndexManager failed to instantiate index reader: {:?}", - e - ); - return FolderIndexManagerImpl::empty(); - } - let index_writer = index.writer(50_000_000); - if let Err(e) = index_writer { - tracing::error!( - "FolderIndexManager failed to instantiate index writer: {:?}", - e - ); - return FolderIndexManagerImpl::empty(); - } + + let (index_reader, index_writer) = match (index_reader, index_writer) { + (Ok(reader), Ok(writer)) => (reader, writer), + _ => { + tracing::error!("FolderIndexManager failed to instantiate index writer and/or reader"); + return FolderIndexManagerImpl::empty(); + }, + }; Self { folder_schema: Some(folder_schema), index: Some(index), - index_reader: Some(index_reader.unwrap()), - index_writer: Some(Arc::new(Mutex::new(index_writer.unwrap()))), + index_reader: Some(index_reader), + index_writer: Some(Arc::new(Mutex::new(index_writer))), } } @@ -129,7 +121,6 @@ impl FolderIndexManagerImpl { } let mut index_writer = self.get_index_writer()?; - let folder_schema = self.get_folder_schema()?; let id_field = folder_schema.schema.get_field(FOLDER_ID_FIELD_NAME)?; @@ -223,15 +214,11 @@ impl FolderIndexManagerImpl { ) -> Result, FlowyError> { let folder_schema = self.get_folder_schema()?; - let index = match &self.index { - Some(index) => index, - None => return Err(FlowyError::folder_index_manager_unavailable()), - }; - - let index_reader = match &self.index_reader { - Some(index_reader) => index_reader, - None => return Err(FlowyError::folder_index_manager_unavailable()), - }; + let (index, index_reader) = self + .index + .as_ref() + .zip(self.index_reader.as_ref()) + .ok_or_else(FlowyError::folder_index_manager_unavailable)?; let title_field = folder_schema.schema.get_field(FOLDER_TITLE_FIELD_NAME)?; @@ -272,6 +259,29 @@ impl FolderIndexManagerImpl { let distance = levenshtein(query, term) as f64; 1.0 / (distance + 1.0) } + + fn get_schema_fields(&self) -> Result<(Field, Field, Field, Field, Field), FlowyError> { + let folder_schema = match self.folder_schema.clone() { + Some(schema) => schema, + _ => return Err(FlowyError::folder_index_manager_unavailable()), + }; + + 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 workspace_id_field = folder_schema + .schema + .get_field(FOLDER_WORKSPACE_ID_FIELD_NAME)?; + + Ok(( + id_field, + title_field, + icon_field, + icon_ty_field, + workspace_id_field, + )) + } } impl IndexManager for FolderIndexManagerImpl { @@ -288,9 +298,12 @@ impl IndexManager for FolderIndexManagerImpl { let wid = workspace_id.clone(); af_spawn(async move { while let Ok(msg) = rx.recv().await { + tracing::warn!("[Indexer] Message received: {:?}", msg); match msg { IndexContent::Create(value) => match serde_json::from_value::(value) { Ok(view) => { + tracing::warn!("[Indexer] CREATE: {:?}", view); + let _ = indexer.add_index(IndexableData { id: view.id, data: view.name, @@ -303,6 +316,7 @@ impl IndexManager for FolderIndexManagerImpl { }, IndexContent::Update(value) => match serde_json::from_value::(value) { Ok(view) => { + tracing::warn!("[Indexer] UPDATE: {:?}", view); let _ = indexer.update_index(IndexableData { id: view.id, data: view.name, @@ -314,6 +328,7 @@ impl IndexManager for FolderIndexManagerImpl { Err(err) => tracing::error!("FolderIndexManager error deserialize: {:?}", err), }, IndexContent::Delete(ids) => { + tracing::warn!("[Indexer] DELETE: {:?}", ids); if let Err(e) = indexer.remove_indices(ids) { tracing::error!("FolderIndexManager error deserialize: {:?}", e); } @@ -326,15 +341,8 @@ impl IndexManager for FolderIndexManagerImpl { fn update_index(&self, data: IndexableData) -> Result<(), FlowyError> { let mut index_writer = self.get_index_writer()?; - let folder_schema = self.get_folder_schema()?; - 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: 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 (id_field, title_field, icon_field, icon_ty_field, workspace_id_field) = + self.get_schema_fields()?; let delete_term = Term::from_field_text(id_field, &data.id.clone()); @@ -361,7 +369,6 @@ impl IndexManager for FolderIndexManagerImpl { let mut index_writer = self.get_index_writer()?; let folder_schema = self.get_folder_schema()?; - let id_field = folder_schema.schema.get_field(FOLDER_ID_FIELD_NAME)?; for id in ids { let delete_term = Term::from_field_text(id_field, &id); @@ -376,15 +383,8 @@ impl IndexManager for FolderIndexManagerImpl { fn add_index(&self, data: IndexableData) -> Result<(), FlowyError> { let mut index_writer = self.get_index_writer()?; - let folder_schema = self.get_folder_schema()?; - - 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 workspace_id_field = folder_schema - .schema - .get_field(FOLDER_WORKSPACE_ID_FIELD_NAME)?; + let (id_field, title_field, icon_field, icon_ty_field, workspace_id_field) = + self.get_schema_fields()?; let (icon, icon_ty) = self.extract_icon(data.icon, data.layout); @@ -402,6 +402,24 @@ impl IndexManager for FolderIndexManagerImpl { Ok(()) } + /// Removes all indexes that are related by workspace id. This is useful + /// for cleaning indexes when eg. removing/leaving a workspace. + /// + fn remove_indices_for_workspace(&self, workspace_id: String) -> Result<(), FlowyError> { + let mut index_writer = self.get_index_writer()?; + + let folder_schema = self.get_folder_schema()?; + let id_field = folder_schema + .schema + .get_field(FOLDER_WORKSPACE_ID_FIELD_NAME)?; + let delete_term = Term::from_field_text(id_field, &workspace_id); + index_writer.delete_term(delete_term); + + index_writer.commit()?; + + Ok(()) + } + fn as_any(&self) -> &dyn Any { self } @@ -416,4 +434,35 @@ impl FolderIndexManager for FolderIndexManagerImpl { let _ = self.index_all(indexable_data); } + + fn index_view_changes( + &self, + views: Vec>, + changes: Vec, + workspace_id: String, + ) { + let mut views_iter = views.into_iter(); + for change in changes { + match change { + FolderViewChange::Inserted { view_id } => { + let view = views_iter.find(|view| view.id == view_id); + if let Some(view) = view { + let indexable_data = IndexableData::from_view(view, workspace_id.clone()); + let _ = self.add_index(indexable_data); + } + }, + FolderViewChange::Updated { view_id } => { + let view = views_iter.find(|view| view.id == view_id); + if let Some(view) = view { + let indexable_data = IndexableData::from_view(view, workspace_id.clone()); + let _ = self.update_index(indexable_data); + } + }, + FolderViewChange::Deleted { view_ids } => { + tracing::warn!("[Indexer] ViewChange Reached Deleted: {:?}", view_ids); + let _ = self.remove_indices(view_ids); + }, + }; + } + } } diff --git a/frontend/rust-lib/flowy-sqlite/src/schema.rs b/frontend/rust-lib/flowy-sqlite/src/schema.rs index 24290ea5d8..b1737d85eb 100644 --- a/frontend/rust-lib/flowy-sqlite/src/schema.rs +++ b/frontend/rust-lib/flowy-sqlite/src/schema.rs @@ -68,10 +68,10 @@ diesel::table! { } diesel::allow_tables_to_appear_in_same_query!( - chat_message_table, - chat_table, - collab_snapshot, - user_data_migration_records, - user_table, - user_workspace_table, + chat_message_table, + chat_table, + collab_snapshot, + user_data_migration_records, + user_table, + user_workspace_table, ); diff --git a/frontend/rust-lib/flowy-user-pub/src/workspace_service.rs b/frontend/rust-lib/flowy-user-pub/src/workspace_service.rs index 7938f8a862..d588945618 100644 --- a/frontend/rust-lib/flowy-user-pub/src/workspace_service.rs +++ b/frontend/rust-lib/flowy-user-pub/src/workspace_service.rs @@ -10,4 +10,7 @@ pub trait UserWorkspaceService: Send + Sync { &self, ids_by_database_id: HashMap>, ) -> FlowyResult<()>; + + /// Removes local indexes when a workspace is left/deleted + fn did_delete_workspace(&self, workspace_id: String) -> FlowyResult<()>; } diff --git a/frontend/rust-lib/flowy-user/src/user_manager/manager_user_workspace.rs b/frontend/rust-lib/flowy-user/src/user_manager/manager_user_workspace.rs index 8e30c43df7..0f74c563b1 100644 --- a/frontend/rust-lib/flowy-user/src/user_manager/manager_user_workspace.rs +++ b/frontend/rust-lib/flowy-user/src/user_manager/manager_user_workspace.rs @@ -261,7 +261,11 @@ impl UserManager { // delete workspace from local sqlite db let uid = self.user_id()?; let conn = self.db_connection(uid)?; - delete_user_workspaces(conn, workspace_id) + delete_user_workspaces(conn, workspace_id)?; + + self + .user_workspace_service + .did_delete_workspace(workspace_id.to_string()) } #[instrument(level = "info", skip(self), err)] @@ -275,6 +279,11 @@ impl UserManager { let uid = self.user_id()?; let conn = self.db_connection(uid)?; delete_user_workspaces(conn, workspace_id)?; + + self + .user_workspace_service + .did_delete_workspace(workspace_id.to_string())?; + Ok(()) }