mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-05 10:53:59 +00:00
Merge origin/main: keep the provider registry, slim it
main grew the Street Level provider registry while this branch removed it (#982–#985: injected providers, an empty composition, the `r` switch field). The registry, params, uiState and pick router come back as main has them and the slimmed layer sits behind the provider contract: - The core (index.js) drives providers as on main, without surface modes, ground casting, FOLLOW, prewarm and nearest-image lookups. A provider's key status is asked with a 10 s timeout and asked again on a switch-on while no key is known. - Mapillary is mapillaryProvider.js over the slim coverage, sequences and viewer modules, which read the filter and the active flag from the provider context. - The viewer host mounts one provider adapter at a time, no prewarm. - The panel has a chip per provider again (the pill switches the layer); no legend, EXPAND stays the Fullscreen API. - The contract drops what no provider implements: groundCaster, meshSampler, getSurface/setSurface, nearestImage, prewarm, reportError, the legend and surface fields of the UI snapshot. Co-Authored-By: Claude Fable 5.1 <[email protected]>
This commit is contained in:
commit
c29ccd55d6
103 files changed
+5469
-522
No files matched your search
@@ -0,0 +1,100 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import test from 'node:test';
|
||||
import { composeUIState, summarizeCoverage } from './uiState.js';
|
||||
import { providerSnapshot } from '../../testSupport/streetLevelFakes.mjs';
|
||||
|
||||
const provider = (overrides = {}) =>
|
||||
providerSnapshot({ count: 10, ...overrides });
|
||||
const base = {
|
||||
enabled: true,
|
||||
filter: { pano: 'all', sinceDays: 0 },
|
||||
street: { open: false },
|
||||
sequence: { selectedId: null, images: 0, loading: false },
|
||||
};
|
||||
|
||||
test('counts add up across active providers only', () => {
|
||||
const ui = composeUIState({
|
||||
...base,
|
||||
providers: [
|
||||
provider(),
|
||||
provider({ id: 'panoramax', name: 'Panoramax', count: 5, on: false }),
|
||||
provider({ id: 'kartaview', name: 'KartaView', count: 7, loading: true }),
|
||||
],
|
||||
});
|
||||
assert.equal(ui.coverage.count, 17);
|
||||
assert.equal(ui.coverage.loading, true);
|
||||
});
|
||||
|
||||
test('the layer is key-gated only when every switched-on provider lacks its key', () => {
|
||||
const gated = composeUIState({
|
||||
...base,
|
||||
providers: [provider({ keyRequired: true })],
|
||||
});
|
||||
assert.equal(gated.keyRequired, true);
|
||||
const mixed = composeUIState({
|
||||
...base,
|
||||
providers: [
|
||||
provider({ keyRequired: true }),
|
||||
provider({ id: 'panoramax', name: 'Panoramax', requiresKeyId: null }),
|
||||
],
|
||||
});
|
||||
assert.equal(mixed.keyRequired, false, 'a keyless provider still draws');
|
||||
const offOnly = composeUIState({
|
||||
...base,
|
||||
providers: [provider({ keyRequired: true, on: false })],
|
||||
});
|
||||
assert.equal(offOnly.keyRequired, false, 'nothing switched on to gate');
|
||||
});
|
||||
|
||||
test('hint and error come from the first active provider that has one', () => {
|
||||
const ui = composeUIState({
|
||||
...base,
|
||||
providers: [
|
||||
provider({ hint: '', error: null }),
|
||||
provider({ id: 'b', name: 'B', hint: 'Look down', error: 'boom' }),
|
||||
],
|
||||
});
|
||||
assert.equal(ui.coverage.hint, 'Look down');
|
||||
assert.equal(ui.coverage.error, 'boom');
|
||||
assert.deepEqual(ui.filter, base.filter);
|
||||
assert.notEqual(ui.filter, base.filter, 'snapshot copies the filter');
|
||||
});
|
||||
|
||||
test('summarizeCoverage is what getStats reports, without building a snapshot', () => {
|
||||
assert.deepEqual(
|
||||
summarizeCoverage([
|
||||
provider({ count: 4, hint: 'Look down' }),
|
||||
provider({ id: 'b', name: 'B', count: 6, loading: true, error: 'boom' }),
|
||||
provider({ id: 'c', name: 'C', count: 99, on: false, keyRequired: true }),
|
||||
]),
|
||||
{
|
||||
count: 10,
|
||||
loading: true,
|
||||
hint: 'Look down',
|
||||
error: 'boom',
|
||||
keyRequired: false,
|
||||
keyRejected: false,
|
||||
},
|
||||
);
|
||||
assert.equal(summarizeCoverage([]).keyRequired, false);
|
||||
});
|
||||
|
||||
test('a rejected key gates like a missing one and is named as rejected', () => {
|
||||
const rejected = provider({
|
||||
keyRequired: true,
|
||||
keyRejected: true,
|
||||
error: 'Mapillary rejected MAPILLARY_CLIENT_TOKEN',
|
||||
});
|
||||
const summary = summarizeCoverage([rejected]);
|
||||
assert.equal(summary.keyRequired, true);
|
||||
assert.equal(summary.keyRejected, true);
|
||||
assert.equal(summary.error, 'Mapillary rejected MAPILLARY_CLIENT_TOKEN');
|
||||
const state = composeUIState({ ...base, providers: [rejected] });
|
||||
assert.equal(state.keyRequired, true);
|
||||
assert.equal(state.keyRejected, true);
|
||||
// A provider that is merely missing its key is not "rejected".
|
||||
assert.equal(
|
||||
summarizeCoverage([provider({ keyRequired: true })]).keyRejected,
|
||||
false,
|
||||
);
|
||||
});
|
||||
Reference in new issue
Block a user