diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 90bc8c701..508bda056 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -56,8 +56,8 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: - tagName: v__VERSION__ # the action automatically replaces \_\_VERSION\_\_ with the app version - releaseName: "Spyglass v__VERSION__" + tagName: v20__VERSION__ # the action automatically replaces \_\_VERSION\_\_ with the app version + releaseName: "Spyglass v20__VERSION__" releaseBody: "See the assets to download this version and install." releaseDraft: true prerelease: false diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index decde4dd6..49d723587 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -15,11 +15,23 @@ jobs: runs-on: ubuntu-latest steps: + # Checkout source code - uses: actions/checkout@v3 + # Setup arch target for sidecar build - name: Setup arch target run: echo "target_arch=$(rustc -Vv | grep host | awk '{print $2 " "}')" >> $GITHUB_ENV - - name: Setup wasm target - run: rustup target add wasm32-unknown-unknown + # Setup rust toolchain + - name: Setup rust toolchain + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + target: wasm32-unknown-unknown + components: clippy + # Should help bring down build times + - uses: Swatinem/rust-cache@v1 + with: + key: "1" # increment this to bust the cache if needed - name: Install tauri system deps run: | sudo apt-get update -y @@ -31,15 +43,37 @@ jobs: librsvg2-dev cargo install tauri-cli --locked --version ^1.0.0-rc.8 cargo install --locked trunk - - name: Build backend - run: cargo build -p spyglass --verbose - - name: Create sidecar + + - name: Build sidecar + uses: actions-rs/cargo@v1 + with: + command: build + args: -p spyglass + + - name: Move sidecar into place run: | mkdir -p crates/tauri/binaries cp target/debug/spyglass crates/tauri/binaries/spyglass-server-${{ env.target_arch }} - - name: Build everything - run: | - cargo tauri build - cargo build --verbose + # Build front-end client + - name: Build client + uses: actions-rs/cargo@v1 + with: + command: tauri + args: build + # Build backend crates + - name: Build backend + uses: actions-rs/cargo@v1 + with: + command: build + # Run tests - name: Run tests - run: cargo test --verbose + uses: actions-rs/cargo@v1 + with: + command: test + args: --verbose + # Run clippy + - name: Run clippy + uses: actions-rs/cargo@v1 + with: + command: clippy + args: -- -D warnings diff --git a/Cargo.lock b/Cargo.lock index d43609969..525ca2f65 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4160,6 +4160,7 @@ dependencies = [ "shared", "tauri", "tauri-build", + "tokio", "tokio-retry", "tracing", "tracing-appender", diff --git a/Makefile b/Makefile index e5a3df208..57fe7da23 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ build-client: build-release: # Build backend binaries cargo build -p spyglass --release - mkdir -p crates/tauri/binaries/spyglss-server-$(TARGET_ARCH) + mkdir -p crates/tauri/binaries cp target/release/spyglass crates/tauri/binaries/spyglass-server-$(TARGET_ARCH) # Build client cargo tauri build @@ -37,4 +37,4 @@ setup-dev: cargo install --locked trunk run-client-dev: - cargo tauri dev \ No newline at end of file + cargo tauri dev diff --git a/README.md b/README.md index b49516b64..804cc670f 100644 --- a/README.md +++ b/README.md @@ -78,17 +78,17 @@ curated set of websites with high quality recipes. "#), domains: [ - # Major sites that often have really good recipes + // Major sites that often have really good recipes "www.seriouseats.com", "cooking.nytimes.com", ... - # Specific cuisines/sites that I've found randomly w/ high-quality recipes + // Specific cuisines/sites that I've found randomly w/ high-quality recipes "www.hungryhuy.com", "www.vickypham.com", ], - # Not yet supported but ideally more ways to filter URLs within a domain + // Not yet supported but ideally more ways to filter URLs within a domain urls: [ "www.reddit.com/r/recipes/*", ] @@ -108,7 +108,7 @@ programming language and not the Rust game / The Rust Belt / oxidation / etc. name: "rustlang", description: Some("Rustlang targeted websites"), domains: [ - # Support for wildcards in domain names + // Support for wildcards in domain names "*.rust-lang.org", "docs.rs", "rustconf.com", @@ -117,8 +117,8 @@ programming language and not the Rust game / The Rust Belt / oxidation / etc. ... ], - # Again not yet supported but an example of indexing specific communities that - # are relevant to the topic + // Again not yet supported but an example of indexing specific communities that + // are relevant to the topic urls: [ "www.reddit.com/r/rust", "www.reddit.com/r/rust_gamedev", @@ -135,22 +135,22 @@ file found in their directory on startup, a default one will be created. ``` rust ( - # The max number of pages to index per domain + // The max number of pages to index per domain domain_crawl_limit: Finite(1000), - # The max number of crawlers per domain + // The max number of crawlers per domain inflight_domain_limit: Finite(2), - # The max number of crawlers in total + // The max number of crawlers in total inflight_crawl_limit: Finite(10), - # Not used... yet! + // Not used... yet! run_wizard: false, - # Not used... yet! + // Not used... yet! allow_list: [], - # Domains to completely ignore. + // Domains to completely ignore. block_list: [ "web.archive.org", "w3schools.com" ], - # Shortcut to launch the search bar + // Shortcut to launch the search bar shortcut: "CmdOrCtrl+Shift+/", ) ``` @@ -171,5 +171,8 @@ Supported Modifiers: Examples: * "CmdOrCtrl+/" => Launches the app w/ `Cmd` or `Ctrl` + `/` -* "CmdOrCtrl+Shift+/" => Launches the app w/ `Cmd` or `Ctrl` + `/` -* "Shift+4+2" => Launches the app w/ `Shift` + `4` + `2` \ No newline at end of file +* "CmdOrCtrl+Shift+/" => Launches the app w/ `Cmd` or `Ctrl` + `Shift` + `/` +* "Shift+4" => Launches the app w/ `Shift` + `4` + +NOTE: Shortcuts are allowed to have any number of modifiers but only a *single* key. +For example, `Shift+4` will work but not `Shift+4+2` \ No newline at end of file diff --git a/crates/client/src/constants.rs b/crates/client/src/constants.rs index bf582e536..8adc1b473 100644 --- a/crates/client/src/constants.rs +++ b/crates/client/src/constants.rs @@ -1,3 +1,2 @@ -pub const DEBOUNCE_TIME_MS: f64 = (1 * 1000) as f64; pub const LENS_SEARCH_PREFIX: &str = "/"; pub const MIN_CHARS: usize = 2; diff --git a/crates/client/src/events.rs b/crates/client/src/events.rs index 656d5ea09..9f4c16b41 100644 --- a/crates/client/src/events.rs +++ b/crates/client/src/events.rs @@ -1,4 +1,3 @@ -use js_sys::Date; use wasm_bindgen::prelude::*; use wasm_bindgen::JsCast; use wasm_bindgen_futures::spawn_local; @@ -71,16 +70,12 @@ pub fn handle_global_key_down( pub fn handle_query_change( query: &str, - query_debounce: UseStateHandle, node_ref: UseStateHandle, lens: UseStateHandle>, search_results: UseStateHandle>, selected_idx: UseStateHandle, ) { - // Was the last char typed > 1 sec ago? - let is_debounced = *query_debounce >= constants::DEBOUNCE_TIME_MS; - - if is_debounced && query.len() >= constants::MIN_CHARS { + if query.len() >= constants::MIN_CHARS { let el = node_ref.cast::().unwrap(); if query.starts_with(constants::LENS_SEARCH_PREFIX) { // show lens search @@ -89,6 +84,4 @@ pub fn handle_query_change( super::show_doc_results(search_results, &lens, el, selected_idx, query.to_string()); } } - - query_debounce.set(Date::now()); } diff --git a/crates/client/src/main.rs b/crates/client/src/main.rs index e37544842..d536a4612 100644 --- a/crates/client/src/main.rs +++ b/crates/client/src/main.rs @@ -1,5 +1,4 @@ use gloo::events::EventListener; -use js_sys::Date; use wasm_bindgen::{prelude::*, JsCast}; use wasm_bindgen_futures::spawn_local; use web_sys::{window, Element, HtmlElement, HtmlInputElement}; @@ -46,7 +45,6 @@ pub fn app() -> Html { let lens = use_state_eq(Vec::new); // Current query string let query = use_state_eq(|| "".to_string()); - let query_debounce = use_state_eq(Date::now); // Search results + selected index let search_results = use_state_eq(Vec::new); let selected_idx = use_state_eq(|| 0); @@ -87,7 +85,6 @@ pub fn app() -> Html { move |query| { events::handle_query_change( query, - query_debounce, node_ref, lens, search_results, @@ -142,7 +139,6 @@ pub fn app() -> Html { .collect::(); let onkeyup = { - let query = query.clone(); Callback::from(move |e: KeyboardEvent| { let input: HtmlInputElement = e.target_unchecked_into(); query.set(input.value()); @@ -172,7 +168,6 @@ pub fn app() -> Html { type={"text"} class={"search-box"} placeholder={"Search"} - value={(*query).clone()} {onkeyup} {onkeydown} spellcheck={"false"} diff --git a/crates/spyglass/src/search/query.rs b/crates/spyglass/src/search/query.rs index 74e817340..f3ad66b2b 100644 --- a/crates/spyglass/src/search/query.rs +++ b/crates/spyglass/src/search/query.rs @@ -33,7 +33,7 @@ pub fn build_query( .map(|token| token.trim()) .collect(); - log::info!("lenses: {:?}, terms: {:?}", applied_lens, terms); + log::trace!("lenses: {:?}, terms: {:?}", applied_lens, terms); let mut lense_queries: QueryVec = Vec::new(); for lens in applied_lens { diff --git a/crates/tauri/Cargo.toml b/crates/tauri/Cargo.toml index db551cf92..8c94b49cd 100644 --- a/crates/tauri/Cargo.toml +++ b/crates/tauri/Cargo.toml @@ -24,6 +24,7 @@ serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" shared = { path = "../shared" } tauri = { version = "1.0.0-rc.8", features = ["api-all", "ayatana-tray", "devtools", "notification", "system-tray"] } +tokio = "1" tokio-retry = "0.3" tracing = "0.1" tracing-appender = "0.2" diff --git a/crates/tauri/src/main.rs b/crates/tauri/src/main.rs index 197840e72..ce802ebeb 100644 --- a/crates/tauri/src/main.rs +++ b/crates/tauri/src/main.rs @@ -2,11 +2,14 @@ all(not(debug_assertions), target_os = "windows"), windows_subsystem = "windows" )] -use jsonrpc_core::Value; -use num_format::{Locale, ToFormattedString}; use std::io; use std::path::PathBuf; +use std::time::Duration; + +use jsonrpc_core::Value; +use num_format::{Locale, ToFormattedString}; use tauri::{AppHandle, GlobalShortcutManager, Manager, SystemTray, SystemTrayEvent}; +use tokio::time; use tracing_log::LogTracer; use tracing_subscriber::{fmt, layer::SubscriberExt, EnvFilter}; @@ -36,6 +39,7 @@ fn main() -> Result<(), Box> { LogTracer::init()?; let ctx = tauri::generate_context!(); + let config = Config::new(); tauri::Builder::default() .invoke_handler(tauri::generate_handler![ @@ -46,26 +50,23 @@ fn main() -> Result<(), Box> { cmd::resize_window ]) .menu(menu::get_app_menu()) - .setup(|app| { + .system_tray(SystemTray::new().with_menu(menu::get_tray_menu(&config))) + .setup(move |app| { // hide from dock (also hides menu bar) #[cfg(target_os = "macos")] app.set_activation_policy(tauri::ActivationPolicy::Accessory); - // Only show in dev/debug mode. - #[cfg(debug_assertions)] - app.get_window("main").unwrap().open_devtools(); - - let window = app.get_window("main").unwrap(); - // Start up backend (only in release mode) #[cfg(not(debug_assertions))] rpc::check_and_start_backend(); + let window = app.get_window("main").unwrap(); + let _ = window.set_skip_taskbar(true); + // Wait for the server to boot up app.manage(tauri::async_runtime::block_on(rpc::RpcClient::new())); // Load user settings - let config = Config::new(); app.manage(config.clone()); // Register global shortcut @@ -74,6 +75,7 @@ fn main() -> Result<(), Box> { .is_registered(&config.user_settings.shortcut) .unwrap() { + log::info!("Registering {} as shortcut", &config.user_settings.shortcut); let window = window.clone(); shortcuts .register(&config.user_settings.shortcut, move || { @@ -89,9 +91,18 @@ fn main() -> Result<(), Box> { // Center window horizontally in the current screen window::center_window(&window); + // Keep system tray stats updated + let app_handle = app.app_handle(); + tauri::async_runtime::spawn(async move { + let mut interval = time::interval(Duration::from_secs(10)); + loop { + update_tray_menu(&app_handle).await; + interval.tick().await; + } + }); + Ok(()) }) - .system_tray(SystemTray::new().with_menu(menu::get_tray_menu())) .on_window_event(|event| { if let tauri::WindowEvent::Focused(is_focused) = event.event() { if !is_focused { @@ -100,11 +111,11 @@ fn main() -> Result<(), Box> { } } }) - .on_system_tray_event(|app, event| match event { - SystemTrayEvent::LeftClick { .. } => update_tray_menu(app), - SystemTrayEvent::RightClick { .. } => update_tray_menu(app), - SystemTrayEvent::MenuItemClick { id, .. } => { + .on_system_tray_event(|app, event| { + if let SystemTrayEvent::MenuItemClick { id, .. } = event { let item_handle = app.tray_handle().get_item(&id); + let window = app.get_window("main").unwrap(); + match id.as_str() { menu::CRAWL_STATUS_MENU_ITEM => { let rpc = app.state::().inner(); @@ -118,30 +129,19 @@ fn main() -> Result<(), Box> { item_handle.set_title(new_label).unwrap(); } - menu::OPEN_LENSES_FOLDER => { - open_folder(Config::lenses_dir()); - } - menu::OPEN_SETTINGS_FOLDER => { - open_folder(Config::prefs_dir()); - } - menu::TOGGLE_MENU_ITEM => { - let window = app.get_window("main").unwrap(); - let new_title = if window.is_visible().unwrap() { - window::hide_window(&window); - "Show" - } else { + menu::OPEN_LENSES_FOLDER => open_folder(Config::lenses_dir()), + menu::OPEN_LOGS_FOLDER => open_folder(Config::logs_dir()), + menu::OPEN_SETTINGS_FOLDER => open_folder(Config::prefs_dir()), + menu::SHOW_SEARCHBAR => { + if !window.is_visible().unwrap() { window::show_window(&window); - "Hide" - }; - item_handle.set_title(new_title).unwrap(); - } - menu::QUIT_MENU_ITEM => { - app.exit(0); + } } + menu::QUIT_MENU_ITEM => app.exit(0), + menu::DEV_SHOW_CONSOLE => window.open_devtools(), _ => {} } } - _ => {} }) .run(ctx) .expect("error while running tauri application"); @@ -197,10 +197,10 @@ fn open_folder(folder: PathBuf) { .unwrap(); } -fn update_tray_menu(app: &AppHandle) { +async fn update_tray_menu(app: &AppHandle) { let rpc = app.state::().inner(); - let app_status = tauri::async_runtime::block_on(app_status(rpc)); + let app_status = app_status(rpc).await; let handle = app.tray_handle(); if let Some(app_status) = app_status { diff --git a/crates/tauri/src/menu.rs b/crates/tauri/src/menu.rs index eb598da75..514bb4015 100644 --- a/crates/tauri/src/menu.rs +++ b/crates/tauri/src/menu.rs @@ -1,6 +1,6 @@ +use shared::config::Config; use tauri::{CustomMenuItem, Menu, MenuItem, Submenu, SystemTrayMenu, SystemTrayMenuItem}; -pub const TOGGLE_MENU_ITEM: &str = "toggle"; pub const QUIT_MENU_ITEM: &str = "quit"; pub const NUM_DOCS_MENU_ITEM: &str = "num_docs"; @@ -9,8 +9,17 @@ pub const CRAWL_STATUS_MENU_ITEM: &str = "crawl_status"; pub const OPEN_LENSES_FOLDER: &str = "open_lenses_folder"; pub const OPEN_SETTINGS_FOLDER: &str = "open_settings_folder"; +pub const OPEN_LOGS_FOLDER: &str = "open_logs_folder"; +pub const SHOW_SEARCHBAR: &str = "show_searchbar"; + +pub const DEV_SHOW_CONSOLE: &str = "dev_show_console"; + +pub fn get_tray_menu(config: &Config) -> SystemTrayMenu { + let ctx = tauri::generate_context!(); + + let show = CustomMenuItem::new(SHOW_SEARCHBAR.to_string(), "Show search") + .accelerator(config.user_settings.shortcut.clone()); -pub fn get_tray_menu() -> SystemTrayMenu { let pause = CustomMenuItem::new(CRAWL_STATUS_MENU_ITEM.to_string(), ""); let quit = CustomMenuItem::new(QUIT_MENU_ITEM.to_string(), "Quit"); @@ -19,21 +28,41 @@ pub fn get_tray_menu() -> SystemTrayMenu { let open_settings_folder = CustomMenuItem::new(OPEN_SETTINGS_FOLDER.to_string(), "Show settings folder"); - SystemTrayMenu::new() - .add_item(pause) + let open_logs_folder = CustomMenuItem::new(OPEN_LOGS_FOLDER.to_string(), "Show logs folder"); + + let mut tray = SystemTrayMenu::new(); + tray = tray + .add_item(show) .add_native_item(SystemTrayMenuItem::Separator) + .add_item( + CustomMenuItem::new("about", format!("v20{}", ctx.package_info().version)).disabled(), + ) .add_item( CustomMenuItem::new(NUM_DOCS_MENU_ITEM.to_string(), "XX documents indexed").disabled(), ) .add_item(CustomMenuItem::new(NUM_QUEUED_MENU_ITEM.to_string(), "XX queued").disabled()) + .add_item(pause) .add_native_item(SystemTrayMenuItem::Separator) .add_item(open_lenses_folder) .add_item(open_settings_folder) - .add_native_item(SystemTrayMenuItem::Separator) + .add_item(open_logs_folder); + + // Add dev utils + if cfg!(debug_assertions) { + tray = tray + .add_native_item(SystemTrayMenuItem::Separator) + .add_item(CustomMenuItem::new(DEV_SHOW_CONSOLE, "Show console")); + } + + tray.add_native_item(SystemTrayMenuItem::Separator) .add_item(quit) } pub fn get_app_menu() -> Menu { + if cfg!(target_os = "linux") { + return Menu::new(); + } + let ctx = tauri::generate_context!(); Menu::new().add_submenu(Submenu::new( diff --git a/crates/tauri/src/window.rs b/crates/tauri/src/window.rs index 64a9d1ba8..1c0c12167 100644 --- a/crates/tauri/src/window.rs +++ b/crates/tauri/src/window.rs @@ -3,7 +3,7 @@ use tauri::{async_runtime::spawn, LogicalSize, Size, Window}; use crate::{cmd, constants}; pub fn center_window(window: &Window) { - if let Some(monitor) = window.current_monitor().unwrap() { + if let Some(monitor) = window.primary_monitor().unwrap() { let size = monitor.size(); let scale = monitor.scale_factor(); diff --git a/crates/tauri/tauri.conf.json b/crates/tauri/tauri.conf.json index 682ef9122..820ace85f 100644 --- a/crates/tauri/tauri.conf.json +++ b/crates/tauri/tauri.conf.json @@ -1,7 +1,7 @@ { "package": { "productName": "Spyglass", - "version": "22.4.30" + "version": "22.5.4" }, "build": { "distDir": "../client/dist",