This is an automated email from the ASF dual-hosted git repository. rusackas pushed a commit to branch feat/glyph-single-file in repository https://gitbox.apache.org/repos/asf/superset.git
commit 865b75c90e1cbe9766abb489c6e1af8b8ff9b3c9 Author: Evan Rusackas <[email protected]> AuthorDate: Thu May 14 18:46:02 2026 -0700 feat(glyph): consolidate deckgl Geojson layer to defineChart() Collapse multi-file plugin (buildQuery, controlPanel, transformProps, index) into single index.tsx. The Geojson.tsx component stays as sibling. Largest deckgl controlPanel so far due to extensive label / icon / JavaScript config controls. Co-Authored-By: Claude Sonnet 4.6 <[email protected]> --- .../src/layers/Geojson/buildQuery.ts | 86 ------------ .../src/layers/Geojson/index.ts | 51 ------- .../layers/Geojson/{controlPanel.ts => index.tsx} | 151 +++++++++++++++++++-- .../src/layers/Geojson/transformProps.ts | 50 ------- 4 files changed, 143 insertions(+), 195 deletions(-) diff --git a/superset-frontend/plugins/preset-chart-deckgl/src/layers/Geojson/buildQuery.ts b/superset-frontend/plugins/preset-chart-deckgl/src/layers/Geojson/buildQuery.ts deleted file mode 100644 index 67b5ddd2327..00000000000 --- a/superset-frontend/plugins/preset-chart-deckgl/src/layers/Geojson/buildQuery.ts +++ /dev/null @@ -1,86 +0,0 @@ -/** - * 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 { - buildQueryContext, - ensureIsArray, - QueryFormColumn, - QueryObject, - QueryObjectFilterClause, - SqlaFormData, -} from '@superset-ui/core'; -import { - addJsColumnsToColumns, - addTooltipColumnsToQuery, -} from '../buildQueryUtils'; - -export interface DeckGeoJsonFormData extends SqlaFormData { - geojson?: string; - filter_nulls?: boolean; - js_columns?: string[]; - tooltip_contents?: unknown[]; -} - -export default function buildQuery(formData: DeckGeoJsonFormData) { - const { - geojson, - filter_nulls = true, - js_columns, - tooltip_contents, - } = formData; - - if (!geojson) { - throw new Error('GeoJSON column is required for GeoJSON charts'); - } - - return buildQueryContext(formData, (baseQueryObject: QueryObject) => { - let columns: QueryFormColumn[] = [ - ...ensureIsArray(baseQueryObject.columns || []), - geojson, - ]; - - // Add js_columns - const columnStrings = columns.map(col => - typeof col === 'string' ? col : col.label || col.sqlExpression || '', - ); - const withJsColumns = addJsColumnsToColumns(columnStrings, js_columns); - columns = withJsColumns as QueryFormColumn[]; - - // Add tooltip columns - columns = addTooltipColumnsToQuery(columns, tooltip_contents); - - // Add null filter for geojson column - const filters: QueryObjectFilterClause[] = ensureIsArray( - baseQueryObject.filters || [], - ); - if (filter_nulls) { - filters.push({ col: geojson, op: 'IS NOT NULL' }); - } - - return [ - { - ...baseQueryObject, - columns, - metrics: [], - groupby: [], - filters, - is_timeseries: false, - }, - ]; - }); -} diff --git a/superset-frontend/plugins/preset-chart-deckgl/src/layers/Geojson/index.ts b/superset-frontend/plugins/preset-chart-deckgl/src/layers/Geojson/index.ts deleted file mode 100644 index 618beff2b46..00000000000 --- a/superset-frontend/plugins/preset-chart-deckgl/src/layers/Geojson/index.ts +++ /dev/null @@ -1,51 +0,0 @@ -/** - * 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 { t } from '@apache-superset/core/translation'; -import { ChartMetadata, ChartPlugin, Behavior } from '@superset-ui/core'; -import thumbnail from './images/thumbnail.png'; -import thumbnailDark from './images/thumbnail-dark.png'; -import example from './images/example.png'; -import exampleDark from './images/example-dark.png'; -import controlPanel from './controlPanel'; - -const metadata = new ChartMetadata({ - category: t('Map'), - credits: ['https://uber.github.io/deck.gl'], - description: t( - 'The GeoJsonLayer takes in GeoJSON formatted data and renders it as interactive polygons, lines and points (circles, icons and/or texts).', - ), - exampleGallery: [{ url: example, urlDark: exampleDark }], - name: t('deck.gl Geojson'), - thumbnail, - thumbnailDark, - tags: [t('deckGL'), t('2D')], - behaviors: [Behavior.InteractiveChart], -}); - -export default class GeojsonChartPlugin extends ChartPlugin { - constructor() { - super({ - loadChart: () => import('./Geojson'), - loadTransformProps: () => import('./transformProps'), - loadBuildQuery: () => import('./buildQuery'), - controlPanel, - metadata, - }); - } -} diff --git a/superset-frontend/plugins/preset-chart-deckgl/src/layers/Geojson/controlPanel.ts b/superset-frontend/plugins/preset-chart-deckgl/src/layers/Geojson/index.tsx similarity index 71% rename from superset-frontend/plugins/preset-chart-deckgl/src/layers/Geojson/controlPanel.ts rename to superset-frontend/plugins/preset-chart-deckgl/src/layers/Geojson/index.tsx index 6326968bad9..af7710fa0ed 100644 --- a/superset-frontend/plugins/preset-chart-deckgl/src/layers/Geojson/controlPanel.ts +++ b/superset-frontend/plugins/preset-chart-deckgl/src/layers/Geojson/index.tsx @@ -16,13 +16,32 @@ * specific language governing permissions and limitations * under the License. */ -import { ControlPanelConfig } from '@superset-ui/chart-controls'; import { t } from '@apache-superset/core/translation'; import { - legacyValidateInteger, - isFeatureEnabled, + Behavior, + buildQueryContext, + ChartProps, + ensureIsArray, FeatureFlag, + getColumnLabel, + isFeatureEnabled, + legacyValidateInteger, + QueryFormColumn, + QueryObject, + QueryObjectFilterClause, + SqlaFormData, } from '@superset-ui/core'; +import { defineChart } from '@superset-ui/glyph-core'; +import GeojsonComponent from './Geojson'; +import { DataRecord } from '../spatialUtils'; +import { + createBaseTransformResult, + getRecordsFromQuery, +} from '../transformUtils'; +import { + addJsColumnsToColumns, + addTooltipColumnsToQuery, +} from '../buildQueryUtils'; import { formatSelectOptions } from '../../utilities/utils'; import { filterNulls, @@ -47,6 +66,99 @@ import { } from '../../utilities/Shared_DeckGL'; import { dndGeojsonColumn } from '../../utilities/sharedDndControls'; import { BLACK_COLOR } from '../../utilities/controls'; +import thumbnail from './images/thumbnail.png'; +import thumbnailDark from './images/thumbnail-dark.png'; +import example from './images/example.png'; +import exampleDark from './images/example-dark.png'; + +// ─── Types ─────────────────────────────────────────────────────────────────── + +export interface DeckGeoJsonFormData extends SqlaFormData { + geojson?: string; + filter_nulls?: boolean; + js_columns?: string[]; + tooltip_contents?: unknown[]; +} + +// ─── buildQuery ────────────────────────────────────────────────────────────── + +export function buildQuery(formData: DeckGeoJsonFormData) { + const { + geojson, + filter_nulls = true, + js_columns, + tooltip_contents, + } = formData; + + if (!geojson) { + throw new Error('GeoJSON column is required for GeoJSON charts'); + } + + return buildQueryContext(formData, (baseQueryObject: QueryObject) => { + let columns: QueryFormColumn[] = [ + ...ensureIsArray(baseQueryObject.columns || []), + geojson, + ]; + + const columnStrings = columns.map(col => + typeof col === 'string' ? col : col.label || col.sqlExpression || '', + ); + const withJsColumns = addJsColumnsToColumns(columnStrings, js_columns); + columns = withJsColumns as QueryFormColumn[]; + + columns = addTooltipColumnsToQuery(columns, tooltip_contents); + + const filters: QueryObjectFilterClause[] = ensureIsArray( + baseQueryObject.filters || [], + ); + if (filter_nulls) { + filters.push({ col: geojson, op: 'IS NOT NULL' }); + } + + return [ + { + ...baseQueryObject, + columns, + metrics: [], + groupby: [], + filters, + is_timeseries: false, + }, + ]; + }); +} + +// ─── transformProps ────────────────────────────────────────────────────────── + +function transformProps(chartProps: ChartProps) { + const { rawFormData: formData } = chartProps; + const geojsonCol = formData.geojson + ? getColumnLabel(formData.geojson) + : undefined; + + if (!geojsonCol) { + return createBaseTransformResult(chartProps, []); + } + + const records = getRecordsFromQuery(chartProps.queriesData); + + // Parse each record's geojson column value (replicates backend DeckGeoJson.get_properties) + const features = records + .map((record: DataRecord) => { + const geojsonStr = record[geojsonCol]; + if (geojsonStr == null) return null; + try { + return JSON.parse(String(geojsonStr)); + } catch { + return null; + } + }) + .filter(Boolean); + + return createBaseTransformResult(chartProps, features); +} + +// ─── Default control config templates ──────────────────────────────────────── const defaultLabelConfigGenerator = `() => ({ // Check the documentation at: @@ -65,8 +177,26 @@ const defaultIconConfigGenerator = `() => ({ iconSizeUnits: 'pixels', })`; -const config: ControlPanelConfig = { - controlPanelSections: [ +// ─── Plugin definition ─────────────────────────────────────────────────────── + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export default defineChart<Record<string, never>, any>({ + metadata: { + name: t('deck.gl Geojson'), + description: t( + 'The GeoJsonLayer takes in GeoJSON formatted data and renders it as interactive polygons, lines and points (circles, icons and/or texts).', + ), + category: t('Map'), + credits: ['https://uber.github.io/deck.gl'], + behaviors: [Behavior.InteractiveChart], + tags: [t('deckGL'), t('2D')], + thumbnail, + thumbnailDark, + exampleGallery: [{ url: example, urlDark: exampleDark }], + }, + arguments: {}, + suppressQuerySection: true, + prependSections: [ { label: t('Query'), expanded: true, @@ -374,6 +504,11 @@ const config: ControlPanelConfig = { ], }, ], -}; - -export default config; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + buildQuery: (formData: any) => buildQuery(formData as DeckGeoJsonFormData), + transform: chartProps => transformProps(chartProps), + render: ({ transformedProps }) => ( + // eslint-disable-next-line @typescript-eslint/no-explicit-any + <GeojsonComponent {...(transformedProps as any)} /> + ), +}); diff --git a/superset-frontend/plugins/preset-chart-deckgl/src/layers/Geojson/transformProps.ts b/superset-frontend/plugins/preset-chart-deckgl/src/layers/Geojson/transformProps.ts deleted file mode 100644 index 572df299ade..00000000000 --- a/superset-frontend/plugins/preset-chart-deckgl/src/layers/Geojson/transformProps.ts +++ /dev/null @@ -1,50 +0,0 @@ -/** - * 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 { ChartProps, getColumnLabel } from '@superset-ui/core'; -import { getRecordsFromQuery } from '../transformUtils'; -import { DataRecord } from '../spatialUtils'; -import { createBaseTransformResult } from '../transformUtils'; - -export default function transformProps(chartProps: ChartProps) { - const { rawFormData: formData } = chartProps; - const geojsonCol = formData.geojson - ? getColumnLabel(formData.geojson) - : undefined; - - if (!geojsonCol) { - return createBaseTransformResult(chartProps, []); - } - - const records = getRecordsFromQuery(chartProps.queriesData); - - // Parse each record's geojson column value (replicates backend DeckGeoJson.get_properties) - const features = records - .map((record: DataRecord) => { - const geojsonStr = record[geojsonCol]; - if (geojsonStr == null) return null; - try { - return JSON.parse(String(geojsonStr)); - } catch { - return null; - } - }) - .filter(Boolean); - - return createBaseTransformResult(chartProps, features); -}
