mirror of
https://github.com/apache/superset.git
synced 2026-05-29 11:45:16 +00:00
feat(country-map): manifest-driven control choices
Replace hardcoded WORLDVIEW / COUNTRY / REGION_SET / COMPOSITE choice
tables in controlPanel with options derived from the build pipeline's
manifest.json. Adding a new entry to a YAML config + re-running
./build.sh now populates the control automatically; no plugin code
change needed.
Build script: also writes manifest.json to the plugin's
src/data/manifest.json so controlPanel can `import` it synchronously
(no async fetch needed at chart-edit time). Data files (the actual
GeoJSONs) still live only at superset/static/assets/country-maps/ —
we don't want to bundle 17MB of choropleth data into the JS payload.
Lookup helpers preserve human-friendly labels:
- WORLDVIEW_LABELS — maps NE worldview codes (ukr, default, ind, ...)
to friendly names ("Ukraine (default — Crimea as Ukrainian)" etc.);
unmapped codes render as the raw code
- COUNTRY_LABELS — ISO_A3 → English country name (~85 entries);
formatCountry renders as "France (FRA)"; unmapped codes render raw
- REGION_SET_LABELS / COMPOSITE_LABELS — same pattern
Manifest's regional_aggregations array is grouped by country into
the {country: [(set_id, label), ...]} shape the control panel needs.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -871,6 +871,13 @@ def write_manifest(targets: list[tuple[str, int]]) -> Path:
|
||||
|
||||
manifest_path = OUTPUT_DIR / "manifest.json"
|
||||
manifest_path.write_text(json.dumps(manifest, indent=2))
|
||||
|
||||
# Also write a copy into the plugin source tree so the control
|
||||
# panel can `import manifest from '../data/manifest.json'` without
|
||||
# an async fetch at chart-edit time.
|
||||
plugin_data_dir = SCRIPT_DIR.parent / "src" / "data"
|
||||
plugin_data_dir.mkdir(parents=True, exist_ok=True)
|
||||
(plugin_data_dir / "manifest.json").write_text(json.dumps(manifest, indent=2))
|
||||
log(
|
||||
f"\nWrote manifest.json — {len(worldviews)} worldview(s), "
|
||||
f"{sum(len(v) for v in countries_by_wv.values())} country files, "
|
||||
|
||||
@@ -0,0 +1,263 @@
|
||||
{
|
||||
"ne_pinned_tag": "v5.1.2",
|
||||
"ne_pinned_sha": "f1890d9f152c896d250a77557a5751a93d494776",
|
||||
"build_timestamp_utc": "2026-05-13T00:31:41.547398+00:00",
|
||||
"worldviews": [
|
||||
"ukr"
|
||||
],
|
||||
"admin_levels": [
|
||||
0,
|
||||
1
|
||||
],
|
||||
"countries_by_worldview": {
|
||||
"ukr": [
|
||||
"AFG",
|
||||
"AGO",
|
||||
"AIA",
|
||||
"ALB",
|
||||
"ALD",
|
||||
"AND",
|
||||
"ARE",
|
||||
"ARG",
|
||||
"ARM",
|
||||
"ASM",
|
||||
"ATA",
|
||||
"ATF",
|
||||
"ATG",
|
||||
"AUS",
|
||||
"AUT",
|
||||
"AZE",
|
||||
"BDI",
|
||||
"BEL",
|
||||
"BEN",
|
||||
"BFA",
|
||||
"BGD",
|
||||
"BGR",
|
||||
"BHR",
|
||||
"BHS",
|
||||
"BIH",
|
||||
"BLR",
|
||||
"BLZ",
|
||||
"BMU",
|
||||
"BOL",
|
||||
"BRA",
|
||||
"BRB",
|
||||
"BRN",
|
||||
"BTN",
|
||||
"BWA",
|
||||
"CAF",
|
||||
"CAN",
|
||||
"CHE",
|
||||
"CHL",
|
||||
"CHN",
|
||||
"CIV",
|
||||
"CMR",
|
||||
"COD",
|
||||
"COG",
|
||||
"COK",
|
||||
"COL",
|
||||
"COM",
|
||||
"CPV",
|
||||
"CRI",
|
||||
"CUB",
|
||||
"CYP",
|
||||
"CZE",
|
||||
"DEU",
|
||||
"DJI",
|
||||
"DMA",
|
||||
"DNK",
|
||||
"DOM",
|
||||
"DZA",
|
||||
"ECU",
|
||||
"EGY",
|
||||
"ERI",
|
||||
"ESP",
|
||||
"EST",
|
||||
"ETH",
|
||||
"FIN",
|
||||
"FJI",
|
||||
"FRA",
|
||||
"FSM",
|
||||
"GAB",
|
||||
"GBR",
|
||||
"GEO",
|
||||
"GHA",
|
||||
"GIN",
|
||||
"GMB",
|
||||
"GNB",
|
||||
"GNQ",
|
||||
"GRC",
|
||||
"GRD",
|
||||
"GRL",
|
||||
"GTM",
|
||||
"GUY",
|
||||
"HKG",
|
||||
"HND",
|
||||
"HRV",
|
||||
"HTI",
|
||||
"HUN",
|
||||
"IDN",
|
||||
"IND",
|
||||
"IOA",
|
||||
"IRL",
|
||||
"IRN",
|
||||
"IRQ",
|
||||
"ISL",
|
||||
"ISR",
|
||||
"ITA",
|
||||
"JAM",
|
||||
"JOR",
|
||||
"JPN",
|
||||
"KAZ",
|
||||
"KEN",
|
||||
"KGZ",
|
||||
"KHM",
|
||||
"KIR",
|
||||
"KNA",
|
||||
"KOR",
|
||||
"KOS",
|
||||
"KWT",
|
||||
"LAO",
|
||||
"LBN",
|
||||
"LBR",
|
||||
"LBY",
|
||||
"LCA",
|
||||
"LIE",
|
||||
"LKA",
|
||||
"LSO",
|
||||
"LTU",
|
||||
"LUX",
|
||||
"LVA",
|
||||
"MAR",
|
||||
"MDA",
|
||||
"MDG",
|
||||
"MDV",
|
||||
"MEX",
|
||||
"MHL",
|
||||
"MKD",
|
||||
"MLI",
|
||||
"MLT",
|
||||
"MMR",
|
||||
"MNE",
|
||||
"MNG",
|
||||
"MNP",
|
||||
"MOZ",
|
||||
"MRT",
|
||||
"MSR",
|
||||
"MUS",
|
||||
"MWI",
|
||||
"MYS",
|
||||
"NAM",
|
||||
"NCL",
|
||||
"NER",
|
||||
"NGA",
|
||||
"NIC",
|
||||
"NLD",
|
||||
"NOR",
|
||||
"NPL",
|
||||
"NRU",
|
||||
"NZL",
|
||||
"OMN",
|
||||
"PAK",
|
||||
"PAN",
|
||||
"PER",
|
||||
"PHL",
|
||||
"PLW",
|
||||
"PNG",
|
||||
"POL",
|
||||
"PRK",
|
||||
"PRT",
|
||||
"PRY",
|
||||
"PSX",
|
||||
"PYF",
|
||||
"QAT",
|
||||
"ROU",
|
||||
"RUS",
|
||||
"RWA",
|
||||
"SAU",
|
||||
"SDN",
|
||||
"SDS",
|
||||
"SEN",
|
||||
"SGP",
|
||||
"SHN",
|
||||
"SLB",
|
||||
"SLE",
|
||||
"SLV",
|
||||
"SMR",
|
||||
"SOM",
|
||||
"SPM",
|
||||
"SRB",
|
||||
"STP",
|
||||
"SUR",
|
||||
"SVK",
|
||||
"SVN",
|
||||
"SWE",
|
||||
"SWZ",
|
||||
"SYC",
|
||||
"SYR",
|
||||
"TCA",
|
||||
"TCD",
|
||||
"TGO",
|
||||
"THA",
|
||||
"TJK",
|
||||
"TKM",
|
||||
"TLS",
|
||||
"TON",
|
||||
"TTO",
|
||||
"TUN",
|
||||
"TUR",
|
||||
"TWN",
|
||||
"TZA",
|
||||
"UGA",
|
||||
"UKR",
|
||||
"UMI",
|
||||
"URY",
|
||||
"USA",
|
||||
"UZB",
|
||||
"VCT",
|
||||
"VEN",
|
||||
"VIR",
|
||||
"VNM",
|
||||
"VUT",
|
||||
"WLF",
|
||||
"WSM",
|
||||
"YEM",
|
||||
"ZAF",
|
||||
"ZMB",
|
||||
"ZWE"
|
||||
]
|
||||
},
|
||||
"regional_aggregations": [
|
||||
{
|
||||
"country": "FRA",
|
||||
"set_id": "regions",
|
||||
"worldview": "ukr",
|
||||
"size_bytes": 32077
|
||||
},
|
||||
{
|
||||
"country": "ITA",
|
||||
"set_id": "regions",
|
||||
"worldview": "ukr",
|
||||
"size_bytes": 32116
|
||||
},
|
||||
{
|
||||
"country": "PHL",
|
||||
"set_id": "regions",
|
||||
"worldview": "ukr",
|
||||
"size_bytes": 31805
|
||||
},
|
||||
{
|
||||
"country": "TUR",
|
||||
"set_id": "nuts_1",
|
||||
"worldview": "ukr",
|
||||
"size_bytes": 23036
|
||||
}
|
||||
],
|
||||
"composites": [
|
||||
{
|
||||
"id": "france_overseas",
|
||||
"worldview": "ukr",
|
||||
"size_bytes": 322058
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -24,24 +24,54 @@ import {
|
||||
D3_FORMAT_OPTIONS,
|
||||
getStandardizedControls,
|
||||
} from '@superset-ui/chart-controls';
|
||||
import manifest from '../data/manifest.json';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Choice tables
|
||||
// Choice tables — sourced from the build pipeline's manifest.json
|
||||
//
|
||||
// These are hardcoded for the POC. A follow-up commit will replace them
|
||||
// with options pulled from the build pipeline's manifest.json so adding
|
||||
// a new worldview or country only requires a build script run, not a
|
||||
// plugin code change.
|
||||
// The manifest is regenerated by every `./scripts/build.sh` run; adding
|
||||
// a new worldview or country to the YAML configs and re-running build
|
||||
// makes the new option appear in the UI without touching this file.
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
const WORLDVIEW_CHOICES: Array<[string, string]> = [
|
||||
['ukr', t('Ukraine (default — Crimea as Ukrainian)')],
|
||||
['default', t('Natural Earth Default')],
|
||||
// Future: pull the rest from the build manifest. Available NE
|
||||
// worldviews include arg, bdg, bra, chn, deu, egy, esp, fra, gbr,
|
||||
// grc, idn, ind, isr, ita, jpn, kor, mar, nep, nld, pak, pol, prt,
|
||||
// pse, rus, sau, swe, tur, twn, ukr, usa, vnm.
|
||||
];
|
||||
interface CountryMapManifest {
|
||||
worldviews: string[];
|
||||
admin_levels: number[];
|
||||
countries_by_worldview: Record<string, string[]>;
|
||||
regional_aggregations: Array<{
|
||||
country: string;
|
||||
set_id: string;
|
||||
worldview: string;
|
||||
size_bytes: number;
|
||||
}>;
|
||||
composites: Array<{ id: string; worldview: string; size_bytes: number }>;
|
||||
}
|
||||
|
||||
const M = manifest as CountryMapManifest;
|
||||
|
||||
// Display-name labels for worldviews. Anything not listed here renders
|
||||
// as the worldview code itself in the dropdown.
|
||||
const WORLDVIEW_LABELS: Record<string, string> = {
|
||||
ukr: t('Ukraine (default — Crimea as Ukrainian)'),
|
||||
default: t('Natural Earth Default'),
|
||||
ind: t('India'),
|
||||
pak: t('Pakistan'),
|
||||
chn: t('China'),
|
||||
rus: t('Russia'),
|
||||
isr: t('Israel'),
|
||||
pse: t('Palestine'),
|
||||
tur: t('Türkiye'),
|
||||
jpn: t('Japan'),
|
||||
kor: t('Korea'),
|
||||
usa: t('United States'),
|
||||
fra: t('France'),
|
||||
gbr: t('United Kingdom'),
|
||||
};
|
||||
|
||||
const WORLDVIEW_CHOICES: Array<[string, string]> = M.worldviews.map(wv => [
|
||||
wv,
|
||||
WORLDVIEW_LABELS[wv] || wv,
|
||||
]);
|
||||
|
||||
const ADMIN_LEVEL_CHOICES: Array<[string, string]> = [
|
||||
[String(0), t('Countries (Admin 0)')],
|
||||
@@ -49,68 +79,150 @@ const ADMIN_LEVEL_CHOICES: Array<[string, string]> = [
|
||||
['aggregated', t('Aggregated regions')],
|
||||
];
|
||||
|
||||
// ISO_A3 country codes that have at least 2 subdivisions in NE Admin 1.
|
||||
// Hardcoded snapshot — should come from build manifest in follow-up.
|
||||
const COUNTRY_CHOICES: Array<[string, string]> = [
|
||||
['USA', t('United States')],
|
||||
['CAN', t('Canada')],
|
||||
['MEX', t('Mexico')],
|
||||
['BRA', t('Brazil')],
|
||||
['ARG', t('Argentina')],
|
||||
['GBR', t('United Kingdom')],
|
||||
['FRA', t('France')],
|
||||
['DEU', t('Germany')],
|
||||
['ITA', t('Italy')],
|
||||
['ESP', t('Spain')],
|
||||
['NLD', t('Netherlands')],
|
||||
['BEL', t('Belgium')],
|
||||
['CHE', t('Switzerland')],
|
||||
['AUT', t('Austria')],
|
||||
['POL', t('Poland')],
|
||||
['SWE', t('Sweden')],
|
||||
['NOR', t('Norway')],
|
||||
['FIN', t('Finland')],
|
||||
['DNK', t('Denmark')],
|
||||
['PRT', t('Portugal')],
|
||||
['GRC', t('Greece')],
|
||||
['TUR', t('Türkiye')],
|
||||
['UKR', t('Ukraine')],
|
||||
['RUS', t('Russia')],
|
||||
['CHN', t('China (incl. Taiwan / HK / Macau)')],
|
||||
['JPN', t('Japan')],
|
||||
['KOR', t('South Korea')],
|
||||
['IND', t('India')],
|
||||
['IDN', t('Indonesia')],
|
||||
['THA', t('Thailand')],
|
||||
['VNM', t('Vietnam')],
|
||||
['PHL', t('Philippines')],
|
||||
['MYS', t('Malaysia')],
|
||||
['AUS', t('Australia')],
|
||||
['NZL', t('New Zealand')],
|
||||
['ZAF', t('South Africa')],
|
||||
['EGY', t('Egypt')],
|
||||
['MAR', t('Morocco')],
|
||||
['NGA', t('Nigeria')],
|
||||
['KEN', t('Kenya')],
|
||||
['ETH', t('Ethiopia')],
|
||||
['LVA', t('Latvia')],
|
||||
];
|
||||
|
||||
// Maps a country to its available regional aggregation sets, sourced
|
||||
// from regional_aggregations.yaml. Hardcoded snapshot.
|
||||
const REGION_SET_CHOICES_BY_COUNTRY: Record<string, Array<[string, string]>> = {
|
||||
TUR: [['nuts_1', t('NUTS-1 statistical regions')]],
|
||||
FRA: [['regions', t('Administrative regions')]],
|
||||
ITA: [['regions', t('Administrative regions')]],
|
||||
PHL: [['regions', t('Administrative regions')]],
|
||||
// English country names by ISO_A3, for friendly dropdown labels. Codes
|
||||
// not listed here render as the raw ISO code (rare; missing entries
|
||||
// here aren't a correctness problem).
|
||||
const COUNTRY_LABELS: Record<string, string> = {
|
||||
AFG: 'Afghanistan',
|
||||
ARG: 'Argentina',
|
||||
AUS: 'Australia',
|
||||
AUT: 'Austria',
|
||||
BEL: 'Belgium',
|
||||
BGD: 'Bangladesh',
|
||||
BGR: 'Bulgaria',
|
||||
BIH: 'Bosnia and Herzegovina',
|
||||
BLR: 'Belarus',
|
||||
BOL: 'Bolivia',
|
||||
BRA: 'Brazil',
|
||||
CAN: 'Canada',
|
||||
CHE: 'Switzerland',
|
||||
CHL: 'Chile',
|
||||
CHN: 'China',
|
||||
COL: 'Colombia',
|
||||
CRI: 'Costa Rica',
|
||||
CUB: 'Cuba',
|
||||
CYP: 'Cyprus',
|
||||
CZE: 'Czechia',
|
||||
DEU: 'Germany',
|
||||
DNK: 'Denmark',
|
||||
DOM: 'Dominican Republic',
|
||||
ECU: 'Ecuador',
|
||||
EGY: 'Egypt',
|
||||
ESP: 'Spain',
|
||||
EST: 'Estonia',
|
||||
ETH: 'Ethiopia',
|
||||
FIN: 'Finland',
|
||||
FRA: 'France',
|
||||
GBR: 'United Kingdom',
|
||||
GHA: 'Ghana',
|
||||
GRC: 'Greece',
|
||||
GTM: 'Guatemala',
|
||||
HND: 'Honduras',
|
||||
HRV: 'Croatia',
|
||||
HUN: 'Hungary',
|
||||
IDN: 'Indonesia',
|
||||
IND: 'India',
|
||||
IRL: 'Ireland',
|
||||
IRN: 'Iran',
|
||||
IRQ: 'Iraq',
|
||||
ISL: 'Iceland',
|
||||
ISR: 'Israel',
|
||||
ITA: 'Italy',
|
||||
JPN: 'Japan',
|
||||
KAZ: 'Kazakhstan',
|
||||
KEN: 'Kenya',
|
||||
KGZ: 'Kyrgyzstan',
|
||||
KHM: 'Cambodia',
|
||||
KOR: 'South Korea',
|
||||
LAO: 'Laos',
|
||||
LBN: 'Lebanon',
|
||||
LTU: 'Lithuania',
|
||||
LVA: 'Latvia',
|
||||
MAR: 'Morocco',
|
||||
MEX: 'Mexico',
|
||||
MMR: 'Myanmar',
|
||||
MNG: 'Mongolia',
|
||||
MYS: 'Malaysia',
|
||||
NGA: 'Nigeria',
|
||||
NLD: 'Netherlands',
|
||||
NOR: 'Norway',
|
||||
NPL: 'Nepal',
|
||||
NZL: 'New Zealand',
|
||||
PAK: 'Pakistan',
|
||||
PER: 'Peru',
|
||||
PHL: 'Philippines',
|
||||
POL: 'Poland',
|
||||
PRT: 'Portugal',
|
||||
PRY: 'Paraguay',
|
||||
ROU: 'Romania',
|
||||
RUS: 'Russia',
|
||||
SAU: 'Saudi Arabia',
|
||||
SDN: 'Sudan',
|
||||
SRB: 'Serbia',
|
||||
SVK: 'Slovakia',
|
||||
SVN: 'Slovenia',
|
||||
SWE: 'Sweden',
|
||||
SYR: 'Syria',
|
||||
THA: 'Thailand',
|
||||
TUR: 'Türkiye',
|
||||
TWN: 'Taiwan',
|
||||
UKR: 'Ukraine',
|
||||
URY: 'Uruguay',
|
||||
USA: 'United States',
|
||||
UZB: 'Uzbekistan',
|
||||
VEN: 'Venezuela',
|
||||
VNM: 'Vietnam',
|
||||
YEM: 'Yemen',
|
||||
ZAF: 'South Africa',
|
||||
ZWE: 'Zimbabwe',
|
||||
};
|
||||
|
||||
// Composite maps from composite_maps.yaml. Each composite is an
|
||||
// alternative selection for a country (sits alongside the regular
|
||||
// country picker).
|
||||
const COMPOSITE_CHOICES: Array<[string, string]> = [
|
||||
['france_overseas', t('France (with overseas territories)')],
|
||||
];
|
||||
const formatCountry = (code: string): string =>
|
||||
COUNTRY_LABELS[code] ? `${COUNTRY_LABELS[code]} (${code})` : code;
|
||||
|
||||
// Build country choices from the union of all worldview manifests
|
||||
// (typically the same set since Admin 1 is one global file, but
|
||||
// future per-worldview Admin 1 outputs would naturally differ).
|
||||
const COUNTRY_CHOICES: Array<[string, string]> = (() => {
|
||||
const all = new Set<string>();
|
||||
Object.values(M.countries_by_worldview).forEach(codes =>
|
||||
codes.forEach(c => all.add(c)),
|
||||
);
|
||||
return Array.from(all)
|
||||
.sort()
|
||||
.map<[string, string]>(c => [c, formatCountry(c)]);
|
||||
})();
|
||||
|
||||
// Region-set labels keyed by `<set_id>` (TUR's `nuts_1` etc.).
|
||||
const REGION_SET_LABELS: Record<string, string> = {
|
||||
nuts_1: t('NUTS-1 statistical regions'),
|
||||
regions: t('Administrative regions'),
|
||||
};
|
||||
|
||||
// Build {country: [(set_id, label), ...]} from manifest.
|
||||
const REGION_SET_CHOICES_BY_COUNTRY: Record<string, Array<[string, string]>> = (
|
||||
() => {
|
||||
const out: Record<string, Array<[string, string]>> = {};
|
||||
M.regional_aggregations.forEach(r => {
|
||||
out[r.country] = out[r.country] || [];
|
||||
out[r.country].push([
|
||||
r.set_id,
|
||||
REGION_SET_LABELS[r.set_id] || r.set_id,
|
||||
]);
|
||||
});
|
||||
return out;
|
||||
}
|
||||
)();
|
||||
|
||||
// Composite-map labels keyed by `<id>`.
|
||||
const COMPOSITE_LABELS: Record<string, string> = {
|
||||
france_overseas: t('France (with overseas territories)'),
|
||||
};
|
||||
|
||||
const COMPOSITE_CHOICES: Array<[string, string]> = M.composites.map(c => [
|
||||
c.id,
|
||||
COMPOSITE_LABELS[c.id] || c.id,
|
||||
]);
|
||||
|
||||
// NE NAME_<lang> language codes available across most features.
|
||||
const NAME_LANGUAGE_CHOICES: Array<[string, string]> = [
|
||||
|
||||
Reference in New Issue
Block a user