action detailed view #62
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_proc#62
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?
mirror the approach used for the per-job (issue #58), per-service (issue #59), and per-run (issue #60) detailed views, but for a single action.
when we are looking at one action, we need a different view:
design a good ergonomic view for an action that mirrors the layout/feel of the new job/service/run detail views.
Spec: Issue #62 — Action detailed view
Objective
Mirror the per-job (#58), per-service (#59), and per-run (#60) detailed views for a single action. Clicking a row in the Actions table (or deep-linking to
#actions/<name>) hides the grid and opens a focused two-column workspace inside#tab-actions: action metadata on the left, a live sub-list of jobs the action has spawned across recent runs on the right. The legacy#actions-detailslideout is preserved exclusively for the New / Edit Action forms reached viashowActionForm()/editAction().Requirements
#runs/<id>. Each row clicks through to#jobs/<id>. 1.5 s polling.interpreter === 'ai'), retry policy (max attempts, backoff, delay, max delay), TTY flag, env preview (collapsible<details>, closed by default), dependencies, interpreter, type (process / one-shot).a.tty === true), and a clear "Back to actions" button.#services/<svc>) and to individual jobs (#jobs/<id>).#actions/<name>already deep-links viaviewAction(); rewritingviewActionis sufficient.--bg-*/--text-*/--border-colortokens.#actions-detailslideout forshowActionForm()andeditAction().closePanel('actions')symmetry: also callhideActionsDetailView().Files to modify
crates/hero_proc_ui/templates/index.htmlcrates/hero_proc_ui/static/js/dashboard.jscrates/hero_proc_ui/static/css/dashboard.cssNo backend / Rust changes.
Implementation plan
Step 1 — Restructure
#tab-actionsmarkupWrap the existing toolbar + bulk-bar + main-container (table + legacy
#actions-detailslideout) in<div class="actions-list-view" id="actions-list-view">. Append a sibling<div class="actions-detail-view" id="actions-detail-view" hidden>withactions-detail-header(Back, title, actions) +actions-detail-split(left pane + right pane with toolbar + jobs container). Element IDs:actions-list-view,actions-detail-view,actions-detail-title,actions-detail-actions,actions-detail-back,actions-detail-left,actions-detail-right,actions-detail-jobs-toolbar,actions-detail-jobs-container,actions-detail-jobs-dot,actions-detail-jobs-status,actions-detail-jobs-count,actions-detail-jobs-pause,actions-detail-jobs-open.Dependencies: none.
Step 2 — Extend the existing detail-view CSS
Append
.actions-list-view,.actions-detail-view,.actions-detail-header,.actions-detail-title,.actions-detail-actions,.actions-detail-back,.actions-detail-split,.actions-detail-left,.actions-detail-right,.actions-detail-jobs-toolbar,.actions-detail-jobsto every existing grouped selector list (.jobs-detail-* / .services-detail-* / .runs-detail-*). Extend the 900 px media query similarly. Add a small.actions-detail-jobs { overflow-y: auto; padding: 0; }block plus the same> .data-tablehover rules already present for runs/services.Dependencies: Step 1.
Step 3 — State variables, show/hide helpers, ESC handler
Insert near the existing per-tab detail-view blocks:
Dependencies: Step 1.
Step 4 —
switchTabintegrationAdd
if (tabName !== 'actions') hideActionsDetailView();next to the existing jobs/services/runs equivalents.Dependencies: Step 3.
Step 5 — Rewrite
viewAction(name)Fetch
action.getand the initialjob.list { filter: { action_id: name, limit: 200 } }in parallel. Populate title, header action buttons (Run / Edit / Logs / Jobs / Delete always; Terminal only whena.tty), and left-pane HTML via a helperrenderActionsDetailLeft(a, svcName). Render the right-pane jobs table inline (helperrenderActionsDetailJobsTable(jobs)). Init_actionsDetailName = a.name, reset toolbar state, wireactions-detail-jobs-open.onclick = navigateToActionJobs(a.name). CallshowActionsDetailView(),setRoute('actions/' + encodeURIComponent(a.name)), mark the row selected, and startstartActionsDetailJobsPolling(a.name).Dependencies: Steps 1, 3.
Step 6 — Right-pane helpers + jobs polling loop
Add
renderActionsDetailLeft(a, svcName),renderActionsDetailJobsTable(jobs)(columns: ID / Run / Phase / Attempt / Exit / Created — Run cell ischipLink('#'+j.run_id, 'runs', j.run_id)when present, else-). AddfetchActionsDetailJobs(1.5 s interval) andstartActionsDetailJobsPolling(name). Polling re-fetches the job list scoped to_actionsDetailName(noaction.getround-trip — action metadata is static while the view is open). Empty case: "No jobs for this action yet."Dependencies: Step 5.
Step 7 — Action navigation helpers
Add
navigateToActionJobs(name)(sets#jobs?action=<name>route, switches tabs, pre-fills#jobs-searchwith the action name so the existing client-side filter narrows to the right rows),navigateToActionLogs(name)(resolves the action's recent job IDs viajob.list { action_id }then deep-links to#logs/jobs/<csv>),navigateToActionTerminal(name)(picks the newest running job and hands off tonavigateToTerminalJob(id)).Dependencies: none (used by Step 5).
Step 8 — Hashchange + closePanel symmetry
elsebranch of the hashchange handler, mirror the jobs/services/runs lines:if (hash === 'actions' && _actionsDetailOpen) hideActionsDetailView();.closePanel, whentab === 'actions', callhideActionsDetailView()so legacy bulk/post-save callers drop the detail view too.Dependencies: Step 3.
Step 9 — Smoke test
Manual verification through the dashboard via Hero Browser MCP. Restart via the standard
service_proc start --resetflow.Dependencies: Steps 1–8.
Acceptance criteria
#actions-tbodyhides the grid and shows#actions-detail-view.<details>(when non-empty), Dependencies (when non-empty), and the Script<pre>(or "User prompt" for AI).a.tty === true.runAction(name)and toasts the new id.#runs/<id>; clicking a row opens#jobs/<id>.navigateToActionJobs.#actions/<name>deep-links into the detail view on initial load and onhashchange.#actions/<name>returns to#actionsand closes the view..modal.showis on top.#actions-detailslideout still opens forshowActionForm()andeditAction().Notes
job.list { action_id, limit: 200 }hits a single indexedaction_id = ?clause inlist_jobs.<pre>(which can be long).action_idfilter is the right one.job.createsetsaction_id = Some(spec.name.clone())for every job, so server-side filtering is complete and exact.?action=hash for Jobs tab. The Jobs tab hashchange handler does not yet honour anactionquery param. The cheap path used here pre-fills#jobs-searchso the existing client-side filter narrows to the right rows. A first-class server-side action filter for the Jobs tab list is a clean follow-up.navigateToActionTerminalpicks the newest running job for that action; if none exists it toasts a hint to use Run first.jobServiceName(a.name) === ''(top-level actions), the Parent Service form-group is omitted.showActionForm()/editAction()continue to use#actions-detail(right-side slideout).closePanel('actions')is extended to also close the new detail view so post-save and bulk-delete paths don't leave a stale view open.viewActionrendered a D3 dependency graph viarenderActionGraph. It's left in place and unreferenced for now, exactly asrenderRunGraphwas after #60. Reintroducing it is a clean follow-up.Implementation complete — browser test results
UI-only change, three files. cargo check passes for hero_proc_ui. Service restarted via
service_proc start --reset; the dashboard was driven through Hero Browser MCP at the running ui.sock.Files modified
crates/hero_proc_ui/templates/index.htmlcrates/hero_proc_ui/static/js/dashboard.js_actionsDetailOpen,_actionsDetailName,_actionsDetailJobsPaused,_actionsDetailJobsTimer); show/hide helpers; ESC handler;switchTab/closePanel/ hashchange symmetry; full rewrite ofviewActionwith helpersrenderActionsDetailLeft,renderActionsDetailJobsTable,fetchActionsDetailJobs,startActionsDetailJobsPolling; newnavigateToActionJobs,navigateToActionLogs,navigateToActionTerminalhelperscrates/hero_proc_ui/static/css/dashboard.css.jobs-detail-* / .services-detail-* / .runs-detail-*selector group to also cover.actions-detail-*; added.actions-detail-jobsoverflow + table hover rulesNo backend / Rust changes. The legacy
#actions-detailslideout is preserved —showActionForm()andeditAction()still use it. The legacyrenderActionGraphD3 helper is retained but unreachable; cleanup deferred (mirrors therenderRunGraphprecedent from #60).Test matrix (all pass)
#actions/<name>on open#actions/hero_browser_server)a.tty === true<details>, Script<pre>#runs/6)#runs/<id>; clicking a row opens#jobs/<id>#jobs/14,_jobsDetailOpen=true, actions view + timer cleared)_actionsDetailJobsTimer=nullafter each teardown)navigateToActionJobs#actions/<name>deep-links into the detail view#actions/<name>returns to#actionsand closes the viewflex-direction: column)#actions-detailNew Action form still opensconsole_messages)Notes
job.list { action_id, limit: 200 }hits an indexedaction_id = ?clause inlist_jobs.<pre>(which can be long).action_idfilter is exact.job.createsetsaction_id = Some(spec.name.clone())for every job, so server-side filtering is complete.?action=hash for Jobs tab. The Jobs tab hashchange handler does not yet honour anactionquery param. The cheap path used here pre-fills#jobs-searchso the existing client-side filter narrows to the right rows. A first-class server-side action filter for the Jobs tab list is a clean follow-up.navigateToActionTerminalpicks the newest running job for that action; if none exists it toasts a hint to use Run first.cleanup), the Parent Service chip is omitted.#actions-detail(slideout) and#actions-detail-view(workspace) are siblings inside#tab-actions.closePanel('actions')is extended to also close the new detail view so post-save and bulk-delete paths don't leave a stale view open.actions-detail-view(plural prefix) intentionally mirrorsjobs-detail-view,services-detail-view, andruns-detail-view. Legacy#actions-detailID is unchanged.renderActionGraph(D3) is no longer called and stays in place for now — same precedent asrenderRunGraphafter #60.Implementation complete; ready to merge once reviewed.