Skip to content

Enhance myAvailability gems and integrate SignalR live updates - #420

Merged
OSPFNeighbour merged 10 commits into
masterfrom
master-dev
Aug 22, 2026
Merged

Enhance myAvailability gems and integrate SignalR live updates#420
OSPFNeighbour merged 10 commits into
masterfrom
master-dev

Conversation

@OSPFNeighbour

Copy link
Copy Markdown
Collaborator

This pull request implements a centralized Lambda authorizer for Beacon token authentication, removing duplicated token verification logic from five lad_v2 Lambda handlers. Now, authentication is enforced by the new authorizer-v2 Lambda via API Gateway, and downstream handlers receive the verified Beacon member ID via the event context. The pull request also updates several GitHub Actions to use newer versions of dependencies and actions.

Centralized Beacon token authentication:

  • Added lambda/authorizer-v2/index.mjs, a new Lambda authorizer that verifies Beacon tokens, centralizing the logic previously duplicated in multiple handlers. On success, it passes the verified Beacon member ID (sub) to downstream Lambdas via the event context.
  • Removed direct imports and usage of verifyBeaconToken from default-assets-v2, geocode-v2, map-layers-v2, route-v2, and share-v2 handlers. These handlers now trust the API Gateway authorizer and extract the user ID from event.requestContext.authorizer.lambda.sub. [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11]

GitHub Actions and dependency updates:

  • Updated actions/checkout from v3 to v7 in .github/workflows/linter.yml, .github/workflows/publish_dev.yml, and .github/workflows/publish_prod.yml for improved CI reliability and features. [1] [2] [3]
  • Updated mnao305/chrome-extension-upload action from v4.0.1 to v6.0.0 in publish workflows to ensure compatibility and security. [1] [2]
  • Added @microsoft/signalr v10.0.11 as a new dependency in package.json.

These changes improve code maintainability, security, and reduce duplication by centralizing authentication logic.

OSPFNeighbour and others added 10 commits August 14, 2026 10:14
Adds a row of colour-coded count 'gems' (Activation Accepted, Available, Conditional, Unavailable, Unset) below the Incident Details header on the job view page. Counts and hover popovers listing responder names are populated via a new `lighthouseResponseGems()` function that calls the myavailability/incident Lambda (production only; non-prod Beacon gets placeholder data). Includes a loading pulse animation and full CSS styling for the gem bar.
…ems (#412)

Response gems now show real counts/names even for closed activations
(with a lock icon + note instead of blanking numbers), popovers pin
open on click instead of only showing on hover, member names carry
their id for future use, and long name lists are capped with a "+N
more" indicator. Also adds a role-gated "Create Team" button on the
Activation Accepted gem that opens /Teams/Create pre-filled with the
accepted members and the incident's own HQ.

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Adds LH-BeaconAuthorizerV2, a Lambda REQUEST authorizer wrapping the
existing verifyBeaconToken logic (same trusted-issuer allow-list, same
beaconApi scope check), and attaches it to all /lad_v2/... routes so
invalid/missing tokens are rejected at the gateway before any backend
Lambda runs. The five backend Lambdas now read the verified member id
from the authorizer's context instead of re-verifying the token
themselves, removing duplicated JWKS/JWT logic from each one.

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
The popover panel is appended to <body>, not nested under the gem, so
moving the mouse from the gem into the panel counted as a mouseleave
on the gem and hid it instantly. Track hover on the panel itself once
shown, with a short delay before hiding, so crossing the gap between
gem and panel doesn't close it.

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
…#414)

GitHub Actions runners are deprecating Node 20; actions/checkout@v3 and
mnao305/chrome-extension-upload@v4.0.1 were being force-run on Node 24
with a deprecation warning. Bumping to actions/checkout@v7 and
chrome-extension-upload@v6.0.0, both of which target Node 24 natively.

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
…o Available (#415)

Dev/watch builds zero-padded the version timestamp (e.g. 2026.08.16.0941),
which Chrome then displays with leading zeros stripped per segment
(2026.8.16.941), making the on-disk manifest look out of sync with what's
shown in chrome://extensions. Align dev/watch with prod's unpadded format.

Also extend the "create team from responders" quick action to the
Available gem, not just ActivationAccepted.

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
* Wire SignalR live updates into the tasking page, replacing periodic polling where push covers it

Connects the tasking page to Beacon's Comms SignalR hub for near-real-time
job/team/tasking/ops-log/ICEMS updates, alongside a resilient connection
layer and a config-level kill switch, so REST polling can back off wherever
push already keeps data fresh.

- New src/pages/tasking/signalr/ module: connection manager with infinite
  backoff reconnect + manual-restart safety net, a lightweight Subject/
  registry for routing named hub events, and a shared pushMode flag that
  Job/Team read to size their on-demand fetch cooldowns.
- Job.js/Team.js/Tasking.js: handle jobCreated/jobUpdated/jobRejected (a
  Notification-record shape, not the job view-model it looks like -- JobId
  is the real id, not Id), teamCreated/teamUpdated (a full team object),
  taskingUpdated/taskingCreated, opsLogUpdated, and the ICEMS notification
  events, each admitted against the existing config filters so push can't
  add out-of-scope entities polling would never have fetched.
- Bulk polls (fetchAllJobsData/fetchAllTeamData) and single-entity fetches
  (refreshData/fetchTasking/refreshIcemsIncident) now skip work already
  covered by a more recent push, without letting a push-authoritative
  refresh get blocked by that same cooldown.
- Dropped the ICEMS agency-data poll entirely in favour of expand + push.
- refreshInterval default raised 60s -> 180s (migrated via a renamed
  storage key so it doesn't silently apply to users who'd customized the
  old default); a new "Live Updates" config toggle disables the connection,
  the disconnect banner, and reverts the tightened cooldowns.
- tasking.html: a persistent, high-visibility banner for any non-connected
  state, since this page depends on the connection for live data.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* Fix job popup/list-row rendering breaking on tasking status updates

Root cause was a malformed <button> tag in the team-tasking status
dropdown (missing closing '>', lost when flashOnChange bindings were
added) -- browsers mis-parse the unclosed tag, which corrupts
Knockout's comment-based foreach/if tracking and throws "unmatched end
comment" the first time that markup renders (row expand or popup
open).

Also fixes two related bugs found while tracking it down:
- Tasking.team can be null before it resolves (a tasking upserted
  before its team ref is available); teamCallsign/hasTeam and several
  team.X template bindings dereferenced it unguarded.
- addOrUpdateJobMarker's popup close/reopen has a 250ms deferred
  unbind (to let the close animation finish) that wasn't cancelled on
  a fast reopen, so a stale unbind could later wipe a popup that's
  live and visibly open again.

Also brings in the rest of the SignalR live-update wiring already in
progress on this branch: flashOnChange/flashTextOnChange bindings for
push-driven value changes, jobUpdated now pulls a full refresh (its
notification payload omits fields like Address/Sector), and
refreshData's cooldown tracks real fetches instead of any merge.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
…king (#417)

* Highlight FR-1 rows and shore up push-notification reliability on tasking

- Give FR-1 (Flood Rescue, Category 1) incident rows a distinct colour,
  subtly deeper than a normal Rescue-priority row, in both light and dark
  mode
- Move unaccepted-notification refresh onto the shared jobs/teams refresh
  cycle instead of a per-job 30s timer, and drop a jobReceived fallback so
  jobs admitted straight from a push notification (which carries no
  JobReceived) aren't evicted by date filtering
- Add the same clock-skew tolerance to the end-of-range date check as the
  existing start-of-range one, so jobs admitted right at the boundary via
  push aren't evicted by lag/skew
- Make the incidents/teams toolbars and table columns responsive to a
  narrow sidebar (container queries + minmax column tracks), split the
  Received column into time/date lines, clamp wrapped Situation/Address
  text instead of letting it balloon row height, and add a manual
  per-incident refresh button

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* Fix FR-1 row color inconsistency between light and dark mode

Dark mode's row-rescue-fr1 (#7a2f22, L=31%) was lighter than row-rescue
(#5a2a2a, L=26%), while light mode has it the other way round (fr1 darker
than rescue) -- so which row read as "more severe" flipped depending on
theme. Dark mode's fr1 is now darker and more saturated than rescue,
matching light mode's direction.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
…ate (#418)

Adds fadeForeach/slideForeach binding handlers so team/job rows and
taskings lists animate in and out on live add/remove instead of popping,
applied across the main tables and both map popups. Fixes Team.refreshData
never clearing taskingLoading after a SignalR-triggered force refresh (the
injected fetchTeamById dependency is Promise-based, but refreshData was
calling it callback-style, so the reset callback was silently dropped).
Also quiets SignalR connection logging to Error level.

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
…refill race (#419)

Replaces the direct single-category /Teams/Create navigation with a modal
listing Accepted, Available, and Conditional responders as checkboxes,
pre-ticked for whichever gem's button was clicked. Also fixes a race on
the Team Create page where the page's own async Assigned To default could
overwrite the incident's HQ passed via lhentityid.

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
@OSPFNeighbour
OSPFNeighbour merged commit ca5e007 into master Aug 22, 2026
2 checks passed
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