Home page: replace browser confirm/alert in board delete with a themed modal #81

Open
opened 2026-04-27 14:01:14 +00:00 by AhmedHanafy725 · 3 comments
Member

Bug

Deleting a board from the home page uses window.confirm(...) for the destructive-action confirmation and window.alert(...) for error reporting (crates/hero_whiteboard_ui/templates/web/home.html:412-421). Both:

  • Look out of place next to the home page's other modals (rename board, new board, new workspace) which are themed with the app's CSS variables.
  • Cannot be styled for dark/light mode -- the browser's native dialog ignores the page theme.
  • Are blocked by some browser settings and tab-modal flags.
  • Don't allow keyboard shortcuts consistent with the rest of the app's modals (Enter/Escape).

For a destructive action like delete, a proper themed confirmation modal is the right UX -- with the board's name visible, a clear destructive button styling, and inline error reporting if the RPC fails.

Reproduction

  1. Open the home page (/web/home).
  2. Click the trash icon on any board card.

Observed: a native browser confirm dialog opens. If the user clicks the icon by mistake and the RPC fails, a native alert follows.

Expected: an in-page themed modal opens with the board name and a destructive Delete button.

Root cause

crates/hero_whiteboard_ui/templates/web/home.html:412-421:

async function deleteBoard(id, name) {
    id = parseInt(id, 10);
    if (!confirm('Delete "' + name + '"? This cannot be undone.')) return;
    try {
        await rpcCall('board.delete', { id: id });
        loadBoards();
    } catch (e) {
        alert('Failed to delete: ' + e.message);
    }
}

The inline confirm and alert calls are the only browser dialogs in the delete-board flow. The button that triggers it is at home.html:248 inside the per-card action row.

Affected file

  • crates/hero_whiteboard_ui/templates/web/home.html -- the deleteBoard function and the modal markup.

No server / SDK / openrpc / DB changes -- pure UI refactor.

Expected behavior

Clicking the trash icon opens an in-page modal that:

  • Shows the board name in the prompt text (e.g. Delete "Sprint planning"? This cannot be undone.).
  • Has Cancel and Delete buttons; the Delete button uses destructive styling (red/error color).
  • Surfaces RPC errors inline inside the modal (no alert).
  • Closes on success and refreshes the board list.
  • Enter triggers Delete, Escape cancels (matches the rename / new-board / new-workspace modal handlers in the same file).
  • Themed via var(--wb-...) CSS variables for consistency with dark/light mode.

Reference modals to match

The same file (templates/web/home.html) already has three modals to model after:

  • rename-modal (lines 56-75)
  • new-board-modal (lines 30-55)
  • new-workspace-modal (lines 11-29)

The new delete-confirm modal should follow the same conventions: full-screen overlay with rgba(0,0,0,0.5) backdrop, centered 400px card on var(--wb-surface), padding:24px, border-radius:12px, inline error region using var(--wb-error), and Cancel + action buttons in the same display:flex;gap:8px;justify-content:flex-end row.

Acceptance criteria

  • Clicking the trash icon on a board card opens an in-page themed modal (no window.confirm).
  • The modal shows the board name in the prompt text.
  • The Delete button uses destructive (var(--wb-error)) styling so it's visually distinct from Cancel.
  • Cancel closes the modal without deleting.
  • On Delete, calls rpcCall('board.delete', { id }); on success closes the modal and refreshes the board list.
  • On RPC failure, shows the error inline in the modal (no window.alert); the modal stays open so the user can retry or cancel.
  • Enter triggers Delete; Escape cancels (matches the page's existing modal keyboard handlers).
  • No window.confirm / window.alert calls remain in the board-delete flow.
  • Diff is contained to crates/hero_whiteboard_ui/templates/web/home.html.
  • No regression in the rest of the home page (rename, new board, new workspace, share links still work).

Notes

  • Keep the existing deleteBoard(id, name) entry point so the per-card button at home.html:248 doesn't need to change -- have it open the modal instead of running the inline confirm.
  • The existing keydown handler near the bottom of the script block routes Enter/Escape per modal; extend it to cover this new one.
  • Other browser alert calls remain in saveRename (line 178), duplicateBoard (line 205), and submitNewBoard (multiple). They are out of scope for this issue but worth a follow-up cleanup so the page is fully native-dialog-free.
## Bug Deleting a board from the home page uses `window.confirm(...)` for the destructive-action confirmation and `window.alert(...)` for error reporting (`crates/hero_whiteboard_ui/templates/web/home.html:412-421`). Both: - Look out of place next to the home page's other modals (rename board, new board, new workspace) which are themed with the app's CSS variables. - Cannot be styled for dark/light mode -- the browser's native dialog ignores the page theme. - Are blocked by some browser settings and tab-modal flags. - Don't allow keyboard shortcuts consistent with the rest of the app's modals (Enter/Escape). For a destructive action like delete, a proper themed confirmation modal is the right UX -- with the board's name visible, a clear destructive button styling, and inline error reporting if the RPC fails. ## Reproduction 1. Open the home page (`/web/home`). 2. Click the trash icon on any board card. Observed: a native browser `confirm` dialog opens. If the user clicks the icon by mistake and the RPC fails, a native `alert` follows. Expected: an in-page themed modal opens with the board name and a destructive Delete button. ## Root cause `crates/hero_whiteboard_ui/templates/web/home.html:412-421`: ```js async function deleteBoard(id, name) { id = parseInt(id, 10); if (!confirm('Delete "' + name + '"? This cannot be undone.')) return; try { await rpcCall('board.delete', { id: id }); loadBoards(); } catch (e) { alert('Failed to delete: ' + e.message); } } ``` The inline `confirm` and `alert` calls are the only browser dialogs in the delete-board flow. The button that triggers it is at `home.html:248` inside the per-card action row. ## Affected file - `crates/hero_whiteboard_ui/templates/web/home.html` -- the `deleteBoard` function and the modal markup. No server / SDK / openrpc / DB changes -- pure UI refactor. ## Expected behavior Clicking the trash icon opens an in-page modal that: - Shows the board name in the prompt text (e.g. `Delete "Sprint planning"? This cannot be undone.`). - Has Cancel and Delete buttons; the Delete button uses destructive styling (red/error color). - Surfaces RPC errors inline inside the modal (no `alert`). - Closes on success and refreshes the board list. - Enter triggers Delete, Escape cancels (matches the rename / new-board / new-workspace modal handlers in the same file). - Themed via `var(--wb-...)` CSS variables for consistency with dark/light mode. ## Reference modals to match The same file (`templates/web/home.html`) already has three modals to model after: - `rename-modal` (lines 56-75) - `new-board-modal` (lines 30-55) - `new-workspace-modal` (lines 11-29) The new delete-confirm modal should follow the same conventions: full-screen overlay with `rgba(0,0,0,0.5)` backdrop, centered `400px` card on `var(--wb-surface)`, `padding:24px`, `border-radius:12px`, inline error region using `var(--wb-error)`, and Cancel + action buttons in the same `display:flex;gap:8px;justify-content:flex-end` row. ## Acceptance criteria - [ ] Clicking the trash icon on a board card opens an in-page themed modal (no `window.confirm`). - [ ] The modal shows the board name in the prompt text. - [ ] The Delete button uses destructive (`var(--wb-error)`) styling so it's visually distinct from Cancel. - [ ] Cancel closes the modal without deleting. - [ ] On Delete, calls `rpcCall('board.delete', { id })`; on success closes the modal and refreshes the board list. - [ ] On RPC failure, shows the error inline in the modal (no `window.alert`); the modal stays open so the user can retry or cancel. - [ ] Enter triggers Delete; Escape cancels (matches the page's existing modal keyboard handlers). - [ ] No `window.confirm` / `window.alert` calls remain in the board-delete flow. - [ ] Diff is contained to `crates/hero_whiteboard_ui/templates/web/home.html`. - [ ] No regression in the rest of the home page (rename, new board, new workspace, share links still work). ## Notes - Keep the existing `deleteBoard(id, name)` entry point so the per-card button at `home.html:248` doesn't need to change -- have it open the modal instead of running the inline confirm. - The existing keydown handler near the bottom of the script block routes Enter/Escape per modal; extend it to cover this new one. - Other browser `alert` calls remain in `saveRename` (line 178), `duplicateBoard` (line 205), and `submitNewBoard` (multiple). They are out of scope for this issue but worth a follow-up cleanup so the page is fully native-dialog-free.
Author
Member

Implementation Spec for Issue #81

Objective

Replace the window.confirm confirmation and window.alert error in the home page's board-delete flow with a themed in-page modal styled like the existing rename / new-board / new-workspace modals in the same file.

Requirements

  • Clicking the trash icon on a board card opens an in-page modal (no window.confirm).
  • Modal shows the board name in the prompt text and uses destructive styling on the Delete button.
  • Cancel closes the modal without deleting.
  • Delete calls rpcCall('board.delete', { id }); on success closes the modal and refreshes the board list.
  • On RPC failure, the error is shown inline inside the modal (no window.alert); the modal stays open so the user can retry or cancel.
  • Enter triggers Delete; Escape cancels.
  • Modal is themed via var(--wb-...) CSS variables.
  • Diff stays inside crates/hero_whiteboard_ui/templates/web/home.html.
  • No regression in other home-page features (rename, new board, new workspace, share links).

Files to Modify

  • crates/hero_whiteboard_ui/templates/web/home.html — add modal markup, rewrite deleteBoard to drive the modal, extend the existing keydown handler.

No server / SDK / openrpc / DB changes — pure UI refactor.

Implementation Plan

Step 1: Add the delete-confirm modal markup, update deleteBoard, hook keyboard handler

Files: crates/hero_whiteboard_ui/templates/web/home.html

  1. Modal markup. In the {% block content %} section (next to the existing new-board-modal, new-workspace-modal, and rename-modal blocks), add:

    <!-- Delete Board confirmation modal -->
    <div id="delete-board-modal"
        style="display:none;position:fixed;inset:0;background:rgba(0,0,0,0.5);z-index:9999;align-items:center;justify-content:center;">
        <div
            style="background:var(--wb-surface);border:1px solid var(--wb-border);border-radius:12px;padding:24px;width:400px;max-width:90vw;">
            <h3 style="margin:0 0 12px;font-size:16px;">Delete Board</h3>
            <p id="delete-board-prompt" style="margin:0 0 8px;font-size:14px;color:var(--wb-text);"></p>
            <p style="margin:0;font-size:12px;color:var(--wb-text-muted);">This cannot be undone.</p>
            <div id="delete-board-error" style="margin-top:8px;color:var(--wb-error);font-size:12px;display:none;"></div>
            <div style="display:flex;gap:8px;justify-content:flex-end;margin-top:16px;">
                <button class="btn btn-sm" onclick="closeDeleteBoardModal()"
                    style="background:var(--wb-bg);border:1px solid var(--wb-border);">Cancel</button>
                <button class="btn btn-sm" onclick="submitDeleteBoard()"
                    style="background:var(--wb-error);border:1px solid var(--wb-error);color:#fff;">Delete</button>
            </div>
        </div>
    </div>
    

    The destructive styling on the Delete button uses var(--wb-error) as its background so it's visually distinct from Cancel and aligns with the existing trash-icon color.

  2. Replace deleteBoard (lines 412-421) with three functions:

    var deletingBoardId = null;
    
    function deleteBoard(id, name) {
        deletingBoardId = parseInt(id, 10);
        document.getElementById('delete-board-prompt').textContent =
            'Delete "' + name + '"?';
        var err = document.getElementById('delete-board-error');
        err.textContent = ''; err.style.display = 'none';
        document.getElementById('delete-board-modal').style.display = 'flex';
    }
    
    function closeDeleteBoardModal() {
        document.getElementById('delete-board-modal').style.display = 'none';
        deletingBoardId = null;
    }
    
    async function submitDeleteBoard() {
        if (deletingBoardId == null) { closeDeleteBoardModal(); return; }
        var err = document.getElementById('delete-board-error');
        err.textContent = ''; err.style.display = 'none';
        try {
            await rpcCall('board.delete', { id: deletingBoardId });
            closeDeleteBoardModal();
            loadBoards();
        } catch (e) {
            err.textContent = 'Failed to delete: ' + (e && e.message ? e.message : e);
            err.style.display = 'block';
        }
    }
    

    deleteBoard(id, name) keeps the same call signature so the per-card button at home.html:248 doesn't need to change.

  3. Extend the existing keydown handler (currently routes Enter/Escape to the rename, new-board, and new-workspace modals) to also route to the delete-board modal:

    var dbModal = document.getElementById('delete-board-modal');
    if (dbModal && dbModal.style.display === 'flex') {
        if (e.key === 'Enter') submitDeleteBoard();
        if (e.key === 'Escape') closeDeleteBoardModal();
    }
    

    Insert this branch alongside the existing nbModal/nwModal checks.

Dependencies: none.

Acceptance Criteria

  • Clicking the trash icon on a board card opens an in-page themed modal.
  • Modal shows the board name in the prompt text.
  • Delete button uses destructive (var(--wb-error)) styling.
  • Cancel closes the modal without deleting.
  • Delete calls rpcCall('board.delete', { id }); on success closes the modal and reloads the board list.
  • On RPC failure, the modal shows the error inline and stays open.
  • Enter triggers Delete; Escape cancels.
  • Modal is themed via var(--wb-...) (looks correct in dark + light mode).
  • No window.confirm / window.alert in the board-delete flow.
  • Diff is contained to crates/hero_whiteboard_ui/templates/web/home.html.
  • No regression in rename / new-board / new-workspace / share-links flows.

Notes

  • Reuse the same module-scope var deletingBoardId = null; pattern used by renamingBoardId (declared near the top of the script block) so the design matches what's already there.
  • The Delete button's white text color #fff is hardcoded because var(--wb-error) is a saturated red where any --wb-text value (light or dark) would be hard to read; the rest of the modal uses theme variables.
  • Other browser alert calls in the same file (saveRename, duplicateBoard, submitNewBoard) are out of scope per the issue body — leave them for a follow-up.
## Implementation Spec for Issue #81 ### Objective Replace the `window.confirm` confirmation and `window.alert` error in the home page's board-delete flow with a themed in-page modal styled like the existing rename / new-board / new-workspace modals in the same file. ### Requirements - Clicking the trash icon on a board card opens an in-page modal (no `window.confirm`). - Modal shows the board name in the prompt text and uses destructive styling on the Delete button. - Cancel closes the modal without deleting. - Delete calls `rpcCall('board.delete', { id })`; on success closes the modal and refreshes the board list. - On RPC failure, the error is shown inline inside the modal (no `window.alert`); the modal stays open so the user can retry or cancel. - Enter triggers Delete; Escape cancels. - Modal is themed via `var(--wb-...)` CSS variables. - Diff stays inside `crates/hero_whiteboard_ui/templates/web/home.html`. - No regression in other home-page features (rename, new board, new workspace, share links). ### Files to Modify - `crates/hero_whiteboard_ui/templates/web/home.html` — add modal markup, rewrite `deleteBoard` to drive the modal, extend the existing keydown handler. No server / SDK / openrpc / DB changes — pure UI refactor. ### Implementation Plan #### Step 1: Add the delete-confirm modal markup, update `deleteBoard`, hook keyboard handler Files: `crates/hero_whiteboard_ui/templates/web/home.html` 1. **Modal markup.** In the `{% block content %}` section (next to the existing `new-board-modal`, `new-workspace-modal`, and `rename-modal` blocks), add: ```html <!-- Delete Board confirmation modal --> <div id="delete-board-modal" style="display:none;position:fixed;inset:0;background:rgba(0,0,0,0.5);z-index:9999;align-items:center;justify-content:center;"> <div style="background:var(--wb-surface);border:1px solid var(--wb-border);border-radius:12px;padding:24px;width:400px;max-width:90vw;"> <h3 style="margin:0 0 12px;font-size:16px;">Delete Board</h3> <p id="delete-board-prompt" style="margin:0 0 8px;font-size:14px;color:var(--wb-text);"></p> <p style="margin:0;font-size:12px;color:var(--wb-text-muted);">This cannot be undone.</p> <div id="delete-board-error" style="margin-top:8px;color:var(--wb-error);font-size:12px;display:none;"></div> <div style="display:flex;gap:8px;justify-content:flex-end;margin-top:16px;"> <button class="btn btn-sm" onclick="closeDeleteBoardModal()" style="background:var(--wb-bg);border:1px solid var(--wb-border);">Cancel</button> <button class="btn btn-sm" onclick="submitDeleteBoard()" style="background:var(--wb-error);border:1px solid var(--wb-error);color:#fff;">Delete</button> </div> </div> </div> ``` The destructive styling on the Delete button uses `var(--wb-error)` as its background so it's visually distinct from Cancel and aligns with the existing trash-icon color. 2. **Replace `deleteBoard`** (lines 412-421) with three functions: ```js var deletingBoardId = null; function deleteBoard(id, name) { deletingBoardId = parseInt(id, 10); document.getElementById('delete-board-prompt').textContent = 'Delete "' + name + '"?'; var err = document.getElementById('delete-board-error'); err.textContent = ''; err.style.display = 'none'; document.getElementById('delete-board-modal').style.display = 'flex'; } function closeDeleteBoardModal() { document.getElementById('delete-board-modal').style.display = 'none'; deletingBoardId = null; } async function submitDeleteBoard() { if (deletingBoardId == null) { closeDeleteBoardModal(); return; } var err = document.getElementById('delete-board-error'); err.textContent = ''; err.style.display = 'none'; try { await rpcCall('board.delete', { id: deletingBoardId }); closeDeleteBoardModal(); loadBoards(); } catch (e) { err.textContent = 'Failed to delete: ' + (e && e.message ? e.message : e); err.style.display = 'block'; } } ``` `deleteBoard(id, name)` keeps the same call signature so the per-card button at `home.html:248` doesn't need to change. 3. **Extend the existing keydown handler** (currently routes Enter/Escape to the rename, new-board, and new-workspace modals) to also route to the delete-board modal: ```js var dbModal = document.getElementById('delete-board-modal'); if (dbModal && dbModal.style.display === 'flex') { if (e.key === 'Enter') submitDeleteBoard(); if (e.key === 'Escape') closeDeleteBoardModal(); } ``` Insert this branch alongside the existing `nbModal`/`nwModal` checks. Dependencies: none. ### Acceptance Criteria - [ ] Clicking the trash icon on a board card opens an in-page themed modal. - [ ] Modal shows the board name in the prompt text. - [ ] Delete button uses destructive (`var(--wb-error)`) styling. - [ ] Cancel closes the modal without deleting. - [ ] Delete calls `rpcCall('board.delete', { id })`; on success closes the modal and reloads the board list. - [ ] On RPC failure, the modal shows the error inline and stays open. - [ ] Enter triggers Delete; Escape cancels. - [ ] Modal is themed via `var(--wb-...)` (looks correct in dark + light mode). - [ ] No `window.confirm` / `window.alert` in the board-delete flow. - [ ] Diff is contained to `crates/hero_whiteboard_ui/templates/web/home.html`. - [ ] No regression in rename / new-board / new-workspace / share-links flows. ### Notes - Reuse the same module-scope `var deletingBoardId = null;` pattern used by `renamingBoardId` (declared near the top of the script block) so the design matches what's already there. - The Delete button's white text color `#fff` is hardcoded because `var(--wb-error)` is a saturated red where any `--wb-text` value (light or dark) would be hard to read; the rest of the modal uses theme variables. - Other browser `alert` calls in the same file (`saveRename`, `duplicateBoard`, `submitNewBoard`) are out of scope per the issue body — leave them for a follow-up.
Author
Member

Test Results

  • cargo test --workspace --lib: 4 lib targets, 0 tests / 0 passed / 0 failed each.
  • cargo clippy --workspace -- -D warnings: clean.
  • cargo check --workspace: clean (Askama template compiled successfully).

Template-only change. Manual verification recommended:

  1. Open the home page, click the trash icon on a board card. Confirm a themed modal appears (no browser dialog) with the board name in the prompt.
  2. Click Cancel. Confirm the modal closes and no board is deleted.
  3. Click Delete. Confirm the board is removed and the list refreshes.
  4. Force an RPC failure (stop the server) and click Delete. Confirm the modal stays open and shows the error inline (no alert).
  5. Press Enter while the modal is open — triggers Delete. Press Escape — cancels.
  6. Repeat in dark and light mode to confirm theming.
## Test Results - `cargo test --workspace --lib`: 4 lib targets, 0 tests / 0 passed / 0 failed each. - `cargo clippy --workspace -- -D warnings`: clean. - `cargo check --workspace`: clean (Askama template compiled successfully). Template-only change. Manual verification recommended: 1. Open the home page, click the trash icon on a board card. Confirm a themed modal appears (no browser dialog) with the board name in the prompt. 2. Click Cancel. Confirm the modal closes and no board is deleted. 3. Click Delete. Confirm the board is removed and the list refreshes. 4. Force an RPC failure (stop the server) and click Delete. Confirm the modal stays open and shows the error inline (no `alert`). 5. Press Enter while the modal is open — triggers Delete. Press Escape — cancels. 6. Repeat in dark and light mode to confirm theming.
Author
Member

Implementation Summary

Changes

  • crates/hero_whiteboard_ui/templates/web/home.html (+50 / -6)
    • Added a delete-board-modal block in the content section, themed via var(--wb-...) with a red Delete button styled with var(--wb-error) background and white text for contrast.
    • Added var deletingBoardId = null; alongside the existing renamingBoardId.
    • Replaced the legacy deleteBoard(id, name) (which used window.confirm + window.alert) with three functions:
      • deleteBoard(id, name): opens the modal, fills in the prompt with the board name, clears any previous error.
      • closeDeleteBoardModal(): hides the modal and clears deletingBoardId.
      • submitDeleteBoard(): calls rpcCall('board.delete', { id }). On success, closes the modal and reloads. On failure, shows the error inline inside the modal — no window.alert, modal stays open so the user can retry.
    • Extended the existing keydown handler to also route Enter/Escape to the new delete-board modal.
  • The per-card trash button at home.html:248 was not changed — deleteBoard(id, name) keeps the same call signature.

Verification

  • cargo test --workspace --lib passes (4 lib targets, 0 tests).
  • cargo clippy --workspace -- -D warnings: clean.
  • cargo check --workspace: clean.

Notes / caveats

  • Template-only change; no Rust / SDK / openrpc / DB edits.
  • The Delete button's text color is hardcoded #fff because var(--wb-error) is a saturated red where the theme's --wb-text variants would be hard to read.
  • Other browser alert calls in the same file (saveRename, duplicateBoard, submitNewBoard) were intentionally left out of scope per the issue body, for a follow-up cleanup.
## Implementation Summary ### Changes - `crates/hero_whiteboard_ui/templates/web/home.html` (+50 / -6) - Added a `delete-board-modal` block in the content section, themed via `var(--wb-...)` with a red Delete button styled with `var(--wb-error)` background and white text for contrast. - Added `var deletingBoardId = null;` alongside the existing `renamingBoardId`. - Replaced the legacy `deleteBoard(id, name)` (which used `window.confirm` + `window.alert`) with three functions: - `deleteBoard(id, name)`: opens the modal, fills in the prompt with the board name, clears any previous error. - `closeDeleteBoardModal()`: hides the modal and clears `deletingBoardId`. - `submitDeleteBoard()`: calls `rpcCall('board.delete', { id })`. On success, closes the modal and reloads. On failure, shows the error inline inside the modal — no `window.alert`, modal stays open so the user can retry. - Extended the existing keydown handler to also route Enter/Escape to the new delete-board modal. - The per-card trash button at `home.html:248` was not changed — `deleteBoard(id, name)` keeps the same call signature. ### Verification - `cargo test --workspace --lib` passes (4 lib targets, 0 tests). - `cargo clippy --workspace -- -D warnings`: clean. - `cargo check --workspace`: clean. ### Notes / caveats - Template-only change; no Rust / SDK / openrpc / DB edits. - The Delete button's text color is hardcoded `#fff` because `var(--wb-error)` is a saturated red where the theme's `--wb-text` variants would be hard to read. - Other browser `alert` calls in the same file (`saveRename`, `duplicateBoard`, `submitNewBoard`) were intentionally left out of scope per the issue body, for a follow-up cleanup.
Sign in to join this conversation.
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_whiteboard#81
No description provided.