Replace Leaflet map tab with grouped locations panel - #119
Conversation
Agent-Logs-Url: https://github.com/potemkin666/AlbertAlert/sessions/c41dfd9b-638a-42ed-a740-0645eb9fa650 Co-authored-by: potemkin666 <183807833+potemkin666@users.noreply.github.com>
Agent-Logs-Url: https://github.com/potemkin666/AlbertAlert/sessions/c41dfd9b-638a-42ed-a740-0645eb9fa650 Co-authored-by: potemkin666 <183807833+potemkin666@users.noreply.github.com>
Agent-Logs-Url: https://github.com/potemkin666/AlbertAlert/sessions/c41dfd9b-638a-42ed-a740-0645eb9fa650 Co-authored-by: potemkin666 <183807833+potemkin666@users.noreply.github.com>
|
@copilot resolve the merge conflicts in this pull request |
Agent-Logs-Url: https://github.com/potemkin666/AlbertAlert/sessions/b254742b-d035-43b2-9f66-6c21d9745e11 Co-authored-by: potemkin666 <183807833+potemkin666@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR removes the Leaflet-based map implementation and repurposes the existing map tab into a lightweight grouped locations panel, keeping the existing London / World / Near me mode wiring while changing the rendering model underneath.
Changes:
- Replaces Leaflet-driven map rendering with grouped location markup generated in
shared/map-watch.mjs. - Updates the app shell and styles to present the tab as a locations panel instead of an interactive map.
- Removes Leaflet assets/tests and adds focused tests for grouping, summaries, and rendered detail actions.
Reviewed changes
Copilot reviewed 13 out of 18 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/nearby-map-mode.test.mjs | Renames nearby-radius test copy to match the non-Leaflet implementation. |
| tests/map-popup-accessibility.test.mjs | Removes popup-specific accessibility tests tied to deleted Leaflet UI. |
| tests/map-improvements.test.mjs | Removes legacy Leaflet/map behavior tests that no longer apply. |
| tests/location-panel.test.mjs | Adds tests for country normalization, grouping, summaries, and locations markup. |
| tests/leaflet-sri.test.mjs | Reworks asset tests to assert Leaflet references/assets are gone. |
| styles.css | Replaces map/popup/tile styling with grouped locations panel styling. |
| source-quarantine.html | Updates generated quarantine dashboard metadata snapshot. |
| shared/map-watch.mjs | Replaces Leaflet controller logic with grouped locations rendering/controller behavior. |
| index.html | Renames map UI copy to Locations and swaps the Leaflet mount for the new panel shell. |
| data/top-20-source-remediation.json | Updates generated remediation snapshot data. |
| data/source-remediation-sweep.json | Updates generated remediation sweep snapshot data. |
| assets/vendor/leaflet/leaflet.js | Removes vendored Leaflet runtime asset. |
| assets/vendor/leaflet/leaflet.css | Removes vendored Leaflet stylesheet asset. |
| assets/vendor/leaflet/LICENSE | Removes vendored Leaflet license file alongside asset removal. |
| app/boot/elements.mjs | Points bootstrapped map element lookup at the new locations panel container. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| currentAlerts = alerts; | ||
| if (mapStatusLine) mapStatusLine.textContent = statusLine(mode, alerts.length, hasUserLocation); | ||
| if (mapEmptyState) mapEmptyState.classList.toggle('hidden', alerts.length > 0); | ||
| mapElement.innerHTML = alerts.length > 0 ? renderLocationsMarkup({ alerts, groups, state, mode }) : ''; |
| const preview = group.alerts.slice(0, GROUP_PREVIEW_LIMIT).map(renderAlertButton).join(''); | ||
| const remaining = group.alerts.length - GROUP_PREVIEW_LIMIT; | ||
|
|
||
| function setupPopupAccessibility(popupElement, marker, map) { | ||
| if (!popupElement) return; | ||
| const focusableElements = popupElement.querySelectorAll(FOCUSABLE_SELECTOR); | ||
| const firstFocusable = focusableElements[0]; | ||
| if (firstFocusable) firstFocusable.focus(); | ||
| return ` | ||
| <article class="location-group" data-severity="${escapeHtml(group.severity)}"> | ||
| <div class="location-group-header"> | ||
| <div> | ||
| <p class="location-group-kicker">${escapeHtml(group.kicker)}</p> | ||
| <h4>${escapeHtml(group.label)}</h4> | ||
| <p class="location-group-meta">${escapeHtml(countLabel(group.alerts.length))} • Highest ${escapeHtml(severityLabel(group.severity))}</p> | ||
| </div> | ||
| <span class="location-group-count">${group.alerts.length}</span> | ||
| </div> | ||
| <div class="location-group-list">${preview}</div> | ||
| ${remaining > 0 ? `<p class="location-group-more">+${remaining} more alerts in this area</p>` : ''} |
| <section class="locations-panel" aria-label="Locations overview"> | ||
| <p class="panel-copy locations-intro">${escapeHtml(intro)}</p> | ||
| <div class="locations-summary">${renderSummaryItems(buildSummaryItems(alerts, groups, state, mode))}</div> | ||
| <div class="locations-groups" role="list">${groups.map(renderGroup).join('')}</div> |
| <span class="pill">Generated: 2026-05-02T19:15:49.792Z</span> | ||
| <span class="pill">Low-health sources: 205</span> | ||
| <span class="pill suggest">Pending suggestions: 0</span> | ||
| <span class="pill">SLA: deprioritised, auto-recheck 24h+</span> | ||
| <span class="pill warn">New this week: 202</span> | ||
| <span class="pill">Avg health score: 1/100</span> | ||
| <span class="pill">Avg time in quarantine: 25h</span> | ||
| <span class="pill">Avg time in quarantine: 37h</span> |
Co-authored-by: potemkin666 <183807833+potemkin666@users.noreply.github.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 13b465dcfc
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| .sort((left, right) => { | ||
| if (right.alerts.length !== left.alerts.length) return right.alerts.length - left.alerts.length; | ||
| const severityDelta = SEVERITY_RANK[right.severity] - SEVERITY_RANK[left.severity]; | ||
| if (severityDelta !== 0) return severityDelta; | ||
| return left.label.localeCompare(right.label); |
There was a problem hiding this comment.
Sort nearby groups by distance from the user
In MAP_VIEW_MODES.nearby, groups are still ordered by alert count and severity, not proximity, so a farther location with more/severer alerts can appear before a closer one. This breaks the nearby-mode behavior described in the panel copy (“Surface the closest places first”) and makes the “Near me” tab unreliable for quick local triage when multiple areas are within radius.
Useful? React with 👍 / 👎.
| const preview = group.alerts.slice(0, GROUP_PREVIEW_LIMIT).map(renderAlertButton).join(''); | ||
| const remaining = group.alerts.length - GROUP_PREVIEW_LIMIT; |
There was a problem hiding this comment.
Render all alerts in each location group
Each group only renders the first three alerts (slice(0, GROUP_PREVIEW_LIMIT)), and the remaining alerts are shown as plain text (“+N more”) without any openDetail action. In groups with more than three alerts, users cannot open those additional incidents from the Locations tab, which is a functional regression from the prior map behavior where every visible alert was actionable.
Useful? React with 👍 / 👎.
This change removes the Leaflet-based map experience entirely and replaces it with a lightweight locations view. The tab keeps the existing London / World / Near me modes, but now renders grouped location intelligence instead of an interactive slippy map.
UI replacement
/index.html.Rendering model
/shared/map-watch.mjsfrom Leaflet asset/bootstrap logic into a pure renderer for:openDetailactionsAsset/runtime removal
Styling
Test coverage
Example of the new rendering shape: