feat(country-map): scaffold modern plugin shell

Bootstrap the new @superset-ui/plugin-chart-country-map package with
the modern ChartPlugin pattern. Mirrors plugin-chart-handlebars'
structure (the leanest existing modern plugin in the repo).

Files:
  package.json                     — workspace pkg with d3-* deps
  tsconfig.json                    — extends frontend root tsconfig,
                                     references core/chart-controls
  types/external.d.ts              — ambient types for png/jpg/geojson
  README.md                        — what this plugin is + status
  src/
    index.ts                       — package entry
    types.ts                       — CountryMapFormData + transform props
    CountryMap.tsx                 — placeholder renderer (real D3 port
                                     in a follow-up commit)
    plugin/
      index.ts                     — ChartPlugin class with metadata
      buildQuery.ts                — modern chart/data query (this is
                                     the core difference from the legacy
                                     plugin's explore_json path)
      controlPanel.tsx             — minimal placeholder; full control
                                     set (worldview / admin level /
                                     country / region include-exclude /
                                     fly-islands / language) ports next
      transformProps.ts            — derives geoJsonUrl from form_data
                                     using the build-script's output
                                     naming convention

Renderer scaffold fetches the resolved GeoJSON URL and shows a small
diagnostic block (URL + feature count + data row count + metric name)
so the plugin compiles end-to-end and can be wired to the chart-type
registry without a real D3 render. Real renderer + controls land in
the next commits.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Evan Rusackas
2026-05-12 16:44:43 -07:00
parent d7edbf747a
commit 07532ae1a7
11 changed files with 609 additions and 0 deletions

View File

@@ -0,0 +1,72 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import {
CountryMapChartProps,
CountryMapTransformedProps,
} from '../types';
/**
* Translate Superset's standard ChartProps into the shape the renderer
* needs. Notable: derive `geoJsonUrl` from the form data so the renderer
* can fetch the right output from the build pipeline.
*
* URL layout (matches the build script's output naming):
* <worldview>_admin0.geo.json — world choropleth
* <worldview>_admin1_<adm0_a3>.geo.json — country subdivisions
* regional_<adm0_a3>_<set>_<worldview>.geo.json — aggregated regions
* composite_<id>_<worldview>.geo.json — composite maps
*
* The actual hosting path is wired up in a follow-up commit; for now
* the renderer prefixes URLs with a stubbed base.
*/
const GEOJSON_BASE = '/static/assets/country-maps';
export default function transformProps(
chartProps: CountryMapChartProps,
): CountryMapTransformedProps {
const { formData, queriesData, width, height } = chartProps;
const data = (queriesData?.[0]?.data as Record<string, unknown>[]) ?? [];
const worldview = formData.worldview || 'ukr';
const adminLevel = formData.admin_level ?? 0;
let geoJsonUrl: string | null = null;
if (formData.composite) {
geoJsonUrl = `${GEOJSON_BASE}/composite_${formData.composite}_${worldview}.geo.json`;
} else if (formData.region_set && formData.country) {
geoJsonUrl =
`${GEOJSON_BASE}/regional_${formData.country}_${formData.region_set}_${worldview}.geo.json`;
} else if (adminLevel === 1 && formData.country) {
geoJsonUrl =
`${GEOJSON_BASE}/${worldview}_admin1_${formData.country}.geo.json`;
} else if (adminLevel === 0) {
geoJsonUrl = `${GEOJSON_BASE}/${worldview}_admin0.geo.json`;
}
return {
width,
height,
formData,
data,
geoJsonUrl,
metricName: typeof formData.metric === 'string' ? formData.metric : null,
numberFormat: formData.number_format,
linearColorScheme: formData.linear_color_scheme,
};
}