Replace the native window.prompt for naming a group with a proper themed modal #205
Labels
No labels
prio_critical
prio_low
type_bug
type_contact
type_issue
type_lead
type_question
type_story
type_task
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
lhumina_code/hero_whiteboard#205
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
When the user groups objects in the whiteboard (right-click → Group, or Ctrl+G), the app currently asks for the group name via the browser's native
window.prompt. The dialog ignores the app's theme, blocks the page, and is visually inconsistent with the rest of the UI which uses themed modals everywhere else.Where it happens
crates/hero_whiteboard_admin/static/web/js/whiteboard/contextmenu.js(right-click → Group):prompt('Group name:', 'Group').crates/hero_whiteboard_admin/static/web/js/whiteboard/shortcuts.js(Ctrl+G): sameprompt('Group name:', 'Group').Both follow the call with
WhiteboardGroups.createGroup(nodes, name || 'Group').Scope
Replace those two
window.promptcalls with a small, themed modal that:Group(the existing default), focused on open with the value selected so the user can just type to overwrite.Group(matches current behavior).WhiteboardGroups.createGroup(selectedNodes, name)with the same nodes captured from the trigger; on cancel, does nothing.Acceptance Criteria
Group.window.promptcall related to grouping.Notes
The whiteboard frontend is vanilla JS modules under
crates/hero_whiteboard_admin/static/web/js/whiteboard/embedded via rust-embed. Other in-board dialogs already use the app's modal pattern; mirror that pattern rather than introducing a new mechanism. Keep the change minimal: one small helper for a themed prompt-modal (or just inline the markup), invoked from the two existing call sites.Implementation Spec for Issue #205
Objective
Replace the two native
window.prompt('Group name:', 'Group')call sites (right-click "Group Selected" incontextmenu.jsand Ctrl+G inshortcuts.js) with a themed, in-board modal. The modal must visually match the rest of the whiteboard (via the existing--wb-*CSS variables), capture the selected nodes at trigger time, and route them toWhiteboardGroups.createGroup(capturedNodes, name)on confirm.Requirements
--wb-bg,--wb-surface,--wb-border,--wb-text,--wb-text-muted,--wb-primary,--wb-primary-textCSS variables so dark/light themes work automatically.Group; input text fully selected on open.open()while one is already open returnsPromise<null>without disturbing the first.Group.prompt()in the new code path. No Bootstrap added toboard.html.Files to Modify/Create
crates/hero_whiteboard_admin/static/web/js/whiteboard/prompt_modal.js— new ES5 IIFE module exposingWhiteboardPromptModal.open({title,label,defaultValue,confirmLabel,cancelLabel}) -> Promise<string|null>. Generic helper (cohesive with other in-board modals; reusable for future rename/etc. prompts).crates/hero_whiteboard_admin/templates/web/board.html— add the prompt-modal markup near the existing#webframe-url-modalblock; add the new script tag BEFOREgroups.js/contextmenu.js/shortcuts.js.crates/hero_whiteboard_admin/static/web/css/whiteboard.css— small.wb-prompt-modal*rules using the--wb-*vars.crates/hero_whiteboard_admin/static/web/js/whiteboard/contextmenu.js— replaceprompt(...)at line ~104.crates/hero_whiteboard_admin/static/web/js/whiteboard/shortcuts.js— replaceprompt(...)at line ~117.Implementation Plan
Step 1: Add CSS for the prompt modal (independent)
Files:
static/web/css/whiteboard.css.wb-prompt-modal(backdrop,position:fixed; inset:0; rgba(0,0,0,.5); z-index:9999; display:none; align-items:center; justify-content:center;+.is-open { display:flex; }),.wb-prompt-modal__dialog(uses--wb-surface/--wb-border/--wb-text),__title/__label/__input/__actions/__btn/__btn--primarystyled with the--wb-*vars.Dependencies: none
Step 2: Create the helper module (independent from Step 1; needed by Steps 3-5)
Files:
static/web/js/whiteboard/prompt_modal.jsvar WhiteboardPromptModal = (function(){ ... return { open: open }; })();#wb-prompt-modal,#wb-prompt-modal-title/-label/-input/-confirm/-cancel.open(opts)defaults: titleName, labelName, defaultValue'', confirmLabelCreate, cancelLabelCancel. Single-instance guard returnsPromise.resolve(null). Sets text, value, savepreviouslyFocused, addsis-openclass, attachesclickon backdrop +keydownwith{capture:true}(Enter/Escape stop propagation; other keys flow through so typing works andshortcuts.jsdoesn't fire).setTimeout0 →input.focus()+input.select(). Buttons bound per call (close overopts.defaultValue). ReturnsPromise<string|null>.close(value): remove class + listeners,isOpen=false, restore focus, resolve.Step 3: Add modal markup + script tag (depends on Steps 1-2)
Files:
templates/web/board.html#webframe-url-modal, add<div id="wb-prompt-modal" class="wb-prompt-modal" role="dialog" aria-modal="true" aria-labelledby="wb-prompt-modal-title">with__dialog/__title/__label/__input/__actions/__btn(Cancel/Confirm).<script src="{{ base_path }}/js/whiteboard/prompt_modal.js"></script>immediately abovegroups.js.Step 4: Replace
prompt()in contextmenu.js (parallelizable with Step 5; depends on Steps 2-3)Files:
static/web/js/whiteboard/contextmenu.jsvar selectedNodes = (transformer ? transformer.nodes() : []).slice();snapshot; replace theactionbody withWhiteboardPromptModal.open({title:'Group Selected', label:'Group name', defaultValue:'Group', confirmLabel:'Create'}).then(function(name){ if (name === null) return; WhiteboardGroups.createGroup(selectedNodes, name || 'Group'); });—selectedNodesis the captured snapshot from the outer scope.Step 5: Replace
prompt()in shortcuts.js (parallelizable with Step 4; depends on Steps 2-3)Files:
static/web/js/whiteboard/shortcuts.jsvar capturedNodes = transformer.nodes().slice();(same snapshot pattern), thenWhiteboardPromptModal.open({...}).then(name => { if (name === null) return; WhiteboardGroups.createGroup(capturedNodes, name || 'Group'); });Step 6: Build & verify (depends on all)
touch crates/hero_whiteboard_admin/src/assets.rs(new file added → rust-embed re-scan), thencargo build --release -p hero_whiteboard_admin.Acceptance Criteria
window.promptor bareprompt(left incontextmenu.js(~line 104) orshortcuts.js(~line 117).Groupand selects the text on open.Group); Escape cancels; backdrop click cancels.WhiteboardGroups.createGroup(capturedNodes, name)is called with the nodes selected at trigger time, even if the user changes selection before confirming.open()returnsPromise<null>and doesn't disturb the first.--wb-*vars.prompt_modal.jsloaded beforegroups.js/contextmenu.js/shortcuts.js. No Bootstrap added.cargo build --release -p hero_whiteboard_adminsucceeds.Notes
board.html+webframe.js. The new modal owns its own keydown listener (registered/unregistered around open/close) — no change to the board.html global Webframe keydown block.webframe.jsretains its native-prompt FALLBACK (line ~421) — out of scope for this issue; that path is reachable only when its own themed modal fails. A future refactor could route it throughWhiteboardPromptModaltoo.src/assets.rsbefore the release build to bust the macro cache.Test Results
prompt(calls in contextmenu.js or shortcuts.js: yesNote: change is CSS/HTML/JS-only (no Rust source changed); workspace lib tests run as a regression guard.
Implementation Summary
Replaced the native
window.promptfor group naming with a themed in-board modal.Changes
crates/hero_whiteboard_admin/static/web/js/whiteboard/prompt_modal.js— reusable ES5 IIFE exposingWhiteboardPromptModal.open({ title, label, defaultValue, confirmLabel, cancelLabel }) -> Promise<string|null>. Lazy DOM lookup, single-instance guard, focus + select on open, focus restoration on close, capture-phase Enter/Escape handler that doesn't block typing.crates/hero_whiteboard_admin/static/web/css/whiteboard.css— added.wb-prompt-modal*rules using the existing--wb-*theme variables so dark/light themes are inherited automatically.crates/hero_whiteboard_admin/templates/web/board.html— added the modal markup near the existing Web Frame URL modal, and a<script>tag loadingprompt_modal.jsbeforegroups.js/contextmenu.js/shortcuts.js.crates/hero_whiteboard_admin/static/web/js/whiteboard/contextmenu.js— replaced theprompt('Group name:', 'Group')in the right-click "Group Selected" action.crates/hero_whiteboard_admin/static/web/js/whiteboard/shortcuts.js— replaced theprompt('Group name:', 'Group')in the Ctrl+G handler.WhiteboardGroups.createGroupon confirm; cancel/Escape/backdrop click no-ops.Behavior
Group, input selected on open.Group); Escape and backdrop click cancel.open()returnsPromise<null>without disturbing the first.--wb-*variables.prompt(calls incontextmenu.jsorshortcuts.js.Test results
cargo test --workspace --lib: compiled cleanly, no failures (change is CSS/HTML/JS-only; runs as a regression guard).node --checkpassed forprompt_modal.js,contextmenu.js,shortcuts.js.prompt_modal.jsverified UTF-8 with zero control bytes.