From 9dad9cbfc2f6f4a10d05235785fca2033b74bb3a Mon Sep 17 00:00:00 2001 From: Evan Rusackas Date: Thu, 14 May 2026 18:27:48 -0700 Subject: [PATCH] feat(glyph): consolidate plugin-chart-word-cloud to defineChart() Collapse the multi-file plugin/ subdirectory (buildQuery, controlPanel, transformProps, index) into a single top-level src/index.tsx using defineChart(). The chart/WordCloud.tsx component stays as a sibling. - Move plugin/controls/ up to src/controls/ so the new index.tsx can import the local RotationControl and ColorSchemeControl directly. - Delete src/index.ts barrel (the new index.tsx is the entrypoint and re-exports from ./types). - WordCloudChartPlugin is exported both as default and named, matching the previous public API. Co-Authored-By: Claude Sonnet 4.6 --- .../controls/ColorSchemeControl.tsx | 0 .../ColorSchemeControl/ColorSchemeLabel.tsx | 0 .../controls/ColorSchemeControl/index.tsx | 0 .../{plugin => }/controls/RotationControl.tsx | 0 .../src/{plugin => }/controls/index.ts | 0 .../plugin-chart-word-cloud/src/index.ts | 21 -- .../plugin-chart-word-cloud/src/index.tsx | 241 ++++++++++++++++++ .../src/plugin/buildQuery.ts | 43 ---- .../src/plugin/controlPanel.tsx | 111 -------- .../src/plugin/index.ts | 59 ----- .../src/plugin/transformProps.ts | 85 ------ 11 files changed, 241 insertions(+), 319 deletions(-) rename superset-frontend/plugins/plugin-chart-word-cloud/src/{plugin => }/controls/ColorSchemeControl.tsx (100%) rename superset-frontend/plugins/plugin-chart-word-cloud/src/{plugin => }/controls/ColorSchemeControl/ColorSchemeLabel.tsx (100%) rename superset-frontend/plugins/plugin-chart-word-cloud/src/{plugin => }/controls/ColorSchemeControl/index.tsx (100%) rename superset-frontend/plugins/plugin-chart-word-cloud/src/{plugin => }/controls/RotationControl.tsx (100%) rename superset-frontend/plugins/plugin-chart-word-cloud/src/{plugin => }/controls/index.ts (100%) delete mode 100644 superset-frontend/plugins/plugin-chart-word-cloud/src/index.ts create mode 100644 superset-frontend/plugins/plugin-chart-word-cloud/src/index.tsx delete mode 100644 superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/buildQuery.ts delete mode 100644 superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/controlPanel.tsx delete mode 100644 superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/index.ts delete mode 100644 superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/transformProps.ts diff --git a/superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/controls/ColorSchemeControl.tsx b/superset-frontend/plugins/plugin-chart-word-cloud/src/controls/ColorSchemeControl.tsx similarity index 100% rename from superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/controls/ColorSchemeControl.tsx rename to superset-frontend/plugins/plugin-chart-word-cloud/src/controls/ColorSchemeControl.tsx diff --git a/superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/controls/ColorSchemeControl/ColorSchemeLabel.tsx b/superset-frontend/plugins/plugin-chart-word-cloud/src/controls/ColorSchemeControl/ColorSchemeLabel.tsx similarity index 100% rename from superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/controls/ColorSchemeControl/ColorSchemeLabel.tsx rename to superset-frontend/plugins/plugin-chart-word-cloud/src/controls/ColorSchemeControl/ColorSchemeLabel.tsx diff --git a/superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/controls/ColorSchemeControl/index.tsx b/superset-frontend/plugins/plugin-chart-word-cloud/src/controls/ColorSchemeControl/index.tsx similarity index 100% rename from superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/controls/ColorSchemeControl/index.tsx rename to superset-frontend/plugins/plugin-chart-word-cloud/src/controls/ColorSchemeControl/index.tsx diff --git a/superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/controls/RotationControl.tsx b/superset-frontend/plugins/plugin-chart-word-cloud/src/controls/RotationControl.tsx similarity index 100% rename from superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/controls/RotationControl.tsx rename to superset-frontend/plugins/plugin-chart-word-cloud/src/controls/RotationControl.tsx diff --git a/superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/controls/index.ts b/superset-frontend/plugins/plugin-chart-word-cloud/src/controls/index.ts similarity index 100% rename from superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/controls/index.ts rename to superset-frontend/plugins/plugin-chart-word-cloud/src/controls/index.ts diff --git a/superset-frontend/plugins/plugin-chart-word-cloud/src/index.ts b/superset-frontend/plugins/plugin-chart-word-cloud/src/index.ts deleted file mode 100644 index 87bc4ff60b0..00000000000 --- a/superset-frontend/plugins/plugin-chart-word-cloud/src/index.ts +++ /dev/null @@ -1,21 +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. - */ - -export { default as WordCloudChartPlugin } from './plugin'; -export * from './types'; diff --git a/superset-frontend/plugins/plugin-chart-word-cloud/src/index.tsx b/superset-frontend/plugins/plugin-chart-word-cloud/src/index.tsx new file mode 100644 index 00000000000..7bdebafa70c --- /dev/null +++ b/superset-frontend/plugins/plugin-chart-word-cloud/src/index.tsx @@ -0,0 +1,241 @@ +/** + * 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 { + buildQueryContext, + ChartProps, + getColumnLabel, + QueryFormOrderBy, + validateNonEmpty, +} from '@superset-ui/core'; +import { getStandardizedControls } from '@superset-ui/chart-controls'; +import { defineChart } from '@superset-ui/glyph-core'; +import WordCloud, { + WordCloudEncoding, + WordCloudProps, +} from './chart/WordCloud'; +import { WordCloudFormData } from './types'; +import { RotationControl, ColorSchemeControl } from './controls'; +import thumbnail from './images/thumbnail.png'; +import thumbnailDark from './images/thumbnail-dark.png'; +import example1 from './images/Word_Cloud.jpg'; +import example1Dark from './images/Word_Cloud-dark.jpg'; +import example2 from './images/Word_Cloud_2.jpg'; +import example2Dark from './images/Word_Cloud_2-dark.jpg'; + +export * from './types'; + +// ─── buildQuery ────────────────────────────────────────────────────────────── + +function buildQuery(formData: WordCloudFormData) { + const { metric, sort_by_metric, sort_by_series, series, row_limit } = + formData; + const orderby: QueryFormOrderBy[] = []; + const shouldApplyOrderBy = + row_limit !== undefined && row_limit !== null && row_limit !== 0; + + if (sort_by_metric && metric) { + orderby.push([metric, false]); + } + if (sort_by_series !== false && series) { + orderby.push([series, true]); + } + + return buildQueryContext(formData, baseQueryObject => [ + { + ...baseQueryObject, + ...(shouldApplyOrderBy && orderby.length > 0 && { orderby }), + }, + ]); +} + +// ─── transformProps ────────────────────────────────────────────────────────── + +function getMetricLabel( + metric: WordCloudFormData['metric'], +): string | undefined { + if (typeof metric === 'string' || typeof metric === 'undefined') { + return metric; + } + if (Array.isArray(metric)) { + return metric.length > 0 ? getMetricLabel(metric[0]) : undefined; + } + return metric.label; +} + +function transformProps(chartProps: ChartProps): WordCloudProps { + const { width, height, formData, queriesData } = chartProps; + const { + colorScheme, + metric, + rotation, + series, + sizeFrom = 0, + sizeTo, + sliceId, + } = formData as WordCloudFormData; + + const metricLabel = getMetricLabel(metric); + const seriesLabel = getColumnLabel(series); + + const encoding: Partial = { + color: { + field: seriesLabel, + scale: { scheme: colorScheme }, + type: 'nominal', + }, + fontSize: + typeof metricLabel === 'undefined' + ? undefined + : { + field: metricLabel, + scale: { range: [sizeFrom, sizeTo], zero: true }, + type: 'quantitative', + }, + text: { field: seriesLabel }, + }; + + return { + data: queriesData[0].data, + encoding, + height, + rotation, + width, + sliceId, + colorScheme, + }; +} + +// ─── Plugin definition ─────────────────────────────────────────────────────── + +const WordCloudChartPlugin = defineChart, WordCloudProps>( + { + metadata: { + name: t('Word Cloud'), + description: t( + 'Visualizes the words in a column that appear the most often. Bigger font corresponds to higher frequency.', + ), + category: t('Ranking'), + credits: ['https://github.com/jasondavies/d3-cloud'], + tags: [ + t('Categorical'), + t('Comparison'), + t('Density'), + t('Single Metric'), + ], + thumbnail, + thumbnailDark, + exampleGallery: [ + { url: example1, urlDark: example1Dark }, + { url: example2, urlDark: example2Dark }, + ], + }, + arguments: {}, + suppressQuerySection: true, + prependSections: [ + { + label: t('Query'), + expanded: true, + controlSetRows: [ + ['series'], + ['metric'], + ['adhoc_filters'], + ['row_limit'], + ['sort_by_metric'], + [ + { + name: 'sort_by_series', + config: { + type: 'CheckboxControl', + label: t('Sort by series'), + default: true, + description: t( + 'Sort results by series name in ascending order. ' + + 'When combined with "Sort by metric", this acts as a tiebreaker ' + + 'for equal metric values. Adding this sort may reduce query ' + + 'performance on some databases.', + ), + }, + }, + ], + ], + }, + { + label: t('Options'), + expanded: true, + controlSetRows: [ + [ + { + name: 'size_from', + config: { + type: 'TextControl', + isInt: true, + label: t('Minimum Font Size'), + renderTrigger: true, + default: 10, + description: t('Font size for the smallest value in the list'), + }, + }, + { + name: 'size_to', + config: { + type: 'TextControl', + isInt: true, + label: t('Maximum Font Size'), + renderTrigger: true, + default: 70, + description: t('Font size for the biggest value in the list'), + }, + }, + ], + [], + [ + , + ], + ], + }, + ], + additionalControlOverrides: { + series: { + validators: [validateNonEmpty], + clearable: false, + }, + row_limit: { + default: 100, + }, + }, + formDataOverrides: formData => ({ + ...formData, + series: getStandardizedControls().shiftColumn(), + metric: getStandardizedControls().shiftMetric(), + }), + transform: chartProps => transformProps(chartProps as ChartProps), + buildQuery: (formData: WordCloudFormData) => buildQuery(formData), + render: ({ transformedProps }) => ( + + ), + }, +); + +export { WordCloudChartPlugin }; +export default WordCloudChartPlugin; diff --git a/superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/buildQuery.ts b/superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/buildQuery.ts deleted file mode 100644 index 7d4a31412fc..00000000000 --- a/superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/buildQuery.ts +++ /dev/null @@ -1,43 +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, QueryFormOrderBy } from '@superset-ui/core'; -import { WordCloudFormData } from '../types'; - -export default function buildQuery(formData: WordCloudFormData) { - const { metric, sort_by_metric, sort_by_series, series, row_limit } = - formData; - const orderby: QueryFormOrderBy[] = []; - const shouldApplyOrderBy = - row_limit !== undefined && row_limit !== null && row_limit !== 0; - - if (sort_by_metric && metric) { - orderby.push([metric, false]); - } - if (sort_by_series !== false && series) { - orderby.push([series, true]); - } - - return buildQueryContext(formData, baseQueryObject => [ - { - ...baseQueryObject, - ...(shouldApplyOrderBy && orderby.length > 0 && { orderby }), - }, - ]); -} diff --git a/superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/controlPanel.tsx b/superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/controlPanel.tsx deleted file mode 100644 index 1cf42d21117..00000000000 --- a/superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/controlPanel.tsx +++ /dev/null @@ -1,111 +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 { validateNonEmpty } from '@superset-ui/core'; -import { - ControlPanelConfig, - getStandardizedControls, -} from '@superset-ui/chart-controls'; -import { RotationControl, ColorSchemeControl } from './controls'; - -const config: ControlPanelConfig = { - controlPanelSections: [ - { - label: t('Query'), - expanded: true, - controlSetRows: [ - ['series'], - ['metric'], - ['adhoc_filters'], - ['row_limit'], - ['sort_by_metric'], - [ - { - name: 'sort_by_series', - config: { - type: 'CheckboxControl', - label: t('Sort by series'), - default: true, - description: t( - 'Sort results by series name in ascending order. ' + - 'When combined with "Sort by metric", this acts as a tiebreaker ' + - 'for equal metric values. Adding this sort may reduce query ' + - 'performance on some databases.', - ), - }, - }, - ], - ], - }, - { - label: t('Options'), - expanded: true, - controlSetRows: [ - [ - { - name: 'size_from', - config: { - type: 'TextControl', - isInt: true, - label: t('Minimum Font Size'), - renderTrigger: true, - default: 10, - description: t('Font size for the smallest value in the list'), - }, - }, - { - name: 'size_to', - config: { - type: 'TextControl', - isInt: true, - label: t('Maximum Font Size'), - renderTrigger: true, - default: 70, - description: t('Font size for the biggest value in the list'), - }, - }, - ], - [], - [ - , - ], - ], - }, - ], - controlOverrides: { - series: { - validators: [validateNonEmpty], - clearable: false, - }, - row_limit: { - default: 100, - }, - }, - formDataOverrides: formData => ({ - ...formData, - series: getStandardizedControls().shiftColumn(), - metric: getStandardizedControls().shiftMetric(), - }), -}; - -export default config; diff --git a/superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/index.ts b/superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/index.ts deleted file mode 100644 index e1977db2a8f..00000000000 --- a/superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/index.ts +++ /dev/null @@ -1,59 +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 } from '@superset-ui/core'; -import transformProps from './transformProps'; -import buildQuery from './buildQuery'; -import { WordCloudFormData } from '../types'; -import thumbnail from '../images/thumbnail.png'; -import thumbnailDark from '../images/thumbnail-dark.png'; -import example1 from '../images/Word_Cloud.jpg'; -import example1Dark from '../images/Word_Cloud-dark.jpg'; -import example2 from '../images/Word_Cloud_2.jpg'; -import example2Dark from '../images/Word_Cloud_2-dark.jpg'; -import controlPanel from './controlPanel'; - -const metadata = new ChartMetadata({ - category: t('Ranking'), - credits: ['https://github.com/jasondavies/d3-cloud'], - description: t( - 'Visualizes the words in a column that appear the most often. Bigger font corresponds to higher frequency.', - ), - exampleGallery: [ - { url: example1, urlDark: example1Dark }, - { url: example2, urlDark: example2Dark }, - ], - name: t('Word Cloud'), - tags: [t('Categorical'), t('Comparison'), t('Density'), t('Single Metric')], - thumbnail, - thumbnailDark, -}); - -export default class WordCloudChartPlugin extends ChartPlugin { - constructor() { - super({ - buildQuery, - loadChart: () => import('../chart/WordCloud'), - metadata, - transformProps, - controlPanel, - }); - } -} diff --git a/superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/transformProps.ts b/superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/transformProps.ts deleted file mode 100644 index a7fdcdde6f5..00000000000 --- a/superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/transformProps.ts +++ /dev/null @@ -1,85 +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 { WordCloudProps, WordCloudEncoding } from '../chart/WordCloud'; -import { WordCloudFormData } from '../types'; - -function getMetricLabel( - metric: WordCloudFormData['metric'], -): string | undefined { - if (typeof metric === 'string' || typeof metric === 'undefined') { - return metric; - } - if (Array.isArray(metric)) { - return metric.length > 0 ? getMetricLabel(metric[0]) : undefined; - } - - return metric.label; -} - -export default function transformProps(chartProps: ChartProps): WordCloudProps { - const { width, height, formData, queriesData } = chartProps; - const { - colorScheme, - metric, - rotation, - series, - sizeFrom = 0, - sizeTo, - sliceId, - } = formData as WordCloudFormData; - - const metricLabel = getMetricLabel(metric); - const seriesLabel = getColumnLabel(series); - - const encoding: Partial = { - color: { - field: seriesLabel, - scale: { - scheme: colorScheme, - }, - type: 'nominal', - }, - fontSize: - typeof metricLabel === 'undefined' - ? undefined - : { - field: metricLabel, - scale: { - range: [sizeFrom, sizeTo], - zero: true, - }, - type: 'quantitative', - }, - text: { - field: seriesLabel, - }, - }; - - return { - data: queriesData[0].data, - encoding, - height, - rotation, - width, - sliceId, - colorScheme, - }; -}