Skip to content

feat(ui): replace thread-delete alert with a confirmation card - #135

Merged
marmeladema merged 1 commit into
mainfrom
feat/thread-delete-card
Jul 27, 2026
Merged

feat(ui): replace thread-delete alert with a confirmation card#135
marmeladema merged 1 commit into
mainfrom
feat/thread-delete-card

Conversation

@marmeladema

@marmeladema marmeladema commented Jul 27, 2026

Copy link
Copy Markdown
Owner

Summary

Thread deletion used a native browser confirm() alert box, while project deletion already had a proper confirmation card. This adds a matching modal for thread deletion so the two flows are consistent, per the request that users want a proper card instead of an alert box.

Changes

  • crates/giskard-server/static/index.html — New #removeThreadModal overlay/card, structurally identical to the existing #removeProjectModal: heading, content with the thread name + cascade description, and a footer with Cancel + danger button + inline error slot.
  • crates/giskard-server/static/app.css.remove-thread-dialog rules mirroring the project dialog width/spacing.
  • crates/giskard-server/static/app.js — Replaced the confirm(...) call in deleteThread with openRemoveThreadModal/closeRemoveThreadModal:
    • Cascade text (linked sub-agent threads, all corresponding Codex threads, cannot be undone) is rendered into the card via #removeThreadCascade instead of a native dialog string.
    • Confirm handler reuses the existing delete/cascade/active-view logic, but now closes the modal on success, surfaces failures inline in #removeThreadErr, and disables the button while in flight — matching removeProjectConfirm semantics.
    • Wired Cancel, click-outside-overlay, and the global Escape handler.
  • tests/e2e/tests/subagents.spec.ts — Updated the two tests that drove page.waitForEvent("dialog") to assert the new modal opens and confirm via #removeThreadConfirm.

Verification

  • cargo fmt --check, cargo clippy -D warnings, cargo test — all green.
  • tests/e2e/run.sh tests/subagents.spec.ts — all 4 tests pass (includes the cross-project deletion and sub-agent cascade tests that now drive the modal).
  • README screenshots don't need regenerating: the modal only appears on an explicit delete action, not in the default screenshotted IDE view.

Summary by CodeRabbit

  • New Features
    • Added a dedicated “Delete thread?” confirmation modal (with thread name, cascade details, and irreversible messaging) to replace native confirmation prompts.
  • Accessibility
    • Improved dialog accessibility for the “Remove project” overlay (proper dialog roles/labels) and introduced accessible wiring for the thread delete modal.
  • Bug Fixes
    • Deletion failures now display inline errors and keep the modal open for retry; deletion actions are disabled while the request is in flight.
    • Escape/backdrop/cancel dismissal behaves consistently, with Escape closing the delete modal first.
  • Tests
    • Updated end-to-end coverage to use the modal UI and added cases for cancel/keyboard/backdrop dismiss and failed deletions.
  • Chores
    • Adjusted e2e CA certificate handling in Docker and ensured host CA placeholders are retained in version control.

@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Thread deletion now uses an accessible confirmation modal with cascade details, focus and dismissal handling, timed requests, inline errors, and expanded Playwright coverage. E2E Docker stages also trust additional host CA certificates.

Changes

Thread deletion modal

Layer / File(s) Summary
Delete confirmation modal UI
crates/giskard-server/static/index.html, crates/giskard-server/static/app.css
Adds the thread confirmation modal, cascade and irreversibility text, action controls, alert regions, dialog accessibility attributes, and responsive styling.
Modal deletion flow and request handling
crates/giskard-server/static/app.js
Replaces native confirmation with modal state, focus restoration, dismissal handling, timed deletion requests, active-view cleanup, and inline failure reporting.
Modal deletion end-to-end coverage
tests/e2e/tests/subagents.spec.ts
Covers confirmation, cascade messaging, cancel/Escape/backdrop dismissal, focus behavior, and failed DELETE requests.
E2E host certificate trust setup
.gitignore, tests/e2e/.host-ca-certificates/.gitkeep, tests/e2e/Dockerfile
Adds the certificate directory placeholder and configures both Docker stages to install and use host CA certificates.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant ThreadMenu
  participant RemoveThreadModal
  participant API
  User->>ThreadMenu: Select delete thread
  ThreadMenu->>RemoveThreadModal: Open with cascade details
  User->>RemoveThreadModal: Confirm deletion
  RemoveThreadModal->>API: DELETE thread with timeout
  API-->>RemoveThreadModal: Success or error
Loading

Possibly related PRs

Suggested reviewers: claude

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes replacing native thread deletion confirmation with a confirmation card.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/thread-delete-card

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
crates/giskard-server/static/index.html (1)

252-264: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Expose the confirmation card as an accessible dialog.

The overlay is a generic <div>, and dynamically populated #removeThreadErr is not announced to assistive technologies. Add role="dialog", aria-modal="true", an aria-labelledby target for the heading, and role="alert"/aria-live for the error slot. Verify with keyboard and screen-reader coverage.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/giskard-server/static/index.html` around lines 252 - 264, Update the
removeThreadModal dialog markup to add role="dialog", aria-modal="true", and
aria-labelledby referencing its heading element; give the heading a matching
unique id. Mark removeThreadErr as a live alert region with role="alert" and
appropriate aria-live behavior, then verify keyboard and screen-reader
accessibility for the confirmation flow.
crates/giskard-server/static/app.js (1)

1394-1408: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Restore focus to the invoking control when closing.

openRemoveThreadModal() focuses the confirmation button, but closeRemoveThreadModal() only hides the overlay. Cancel, backdrop, and Escape therefore leave keyboard focus on a hidden element or lose the user’s place. Save the active trigger before opening and restore focus after dismissal, with a connected-element fallback.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/giskard-server/static/app.js` around lines 1394 - 1408, Update
openRemoveThreadModal and closeRemoveThreadModal to capture the invoking control
before focusing removeThreadConfirm, then restore focus to that control when
closing if it remains connected to the document. Add a safe connected-element
fallback when the original trigger is unavailable, while preserving the existing
modal state cleanup.
tests/e2e/tests/subagents.spec.ts (1)

102-107: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Cover modal failure and dismissal paths.

These tests verify only the successful delete flow. Add coverage for Cancel, Escape/outside-click dismissal, the disabled confirmation button during deletion, and an inline #removeThreadErr response when the DELETE fails.

Also applies to: 315-317

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/e2e/tests/subagents.spec.ts` around lines 102 - 107, Add coverage
around the `#removeThreadModal` deletion flow for Cancel, Escape, and
outside-click dismissal, ensuring the modal closes without deleting. Verify
`#removeThreadConfirm` is disabled while deletion is in progress, and mock a
failed DELETE to assert the inline `#removeThreadErr` message appears; retain the
existing successful deletion assertions.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/giskard-server/static/app.js`:
- Around line 1410-1421: Update the remove-thread modal flow around
closeRemoveThreadModal and the removeThreadConfirm handler to track whether
deletion is in flight, block Cancel, outside-click, and Escape dismissal while
deleting, and disable the corresponding dismissal controls. Keep the modal open
while the DELETE request is pending, and force-close it only after a successful
deletion; ensure failure handling can still display the current request’s error
without being overwritten.

---

Nitpick comments:
In `@crates/giskard-server/static/app.js`:
- Around line 1394-1408: Update openRemoveThreadModal and closeRemoveThreadModal
to capture the invoking control before focusing removeThreadConfirm, then
restore focus to that control when closing if it remains connected to the
document. Add a safe connected-element fallback when the original trigger is
unavailable, while preserving the existing modal state cleanup.

In `@crates/giskard-server/static/index.html`:
- Around line 252-264: Update the removeThreadModal dialog markup to add
role="dialog", aria-modal="true", and aria-labelledby referencing its heading
element; give the heading a matching unique id. Mark removeThreadErr as a live
alert region with role="alert" and appropriate aria-live behavior, then verify
keyboard and screen-reader accessibility for the confirmation flow.

In `@tests/e2e/tests/subagents.spec.ts`:
- Around line 102-107: Add coverage around the `#removeThreadModal` deletion flow
for Cancel, Escape, and outside-click dismissal, ensuring the modal closes
without deleting. Verify `#removeThreadConfirm` is disabled while deletion is in
progress, and mock a failed DELETE to assert the inline `#removeThreadErr` message
appears; retain the existing successful deletion assertions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: f79c178d-cacf-4f11-af7d-af56aa29090e

📥 Commits

Reviewing files that changed from the base of the PR and between 2a977ef and 3c1f1b6.

📒 Files selected for processing (4)
  • crates/giskard-server/static/app.css
  • crates/giskard-server/static/app.js
  • crates/giskard-server/static/index.html
  • tests/e2e/tests/subagents.spec.ts

Comment thread crates/giskard-server/static/app.js
@marmeladema
marmeladema force-pushed the feat/thread-delete-card branch from 19a2ddf to 157785f Compare July 27, 2026 10:27

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
tests/e2e/tests/subagents.spec.ts (1)

448-455: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Use times: 1 for this one-shot delete mock
page.route(..., { times: 1 }) is cleaner than calling unroute() from inside the handler. Also reword the later note: the DELETE is still sent, but it’s intercepted before reaching the backend.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/e2e/tests/subagents.spec.ts` around lines 448 - 455, Update the DELETE
interception in the subagent test to configure the route with times: 1, removing
the in-handler page.unroute call while preserving the 500 response for the
single request. Reword the later note to state that the DELETE is sent but
intercepted before reaching the backend.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@tests/e2e/tests/subagents.spec.ts`:
- Around line 448-455: Update the DELETE interception in the subagent test to
configure the route with times: 1, removing the in-handler page.unroute call
while preserving the 500 response for the single request. Reword the later note
to state that the DELETE is sent but intercepted before reaching the backend.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 05dfd952-b494-4575-b240-590ae6f7c53a

📥 Commits

Reviewing files that changed from the base of the PR and between 3c1f1b6 and 19a2ddf.

📒 Files selected for processing (3)
  • crates/giskard-server/static/app.js
  • crates/giskard-server/static/index.html
  • tests/e2e/tests/subagents.spec.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • crates/giskard-server/static/app.js
  • crates/giskard-server/static/index.html

@marmeladema
marmeladema force-pushed the feat/thread-delete-card branch 2 times, most recently from 547c574 to 90a5706 Compare July 27, 2026 11:03

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/giskard-server/static/app.js`:
- Around line 1394-1402: Update openRemoveThreadModal and the remove-thread
modal dismissal/success paths to capture the triggering thread-menu button
before focusing removeThreadConfirm, then restore focus to that opener when the
modal closes. If the opener or deleted row no longer exists, fall back to the
appropriate remaining thread-menu button or another stable focus target, while
preserving existing deletion behavior.
- Around line 1405-1408: Update the api() request helper to support cancellation
or a timeout for fetch calls, ensuring hung requests eventually resolve or abort
and restore the remove-thread modal’s usable state. Integrate this with the
removeThreadConfirm deletion flow and closeRemoveThreadModal so the existing
protection during active deletion remains, while timeout/abort cleanup
re-enables dismissal and preserves the inline error handling.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 2cb87604-d539-4c06-a358-ed2f1c15164c

📥 Commits

Reviewing files that changed from the base of the PR and between 19a2ddf and 90a5706.

📒 Files selected for processing (4)
  • crates/giskard-server/static/app.css
  • crates/giskard-server/static/app.js
  • crates/giskard-server/static/index.html
  • tests/e2e/tests/subagents.spec.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • crates/giskard-server/static/app.css
  • crates/giskard-server/static/index.html
  • tests/e2e/tests/subagents.spec.ts

Comment thread crates/giskard-server/static/app.js
Comment thread crates/giskard-server/static/app.js Outdated
@marmeladema
marmeladema force-pushed the feat/thread-delete-card branch 2 times, most recently from 80746a0 to 232af48 Compare July 27, 2026 13:38

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.gitignore:
- Around line 2-3: Ensure the e2e Docker build receives a populated
tests/e2e/.host-ca-certificates directory: update .github/workflows/e2e.yml,
tests/e2e/run.sh, and tests/e2e/screenshots.sh to generate or copy the required
.crt files before invoking docker build, or fail fast when none are present.
Update the related tests/e2e/Dockerfile CA-copy steps at lines 16-20 and 33-36
only as needed to enforce the non-empty trust-store requirement.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 5a57f372-2f1e-4339-85df-7a8beb2a9905

📥 Commits

Reviewing files that changed from the base of the PR and between 80746a0 and 232af48.

📒 Files selected for processing (7)
  • .gitignore
  • crates/giskard-server/static/app.css
  • crates/giskard-server/static/app.js
  • crates/giskard-server/static/index.html
  • tests/e2e/.host-ca-certificates/.gitkeep
  • tests/e2e/Dockerfile
  • tests/e2e/tests/subagents.spec.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • crates/giskard-server/static/app.css
  • crates/giskard-server/static/index.html
  • tests/e2e/tests/subagents.spec.ts

Comment thread .gitignore
@marmeladema
marmeladema force-pushed the feat/thread-delete-card branch from 232af48 to 3f115e0 Compare July 27, 2026 13:49
Thread deletion used a native browser confirm() while project deletion already
had a proper modal. Add a matching removeThreadModal card with the thread name,
cascade details for linked sub-agents and native threads, Cancel plus danger
actions, and an inline error slot.

The modal now tracks delete-in-flight state explicitly. It disables both
actions, blocks Cancel, Escape, and backdrop dismissal while DELETE is pending,
force-closes only after success, restores focus on dismissal, and surfaces
bounded request failures inline.

Add accessible dialog and alert markup, update Playwright coverage for cancel,
Escape, backdrop, pending failure, and focus behavior, and let the e2e Docker
image trust any local certificates placed in tests/e2e/.host-ca-certificates.
@marmeladema
marmeladema force-pushed the feat/thread-delete-card branch from 3f115e0 to db2ca18 Compare July 27, 2026 13:53
@marmeladema
marmeladema merged commit 4db0c2a into main Jul 27, 2026
5 checks passed
@marmeladema
marmeladema deleted the feat/thread-delete-card branch July 27, 2026 13:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant