fix error popup on startup

This commit is contained in:
Joseph Montanaro 2024-06-03 01:21:43 -04:00
parent 816bd7db00
commit 0491cb5790
9 changed files with 74 additions and 103 deletions

View File

@ -1,6 +1,6 @@
{ {
"name": "creddy", "name": "creddy",
"version": "0.4.8", "version": "0.4.9",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",
"build": "vite build", "build": "vite build",

29
src-tauri/Cargo.lock generated
View File

@ -118,13 +118,14 @@ version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd884d7c72877a94102c3715f3b1cd09ff4fac28221add3e57cfbe25c236d093" checksum = "dd884d7c72877a94102c3715f3b1cd09ff4fac28221add3e57cfbe25c236d093"
dependencies = [ dependencies = [
"async-fs",
"async-net",
"enumflags2", "enumflags2",
"futures-channel", "futures-channel",
"futures-util", "futures-util",
"rand 0.8.5", "rand 0.8.5",
"serde", "serde",
"serde_repr", "serde_repr",
"tokio",
"url", "url",
"zbus", "zbus",
] ]
@ -229,6 +230,17 @@ dependencies = [
"pin-project-lite", "pin-project-lite",
] ]
[[package]]
name = "async-net"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b948000fad4873c1c9339d60f2623323a0cfd3816e5181033c6a5cb68b2accf7"
dependencies = [
"async-io",
"blocking",
"futures-lite 2.0.0",
]
[[package]] [[package]]
name = "async-process" name = "async-process"
version = "2.1.0" version = "2.1.0"
@ -1122,7 +1134,7 @@ dependencies = [
[[package]] [[package]]
name = "creddy" name = "creddy"
version = "0.4.8" version = "0.4.9"
dependencies = [ dependencies = [
"argon2", "argon2",
"auto-launch", "auto-launch",
@ -3548,6 +3560,12 @@ dependencies = [
"windows-sys 0.52.0", "windows-sys 0.52.0",
] ]
[[package]]
name = "pollster"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22686f4785f02a4fcc856d3b3bb19bf6c8160d103f7a99cc258bddd0251dc7f2"
[[package]] [[package]]
name = "poly1305" name = "poly1305"
version = "0.8.0" version = "0.8.0"
@ -3897,15 +3915,14 @@ dependencies = [
"ashpd", "ashpd",
"block", "block",
"dispatch", "dispatch",
"glib-sys",
"gobject-sys",
"gtk-sys",
"js-sys", "js-sys",
"log", "log",
"objc", "objc",
"objc-foundation", "objc-foundation",
"objc_id", "objc_id",
"pollster",
"raw-window-handle 0.6.2", "raw-window-handle 0.6.2",
"urlencoding",
"wasm-bindgen", "wasm-bindgen",
"wasm-bindgen-futures", "wasm-bindgen-futures",
"web-sys", "web-sys",
@ -5128,7 +5145,6 @@ dependencies = [
"signal-hook-registry", "signal-hook-registry",
"socket2 0.5.4", "socket2 0.5.4",
"tokio-macros", "tokio-macros",
"tracing",
"windows-sys 0.48.0", "windows-sys 0.48.0",
] ]
@ -6286,7 +6302,6 @@ dependencies = [
"serde_repr", "serde_repr",
"sha1", "sha1",
"static_assertions", "static_assertions",
"tokio",
"tracing", "tracing",
"uds_windows", "uds_windows",
"windows-sys 0.52.0", "windows-sys 0.52.0",

View File

@ -1,6 +1,6 @@
[package] [package]
name = "creddy" name = "creddy"
version = "0.4.8" version = "0.4.9"
description = "A friendly AWS credentials manager" description = "A friendly AWS credentials manager"
authors = ["Joseph Montanaro"] authors = ["Joseph Montanaro"]
license = "" license = ""
@ -49,7 +49,7 @@ windows = { version = "0.51.1", features = ["Win32_Foundation", "Win32_System_Pi
time = "0.3.31" time = "0.3.31"
tauri-plugin-single-instance = "2.0.0-beta.9" tauri-plugin-single-instance = "2.0.0-beta.9"
tauri-plugin-global-shortcut = "2.0.0-beta.6" tauri-plugin-global-shortcut = "2.0.0-beta.6"
rfd = { version = "0.14", default-features = false, features = [ "tokio", "gtk3", "common-controls-v6" ] } rfd = "0.14.1"
[features] [features]
# by default Tauri runs in production mode # by default Tauri runs in production mode

View File

@ -2,6 +2,10 @@ use std::error::Error;
use std::time::Duration; use std::time::Duration;
use once_cell::sync::OnceCell; use once_cell::sync::OnceCell;
use rfd::{
MessageDialog,
MessageLevel,
};
use sqlx::{ use sqlx::{
SqlitePool, SqlitePool,
sqlite::SqlitePoolOptions, sqlite::SqlitePoolOptions,
@ -10,9 +14,12 @@ use sqlx::{
use tauri::{ use tauri::{
App, App,
AppHandle, AppHandle,
Manager,
async_runtime as rt, async_runtime as rt,
Manager,
RunEvent,
WindowEvent,
}; };
use tauri::menu::MenuItem;
use crate::{ use crate::{
config::{self, AppConfig}, config::{self, AppConfig},
@ -33,7 +40,7 @@ pub fn run() -> tauri::Result<()> {
tauri::Builder::default() tauri::Builder::default()
.plugin(tauri_plugin_single_instance::init(|app, _argv, _cwd| { .plugin(tauri_plugin_single_instance::init(|app, _argv, _cwd| {
show_main_window(app) show_main_window(app)
.blocking_error_popup("Failed to show main window") .error_popup("Failed to show main window")
})) }))
.plugin(tauri_plugin_global_shortcut::Builder::default().build()) .plugin(tauri_plugin_global_shortcut::Builder::default().build())
.invoke_handler(tauri::generate_handler![ .invoke_handler(tauri::generate_handler![
@ -47,17 +54,25 @@ pub fn run() -> tauri::Result<()> {
ipc::launch_terminal, ipc::launch_terminal,
ipc::get_setup_errors, ipc::get_setup_errors,
]) ])
.setup(|app| rt::block_on(setup(app))) .setup(|app| {
let res = rt::block_on(setup(app));
if let Err(ref e) = res {
MessageDialog::new()
.set_level(MessageLevel::Error)
.set_title("Creddy failed to start")
.set_description(format!("{e}"))
.show();
}
res
})
.build(tauri::generate_context!())? .build(tauri::generate_context!())?
.run(|app, run_event| match run_event { .run(|app, run_event| {
tauri::RunEvent::WindowEvent { event, .. } => match event { if let RunEvent::WindowEvent { event, .. } = run_event {
tauri::WindowEvent::CloseRequested { api, .. } => { if let WindowEvent::CloseRequested { api, .. } = event {
let _ = hide_main_window(app); let _ = hide_main_window(app);
api.prevent_close(); api.prevent_close();
} }
_ => ()
} }
_ => ()
}); });
Ok(()) Ok(())
@ -137,7 +152,7 @@ fn start_auto_locker(app: AppHandle) {
tokio::time::sleep(delay).await; tokio::time::sleep(delay).await;
if state.should_auto_lock().await { if state.should_auto_lock().await {
state.lock().await.error_popup("Failed to lock Creddy").await; state.lock().await.error_popup("Failed to lock Creddy");
} }
} }
}); });
@ -147,9 +162,8 @@ fn start_auto_locker(app: AppHandle) {
pub fn show_main_window(app: &AppHandle) -> Result<(), WindowError> { pub fn show_main_window(app: &AppHandle) -> Result<(), WindowError> {
let w = app.get_webview_window("main").ok_or(WindowError::NoMainWindow)?; let w = app.get_webview_window("main").ok_or(WindowError::NoMainWindow)?;
w.show()?; w.show()?;
// app.tray_handle() let show_hide = app.state::<MenuItem<tauri::Wry>>();
// .get_item("show_hide") show_hide.set_text("Hide")?;
// .set_title("Hide")?;
Ok(()) Ok(())
} }
@ -157,9 +171,8 @@ pub fn show_main_window(app: &AppHandle) -> Result<(), WindowError> {
pub fn hide_main_window(app: &AppHandle) -> Result<(), WindowError> { pub fn hide_main_window(app: &AppHandle) -> Result<(), WindowError> {
let w = app.get_webview_window("main").ok_or(WindowError::NoMainWindow)?; let w = app.get_webview_window("main").ok_or(WindowError::NoMainWindow)?;
w.hide()?; w.hide()?;
// app.tray_handle() let show_hide = app.state::<MenuItem<tauri::Wry>>();
// .get_item("show_hide") show_hide.set_text("Show")?;
// .set_title("Show")?;
Ok(()) Ok(())
} }

View File

@ -11,13 +11,13 @@ use aws_sdk_sts::{
}; };
use rfd::{ use rfd::{
AsyncMessageDialog, AsyncMessageDialog,
MessageDialog,
MessageLevel, MessageLevel,
}; };
use sqlx::{ use sqlx::{
error::Error as SqlxError, error::Error as SqlxError,
migrate::MigrateError, migrate::MigrateError,
}; };
use tauri::async_runtime as rt;
use tauri_plugin_global_shortcut::Error as ShortcutError; use tauri_plugin_global_shortcut::Error as ShortcutError;
use tokio::sync::oneshot::error::RecvError; use tokio::sync::oneshot::error::RecvError;
use serde::{ use serde::{
@ -28,66 +28,26 @@ use serde::{
}; };
#[allow(async_fn_in_trait)] pub trait ShowError<T, E>
pub trait ShowError<T>
{ {
async fn error_popup(self, title: &str); fn error_popup(self, title: &str);
async fn error_popup_passthrough(self, title: &str) -> Result<T, ()>;
fn blocking_error_popup(self, title: &str);
fn error_print(self); fn error_print(self);
fn error_print_prefix(self, prefix: &str); fn error_print_prefix(self, prefix: &str);
} }
impl<T, E> ShowError<T> for Result<T, E> impl<T, E> ShowError<T, E> for Result<T, E>
where E: std::fmt::Display where E: std::fmt::Display
{ {
async fn error_popup(self, title: &str) { fn error_popup(self, title: &str) {
if let Err(e) = self { if let Err(e) = self {
AsyncMessageDialog::new() let dialog = AsyncMessageDialog::new()
.set_level(MessageLevel::Error) .set_level(MessageLevel::Error)
.set_title(title) .set_title(title)
.set_description(format!("{e}")) .set_description(format!("{e}"));
.show() rt::spawn(async move {dialog.show().await});
.await;
} }
} }
fn blocking_error_popup(self, title: &str) {
if let Err(e) = self {
MessageDialog::new()
.set_level(MessageLevel::Error)
.set_title(title)
.set_description(format!("{e}"))
.show();
}
}
async fn error_popup_passthrough(self, title: &str) -> Result<T, ()> {
match self {
Ok(v) => Ok(v),
Err(e) => {
AsyncMessageDialog::new()
.set_level(MessageLevel::Error)
.set_title(title)
.set_description(format!("{e}"))
.show()
.await;
Err(())
}
}
}
// fn error_popup_nowait(self, title: &str) {
// if let Err(e) = self {
// let app = app::APP.get().expect("Error popup failed, app handle not available");
// app.dialog()
// .message(format!("{e}"))
// .kind(MessageDialogKind::Error)
// .title(title)
// .show(|_| {})
// }
// }
fn error_print(self) { fn error_print(self) {
if let Err(e) = self { if let Err(e) = self {
eprintln!("{e}"); eprintln!("{e}");

View File

@ -13,7 +13,7 @@ use creddy::{
fn main() { fn main() {
let res = match cli::parser().get_matches().subcommand() { let res = match cli::parser().get_matches().subcommand() {
None | Some(("run", _)) => { None | Some(("run", _)) => {
app::run().blocking_error_popup("Creddy failed to start"); app::run().error_popup("Creddy encountered an error");
Ok(()) Ok(())
}, },
Some(("get", m)) => cli::get(m), Some(("get", m)) => cli::get(m),

View File

@ -1,17 +1,13 @@
use serde::{Serialize, Deserialize}; use serde::{Serialize, Deserialize};
use tauri::{ use tauri::async_runtime as rt;
AppHandle,
Manager,
async_runtime as rt,
};
use tauri_plugin_global_shortcut::{ use tauri_plugin_global_shortcut::{
GlobalShortcutExt, GlobalShortcutExt,
Error as ShortcutError, Error as ShortcutError,
}; };
use crate::app::APP; use crate::app::{self, APP};
use crate::config::HotkeysConfig; use crate::config::HotkeysConfig;
use crate::errors::*; use crate::errors::*;
use crate::terminal; use crate::terminal;
@ -29,36 +25,18 @@ pub fn exec_shortcut(action: ShortcutAction) {
ShortcutAction::LaunchTerminal => launch_terminal(), ShortcutAction::LaunchTerminal => launch_terminal(),
ShortcutAction::ShowWindow => { ShortcutAction::ShowWindow => {
let app = APP.get().unwrap(); let app = APP.get().unwrap();
show_window(app); app::show_main_window(app)
.error_popup("Failed to show Creddy");
}, },
} }
} }
fn show_window(app: &AppHandle) {
let handle = app.clone();
rt::spawn(async move {
handle.get_webview_window("main")
.ok_or("Couldn't find application main window")
.error_popup_passthrough("Failed to show window").await?
.show()
.error_popup("Failed to show window").await;
Ok::<(), ()>(())
});
// app.get_webview_window("main") // Option<Window>
// .ok_or("Couldn't find application main window") // Result<Window, &'static str>
// .map(|w| w.show().error_popup("Failed to show window"))
// .error_popup("Failed to show window");
}
fn launch_terminal() { fn launch_terminal() {
rt::spawn(async { rt::spawn(async {
terminal::launch(false) terminal::launch(false)
.await .await
.error_popup("Failed to launch terminal") .error_popup("Failed to launch terminal")
.await;
}); });
} }
@ -74,7 +52,9 @@ pub fn register_hotkeys(hotkeys: &HotkeysConfig) -> Result<(), ShortcutError> {
if hotkeys.show_window.enabled { if hotkeys.show_window.enabled {
shortcuts.on_shortcut( shortcuts.on_shortcut(
hotkeys.show_window.keys.as_str(), hotkeys.show_window.keys.as_str(),
|app, _shortcut, _event| show_window(app) |app, _shortcut, _event| {
app::show_main_window(app).error_popup("Failed to show Creddy")
}
)?; )?;
} }

View File

@ -15,7 +15,7 @@ use crate::state::AppState;
pub fn setup(app: &App) -> tauri::Result<()> { pub fn setup(app: &App) -> tauri::Result<()> {
let show_hide = MenuItemBuilder::with_id("show_hide", "Show/Hide").build(app)?; let show_hide = MenuItemBuilder::with_id("show_hide", "Show").build(app)?;
let exit = MenuItemBuilder::with_id("exit", "Exit").build(app)?; let exit = MenuItemBuilder::with_id("exit", "Exit").build(app)?;
let menu = MenuBuilder::new(app) let menu = MenuBuilder::new(app)
@ -26,6 +26,9 @@ pub fn setup(app: &App) -> tauri::Result<()> {
tray.set_menu(Some(menu))?; tray.set_menu(Some(menu))?;
tray.on_menu_event(handle_event); tray.on_menu_event(handle_event);
// stash this so we can find it later to change the text
app.manage(show_hide);
Ok(()) Ok(())
} }

View File

@ -50,7 +50,7 @@
} }
}, },
"productName": "creddy", "productName": "creddy",
"version": "0.4.8", "version": "0.4.9",
"identifier": "creddy", "identifier": "creddy",
"plugins": {}, "plugins": {},
"app": { "app": {