mirror of
https://github.com/t8y2/dbx.git
synced 2026-10-29 08:11:06 +00:00
feat(app): handle SQL export and tray updates
This commit is contained in:
@@ -9,6 +9,11 @@ pub fn pending_open_sql_files(state: tauri::State<'_, ExternalSqlOpenState>) ->
|
||||
dedupe_paths(paths)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn read_external_sql_file(path: String) -> Result<String, String> {
|
||||
read_external_sql_file_content(Path::new(&path))
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct ExternalSqlOpenState {
|
||||
pending: Mutex<Vec<String>>,
|
||||
@@ -55,6 +60,13 @@ pub fn is_sql_file_path(path: &Path) -> bool {
|
||||
path.extension().and_then(|ext| ext.to_str()).map(|ext| ext.eq_ignore_ascii_case("sql")).unwrap_or(false)
|
||||
}
|
||||
|
||||
pub fn read_external_sql_file_content(path: &Path) -> Result<String, String> {
|
||||
if !is_sql_file_path(path) {
|
||||
return Err("Only .sql files can be opened this way".to_string());
|
||||
}
|
||||
std::fs::read_to_string(path).map_err(|e| format!("Failed to read SQL file: {e}"))
|
||||
}
|
||||
|
||||
fn dedupe_paths(paths: Vec<String>) -> Vec<String> {
|
||||
let mut unique = Vec::new();
|
||||
for path in paths {
|
||||
@@ -91,4 +103,26 @@ mod tests {
|
||||
assert_eq!(state.drain(), vec!["/tmp/a.sql"]);
|
||||
assert!(state.drain().is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reads_external_sql_file_content() {
|
||||
let path = std::env::temp_dir().join(format!("dbx-test-{}.sql", uuid::Uuid::new_v4()));
|
||||
std::fs::write(&path, "select 1;").unwrap();
|
||||
|
||||
let result = read_external_sql_file_content(&path);
|
||||
|
||||
let _ = std::fs::remove_file(&path);
|
||||
assert_eq!(result.unwrap(), "select 1;");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rejects_external_non_sql_file_content() {
|
||||
let path = std::env::temp_dir().join(format!("dbx-test-{}.txt", uuid::Uuid::new_v4()));
|
||||
std::fs::write(&path, "select 1;").unwrap();
|
||||
|
||||
let result = read_external_sql_file_content(&path);
|
||||
|
||||
let _ = std::fs::remove_file(&path);
|
||||
assert!(result.unwrap_err().contains(".sql"));
|
||||
}
|
||||
}
|
||||
|
||||
+66
-7
@@ -8,8 +8,66 @@ use commands::connection::AppState;
|
||||
use dbx_core::storage::Storage;
|
||||
use std::sync::Arc;
|
||||
use std::time::Instant;
|
||||
use tauri::{
|
||||
menu::MenuBuilder,
|
||||
tray::{MouseButton, MouseButtonState, TrayIconBuilder, TrayIconEvent},
|
||||
};
|
||||
use tauri::{Emitter, Manager, RunEvent};
|
||||
|
||||
fn should_hide_window_on_close(target_os: &str) -> bool {
|
||||
matches!(target_os, "macos" | "windows")
|
||||
}
|
||||
|
||||
fn show_main_window(app: &tauri::AppHandle) {
|
||||
if let Some(window) = app.get_webview_window("main") {
|
||||
let _ = window.show();
|
||||
let _ = window.unminimize();
|
||||
let _ = window.set_focus();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(not(target_os = "windows"), allow(dead_code))]
|
||||
fn setup_windows_tray(app: &mut tauri::App) -> tauri::Result<()> {
|
||||
let menu = MenuBuilder::new(app).text("show", "Show DBX").separator().text("quit", "Quit DBX").build()?;
|
||||
let mut tray = TrayIconBuilder::with_id("main-tray").tooltip("DBX").menu(&menu).show_menu_on_left_click(false);
|
||||
|
||||
if let Some(icon) = app.default_window_icon().cloned() {
|
||||
tray = tray.icon(icon);
|
||||
}
|
||||
|
||||
tray.on_menu_event(|app, event| {
|
||||
if event.id() == "show" {
|
||||
show_main_window(app);
|
||||
} else if event.id() == "quit" {
|
||||
app.exit(0);
|
||||
}
|
||||
})
|
||||
.on_tray_icon_event(|tray, event| match event {
|
||||
TrayIconEvent::Click { button: MouseButton::Left, button_state: MouseButtonState::Up, .. }
|
||||
| TrayIconEvent::DoubleClick { button: MouseButton::Left, .. } => show_main_window(tray.app_handle()),
|
||||
_ => {}
|
||||
})
|
||||
.build(app)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::should_hide_window_on_close;
|
||||
|
||||
#[test]
|
||||
fn hides_window_on_close_for_windows_and_macos() {
|
||||
assert!(should_hide_window_on_close("windows"));
|
||||
assert!(should_hide_window_on_close("macos"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn does_not_hide_window_on_close_for_other_platforms() {
|
||||
assert!(!should_hide_window_on_close("linux"));
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
||||
pub fn run() {
|
||||
rustls::crypto::aws_lc_rs::default_provider().install_default().expect("Failed to install rustls crypto provider");
|
||||
@@ -75,15 +133,18 @@ pub fn run() {
|
||||
let _ = window.set_decorations(false);
|
||||
}
|
||||
}
|
||||
#[cfg(target_os = "windows")]
|
||||
setup_windows_tray(app)?;
|
||||
window_state_guard::enforce_main_window_bounds(app.handle());
|
||||
|
||||
Ok(())
|
||||
})
|
||||
.on_window_event(|window, event| {
|
||||
#[cfg(target_os = "macos")]
|
||||
if let tauri::WindowEvent::CloseRequested { api, .. } = event {
|
||||
window.hide().unwrap();
|
||||
api.prevent_close();
|
||||
if should_hide_window_on_close(std::env::consts::OS) {
|
||||
let _ = window.hide();
|
||||
api.prevent_close();
|
||||
}
|
||||
}
|
||||
})
|
||||
.invoke_handler(tauri::generate_handler![
|
||||
@@ -135,6 +196,7 @@ pub fn run() {
|
||||
commands::sql_file::execute_sql_file,
|
||||
commands::sql_file::cancel_sql_file_execution,
|
||||
commands::external_sql::pending_open_sql_files,
|
||||
commands::external_sql::read_external_sql_file,
|
||||
commands::table_import::preview_table_import_file,
|
||||
commands::table_import::import_table_file,
|
||||
commands::table_import::cancel_table_import,
|
||||
@@ -215,10 +277,7 @@ pub fn run() {
|
||||
#[cfg(target_os = "macos")]
|
||||
if let RunEvent::Reopen { has_visible_windows, .. } = &event {
|
||||
if !has_visible_windows {
|
||||
if let Some(window) = app_handle.get_webview_window("main") {
|
||||
let _ = window.show();
|
||||
let _ = window.set_focus();
|
||||
}
|
||||
show_main_window(app_handle);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user