Replace the Resources Hub with Radar - #325
Merged
roncodes merged 13 commits intoSep 16, 2026
Merged
Conversation
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.
2 tasks
Acknowledging or snoozing a Radar item failed with "Unknown column 'public_id'". Fleetbase\Models\Alert uses HasPublicId, whose creating hook checks alerts.public_id for a collision, but the core migration never created the column, so every alert insert failed: Radar's state rows, and the low-stock, sensor and device event alerts FleetOps already raises. Add it, guarded so it is a no-op wherever core-api adds it itself.
- The header's search, view toggle, refresh and new-notice controls sit at the right edge again: the hub header aligns its children to the start at 768px and up, which shrank Radar's row to its content. - Search, toggle and buttons share one 2rem height, and the search text clears the magnifying glass; ember-ui's form-input-sm padding was winning on specificity. - Last sync and the snooze toast format times with date-fns instead of the browser locale, which rendered Arabic digits. - Rows get a real checkbox, so selection and bulk actions work; the Font Awesome regular square never rendered. - Rail buttons, including the snooze dropdown, line up at one height, the open-record icon is smaller, and saved views are shorter with the save button keeping its padding. - Keyboard hints, the count and paging float in a container pinned to the bottom of the viewport. - Rows, decision cards, handover cards and brief links open the record in a context panel instead of navigating away from Radar. - The select modal renders options with the resource select-option components.
PHP CI installs core-api 1.6.55 from composer.lock, which predates the alert snooze and assignment API. RadarItemStateTest died on "undefined relationship [assignedTo]", and the same calls would fail wherever that core is deployed. RadarItemState now writes the state columns itself (acknowledge, snooze, wake, assign, plan, resolve), resolves user names from one uuid lookup instead of the new relations, and reads dates through RadarRules::carbon rather than model casts. The controller routes every state change through it. Coverage was far short of the gate: the probe tests replace the controller's loaders and plumbing, so none of that ran. A new database test drives the real controller over in-memory SQLite: every source loader, handover orders, shift extension, company membership, notices, score history and the failure paths. Edge-case tests cover the remaining branches in the rules, brief, agenda and state helpers. All Radar files are at 100% lines and methods, and the full suite passes against core-api 1.6.55.
- Ember CI: merge the duplicate .fleet-ops-radar-body selector stylelint rejected. - Row checkboxes show as checked: in-array takes the item first, and Radar passed the list first, so every row read as unselected. - Shift-click selects or clears every row between the last row toggled and this one. - The keys and paging footer is a full-width bar flush with the bottom and side edges, the same 39px height as the sidebar's attribution footer so the borders line up. - Last sync shows the date as well as the time. - Send PIN asks how to send it, offering only the channels the link's recipient can receive, as the inspection form's link list does. It used to post without `via` and fail validation. - Picking a vehicle for a driver no longer shows "-". ModelSelect only resolves a uuid on first render, and the modal fed the picked uuid back in; it now keeps the chosen record.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## release/v0.6.66 #325 +/- ##
=====================================================
Coverage 100.00% 100.00%
- Complexity 11073 11709 +636
=====================================================
Files 576 581 +5
Lines 42186 44307 +2121
=====================================================
+ Hits 42186 44307 +2121
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
… details routes Radar opened records through each resource's panel.view, and most of those registered only an overview tab with no header, title or buttons, drew the default header rule above the tab list, and opened narrower than the route. Work order, maintenance, schedule, part, equipment, issue and device panels now carry their route's header component, tabs and action buttons; inspection submissions and forms gain panels. Header menus are shared between routes and panels so they cannot drift. Radar loads records by public id with a single-record query, as the details routes do, which stops Ember Data's RecordIdentifier type error. Closing an issue from Radar uses the close-issue modal, and selected inspection links can be revoked in bulk. Adds the missing issue timeline, panel header and card re-exports the host panel needs.
…ze and fitted geofence maps Driver, vehicle, trailer, fleet, place, contact, customer, vendor, fuel report, service area and zone context panels now open with their details route's title, tabs and actions, and without the header rule above the tabs. The driver, vehicle, trailer and fleet header menus move into their action services so the route and the panel share one definition. New tabs: driver activity, fleet vehicles and drivers, vendor personnel, vehicle inspections. Opening a facilitator from the orders table froze the page with no error: the index payload normalizes it as a bare facilitator record, and the polymorphic descriptor handed it back to registry.open, which resolved it to itself in an endless promise loop. The base now opens the concrete descriptor with the concrete record. Service area and zone panels use a geofence map that re-measures Leaflet once the overlay settles and fits the whole boundary, so the map is no longer grey or off-centre, and is taller. The zone's description field shows its description. Work order, maintenance and schedule forms can clear their target, assignee and type selectors. The Radar open-record test follows the panel behaviour.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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.
J K X E S A ⏎work the list from the keyboard.inspection_failed, inspection-type schedules due.Items are computed live from existing records (
RadarRules, pure and fixture-tested); state (acknowledge, snooze, assign, plan) lives on the corealertstable 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 theschedule_itemsenum does not have, parts had three different definitions of "low stock", and inspection schedules producedpreventive_maintenancework orders.Depends on
fleetbase/core-api#258 (branch
feature/alerts-snooze-assignment, targetingrelease/v1.6.62; addssnoozed_until,snoozed_by_uuid,assigned_to_uuid,planned_attoalerts, plusunsnooze(),assignTo(),snoozed()/active()scopes, andacknowledge()now setsstatus = acknowledged). Land and migrate that first.Test plan
RadarRulesTest,RadarItemStateTest,RadarBriefingTest,RadarAgendaTest,RadarControllerTest,RadarRoutesTest(41 tests), plus the existing hub, command, driver-scheduling, model-accessor and route-registration suitesnpm run lint(js, hbs, css, intl)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 dashboardNotes for reviewers: the dummy test app now loads only
en-ustranslations (tests/dummy/config/ember-intl.js) because Chrome 152 ships no Intl data formnand ember-intl hydrates every locale at boot, which took every rendering test down; the sidebar'soperations-monitorcomponent gained theapp/re-export it was missing. The one remaining red test in the hub-index unit module (a devices controller injectinghostRouter) is pre-existing.