feat: add persistent dynamic panels
CI / rust (push) Successful in 2m10s

This commit is contained in:
2026-08-31 18:43:36 -07:00
parent 4ed7613b22
commit 3409cabb80
13 changed files with 1125 additions and 133 deletions
+63
View File
@@ -75,6 +75,12 @@ CREATE TABLE IF NOT EXISTS workspace_buzz_channels (
channel_name TEXT NOT NULL,
PRIMARY KEY (workspace_id, account_id, channel_id)
) STRICT;
CREATE TABLE IF NOT EXISTS workspace_snapshots (
workspace_id TEXT PRIMARY KEY NOT NULL,
snapshot_json TEXT NOT NULL,
updated_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
) STRICT;
";
#[derive(Debug)]
@@ -222,6 +228,44 @@ impl Store {
.transpose()
}
/// Save a credential-free UI snapshot for a workspace.
///
/// The caller owns the versioned JSON shape. This storage boundary treats
/// it as opaque local state and must never receive secrets or transcripts.
///
/// # Errors
///
/// Returns an error when `SQLite` cannot insert or update the snapshot.
pub fn save_workspace_snapshot(&self, workspace_id: &str, snapshot_json: &str) -> Result<()> {
self.connection.execute(
r"
INSERT INTO workspace_snapshots (workspace_id, snapshot_json)
VALUES (?1, ?2)
ON CONFLICT(workspace_id) DO UPDATE SET
snapshot_json = excluded.snapshot_json,
updated_at = CURRENT_TIMESTAMP
",
params![workspace_id, snapshot_json],
)?;
Ok(())
}
/// Load the last credential-free UI snapshot for a workspace.
///
/// # Errors
///
/// Returns an error when `SQLite` cannot read the snapshot.
pub fn workspace_snapshot(&self, workspace_id: &str) -> Result<Option<String>> {
self.connection
.query_row(
"SELECT snapshot_json FROM workspace_snapshots WHERE workspace_id = ?1",
[workspace_id],
|row| row.get(0),
)
.optional()
.map_err(StorageError::from)
}
#[cfg(test)]
fn contains_column(&self, table: &str, column: &str) -> Result<bool> {
let mut statement = self
@@ -281,4 +325,23 @@ mod tests {
);
}
}
#[test]
fn workspace_snapshot_round_trips_as_opaque_local_state() {
let store = Store::open_in_memory().expect("store should initialize");
assert_eq!(store.workspace_snapshot("lumbridge-code").unwrap(), None);
store
.save_workspace_snapshot(
"lumbridge-code",
r#"{"selected":7,"panels":[{"id":7,"kind":"terminal"}]}"#,
)
.unwrap();
assert_eq!(
store
.workspace_snapshot("lumbridge-code")
.unwrap()
.as_deref(),
Some(r#"{"selected":7,"panels":[{"id":7,"kind":"terminal"}]}"#)
);
}
}