Collaborative tasking layers, Beacon auth hardening, and fixes - #405
Merged
Conversation
Extract hardcoded width values ('280px' and '30px') into constants for better maintainability. Add comprehensive state synchronization in the in-place update path to ensure collapsed/open states, classes, and UI elements are properly kept in sync when rules are updated. This prevents stale classes and styles from persisting during updates.
Adds shared tasking layers with marker sync, right-click marker creation, and popup editing/deletion. Also adds the collaborative layer list and visibility controls in the config modal, plus Beacon person-name lookup for marker attribution.
Bumps [postcss](https://github.com/postcss/postcss) from 8.5.10 to 8.5.25. - [Release notes](https://github.com/postcss/postcss/releases) - [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md) - [Commits](postcss/postcss@8.5.10...8.5.25) --- updated-dependencies: - dependency-name: postcss dependency-version: 8.5.25 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [immutable](https://github.com/immutable-js/immutable-js) from 4.3.8 to 4.3.9. - [Release notes](https://github.com/immutable-js/immutable-js/releases) - [Changelog](https://github.com/immutable-js/immutable-js/blob/main/CHANGELOG.md) - [Commits](immutable-js/immutable-js@v4.3.8...v4.3.9) --- updated-dependencies: - dependency-name: immutable dependency-version: 4.3.9 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [tmp](https://github.com/raszi/node-tmp) from 0.2.6 to 0.2.7. - [Changelog](https://github.com/raszi/node-tmp/blob/master/CHANGELOG.md) - [Commits](raszi/node-tmp@v0.2.6...v0.2.7) --- updated-dependencies: - dependency-name: tmp dependency-version: 0.2.7 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [js-yaml](https://github.com/nodeca/js-yaml) from 4.1.1 to 4.3.0. - [Changelog](https://github.com/nodeca/js-yaml/blob/master/CHANGELOG.md) - [Commits](nodeca/js-yaml@4.1.1...4.3.0) --- updated-dependencies: - dependency-name: js-yaml dependency-version: 4.3.0 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
) The lambda.lighthouse-extension.com/lad/... endpoints accepted requests from anyone with the URL. Add /lad_v2/... copies of all five Lambdas (share, default-assets, map-layers, route, geocode) that verify the caller's existing Beacon access token (RS256 JWT, verified locally against SES's identity server JWKS) before doing anything -- no new login step, no token minted by us. route/geocode also required threading a token into two places outside the tasking SPA: src/contentscripts/jobs/create.js (a real content script, reads the token from chrome.storage.local) and src/injectscripts/jobs/view.js (a true page-context inject script, uses the page's own `user.accessToken` global directly). The injectscripts/jobs/create.js counterpart now also forwards `user.accessToken` via postMessage to its content-script pair, which needed it for its own route-Lambda call. Also fixes three call sites in models/Team.js that were still calling fetchSharedDefaults() with the pre-auth two-arg signature, sending a literal "Bearer undefined" header. Also un-ignore lambda/ (it was fully git-ignored, so none of this source -- old or new -- was previously tracked). Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Each of the five auth-gated Lambdas discarded the verified token's claims after checking them. Capture the returned claims and emit one structured log line (sub/client_id + route) per successful auth so usage can be broken down per user in CloudWatch Logs Insights, not just aggregate invocation counts. Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
…387) updateIndex()'s optimistic-concurrency retry only treated HTTP 412 as a lost race and retried; everything else (including the actual error) was rethrown straight to the caller. S3's conditional-write feature (IfMatch/IfNoneMatch on PutObject) reports a lost race as 409 ConditionalRequestConflict, not 412 -- so the retry never fired, and every real race surfaced as a 500 to the client. Confirmed via CloudWatch: dozens of these on LH-MapLayersv2's GET /{id} route (which bumps lastUsedAt on every view), all against the same org's index.json. Applied to both map-layers-v2 (currently deployed to LH-MapLayersv2) and map-layers (the pre-auth v1 copy, still live on LH-MapLayers with real traffic) since they share the identical bug. Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Beacon has separate identity server deployments per environment (prod, train, ...) with their own signing keys, so a single TRUSTED_ISS/JWKS_URI pair can't validate tokens from more than one. TRUSTED_ISS is now a comma-separated allow-list; the JWKS endpoint and expected audience are derived per-issuer from the matched trusted value instead of needing separate lists kept in sync. Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
) Markers on the collaborative tasking layer now support a threaded comment log, resolved through the Beacon Operations Log (title/ description and comments are pointers into Ops Log entries rather than free text stored on the marker itself). Also replaces the marker icon picker's 42-icon/7-group set with a curated 26-icon/6-group set (Hazards & Weather, Vehicles & Rescue, People & Animals, Resources & Supplies, Observation & Comms, Status & Markers), and updates the map-layers-v2 Lambda's icon allowlist and default icon to match -- it must stay in sync with the client's MARKER_ICON_GROUPS or new icons get silently rejected server-side. Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
…ive map layers (#390) Creators can now restrict a layer at creation time: only they can add markers, only they can delete the layer, and/or comments are disabled entirely. Enforced server-side in lambda/map-layers-v2 against the Beacon member id from the caller's verified JWT (claims.sub), stored as createdByMemberId on the layer -- not the client-supplied actorId, which stays purely for display/audit. Adds a soft-delete DELETE /lad_v2/map-layers/{id} route/handler for removing a layer. The tasking UI gains matching controls: a collapsed-by-default "New layer permissions" section with Anyone/Only-I radio pairs for markers, layer deletion and comments, a per-row Delete-layer button, and marker popup/add-marker gating that gets out of the way once the Lambda would reject the action anyway. Also fixes a pre-existing bug where layer creation was attributed to a different Beacon identity (userId) than every marker/comment action on that layer (personId), which would have silently broken creator checks. Already deployed to the live LH-MapLayersv2 Lambda and its API Gateway route. Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
) The page reveal (body opacity 1) fired on the plain DOMContentLoaded event, racing ahead of the async require(["knockout", ...]) load and ko.applyBindings call. That let raw, unbound markup (and the config modal popping in afterward) flash briefly on page load. Now the reveal happens right after bindings are applied and the modal is already open.
Collab markers previously fell into Leaflet's default markerPane (fixed z-index 600), so they weren't part of the layer-order drawer and could render inconsistently relative to Incident/Asset markers depending on the user's pane order config. Adds a pane-collab pane, defaulted to sit under Incident markers but above Asset markers, and makes it a first-class entry in the draggable layer order list. Existing saved pane orders get the new pane inserted at its default relative position instead of always appended at the bottom. Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
…ptions model for collaborative map layers (#393) - Every layer must now belong to an HQ (required, defaults to ?hq=) and can optionally be attached to a Beacon event; both are searchable via new BeaconClient modules (entities-backed HQ search, new events.js, new users.js for moderator search). - Marker/delete/comment permissions are now a 3-way mode (anyone/creator/moderators) instead of booleans, with a shared moderator list per layer. Moderators can now manage that list themselves, not just the creator. - Replaced the HQ-filtered "list with a View toggle" model with a subscriptions model: a "My layers" list (always cross-HQ, so unsubscribing never depends on knowing which HQ a layer came from) plus a separate "Find a layer" search to discover and subscribe. Show/hide is now solely the map's own Layers control's job. - listLayers.js supports server-side HQ filtering; permission checks centralized in lib/permissions.js and reused across handlers. - Marker/comment Ops Log entries now carry the layer's EventId when one is attached. Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
…r creation (#394) Previously markerMode/deleteMode/commentMode were fixed at creation. Adds a PUT /permissions Lambda route (creator-or-moderator authorized, same as moderator management) and a standalone Config modal to edit them, with poll-driven sync so other subscribers see permission changes without a manual refresh. Also includes the getWritableCollabLayers rename and Add-marker disabled state that were already uncommitted in the working tree and are required for the collab layer permission model to be consistent.
Every Leaflet popup on the tasking map (collab layer, incidents, assets, dams, WaterNSW, hazard watch, BOM weather, transport cameras/ roadworks, SES unit locations, and context-menu search/geocode results) fell back to Leaflet's built-in popupPane, which loses z-index ties against this app's custom marker panes since it's created earlier in the DOM. Give all of them a dedicated pane-popup-top pane fixed above every marker pane. Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
…t after creation (#396) Both were previously fixed at creation with no later "reassign HQ" or "attach/detach event" flow. Adds a PUT /map-layers/{id}/attachment route (same creator-or-moderator authorization as permissions/ moderators) and extends the existing "Manage permissions" modal with HQ and event pickers, reusing the same widgets from the create-layer form. Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
) * Move collaborative layer moderator editing into the settings modal Moderators had their own inline expanding panel and Save/Cancel separate from the permissions/HQ/event modal, despite being gated by the same creator-or-moderator authorization. Folds it into #collabPermissionsModal alongside them so one Save click updates permissions, attachment and moderators together. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Use the pencil icon on this branch too This branch forked from master-dev before the pencil-icon fix (#397) merged, so the settings button still showed the old padlock. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Shows each candidate's unit alongside their member number in the moderator search dropdown, closes the create-layer form automatically after a successful create (it previously stayed open with the fields reset), and makes the selected HQ/event chip itself clickable to reopen search rather than only the small "x" button, so it reads more like the searchable dropdown pattern used elsewhere. Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
…400) Move the collaborative marker create/edit popup's audit disclaimer below the button row as a quiet caption instead of a boxed callout. Also make the "Create layer" button show its in-flight and success states (spinner, then a brief checkmark) instead of the form closing the instant the request resolves. Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
- SMSRecipient no longer discards the beaconContact passed to its
constructor, so recipients added via the recipient search box keep
their contact info instead of always ending up empty.
- Search-added recipients now build a beaconContact entry with the
real Id/Detail/ContactTypeId/Description fields instead of the
lossy {id, name, detail} row used for display.
- messages.js now derives the Recipients[i][Description] field from
either FirstName/LastName (team-member contacts) or Description
(search-added contacts), since the two contact shapes differ.
- attachSendSMSModal's job branch now sets taskId, fixing the empty
JobId on the "Task & SMS Details" button.
- Team-member recipients start as loading so the Send button is
disabled until each one's SMS number finishes fetching, instead of
allowing a send before beaconContact is populated; a failed lookup
now clears loading too so it can't lock the button permanently.
- Recipient search results now show which headquarters each contact
belongs to.
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Bumps [brace-expansion](https://github.com/juliangruber/brace-expansion) from 1.1.13 to 1.1.18. - [Release notes](https://github.com/juliangruber/brace-expansion/releases) - [Commits](juliangruber/brace-expansion@v1.1.13...v1.1.18) --- updated-dependencies: - dependency-name: brace-expansion dependency-version: 1.1.18 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* Fix wrong apiHost passed to transport incidents ops log lookup An extra hardcoded argument shifted every parameter in the getTransportApiKeyOpsLog call, so it resolved the wrong ops log ID and passed a non-function as the callback. * remove debug
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
lambda.lighthouse-extension.comLambdas, logs the authenticated user on eachlad_v2invocation, and supports multiple trusted Beacon token issuersapiHostused for the transport incidents ops log lookup, BMB unit HQ coordinates, map-layersindex.jsonretry not catching S3's actual conflict status, and a flash of unbound placeholder content before the config modal showsjs-yaml,tmp,immutable, andpostcssto patched versionsTest plan
lambda.lighthouse-extension.com🤖 Generated with Claude Code