refactor(street-level): one provider, no orbit overview, no prewarm, simpler tile choice

The layer now owns its Mapillary parts directly: the provider registry,
pick router, multi-provider UI summary, params codec helper and provider
context are gone. createStreetLevelLayer({ source }) builds coverage,
sequences, the nearest-image lookup and the MapillaryJS viewer itself; a
single providerOn switch keeps the share link's `mapillary` option (off
draws nothing), and getParams/setParams keep { mapillary, pano, sinceDays }.

No z0-5 overview points: above 60 km nothing is drawn and the panel says to
zoom in; the proxy now serves only coverage z11-14. Tiles come from the
visible ground within range of the camera, ranked from the ground under it
(no line-of-sight ranking or near-range padding). MapillaryJS loads on the
first photo; viewer prewarm is removed. Key status, a rejected key and a
rate limit share one `blocked` state on coverage.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
German KhokhlovandClaude Opus 5.5 committed 2026-10-07 22:19:24 +04:00
1 parent 0f41fb04cd
commit 37a96072fa
51 files changed
+1240 -2659

No files matched your search

-74
View File
@@ -1,74 +0,0 @@
import { COLORS } from './policy.js';
/**
* @typedef {object} ProviderSnapshot
* @property {string} id
* @property {string} name
* @property {string} label
* @property {boolean} on
* @property {boolean|null} configured null until the status call answers
* @property {boolean} keyRequired no usable key: missing or rejected
* @property {boolean} [keyRejected] the provider refused the configured key
* @property {string|null} requiresKeyId
* @property {boolean} loading
* @property {number} count
* @property {string} hint
* @property {string|null} error
* @property {string} color The source's one colour.
*/
/**
* Totals over switched-on providers. Key-gated only when every one lacks its
* key; `keyRejected` when that is because a key was refused.
* @param {Array<ProviderSnapshot>} providers
*/
export function summarizeCoverage(providers) {
const active = providers.filter((p) => p.on);
return {
count: active.reduce((sum, p) => sum + (p.count || 0), 0),
loading: active.some((p) => p.loading),
hint: active.find((p) => p.hint)?.hint || '',
error: active.find((p) => p.error)?.error || null,
keyRequired:
active.length > 0 && active.every((p) => p.keyRequired === true),
keyRejected:
active.length > 0 &&
active.every((p) => p.keyRequired === true) &&
active.some((p) => p.keyRejected === true),
};
}
/**
* The panel snapshot from core state and provider snapshots. The legend has
* one swatch per active source, then the shared selection colour.
* @param {{enabled: boolean, filter: object, providers: Array<ProviderSnapshot>, street: object, sequence: object}} input
*/
export function composeUIState({
enabled,
filter,
providers,
street,
sequence,
}) {
const active = providers.filter((p) => p.on);
const { keyRequired, keyRejected, ...coverage } =
summarizeCoverage(providers);
const legend = active.map((provider) => ({
key: provider.id,
label: provider.name,
color: provider.color,
}));
if (active.length)
legend.push({ key: 'selected', label: 'Selected', color: COLORS.selected });
return {
enabled,
keyRequired,
keyRejected,
filter: { ...filter },
providers: providers.map((p) => ({ ...p })),
coverage,
legend,
sequence: { ...sequence },
street: { ...street },
};
}