From 124af4c566af8c13dd1ee029144dd9a77c40e851 Mon Sep 17 00:00:00 2001 From: Kamil Gabryjelski Date: Wed, 15 Dec 2021 10:15:14 +0100 Subject: [PATCH] chore(explore): Migrate BigNumber to v1 api [ID-28][ID-55] (#17587) * chore(explore): Migrate BigNumber to v1 api * Move to echarts * Use Echarts trendline * Fix imports * Fix parsing dates as strings * Add from_dttm and to_dttm to v1 chart response * Fix post processing * Fix timeRangeFixed * Fix tests * Remove from and to dttm from cache * Cleanup date formatting * Fix storybook * Fix missing types * Fix timestamp with timezone * Add types to demo's tsconfig * bug fix * fix import * Fix cypress tests * add sort * add resample to handle missing values properly * Sync ChartDataResponseResult schema with ts interface * Lint fix * Add migration * Fix migration * Remove pass * Re-raise the exception in migration * Typo fix * Update revision Co-authored-by: Ville Brofeldt --- .../explore/visualizations/big_number.test.js | 12 +- .../visualizations/big_number_total.test.js | 17 +- .../cypress-base/cypress/utils/vizPlugins.ts | 2 + superset-frontend/package-lock.json | 27 +- superset-frontend/package.json | 2 +- .../src/query/types/QueryResponse.ts | 4 +- .../packages/superset-ui-demo/package.json | 1 - .../BigNumber/BigNumberStories.tsx | 4 +- .../BigNumberTotal/BigNumberTotalStories.tsx | 2 +- .../ChartDataProviderStories.tsx | 4 +- .../packages/superset-ui-demo/tsconfig.json | 1 + .../legacy-preset-chart-big-number/README.md | 67 ----- .../package.json | 42 --- .../src/BigNumber/transformProps.ts | 187 ------------- .../test/tsconfig.json | 19 -- .../tsconfig.json | 25 -- .../BigNumber/BigNumberTotal/buildQuery.ts} | 8 +- .../BigNumber}/BigNumberTotal/controlPanel.ts | 47 ++-- .../BigNumberTotal/images/BigNumber.jpg | Bin .../BigNumberTotal/images/BigNumber2.jpg | Bin .../BigNumberTotal/images/thumbnail.png | Bin .../BigNumberTotal/images/thumbnailLarge.png | Bin .../src/BigNumber}/BigNumberTotal/index.ts | 15 +- .../BigNumberTotal/transformProps.ts | 76 ++++++ .../src/BigNumber/BigNumberViz.tsx} | 122 +-------- .../BigNumberWithTrendline/buildQuery.ts | 92 +++++++ .../BigNumberWithTrendline}/controlPanel.tsx | 45 ++-- .../images/Big_Number_Trendline.jpg | Bin .../images/thumbnail.png | Bin .../images/thumbnailLarge.png | Bin .../BigNumberWithTrendline}/index.ts | 20 +- .../BigNumberWithTrendline/transformProps.ts | 252 ++++++++++++++++++ .../src/BigNumber}/CHANGELOG.md | 0 .../src/BigNumber}/index.ts | 5 +- .../src/BigNumber}/sharedControls.ts | 2 +- .../src/BigNumber/types.ts | 57 ++++ .../src/BigNumber/utils.ts} | 39 ++- .../plugins/plugin-chart-echarts/src/index.ts | 1 + .../test/BigNumber}/transformProps.test.ts | 21 +- .../plugin-chart-table/test/testData.ts | 2 +- .../src/visualizations/presets/MainPreset.js | 6 +- superset/charts/schemas.py | 10 + superset/common/query_context_processor.py | 4 + ...1_rename_big_viz_total_form_data_fields.py | 100 +++++++ superset/models/helpers.py | 4 + 45 files changed, 763 insertions(+), 581 deletions(-) delete mode 100644 superset-frontend/plugins/legacy-preset-chart-big-number/README.md delete mode 100644 superset-frontend/plugins/legacy-preset-chart-big-number/package.json delete mode 100644 superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/transformProps.ts delete mode 100644 superset-frontend/plugins/legacy-preset-chart-big-number/test/tsconfig.json delete mode 100644 superset-frontend/plugins/legacy-preset-chart-big-number/tsconfig.json rename superset-frontend/plugins/{legacy-preset-chart-big-number/src/types/external.d.ts => plugin-chart-echarts/src/BigNumber/BigNumberTotal/buildQuery.ts} (79%) rename superset-frontend/plugins/{legacy-preset-chart-big-number/src => plugin-chart-echarts/src/BigNumber}/BigNumberTotal/controlPanel.ts (81%) rename superset-frontend/plugins/{legacy-preset-chart-big-number/src => plugin-chart-echarts/src/BigNumber}/BigNumberTotal/images/BigNumber.jpg (100%) rename superset-frontend/plugins/{legacy-preset-chart-big-number/src => plugin-chart-echarts/src/BigNumber}/BigNumberTotal/images/BigNumber2.jpg (100%) rename superset-frontend/plugins/{legacy-preset-chart-big-number/src => plugin-chart-echarts/src/BigNumber}/BigNumberTotal/images/thumbnail.png (100%) rename superset-frontend/plugins/{legacy-preset-chart-big-number/src => plugin-chart-echarts/src/BigNumber}/BigNumberTotal/images/thumbnailLarge.png (100%) rename superset-frontend/plugins/{legacy-preset-chart-big-number/src => plugin-chart-echarts/src/BigNumber}/BigNumberTotal/index.ts (86%) create mode 100644 superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/transformProps.ts rename superset-frontend/plugins/{legacy-preset-chart-big-number/src/BigNumber/BigNumber.tsx => plugin-chart-echarts/src/BigNumber/BigNumberViz.tsx} (73%) create mode 100644 superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/buildQuery.ts rename superset-frontend/plugins/{legacy-preset-chart-big-number/src/BigNumber => plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline}/controlPanel.tsx (91%) rename superset-frontend/plugins/{legacy-preset-chart-big-number/src/BigNumber => plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline}/images/Big_Number_Trendline.jpg (100%) rename superset-frontend/plugins/{legacy-preset-chart-big-number/src/BigNumber => plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline}/images/thumbnail.png (100%) rename superset-frontend/plugins/{legacy-preset-chart-big-number/src/BigNumber => plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline}/images/thumbnailLarge.png (100%) rename superset-frontend/plugins/{legacy-preset-chart-big-number/src/BigNumber => plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline}/index.ts (80%) create mode 100644 superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/transformProps.ts rename superset-frontend/plugins/{legacy-preset-chart-big-number => plugin-chart-echarts/src/BigNumber}/CHANGELOG.md (100%) rename superset-frontend/plugins/{legacy-preset-chart-big-number/src => plugin-chart-echarts/src/BigNumber}/index.ts (85%) rename superset-frontend/plugins/{legacy-preset-chart-big-number/src => plugin-chart-echarts/src/BigNumber}/sharedControls.ts (98%) create mode 100644 superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/types.ts rename superset-frontend/plugins/{legacy-preset-chart-big-number/src/preset.ts => plugin-chart-echarts/src/BigNumber/utils.ts} (52%) rename superset-frontend/plugins/{legacy-preset-chart-big-number/test => plugin-chart-echarts/test/BigNumber}/transformProps.test.ts (87%) create mode 100644 superset/migrations/versions/fe23025b9441_rename_big_viz_total_form_data_fields.py diff --git a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/big_number.test.js b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/big_number.test.js index 9e8ca246258f4..30e7716b730c2 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/big_number.test.js +++ b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/big_number.test.js @@ -16,6 +16,8 @@ * specific language governing permissions and limitations * under the License. */ +import { interceptChart } from 'cypress/utils'; + describe('Visualization > Big Number with Trendline', () => { const BIG_NUMBER_FORM_DATA = { datasource: '2__table', @@ -42,21 +44,21 @@ describe('Visualization > Big Number with Trendline', () => { function verify(formData) { cy.visitChartByParams(JSON.stringify(formData)); cy.verifySliceSuccess({ - waitAlias: '@getJson', + waitAlias: '@chartData', chartSelector: '.superset-legacy-chart-big-number', }); } beforeEach(() => { cy.login(); - cy.intercept('POST', '/superset/explore_json/**').as('getJson'); + interceptChart({ legacy: false }).as('chartData'); }); it('should work', () => { verify(BIG_NUMBER_FORM_DATA); cy.get('.chart-container .header-line'); cy.get('.chart-container .subheader-line'); - cy.get('.chart-container svg path.vx-linepath'); + cy.get('.chart-container canvas'); }); it('should work without subheader', () => { @@ -66,7 +68,7 @@ describe('Visualization > Big Number with Trendline', () => { }); cy.get('.chart-container .header-line'); cy.get('.chart-container .subheader-line').should('not.exist'); - cy.get('.chart-container svg path.vx-linepath'); + cy.get('.chart-container canvas'); }); it('should not render trendline when hidden', () => { @@ -76,6 +78,6 @@ describe('Visualization > Big Number with Trendline', () => { }); cy.get('[data-test="chart-container"] .header-line'); cy.get('[data-test="chart-container"] .subheader-line'); - cy.get('[data-test="chart-container"] svg').should('not.exist'); + cy.get('[data-test="chart-container"] canvas').should('not.exist'); }); }); diff --git a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/big_number_total.test.js b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/big_number_total.test.js index b6794c42b741b..e2fcc5a1a1e32 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/big_number_total.test.js +++ b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/big_number_total.test.js @@ -16,6 +16,7 @@ * specific language governing permissions and limitations * under the License. */ +import { interceptChart } from 'cypress/utils'; import { FORM_DATA_DEFAULTS, NUM_METRIC } from './shared.helper'; describe('Visualization > Big Number Total', () => { @@ -26,15 +27,15 @@ describe('Visualization > Big Number Total', () => { beforeEach(() => { cy.login(); - cy.intercept('POST', '/superset/explore_json/**').as('getJson'); + interceptChart({ legacy: false }).as('chartData'); }); it('Test big number chart with adhoc metric', () => { const formData = { ...BIG_NUMBER_DEFAULTS, metric: NUM_METRIC }; - cy.visitChartByParams(JSON.stringify(formData)); + cy.visitChartByParams(formData); cy.verifySliceSuccess({ - waitAlias: '@getJson', + waitAlias: '@chartData', querySubstring: NUM_METRIC.label, }); }); @@ -58,8 +59,8 @@ describe('Visualization > Big Number Total', () => { adhoc_filters: filters, }; - cy.visitChartByParams(JSON.stringify(formData)); - cy.verifySliceSuccess({ waitAlias: '@getJson' }); + cy.visitChartByParams(formData); + cy.verifySliceSuccess({ waitAlias: '@chartData' }); }); it('Test big number chart ignores groupby', () => { @@ -69,11 +70,11 @@ describe('Visualization > Big Number Total', () => { groupby: ['state'], }; - cy.visitChartByParams(JSON.stringify(formData)); - cy.wait(['@getJson']).then(async ({ response }) => { + cy.visitChartByParams(formData); + cy.wait(['@chartData']).then(async ({ response }) => { cy.verifySliceContainer(); const responseBody = response?.body; - expect(responseBody.query).not.contains(formData.groupby[0]); + expect(responseBody.result[0].query).not.contains(formData.groupby[0]); }); }); }); diff --git a/superset-frontend/cypress-base/cypress/utils/vizPlugins.ts b/superset-frontend/cypress-base/cypress/utils/vizPlugins.ts index 850cc09879ba0..36a837476c396 100644 --- a/superset-frontend/cypress-base/cypress/utils/vizPlugins.ts +++ b/superset-frontend/cypress-base/cypress/utils/vizPlugins.ts @@ -40,6 +40,8 @@ const V1_PLUGINS = [ 'word_cloud', 'pie', 'table', + 'big_number', + 'big_number_total', ]; export const DASHBOARD_CHART_ALIAS_PREFIX = 'getChartData_'; diff --git a/superset-frontend/package-lock.json b/superset-frontend/package-lock.json index 0ea5b6d87a433..82f2dca65b675 100644 --- a/superset-frontend/package-lock.json +++ b/superset-frontend/package-lock.json @@ -41,7 +41,6 @@ "@superset-ui/legacy-plugin-chart-sunburst": "^0.18.25", "@superset-ui/legacy-plugin-chart-treemap": "^0.18.25", "@superset-ui/legacy-plugin-chart-world-map": "^0.18.25", - "@superset-ui/legacy-preset-chart-big-number": "^0.18.25", "@superset-ui/legacy-preset-chart-deckgl": "^0.4.13", "@superset-ui/legacy-preset-chart-nvd3": "^0.18.25", "@superset-ui/plugin-chart-echarts": "^0.18.25", @@ -198,6 +197,7 @@ "@types/redux-localstorage": "^1.0.8", "@types/redux-mock-store": "^1.0.2", "@types/rison": "0.0.6", + "@types/shortid": "^0.0.29", "@types/sinon": "^9.0.5", "@types/yargs": "12 - 15", "@typescript-eslint/eslint-plugin": "^5.3.0", @@ -21125,10 +21125,6 @@ "resolved": "plugins/legacy-plugin-chart-world-map", "link": true }, - "node_modules/@superset-ui/legacy-preset-chart-big-number": { - "resolved": "plugins/legacy-preset-chart-big-number", - "link": true - }, "node_modules/@superset-ui/legacy-preset-chart-deckgl": { "resolved": "plugins/legacy-preset-chart-deckgl", "link": true @@ -22433,7 +22429,8 @@ "node_modules/@types/shortid": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/shortid/-/shortid-0.0.29.tgz", - "integrity": "sha1-gJPuBBam4r8qpjOBCRFLP7/6Dps=" + "integrity": "sha1-gJPuBBam4r8qpjOBCRFLP7/6Dps=", + "dev": true }, "node_modules/@types/sinon": { "version": "9.0.5", @@ -60726,7 +60723,6 @@ "@superset-ui/legacy-plugin-chart-time-table": "0.18.25", "@superset-ui/legacy-plugin-chart-treemap": "0.18.25", "@superset-ui/legacy-plugin-chart-world-map": "0.18.25", - "@superset-ui/legacy-preset-chart-big-number": "0.18.25", "@superset-ui/legacy-preset-chart-deckgl": "^0.4.13", "@superset-ui/legacy-preset-chart-nvd3": "0.18.25", "@superset-ui/plugin-chart-echarts": "0.18.25", @@ -61502,6 +61498,7 @@ "plugins/legacy-preset-chart-big-number": { "name": "@superset-ui/legacy-preset-chart-big-number", "version": "0.18.25", + "extraneous": true, "license": "Apache-2.0", "dependencies": { "@data-ui/xy-chart": "^0.0.84", @@ -77854,7 +77851,6 @@ "@superset-ui/legacy-plugin-chart-time-table": "0.18.25", "@superset-ui/legacy-plugin-chart-treemap": "0.18.25", "@superset-ui/legacy-plugin-chart-world-map": "0.18.25", - "@superset-ui/legacy-preset-chart-big-number": "0.18.25", "@superset-ui/legacy-preset-chart-deckgl": "^0.4.13", "@superset-ui/legacy-preset-chart-nvd3": "0.18.25", "@superset-ui/plugin-chart-echarts": "0.18.25", @@ -78481,18 +78477,6 @@ } } }, - "@superset-ui/legacy-preset-chart-big-number": { - "version": "file:plugins/legacy-preset-chart-big-number", - "requires": { - "@data-ui/xy-chart": "^0.0.84", - "@superset-ui/chart-controls": "0.18.25", - "@superset-ui/core": "0.18.25", - "@types/d3-color": "^1.2.2", - "@types/shortid": "^0.0.29", - "d3-color": "^1.2.3", - "shortid": "^2.2.14" - } - }, "@superset-ui/legacy-preset-chart-deckgl": { "version": "file:plugins/legacy-preset-chart-deckgl", "requires": { @@ -79940,7 +79924,8 @@ "@types/shortid": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/shortid/-/shortid-0.0.29.tgz", - "integrity": "sha1-gJPuBBam4r8qpjOBCRFLP7/6Dps=" + "integrity": "sha1-gJPuBBam4r8qpjOBCRFLP7/6Dps=", + "dev": true }, "@types/sinon": { "version": "9.0.5", diff --git a/superset-frontend/package.json b/superset-frontend/package.json index b72640d802459..07ffcd0ce992c 100644 --- a/superset-frontend/package.json +++ b/superset-frontend/package.json @@ -101,7 +101,6 @@ "@superset-ui/legacy-plugin-chart-sunburst": "^0.18.25", "@superset-ui/legacy-plugin-chart-treemap": "^0.18.25", "@superset-ui/legacy-plugin-chart-world-map": "^0.18.25", - "@superset-ui/legacy-preset-chart-big-number": "^0.18.25", "@superset-ui/legacy-preset-chart-deckgl": "^0.4.13", "@superset-ui/legacy-preset-chart-nvd3": "^0.18.25", "@superset-ui/plugin-chart-echarts": "^0.18.25", @@ -258,6 +257,7 @@ "@types/redux-localstorage": "^1.0.8", "@types/redux-mock-store": "^1.0.2", "@types/rison": "0.0.6", + "@types/shortid": "^0.0.29", "@types/sinon": "^9.0.5", "@types/yargs": "12 - 15", "@typescript-eslint/eslint-plugin": "^5.3.0", diff --git a/superset-frontend/packages/superset-ui-core/src/query/types/QueryResponse.ts b/superset-frontend/packages/superset-ui-core/src/query/types/QueryResponse.ts index 6c99ca9aa632c..90898fcf1784b 100644 --- a/superset-frontend/packages/superset-ui-core/src/query/types/QueryResponse.ts +++ b/superset-frontend/packages/superset-ui-core/src/query/types/QueryResponse.ts @@ -50,7 +50,7 @@ export interface ChartDataResponseResult { annotation_data: AnnotationData[] | null; cache_key: string | null; cache_timeout: number | null; - cache_dttm: string | null; + cached_dttm: string | null; /** * Array of data records as dictionary */ @@ -76,6 +76,8 @@ export interface ChartDataResponseResult { | 'scheduled' | 'success' | 'timed_out'; + from_dttm: number | null; + to_dttm: number | null; } export interface TimeseriesChartDataResponseResult diff --git a/superset-frontend/packages/superset-ui-demo/package.json b/superset-frontend/packages/superset-ui-demo/package.json index d218442670454..90162756821ca 100644 --- a/superset-frontend/packages/superset-ui-demo/package.json +++ b/superset-frontend/packages/superset-ui-demo/package.json @@ -61,7 +61,6 @@ "@superset-ui/legacy-plugin-chart-time-table": "0.18.25", "@superset-ui/legacy-plugin-chart-treemap": "0.18.25", "@superset-ui/legacy-plugin-chart-world-map": "0.18.25", - "@superset-ui/legacy-preset-chart-big-number": "0.18.25", "@superset-ui/legacy-preset-chart-deckgl": "^0.4.13", "@superset-ui/legacy-preset-chart-nvd3": "0.18.25", "@superset-ui/plugin-chart-echarts": "0.18.25", diff --git a/superset-frontend/packages/superset-ui-demo/storybook/stories/plugins/legacy-preset-chart-big-number/BigNumber/BigNumberStories.tsx b/superset-frontend/packages/superset-ui-demo/storybook/stories/plugins/legacy-preset-chart-big-number/BigNumber/BigNumberStories.tsx index dd56c58bbf625..18fe9acddb2ea 100644 --- a/superset-frontend/packages/superset-ui-demo/storybook/stories/plugins/legacy-preset-chart-big-number/BigNumber/BigNumberStories.tsx +++ b/superset-frontend/packages/superset-ui-demo/storybook/stories/plugins/legacy-preset-chart-big-number/BigNumber/BigNumberStories.tsx @@ -18,7 +18,7 @@ */ import React from 'react'; import { SuperChart } from '@superset-ui/core'; -import { BigNumberChartPlugin } from '@superset-ui/legacy-preset-chart-big-number'; +import { BigNumberChartPlugin } from '@superset-ui/plugin-chart-echarts'; import testData from './data'; new BigNumberChartPlugin().configure({ key: 'big-number' }).register(); @@ -56,7 +56,7 @@ function withNulls(origData: object[], nullPosition = 3) { } export default { - title: 'Legacy Chart Plugins/legacy-preset-big-number/BigNumber', + title: 'Legacy Chart Plugins/legacy-preset-big-number/BigNumberWithTrendline', }; export const basicWithTrendline = () => ( diff --git a/superset-frontend/packages/superset-ui-demo/storybook/stories/plugins/legacy-preset-chart-big-number/BigNumberTotal/BigNumberTotalStories.tsx b/superset-frontend/packages/superset-ui-demo/storybook/stories/plugins/legacy-preset-chart-big-number/BigNumberTotal/BigNumberTotalStories.tsx index f99d4f2e0395d..2d1e105f3d7a8 100644 --- a/superset-frontend/packages/superset-ui-demo/storybook/stories/plugins/legacy-preset-chart-big-number/BigNumberTotal/BigNumberTotalStories.tsx +++ b/superset-frontend/packages/superset-ui-demo/storybook/stories/plugins/legacy-preset-chart-big-number/BigNumberTotal/BigNumberTotalStories.tsx @@ -18,7 +18,7 @@ */ import React from 'react'; import { SuperChart } from '@superset-ui/core'; -import { BigNumberTotalChartPlugin } from '@superset-ui/legacy-preset-chart-big-number'; +import { BigNumberTotalChartPlugin } from '@superset-ui/plugin-chart-echarts'; import data from './data'; new BigNumberTotalChartPlugin() diff --git a/superset-frontend/packages/superset-ui-demo/storybook/stories/superset-ui-chart/ChartDataProviderStories.tsx b/superset-frontend/packages/superset-ui-demo/storybook/stories/superset-ui-chart/ChartDataProviderStories.tsx index 14d4d6d8bd48e..ff72aff37db56 100644 --- a/superset-frontend/packages/superset-ui-demo/storybook/stories/superset-ui-chart/ChartDataProviderStories.tsx +++ b/superset-frontend/packages/superset-ui-demo/storybook/stories/superset-ui-chart/ChartDataProviderStories.tsx @@ -25,7 +25,7 @@ import { ChartDataProvider, SupersetClient, } from '@superset-ui/core'; -import { BigNumberChartPlugin as LegacyBigNumberPlugin } from '@superset-ui/legacy-preset-chart-big-number'; +import { BigNumberChartPlugin } from '@superset-ui/plugin-chart-echarts'; import LegacySankeyPlugin from '@superset-ui/legacy-plugin-chart-sankey'; import LegacySunburstPlugin from '@superset-ui/legacy-plugin-chart-sunburst'; import { WordCloudChartPlugin } from '@superset-ui/plugin-chart-word-cloud'; @@ -46,7 +46,7 @@ const SUNBURST = sunburstFormData.viz_type; const WORD_CLOUD_LEGACY = wordCloudFormData.viz_type; const WORD_CLOUD = 'new_word_cloud'; -new LegacyBigNumberPlugin().configure({ key: BIG_NUMBER }).register(); +new BigNumberChartPlugin().configure({ key: BIG_NUMBER }).register(); // eslint-disable-next-line new LegacySankeyPlugin().configure({ key: SANKEY }).register(); // eslint-disable-next-line diff --git a/superset-frontend/packages/superset-ui-demo/tsconfig.json b/superset-frontend/packages/superset-ui-demo/tsconfig.json index a7983cf472e56..36179f3624078 100644 --- a/superset-frontend/packages/superset-ui-demo/tsconfig.json +++ b/superset-frontend/packages/superset-ui-demo/tsconfig.json @@ -16,5 +16,6 @@ "storybook", "../**/src", "../../plugins/**/src", + "../../plugins/**/types", ] } diff --git a/superset-frontend/plugins/legacy-preset-chart-big-number/README.md b/superset-frontend/plugins/legacy-preset-chart-big-number/README.md deleted file mode 100644 index cceb13a5f6775..0000000000000 --- a/superset-frontend/plugins/legacy-preset-chart-big-number/README.md +++ /dev/null @@ -1,67 +0,0 @@ - - -## @superset-ui/legacy-preset-chart-big-number - -[![Version](https://img.shields.io/npm/v/@superset-ui/legacy-preset-chart-big-number.svg?style=flat-square)](https://www.npmjs.com/package/@superset-ui/legacy-preset-chart-big-number) -[![David (path)](https://img.shields.io/david/apache-superset/superset-ui-plugins.svg?path=packages%2Fsuperset-ui-legacy-preset-chart-big-number&style=flat-square)](https://david-dm.org/apache-superset/superset-ui-plugins?path=plugins/superset-ui-legacy-preset-chart-big-number) - -This plugin provides Big Number for Superset. - -### Usage - -Import the preset and register. This will register the `BigNumber` and `BigNumberTotal` charts with -key `big-number` and `big-number-total`, respectively. - -```js -import { BigNumberChartPreset } from '@superset-ui/legacy-preset-chart-big-number'; - -new BigNumberChartPreset().register(); -``` - -or register charts one by one. Configure `key`, which can be any `string`, and register the plugin. -This `key` will be used to lookup this chart throughout the app. - -```js -import { - BigNumberChartPlugin, - BigNumberTotalChartPlugin, -} from '@superset-ui/legacy-preset-chart-big-number'; - -new BigNumberChartPlugin().configure({ key: 'big-number' }).register(); -new BigNumberTotalChartPlugin() - .configure({ key: 'big-number-total' }) - .register(); -``` - -Then use it via `SuperChart`. See -[storybook](https://apache-superset.github.io/superset-ui-plugins/?selectedKind=plugin-chart-big-number) -for more details. - -```js - -``` diff --git a/superset-frontend/plugins/legacy-preset-chart-big-number/package.json b/superset-frontend/plugins/legacy-preset-chart-big-number/package.json deleted file mode 100644 index 81adb1d545252..0000000000000 --- a/superset-frontend/plugins/legacy-preset-chart-big-number/package.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "name": "@superset-ui/legacy-preset-chart-big-number", - "version": "0.18.25", - "description": "Superset Legacy Chart - Big Number", - "sideEffects": [ - "*.css" - ], - "main": "lib/index.js", - "module": "esm/index.js", - "files": [ - "esm", - "lib" - ], - "repository": { - "type": "git", - "url": "git+https://github.com/apache-superset/superset-ui.git" - }, - "keywords": [ - "superset" - ], - "author": "Superset", - "license": "Apache-2.0", - "bugs": { - "url": "https://github.com/apache-superset/superset-ui/issues" - }, - "homepage": "https://github.com/apache-superset/superset-ui#readme", - "publishConfig": { - "access": "public" - }, - "dependencies": { - "@data-ui/xy-chart": "^0.0.84", - "@superset-ui/chart-controls": "0.18.25", - "@superset-ui/core": "0.18.25", - "@types/d3-color": "^1.2.2", - "@types/shortid": "^0.0.29", - "d3-color": "^1.2.3", - "shortid": "^2.2.14" - }, - "peerDependencies": { - "react": "^15 || ^16" - } -} diff --git a/superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/transformProps.ts b/superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/transformProps.ts deleted file mode 100644 index 6e4674dca1dc3..0000000000000 --- a/superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/transformProps.ts +++ /dev/null @@ -1,187 +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 * as color from 'd3-color'; -import { - extractTimegrain, - getNumberFormatter, - getTimeFormatter, - getTimeFormatterForGranularity, - NumberFormats, - ChartProps, - LegacyQueryData, - QueryFormData, - smartDateFormatter, -} from '@superset-ui/core'; - -const TIME_COLUMN = '__timestamp'; -const formatPercentChange = getNumberFormatter( - NumberFormats.PERCENT_SIGNED_1_POINT, -); - -// we trust both the x (time) and y (big number) to be numeric -export interface BigNumberDatum { - [key: string]: number | null; -} - -export type BigNumberFormData = QueryFormData & { - colorPicker?: { - r: number; - g: number; - b: number; - }; - metric?: - | { - label: string; - } - | string; - compareLag?: string | number; - yAxisFormat?: string; -}; - -export type BigNumberChartProps = ChartProps & { - formData: BigNumberFormData; - queriesData: (LegacyQueryData & { - data?: BigNumberDatum[]; - })[]; -}; - -export default function transformProps(chartProps: BigNumberChartProps) { - const { width, height, queriesData, formData, rawFormData } = chartProps; - const { - colorPicker, - compareLag: compareLag_, - compareSuffix = '', - timeFormat, - headerFontSize, - metric = 'value', - showTimestamp, - showTrendLine, - startYAxisAtZero, - subheader = '', - subheaderFontSize, - vizType, - timeRangeFixed = false, - } = formData; - const granularity = extractTimegrain(rawFormData as QueryFormData); - let { yAxisFormat } = formData; - const { headerFormatSelector, headerTimestampFormat } = formData; - const { - data = [], - from_dttm: fromDatetime, - to_dttm: toDatetime, - } = queriesData[0]; - const metricName = typeof metric === 'string' ? metric : metric.label; - const compareLag = Number(compareLag_) || 0; - const supportTrendLine = vizType === 'big_number'; - const supportAndShowTrendLine = supportTrendLine && showTrendLine; - let formattedSubheader = subheader; - - let mainColor; - if (colorPicker) { - const { r, g, b } = colorPicker; - mainColor = color.rgb(r, g, b).hex(); - } - - let trendLineData; - let percentChange = 0; - let bigNumber = data.length === 0 ? null : data[0][metricName]; - let timestamp = data.length === 0 ? null : data[0][TIME_COLUMN]; - let bigNumberFallback; - - if (data.length > 0) { - const sortedData = (data as BigNumberDatum[]) - .map(d => ({ x: d[TIME_COLUMN], y: d[metricName] })) - // sort in time descending order - .sort((a, b) => (a.x !== null && b.x !== null ? b.x - a.x : 0)); - - bigNumber = sortedData[0].y; - timestamp = sortedData[0].x; - - if (bigNumber === null) { - bigNumberFallback = sortedData.find(d => d.y !== null); - bigNumber = bigNumberFallback ? bigNumberFallback.y : null; - timestamp = bigNumberFallback ? bigNumberFallback.x : null; - } - - if (compareLag > 0) { - const compareIndex = compareLag; - if (compareIndex < sortedData.length) { - const compareValue = sortedData[compareIndex].y; - // compare values must both be non-nulls - if (bigNumber !== null && compareValue !== null && compareValue !== 0) { - percentChange = (bigNumber - compareValue) / Math.abs(compareValue); - formattedSubheader = `${formatPercentChange( - percentChange, - )} ${compareSuffix}`; - } - } - } - - if (supportTrendLine) { - // must reverse to ascending order otherwise it confuses tooltip triggers - sortedData.reverse(); - trendLineData = supportAndShowTrendLine ? sortedData : undefined; - } - } - - let className = ''; - if (percentChange > 0) { - className = 'positive'; - } else if (percentChange < 0) { - className = 'negative'; - } - - if (!yAxisFormat && chartProps.datasource && chartProps.datasource.metrics) { - chartProps.datasource.metrics.forEach(metricEntry => { - if (metricEntry.metric_name === metric && metricEntry.d3format) { - yAxisFormat = metricEntry.d3format; - } - }); - } - - const headerFormatter = headerFormatSelector - ? getTimeFormatter(headerTimestampFormat) - : getNumberFormatter(yAxisFormat); - const formatTime = - timeFormat === smartDateFormatter.id - ? getTimeFormatterForGranularity(granularity) - : getTimeFormatter(timeFormat); - - return { - width, - height, - bigNumber, - bigNumberFallback, - className, - headerFormatter, - formatTime, - headerFontSize, - subheaderFontSize, - mainColor, - showTimestamp, - showTrendLine: supportAndShowTrendLine, - startYAxisAtZero, - subheader: formattedSubheader, - timestamp, - trendLineData, - fromDatetime, - toDatetime, - timeRangeFixed, - }; -} diff --git a/superset-frontend/plugins/legacy-preset-chart-big-number/test/tsconfig.json b/superset-frontend/plugins/legacy-preset-chart-big-number/test/tsconfig.json deleted file mode 100644 index 481ca5b4db938..0000000000000 --- a/superset-frontend/plugins/legacy-preset-chart-big-number/test/tsconfig.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "compilerOptions": { - "composite": false, - "emitDeclarationOnly": false, - "noEmit": true, - "rootDir": "." - }, - "extends": "../../../tsconfig.json", - "include": [ - "**/*", - "../types/**/*", - "../../../types/**/*" - ], - "references": [ - { - "path": ".." - } - ] -} diff --git a/superset-frontend/plugins/legacy-preset-chart-big-number/tsconfig.json b/superset-frontend/plugins/legacy-preset-chart-big-number/tsconfig.json deleted file mode 100644 index b6bfaa2d98446..0000000000000 --- a/superset-frontend/plugins/legacy-preset-chart-big-number/tsconfig.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "compilerOptions": { - "declarationDir": "lib", - "outDir": "lib", - "rootDir": "src" - }, - "exclude": [ - "lib", - "test" - ], - "extends": "../../tsconfig.json", - "include": [ - "src/**/*", - "types/**/*", - "../../types/**/*" - ], - "references": [ - { - "path": "../../packages/superset-ui-chart-controls" - }, - { - "path": "../../packages/superset-ui-core" - } - ] -} diff --git a/superset-frontend/plugins/legacy-preset-chart-big-number/src/types/external.d.ts b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/buildQuery.ts similarity index 79% rename from superset-frontend/plugins/legacy-preset-chart-big-number/src/types/external.d.ts rename to superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/buildQuery.ts index bd49e0aeeabef..e714898b024ec 100644 --- a/superset-frontend/plugins/legacy-preset-chart-big-number/src/types/external.d.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/buildQuery.ts @@ -16,6 +16,8 @@ * specific language governing permissions and limitations * under the License. */ -declare module '@data-ui/xy-chart'; -declare module '*.png'; -declare module '*.jpg'; +import { buildQueryContext, QueryFormData } from '@superset-ui/core'; + +export default function buildQuery(formData: QueryFormData) { + return buildQueryContext(formData, baseQueryObject => [baseQueryObject]); +} diff --git a/superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumberTotal/controlPanel.ts b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/controlPanel.ts similarity index 81% rename from superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumberTotal/controlPanel.ts rename to superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/controlPanel.ts index f6ab2f3c6e577..e30dcbe6bee6d 100644 --- a/superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumberTotal/controlPanel.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/controlPanel.ts @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -import { t } from '@superset-ui/core'; +import { smartDateFormatter, t } from '@superset-ui/core'; import { ControlPanelConfig, D3_FORMAT_DOCS, @@ -27,7 +27,7 @@ import { headerFontSize, subheaderFontSize } from '../sharedControls'; export default { controlPanelSections: [ - sections.legacyRegularTime, + sections.legacyTimeseriesTime, { label: t('Query'), expanded: true, @@ -51,44 +51,45 @@ export default { }, }, ], + ], + }, + { + label: t('Chart Options'), + expanded: true, + controlSetRows: [ + [headerFontSize], + [subheaderFontSize], ['y_axis_format'], [ { - name: 'header_format_selector', + name: 'time_format', config: { - type: 'CheckboxControl', - label: t('Timestamp Format'), + type: 'SelectControl', + freeForm: true, + label: t('Date format'), renderTrigger: true, - default: false, - description: t('Whether to format the timestamp'), + choices: D3_TIME_FORMAT_OPTIONS, + description: D3_FORMAT_DOCS, + default: smartDateFormatter.id, }, }, ], [ { - name: 'header_timestamp_format', + name: 'force_timestamp_formatting', config: { - type: 'SelectControl', - freeForm: true, - label: t('Date format'), + type: 'CheckboxControl', + label: t('Force date format'), renderTrigger: true, - choices: D3_TIME_FORMAT_OPTIONS, - default: '%d-%m-%Y %H:%M:%S', - description: D3_FORMAT_DOCS, - visibility(props) { - const { header_format_selector } = props.form_data; - return !!header_format_selector; - }, + default: false, + description: t( + 'Use date formatting even when metric value is not a timestamp', + ), }, }, ], ], }, - { - label: t('Chart Options'), - expanded: true, - controlSetRows: [[headerFontSize], [subheaderFontSize]], - }, ], controlOverrides: { y_axis_format: { diff --git a/superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumberTotal/images/BigNumber.jpg b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/images/BigNumber.jpg similarity index 100% rename from superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumberTotal/images/BigNumber.jpg rename to superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/images/BigNumber.jpg diff --git a/superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumberTotal/images/BigNumber2.jpg b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/images/BigNumber2.jpg similarity index 100% rename from superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumberTotal/images/BigNumber2.jpg rename to superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/images/BigNumber2.jpg diff --git a/superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumberTotal/images/thumbnail.png b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/images/thumbnail.png similarity index 100% rename from superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumberTotal/images/thumbnail.png rename to superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/images/thumbnail.png diff --git a/superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumberTotal/images/thumbnailLarge.png b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/images/thumbnailLarge.png similarity index 100% rename from superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumberTotal/images/thumbnailLarge.png rename to superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/images/thumbnailLarge.png diff --git a/superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumberTotal/index.ts b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/index.ts similarity index 86% rename from superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumberTotal/index.ts rename to superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/index.ts index 7bece7b8c1cbb..3f45db74cfd95 100644 --- a/superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumberTotal/index.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/index.ts @@ -18,13 +18,12 @@ */ import { t, ChartMetadata, ChartPlugin } from '@superset-ui/core'; import controlPanel from './controlPanel'; -import transformProps, { - BigNumberChartProps, - BigNumberFormData, -} from '../BigNumber/transformProps'; +import transformProps from './transformProps'; +import buildQuery from './buildQuery'; import example1 from './images/BigNumber.jpg'; import example2 from './images/BigNumber2.jpg'; import thumbnail from './images/thumbnail.png'; +import { BigNumberTotalChartProps, BigNumberTotalFormData } from '../types'; const metadata = new ChartMetadata({ category: t('KPI'), @@ -47,17 +46,17 @@ const metadata = new ChartMetadata({ t('Description'), ], thumbnail, - useLegacyApi: true, }); export default class BigNumberTotalChartPlugin extends ChartPlugin< - BigNumberFormData, - BigNumberChartProps + BigNumberTotalFormData, + BigNumberTotalChartProps > { constructor() { super({ - loadChart: () => import('../BigNumber/BigNumber'), + loadChart: () => import('../BigNumberViz'), metadata, + buildQuery, transformProps, controlPanel, }); diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/transformProps.ts b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/transformProps.ts new file mode 100644 index 0000000000000..23126739346cb --- /dev/null +++ b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/transformProps.ts @@ -0,0 +1,76 @@ +/** + * 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 { + getNumberFormatter, + GenericDataType, + getMetricLabel, + extractTimegrain, + QueryFormData, +} from '@superset-ui/core'; +import { BigNumberTotalChartProps } from '../types'; +import { getDateFormatter, parseMetricValue } from '../utils'; + +export default function transformProps(chartProps: BigNumberTotalChartProps) { + const { width, height, queriesData, formData, rawFormData } = chartProps; + const { + headerFontSize, + metric = 'value', + subheader = '', + subheaderFontSize, + forceTimestampFormatting, + timeFormat, + yAxisFormat, + } = formData; + const { data = [], coltypes = [] } = queriesData[0]; + const granularity = extractTimegrain(rawFormData as QueryFormData); + const metricName = getMetricLabel(metric); + const formattedSubheader = subheader; + const bigNumber = + data.length === 0 ? null : parseMetricValue(data[0][metricName]); + + let metricEntry; + if (chartProps.datasource && chartProps.datasource.metrics) { + metricEntry = chartProps.datasource.metrics.find( + metricItem => metricItem.metric_name === metric, + ); + } + + const formatTime = getDateFormatter( + timeFormat, + granularity, + metricEntry?.d3format, + ); + + const headerFormatter = + coltypes[0] === GenericDataType.TEMPORAL || + coltypes[0] === GenericDataType.STRING || + forceTimestampFormatting + ? formatTime + : getNumberFormatter(yAxisFormat ?? metricEntry?.d3format ?? undefined); + + return { + width, + height, + bigNumber, + headerFormatter, + headerFontSize, + subheaderFontSize, + subheader: formattedSubheader, + }; +} diff --git a/superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/BigNumber.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberViz.tsx similarity index 73% rename from superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/BigNumber.tsx rename to superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberViz.tsx index 6f559f3e71b53..1c650efeea31a 100644 --- a/superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/BigNumber.tsx +++ b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberViz.tsx @@ -17,7 +17,6 @@ * under the License. */ import React from 'react'; -import shortid from 'shortid'; import { t, getNumberFormatter, @@ -28,22 +27,12 @@ import { BRAND_COLOR, styled, } from '@superset-ui/core'; -import { - XYChart, - AreaSeries, - CrossHair, - LinearGradient, -} from '@data-ui/xy-chart'; +import { EChartsCoreOption } from 'echarts'; +import Echart from '../components/Echart'; +import { TimeSeriesDatum } from './types'; const defaultNumberFormatter = getNumberFormatter(); -const CHART_MARGIN = { - top: 4, - right: 4, - bottom: 4, - left: 4, -}; - const PROPORTION = { // text size: proportion of the chart container sans trendline KICKER: 0.1, @@ -53,32 +42,6 @@ const PROPORTION = { TRENDLINE: 0.3, }; -type TimeSeriesDatum = { - x: number; // timestamp as a number - y: number | null; -}; - -export function renderTooltipFactory( - formatDate = smartDateVerboseFormatter, - formatValue = defaultNumberFormatter, -) { - return function renderTooltip({ - datum: { x, y }, - }: { - datum: TimeSeriesDatum; - }) { - // even though `formatDate` supports timestamp as numbers, we need - // `new Date` to pass type check - return ( -
- {formatDate(new Date(x))} -
- {y === null ? t('N/A') : formatValue(y)} -
- ); - }; -} - type BigNumberVisProps = { className?: string; width: number; @@ -87,8 +50,6 @@ type BigNumberVisProps = { bigNumberFallback?: TimeSeriesDatum; headerFormatter: NumberFormatter | TimeFormatter; formatTime: TimeFormatter; - fromDatetime?: number; - toDatetime?: number; headerFontSize: number; kickerFontSize: number; subheader: string; @@ -100,11 +61,10 @@ type BigNumberVisProps = { timestamp?: number; trendLineData?: TimeSeriesDatum[]; mainColor: string; + echartOptions: EChartsCoreOption; }; -class BigNumberVis extends React.PureComponent { - private gradientId: string = shortid.generate(); - +class BigNumberVis extends React.PureComponent { static defaultProps = { className: '', headerFormatter: defaultNumberFormatter, @@ -146,7 +106,7 @@ class BigNumberVis extends React.PureComponent { role="alert" title={t( `Last available value seen on %s`, - formatTime(bigNumberFallback.x), + formatTime(bigNumberFallback[0]), )} > {t('Not up to date')} @@ -254,79 +214,19 @@ class BigNumberVis extends React.PureComponent { } renderTrendline(maxHeight: number) { - const { - width, - trendLineData, - mainColor, - subheader, - startYAxisAtZero, - headerFormatter, - formatTime, - fromDatetime, - timeRangeFixed, - } = this.props; + const { width, trendLineData, echartOptions } = this.props; // if can't find any non-null values, no point rendering the trendline - if (!trendLineData?.some(d => d.y !== null)) { + if (!trendLineData?.some(d => d[1] !== null)) { return null; } - // Apply a fixed X range if a time range is specified. - // - // XYChart checks the existence of `domain` property and decide whether to - // apply a domain or not, so it must not be `null` or `undefined` - const xScale: { type: string; domain?: number[] } = { type: 'timeUtc' }; - const tooltipData = trendLineData && [...trendLineData]; - if (tooltipData && timeRangeFixed && fromDatetime) { - const toDatetime = this.props.toDatetime ?? Date.now(); - if (tooltipData[0].x > fromDatetime) { - tooltipData.unshift({ - x: fromDatetime, - y: null, - }); - } - if (tooltipData[tooltipData.length - 1].x < toDatetime) { - tooltipData.push({ - x: toDatetime, - y: null, - }); - } - xScale.domain = [fromDatetime, toDatetime]; - } return ( - - - - - + echartOptions={echartOptions} + /> ); } diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/buildQuery.ts b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/buildQuery.ts new file mode 100644 index 0000000000000..1a9096ff77906 --- /dev/null +++ b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/buildQuery.ts @@ -0,0 +1,92 @@ +/** + * 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, + DTTM_ALIAS, + PostProcessingResample, + QueryFormData, +} from '@superset-ui/core'; +import { + rollingWindowOperator, + TIME_COLUMN, +} from '@superset-ui/chart-controls'; + +const TIME_GRAIN_MAP: Record = { + PT1S: 'S', + PT1M: 'min', + PT5M: '5min', + PT10M: '10min', + PT15M: '15min', + PT30M: '30min', + PT1H: 'H', + P1D: 'D', + P1M: 'M', + P3M: 'Q', + P1Y: 'A', + // TODO: these need to be mapped carefully, as the first day of week + // can vary from engine to engine + // P1W: 'W', + // '1969-12-28T00:00:00Z/P1W': 'W', + // '1969-12-29T00:00:00Z/P1W': 'W', + // 'P1W/1970-01-03T00:00:00Z': 'W', + // 'P1W/1970-01-04T00:00:00Z': 'W', +}; + +export default function buildQuery(formData: QueryFormData) { + return buildQueryContext(formData, baseQueryObject => { + const rollingProc = rollingWindowOperator(formData, baseQueryObject); + if (rollingProc) { + rollingProc.options = { ...rollingProc.options, is_pivot_df: false }; + } + const { time_grain_sqla } = formData; + let resampleProc: PostProcessingResample | undefined; + if (rollingProc && time_grain_sqla) { + const rule = TIME_GRAIN_MAP[time_grain_sqla]; + if (rule) { + resampleProc = { + operation: 'resample', + options: { + method: 'asfreq', + rule, + fill_value: null, + time_column: TIME_COLUMN, + }, + }; + } + } + return [ + { + ...baseQueryObject, + is_timeseries: true, + post_processing: [ + { + operation: 'sort', + options: { + columns: { + [DTTM_ALIAS]: true, + }, + }, + }, + resampleProc, + rollingProc, + ], + }, + ]; + }); +} diff --git a/superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/controlPanel.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx similarity index 91% rename from superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/controlPanel.tsx rename to superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx index 045f7fc7bdfb2..c1378543f6b0c 100644 --- a/superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/controlPanel.tsx +++ b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -import { t } from '@superset-ui/core'; +import { smartDateFormatter, t } from '@superset-ui/core'; import { ControlPanelConfig, D3_FORMAT_DOCS, @@ -63,20 +63,6 @@ const config: ControlPanelConfig = { }, }, ], - ['y_axis_format'], - [ - { - name: 'time_format', - config: { - type: 'SelectControl', - freeForm: true, - label: t('Timestamp format'), - renderTrigger: true, - choices: D3_TIME_FORMAT_OPTIONS, - description: D3_FORMAT_DOCS, - }, - }, - ], [ { name: 'show_timestamp', @@ -142,6 +128,35 @@ const config: ControlPanelConfig = { ['color_picker', null], [headerFontSize], [subheaderFontSize], + ['y_axis_format'], + [ + { + name: 'time_format', + config: { + type: 'SelectControl', + freeForm: true, + label: t('Date format'), + renderTrigger: true, + choices: D3_TIME_FORMAT_OPTIONS, + description: D3_FORMAT_DOCS, + default: smartDateFormatter.id, + }, + }, + ], + [ + { + name: 'force_timestamp_formatting', + config: { + type: 'CheckboxControl', + label: t('Force date format'), + renderTrigger: true, + default: false, + description: t( + 'Use date formatting even when metric value is not a timestamp', + ), + }, + }, + ], ], }, { diff --git a/superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/images/Big_Number_Trendline.jpg b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/images/Big_Number_Trendline.jpg similarity index 100% rename from superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/images/Big_Number_Trendline.jpg rename to superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/images/Big_Number_Trendline.jpg diff --git a/superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/images/thumbnail.png b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/images/thumbnail.png similarity index 100% rename from superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/images/thumbnail.png rename to superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/images/thumbnail.png diff --git a/superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/images/thumbnailLarge.png b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/images/thumbnailLarge.png similarity index 100% rename from superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/images/thumbnailLarge.png rename to superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/images/thumbnailLarge.png diff --git a/superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/index.ts b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/index.ts similarity index 80% rename from superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/index.ts rename to superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/index.ts index 2cfee291fc163..e774db4824e06 100644 --- a/superset-frontend/plugins/legacy-preset-chart-big-number/src/BigNumber/index.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/index.ts @@ -18,12 +18,14 @@ */ import { t, ChartMetadata, ChartPlugin } from '@superset-ui/core'; import controlPanel from './controlPanel'; -import transformProps, { - BigNumberChartProps, - BigNumberFormData, -} from './transformProps'; +import transformProps from './transformProps'; +import buildQuery from './buildQuery'; import example from './images/Big_Number_Trendline.jpg'; import thumbnail from './images/thumbnail.png'; +import { + BigNumberWithTrendlineChartProps, + BigNumberWithTrendlineFormData, +} from '../types'; const metadata = new ChartMetadata({ category: t('KPI'), @@ -43,17 +45,17 @@ const metadata = new ChartMetadata({ t('Trend'), ], thumbnail, - useLegacyApi: true, }); -export default class BigNumberChartPlugin extends ChartPlugin< - BigNumberFormData, - BigNumberChartProps +export default class BigNumberWithTrendlineChartPlugin extends ChartPlugin< + BigNumberWithTrendlineFormData, + BigNumberWithTrendlineChartProps > { constructor() { super({ - loadChart: () => import('./BigNumber'), + loadChart: () => import('../BigNumberViz'), metadata, + buildQuery, transformProps, controlPanel, }); diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/transformProps.ts b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/transformProps.ts new file mode 100644 index 0000000000000..5054d99515ccf --- /dev/null +++ b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/transformProps.ts @@ -0,0 +1,252 @@ +/** + * 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 { + extractTimegrain, + getNumberFormatter, + NumberFormats, + QueryFormData, + GenericDataType, + getMetricLabel, + t, + smartDateVerboseFormatter, + NumberFormatter, + TimeFormatter, +} from '@superset-ui/core'; +import { EChartsCoreOption, graphic } from 'echarts'; +import { + BigNumberDatum, + BigNumberWithTrendlineChartProps, + TimeSeriesDatum, +} from '../types'; +import { getDateFormatter, parseMetricValue } from '../utils'; + +const defaultNumberFormatter = getNumberFormatter(); +export function renderTooltipFactory( + formatDate: TimeFormatter = smartDateVerboseFormatter, + formatValue: NumberFormatter | TimeFormatter = defaultNumberFormatter, +) { + return function renderTooltip(params: { data: TimeSeriesDatum }[]) { + return ` + ${formatDate(params[0].data[0])} +
+ + ${ + params[0].data[1] === null ? t('N/A') : formatValue(params[0].data[1]) + } + + `; + }; +} + +const TIME_COLUMN = '__timestamp'; +const formatPercentChange = getNumberFormatter( + NumberFormats.PERCENT_SIGNED_1_POINT, +); + +export default function transformProps( + chartProps: BigNumberWithTrendlineChartProps, +) { + const { width, height, queriesData, formData, rawFormData } = chartProps; + const { + colorPicker, + compareLag: compareLag_, + compareSuffix = '', + timeFormat, + headerFontSize, + metric = 'value', + showTimestamp, + showTrendLine, + startYAxisAtZero, + subheader = '', + subheaderFontSize, + forceTimestampFormatting, + yAxisFormat, + timeRangeFixed, + } = formData; + const granularity = extractTimegrain(rawFormData as QueryFormData); + const { + data = [], + colnames = [], + coltypes = [], + from_dttm: fromDatetime, + to_dttm: toDatetime, + } = queriesData[0]; + const metricName = getMetricLabel(metric); + const compareLag = Number(compareLag_) || 0; + let formattedSubheader = subheader; + + const { r, g, b } = colorPicker; + const mainColor = `rgb(${r}, ${g}, ${b})`; + + let trendLineData; + let percentChange = 0; + let bigNumber = data.length === 0 ? null : data[0][metricName]; + let timestamp = data.length === 0 ? null : data[0][TIME_COLUMN]; + let bigNumberFallback; + + const metricColtypeIndex = colnames.findIndex(name => name === metricName); + const metricColtype = + metricColtypeIndex > -1 ? coltypes[metricColtypeIndex] : null; + + if (data.length > 0) { + const sortedData = (data as BigNumberDatum[]) + .map(d => [d[TIME_COLUMN], parseMetricValue(d[metricName])]) + // sort in time descending order + .sort((a, b) => (a[0] !== null && b[0] !== null ? b[0] - a[0] : 0)); + + bigNumber = sortedData[0][1]; + timestamp = sortedData[0][0]; + + if (bigNumber === null) { + bigNumberFallback = sortedData.find(d => d[1] !== null); + bigNumber = bigNumberFallback ? bigNumberFallback[1] : null; + timestamp = bigNumberFallback ? bigNumberFallback[0] : null; + } + + if (compareLag > 0) { + const compareIndex = compareLag; + if (compareIndex < sortedData.length) { + const compareValue = sortedData[compareIndex][1]; + // compare values must both be non-nulls + if (bigNumber !== null && compareValue !== null && compareValue !== 0) { + percentChange = (bigNumber - compareValue) / Math.abs(compareValue); + formattedSubheader = `${formatPercentChange( + percentChange, + )} ${compareSuffix}`; + } + } + } + sortedData.reverse(); + trendLineData = showTrendLine ? sortedData : undefined; + } + + let className = ''; + if (percentChange > 0) { + className = 'positive'; + } else if (percentChange < 0) { + className = 'negative'; + } + + let metricEntry; + if (chartProps.datasource && chartProps.datasource.metrics) { + metricEntry = chartProps.datasource.metrics.find( + metricEntry => metricEntry.metric_name === metric, + ); + } + + const formatTime = getDateFormatter( + timeFormat, + granularity, + metricEntry?.d3format, + ); + + const headerFormatter = + metricColtype === GenericDataType.TEMPORAL || + metricColtype === GenericDataType.STRING || + forceTimestampFormatting + ? formatTime + : getNumberFormatter(yAxisFormat ?? metricEntry?.d3format ?? undefined); + + if (trendLineData && timeRangeFixed && fromDatetime) { + const toDatetimeOrToday = toDatetime ?? Date.now(); + if (!trendLineData[0][0] || trendLineData[0][0] > fromDatetime) { + trendLineData.unshift([fromDatetime, null]); + } + if ( + !trendLineData[trendLineData.length - 1][0] || + trendLineData[trendLineData.length - 1][0]! < toDatetimeOrToday + ) { + trendLineData.push([toDatetimeOrToday, null]); + } + } + + const echartOptions: EChartsCoreOption = trendLineData + ? { + series: [ + { + data: trendLineData, + type: 'line', + smooth: true, + symbol: 'circle', + showSymbol: false, + color: mainColor, + areaStyle: { + color: new graphic.LinearGradient(0, 0, 0, 1, [ + { + offset: 0, + color: mainColor, + }, + { + offset: 1, + color: 'white', + }, + ]), + }, + }, + ], + xAxis: { + min: trendLineData[0][0], + max: trendLineData[trendLineData.length - 1][0], + show: false, + type: 'value', + }, + yAxis: { + scale: !startYAxisAtZero, + show: false, + }, + grid: { + left: 0, + right: 0, + top: 0, + bottom: 0, + }, + tooltip: { + show: true, + trigger: 'axis', + confine: true, + formatter: renderTooltipFactory(formatTime, headerFormatter), + }, + aria: { + enabled: true, + label: { + description: `Big number visualization ${subheader}`, + }, + }, + } + : {}; + return { + width, + height, + bigNumber, + bigNumberFallback, + className, + headerFormatter, + formatTime, + headerFontSize, + subheaderFontSize, + mainColor, + showTimestamp, + showTrendLine, + startYAxisAtZero, + subheader: formattedSubheader, + timestamp, + trendLineData, + echartOptions, + }; +} diff --git a/superset-frontend/plugins/legacy-preset-chart-big-number/CHANGELOG.md b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/CHANGELOG.md similarity index 100% rename from superset-frontend/plugins/legacy-preset-chart-big-number/CHANGELOG.md rename to superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/CHANGELOG.md diff --git a/superset-frontend/plugins/legacy-preset-chart-big-number/src/index.ts b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/index.ts similarity index 85% rename from superset-frontend/plugins/legacy-preset-chart-big-number/src/index.ts rename to superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/index.ts index ec2413cf2ddcb..f9b7f3c8a033f 100644 --- a/superset-frontend/plugins/legacy-preset-chart-big-number/src/index.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/index.ts @@ -17,6 +17,5 @@ * under the License. */ -export { default as BigNumberChartPlugin } from './BigNumber/index'; -export { default as BigNumberTotalChartPlugin } from './BigNumberTotal/index'; -export { default as BigNumberChartPreset } from './preset'; +export { default as BigNumberChartPlugin } from './BigNumberWithTrendline'; +export { default as BigNumberTotalChartPlugin } from './BigNumberTotal'; diff --git a/superset-frontend/plugins/legacy-preset-chart-big-number/src/sharedControls.ts b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/sharedControls.ts similarity index 98% rename from superset-frontend/plugins/legacy-preset-chart-big-number/src/sharedControls.ts rename to superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/sharedControls.ts index de13c6c844ea8..9cd6032affd98 100644 --- a/superset-frontend/plugins/legacy-preset-chart-big-number/src/sharedControls.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/sharedControls.ts @@ -17,7 +17,7 @@ * under the License. */ -// These are control configurations that are shared ONLY within the BigNumber viz plugin repo. +// These are control configurations that are shared ONLY within the BigNumberWithTrendline viz plugin repo. import { t } from '@superset-ui/core'; import { CustomControlItem } from '@superset-ui/chart-controls'; diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/types.ts b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/types.ts new file mode 100644 index 0000000000000..49f5ea2bfd98f --- /dev/null +++ b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/types.ts @@ -0,0 +1,57 @@ +/** + * 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 { + ChartDataResponseResult, + ChartProps, + QueryFormData, + QueryFormMetric, +} from '@superset-ui/core'; + +export interface BigNumberDatum { + [key: string]: number | null; +} + +export type BigNumberTotalFormData = QueryFormData & { + metric?: QueryFormMetric; + yAxisFormat?: string; + forceTimestampFormatting?: boolean; +}; + +export type BigNumberWithTrendlineFormData = BigNumberTotalFormData & { + colorPicker: { + r: number; + g: number; + b: number; + }; + compareLag?: string | number; +}; + +export type BigNumberTotalChartProps = ChartProps & { + formData: BigNumberTotalFormData; + queriesData: (ChartDataResponseResult & { + data?: BigNumberDatum[]; + })[]; +}; + +export type BigNumberWithTrendlineChartProps = BigNumberTotalChartProps & { + formData: BigNumberWithTrendlineFormData; +}; + +export type TimeSeriesDatum = [number, number | null]; diff --git a/superset-frontend/plugins/legacy-preset-chart-big-number/src/preset.ts b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/utils.ts similarity index 52% rename from superset-frontend/plugins/legacy-preset-chart-big-number/src/preset.ts rename to superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/utils.ts index 6e330e49fb4eb..b30e13d539f7c 100644 --- a/superset-frontend/plugins/legacy-preset-chart-big-number/src/preset.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/utils.ts @@ -16,18 +16,31 @@ * specific language governing permissions and limitations * under the License. */ -import { Preset } from '@superset-ui/core'; -import BigNumberChartPlugin from './BigNumber'; -import BigNumberTotalChartPlugin from './BigNumberTotal'; -export default class BigNumberChartPreset extends Preset { - constructor() { - super({ - name: 'BigNumber charts', - plugins: [ - new BigNumberChartPlugin().configure({ key: 'big_number' }), - new BigNumberTotalChartPlugin().configure({ key: 'big_number_total' }), - ], - }); +import moment from 'moment'; +import { + getTimeFormatter, + getTimeFormatterForGranularity, + smartDateFormatter, + TimeGranularity, +} from '@superset-ui/core'; + +export const parseMetricValue = (metricValue: number | string | null) => { + if (typeof metricValue === 'string') { + const dateObject = moment.utc(metricValue, moment.ISO_8601, true); + if (dateObject.isValid()) { + return dateObject.valueOf(); + } + return null; } -} + return metricValue; +}; + +export const getDateFormatter = ( + timeFormat: string, + granularity?: TimeGranularity, + fallbackFormat?: string | null, +) => + timeFormat === smartDateFormatter.id + ? getTimeFormatterForGranularity(granularity) + : getTimeFormatter(timeFormat ?? fallbackFormat); diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/index.ts b/superset-frontend/plugins/plugin-chart-echarts/src/index.ts index ad9f9113cc574..84a1a3a3dcc39 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/index.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/index.ts @@ -32,6 +32,7 @@ export { default as EchartsRadarChartPlugin } from './Radar'; export { default as EchartsFunnelChartPlugin } from './Funnel'; export { default as EchartsTreeChartPlugin } from './Tree'; export { default as EchartsTreemapChartPlugin } from './Treemap'; +export { BigNumberChartPlugin, BigNumberTotalChartPlugin } from './BigNumber'; export { default as BoxPlotTransformProps } from './BoxPlot/transformProps'; export { default as FunnelTransformProps } from './Funnel/transformProps'; diff --git a/superset-frontend/plugins/legacy-preset-chart-big-number/test/transformProps.test.ts b/superset-frontend/plugins/plugin-chart-echarts/test/BigNumber/transformProps.test.ts similarity index 87% rename from superset-frontend/plugins/legacy-preset-chart-big-number/test/transformProps.test.ts rename to superset-frontend/plugins/plugin-chart-echarts/test/BigNumber/transformProps.test.ts index d19139b0fd2a1..4fdb3de8748d8 100644 --- a/superset-frontend/plugins/legacy-preset-chart-big-number/test/transformProps.test.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/test/BigNumber/transformProps.test.ts @@ -17,10 +17,11 @@ * under the License. */ import { DatasourceType, TimeGranularity } from '@superset-ui/core'; -import transformProps, { - BignumberChartProps, +import transformProps from '../../src/BigNumber/BigNumberWithTrendline/transformProps'; +import { BigNumberDatum, -} from '../src/BigNumber/transformProps'; + BigNumberWithTrendlineChartProps, +} from '../../src/BigNumber/types'; const formData = { metric: 'value', @@ -33,8 +34,9 @@ const formData = { compareLag: 1, timeGrainSqla: 'P3M' as TimeGranularity, compareSuffix: 'over last quarter', - vizType: 'big_number', + viz_type: 'big_number', yAxisFormat: '.3s', + datasource: 'test_datasource', }; const rawFormData = { @@ -56,7 +58,7 @@ function generateProps( data: BigNumberDatum[], extraFormData = {}, extraQueryData = {}, -): BignumberChartProps { +): BigNumberWithTrendlineChartProps { return { width: 200, height: 500, @@ -84,10 +86,13 @@ function generateProps( ...extraQueryData, }, ], + ownState: {}, + filterState: {}, + behaviors: [], }; } -describe('BigNumber', () => { +describe('BigNumberWithTrendline', () => { const props = generateProps( [ { @@ -109,8 +114,8 @@ describe('BigNumber', () => { const lastDatum = transformed.trendLineData?.pop(); // should use last available value - expect(lastDatum?.x).toStrictEqual(100); - expect(lastDatum?.y).toBeNull(); + expect(lastDatum?.[0]).toStrictEqual(100); + expect(lastDatum?.[1]).toBeNull(); // should note this is a fallback expect(transformed.bigNumber).toStrictEqual(1.2345); diff --git a/superset-frontend/plugins/plugin-chart-table/test/testData.ts b/superset-frontend/plugins/plugin-chart-table/test/testData.ts index e9eee7e92d493..dd411c932f073 100644 --- a/superset-frontend/plugins/plugin-chart-table/test/testData.ts +++ b/superset-frontend/plugins/plugin-chart-table/test/testData.ts @@ -68,7 +68,7 @@ const basicChartProps = { const basicQueryResult: ChartDataResponseResult = { annotation_data: null, cache_key: null, - cache_dttm: null, + cached_dttm: null, cache_timeout: null, data: [], colnames: [], diff --git a/superset-frontend/src/visualizations/presets/MainPreset.js b/superset-frontend/src/visualizations/presets/MainPreset.js index 97c14a99d57da..a32fbb2b74f88 100644 --- a/superset-frontend/src/visualizations/presets/MainPreset.js +++ b/superset-frontend/src/visualizations/presets/MainPreset.js @@ -17,10 +17,6 @@ * under the License. */ import { isFeatureEnabled, Preset, FeatureFlag } from '@superset-ui/core'; -import { - BigNumberChartPlugin, - BigNumberTotalChartPlugin, -} from '@superset-ui/legacy-preset-chart-big-number'; import CalendarChartPlugin from '@superset-ui/legacy-plugin-chart-calendar'; import ChordChartPlugin from '@superset-ui/legacy-plugin-chart-chord'; import CountryMapChartPlugin from '@superset-ui/legacy-plugin-chart-country-map'; @@ -54,6 +50,8 @@ import { } from '@superset-ui/legacy-preset-chart-nvd3'; import { DeckGLChartPreset } from '@superset-ui/legacy-preset-chart-deckgl'; import { + BigNumberChartPlugin, + BigNumberTotalChartPlugin, EchartsPieChartPlugin, EchartsBoxPlotChartPlugin, EchartsAreaChartPlugin, diff --git a/superset/charts/schemas.py b/superset/charts/schemas.py index f68c4ff4b8c95..225410eb4c9ab 100644 --- a/superset/charts/schemas.py +++ b/superset/charts/schemas.py @@ -1240,12 +1240,22 @@ class ChartDataResponseResult(Schema): description="Amount of rows in result set", allow_none=False, ) data = fields.List(fields.Dict(), description="A list with results") + colnames = fields.List(fields.String(), description="A list of column names") + coltypes = fields.List( + fields.Integer(), description="A list of generic data types of each column" + ) applied_filters = fields.List( fields.Dict(), description="A list with applied filters" ) rejected_filters = fields.List( fields.Dict(), description="A list with rejected filters" ) + from_dttm = fields.Integer( + desciption="Start timestamp of time range", required=False, allow_none=True + ) + to_dttm = fields.Integer( + desciption="End timestamp of time range", required=False, allow_none=True + ) class ChartDataResponseSchema(Schema): diff --git a/superset/common/query_context_processor.py b/superset/common/query_context_processor.py index 09f991420c60a..9c641cb3ea7c0 100644 --- a/superset/common/query_context_processor.py +++ b/superset/common/query_context_processor.py @@ -144,6 +144,8 @@ def get_df_payload( "status": cache.status, "stacktrace": cache.stacktrace, "rowcount": len(cache.df.index), + "from_dttm": query_obj.from_dttm, + "to_dttm": query_obj.to_dttm, } def query_cache_key(self, query_obj: QueryObject, **kwargs: Any) -> Optional[str]: @@ -201,6 +203,8 @@ def get_query_result(self, query_object: QueryObject) -> QueryResult: result.df = df result.query = query + result.from_dttm = query_object.from_dttm + result.to_dttm = query_object.to_dttm return result def normalize_df(self, df: pd.DataFrame, query_object: QueryObject) -> pd.DataFrame: diff --git a/superset/migrations/versions/fe23025b9441_rename_big_viz_total_form_data_fields.py b/superset/migrations/versions/fe23025b9441_rename_big_viz_total_form_data_fields.py new file mode 100644 index 0000000000000..d391348ee8c9b --- /dev/null +++ b/superset/migrations/versions/fe23025b9441_rename_big_viz_total_form_data_fields.py @@ -0,0 +1,100 @@ +# 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. +"""rename_big_viz_total_form_data_fields + +Revision ID: fe23025b9441 +Revises: 3ba29ecbaac5 +Create Date: 2021-12-13 14:06:24.426970 + +""" + +# revision identifiers, used by Alembic. +revision = "fe23025b9441" +down_revision = "3ba29ecbaac5" + +import json +import logging + +from alembic import op +from sqlalchemy import Column, Integer, String, Text +from sqlalchemy.ext.declarative import declarative_base + +from superset import db + +Base = declarative_base() + +logger = logging.getLogger("alembic") + + +class Slice(Base): + __tablename__ = "slices" + + id = Column(Integer, primary_key=True) + params = Column(Text) + viz_type = Column(String(250)) + + +def upgrade(): + bind = op.get_bind() + session = db.Session(bind=bind) + + slices = session.query(Slice).filter(Slice.viz_type == "big_number_total").all() + for slc in slices: + try: + params = json.loads(slc.params) + header_format_selector = params.pop("header_format_selector", None) + header_timestamp_format = params.pop("header_timestamp_format", None) + if header_format_selector: + params["force_timestamp_formatting"] = header_format_selector + if header_timestamp_format: + params["time_format"] = header_timestamp_format + slc.params = json.dumps(params, sort_keys=True) + except Exception as e: + logger.exception( + f"An error occurred: parsing params for slice {slc.id} failed." + f"You need to fix it before upgrading your DB." + ) + raise e + + session.commit() + session.close() + + +def downgrade(): + bind = op.get_bind() + session = db.Session(bind=bind) + + slices = session.query(Slice).filter(Slice.viz_type == "big_number_total").all() + for slc in slices: + try: + params = json.loads(slc.params) + time_format = params.pop("time_format", None) + force_timestamp_formatting = params.pop("force_timestamp_formatting", None) + if time_format: + params["header_timestamp_format"] = time_format + if force_timestamp_formatting: + params["header_format_selector"] = force_timestamp_formatting + slc.params = json.dumps(params, sort_keys=True) + except Exception as e: + logger.exception( + f"An error occurred: parsing params for slice {slc.id} failed. " + "You need to fix it before downgrading your DB." + ) + raise e + + session.commit() + session.close() diff --git a/superset/models/helpers.py b/superset/models/helpers.py index 1875d247dc0a3..42779239985d8 100644 --- a/superset/models/helpers.py +++ b/superset/models/helpers.py @@ -446,6 +446,8 @@ def __init__( # pylint: disable=too-many-arguments status: str = QueryStatus.SUCCESS, error_message: Optional[str] = None, errors: Optional[List[Dict[str, Any]]] = None, + from_dttm: Optional[datetime] = None, + to_dttm: Optional[datetime] = None, ) -> None: self.df = df self.query = query @@ -454,6 +456,8 @@ def __init__( # pylint: disable=too-many-arguments self.status = status self.error_message = error_message self.errors = errors or [] + self.from_dttm = from_dttm + self.to_dttm = to_dttm class ExtraJSONMixin: