fix: serialize tags as array (not JSON string), DevTools debug-only

- ConnectionRecord.tags changed from String to Vec<String> so the
  frontend receives a proper array instead of a raw JSON string.
  The old behavior caused v-for to iterate characters, corrupting
  the connection display in the sidebar.
- DevTools now only auto-opens in debug builds (cfg(debug_assertions)),
  not in production.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Vantz Stockwell 2026-03-24 16:58:58 -04:00
parent d844a69cdb
commit 6e33bbdcf1
2 changed files with 16 additions and 13 deletions

View File

@ -38,10 +38,8 @@ pub struct ConnectionRecord {
pub group_id: Option<i64>, pub group_id: Option<i64>,
pub credential_id: Option<i64>, pub credential_id: Option<i64>,
pub color: Option<String>, pub color: Option<String>,
/// JSON array string, e.g. `["linux","prod"]` pub tags: Vec<String>,
pub tags: String,
pub notes: Option<String>, pub notes: Option<String>,
/// JSON object string, e.g. `{"keepalive":30}`
pub options: String, pub options: String,
pub sort_order: i64, pub sort_order: i64,
pub last_connected: Option<String>, pub last_connected: Option<String>,
@ -254,7 +252,7 @@ impl ConnectionService {
group_id: input.group_id, group_id: input.group_id,
credential_id: input.credential_id, credential_id: input.credential_id,
color: input.color, color: input.color,
tags: tags_json, tags: input.tags,
notes: input.notes, notes: input.notes,
options: options_json, options: options_json,
sort_order, sort_order,
@ -439,6 +437,8 @@ impl ConnectionService {
/// ///
/// Column order must match the SELECT lists used throughout this module. /// Column order must match the SELECT lists used throughout this module.
fn map_connection_row(row: &rusqlite::Row<'_>) -> rusqlite::Result<ConnectionRecord> { fn map_connection_row(row: &rusqlite::Row<'_>) -> rusqlite::Result<ConnectionRecord> {
let tags_json: String = row.get(8)?;
let tags: Vec<String> = serde_json::from_str(&tags_json).unwrap_or_default();
Ok(ConnectionRecord { Ok(ConnectionRecord {
id: row.get(0)?, id: row.get(0)?,
name: row.get(1)?, name: row.get(1)?,
@ -448,7 +448,7 @@ fn map_connection_row(row: &rusqlite::Row<'_>) -> rusqlite::Result<ConnectionRec
group_id: row.get::<_, Option<i64>>(5)?, group_id: row.get::<_, Option<i64>>(5)?,
credential_id: row.get::<_, Option<i64>>(6)?, credential_id: row.get::<_, Option<i64>>(6)?,
color: row.get::<_, Option<String>>(7)?, color: row.get::<_, Option<String>>(7)?,
tags: row.get(8)?, tags,
notes: row.get::<_, Option<String>>(9)?, notes: row.get::<_, Option<String>>(9)?,
options: row.get(10)?, options: row.get(10)?,
sort_order: row.get(11)?, sort_order: row.get(11)?,
@ -556,12 +556,10 @@ mod tests {
} }
#[test] #[test]
fn tags_serialised_as_json_array() { fn tags_serialised_as_vec() {
let svc = make_service(); let svc = make_service();
let rec = svc.create_connection(default_input("tagged")).unwrap(); let rec = svc.create_connection(default_input("tagged")).unwrap();
// tags should be a valid JSON array assert_eq!(rec.tags, vec!["linux", "prod"]);
let parsed: Vec<String> = serde_json::from_str(&rec.tags).unwrap();
assert_eq!(parsed, vec!["linux", "prod"]);
} }
#[test] #[test]
@ -629,8 +627,7 @@ mod tests {
.unwrap(); .unwrap();
let updated = svc.get_connection(rec.id).unwrap(); let updated = svc.get_connection(rec.id).unwrap();
let parsed: Vec<String> = serde_json::from_str(&updated.tags).unwrap(); assert_eq!(updated.tags, vec!["windows"]);
assert_eq!(parsed, vec!["windows"]);
} }
#[test] #[test]

View File

@ -87,8 +87,14 @@ pub fn run() {
.plugin(tauri_plugin_shell::init()) .plugin(tauri_plugin_shell::init())
.manage(app_state) .manage(app_state)
.setup(|app| { .setup(|app| {
use tauri::Manager; #[cfg(debug_assertions)]
if let Some(window) = app.get_webview_window("main") { let _ = window.open_devtools(); } {
use tauri::Manager;
if let Some(window) = app.get_webview_window("main") {
window.open_devtools();
}
}
let _ = app;
Ok(()) Ok(())
}) })
.invoke_handler(tauri::generate_handler![ .invoke_handler(tauri::generate_handler![