show non-fatal setup errors on home screen instead of in popup
This commit is contained in:
		@@ -1,6 +1,6 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "creddy",
 | 
					  "name": "creddy",
 | 
				
			||||||
  "version": "0.3.1",
 | 
					  "version": "0.3.2",
 | 
				
			||||||
  "scripts": {
 | 
					  "scripts": {
 | 
				
			||||||
    "dev": "vite",
 | 
					    "dev": "vite",
 | 
				
			||||||
    "build": "vite build",
 | 
					    "build": "vite build",
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								src-tauri/Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										2
									
								
								src-tauri/Cargo.lock
									
									
									
										generated
									
									
									
								
							@@ -1035,7 +1035,7 @@ dependencies = [
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "creddy"
 | 
					name = "creddy"
 | 
				
			||||||
version = "0.3.1"
 | 
					version = "0.3.2"
 | 
				
			||||||
dependencies = [
 | 
					dependencies = [
 | 
				
			||||||
 "argon2",
 | 
					 "argon2",
 | 
				
			||||||
 "auto-launch",
 | 
					 "auto-launch",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
[package]
 | 
					[package]
 | 
				
			||||||
name = "creddy"
 | 
					name = "creddy"
 | 
				
			||||||
version = "0.3.1"
 | 
					version = "0.3.2"
 | 
				
			||||||
description = "A friendly AWS credentials manager"
 | 
					description = "A friendly AWS credentials manager"
 | 
				
			||||||
authors = ["Joseph Montanaro"]
 | 
					authors = ["Joseph Montanaro"]
 | 
				
			||||||
license = ""
 | 
					license = ""
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -43,6 +43,7 @@ pub fn run() -> tauri::Result<()> {
 | 
				
			|||||||
            ipc::get_config,
 | 
					            ipc::get_config,
 | 
				
			||||||
            ipc::save_config,
 | 
					            ipc::save_config,
 | 
				
			||||||
            ipc::launch_terminal,
 | 
					            ipc::launch_terminal,
 | 
				
			||||||
 | 
					            ipc::get_setup_errors,
 | 
				
			||||||
        ])
 | 
					        ])
 | 
				
			||||||
        .setup(|app| rt::block_on(setup(app)))
 | 
					        .setup(|app| rt::block_on(setup(app)))
 | 
				
			||||||
        .build(tauri::generate_context!())?
 | 
					        .build(tauri::generate_context!())?
 | 
				
			||||||
@@ -77,14 +78,15 @@ async fn setup(app: &mut App) -> Result<(), Box<dyn Error>> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    // get_or_create_db_path doesn't create the actual db file, just the directory
 | 
					    // get_or_create_db_path doesn't create the actual db file, just the directory
 | 
				
			||||||
    let is_first_launch = !config::get_or_create_db_path()?.exists();
 | 
					    let is_first_launch = !config::get_or_create_db_path()?.exists();
 | 
				
			||||||
 | 
					 | 
				
			||||||
    let pool = connect_db().await?;
 | 
					    let pool = connect_db().await?;
 | 
				
			||||||
 | 
					    let mut setup_errors: Vec<String> = vec![];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let conf = match AppConfig::load(&pool).await {
 | 
					    let conf = match AppConfig::load(&pool).await {
 | 
				
			||||||
        Ok(c) => c,
 | 
					        Ok(c) => c,
 | 
				
			||||||
        Err(SetupError::ConfigParseError(_)) => {
 | 
					        Err(SetupError::ConfigParseError(_)) => {
 | 
				
			||||||
            Err("Could not load configuration from database. Reverting to defaults.")
 | 
					            setup_errors.push(
 | 
				
			||||||
                .error_popup("Setup error");
 | 
					                "Could not load configuration from database. Reverting to defaults.".into()
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
            AppConfig::default()
 | 
					            AppConfig::default()
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        err => err?,
 | 
					        err => err?,
 | 
				
			||||||
@@ -94,7 +96,12 @@ async fn setup(app: &mut App) -> Result<(), Box<dyn Error>> {
 | 
				
			|||||||
    let srv = Server::new(conf.listen_addr, conf.listen_port, app.handle()).await?;
 | 
					    let srv = Server::new(conf.listen_addr, conf.listen_port, app.handle()).await?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    config::set_auto_launch(conf.start_on_login)?;
 | 
					    config::set_auto_launch(conf.start_on_login)?;
 | 
				
			||||||
    config::register_hotkeys(&conf.hotkeys).error_popup("Setup error");
 | 
					    if let Err(_e) = config::set_auto_launch(conf.start_on_login) {
 | 
				
			||||||
 | 
					        setup_errors.push("Error: Failed to manage autolaunch.".into());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if let Err(e) = config::register_hotkeys(&conf.hotkeys) {
 | 
				
			||||||
 | 
					        setup_errors.push(format!("{e}"));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // if session is empty, this is probably the first launch, so don't autohide
 | 
					    // if session is empty, this is probably the first launch, so don't autohide
 | 
				
			||||||
    if !conf.start_minimized || is_first_launch {
 | 
					    if !conf.start_minimized || is_first_launch {
 | 
				
			||||||
@@ -103,7 +110,7 @@ async fn setup(app: &mut App) -> Result<(), Box<dyn Error>> {
 | 
				
			|||||||
            .show()?;
 | 
					            .show()?;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let state = AppState::new(conf, session, srv, pool);
 | 
					    let state = AppState::new(conf, session, srv, pool, setup_errors);
 | 
				
			||||||
    app.manage(state);
 | 
					    app.manage(state);
 | 
				
			||||||
    Ok(())
 | 
					    Ok(())
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,6 +22,7 @@ use serde::{Serialize, Serializer, ser::SerializeMap};
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
pub trait ErrorPopup {
 | 
					pub trait ErrorPopup {
 | 
				
			||||||
    fn error_popup(self, title: &str);
 | 
					    fn error_popup(self, title: &str);
 | 
				
			||||||
 | 
					    fn error_popup_nowait(self, title: &str);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<E: std::fmt::Display> ErrorPopup for Result<(), E> {
 | 
					impl<E: std::fmt::Display> ErrorPopup for Result<(), E> {
 | 
				
			||||||
@@ -35,6 +36,14 @@ impl<E: std::fmt::Display> ErrorPopup for Result<(), E> {
 | 
				
			|||||||
            rx.recv().unwrap();
 | 
					            rx.recv().unwrap();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn error_popup_nowait(self, title: &str) {
 | 
				
			||||||
 | 
					        if let Err(e) = self {
 | 
				
			||||||
 | 
					            MessageDialogBuilder::new(title, format!("{e}"))
 | 
				
			||||||
 | 
					                .kind(MessageDialogKind::Error)
 | 
				
			||||||
 | 
					                .show(|_| {})
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -85,3 +85,9 @@ pub async fn save_config(config: AppConfig, app_state: State<'_, AppState>) -> R
 | 
				
			|||||||
pub async fn launch_terminal(base: bool) -> Result<(), LaunchTerminalError> {
 | 
					pub async fn launch_terminal(base: bool) -> Result<(), LaunchTerminalError> {
 | 
				
			||||||
    terminal::launch(base).await
 | 
					    terminal::launch(base).await
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[tauri::command]
 | 
				
			||||||
 | 
					pub async fn get_setup_errors(app_state: State<'_, AppState>) -> Result<Vec<String>, ()> {
 | 
				
			||||||
 | 
					    Ok(app_state.setup_errors.clone())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -30,12 +30,20 @@ pub struct AppState {
 | 
				
			|||||||
    pub waiting_requests: RwLock<HashMap<u64, RequestWaiter>>,
 | 
					    pub waiting_requests: RwLock<HashMap<u64, RequestWaiter>>,
 | 
				
			||||||
    pub pending_terminal_request: RwLock<bool>,
 | 
					    pub pending_terminal_request: RwLock<bool>,
 | 
				
			||||||
    pub bans: RwLock<std::collections::HashSet<Option<Client>>>,
 | 
					    pub bans: RwLock<std::collections::HashSet<Option<Client>>>,
 | 
				
			||||||
 | 
					    // setup_errors is never modified and so doesn't need to be wrapped in RwLock
 | 
				
			||||||
 | 
					    pub setup_errors: Vec<String>,
 | 
				
			||||||
    server: RwLock<Server>,
 | 
					    server: RwLock<Server>,
 | 
				
			||||||
    pool: sqlx::SqlitePool,
 | 
					    pool: sqlx::SqlitePool,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl AppState {
 | 
					impl AppState {
 | 
				
			||||||
    pub fn new(config: AppConfig, session: Session, server: Server, pool: SqlitePool) -> AppState {
 | 
					    pub fn new(
 | 
				
			||||||
 | 
					        config: AppConfig,
 | 
				
			||||||
 | 
					        session: Session,
 | 
				
			||||||
 | 
					        server: Server,
 | 
				
			||||||
 | 
					        pool: SqlitePool,
 | 
				
			||||||
 | 
					        setup_errors: Vec<String>,
 | 
				
			||||||
 | 
					    ) -> AppState {
 | 
				
			||||||
        AppState {
 | 
					        AppState {
 | 
				
			||||||
            config: RwLock::new(config),
 | 
					            config: RwLock::new(config),
 | 
				
			||||||
            session: RwLock::new(session),
 | 
					            session: RwLock::new(session),
 | 
				
			||||||
@@ -43,6 +51,7 @@ impl AppState {
 | 
				
			|||||||
            waiting_requests: RwLock::new(HashMap::new()),
 | 
					            waiting_requests: RwLock::new(HashMap::new()),
 | 
				
			||||||
            pending_terminal_request: RwLock::new(false),
 | 
					            pending_terminal_request: RwLock::new(false),
 | 
				
			||||||
            bans: RwLock::new(HashSet::new()),
 | 
					            bans: RwLock::new(HashSet::new()),
 | 
				
			||||||
 | 
					            setup_errors,
 | 
				
			||||||
            server: RwLock::new(server),
 | 
					            server: RwLock::new(server),
 | 
				
			||||||
            pool,
 | 
					            pool,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,7 +8,7 @@
 | 
				
			|||||||
  },
 | 
					  },
 | 
				
			||||||
  "package": {
 | 
					  "package": {
 | 
				
			||||||
    "productName": "creddy",
 | 
					    "productName": "creddy",
 | 
				
			||||||
    "version": "0.3.1"
 | 
					    "version": "0.3.2"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "tauri": {
 | 
					  "tauri": {
 | 
				
			||||||
    "allowlist": {
 | 
					    "allowlist": {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -28,7 +28,12 @@ listen('launch-terminal-request', async (tauriEvent) => {
 | 
				
			|||||||
        // else, session is unlocked, so do nothing
 | 
					        // else, session is unlocked, so do nothing
 | 
				
			||||||
        // (although we shouldn't even get the event in that case)
 | 
					        // (although we shouldn't even get the event in that case)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
})
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					invoke('get_setup_errors')
 | 
				
			||||||
 | 
					    .then(errs => {
 | 
				
			||||||
 | 
					        $appState.setupErrors = errs.map(e => ({msg: e, show: true}));
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
acceptRequest();
 | 
					acceptRequest();
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,6 +8,7 @@ export let appState = writable({
 | 
				
			|||||||
    currentRequest: null,
 | 
					    currentRequest: null,
 | 
				
			||||||
    pendingRequests: queue(),
 | 
					    pendingRequests: queue(),
 | 
				
			||||||
    credentialStatus: 'locked',
 | 
					    credentialStatus: 'locked',
 | 
				
			||||||
 | 
					    setupErrors: [],
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -52,3 +52,16 @@
 | 
				
			|||||||
        {/await}
 | 
					        {/await}
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{#if $appState.setupErrors.some(e => e.show)}
 | 
				
			||||||
 | 
					    <div class="toast">
 | 
				
			||||||
 | 
					        {#each $appState.setupErrors as error}
 | 
				
			||||||
 | 
					            {#if error.show}
 | 
				
			||||||
 | 
					                <div class="alert alert-error shadow-lg">
 | 
				
			||||||
 | 
					                    {error.msg}
 | 
				
			||||||
 | 
					                    <button class="btn btn-sm btn-alert-error" on:click={() => error.show = false}>Ok</button>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            {/if}
 | 
				
			||||||
 | 
					        {/each}
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					{/if}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user