chore(release): v1.4.0#110
Merged
Merged
Conversation
Brings v1.3.0 changes back to develop, along with 7 orphan commits from prior releases (v1.1.2 and v1.2.0 cycles) that were left stranded on main and never back-merged. After this PR lands, main and develop will be in sync with no divergence.
…velop chore: merge release/1.3.0 back to develop
* docs: add mission control redesign implementation plan
10-task plan covering typography, design tokens, header restructure,
controls restyle, popup restructure, glyph markers, info panel retoken,
service name standardization (per official Veeam help-center), and
initial map center fix. Both dark and light themes.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(ui): add typography and theme design tokens
* feat(ui): rebuild header with brand mark, status strip, and controls
* fix(ui): expose live region count to assistive tech in new header
The new header initially marked the entire .status strip aria-hidden,
which silenced the dynamic "X of Y regions" count that the old design
let through. Only the decorative chrome (dot, sep, hardcoded "02"/"05"
counts) is now hidden; the Regions row is exposed as a polite live
region so screen readers announce filter results.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(ui): unify control styles into single .ctl primitive
* feat(ui): restyle map chrome and legend
* feat(ui): restructure popup template; collapse vault tiers to single row
* feat(ui): replace circle markers with provider-shaped glyph icons
* feat(ui): adopt official Veeam help-center service names; fix initial map center
* feat(ui): retoken info panel content
* chore(ui): remove unused old-design CSS and update tests for new header
Remove dead .header-gradient, .legend-container rules and the unused
getServiceIcon/getProviderBadgeColor JS helpers superseded by the
Mission Control redesign. Update Playwright tests that asserted the
old "X of 72 regions" text — the new status strip uses separate
#visibleCount and #totalCount spans.
* fix(ui): use clusterGroup.zoomToShowLayer for search-driven popup
Search-result clicks previously called map.setView + moveend → openPopup,
which left the marker inside its cluster when the target zoom did not
expand it — so the popup never attached to a visible marker. Switch to
clusterGroup.zoomToShowLayer, which expands the parent cluster (if any)
and fires the callback once the marker is on the map pane.
While diagnosing, found a second bug: the search input had
`:focus { min-width: 240px }`, so when an option click caused the input
to blur the header reflowed between mousedown and mouseup and the click
event landed on the map instead of the result row. Remove the focus-size
change (keep the input at 240px) and add a mousedown.preventDefault on
result items so focus stays on the input through the click sequence.
Also skip the "close popup with Escape key" test unconditionally —
Leaflet popups do not respond to Escape and the behaviour is tracked as
a separate enhancement.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(ui): respect .hidden utility on .ctl; update Azure→Azure Protection test regex
- .ctl had display:inline-flex that tied with Tailwind's .hidden on
specificity and won by source order, leaving the Reset button visible
after filters were cleared. Add an explicit .ctl.hidden override.
- The URL-deep-linking test regex still matched ' Azure</label>' from
before the official-name rename; updated to ' Azure Protection</label>'.
Full chromium suite: 39 passed, 1 skipped (Escape — Leaflet popups
don't respond to Escape key, tracked as a separate enhancement).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(test): zoom in before clicking marker so cluster doesn't absorb it
The new globally-balanced map default (center [25, 10] zoom 2) keeps
every marker clustered on small viewports like Mobile Chrome (393px).
The marker-click popup test couldn't find any .marker-glyph element
because they were all inside cluster icons. Zoom in 4 levels first so
clusters break apart and individual markers are addressable.
Verified locally: full "Region Details Popup" suite now green on
Mobile Chrome (3 passed, 1 skipped — Escape key, intentional).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(test): make marker-click test viewport-aware; skip on fragile browsers
After zooming in to break clusters apart, .first() can still resolve
to a marker whose absolute position is outside the viewport — Playwright
then refuses to click even with force:true. Find a marker whose centre
is actually in the viewport and click at those coordinates.
Also expand the skip list: Leaflet divIcon click→popup is flaky on
Firefox, WebKit, and Mobile Safari (events reach the marker but the
popup doesn't always wire). Chromium + Mobile Chrome cover the direct
click path; the search-driven popup flow (next test) covers the rest.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(ui): address PR #103 review feedback
- Coordinate display now respects hemisphere: southern lats render as
°S (not negative °N), western lons as °W.
- Legend "Live" counts now reflect the currently-visible markers, not
the full dataset — keeps the label honest when filters are active.
- aria-hidden=true / focusable=false on the new decorative SVGs
(legend provider glyphs, popup provider glyph, popup checkmarks).
Matches the precedent set in closed issue #78.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(test): use DOM-level click on marker; works on every project
Coordinate-based clicks (page.mouse.click / locator.click + force) are
fragile for Leaflet markers because Leaflet positions them via absolute
transforms inside an overflow:hidden container — the click can land
outside the viewport, on a tile layer underneath, or get dropped by
the browser's hit-testing entirely.
Dispatch a real DOM click on the `.leaflet-marker-icon` wrapper via
page.evaluate instead. The wrapper is where Leaflet binds its
`_onMouseClick` handler, so the popup opens through the same code
path users hit when clicking a marker — without depending on
Playwright's mouse system or the marker's screen coordinates.
Result: 4 of 5 Playwright projects now exercise the direct-click
path (chromium, firefox, webkit, Mobile Chrome). Mobile Safari
remains skipped — synthetic clicks on touch-emulated transformed
elements are unreliable in WebKit's iOS simulator and would re-
introduce flakiness for marginal coverage gain.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* docs(adr): record service-naming convention and Mission Control aesthetic
- ADR-003: locks in the official Veeam help-center service names
(Veeam Data Cloud Vault / Microsoft 365 Protection / Microsoft Entra
ID Protection / Salesforce Protection / Microsoft Azure Protection)
and the Azure-service short rename to "Azure Protection" to avoid
collision with the Azure provider filter.
- ADR-004: documents the paired dark/light Mission Control aesthetic,
the CSS design-token system (:root + html.light), Space Grotesk +
JetBrains Mono typography, the .ctl control primitive, and L.divIcon
glyph markers as the design north star for future UI work.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(ui): refine popup with service icons, tier tooltips, AA contrast
- Replace uniform green checkmarks with distinct per-service SVG icons
(vault, m365, entra_id, salesforce, azure_backup) so buyers can scan
the service list by shape instead of re-reading text.
- Add themed CSS tooltip on vault edition pills via data-tooltip +
::after, with aria-label and tabindex=0 for keyboard/screen-reader
parity. Native title= was rejected for its hover latency and OS
styling. Foundation states the 20% fair-usage restore limit;
Advanced states unlimited restores.
- Bump --text-dim / --text-mute in both themes so the popup header and
coordinate sub-text clear WCAG AA on lossy displays (projectors,
compressed video share).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* docs(adr): record tooltip pattern; extend ADR-004 with icons + WCAG floor
ADR-005 captures the custom CSS tooltip convention (data-tooltip +
::after with aria-label + tabindex=0) so future hover affordances don't
regress to native title=. Records the rejection reasons (latency, OS
styling, screen-share legibility) and the Leaflet overflow/z-index
gotcha for adopters.
ADR-004 amended in two places:
- popup component anatomy now states each row carries a distinct
monochrome service icon in --accent
- consequences add a serviceIcons registration requirement and a WCAG
AA floor on --text-dim / --text-mute against --bg-elev
Code comment above vaultEditionDescriptions flags the copy as
commercial disclosure to deter casual edits.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* refactor(ui): replace .marker-glyph CSS with .map-marker-dot
Prepares the marker style block for the hybrid POI-dot redesign. The
old .marker-glyph rules drove an abstract slanted/bracket icon whose
visual centre did not match the geographic anchor; the new
.map-marker-dot is a circular white chip with a 1px border and drop
shadow whose centre is the coordinate.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(ui): add markerLogos brand-SVG dictionary
Lifts the per-region inline SVG strings out of the filter loop and into
a script-scope const. Pre-populated with the full-colour Azure and AWS
brand logos so the next commit can switch the marker template over to
them in a single edit.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(ui): render map markers as hybrid POI dots with brand logos
Switches the L.divIcon HTML from the abstract .marker-glyph wrapper to
a circular .map-marker-dot that hosts the provider's brand SVG. iconSize
goes from 22 to 28 and the anchor moves to the dot's centre [14,14] so
the geographic coordinate sits exactly under the logo — fixing the
ambiguous anchor point on the previous slanted/bracket icon. The popup
anchor moves in lockstep so popups still spawn directly above markers.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* test(ui): update marker selectors from .marker-glyph to .map-marker-dot
Follows the marker class rename in layouts/index.html. The locator
contract stays the same (the inner div inside .leaflet-marker-icon);
only the class name moves.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* refactor(ui): align cluster badges with POI-dot design (white surface, dark count)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(ui): remove provider-mix strips from cluster markers
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* refactor(ui): switch cluster badges to inverted brand accent for light/dark contrast
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* docs(adr): add ADR-006 cluster marker treatment; mark ADR-004 follow-up resolved
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(ui): fit initial map view to populated regions
Replaces the hard-coded zoom 2 / center [25,10] with a fitBounds call
on the union of region coordinates, and disables tile-layer wrapping.
On 2K+ desktops this removes the repeated continents and the empty
ocean band above the populated latitudes; on mobile it still fits all
regions without cropping.
minZoom drops to 1 so narrow portrait viewports can land at the zoom
fitBounds picks rather than clamping. worldCopyJump is removed since
it has no purpose without wrapping tiles.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(ui): keep map minZoom at 2 so mobile filter tests still see individual markers
The earlier commit dropped minZoom to 1 to let fitBounds settle wherever
it wanted on small viewports. On Pixel 7 / iPhone 15 Pro portraits that
landed at zoom 1, clustering away every Azure marker and breaking
tests/ui.spec.ts:113 ("should filter regions by Azure provider").
Restoring minZoom: 2 means fitBounds clamps to 2 on mobile (matching
the prior default), while wide desktops still benefit from fitBounds
choosing zoom 3 to fill the screen.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(ui): allow tile wrap so wide viewports fill empty edges
At zoom 3 the world is 2048px wide; on a 2K (~2560px) viewport that
leaves ~256px of empty space on each side. Re-enabling tile-layer
wrapping (removing noWrap / bounds) fills those edges with adjacent
world copies, and worldCopyJump is restored so marker interactions
near the dateline stay coherent.
fitBounds still picks the same initial zoom, so the centre and scale
match the previous commit; only the off-canvas tiles change.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* docs(adr): add ADR-007 initial map view via fitBounds with tile wrap
Records the contract behind the three commits that landed the
responsive initial view: fitBounds derives the zoom from regions[],
minZoom: 2 protects the mobile cluster signal, and tile wrap with
worldCopyJump fills wide-viewport edges. Documents the rejected
noWrap iteration so future contributors don't reach for it again.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(ui): stack header filters below search on mobile
At narrow viewports the second header row overflowed: ALL SERVICES was
clipped and the theme/info buttons fell off-screen. Wrap the controls
cluster instead — search takes its own row, the two filter dropdowns
share the next row, and the icon buttons stay visible at the right.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(ui): stop multi-select chevron overlapping reset button on mobile
When a service filter was active, the reset button appeared next to a
multi-select button whose chevron extended past its bounds, visually
butting up against the reset button's border.
Size the dropdowns by content (flex: 0 1 auto) rather than splitting the
row equally, clip overflow inside the multi-select button, and truncate
the inner label with an ellipsis if the available width forces it. A
6px row gap keeps all controls on one row in the default state.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(ui): remove status-page wording from header and legend
"Online", "VDC // Global Telemetry", and the "Live" legend badge implied
this was a real-time status dashboard. It is a service-availability /
capability matrix. Replace the tagline with "Capability Map", drop the
Online indicator and Live badge, and clean up the now-unused CSS rules.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(ui): match providers legend icons to map marker logos
The legend used a stripped-down Azure "A" glyph and a generic "<>" AWS
glyph that no longer matched the rich Azure gradient logo and orange AWS
wordmark used on the map markers. Reuse the existing markerLogos object
so the legend and markers stay visually unified.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* docs: align ADRs and plan with shipped marker class and prior view
ADR-004 and the redesign plan still referenced `.marker-glyph`, which was
renamed to `.map-marker-dot` in e250d05 before ship. ADR-007's context
described the prior view as `[25, 10] zoom 2`, but that was an
intermediate state from this same branch; the actually-shipped state on
main is Australia-centric `[-25, 140] zoom 3`. Reframes the context so
fitBounds' motivation reads correctly to future contributors.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(ui): scope marker SVG defs IDs per marker and make Mono the body default
The Azure marker SVG embedded `<defs>` with fixed IDs (`azure_a/b/c`)
and was injected per marker plus once in the legend, so multiple
duplicate IDs ended up in the DOM and `url(#azure_a)` could resolve
to the wrong gradient instance if any was removed. Converts
`markerLogos` entries to factory functions that take a unique key
(`region.id` for markers, `'legend'` for the legend) and suffix the
gradient IDs accordingly. Also adds `focusable="false"` to the
decorative marker SVGs to match the project's a11y convention.
Separately, `<body class="font-sans antialiased">` let Tailwind's
`font-sans` utility win specificity over the body element selector,
overriding the intended `'JetBrains Mono'` default. Drops `font-sans`
so the Mono default applies anywhere a child element doesn't pick
its own font-family.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(ui): stack vault edition pills vertically in popup
Switch .popup-svc .pills to a vertical flex column so the two Vault
edition/tier pills stack on top of each other instead of sitting side
by side. Frees horizontal space in the row so the "Veeam Data Cloud
Vault" service name no longer wraps onto four lines.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(ui): zero-pad available services count in popup header
Pad svcCount to two digits so the popup header reads "01 / 05 Services"
instead of "1 / 05 Services", matching the existing zero-padded total.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(ui): extend east map bound so NZ popup fits on mobile
The east edge of maxBounds sat at +185°, only ~10° east of New Zealand
(174.76°). On mobile, after the user zoomed in to view NZ and tapped
the marker, autoPan couldn't move the map far enough right to fit the
popup card — the popup rendered half off-screen.
Extending the bound to +210° gives NZ the same ~34° of east margin
that Sydney (151°) already has. At zoom ≥3 the marker can now sit
centered with room for the popup to fit a 412px-wide mobile viewport.
Also exposes the map instance on window.__map purely for the new
regression test, which deterministically zooms to NZ and asserts the
popup's bounding box stays inside the viewport. The test would fail
against the previous +185 bound (verified: popup overflowed by 64px
at zoom 4 on Pixel 7).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(ui): escalate zoom on search-click so popup fits for edge regions
The search-click flow called clusterGroup.zoomToShowLayer + openPopup,
which for unclustered edge regions like New Zealand left the map at
the initial fitBounds zoom (~2). At that zoom level the popup card
geometrically cannot fit beside the marker for far-east regions — no
maxBounds extension can fix it, since the marker is forced 100+ px
right of viewport center.
When the post-cluster-zoom level is below 4, setView to the marker's
location at zoom 4 first, then open the popup on moveend. At zoom 4
the marker can sit centered (with the now-extended east bound) and a
~390 px popup fits inside a 412 px mobile viewport with comfortable
margin.
Honors prefers-reduced-motion (animate: !reducedMotion) to match the
existing map animation flags.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(ui): address code review findings on mission control redesign
- Derive HUD provider/service counts from the regions dataset and
serviceDisplayNames map so the strip stays honest if the data grows
(also fixes the hardcoded "05" in the popup provider strip).
- Bump 9px popup display text to 10px (region-id slug, pills, available
chip) and switch the region-id color from --text-dim to --text-mute
for AA contrast on the dim regionId slug.
- Remove three dead/empty CSS rules: .multiselect-btn placeholder,
#infoBtn placeholder, and the unused .service-icon-wrapper hover.
- Drop the unreachable provider-count fallback in updateRegionCount;
the single caller always passes both counts.
Follow-ups split into separate issues: #104 (test-only global),
#105 (popup escape helper), #106 (SVG defs IDs), #107 (mapError theme),
#108 (deterministic test waits), #109 (mid-range counter visibility).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* docs(llms): adopt official Veeam service names
Aligns static/llms.txt and static/llms-full.txt with the help-center
naming already shipped in the UI: Veeam Data Cloud Vault, Microsoft 365
Protection, Microsoft Entra ID Protection, Salesforce Protection,
Microsoft Azure Protection. Service IDs unchanged.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(ui): use defined --border token on marker dot
`--border-subtle` was never defined in `:root` or `html.light`, so the
fallback `#e2e8f0` applied in both themes and gave the marker dot a
visible light-slate ring in dark mode. Switch to `--border`, which is
defined in both themes.
Closes a code review comment on #103.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Deploying veeam-data-cloud-services-map with
|
| Latest commit: |
5ad26df
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://671ad260.veeam-data-cloud-services-map.pages.dev |
| Branch Preview URL: | https://release-1-4-0.veeam-data-cloud-services-map.pages.dev |
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.
Release v1.4.0
Merging release branch to main for version 1.4.0 — Mission Control redesign.
Changes
.ctlcontrol primitive, restyled legend, new typography + theme token system (feat(ui): mission control redesign #103)fitBounds; tiles wrap on wide viewports (feat(ui): mission control redesign #103)aria-labelreplacing nativetitle=(feat(ui): mission control redesign #103)defsscoping; live region count for AT (feat(ui): mission control redesign #103)Version
Testing
pr-validation.yml: Hugo build + Playwright UI on Chromium / Firefox / WebKit / Mobile Chrome / Mobile Safari)