service detailed view #59

Open
opened 2026-04-28 07:11:22 +00:00 by despiegk · 2 comments
Owner

mirror the approach used for the per-job detailed view (issue #58), but for a single service.

when we are looking at one service, we need a different view:

  • no longer show the grid
  • show the full service in a pane
  • right: a useful default (live runtime status + per-action quick view, or live logs from the service's actions; see acceptance)
  • left: details of the service - config, dependencies, current run, runtime state, jobs summary
  • link back to the parent run, child jobs, actions, secrets, anything relevant
  • a clear "Back to services" button to return to the tab
  • esc + browser back + url deep-link (#services/) all work
  • responsive collapse below 900 px viewport

design a good ergonomic view for a service that mirrors the layout/feel of the new job detail view.

mirror the approach used for the per-job detailed view (issue #58), but for a single service. when we are looking at one service, we need a different view: - no longer show the grid - show the full service in a pane - right: a useful default (live runtime status + per-action quick view, or live logs from the service's actions; see acceptance) - left: details of the service - config, dependencies, current run, runtime state, jobs summary - link back to the parent run, child jobs, actions, secrets, anything relevant - a clear "Back to services" button to return to the tab - esc + browser back + url deep-link (#services/<name>) all work - responsive collapse below 900 px viewport design a good ergonomic view for a service that mirrors the layout/feel of the new job detail view.
Author
Owner

Spec: Issue #59 — Service Detailed View

Objective

Mirror the per-job detail view shipped in issue #58 (commit 400cfcb) for individual services. Clicking a service row in #tab-services hides the table and opens a focused two-column workspace inside the same tab pane: left = service config, dependencies, runtime state and metadata; right = a live, run-scoped jobs table. The view is hash-routable at #services/<name>, dismissable via Back button / Esc / browser back, and collapses to a vertical stack below 900 px.

Requirements

  • Hide services-list-view (toolbar + table) and show services-detail-view (header + split) when a service is opened.
  • Header: Back button, title, action buttons (Run, Edit, Logs, Jobs, Start/Stop/Restart/Kill, Delete).
  • Left pane: name, description, runtime state badge, wanted status, class, critical flag, current run chip, PID, restarts, dependencies (chips per category), actions (chips), linkbacks (Run, Logs, Jobs, Terminal where applicable).
  • Right pane: live, run-scoped jobs table for current_run_id (1.5 s polling, mirroring _jobLogPollTimer lifecycle). Each row clicks through to the per-job detail view.
  • Hash route #services/<name> deep-links and persists across reload.
  • Esc closes the view (yields to active modals).
  • Browser back closes the view (existing hashchange branch returns to plain #services and triggers hideServicesDetailView()).
  • Switching tabs closes the view (mirror the if (tabName !== 'jobs') hideJobsDetailView() line).
  • Responsive collapse below 900 px viewport.
  • Preserve the legacy #services-detail side panel (still used by showServiceForm() for the New / Edit Service form).

Files to modify

  • crates/hero_proc_ui/templates/index.html
  • crates/hero_proc_ui/static/js/dashboard.js
  • crates/hero_proc_ui/static/css/dashboard.css

No backend / Rust changes. All required RPCs (service.get, service.status, job.list { filter: { run_id } }) already exist.

Implementation plan

Step 1 — Restructure #tab-services markup

Wrap the existing toolbar + bulk-bar + main-container (table + legacy #services-detail side panel) in <div class="services-list-view" id="services-list-view">. Append a sibling <div class="services-detail-view" id="services-detail-view" hidden> with services-detail-header (Back, title, actions) + services-detail-split (left pane + right pane with toolbar + jobs container). The legacy #services-detail panel stays inside #services-list-view.

Dependencies: none.

Step 2 — Add CSS for services-detail-view

Append rules for .services-list-view, .services-detail-view, .services-detail-header, .services-detail-title, .services-detail-actions, .services-detail-back, .services-detail-split, .services-detail-left, .services-detail-right, .services-detail-jobs-toolbar, .services-detail-jobs, .services-detail-left .form-group, .services-detail-left .chip. Use the same --bg-* / --text-* / --border-color tokens as the jobs detail view. Add a 900 px media query that flips .services-detail-split to flex-direction: column. Or extend the existing selectors as .jobs-list-view, .services-list-view { ... } etc.

Dependencies: Step 1.

Step 3 — State variables and show/hide helpers

Add (near the existing _jobsDetailOpen block):

let _servicesDetailOpen = false;
let _servicesDetailName = null;
let _servicesDetailJobsPaused = false;
let _servicesDetailJobsTimer = null;
let _servicesDetailRunId = null;

function showServicesDetailView() { ... }
function hideServicesDetailView() { ... }
function toggleServicesDetailJobsPause() { ... }
function refreshServicesDetailJobs() { ... }

hideServicesDetailView() clears the timer, resets state, restores the list view, and replaceRoute('services') if the hash starts with services/.

Dependencies: Step 1.

Step 4 — Esc handler

Add a second keydown listener that calls hideServicesDetailView() when _servicesDetailOpen is true and no modal overlay is visible (#job-modal-overlay, .confirm-modal-overlay, .modal.show).

Dependencies: Step 3.

Step 5 — switchTab integration

In switchTab, add if (tabName !== 'services') hideServicesDetailView(); next to the existing jobs-equivalent line.

Dependencies: Step 3.

Step 6 — Rewrite viewService(name)

Fetch service.get and service.status in parallel. Populate title, action buttons (state-gated Start vs Stop+Restart+Kill, plus Run/Edit/Logs/Jobs/Delete), and left-pane HTML (state badge, wanted status, class, critical flag, current-run chip, PID, restarts, dependency chips per category, action chips, jobs-summary chip, links to Logs/Terminal). Initialise the right pane with a "Loading…" placeholder and the toolbar label "Jobs in run #N" (or "No active run"). Then _servicesDetailName = name, _servicesDetailRunId = current_run_id, showServicesDetailView(), setRoute('services/' + encodeURIComponent(name)). Mark the row selected. Start startServicesDetailJobsPolling(name).

Dependencies: Steps 1, 3.

Step 7 — Right-pane jobs polling loop

Add stopServicesDetailJobsPolling, fetchServicesDetailJobs, startServicesDetailJobsPolling. The fetch re-reads service.status every tick to track current_run_id changes (e.g. after Restart) and re-targets job.list { filter: { run_id, limit: 200 } }. Renders a <table class="data-table"> with abbreviated columns (ID, Action, Phase, Attempt, Exit, Duration). Row onclick opens the per-job detail view. 1.5 s interval. The poller updates the live-dot, the toolbar label, and the jobs-count.

Dependencies: Step 6.

Step 8 — Toolbar wiring

Right-pane toolbar buttons:

  • Pause/Play → toggleServicesDetailJobsPause().
  • Refresh → fetchServicesDetailJobs() (one-shot).
  • Open in Jobs tab → navigateToServiceJobs(_servicesDetailName, _servicesDetailRunId).

Dependencies: Steps 1, 7.

Step 9 — Hashchange + DOMContentLoaded + back-to-list cleanup

Tweak the hashchange handler's terminal else branch: when hash === 'services', if (_servicesDetailOpen) hideServicesDetailView();. The existing else if (hash.startsWith('services/')) branch already calls viewService(name). The DOMContentLoaded deep-link block routes type: 'service' through viewService(value) — unchanged.

Dependencies: Step 3.

Step 10 — closePanel('services') cleanup

In closePanel, when tab === 'services', call hideServicesDetailView() so legacy callers (bulk delete, save-then-close) drop the detail view if it's open.

Dependencies: Step 3.

Step 11 — Row click rewires to the new detail view

The row's onclick="viewService('<name>')" (line 2594) is unchanged — the rewritten viewService now opens the full-pane view.

Dependencies: Step 6.

Acceptance criteria

  • Clicking a row in the services table hides the table + toolbar and shows a full-pane two-column detail view.
  • Header shows the service name, a Back button, and Run / Edit / Logs / Jobs / Start-or-Stop+Restart+Kill / Delete buttons that work.
  • Left pane shows runtime state badge, wanted status, class, critical flag, current-run chip, PID, restarts, dependencies (per requires/after/wants/conflicts), and action chips. Each chip navigates correctly.
  • Right pane shows a live run-scoped jobs table for the service's current_run_id, refreshed every 1.5 s, with live dot, pause, refresh, and open-in-Jobs-tab controls.
  • Clicking a job row in the right pane opens the per-job detail view in #tab-jobs.
  • If the service has no current run, the right pane shows "No active run." with no errors.
  • URL updates to #services/<name> when opened, reverts to #services when closed.
  • Reload at #services/<name> lands directly on the detail view for that service.
  • Back button / Esc / browser back / tab switch all return to the list view and stop polling.
  • Below 900 px viewport, the split collapses to a vertical stack.
  • The legacy #services-detail side panel still works for New / Edit Service forms.
  • No console errors, no leaked timers (verify _servicesDetailJobsTimer is null after closing).

Notes & tradeoffs

  • Right pane = live jobs sub-list (Option A). Chosen over aggregated-logs because it leverages the run-id filtering from commit 4ca6ed0 and gives instant per-job phase/exit-code visibility. Logs are one click away via the header "Logs" button. A future enhancement could add a Jobs/Logs toggle in the right-pane toolbar.
  • _pendingRunFilter interaction. The detail view holds its own _servicesDetailRunId snapshot and does not touch the global _pendingRunFilter until the user explicitly clicks "Open in Jobs tab" (which calls navigateToServiceJobs(name, runId)).
  • current_run_id can change while the view is open. The poller re-fetches service.status on every tick so the right pane re-targets the new run automatically.
  • Secrets section deferred. There is no UI-side service↔secret association today; tracking-only for this issue.
  • Polling interval. 1.5 s matches _jobLogPollTimer. Idle services still get polled so the view detects a new run starting.
  • Class names. services-detail-view (plural prefix) intentionally mirrors jobs-detail-view. The legacy #services-detail side-panel ID is unchanged.
# Spec: Issue #59 — Service Detailed View ## Objective Mirror the per-job detail view shipped in issue #58 (commit `400cfcb`) for individual services. Clicking a service row in `#tab-services` hides the table and opens a focused two-column workspace inside the same tab pane: left = service config, dependencies, runtime state and metadata; right = a live, run-scoped jobs table. The view is hash-routable at `#services/<name>`, dismissable via Back button / Esc / browser back, and collapses to a vertical stack below 900 px. ## Requirements - Hide `services-list-view` (toolbar + table) and show `services-detail-view` (header + split) when a service is opened. - Header: Back button, title, action buttons (Run, Edit, Logs, Jobs, Start/Stop/Restart/Kill, Delete). - Left pane: name, description, runtime state badge, wanted status, class, critical flag, current run chip, PID, restarts, dependencies (chips per category), actions (chips), linkbacks (Run, Logs, Jobs, Terminal where applicable). - Right pane: live, run-scoped jobs table for `current_run_id` (1.5 s polling, mirroring `_jobLogPollTimer` lifecycle). Each row clicks through to the per-job detail view. - Hash route `#services/<name>` deep-links and persists across reload. - Esc closes the view (yields to active modals). - Browser back closes the view (existing hashchange branch returns to plain `#services` and triggers `hideServicesDetailView()`). - Switching tabs closes the view (mirror the `if (tabName !== 'jobs') hideJobsDetailView()` line). - Responsive collapse below 900 px viewport. - Preserve the legacy `#services-detail` side panel (still used by `showServiceForm()` for the New / Edit Service form). ## Files to modify - `crates/hero_proc_ui/templates/index.html` - `crates/hero_proc_ui/static/js/dashboard.js` - `crates/hero_proc_ui/static/css/dashboard.css` No backend / Rust changes. All required RPCs (`service.get`, `service.status`, `job.list { filter: { run_id } }`) already exist. ## Implementation plan ### Step 1 — Restructure `#tab-services` markup Wrap the existing toolbar + bulk-bar + main-container (table + legacy `#services-detail` side panel) in `<div class="services-list-view" id="services-list-view">`. Append a sibling `<div class="services-detail-view" id="services-detail-view" hidden>` with `services-detail-header` (Back, title, actions) + `services-detail-split` (left pane + right pane with toolbar + jobs container). The legacy `#services-detail` panel stays inside `#services-list-view`. Dependencies: none. ### Step 2 — Add CSS for `services-detail-view` Append rules for `.services-list-view`, `.services-detail-view`, `.services-detail-header`, `.services-detail-title`, `.services-detail-actions`, `.services-detail-back`, `.services-detail-split`, `.services-detail-left`, `.services-detail-right`, `.services-detail-jobs-toolbar`, `.services-detail-jobs`, `.services-detail-left .form-group`, `.services-detail-left .chip`. Use the same `--bg-*` / `--text-*` / `--border-color` tokens as the jobs detail view. Add a 900 px media query that flips `.services-detail-split` to `flex-direction: column`. Or extend the existing selectors as `.jobs-list-view, .services-list-view { ... }` etc. Dependencies: Step 1. ### Step 3 — State variables and show/hide helpers Add (near the existing `_jobsDetailOpen` block): ``` let _servicesDetailOpen = false; let _servicesDetailName = null; let _servicesDetailJobsPaused = false; let _servicesDetailJobsTimer = null; let _servicesDetailRunId = null; function showServicesDetailView() { ... } function hideServicesDetailView() { ... } function toggleServicesDetailJobsPause() { ... } function refreshServicesDetailJobs() { ... } ``` `hideServicesDetailView()` clears the timer, resets state, restores the list view, and `replaceRoute('services')` if the hash starts with `services/`. Dependencies: Step 1. ### Step 4 — Esc handler Add a second `keydown` listener that calls `hideServicesDetailView()` when `_servicesDetailOpen` is true and no modal overlay is visible (`#job-modal-overlay`, `.confirm-modal-overlay`, `.modal.show`). Dependencies: Step 3. ### Step 5 — `switchTab` integration In `switchTab`, add `if (tabName !== 'services') hideServicesDetailView();` next to the existing jobs-equivalent line. Dependencies: Step 3. ### Step 6 — Rewrite `viewService(name)` Fetch `service.get` and `service.status` in parallel. Populate title, action buttons (state-gated Start vs Stop+Restart+Kill, plus Run/Edit/Logs/Jobs/Delete), and left-pane HTML (state badge, wanted status, class, critical flag, current-run chip, PID, restarts, dependency chips per category, action chips, jobs-summary chip, links to Logs/Terminal). Initialise the right pane with a "Loading…" placeholder and the toolbar label "Jobs in run #N" (or "No active run"). Then `_servicesDetailName = name`, `_servicesDetailRunId = current_run_id`, `showServicesDetailView()`, `setRoute('services/' + encodeURIComponent(name))`. Mark the row selected. Start `startServicesDetailJobsPolling(name)`. Dependencies: Steps 1, 3. ### Step 7 — Right-pane jobs polling loop Add `stopServicesDetailJobsPolling`, `fetchServicesDetailJobs`, `startServicesDetailJobsPolling`. The fetch re-reads `service.status` every tick to track `current_run_id` changes (e.g. after Restart) and re-targets `job.list { filter: { run_id, limit: 200 } }`. Renders a `<table class="data-table">` with abbreviated columns (ID, Action, Phase, Attempt, Exit, Duration). Row `onclick` opens the per-job detail view. 1.5 s interval. The poller updates the live-dot, the toolbar label, and the jobs-count. Dependencies: Step 6. ### Step 8 — Toolbar wiring Right-pane toolbar buttons: - Pause/Play → `toggleServicesDetailJobsPause()`. - Refresh → `fetchServicesDetailJobs()` (one-shot). - Open in Jobs tab → `navigateToServiceJobs(_servicesDetailName, _servicesDetailRunId)`. Dependencies: Steps 1, 7. ### Step 9 — Hashchange + DOMContentLoaded + back-to-list cleanup Tweak the `hashchange` handler's terminal `else` branch: when `hash === 'services'`, `if (_servicesDetailOpen) hideServicesDetailView();`. The existing `else if (hash.startsWith('services/'))` branch already calls `viewService(name)`. The DOMContentLoaded deep-link block routes `type: 'service'` through `viewService(value)` — unchanged. Dependencies: Step 3. ### Step 10 — `closePanel('services')` cleanup In `closePanel`, when `tab === 'services'`, call `hideServicesDetailView()` so legacy callers (bulk delete, save-then-close) drop the detail view if it's open. Dependencies: Step 3. ### Step 11 — Row click rewires to the new detail view The row's `onclick="viewService('<name>')"` (line 2594) is unchanged — the rewritten `viewService` now opens the full-pane view. Dependencies: Step 6. ## Acceptance criteria - [ ] Clicking a row in the services table hides the table + toolbar and shows a full-pane two-column detail view. - [ ] Header shows the service name, a Back button, and Run / Edit / Logs / Jobs / Start-or-Stop+Restart+Kill / Delete buttons that work. - [ ] Left pane shows runtime state badge, wanted status, class, critical flag, current-run chip, PID, restarts, dependencies (per `requires`/`after`/`wants`/`conflicts`), and action chips. Each chip navigates correctly. - [ ] Right pane shows a live run-scoped jobs table for the service's `current_run_id`, refreshed every 1.5 s, with live dot, pause, refresh, and open-in-Jobs-tab controls. - [ ] Clicking a job row in the right pane opens the per-job detail view in `#tab-jobs`. - [ ] If the service has no current run, the right pane shows "No active run." with no errors. - [ ] URL updates to `#services/<name>` when opened, reverts to `#services` when closed. - [ ] Reload at `#services/<name>` lands directly on the detail view for that service. - [ ] Back button / Esc / browser back / tab switch all return to the list view and stop polling. - [ ] Below 900 px viewport, the split collapses to a vertical stack. - [ ] The legacy `#services-detail` side panel still works for New / Edit Service forms. - [ ] No console errors, no leaked timers (verify `_servicesDetailJobsTimer` is null after closing). ## Notes & tradeoffs - **Right pane = live jobs sub-list (Option A).** Chosen over aggregated-logs because it leverages the run-id filtering from commit `4ca6ed0` and gives instant per-job phase/exit-code visibility. Logs are one click away via the header "Logs" button. A future enhancement could add a Jobs/Logs toggle in the right-pane toolbar. - **`_pendingRunFilter` interaction.** The detail view holds its own `_servicesDetailRunId` snapshot and does not touch the global `_pendingRunFilter` until the user explicitly clicks "Open in Jobs tab" (which calls `navigateToServiceJobs(name, runId)`). - **`current_run_id` can change while the view is open.** The poller re-fetches `service.status` on every tick so the right pane re-targets the new run automatically. - **Secrets section deferred.** There is no UI-side service↔secret association today; tracking-only for this issue. - **Polling interval.** 1.5 s matches `_jobLogPollTimer`. Idle services still get polled so the view detects a new run starting. - **Class names.** `services-detail-view` (plural prefix) intentionally mirrors `jobs-detail-view`. The legacy `#services-detail` side-panel ID is unchanged.
Author
Owner

Implementation complete — browser test results

UI-only change, three files. cargo check passes for hero_proc_ui. Service was restarted via service_proc start --reset; the dashboard was driven through the Hero Browser MCP at the running ui.sock.

Files modified

File Change
crates/hero_proc_ui/templates/index.html services tab restructured into list-view / detail-view + 2-column split with header, left pane, right-pane jobs toolbar (live-dot, status, count, pause, refresh, open-in-jobs)
crates/hero_proc_ui/static/js/dashboard.js new state vars, show/hide helpers, ESC handler, switchTab integration, full rewrite of viewService to render into the new container, new fetchServicesDetailJobs + startServicesDetailJobsPolling, hashchange branch + closePanel symmetry
crates/hero_proc_ui/static/css/dashboard.css extended every existing .jobs-detail-* selector to also cover the .services-detail-* counterparts; added .services-detail-jobs overflow + table hover rules

No backend / Rust changes. The legacy #services-detail panel is preserved — showServiceForm() still uses it for New / Edit Service.

Test matrix (all pass)

Acceptance criterion Result
Click service row hides list, shows two-pane detail view pass
URL becomes #services/<name> on open pass
Header shows Run / Edit / Logs / Jobs / state-gated Start-or-Stop+Restart+Kill / Delete pass
Left pane shows State, Wanted, Class, Critical, Current Run chip, PID, Restarts, Description, Actions, Dependencies, Jobs Summary pass (all 11 labels)
Right pane shows live run-scoped jobs table, 1.5 s polling, live dot, status, "run #N · M jobs" count pass (run #501, 1 job)
Run chip in left pane jumps to Runs tab and clears the services view + timer pass
Action chip and Dependency chips navigate correctly pass (verified via onclick attribute)
Clicking a job row in the right pane opens the per-job detail view in #tab-jobs pass (lands at #jobs/924, _jobsDetailOpen=true, services state cleared)
Deep-link #services/<name> opens the view directly pass (hero_aibroker, runId 50)
Service with no current run shows "No active run." with no errors pass
Esc dismisses the view and stops the poller pass (_servicesDetailJobsTimer=null)
Browser back returns to list, stops poller pass
Switching tabs returns to list, stops poller pass
Below 900 px viewport, the split collapses to a vertical stack pass
Legacy #services-detail New Service form still opens pass
List filter (search) still works after Back pass (1 row matches "hero_proc")
No console errors pass (empty console_messages)

Notes

  • Right pane = live jobs sub-list (Option A). Selected per the spec — leverages the run-id filtering shipped in 4ca6ed0 and gives instant per-job phase/exit-code visibility. Logs are one click away via the header Logs button.
  • Polling re-fetches service.status every tick so the right pane re-targets a new current_run_id when the user clicks Restart while the view is open. The toolbar label updates in place.
  • State isolation. The detail view holds its own _servicesDetailRunId snapshot and never writes to the global _pendingRunFilter / _activeRunFilter (those still drive the Jobs tab's own filter). The "Open in Jobs tab" button in the right-pane toolbar hands off through navigateToServiceJobs(name, runId) which sets the global filter as before.
  • Theme parity. The view inherits from the existing --bg-* / --text-* / --border-color tokens and follows the dashboard's existing dark/light toggle.
  • Secrets section deferred. No UI-side service↔secret association exists today; tracking-only for this issue.

Implementation complete; ready to merge once reviewed.

## Implementation complete — browser test results UI-only change, three files. cargo check passes for hero_proc_ui. Service was restarted via `service_proc start --reset`; the dashboard was driven through the Hero Browser MCP at the running ui.sock. ### Files modified | File | Change | |---|---| | `crates/hero_proc_ui/templates/index.html` | services tab restructured into list-view / detail-view + 2-column split with header, left pane, right-pane jobs toolbar (live-dot, status, count, pause, refresh, open-in-jobs) | | `crates/hero_proc_ui/static/js/dashboard.js` | new state vars, show/hide helpers, ESC handler, switchTab integration, full rewrite of `viewService` to render into the new container, new `fetchServicesDetailJobs` + `startServicesDetailJobsPolling`, hashchange branch + closePanel symmetry | | `crates/hero_proc_ui/static/css/dashboard.css` | extended every existing `.jobs-detail-*` selector to also cover the `.services-detail-*` counterparts; added `.services-detail-jobs` overflow + table hover rules | No backend / Rust changes. The legacy `#services-detail` panel is preserved — `showServiceForm()` still uses it for New / Edit Service. ### Test matrix (all pass) | Acceptance criterion | Result | |---|---| | Click service row hides list, shows two-pane detail view | pass | | URL becomes `#services/<name>` on open | pass | | Header shows Run / Edit / Logs / Jobs / state-gated Start-or-Stop+Restart+Kill / Delete | pass | | Left pane shows State, Wanted, Class, Critical, Current Run chip, PID, Restarts, Description, Actions, Dependencies, Jobs Summary | pass (all 11 labels) | | Right pane shows live run-scoped jobs table, 1.5 s polling, live dot, status, "run #N · M jobs" count | pass (run #501, 1 job) | | Run chip in left pane jumps to Runs tab and clears the services view + timer | pass | | Action chip and Dependency chips navigate correctly | pass (verified via onclick attribute) | | Clicking a job row in the right pane opens the per-job detail view in `#tab-jobs` | pass (lands at `#jobs/924`, `_jobsDetailOpen=true`, services state cleared) | | Deep-link `#services/<name>` opens the view directly | pass (hero_aibroker, runId 50) | | Service with no current run shows "No active run." with no errors | pass | | Esc dismisses the view and stops the poller | pass (`_servicesDetailJobsTimer=null`) | | Browser back returns to list, stops poller | pass | | Switching tabs returns to list, stops poller | pass | | Below 900 px viewport, the split collapses to a vertical stack | pass | | Legacy `#services-detail` New Service form still opens | pass | | List filter (search) still works after Back | pass (1 row matches "hero_proc") | | No console errors | pass (empty `console_messages`) | ### Notes - **Right pane = live jobs sub-list (Option A).** Selected per the spec — leverages the run-id filtering shipped in `4ca6ed0` and gives instant per-job phase/exit-code visibility. Logs are one click away via the header `Logs` button. - **Polling re-fetches `service.status` every tick** so the right pane re-targets a new `current_run_id` when the user clicks Restart while the view is open. The toolbar label updates in place. - **State isolation.** The detail view holds its own `_servicesDetailRunId` snapshot and never writes to the global `_pendingRunFilter` / `_activeRunFilter` (those still drive the Jobs tab's own filter). The "Open in Jobs tab" button in the right-pane toolbar hands off through `navigateToServiceJobs(name, runId)` which sets the global filter as before. - **Theme parity.** The view inherits from the existing `--bg-*` / `--text-*` / `--border-color` tokens and follows the dashboard's existing dark/light toggle. - **Secrets section deferred.** No UI-side service↔secret association exists today; tracking-only for this issue. Implementation complete; ready to merge once reviewed.
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_proc#59
No description provided.