From 2bf95bfcd09afbb80a3df0133eee1188da4718d5 Mon Sep 17 00:00:00 2001 From: "Bauer, Georg" Date: Wed, 22 Jul 2026 15:15:31 +0200 Subject: [PATCH] Spec script deletion as confirm_delete_modal and cover it with a test. Co-Authored-By: Claude Fable 5 --- crates/bds-ui/src/app.rs | 31 +++++++++++++++++++++++++++++++ specs/action_patterns.allium | 3 ++- specs/editor_script.allium | 15 ++++++++++++--- 3 files changed, 45 insertions(+), 4 deletions(-) diff --git a/crates/bds-ui/src/app.rs b/crates/bds-ui/src/app.rs index 6a075aa..ad2576d 100644 --- a/crates/bds-ui/src/app.rs +++ b/crates/bds-ui/src/app.rs @@ -12498,6 +12498,37 @@ mod tests { ); } + #[test] + fn script_delete_requires_confirmation_before_removal() { + let (db, project, tmp) = setup(); + let mut app = make_app(db, project, &tmp); + let _ = app.update(Message::CreateScript); + let script_id = app.sidebar_scripts[0].id.clone(); + + let _ = app.update(Message::ScriptEditor(ScriptEditorMsg::Delete)); + assert!( + bds_core::db::queries::script::get_script_by_id( + app.db.as_ref().unwrap().conn(), + &script_id + ) + .is_ok() + ); + assert!(app.tabs.iter().any(|tab| tab.id == script_id)); + + let _ = app.update(Message::ConfirmModal(modal::ConfirmAction::DeleteScript( + script_id.clone(), + ))); + assert!( + bds_core::db::queries::script::get_script_by_id( + app.db.as_ref().unwrap().conn(), + &script_id + ) + .is_err() + ); + assert!(!app.tabs.iter().any(|tab| tab.id == script_id)); + assert!(!app.script_editors.contains_key(&script_id)); + } + #[test] fn rebuild_completion_refreshes_project_metadata_in_settings() { let (db, project, tmp) = setup(); diff --git a/specs/action_patterns.allium b/specs/action_patterns.allium index 3227d8f..a59e0ac 100644 --- a/specs/action_patterns.allium +++ b/specs/action_patterns.allium @@ -219,7 +219,8 @@ config { ConfirmationAssignment(action: "tag_merge", pattern: confirm_dialog), -- "Merge N tags into {target}? Cannot be undone." ConfirmationAssignment(action: "rebuild_operations", pattern: none), - ConfirmationAssignment(action: "script_delete", pattern: none), + ConfirmationAssignment(action: "script_delete", pattern: confirm_delete_modal), + -- shows script title, no reference list ConfirmationAssignment(action: "menu_item_delete", pattern: none), ConfirmationAssignment(action: "metadata_diff_field_sync", pattern: none), ConfirmationAssignment(action: "import_execute", pattern: none), diff --git a/specs/editor_script.allium b/specs/editor_script.allium index c211cbe..7b4459a 100644 --- a/specs/editor_script.allium +++ b/specs/editor_script.allium @@ -43,6 +43,7 @@ surface ScriptEditorSurface { ScriptRunRequested(editor.script_id) ScriptCheckSyntaxRequested(editor.script_id) ScriptDeleteRequested(editor.script_id) + ScriptDeleteConfirmed(editor.script_id) @guarantee HeaderLayout -- Header bar with script title tab. @@ -123,11 +124,19 @@ rule ScriptRun { -- Output panel tab, which auto-opens when not visible } -rule ScriptDelete { +rule ScriptDeleteAction { when: ScriptDeleteRequested(script_id) let target = script/Script{id: script_id} - -- No confirmation dialog (action_patterns.allium - -- confirmation_assignments: script_delete -> none) + ensures: ConfirmDeleteModalOpened(script_id) + -- custom modal (not a native dialog): script title, no + -- reference list; Cancel + Delete (destructive red style) + -- — action_patterns.allium + -- confirmation_assignments: script_delete +} + +rule ScriptDeleteExecute { + when: ScriptDeleteConfirmed(script_id) + let target = script/Script{id: script_id} ensures: DeleteScriptRequested(target) -- DB record + published script file: script.allium DeleteScript ensures: closeTab(script_id)