fix all routes on all UI functionality #39

Open
opened 2026-04-05 13:28:16 +00:00 by despiegk · 3 comments
Owner

image

implement /hero_ui_routes

use browser mcp to test, if you can't find give error

![image](/attachments/8f387a4e-0662-4793-a6fc-19063559cb1a) implement /hero_ui_routes use browser mcp to test, if you can't find give error
865 KiB
Author
Owner

Implementation Spec for Issue #39 — Hash-Based Routing

Objective

Implement a complete, stable, hash-based routing model for the hero_proc dashboard SPA so that every major section, every meaningful domain object, and every significant cross-object relationship has a canonical, reproducible URL.

Current State

Tab-level routing already works (e.g. #actions, #services). The critical gap is object-level routes — clicking a row opens a side panel but the URL never reflects the selected object.

Route Canonical Table

Route Behavior
#actions/<name> Open action detail panel
#services/<name> Open service detail panel
#runs/<id> Open run detail panel
#jobs/<id> Open job detail panel
#jobs?service=<name> Filter jobs by service
#secrets/<key> Open secret detail panel
#schedules/<name> Open schedule detail panel
#logs, #logs/<src>, #logs/job/<id> Already implemented
#terminal/<id>, #docs/<page>, #heroscript/<path> Already implemented

Files to Modify

  • crates/hero_proc_ui/static/js/dashboard.js — all routing logic

Implementation Steps

  1. Add setRoute() helper using history.replaceState (avoids re-firing hashchange)
  2. Update viewAction/viewService/viewRun/viewJob/viewSecret/viewSchedule to call setRoute('tab/id') when opening panels
  3. Update closePanel(tab) to reset hash to #tab when an object sub-route is active
  4. Update switchTab to preserve deeper sub-routes (not overwrite #services/foo with #services)
  5. Update navigateToServiceJobs to set #jobs?service=<name>
  6. Extend hashchange handler to parse all new #tab/id patterns and open panels
  7. Extend DOMContentLoaded init to deep-link on fresh page load (open correct panel after data loads)
  8. Add _pendingServiceFilter so #jobs?service=foo restores the filter on fresh load
  9. Remove dead pathname-based routing (legacy fallback replaced by hash routing)

Acceptance Criteria

  • Clicking any action/service/run/job/secret/schedule row updates the URL to #tab/id
  • Closing a panel resets URL to #tab
  • Opening #services/hero_aibroker in a fresh tab opens the correct detail panel
  • Opening #jobs?service=hero_aibroker in a fresh tab filters jobs to that service
  • Back/forward browser navigation works between object routes
  • All pre-existing routes (#logs/, #terminal/, #docs/, #heroscript/) continue working
  • Browser MCP can navigate the UI deterministically via canonical URLs

Implementation Note

Using history.replaceState (not location.hash = ...) throughout to avoid re-triggering the hashchange listener and polluting browser history.

## Implementation Spec for Issue #39 — Hash-Based Routing ### Objective Implement a complete, stable, hash-based routing model for the hero_proc dashboard SPA so that every major section, every meaningful domain object, and every significant cross-object relationship has a canonical, reproducible URL. ### Current State Tab-level routing already works (e.g. `#actions`, `#services`). The critical gap is **object-level routes** — clicking a row opens a side panel but the URL never reflects the selected object. ### Route Canonical Table | Route | Behavior | |---|---| | `#actions/<name>` | Open action detail panel | | `#services/<name>` | Open service detail panel | | `#runs/<id>` | Open run detail panel | | `#jobs/<id>` | Open job detail panel | | `#jobs?service=<name>` | Filter jobs by service | | `#secrets/<key>` | Open secret detail panel | | `#schedules/<name>` | Open schedule detail panel | | `#logs`, `#logs/<src>`, `#logs/job/<id>` | Already implemented | | `#terminal/<id>`, `#docs/<page>`, `#heroscript/<path>` | Already implemented | ### Files to Modify - `crates/hero_proc_ui/static/js/dashboard.js` — all routing logic ### Implementation Steps 1. **Add `setRoute()` helper** using `history.replaceState` (avoids re-firing `hashchange`) 2. **Update `viewAction/viewService/viewRun/viewJob/viewSecret/viewSchedule`** to call `setRoute('tab/id')` when opening panels 3. **Update `closePanel(tab)`** to reset hash to `#tab` when an object sub-route is active 4. **Update `switchTab`** to preserve deeper sub-routes (not overwrite `#services/foo` with `#services`) 5. **Update `navigateToServiceJobs`** to set `#jobs?service=<name>` 6. **Extend `hashchange` handler** to parse all new `#tab/id` patterns and open panels 7. **Extend `DOMContentLoaded` init** to deep-link on fresh page load (open correct panel after data loads) 8. **Add `_pendingServiceFilter`** so `#jobs?service=foo` restores the filter on fresh load 9. **Remove dead pathname-based routing** (legacy fallback replaced by hash routing) ### Acceptance Criteria - [ ] Clicking any action/service/run/job/secret/schedule row updates the URL to `#tab/id` - [ ] Closing a panel resets URL to `#tab` - [ ] Opening `#services/hero_aibroker` in a fresh tab opens the correct detail panel - [ ] Opening `#jobs?service=hero_aibroker` in a fresh tab filters jobs to that service - [ ] Back/forward browser navigation works between object routes - [ ] All pre-existing routes (`#logs/`, `#terminal/`, `#docs/`, `#heroscript/`) continue working - [ ] Browser MCP can navigate the UI deterministically via canonical URLs ### Implementation Note Using `history.replaceState` (not `location.hash = ...`) throughout to avoid re-triggering the `hashchange` listener and polluting browser history.
Author
Owner

Spec update (approved): Adding multi-job query support via #jobs?ids=1,2,3 (Option A — query param). This is combinable with the service filter: #jobs?service=hero_aibroker&ids=1,2,3. Behavior: filters the jobs table to show only the specified job IDs. Proceeding with implementation.

**Spec update (approved):** Adding multi-job query support via `#jobs?ids=1,2,3` (Option A — query param). This is combinable with the service filter: `#jobs?service=hero_aibroker&ids=1,2,3`. Behavior: filters the jobs table to show only the specified job IDs. Proceeding with implementation.
Author
Owner

Implementation Complete

Changes Made

File: crates/hero_proc_ui/static/js/dashboard.js

Core routing infrastructure

  • Added setRoute(hash) helper using history.replaceState (avoids re-triggering hashchange)
  • Added _pendingServiceFilter and _pendingJobIds module-level variables for deep-link restore

Object-level routes (new)

Each view* function now calls setRoute when opening a detail panel:

  • viewAction(name)#actions/<name>
  • viewService(name)#services/<name>
  • viewRun(id)#runs/<id>
  • viewJob(id)#jobs/<id>
  • viewSecret(key)#secrets/<key>
  • viewSchedule(name)#schedules/<name>

Panel close resets route

closePanel(tab) now resets hash to #<tab> when an object sub-route is active

switchTab preserves sub-routes

No longer overwrites #services/foo with #services on tab switch

Jobs filtering routes

  • navigateToServiceJobs now sets #jobs?service=<name>
  • New: #jobs?ids=1,2,3 — filter jobs table to specific IDs (combinable: #jobs?service=foo&ids=1,2,3)

hashchange handler extended

Handles all new patterns: #actions/<name>, #services/<name>, #runs/<id>, #jobs/<id>, #jobs?service=<name>, #jobs?ids=1,2,3, #secrets/<key>, #schedules/<name>

DOMContentLoaded init rewritten

Full hash-based deep-link parsing on fresh page load — opens correct tab AND correct detail panel after data loads

All history.replaceState calls consolidated

All routing now goes through setRoute for consistency

Build

cargo build success (1 pre-existing warning, 0 errors)

Canonical Route Table

Route Behavior
#actions Actions tab
#actions/<name> Actions tab + open panel
#services/<name> Services tab + open panel
#runs/<id> Runs tab + open panel
#jobs/<id> Jobs tab + open panel
#jobs?service=<name> Jobs tab filtered by service
#jobs?ids=1,2,3 Jobs tab filtered to specific IDs
#secrets/<key> Secrets tab + open panel
#schedules/<name> Schedules tab + open panel
#logs, #logs/<src>, #logs/job/<id>, #logs/jobs/<ids> Already existed
#terminal/<id>, #docs/<page>, #heroscript/<path> Already existed
## Implementation Complete ### Changes Made **File:** `crates/hero_proc_ui/static/js/dashboard.js` #### Core routing infrastructure - Added `setRoute(hash)` helper using `history.replaceState` (avoids re-triggering `hashchange`) - Added `_pendingServiceFilter` and `_pendingJobIds` module-level variables for deep-link restore #### Object-level routes (new) Each `view*` function now calls `setRoute` when opening a detail panel: - `viewAction(name)` → `#actions/<name>` - `viewService(name)` → `#services/<name>` - `viewRun(id)` → `#runs/<id>` - `viewJob(id)` → `#jobs/<id>` - `viewSecret(key)` → `#secrets/<key>` - `viewSchedule(name)` → `#schedules/<name>` #### Panel close resets route `closePanel(tab)` now resets hash to `#<tab>` when an object sub-route is active #### `switchTab` preserves sub-routes No longer overwrites `#services/foo` with `#services` on tab switch #### Jobs filtering routes - `navigateToServiceJobs` now sets `#jobs?service=<name>` - New: `#jobs?ids=1,2,3` — filter jobs table to specific IDs (combinable: `#jobs?service=foo&ids=1,2,3`) #### `hashchange` handler extended Handles all new patterns: `#actions/<name>`, `#services/<name>`, `#runs/<id>`, `#jobs/<id>`, `#jobs?service=<name>`, `#jobs?ids=1,2,3`, `#secrets/<key>`, `#schedules/<name>` #### `DOMContentLoaded` init rewritten Full hash-based deep-link parsing on fresh page load — opens correct tab AND correct detail panel after data loads #### All `history.replaceState` calls consolidated All routing now goes through `setRoute` for consistency ### Build `cargo build` — ✅ success (1 pre-existing warning, 0 errors) ### Canonical Route Table | Route | Behavior | |---|---| | `#actions` | Actions tab | | `#actions/<name>` | Actions tab + open panel | | `#services/<name>` | Services tab + open panel | | `#runs/<id>` | Runs tab + open panel | | `#jobs/<id>` | Jobs tab + open panel | | `#jobs?service=<name>` | Jobs tab filtered by service | | `#jobs?ids=1,2,3` | Jobs tab filtered to specific IDs | | `#secrets/<key>` | Secrets tab + open panel | | `#schedules/<name>` | Schedules tab + open panel | | `#logs`, `#logs/<src>`, `#logs/job/<id>`, `#logs/jobs/<ids>` | Already existed | | `#terminal/<id>`, `#docs/<page>`, `#heroscript/<path>` | Already existed |
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#39
No description provided.