fix(street-level): point a key-gated layer at Street View; button beside the hint

Review of #966: with a Google Maps key but no Mapillary token, switching
Street Level on read KEY REQUIRED / "Needs MAPILLARY_CLIENT_TOKEN" with
nothing about Street View, which stayed off (billing), so the layer looked
broken.

- While the switched-on providers lack their keys, the layer reports the
  switched-off ones that would draw with a key already set
  (keyAlternatives: Street View on Google 3D with a Google key). The
  panel's KEY REQUIRED tooltip, its coverage line and the layer row's
  tooltip then read "Needs MAPILLARY_CLIENT_TOKEN — add it in Provider
  Settings, or light STREET VIEW to use your Google Maps key"
  (keySetupWithAlternatives). Off Google 3D the plain KEY REQUIRED stays.
  Street View stays off by default.
- OPEN STREET VIEW moves beside the coverage hint: at the default panel
  width the PROVIDERS row has no room for it, so it wrapped onto a line of
  its own.
- The panel gate's corner drag names what lay under the pointer when it
  fails.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
Said TurkseverandClaude Opus 5.5 committed 2026-10-09 00:05:58 +01:00
1 parent f5c4f3fda3
commit e823e15025
15 files changed
+669 -138

No files matched your search

+24
View File
@@ -352,6 +352,30 @@ export function keySetupRequirement(id) {
return `Needs ${entry.envVars.join(' + ')} — add it in Provider Settings`;
}
/**
* Key guidance that also names the switched-off sources the layer could use
* with a key that is already set: `[{label, requiresKeyId}]`, e.g. Street
* View beside a Mapillary layer with no token.
* @param {string} requirement What `keySetupRequirement` said ('' allowed).
* @param {Array<{label: string, requiresKeyId?: string|null}>} [alternatives]
*/
export function keySetupWithAlternatives(requirement, alternatives = []) {
const options = alternatives.map(({ label, requiresKeyId }) => {
const entry = KEY_SETUP_KEYS.find(
(candidate) => candidate.id === requiresKeyId,
);
const name = entry
? entry.title
.toLowerCase()
.replace(/\b\w/g, (letter) => letter.toUpperCase())
: null;
return name ? `light ${label} to use your ${name} key` : `light ${label}`;
});
if (!options.length) return requirement;
const offer = `or ${options.join(', or ')}`;
return requirement ? `${requirement}, ${offer}` : offer.replace(/^or l/, 'L');
}
/**
* Decide whether a live provider value belongs to a source outside the store
* Provider Settings is allowed to edit. `wasExternalAtBoot` carries source