mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-14 15:22:21 +00:00
Put news on the globe, with a feed panel in the right rail
Events ▸ News draws the last 24 hours of reports from curated hotspots (Ukraine–Russia, Israel–Gaza–Lebanon, Iran–Hormuz, Yemen–Red Sea, Sudan, Sahel) and developing situations elsewhere, from any server that answers the `/api/news` read routes. - Globe: one marker per merged event, clamped to the ground and culled at the horizon; one beacon per hotspot when zoomed out and a pulsing beacon for a developing situation; hotspot outlines with disputed areas dotted and labelled by who administers and who claims them; picture cards for at most ten major or fast-growing events with two or more sources, never overlapping, switchable off. - Panel: hotspot chips, a severity filter (significant and above by default), categories, minor news off by default, and a scrolling list of event cards with picture, headline, place, sources, age and the sides that reported it. "In view" lists what is near the map below 3,000 km once the camera settles. A card flies the globe to its event and opens it with a link to the publisher. Reduced motion stops the pulse and the flights. - Core serves no news itself: the local server proxies GEV_NEWS_ORIGIN when it is set, and answers 503 unavailable otherwise, so the layer reads "not configured" once instead of retrying. - Share token 9 (enabled-only); voice stays off for this layer.
This commit is contained in:
1 parent
2d9d518946
commit
5bb489d1fb
48 files changed
+3394
-53
No files matched your search
@@ -128,7 +128,7 @@ test('reservation ledger is complete, pinned, and rejects duplicate or malformed
|
||||
{ ...parseLayerStateTokenReservations(reservationRows) },
|
||||
{ ...LAYER_STATE_TOKEN_RESERVATIONS },
|
||||
);
|
||||
assert.equal(Object.keys(LAYER_STATE_TOKEN_RESERVATIONS).length, 35);
|
||||
assert.equal(Object.keys(LAYER_STATE_TOKEN_RESERVATIONS).length, 36);
|
||||
assert.deepEqual(
|
||||
{ ...LAYER_STATE_TOKEN_RESERVATIONS },
|
||||
{
|
||||
@@ -140,6 +140,7 @@ test('reservation ledger is complete, pinned, and rejects duplicate or malformed
|
||||
'sea-marks': '6',
|
||||
'ski-pistes': '7',
|
||||
'drone-airspace': '8',
|
||||
news: '9',
|
||||
},
|
||||
);
|
||||
assert.throws(
|
||||
@@ -165,9 +166,9 @@ test('reservation ledger is complete, pinned, and rejects duplicate or malformed
|
||||
/Duplicate layer-state token reservation/,
|
||||
);
|
||||
assert.equal(
|
||||
parseLayerStateTokenReservations([...reservationRows, ['future', '9']])
|
||||
parseLayerStateTokenReservations([...reservationRows, ['future', '00']])
|
||||
.future,
|
||||
'9',
|
||||
'00',
|
||||
);
|
||||
assert.throws(
|
||||
() =>
|
||||
@@ -185,14 +186,14 @@ test('reservation ledger is complete, pinned, and rejects duplicate or malformed
|
||||
|
||||
test('published retired digits and competing PRs advance the merge-time allocation', () => {
|
||||
withPublishedBase(
|
||||
{ rows: [...reservationRows, ['retired-layer', '9']] },
|
||||
{ rows: [...reservationRows, ['retired-layer', '00']] },
|
||||
(cwd) => {
|
||||
const published = readPublishedLayerStateReservations('HEAD', cwd);
|
||||
assert.equal(nextLayerStateToken(published), '00');
|
||||
assert.equal(nextLayerStateToken(published), '01');
|
||||
assert.equal(
|
||||
validateLayerStateAllocations(published, {
|
||||
...published,
|
||||
newcomer: '00',
|
||||
newcomer: '01',
|
||||
}),
|
||||
true,
|
||||
);
|
||||
@@ -200,15 +201,15 @@ test('published retired digits and competing PRs advance the merge-time allocati
|
||||
() =>
|
||||
validateLayerStateAllocations(published, {
|
||||
...published,
|
||||
competing: '9',
|
||||
competing: '00',
|
||||
}),
|
||||
/next free token 00/,
|
||||
/next free token 01/,
|
||||
);
|
||||
assert.throws(
|
||||
() =>
|
||||
validateLayerStateAllocations(published, {
|
||||
...LAYER_STATE_TOKEN_RESERVATIONS,
|
||||
newcomer: '9',
|
||||
newcomer: '00',
|
||||
}),
|
||||
/changed or removed: retired-layer/,
|
||||
);
|
||||
@@ -216,8 +217,8 @@ test('published retired digits and competing PRs advance the merge-time allocati
|
||||
);
|
||||
});
|
||||
|
||||
test('PR B manually replaces provisional 9 with 00 after PR A publishes 9', () => {
|
||||
withPublishedBase({ rows: [...reservationRows, ['pr-a', '9']] }, (cwd) => {
|
||||
test('PR B manually replaces provisional 00 with 01 after PR A publishes 00', () => {
|
||||
withPublishedBase({ rows: [...reservationRows, ['pr-a', '00']] }, (cwd) => {
|
||||
mkdirSync(path.join(cwd, 'scripts'));
|
||||
const fixtureChecker = path.join(
|
||||
cwd,
|
||||
@@ -238,8 +239,8 @@ test('PR B manually replaces provisional 9 with 00 after PR A publishes 9', () =
|
||||
|
||||
writeCodecFixture(
|
||||
cwd,
|
||||
[...reservationRows, ['pr-b', '9']],
|
||||
[{ id: 'pr-b', token: '9' }],
|
||||
[...reservationRows, ['pr-b', '00']],
|
||||
[{ id: 'pr-b', token: '00' }],
|
||||
);
|
||||
const beforeRebase = runCheck();
|
||||
assert.equal(beforeRebase.status, 1);
|
||||
@@ -247,10 +248,10 @@ test('PR B manually replaces provisional 9 with 00 after PR A publishes 9', () =
|
||||
|
||||
writeCodecFixture(
|
||||
cwd,
|
||||
[...reservationRows, ['pr-a', '9'], ['pr-b', '9']],
|
||||
[...reservationRows, ['pr-a', '00'], ['pr-b', '00']],
|
||||
[
|
||||
{ id: 'pr-a', token: '9' },
|
||||
{ id: 'pr-b', token: '9' },
|
||||
{ id: 'pr-a', token: '00' },
|
||||
{ id: 'pr-b', token: '00' },
|
||||
],
|
||||
);
|
||||
const staleRebase = runCheck();
|
||||
@@ -258,16 +259,16 @@ test('PR B manually replaces provisional 9 with 00 after PR A publishes 9', () =
|
||||
assert.match(staleRebase.stderr, /Duplicate layer-state token reservation/);
|
||||
|
||||
const published = readPublishedLayerStateReservations('HEAD', cwd);
|
||||
assert.equal(nextLayerStateToken(published), '00');
|
||||
const validBaselineRows = [...reservationRows, ['pr-a', '9']];
|
||||
writeCodecFixture(cwd, validBaselineRows, [{ id: 'pr-a', token: '9' }]);
|
||||
assert.equal(nextLayerStateToken(published), '01');
|
||||
const validBaselineRows = [...reservationRows, ['pr-a', '00']];
|
||||
writeCodecFixture(cwd, validBaselineRows, [{ id: 'pr-a', token: '00' }]);
|
||||
const helper = spawnSync(
|
||||
process.execPath,
|
||||
[realpathSync(fixtureNext), 'pr-b'],
|
||||
{ cwd, encoding: 'utf8' },
|
||||
);
|
||||
assert.equal(helper.status, 0, helper.stderr);
|
||||
assert.match(helper.stdout, /pr-b: 00/);
|
||||
assert.match(helper.stdout, /pr-b: 01/);
|
||||
assert.deepEqual(
|
||||
JSON.parse(readFileSync(path.join(cwd, LEDGER_PATH), 'utf8')),
|
||||
validBaselineRows,
|
||||
@@ -275,26 +276,27 @@ test('PR B manually replaces provisional 9 with 00 after PR A publishes 9', () =
|
||||
);
|
||||
writeCodecFixture(
|
||||
cwd,
|
||||
[...reservationRows, ['pr-a', '9'], ['pr-b', '00']],
|
||||
[...reservationRows, ['pr-a', '00'], ['pr-b', '01']],
|
||||
[
|
||||
{ id: 'pr-a', token: '9' },
|
||||
{ id: 'pr-b', token: '00' },
|
||||
{ id: 'pr-a', token: '00' },
|
||||
{ id: 'pr-b', token: '01' },
|
||||
],
|
||||
);
|
||||
const corrected = runCheck();
|
||||
assert.equal(corrected.status, 0, corrected.stderr);
|
||||
assert.match(corrected.stdout, /36 published, 1 new/);
|
||||
assert.match(corrected.stdout, /37 published, 1 new/);
|
||||
});
|
||||
});
|
||||
|
||||
test('allocation batches cross the last digit and base-36 pair boundaries in order', () => {
|
||||
const digitRows = [...'9'].map((digit) => [`retired-${digit}`, digit]);
|
||||
// News holds the last digit, 9: the ledger has no free digit left.
|
||||
const digitRows = [];
|
||||
const allDigits = parseLayerStateTokenReservations([
|
||||
...reservationRows,
|
||||
...digitRows,
|
||||
]);
|
||||
const beforeNine = { ...allDigits };
|
||||
delete beforeNine['retired-9'];
|
||||
delete beforeNine.news;
|
||||
assert.equal(
|
||||
validateLayerStateAllocations(beforeNine, {
|
||||
...beforeNine,
|
||||
@@ -340,10 +342,8 @@ test('allocation batches cross the last digit and base-36 pair boundaries in ord
|
||||
test('an isolated valid two-character fixture round-trips an l field beyond the old 64-character cap', async () => {
|
||||
const cwd = mkdtempSync(path.join(tmpdir(), 'gev-layer-token-width-'));
|
||||
try {
|
||||
const priorDigits = [...'9'].map((digit) => [
|
||||
`qa-prior-digit-${digit}`,
|
||||
digit,
|
||||
]);
|
||||
// News holds the last digit: no prior digit to fill.
|
||||
const priorDigits = [];
|
||||
const fixtureLayers = ['00', '01', '02', '03'].map((token) => ({
|
||||
id: `qa-layer-${token}`,
|
||||
token,
|
||||
@@ -377,7 +377,7 @@ test('an isolated valid two-character fixture round-trips an l field beyond the
|
||||
const params = new URLSearchParams([['v', '2']]);
|
||||
codec.encodeLayerStateParams(params, state);
|
||||
assert.ok(params.get('l').length > 64, 'fixture must cross the old cap');
|
||||
assert.equal(params.get('l').length, 81);
|
||||
assert.equal(params.get('l').length, 83);
|
||||
const restored = codec.decodeLayerStateParams(params);
|
||||
assert.deepEqual(restored?.enabledLayerIds, expectedLayerIds);
|
||||
assert.deepEqual(restored?.options, state.options);
|
||||
@@ -395,7 +395,7 @@ test('checker reads a complete future base ledger and rejects retired-token reus
|
||||
},
|
||||
(cwd) => {
|
||||
const published = readPublishedLayerStateReservations('HEAD', cwd);
|
||||
assert.equal(Object.keys(published).length, 36);
|
||||
assert.equal(Object.keys(published).length, 37);
|
||||
assert.equal(published['retired-layer'], '00');
|
||||
assert.throws(
|
||||
() =>
|
||||
|
||||
Reference in new issue
Block a user