Skip to content

Replace the Resources Hub with Radar - #325

Open
roncodes wants to merge 4 commits into
release/v0.6.66from
feature/resources-hub-refactor-design-ad15e9
Open

roncodes wants to merge 4 commits into
release/v0.6.66from
feature/resources-hub-refactor-design-ad15e9

Conversation

@roncodes

@roncodes roncodes commented Sep 16, 2026

Copy link
Copy Markdown
Member

Summary

The Resources Hub was a landing page of counts and links. Radar is the triage list behind them, built from the "Fleet Health Concepts" design review: Ops Desk (inbox) as the page, the Morning Brief as a strip on top, and Agenda/Handover as a view toggle, on the console's own palette and dark-mode conventions.

  • List. One row per gap across resources, maintenance, inspections, staffing, compliance, fuel and parts, grouped by due date. Count pills are the only filter and combine in the URL; Open / Snoozed / Resolved tabs; saved views per user. A row's hover rail carries the record's own action (raise the work order, assign the vehicle, match the transaction, send the PIN) beside acknowledge, snooze and assign. A drawer shows failed inspection items or the shift behind a row. Selection turns the rail into a bulk bar; J K X E S A ⏎ work the list from the keyboard.
  • Morning brief. Each category scored with visible arithmetic and a delta against yesterday, a few linked sentences about the day, and one decision per card — each a single existing endpoint call, with an undo strip where reversible.
  • Agenda. The same items on the next 24 hours or 7 days: an overdue band left of now, four lanes, a later rail, an anytime tray a drop can schedule from. Every live shift is a bar; a shift ending with orders still assigned gets a handover card naming the nearest on-shift driver with capacity, with reassign / extend shift / snooze.
  • Inspections are first-class input: failed submissions without follow-up, unresolved follow-ups, stale drafts, links expiring unused, vehicles flagged inspection_failed, inspection-type schedules due.
  • Widget "Radar · N overdue" and a header shortcut.

Items are computed live from existing records (RadarRules, pure and fixture-tested); state (acknowledge, snooze, assign, plan) lives on the core alerts table and auto-resolves when a gap closes. Each source loads in its own try/catch so one failing table degrades the page instead of blanking it.

Three bugs the rules exposed are fixed: Driver::currentShift() filtered on a status the schedule_items enum does not have, parts had three different definitions of "low stock", and inspection schedules produced preventive_maintenance work orders.

Depends on

fleetbase/core-api#258 (branch feature/alerts-snooze-assignment, targeting release/v1.6.62; adds snoozed_until, snoozed_by_uuid, assigned_to_uuid, planned_at to alerts, plus unsnooze(), assignTo(), snoozed() / active() scopes, and acknowledge() now sets status = acknowledged). Land and migrate that first.

Test plan

  • PHP: RadarRulesTest, RadarItemStateTest, RadarBriefingTest, RadarAgendaTest, RadarControllerTest, RadarRoutesTest (41 tests), plus the existing hub, command, driver-scheduling, model-accessor and route-registration suites
  • Ember: 35 Radar tests (components, modifier, controller, utils, widget) in headless Chrome; sidebar rename tests updated
  • npm run lint (js, hbs, css, intl)
  • Live: migrate core-api + fleetops, octane:reload, open /fleet-ops/manage; walk pills, tabs, saved views, rail actions, keyboard, bulk, drawer, brief decisions, agenda drag and handover card; dark mode; widget on the dashboard

Notes for reviewers: the dummy test app now loads only en-us translations (tests/dummy/config/ember-intl.js) because Chrome 152 ships no Intl data for mn and ember-intl hydrates every locale at boot, which took every rendering test down; the sidebar's operations-monitor component gained the app/ re-export it was missing. The one remaining red test in the hub-index unit module (a devices controller injecting hostRouter) is pre-existing.

Radar replaces the Resources Hub with the gaps a fleet manager has to
decide about, one item per record: maintenance and inspection schedules
due, overdue or blocked work orders, open issues, failed inspections with
no follow-up, unresolved inspection follow-ups, stale drafts, inspection
links expiring unused, vehicles flagged inspection_failed, drivers late
for a shift, on shift without a vehicle, or ending a shift with orders
still assigned, licences and leases expiring, unmatched fuel, low stock,
and the notices people write themselves.

RadarRules is pure: it takes plain rows and a clock and answers with
items, pill counts and a summary, so every rule is tested against a
fixture and a fixed morning. RadarItemState is the one piece that touches
the database: acknowledge, snooze, assign and plan live on the core
alerts table, a row created only when someone acts, found again by the
item key, and resolved automatically when the record's gap closes.
RadarController loads each source in its own try/catch so one failing
table degrades the page rather than blanking it.

Three fixes the rules exposed: a driver's current shift filtered on a
status the schedule_items enum does not have; a part had three different
definitions of "low stock"; an inspection schedule produced a preventive
maintenance work order.
The brief is arithmetic, not a black box: each category row scores its
open gaps by severity (capped per rule), the overall score is the mean,
and yesterday's score comes from a per-company setting so the delta is
real. Three or four sentences name the records behind the morning with
links, and the decision cards each describe one call the console can make
in a click (raise the work order for a failed inspection, open a work
order for an overdue schedule, put an idle vehicle on a driver without
one, match a fuel transaction to the vehicle its card belongs to), with
the undo where there is one.

The agenda answers the same items placed on the next 24 hours or 7 days:
an overdue band left of now, four lanes, a later rail, and an anytime
tray for undated work, which a drop gives a time via `planned_at`. Every
live shift becomes a bar on the shifts lane; a shift ending with orders
still assigned gets a handover card naming the nearest on-shift driver
with capacity, and an endpoint extends a shift by the hour.

Also: items can be narrowed to one category or to the caller's own
assignments, and driver subjects carry a phone for the Call action.
The hub was a landing page of counts and links. Radar is the triage
list behind them: one row per gap, grouped by due date, with count pills
as the only filter, Open / Snoozed / Resolved tabs, and saved views kept
per user. A row's hover rail carries the record's own action (raise the
work order, assign the vehicle, match the transaction, send the PIN)
beside acknowledge, snooze and assign; a drawer shows the failed
inspection items or the shift behind a row. Selection turns the rail
into a bulk bar, and J/K/X/E/S/A/Enter work the list from the keyboard.

Above the list the morning brief scores each category with visible
arithmetic, writes a few linked sentences about the day, and offers one
decision per card, each a single call with an undo strip. The Agenda
toggle lays the same items on the next 24 hours or 7 days: an overdue
band, four lanes, a later rail and an anytime tray a drop can schedule
from, with every live shift as a bar and a handover card naming the
nearest driver with capacity to take a leaving driver's orders.

Styling stays on the console's palette: sky-500 for the active pill and
primary actions, the badge palette for chips and severities, the hub's
rose and amber tones for overdue and today, and dark mode through the
same body[data-theme] overrides as the rest of the engine.
"Radar · 3 overdue" as a KPI tile that links to the page, registered
with the other tiles and as a Fleet-Ops header shortcut.

Two things the test build needed: the dummy app now loads only en-us
translations, because ember-intl hydrates every locale at boot and
Chrome 152 ships no Intl data for `mn`, which took every rendering test
down before it began; and the sidebar's operations-monitor component
gets the app re-export every engine component needs to resolve outside
the engine.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant