feat(terminal): treeview, terminal type selection, copy/paste, and connect/disconnect improvements #64
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_router#64
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?
treeview
Make treeview for the terminals, so we can organize in 1...3 levels (max 3) the sessions = terminals
type of terminal
When opening a terminal we can select if its tmux, nushell or just bash
Default = nushell
test copy paste
In terminal test the copy paste (nushell & bash terminal for now)
test connect/disconnect
for all
service_router start --resetImplementation Spec for Issue #64
Objective
Enhance the hero_router terminal tab with four improvements:
Requirements
/separator are grouped. Level 1 is everything before the first/, level 2 is the next segment, level 3 is the leaf name. Max 3 levels. Sessions without a/live in a top-level flat list.terminal.createaccepts an optionalshellparameter ("nu","bash","tmux"). Default is"nu". The shell is recorded as a suffix in the hero_proc job name so the sidebar can display a small colored badge.allowProposedApi: true. Keyboard shortcuts: Ctrl+Shift+C = copy selection, Ctrl+Shift+V = paste from clipboard. Right-click on terminal area shows a Copy/Paste context menu./separators are encoded as double-underscore (__) in the hero_proc job name (e.g.work/rust/debug→router_term_work__rust__debug__nu). The shell type is appended as a suffix.terminal.createandterminal.listschemas are updated to reflect the optionalshellparam.Files to Modify
crates/hero_router/src/server/terminal.rsShellTypeenum +shellfield toTerminalSession; updatecreate_session()to accept shell; updatevalidate_name()to allow/(max 3 segments); add encode/decode helpers for job namescrates/hero_router/src/server/rpc.rsshellparam fromterminal.createcall intocreate_session()crates/hero_router/static/js/terminal.jscrates/hero_router/templates/terminal.htmlcrates/hero_router/static/openrpc.jsonterminal.createparams andterminal.listitem schemaImplementation Plan
Step 1: Extend
TerminalSessionwithshellfield and helpersFiles:
terminal.rsShellTypeenum (Nu,Bash,Tmux)shell: ShellTypetoTerminalSessionjob_name_encode(name, shell)andjob_name_decode(job_name) -> (name, shell)helpersvalidate_name()to allow/(max 3 segments, no__in input)create_session(name, shell, host_url)to pick shell command based onShellTypeDependencies: none
Step 2: Wire
shellparameter throughrpc.rsFiles:
rpc.rsshellparam interminal.createarmShellTypetocreate_session()Dependencies: Step 1
Step 3: Update
terminal.html— new-session modal + treeview CSSFiles:
terminal.htmlDependencies: none (parallel with Step 1)
Step 4: Rewrite
terminal.js— treeview renderingFiles:
terminal.jsrenderSessions()with treeview builder/, build nested map, render collapsible groupscreateSession(name, shell)encodeURIComponent(name)in WebSocket URL and switch PTY route to query param to handle/in namesDependencies: Steps 1, 3
Step 5: Add copy/paste keyboard handler
Files:
terminal.jsattachCustomKeyEventHandlerfor Ctrl+Shift+C and Ctrl+Shift+VallowProposedApi: trueto Terminal constructor optionsDependencies: Step 4
Step 6: Connect/disconnect improvements
Files:
terminal.jsws.close(1000)is called on detachDependencies: Step 4
Step 7: Update
openrpc.jsonFiles:
openrpc.jsonshellparam toterminal.createshellfield to session object interminal.listresultDependencies: Step 1
Acceptance Criteria
/-separated names group into a collapsible treeview (max 3 levels)/appear as flat leaves at root levelterminal.createwith{shell: "bash"}starts bash; omittingshellstarts nushellcargo checkpassesservice_router start --resetrestarts cleanly; new sessions can be created afterNotes
Name encoding:
work/rust/debug→ job namerouter_term_work__rust__debug__nu. Input validation rejects names containing__to keep the encoding unambiguous.PTY route: The WebSocket route must be changed from
GET /api/terminal/pty/:name(path param) toGET /api/terminal/pty?name=<encoded>(query param) to avoid Axum mis-parsing/inside the session name as nested path segments.tmux: Running tmux inside a hero_proc PTY means tmux key bindings are active. Users use
Ctrl-B dto detach from tmux itself; the router Detach button closes the WebSocket. Both behaviors are acceptable.Clipboard API:
navigator.clipboardrequires HTTPS or localhost. For HTTP non-localhost, fall back todocument.execCommand('copy').xterm.js version: 5.3.0 (bundled). No new addon files needed —
attachCustomKeyEventHandleris sufficient for clipboard support.Test Results
cargo testrun after all implementation steps. All 79 existing tests pass. No regressions.Implementation Summary
Changes made
crates/hero_router/src/server/terminal.rsShellTypeenum (Nu,Bash,Tmux) with serde support, defaulting toNushell: ShellTypefield toTerminalSessionencode_job_name(name, shell)anddecode_job_name(job_name)helpers —/in session names is encoded as__in hero_proc job names; shell type is appended as a suffix (__nu,__bash,__tmux)validate_name()to allow/(max 3 segments), reject__in input to keep encoding unambiguouscreate_session(name, shell, host_url)to accept shell type and choose the appropriate shell commandlist_sessions(),get_session(),delete_session(),job_id_for_session()to usedecode_job_name()for name+shell extraction/:name) to query parameter (?name=)crates/hero_router/src/server/rpc.rsterminal.createdispatch now reads optionalshellparam and passesShellTypetocreate_session()crates/hero_router/src/server/routes.rs/api/terminal/pty/:nameto/api/terminal/pty(query param)crates/hero_router/static/js/terminal.jscollapsedGroupsSet for persisting tree expand/collapse state across pollingbuildTree(list),makeShellBadge(shell),makeLeaf(),makeGroup()helpers for treeview renderingrenderSessions(list)to build a collapsible treeview (max 3 levels)#termNewSubmittocreateSession(name, shell)from modal form/api/terminal/pty?name=<encoded>allowProposedApi: trueto xterm Terminal constructorattachCustomKeyEventHandlerfor Ctrl+Shift+C (copy) and Ctrl+Shift+V (paste)sendInput(text)helper for sending text to PTYattach(): early-return if same session already attached, pre-detach guarddetach():ws.close(1000), explicit null resets, context menu cleanupcrates/hero_router/templates/terminal.html#termNewModalmodal with session name input and shell type selector (nushell default)crates/hero_router/static/openrpc.jsonshellparam toterminal.createshellfield to session object schema interminal.listandterminal.createresultsAcceptance criteria status
All backend criteria verified via
cargo test(79/79 passed). UI/browser criteria (treeview rendering, copy/paste, detach/attach cycling) require browser-based testing withservice_router start --reset.