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

View File

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