Gospel Resources: Show all drops only the table filter's own keys, keeping the tab, a partner's keys, the hash and the history state
This commit is contained in:
parent
789d90eb2f
commit
b843fcade1
5 changed files with 71 additions and 1 deletions
|
|
@ -37,6 +37,7 @@ const STATIC = [
|
|||
['check:click-sheet', 'the country sheet resolves, links are absolute'],
|
||||
['check:snapshot-guard', 'no fetcher writes around the guard'],
|
||||
['check:gospel-tables-staged', 'every asset the map fetches is in the shipped tree'],
|
||||
['check:gospel-clear-filter-url', 'Show all drops only the filter keys, not a partner\'s'],
|
||||
]
|
||||
const BROWSER = [
|
||||
['check:leaves-mount', 'all five leaves actually mount'],
|
||||
|
|
|
|||
|
|
@ -116,6 +116,7 @@
|
|||
"check:gospel-all": "node internal/check-gospel-all.mjs",
|
||||
"check:gospel-internet": "node plugin-designs/gospel-internet/scripts/check-gospel-internet-model.mjs && node plugin-designs/gospel-internet/scripts/check-gospel-internet-i18n.mjs && node plugin-designs/gospel-internet/scripts/check-language-tree.mjs && node plugin-designs/gospel-internet/scripts/check-gospel-internet-render.mjs",
|
||||
"check:gospel-tables-staged": "node internal/check-gospel-tables-staged.mjs",
|
||||
"check:gospel-clear-filter-url": "node plugin-designs/gospel-resources/scripts/check-clear-filter-url.mjs && node plugin-designs/gospel-resources/scripts/check-clear-filter-url.mjs --poison",
|
||||
"check:gospel-whiteboard": "node internal/check-gospel-whiteboard.mjs",
|
||||
"check:hardcoded-english": "node internal/check-hardcoded-english.mjs",
|
||||
"check:hardcoded-english:self-test": "node internal/check-hardcoded-english.mjs --self-test",
|
||||
|
|
@ -529,6 +530,7 @@
|
|||
"check:gallery-embed:live-cors": "the Research Gallery on a foreign page under the LIVE static layer's CORS rule (Access-Control-Allow-Origin on files inside the tree's folders, NOT on the root manifest.json, measured on the live test host): it must still boot every tab, by reading the CORS-readable manifest copy generate-tree writes beside its bundle.",
|
||||
"check:gated-not-in-tree": "a GATED profile (the build config's gatedProfiles, today key-cities) never reaches the public tree: no public/<tree>/<name>/ folder, no manifest.json entry, no page referencing <name>/<name>.js. vite.config.js builds a gated bundle into .gated/<tree>/ (ignored by git). Data tables are out of scope on purpose: key-cities.json also feeds the production Cities with Internet map. Two-sided: three planted leaks in a temporary tree, each caught. Node only.",
|
||||
"check:gospel-all": "EVERYTHING gospel-resources owns, in one command. Its ten gates were all hand-run, which is how a dead bundle shipped: a duplicate module killed all five leaves and the one gate run that day was pointed at the map. check:no-orphan-gates was right that they were reachable — reachable is not run. Deliberately NOT in gates:pre/post: three need a browser, the shared wave holds browser gates under load, and a bundle owner should not be able to slow everyone else's build by adding to a list they do not own. Static gates run first and stop the run on failure, so a scarce browser slot is never spent confirming a table is inconsistent. Exit 75 = NOT MEASURED, never folded into a pass.",
|
||||
"check:gospel-clear-filter-url": "the gospel tables' Show all drops ONLY its own filter keys (iso, country, label, province): the page's ?tab=, a host's or partner's keys, the #hash and the history state stay. It used to replaceState the bare pathname, wiping a partner's query. Proves the pure helper (filter-url.js) and that data-tables.vue calls it; --poison runs the old wipe and must fail.",
|
||||
"check:gospel-internet": "the Gospel x Internet board, headless, against the REAL table and the REAL kit bus: the join table is what its builder makes from main (2,107 / 2,107, province placement agreeing with gospel-by-province), every facet count equals the rows the bus then keeps (the five-numbers-agree invariant), D1 OR-within-key, the country->province cascade, the 369 zero-access headline by band 220/45/45/59, URL state round-trip, CSV header-first/provenance-last with injection neutralised, no engagement column; then every catalogue key the bundle names exists in all 11 locales and is translated. Each half has a --poison arm that must fail. Plugin-local because check:i18n-keys-exist cannot see a useOptionalT-based alias.",
|
||||
"check:gospel-whiteboard": "the gospel set charts' geometry once drawn on a map: the bounded set's gap survives projection, the drawing stays inside the Mercator clamp, and three more properties, each with the arm that would catch its own defect. By the gospel owner. Headless.",
|
||||
"check:hardcoded-english": "English a reader sees that no locale can reach: template text, static title=, script-block sentences, template literals, and quoted literals inside BOUND attributes, across the production plugins. Quiet on translator calls (including discovered aliases and proxy-t misses), te()-guarded fallbacks, css, urls and developer error text. Deliberately NOT in gates:post yet: it reports 179 today (gospel-resources 148, my-upg-100-list 25, cities-internet 6 incl. one cross-area key), with English inside dir=ltr islands listed as deliberate and not counted; it joins when that reaches 0 or every hit is carded. The :self-test (28 assertions, fixtures validated first so a malformed sample cannot pass as silence) runs in gates:pre.",
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import { EN_MESSAGES } from '@map/i18n/index.js'
|
|||
import DataTable from '@map/components/tables/DataTable.vue'
|
||||
import { useShadowStyles } from '@map/composables/useShadowStyles.js'
|
||||
import { resolveAssetsBase } from '@map/utils/embedBase.js'
|
||||
import { withoutKeys, FILTER_KEYS } from './filter-url.js'
|
||||
|
||||
|
||||
const profileConfig = inject('profileConfig', ref(null))
|
||||
|
|
@ -148,9 +149,11 @@ const fLabel = ref((params.get('label') || '').trim())
|
|||
const fProvince = ref((params.get('province') || '').trim())
|
||||
const fold = (v) => String(v || '').normalize('NFD').replace(/[\u0300-\u036f]/g, '').toLowerCase().trim()
|
||||
const hasFilter = computed(() => !!(fIso.value || fCountry.value || fProvince.value))
|
||||
// "Show all" drops only the filter's own keys (filter-url.js): the tab, a host's or partner's keys,
|
||||
// the hash and the history state stay as they were.
|
||||
function clearFilter() {
|
||||
fIso.value = ''; fCountry.value = ''; fLabel.value = ''; fProvince.value = ''
|
||||
try { window.history.replaceState({}, '', window.location.pathname) } catch (_) {}
|
||||
try { window.history.replaceState(window.history.state, '', withoutKeys(window.location.href, FILTER_KEYS)) } catch (_) {}
|
||||
}
|
||||
|
||||
const active = ref(TABS.some((t) => t.id === params.get('tab')) ? params.get('tab') : 'links')
|
||||
|
|
|
|||
16
plugin-designs/gospel-resources/filter-url.js
Normal file
16
plugin-designs/gospel-resources/filter-url.js
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
/**
|
||||
* filter-url.js — the address after this page drops its OWN filter keys.
|
||||
*
|
||||
* The tables page reads a deep-link filter from the query (?iso= / ?country= / ?label= / ?province=).
|
||||
* "Show all" must remove exactly those keys: the page's ?tab=, any key a host or a partner put on the
|
||||
* address, and the #hash are someone else's and stay as they were. Pure (no DOM), so a node check can
|
||||
* prove it without a browser.
|
||||
*/
|
||||
export const FILTER_KEYS = ['iso', 'country', 'label', 'province']
|
||||
|
||||
/** `href` without `keys`, as pathname + search + hash (what history.replaceState takes). */
|
||||
export function withoutKeys(href, keys = FILTER_KEYS) {
|
||||
const u = new URL(href)
|
||||
for (const k of keys) u.searchParams.delete(k)
|
||||
return u.pathname + u.search + u.hash
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
#!/usr/bin/env node
|
||||
/**
|
||||
* check-clear-filter-url.mjs — "Show all" on the gospel tables drops ONLY the filter's own keys.
|
||||
*
|
||||
* WHY: clearFilter used to replaceState({}, '', pathname), which wiped the whole query and the hash —
|
||||
* the page's own ?tab=, and any key a host or a partner had put on the address — and the history
|
||||
* state with them. The address after "Show all" must differ from the one before by the filter keys
|
||||
* alone.
|
||||
*
|
||||
* Proves it two ways: the pure helper (filter-url.js) on real-shaped addresses, and the component —
|
||||
* data-tables.vue's clearFilter calls that helper and keeps history.state, and the old wipe is gone.
|
||||
* `--poison` runs the old behaviour through the same assertions and requires them to FAIL.
|
||||
* Exit 0 pass · 1 fail.
|
||||
*/
|
||||
import { readFileSync } from 'node:fs'
|
||||
import { resolve, dirname } from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { withoutKeys, FILTER_KEYS } from '../filter-url.js'
|
||||
|
||||
const HERE = dirname(fileURLToPath(import.meta.url))
|
||||
const POISON = process.argv.includes('--poison')
|
||||
const strip = POISON ? (href) => new URL(href).pathname : (href) => withoutKeys(href, FILTER_KEYS)
|
||||
|
||||
let fails = 0
|
||||
const ok = (c, m) => { if (c) console.log('ok ' + m); else { fails++; console.log('FAIL ' + m) } }
|
||||
const base = 'https://example.org/dx-maps/gospel-resources/data-tables/index.html'
|
||||
|
||||
const a = strip(`${base}?tab=links&iso=hin&country=IND&label=Hindi&province=Bihar&partner=abc#tables`)
|
||||
ok(!/[?&](iso|country|label|province)=/.test(a), `the filter keys are gone (${a})`)
|
||||
ok(/[?&]tab=links\b/.test(a), 'the page\'s own ?tab= stays')
|
||||
ok(/[?&]partner=abc\b/.test(a), 'a host\'s or partner\'s key stays')
|
||||
ok(a.endsWith('#tables'), 'the #hash stays')
|
||||
const b = strip(`${base}?iso=hin`)
|
||||
ok(b === new URL(base).pathname, `only filter keys: no dangling "?" (${b})`)
|
||||
const c = strip(`${base}?tab=countries`)
|
||||
ok(c === new URL(base).pathname + '?tab=countries', 'no filter: the address is unchanged')
|
||||
|
||||
if (!POISON) {
|
||||
const vue = readFileSync(resolve(HERE, '../data-tables.vue'), 'utf8')
|
||||
const fn = (vue.match(/function clearFilter\(\)\s*\{[\s\S]*?\n\}/) || [''])[0]
|
||||
ok(/withoutKeys\(window\.location\.href,\s*FILTER_KEYS\)/.test(fn), 'data-tables.vue clearFilter uses the helper')
|
||||
ok(/replaceState\(window\.history\.state,/.test(fn), 'and keeps history.state')
|
||||
ok(!/replaceState\(\{\},\s*'',\s*window\.location\.pathname\)/.test(vue), 'the old whole-address wipe is gone')
|
||||
}
|
||||
|
||||
if (POISON) { console.log(fails ? `POISON OK: ${fails} caught` : 'POISON FAILED'); process.exit(fails ? 0 : 1) }
|
||||
console.log(fails ? `FAIL check-clear-filter-url: ${fails}` : 'PASS check-clear-filter-url')
|
||||
process.exit(fails ? 1 : 0)
|
||||
Loading…
Reference in a new issue