Skip to content

Commit 7de9b7d

Browse files
boxerabclaude
andcommitted
ui: delete snapshots from the sidebar
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent b67adf1 commit 7de9b7d

3 files changed

Lines changed: 35 additions & 2 deletions

File tree

crates/ui/frontend/src/App.svelte

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import {
88
listNodes, listLinks, socketPath, onSwdEvent,
99
createLink, deleteLink, loadLayout, saveLayout,
10-
listSnapshots, saveSnapshot, restoreSnapshot, getMetrics,
10+
listSnapshots, saveSnapshot, restoreSnapshot, deleteSnapshot, getMetrics,
1111
} from "./swd.js";
1212
import { layoutNodes } from "./layout.js";
1313
import MetricsNode from "./MetricsNode.svelte";
@@ -222,6 +222,16 @@
222222
}
223223
}
224224
225+
async function onDeleteSnapshot(name) {
226+
try {
227+
await deleteSnapshot(name);
228+
await refreshSnapshots();
229+
pushEvent({ kind: "SnapshotDeleted", data: { name } });
230+
} catch (e) {
231+
status = `snapshot delete failed: ${e}`;
232+
}
233+
}
234+
225235
async function onRestoreSnapshot(name) {
226236
try {
227237
const { applied, skipped } = await restoreSnapshot(name);
@@ -409,6 +419,7 @@
409419
<li class="snap-row">
410420
<span class="snap-name">{s}</span>
411421
<button class="restore" onclick={() => onRestoreSnapshot(s)}>Restore</button>
422+
<button class="del" title="delete snapshot" onclick={() => onDeleteSnapshot(s)}></button>
412423
</li>
413424
{:else}
414425
<li class="muted">none saved</li>
@@ -514,6 +525,12 @@
514525
.snap-row .snap-name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
515526
.snap-row .restore { background: transparent; color: var(--accent); border: 1px solid var(--border); }
516527
.snap-row .restore:hover { border-color: var(--accent); }
528+
.snap-row .del {
529+
flex-shrink: 0; background: transparent; color: var(--muted);
530+
border: 1px solid var(--border); border-radius: 4px;
531+
padding: 4px 7px; font-size: 11px; cursor: pointer;
532+
}
533+
.snap-row .del:hover { color: #ff8080; border-color: #ff8080; }
517534
518535
/* Dark-theme overrides for Svelte Flow's default widgets. */
519536
:global(.svelte-flow__controls) {

crates/ui/frontend/src/swd.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ export const saveLayout = (positions) => invoke("save_layout", { positions });
2424
export const listSnapshots = () => invoke("list_snapshots");
2525
export const saveSnapshot = (name) => invoke("save_snapshot", { name });
2626
export const restoreSnapshot = (name) => invoke("restore_snapshot", { name });
27+
export const deleteSnapshot = (name) => invoke("delete_snapshot", { name });
2728

2829
// Per-node latency percentiles + xrun counts. Polled for the overlay.
2930
export const getMetrics = () => invoke("get_metrics");

crates/ui/src/main.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,21 @@ async fn restore_snapshot(
248248
}
249249
}
250250

251+
#[tauri::command]
252+
async fn delete_snapshot(name: String) -> Result<(), String> {
253+
// Snapshot names are plain file stems; reject anything that could
254+
// escape the snapshots dir before touching the filesystem.
255+
if name.is_empty() || name.contains(['/', '\\']) || name.contains("..") {
256+
return Err("invalid snapshot name".into());
257+
}
258+
let path = data_dir().join("snapshots").join(format!("{name}.json"));
259+
match std::fs::remove_file(&path) {
260+
Ok(()) => Ok(()),
261+
Err(e) if e.kind() == std::io::ErrorKind::NotFound => Ok(()),
262+
Err(e) => Err(e.to_string()),
263+
}
264+
}
265+
251266
async fn run_event_pump(app: AppHandle) -> Result<()> {
252267
let path = default_socket_path();
253268
let mut rx = connect_subscriber(&path, None).await?;
@@ -312,7 +327,7 @@ fn main() {
312327
.invoke_handler(tauri::generate_handler![
313328
list_nodes, list_ports, list_links, socket_path,
314329
create_link, delete_link, load_layout, save_layout,
315-
list_snapshots, save_snapshot, restore_snapshot, get_metrics,
330+
list_snapshots, save_snapshot, restore_snapshot, delete_snapshot, get_metrics,
316331
read_config, write_config, apply_rules, apply_script,
317332
])
318333
.run(tauri::generate_context!())

0 commit comments

Comments
 (0)