diff --git a/src-tauri/src/commands/connection.rs b/src-tauri/src/commands/connection.rs index 1316c58f7..3aebd10ef 100644 --- a/src-tauri/src/commands/connection.rs +++ b/src-tauri/src/commands/connection.rs @@ -248,6 +248,33 @@ pub async fn load_connections(app: AppHandle) -> Result, S load_connections_from_file(&path, &*store) } +fn sidebar_layout_file(app: &AppHandle) -> Result { + let dir = app.path().app_data_dir().map_err(|e| e.to_string())?; + std::fs::create_dir_all(&dir).map_err(|e| e.to_string())?; + Ok(dir.join("sidebar_layout.json")) +} + +#[tauri::command] +pub async fn save_sidebar_layout( + app: AppHandle, + layout: serde_json::Value, +) -> Result<(), String> { + let path = sidebar_layout_file(&app)?; + let json = serde_json::to_string_pretty(&layout).map_err(|e| e.to_string())?; + std::fs::write(&path, json).map_err(|e| e.to_string()) +} + +#[tauri::command] +pub async fn load_sidebar_layout(app: AppHandle) -> Result, String> { + let path = sidebar_layout_file(&app)?; + if !path.exists() { + return Ok(None); + } + let content = std::fs::read_to_string(&path).map_err(|e| e.to_string())?; + let value: serde_json::Value = serde_json::from_str(&content).map_err(|e| e.to_string())?; + Ok(Some(value)) +} + #[tauri::command] pub async fn test_connection( state: State<'_, Arc>, diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index a70203ef4..58a0fafb9 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -54,6 +54,8 @@ pub fn run() { commands::connection::disconnect_db, commands::connection::save_connections, commands::connection::load_connections, + commands::connection::save_sidebar_layout, + commands::connection::load_sidebar_layout, commands::schema::list_databases, commands::schema::list_tables, commands::schema::list_schemas, diff --git a/src/App.vue b/src/App.vue index 4a90b1a46..77f2afb92 100644 --- a/src/App.vue +++ b/src/App.vue @@ -135,6 +135,8 @@ const showTableImportDialog = ref(false); const showStructureEditorDialog = ref(false); const showFieldLineageDialog = ref(false); const showDatabaseSearchDialog = ref(false); +const showImportLayoutConfirm = ref(false); +const pendingImportLayout = ref(null); const showConfigPassphraseDialog = ref(false); const configPassphraseMode = ref<"export" | "import">("export"); const configPassphraseError = ref(""); @@ -409,8 +411,12 @@ async function onImportClick() { configPassphraseError.value = ""; showConfigPassphraseDialog.value = true; } else { - const count = await connectionStore.importConnectionsFromFile(result.content, null); + const { count, layout } = await connectionStore.importConnectionsFromFile(result.content, null); toast(count > 0 ? t("configExport.importSuccess", { count }) : t("configExport.importNone"), 2000); + if (layout && count > 0) { + pendingImportLayout.value = layout; + showImportLayoutConfirm.value = true; + } } } catch (e: any) { toast(e?.message || String(e), 4000); @@ -419,9 +425,13 @@ async function onImportClick() { async function onImportConfirm(passphrase: string) { try { - const count = await connectionStore.importConnectionsFromFile(pendingImportContent.value, passphrase); + const { count, layout } = await connectionStore.importConnectionsFromFile(pendingImportContent.value, passphrase); showConfigPassphraseDialog.value = false; toast(count > 0 ? t("configExport.importSuccess", { count }) : t("configExport.importNone"), 2000); + if (layout && count > 0) { + pendingImportLayout.value = layout; + showImportLayoutConfirm.value = true; + } } catch (e: any) { configPassphraseError.value = e?.message === "wrong_passphrase" ? t("configExport.wrongPassphrase") : (e?.message || String(e)); } @@ -1707,6 +1717,18 @@ async function setupFileDrop() { :external-error="configPassphraseError" @confirm="configPassphraseMode === 'export' ? onExportConfirm($event) : onImportConfirm($event)" /> + + + + {{ t('configExport.importLayoutTitle') }} + +

{{ t('configExport.importLayoutConfirm') }}

+ + + + +
+
diff --git a/src/components/sidebar/ConnectionTree.vue b/src/components/sidebar/ConnectionTree.vue index 362ea45e7..e97700278 100644 --- a/src/components/sidebar/ConnectionTree.vue +++ b/src/components/sidebar/ConnectionTree.vue @@ -1,7 +1,7 @@