make it possible to multi select history of slides #9

Open
opened 2026-04-14 04:01:02 +00:00 by despiegk · 4 comments
Owner

image

  • make it possible to multi select history of slides
  • make it possible to delete one or more of older slides, remove markdown, images, ... from history
![image](/attachments/583da93a-e355-4470-a4b7-84c5e8d470c8) - [ ] make it possible to multi select history of slides - [ ] make it possible to delete one or more of older slides, remove markdown, images, ... from history
770 KiB
Author
Owner

Implementation Spec for Issue #9

Objective

Add multi-selection and batch deletion to the Slide Version History panel in the hero_slides_ui web dashboard. Users must be able to select one or more version cards (via checkbox), then delete the selected versions — removing their .png image and .md content files from output/.versions/<slide_name>/ on disk. The current version must be protected from deletion.

Requirements

  • Users can select individual version cards via checkbox click
  • A "Select All" checkbox appears in the version panel toolbar when at least one version is listed; it selects/deselects all non-current versions
  • A "Delete Selected" button appears in the version panel toolbar whenever one or more non-current versions are selected
  • Clicking "Delete Selected" shows a confirm modal listing the count, then calls the new slide.deleteVersions RPC method
  • The current version cannot be selected for deletion; its checkbox is disabled
  • After deletion the panel re-renders to reflect the new list
  • A new slide.deleteVersions RPC method accepts deck_path, slide_name, and versions: string[] and removes the specified version files from disk
  • A new lib function slide_delete_versions(deck_path, slide_name, &[version]) removes only the .png and .md files for each given version tag; does NOT renumber surviving versions
  • OpenRPC spec and generated client stub are updated to include slide.deleteVersions

Files to Modify/Create

File Change
crates/hero_slides_lib/src/deck.rs Add slide_delete_versions() public function
crates/hero_slides_lib/src/lib.rs Re-export slide_delete_versions
crates/hero_slides_server/src/rpc.rs Add "slide.deleteVersions" match arm + handler
crates/hero_slides_server/openrpc.json Add slide.deleteVersions method entry
crates/hero_slides_server/openrpc.client.generated.rs Add generated stub for slide_delete_versions
crates/hero_slides_ui/static/js/dashboard.js Add selection state, selection UI logic, deleteSelectedVersions(), update renderVersions()
crates/hero_slides_ui/templates/index.html Add toolbar with "Select All" checkbox and "Delete Selected" button to version panel header
crates/hero_slides_ui/static/css/dashboard.css Add .version-card.selected, .version-card-cb, .version-panel-toolbar styles

Implementation Plan

Step 1: Add slide_delete_versions to hero_slides_lib

Files: crates/hero_slides_lib/src/deck.rs, crates/hero_slides_lib/src/lib.rs

Add a new public function slide_delete_versions(deck_path: &Path, slide_name: &str, versions: &[&str]) -> Result<(), HeroSlidesError> that, for each version tag, removes output/.versions/<slide_name>/<tag>.png and output/.versions/<slide_name>/<tag>.md if they exist. Silently skips missing files. Re-export in lib.rs.

Dependencies: none

Step 2: Add slide.deleteVersions RPC handler

Files: crates/hero_slides_server/src/rpc.rs

Add "slide.deleteVersions" => handle_slide_delete_versions(&req.params).await, to the match block alongside other slide.* methods. Add the handle_slide_delete_versions async function that parses deck_path, slide_name, versions from params, calls hero_slides_lib::slide_delete_versions in a spawn_blocking block, and returns {"deleted": N}.

Dependencies: Step 1

Step 3: Update OpenRPC spec and generated client stub

Files: crates/hero_slides_server/openrpc.json, crates/hero_slides_server/openrpc.client.generated.rs

Add slide.deleteVersions method to openrpc.json with params deck_path (string), slide_name (string), versions (array of strings) and result {"deleted": integer}. Add corresponding SlideDeleteVersionsInput, SlideDeleteVersionsOutput structs and slide_delete_versions method to the generated client file.

Dependencies: Step 2

Step 4: Add CSS for selected version cards

Files: crates/hero_slides_ui/static/css/dashboard.css

Add .version-card.selected (blue border + tinted background), .version-card-cb (checkbox sizing), and .version-panel-toolbar (flex bar) styles after the existing .version-card.current rule.

Dependencies: none

Step 5: Update HTML version panel markup

Files: crates/hero_slides_ui/templates/index.html

Add a version-panel-toolbar div inside the version panel (between the slide strip and the version list), containing a "Select All" checkbox and a "Delete (N)" button (initially hidden).

Dependencies: Step 4

Step 6: Add JavaScript multi-select and deletion logic

Files: crates/hero_slides_ui/static/js/dashboard.js

  • Add versionSelectedVersions = new Set() state variable
  • Update renderVersions(data) to: show toolbar, add data-version attribute and checkbox to each card, wire .version-card click to toggleVersionSelection, apply .selected class
  • Add toggleVersionSelection(tag, event) — toggles tag in the Set, updates card class and checkbox
  • Add toggleSelectAllVersions(checked) — selects/deselects all non-current cards using data-version
  • Add updateVersionSelectionUI() — syncs delete button visibility, count span, and select-all indeterminate state
  • Add deleteSelectedVersions() — shows confirm modal, calls rpc('slide.deleteVersions', {...}), then calls loadVersionHistory(versionSlideName) on success

Dependencies: Steps 4, 5

Acceptance Criteria

  • Non-current version cards are selectable via checkbox or card click; selected cards highlight in blue
  • Current version card checkbox is disabled; clicking current card does nothing
  • "Delete (N)" button appears when N > 0 versions are selected; is hidden otherwise
  • "All" checkbox selects all non-current versions; shows indeterminate when partially selected
  • Confirming deletion calls slide.deleteVersions RPC and the files are removed from disk
  • Version list re-renders after deletion; deleted versions are gone, current version remains
  • slide_delete_versions in hero_slides_lib silently skips nonexistent version tags
  • openrpc.json and openrpc.client.generated.rs contain the slide.deleteVersions entry

Notes

  • Version numbering is not affected by deletion — surviving versions keep original numbers (gaps are fine)
  • Current version protection is UI-only; the server does not enforce it
  • The openrpc.client.generated.rs file appears to be manually maintained (not auto-generated by build.rs) — edit it directly
  • Each version tag vNNN has up to two files: <tag>.png and <tag>.md — both must be removed
  • File layout: output/.versions/<slide_name>/vNNN.{png,md}
## Implementation Spec for Issue #9 ### Objective Add multi-selection and batch deletion to the Slide Version History panel in the hero_slides_ui web dashboard. Users must be able to select one or more version cards (via checkbox), then delete the selected versions — removing their `.png` image and `.md` content files from `output/.versions/<slide_name>/` on disk. The current version must be protected from deletion. ### Requirements - Users can select individual version cards via checkbox click - A "Select All" checkbox appears in the version panel toolbar when at least one version is listed; it selects/deselects all non-current versions - A "Delete Selected" button appears in the version panel toolbar whenever one or more non-current versions are selected - Clicking "Delete Selected" shows a confirm modal listing the count, then calls the new `slide.deleteVersions` RPC method - The current version cannot be selected for deletion; its checkbox is disabled - After deletion the panel re-renders to reflect the new list - A new `slide.deleteVersions` RPC method accepts `deck_path`, `slide_name`, and `versions: string[]` and removes the specified version files from disk - A new lib function `slide_delete_versions(deck_path, slide_name, &[version])` removes only the `.png` and `.md` files for each given version tag; does NOT renumber surviving versions - OpenRPC spec and generated client stub are updated to include `slide.deleteVersions` ### Files to Modify/Create | File | Change | |---|---| | `crates/hero_slides_lib/src/deck.rs` | Add `slide_delete_versions()` public function | | `crates/hero_slides_lib/src/lib.rs` | Re-export `slide_delete_versions` | | `crates/hero_slides_server/src/rpc.rs` | Add `"slide.deleteVersions"` match arm + handler | | `crates/hero_slides_server/openrpc.json` | Add `slide.deleteVersions` method entry | | `crates/hero_slides_server/openrpc.client.generated.rs` | Add generated stub for `slide_delete_versions` | | `crates/hero_slides_ui/static/js/dashboard.js` | Add selection state, selection UI logic, `deleteSelectedVersions()`, update `renderVersions()` | | `crates/hero_slides_ui/templates/index.html` | Add toolbar with "Select All" checkbox and "Delete Selected" button to version panel header | | `crates/hero_slides_ui/static/css/dashboard.css` | Add `.version-card.selected`, `.version-card-cb`, `.version-panel-toolbar` styles | ### Implementation Plan #### Step 1: Add `slide_delete_versions` to hero_slides_lib Files: `crates/hero_slides_lib/src/deck.rs`, `crates/hero_slides_lib/src/lib.rs` Add a new public function `slide_delete_versions(deck_path: &Path, slide_name: &str, versions: &[&str]) -> Result<(), HeroSlidesError>` that, for each version tag, removes `output/.versions/<slide_name>/<tag>.png` and `output/.versions/<slide_name>/<tag>.md` if they exist. Silently skips missing files. Re-export in `lib.rs`. Dependencies: none #### Step 2: Add `slide.deleteVersions` RPC handler Files: `crates/hero_slides_server/src/rpc.rs` Add `"slide.deleteVersions" => handle_slide_delete_versions(&req.params).await,` to the match block alongside other `slide.*` methods. Add the `handle_slide_delete_versions` async function that parses `deck_path`, `slide_name`, `versions` from params, calls `hero_slides_lib::slide_delete_versions` in a `spawn_blocking` block, and returns `{"deleted": N}`. Dependencies: Step 1 #### Step 3: Update OpenRPC spec and generated client stub Files: `crates/hero_slides_server/openrpc.json`, `crates/hero_slides_server/openrpc.client.generated.rs` Add `slide.deleteVersions` method to `openrpc.json` with params `deck_path` (string), `slide_name` (string), `versions` (array of strings) and result `{"deleted": integer}`. Add corresponding `SlideDeleteVersionsInput`, `SlideDeleteVersionsOutput` structs and `slide_delete_versions` method to the generated client file. Dependencies: Step 2 #### Step 4: Add CSS for selected version cards Files: `crates/hero_slides_ui/static/css/dashboard.css` Add `.version-card.selected` (blue border + tinted background), `.version-card-cb` (checkbox sizing), and `.version-panel-toolbar` (flex bar) styles after the existing `.version-card.current` rule. Dependencies: none #### Step 5: Update HTML version panel markup Files: `crates/hero_slides_ui/templates/index.html` Add a `version-panel-toolbar` div inside the version panel (between the slide strip and the version list), containing a "Select All" checkbox and a "Delete (N)" button (initially hidden). Dependencies: Step 4 #### Step 6: Add JavaScript multi-select and deletion logic Files: `crates/hero_slides_ui/static/js/dashboard.js` - Add `versionSelectedVersions = new Set()` state variable - Update `renderVersions(data)` to: show toolbar, add `data-version` attribute and checkbox to each card, wire `.version-card` click to `toggleVersionSelection`, apply `.selected` class - Add `toggleVersionSelection(tag, event)` — toggles tag in the Set, updates card class and checkbox - Add `toggleSelectAllVersions(checked)` — selects/deselects all non-current cards using `data-version` - Add `updateVersionSelectionUI()` — syncs delete button visibility, count span, and select-all indeterminate state - Add `deleteSelectedVersions()` — shows confirm modal, calls `rpc('slide.deleteVersions', {...})`, then calls `loadVersionHistory(versionSlideName)` on success Dependencies: Steps 4, 5 ### Acceptance Criteria - [ ] Non-current version cards are selectable via checkbox or card click; selected cards highlight in blue - [ ] Current version card checkbox is disabled; clicking current card does nothing - [ ] "Delete (N)" button appears when N > 0 versions are selected; is hidden otherwise - [ ] "All" checkbox selects all non-current versions; shows indeterminate when partially selected - [ ] Confirming deletion calls `slide.deleteVersions` RPC and the files are removed from disk - [ ] Version list re-renders after deletion; deleted versions are gone, current version remains - [ ] `slide_delete_versions` in hero_slides_lib silently skips nonexistent version tags - [ ] `openrpc.json` and `openrpc.client.generated.rs` contain the `slide.deleteVersions` entry ### Notes - Version numbering is not affected by deletion — surviving versions keep original numbers (gaps are fine) - Current version protection is UI-only; the server does not enforce it - The `openrpc.client.generated.rs` file appears to be manually maintained (not auto-generated by build.rs) — edit it directly - Each version tag `vNNN` has up to two files: `<tag>.png` and `<tag>.md` — both must be removed - File layout: `output/.versions/<slide_name>/vNNN.{png,md}`
Author
Owner

Test Results

  • Total: 57
  • Passed: 56
  • Failed: 0
  • Ignored: 1

Breakdown by crate

hero_slides_lib (unit tests): 42 passed, 0 failed, 0 ignored

hero_slides_lib (integration tests): 12 passed, 0 failed, 1 ignored

  • Ignored: test_generate_single_slide_ai (requires live AI service)

hero_slides_lib (doc-tests): 2 passed, 0 failed, 0 ignored

hero_slides_rhai (doc-tests): 1 passed, 0 failed, 0 ignored

hero_slides, hero_slides_sdk, hero_slides_server, hero_slides_ui: 0 tests each (binaries/UI crates)

Compilation

All crates compiled cleanly. One minor warning in examples:

  • crates/hero_slides_examples/examples/basic_usage.rs:18 -- unused variable spec (suggestion: prefix with _spec)

Status: PASS

All 56 runnable tests passed in ~38 seconds.

## Test Results - Total: 57 - Passed: 56 - Failed: 0 - Ignored: 1 ### Breakdown by crate **hero_slides_lib** (unit tests): 42 passed, 0 failed, 0 ignored **hero_slides_lib** (integration tests): 12 passed, 0 failed, 1 ignored - Ignored: `test_generate_single_slide_ai` (requires live AI service) **hero_slides_lib** (doc-tests): 2 passed, 0 failed, 0 ignored **hero_slides_rhai** (doc-tests): 1 passed, 0 failed, 0 ignored **hero_slides**, **hero_slides_sdk**, **hero_slides_server**, **hero_slides_ui**: 0 tests each (binaries/UI crates) ### Compilation All crates compiled cleanly. One minor warning in examples: - `crates/hero_slides_examples/examples/basic_usage.rs:18` -- unused variable `spec` (suggestion: prefix with `_spec`) ### Status: PASS All 56 runnable tests passed in ~38 seconds.
Author
Owner

Implementation Summary

The multi-select and batch deletion feature for the Slide Version History panel has been implemented.

Changes Made

crates/hero_slides_lib/src/deck.rs

  • Added slide_delete_versions(deck_path, slide_name, versions) — removes .png and .md files for each specified version tag from output/.versions/<slide_name>/. Silently skips missing files. Does not renumber surviving versions.

crates/hero_slides_lib/src/lib.rs

  • Re-exported slide_delete_versions alongside other slide operations.

crates/hero_slides_server/src/rpc.rs

  • Added "slide.deleteVersions" match arm and handle_slide_delete_versions async handler. Accepts deck_path, slide_name, and versions array. Returns {"deleted": N}.

crates/hero_slides_server/openrpc.json

  • Added slide.deleteVersions method entry with full parameter and result schema.

crates/hero_slides_server/openrpc.client.generated.rs

  • Added SlideDeleteVersionsInput, SlideDeleteVersionsOutput structs and slide_delete_versions client method.

crates/hero_slides_ui/static/css/dashboard.css

  • Added .version-card.selected (blue highlight), .version-card-cb (checkbox sizing), .version-panel-toolbar (flex toolbar strip), and .version-panel-toolbar .version-select-all-label styles.

crates/hero_slides_ui/templates/index.html

  • Added version-panel-toolbar div inside the version panel containing a "Select All" checkbox and "Delete (N)" button (hidden by default).

crates/hero_slides_ui/static/js/dashboard.js

  • Added versionSelectedVersions Set state variable.
  • Updated renderVersions() to add data-version attributes, checkboxes per card, and toolbar show/hide logic.
  • Added toggleVersionSelection(tag, event) — toggles individual card selection.
  • Added toggleSelectAllVersions(checked) — bulk select/deselect all non-current versions.
  • Added updateVersionSelectionUI() — syncs delete button visibility, count, and select-all indeterminate state.
  • Added deleteSelectedVersions() — shows confirm modal, calls slide.deleteVersions RPC, reloads version history on success.

Test Results

  • Total: 57
  • Passed: 56
  • Failed: 0
  • Ignored: 1 (AI integration test requiring live service)
## Implementation Summary The multi-select and batch deletion feature for the Slide Version History panel has been implemented. ### Changes Made **`crates/hero_slides_lib/src/deck.rs`** - Added `slide_delete_versions(deck_path, slide_name, versions)` — removes `.png` and `.md` files for each specified version tag from `output/.versions/<slide_name>/`. Silently skips missing files. Does not renumber surviving versions. **`crates/hero_slides_lib/src/lib.rs`** - Re-exported `slide_delete_versions` alongside other slide operations. **`crates/hero_slides_server/src/rpc.rs`** - Added `"slide.deleteVersions"` match arm and `handle_slide_delete_versions` async handler. Accepts `deck_path`, `slide_name`, and `versions` array. Returns `{"deleted": N}`. **`crates/hero_slides_server/openrpc.json`** - Added `slide.deleteVersions` method entry with full parameter and result schema. **`crates/hero_slides_server/openrpc.client.generated.rs`** - Added `SlideDeleteVersionsInput`, `SlideDeleteVersionsOutput` structs and `slide_delete_versions` client method. **`crates/hero_slides_ui/static/css/dashboard.css`** - Added `.version-card.selected` (blue highlight), `.version-card-cb` (checkbox sizing), `.version-panel-toolbar` (flex toolbar strip), and `.version-panel-toolbar .version-select-all-label` styles. **`crates/hero_slides_ui/templates/index.html`** - Added `version-panel-toolbar` div inside the version panel containing a "Select All" checkbox and "Delete (N)" button (hidden by default). **`crates/hero_slides_ui/static/js/dashboard.js`** - Added `versionSelectedVersions` Set state variable. - Updated `renderVersions()` to add `data-version` attributes, checkboxes per card, and toolbar show/hide logic. - Added `toggleVersionSelection(tag, event)` — toggles individual card selection. - Added `toggleSelectAllVersions(checked)` — bulk select/deselect all non-current versions. - Added `updateVersionSelectionUI()` — syncs delete button visibility, count, and select-all indeterminate state. - Added `deleteSelectedVersions()` — shows confirm modal, calls `slide.deleteVersions` RPC, reloads version history on success. ### Test Results - Total: 57 - Passed: 56 - Failed: 0 - Ignored: 1 (AI integration test requiring live service)
Author
Owner

Pull request opened: #11

This PR implements the changes discussed in this issue.

Pull request opened: https://forge.ourworld.tf/lhumina_code/hero_slides/pulls/11 This PR implements the changes discussed in this issue.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
lhumina_code/hero_slides#9
No description provided.