From 375797f6496e0098f145bb4a4ca8282418c8db89 Mon Sep 17 00:00:00 2001 From: Ville Brofeldt <33317356+villebro@users.noreply.github.com> Date: Tue, 9 Mar 2021 17:27:46 +0200 Subject: [PATCH] feat(native-filters): add timegrain and column filter (#13484) * feat(native-filters): add timegrain and column filter * add fetch values predicate * bump deps * lint * fix test * add python test for legacy merge * fix default value and isInitialized to not check strict equality * Address comments * add FilterValue type * address review comments --- superset-frontend/package-lock.json | 676 ++++++++---------- superset-frontend/package.json | 54 +- .../spec/javascripts/filters/utils_spec.ts | 10 +- .../components/FiltersBadge/selectors.ts | 13 +- .../nativeFilters/FilterBar/FilterValue.tsx | 4 +- .../FiltersConfigForm/ControlItems.tsx | 1 - .../FiltersConfigForm/FiltersConfigForm.tsx | 46 +- .../FiltersConfigForm/state.ts | 10 +- .../nativeFilters/FiltersConfigModal/utils.ts | 14 +- .../components/nativeFilters/types.ts | 6 +- .../components/nativeFilters/utils.ts | 12 +- .../components/Range/RangeFilterPlugin.tsx | 9 +- .../filters/components/Range/buildQuery.ts | 1 + .../src/filters/components/Range/index.ts | 2 +- .../components/Select/SelectFilterPlugin.tsx | 42 +- .../filters/components/Select/buildQuery.ts | 1 + .../src/filters/components/Select/index.ts | 2 +- .../components/Time/TimeFilterPlugin.tsx | 10 +- .../src/filters/components/Time/index.ts | 2 +- .../TimeColumn/TimeColumnFilterPlugin.tsx | 110 +++ .../components/TimeColumn/buildQuery.ts | 44 ++ .../components/TimeColumn/controlPanel.ts | 25 + .../TimeColumn/images/thumbnail.png | Bin 0 -> 5658 bytes .../filters/components/TimeColumn/index.ts | 42 ++ .../components/TimeColumn/transformProps.ts | 36 + .../filters/components/TimeColumn/types.ts | 48 ++ .../TimeGrain/TimeGrainFilterPlugin.tsx | 93 +++ .../components/TimeGrain/buildQuery.ts | 44 ++ .../components/TimeGrain/controlPanel.ts | 25 + .../components/TimeGrain/images/thumbnail.png | Bin 0 -> 5658 bytes .../src/filters/components/TimeGrain/index.ts | 42 ++ .../components/TimeGrain/transformProps.ts | 35 + .../src/filters/components/TimeGrain/types.ts | 42 ++ .../src/filters/components/common.ts | 30 + .../src/filters/components/index.ts | 2 + superset-frontend/src/filters/utils.ts | 10 +- .../src/visualizations/presets/MainPreset.js | 4 + superset/charts/schemas.py | 5 + superset/common/query_object.py | 16 +- superset/connectors/druid/models.py | 8 +- superset/connectors/sqla/models.py | 28 +- superset/db_engine_specs/base.py | 36 +- superset/utils/core.py | 18 +- tests/core_tests.py | 2 +- tests/dashboard_utils.py | 5 +- tests/databases/commands_tests.py | 2 +- tests/fixtures/birth_names_dashboard.py | 26 +- tests/query_context_tests.py | 41 +- tests/utils_tests.py | 27 +- 49 files changed, 1215 insertions(+), 546 deletions(-) create mode 100644 superset-frontend/src/filters/components/TimeColumn/TimeColumnFilterPlugin.tsx create mode 100644 superset-frontend/src/filters/components/TimeColumn/buildQuery.ts create mode 100644 superset-frontend/src/filters/components/TimeColumn/controlPanel.ts create mode 100644 superset-frontend/src/filters/components/TimeColumn/images/thumbnail.png create mode 100644 superset-frontend/src/filters/components/TimeColumn/index.ts create mode 100644 superset-frontend/src/filters/components/TimeColumn/transformProps.ts create mode 100644 superset-frontend/src/filters/components/TimeColumn/types.ts create mode 100644 superset-frontend/src/filters/components/TimeGrain/TimeGrainFilterPlugin.tsx create mode 100644 superset-frontend/src/filters/components/TimeGrain/buildQuery.ts create mode 100644 superset-frontend/src/filters/components/TimeGrain/controlPanel.ts create mode 100644 superset-frontend/src/filters/components/TimeGrain/images/thumbnail.png create mode 100644 superset-frontend/src/filters/components/TimeGrain/index.ts create mode 100644 superset-frontend/src/filters/components/TimeGrain/transformProps.ts create mode 100644 superset-frontend/src/filters/components/TimeGrain/types.ts create mode 100644 superset-frontend/src/filters/components/common.ts diff --git a/superset-frontend/package-lock.json b/superset-frontend/package-lock.json index 5dd8aff418..341898a645 100644 --- a/superset-frontend/package-lock.json +++ b/superset-frontend/package-lock.json @@ -13,34 +13,34 @@ "@babel/runtime-corejs3": "^7.12.5", "@data-ui/sparkline": "^0.0.84", "@emotion/core": "^10.0.35", - "@superset-ui/chart-controls": "^0.17.14", - "@superset-ui/core": "^0.17.14", - "@superset-ui/legacy-plugin-chart-calendar": "^0.17.14", - "@superset-ui/legacy-plugin-chart-chord": "^0.17.14", - "@superset-ui/legacy-plugin-chart-country-map": "^0.17.14", - "@superset-ui/legacy-plugin-chart-event-flow": "^0.17.14", - "@superset-ui/legacy-plugin-chart-force-directed": "^0.17.14", - "@superset-ui/legacy-plugin-chart-heatmap": "^0.17.14", - "@superset-ui/legacy-plugin-chart-histogram": "^0.17.14", - "@superset-ui/legacy-plugin-chart-horizon": "^0.17.14", - "@superset-ui/legacy-plugin-chart-map-box": "^0.17.14", - "@superset-ui/legacy-plugin-chart-paired-t-test": "^0.17.14", - "@superset-ui/legacy-plugin-chart-parallel-coordinates": "^0.17.14", - "@superset-ui/legacy-plugin-chart-partition": "^0.17.14", - "@superset-ui/legacy-plugin-chart-pivot-table": "^0.17.14", - "@superset-ui/legacy-plugin-chart-rose": "^0.17.14", - "@superset-ui/legacy-plugin-chart-sankey": "^0.17.14", - "@superset-ui/legacy-plugin-chart-sankey-loop": "^0.17.14", - "@superset-ui/legacy-plugin-chart-sunburst": "^0.17.14", - "@superset-ui/legacy-plugin-chart-treemap": "^0.17.14", - "@superset-ui/legacy-plugin-chart-world-map": "^0.17.14", - "@superset-ui/legacy-preset-chart-big-number": "^0.17.14", + "@superset-ui/chart-controls": "^0.17.15", + "@superset-ui/core": "^0.17.15", + "@superset-ui/legacy-plugin-chart-calendar": "^0.17.15", + "@superset-ui/legacy-plugin-chart-chord": "^0.17.15", + "@superset-ui/legacy-plugin-chart-country-map": "^0.17.15", + "@superset-ui/legacy-plugin-chart-event-flow": "^0.17.15", + "@superset-ui/legacy-plugin-chart-force-directed": "^0.17.15", + "@superset-ui/legacy-plugin-chart-heatmap": "^0.17.15", + "@superset-ui/legacy-plugin-chart-histogram": "^0.17.15", + "@superset-ui/legacy-plugin-chart-horizon": "^0.17.15", + "@superset-ui/legacy-plugin-chart-map-box": "^0.17.15", + "@superset-ui/legacy-plugin-chart-paired-t-test": "^0.17.15", + "@superset-ui/legacy-plugin-chart-parallel-coordinates": "^0.17.15", + "@superset-ui/legacy-plugin-chart-partition": "^0.17.15", + "@superset-ui/legacy-plugin-chart-pivot-table": "^0.17.15", + "@superset-ui/legacy-plugin-chart-rose": "^0.17.15", + "@superset-ui/legacy-plugin-chart-sankey": "^0.17.15", + "@superset-ui/legacy-plugin-chart-sankey-loop": "^0.17.15", + "@superset-ui/legacy-plugin-chart-sunburst": "^0.17.15", + "@superset-ui/legacy-plugin-chart-treemap": "^0.17.15", + "@superset-ui/legacy-plugin-chart-world-map": "^0.17.15", + "@superset-ui/legacy-preset-chart-big-number": "^0.17.15", "@superset-ui/legacy-preset-chart-deckgl": "^0.4.6", - "@superset-ui/legacy-preset-chart-nvd3": "^0.17.14", - "@superset-ui/plugin-chart-echarts": "^0.17.14", - "@superset-ui/plugin-chart-table": "^0.17.14", - "@superset-ui/plugin-chart-word-cloud": "^0.17.14", - "@superset-ui/preset-chart-xy": "^0.17.14", + "@superset-ui/legacy-preset-chart-nvd3": "^0.17.15", + "@superset-ui/plugin-chart-echarts": "^0.17.15", + "@superset-ui/plugin-chart-table": "^0.17.15", + "@superset-ui/plugin-chart-word-cloud": "^0.17.15", + "@superset-ui/preset-chart-xy": "^0.17.15", "@vx/responsive": "^0.0.195", "abortcontroller-polyfill": "^1.1.9", "antd": "^4.9.4", @@ -306,8 +306,6 @@ "integrity": "sha512-+y4ZnePpvWs1fc/LhZRTHkTesbXkyBYuOB+5CyodZqrEuETXi3zOVfpAQIdgC3lXbHLTDG9dQosxR9BhvLKDLQ==", "dev": true, "dependencies": { - "@nicolo-ribaudo/chokidar-2": "2.1.8-no-fsevents", - "chokidar": "^3.4.0", "commander": "^4.0.1", "convert-source-map": "^1.1.0", "fs-readdir-recursive": "^1.1.0", @@ -7113,7 +7111,6 @@ "@types/node": "*", "anymatch": "^3.0.3", "fb-watchman": "^2.0.0", - "fsevents": "^2.1.2", "graceful-fs": "^4.2.4", "jest-regex-util": "^26.0.0", "jest-serializer": "^26.6.2", @@ -7717,7 +7714,6 @@ "jest-resolve": "^26.6.2", "jest-util": "^26.6.2", "jest-worker": "^26.6.2", - "node-notifier": "^8.0.0", "slash": "^3.0.0", "source-map": "^0.6.0", "string-length": "^4.0.1", @@ -7906,7 +7902,6 @@ "@types/node": "*", "anymatch": "^3.0.3", "fb-watchman": "^2.0.0", - "fsevents": "^2.1.2", "graceful-fs": "^4.2.4", "jest-regex-util": "^26.0.0", "jest-serializer": "^26.6.2", @@ -8338,7 +8333,6 @@ "@types/node": "*", "anymatch": "^3.0.3", "fb-watchman": "^2.0.0", - "fsevents": "^2.1.2", "graceful-fs": "^4.2.4", "jest-regex-util": "^26.0.0", "jest-serializer": "^26.6.2", @@ -10645,8 +10639,7 @@ "esprima": "^4.0.1", "estraverse": "^4.2.0", "esutils": "^2.0.2", - "optionator": "^0.8.1", - "source-map": "~0.6.1" + "optionator": "^0.8.1" }, "bin": { "escodegen": "bin/escodegen.js", @@ -11980,9 +11973,6 @@ "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.22.0.tgz", "integrity": "sha512-lLJ/Wt9yy0AiSYBf212kK3mM5L8ycwlyTlSxHBAneXLR0nzFMlZ5y7riFPF3E33zXOF2IH95xdY5jIyZbM9z/w==", "dev": true, - "dependencies": { - "clipboard": "^2.0.0" - }, "optionalDependencies": { "clipboard": "^2.0.0" } @@ -15967,11 +15957,11 @@ } }, "node_modules/@superset-ui/chart-controls": { - "version": "0.17.14", - "resolved": "https://registry.npmjs.org/@superset-ui/chart-controls/-/chart-controls-0.17.14.tgz", - "integrity": "sha512-YY9Gn40bRbZr4ivCQcP8E+9+maWcpoENtCQm3dPNgwVaa8wmZ03dR+VMkIsM5G3VWOHl6T+nSCyo5R/qTFlh5g==", + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@superset-ui/chart-controls/-/chart-controls-0.17.15.tgz", + "integrity": "sha512-D0KoG5QvE3gxDnnN3lrLaQOXLQOCk8HBfQLXqAafGJDxIjatfAopty+7lz6Yzu859/OCBJK5AJybLm7fW5JtTg==", "dependencies": { - "@superset-ui/core": "0.17.14", + "@superset-ui/core": "0.17.15", "lodash": "^4.17.15", "prop-types": "^15.7.2" }, @@ -15984,9 +15974,9 @@ } }, "node_modules/@superset-ui/core": { - "version": "0.17.14", - "resolved": "https://registry.npmjs.org/@superset-ui/core/-/core-0.17.14.tgz", - "integrity": "sha512-wdzCaDG8DO02wheBWyVd1q5EUV0RuEUjVSNKVm0aiZzBxcv95mlS62mgN24VdxDiL1Zca1+MJ4/bCz/K3wZ08w==", + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@superset-ui/core/-/core-0.17.15.tgz", + "integrity": "sha512-6SVtSQgdZVnhfpEwPOLmQhePsET8jOKjuUJ5kY6OCTk8e7R2ghFsHKwiCdJa5T7/+F7ghQ2kKDzns1VQyhx+oA==", "dependencies": { "@babel/runtime": "^7.1.2", "@emotion/core": "^10.0.28", @@ -16075,12 +16065,12 @@ } }, "node_modules/@superset-ui/legacy-plugin-chart-calendar": { - "version": "0.17.14", - "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-calendar/-/legacy-plugin-chart-calendar-0.17.14.tgz", - "integrity": "sha512-+xykD1FdquEfcmSvtDkR/NuiPlu6QYEIFLZ3H41U/AdzQb5n+kkgCG0M883qdfkQlbaGsZtjnjIoqotWclmwMQ==", + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-calendar/-/legacy-plugin-chart-calendar-0.17.15.tgz", + "integrity": "sha512-GIDY1ihvS24tV7IQYQKZJQaxlOvQ45RGfPMhi9bOmphVaV1X/sWwlBZK0LbL00kAzQJyOgvC+tE1+8y4ZoHrvg==", "dependencies": { - "@superset-ui/chart-controls": "0.17.14", - "@superset-ui/core": "0.17.14", + "@superset-ui/chart-controls": "0.17.15", + "@superset-ui/core": "0.17.15", "d3-array": "^2.0.3", "d3-selection": "^1.4.0", "d3-tip": "^0.9.1", @@ -16099,24 +16089,24 @@ } }, "node_modules/@superset-ui/legacy-plugin-chart-chord": { - "version": "0.17.14", - "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-chord/-/legacy-plugin-chart-chord-0.17.14.tgz", - "integrity": "sha512-QNeUnUR9Z/TDb2Q+lYIzUtCyKVM/tG0iLceE6kWHtlxCH3QI0aw43bhDS6wK9LLbBzURQezGStxLeJaIwmsmuA==", + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-chord/-/legacy-plugin-chart-chord-0.17.15.tgz", + "integrity": "sha512-1coV7lCw5T1AnaDaRVaHWvwkCZDJFLHItHLby0dsnQ8tYgBTVOocC7GC34EESmirwfYSh/yutAV8uyNU4g3MMA==", "dependencies": { - "@superset-ui/chart-controls": "0.17.14", - "@superset-ui/core": "0.17.14", + "@superset-ui/chart-controls": "0.17.15", + "@superset-ui/core": "0.17.15", "d3": "^3.5.17", "prop-types": "^15.6.2", "react": "^16.13.1" } }, "node_modules/@superset-ui/legacy-plugin-chart-country-map": { - "version": "0.17.14", - "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-country-map/-/legacy-plugin-chart-country-map-0.17.14.tgz", - "integrity": "sha512-qtjWyxPwWNEhNzXxx1h81u7DBdr44UP41JPHRkLsWoWQweecR9Q8nWCSFEVcE9+7ehAxGigtbXEHVoix4L1mzw==", + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-country-map/-/legacy-plugin-chart-country-map-0.17.15.tgz", + "integrity": "sha512-e1ve2hm9BAXihOwLkJeZ46N7E0h3VUBOUjF4Q087WHC/n4Mwh+JEcD8/xWwrrQ+HLZ9QhaRQNeTc2EjuZjfTKA==", "dependencies": { - "@superset-ui/chart-controls": "0.17.14", - "@superset-ui/core": "0.17.14", + "@superset-ui/chart-controls": "0.17.15", + "@superset-ui/core": "0.17.15", "d3": "^3.5.17", "d3-array": "^2.0.3", "prop-types": "^15.6.2" @@ -16131,13 +16121,13 @@ } }, "node_modules/@superset-ui/legacy-plugin-chart-event-flow": { - "version": "0.17.14", - "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-event-flow/-/legacy-plugin-chart-event-flow-0.17.14.tgz", - "integrity": "sha512-A/4XpGJtBDQ1qEj5sS/wuMI4McF8XLW2h3gV6HNLga6H3Z2SV6OLb4mP15frQlCQ8Rmvf3DALT5hy5afnI2K4w==", + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-event-flow/-/legacy-plugin-chart-event-flow-0.17.15.tgz", + "integrity": "sha512-iYxkUysd/3Xvfi459ER3R+JKo5AZHiAf9YanXsh1W9UvWdfRgtFuef+lr+ZTUT2S7CMS8PsFqczs51DXyMha5w==", "dependencies": { "@data-ui/event-flow": "^0.0.84", - "@superset-ui/chart-controls": "0.17.14", - "@superset-ui/core": "0.17.14", + "@superset-ui/chart-controls": "0.17.15", + "@superset-ui/core": "0.17.15", "prop-types": "^15.6.2" }, "peerDependencies": { @@ -16145,12 +16135,12 @@ } }, "node_modules/@superset-ui/legacy-plugin-chart-force-directed": { - "version": "0.17.14", - "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-force-directed/-/legacy-plugin-chart-force-directed-0.17.14.tgz", - "integrity": "sha512-If1y45YKtQZbqc+XPJYtrgAZVuQgWgIjvQa9eQe09J+tAJQuLO9bo0SeqhuHRXUJQzge3AkItURdu+zdi/Z/3A==", + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-force-directed/-/legacy-plugin-chart-force-directed-0.17.15.tgz", + "integrity": "sha512-EB4oKcGDIJ5qoICOmXIsOKkyPNOHnwujp9iDcTEDjxDt70jBoLRtEnUjJDXvMW9Fx2a5RncIFczYfVG5imgw8Q==", "dependencies": { - "@superset-ui/chart-controls": "0.17.14", - "@superset-ui/core": "0.17.14", + "@superset-ui/chart-controls": "0.17.15", + "@superset-ui/core": "0.17.15", "d3": "^3.5.17", "prop-types": "^15.7.2" }, @@ -16159,12 +16149,12 @@ } }, "node_modules/@superset-ui/legacy-plugin-chart-heatmap": { - "version": "0.17.14", - "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-heatmap/-/legacy-plugin-chart-heatmap-0.17.14.tgz", - "integrity": "sha512-6DClVIQNUtmqIuhlq9JrSjm8OmcEp0YHN4yNT0yTxoV16LYA+T8SCcMt3nJB8DjpZwJLd/JKLcuE2ijxe8qGxQ==", + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-heatmap/-/legacy-plugin-chart-heatmap-0.17.15.tgz", + "integrity": "sha512-AXLMn8UE3UoDhAdAOiicSwAvQijWCPnTeBsKSy6s3iHMPpAgMzcm2ZhoNlc0r40cKs4zTzsytB91/l/1qoHqEw==", "dependencies": { - "@superset-ui/chart-controls": "0.17.14", - "@superset-ui/core": "0.17.14", + "@superset-ui/chart-controls": "0.17.15", + "@superset-ui/core": "0.17.15", "d3": "^3.5.17", "d3-svg-legend": "^1.x", "d3-tip": "^0.9.1", @@ -16172,14 +16162,14 @@ } }, "node_modules/@superset-ui/legacy-plugin-chart-histogram": { - "version": "0.17.14", - "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-histogram/-/legacy-plugin-chart-histogram-0.17.14.tgz", - "integrity": "sha512-zmcxm92huKldnDFj+Wi2L0Swpf4vPXO4Bx3rMxLguDVkmXpGl++axmaSl8V0Wkmvx/80cPYBWcwO/pUxY8m1XA==", + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-histogram/-/legacy-plugin-chart-histogram-0.17.15.tgz", + "integrity": "sha512-cyzbFKj5vOn+bp8Q/ZEDufuJ2G+7ujt+z5TUevVTWXcCDxbQ59XcDLsn7itfNzMmOyrLPNz786eG/yWdozqpgA==", "dependencies": { "@data-ui/histogram": "^0.0.84", "@data-ui/theme": "^0.0.84", - "@superset-ui/chart-controls": "0.17.14", - "@superset-ui/core": "0.17.14", + "@superset-ui/chart-controls": "0.17.15", + "@superset-ui/core": "0.17.15", "@vx/legend": "^0.0.198", "@vx/responsive": "^0.0.199", "@vx/scale": "^0.0.197", @@ -16248,12 +16238,12 @@ } }, "node_modules/@superset-ui/legacy-plugin-chart-horizon": { - "version": "0.17.14", - "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-horizon/-/legacy-plugin-chart-horizon-0.17.14.tgz", - "integrity": "sha512-qxO1SklS6UX3OzM8RmnXYDvhEwMeU7ptidZbknBBmyA66JUn2ewwym4kWnbi0QT+v5ModMZpiLiEme1ZmfExhA==", + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-horizon/-/legacy-plugin-chart-horizon-0.17.15.tgz", + "integrity": "sha512-8qW5gsP+hL0S0RESlwIuCsvroN3SJcCo8wtxS1NURrvUK85SBZx4pNzrVf+OMDBtb1WYzUge9JkF6I5G4vqLKQ==", "dependencies": { - "@superset-ui/chart-controls": "0.17.14", - "@superset-ui/core": "0.17.14", + "@superset-ui/chart-controls": "0.17.15", + "@superset-ui/core": "0.17.15", "d3-array": "^2.0.3", "d3-scale": "^3.0.1", "prop-types": "^15.6.2" @@ -16283,12 +16273,12 @@ } }, "node_modules/@superset-ui/legacy-plugin-chart-map-box": { - "version": "0.17.14", - "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-map-box/-/legacy-plugin-chart-map-box-0.17.14.tgz", - "integrity": "sha512-rOeybfBISuiWYtxsv52CPlgb0cAdjIFahS1W8Y8U8a0idYCNoypBmsa9WLrG4v+MBXCB2l4cgELMW8lurRBcCQ==", + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-map-box/-/legacy-plugin-chart-map-box-0.17.15.tgz", + "integrity": "sha512-2iYN5QTKyyPmXARo9B0pMaSvlyXnbfiw3BdS5I0kGzhGGf2XV03aM1wrsZ0gNJxXtIvFL9XJ3sa6qjKFo1vsQw==", "dependencies": { - "@superset-ui/chart-controls": "0.17.14", - "@superset-ui/core": "0.17.14", + "@superset-ui/chart-controls": "0.17.15", + "@superset-ui/core": "0.17.15", "immutable": "^3.8.2", "mapbox-gl": "^0.53.0", "prop-types": "^15.6.2", @@ -16309,12 +16299,12 @@ } }, "node_modules/@superset-ui/legacy-plugin-chart-paired-t-test": { - "version": "0.17.14", - "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-paired-t-test/-/legacy-plugin-chart-paired-t-test-0.17.14.tgz", - "integrity": "sha512-co4UG6dYMbZk1hhsI5JgbFHw3lLGmA2nG46T3nbn2ySJa23CYyQg8yCQHiJa/7SSKP0I5jFkmgD0JAOcvI9bHg==", + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-paired-t-test/-/legacy-plugin-chart-paired-t-test-0.17.15.tgz", + "integrity": "sha512-RO0L+p3E8FZ4e9cdJreFPsiXz0yhBX7eTar3rMjA6TWnCm1Lc/RQPjxi6EqiY39gbY/I8d4dYgBiFWCKdDiYJw==", "dependencies": { - "@superset-ui/chart-controls": "0.17.14", - "@superset-ui/core": "0.17.14", + "@superset-ui/chart-controls": "0.17.15", + "@superset-ui/core": "0.17.15", "distributions": "^1.0.0", "prop-types": "^15.6.2", "reactable": "^1.1.0" @@ -16324,12 +16314,12 @@ } }, "node_modules/@superset-ui/legacy-plugin-chart-parallel-coordinates": { - "version": "0.17.14", - "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-parallel-coordinates/-/legacy-plugin-chart-parallel-coordinates-0.17.14.tgz", - "integrity": "sha512-9xmCLtfHF9pYSEz4RwydhiXU3xNkw2ZirMGa4CTWSXVZlEWr794lnUNtWvlunFNz4JhJClKoTNiZXHIFa+kBzg==", + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-parallel-coordinates/-/legacy-plugin-chart-parallel-coordinates-0.17.15.tgz", + "integrity": "sha512-JT0mjItlu6T2Rs6nGzbS9z8BWeWmTok7TQT4JMonMjzqWNlGEPXLR89SnAIh3Nz8wZX6ilZ0YjteXTujnivErA==", "dependencies": { - "@superset-ui/chart-controls": "0.17.14", - "@superset-ui/core": "0.17.14", + "@superset-ui/chart-controls": "0.17.15", + "@superset-ui/core": "0.17.15", "d3": "^3.5.17", "prop-types": "^15.7.2" }, @@ -16338,12 +16328,12 @@ } }, "node_modules/@superset-ui/legacy-plugin-chart-partition": { - "version": "0.17.14", - "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-partition/-/legacy-plugin-chart-partition-0.17.14.tgz", - "integrity": "sha512-avTFsI7VWv9yxOkgAtl7ov85t4bZj57bjj8ivZrSyeWQOuQerHBVlNQr3Hb+C5uG4aUgjez5jXEOEB/iBbyfUA==", + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-partition/-/legacy-plugin-chart-partition-0.17.15.tgz", + "integrity": "sha512-xQM/Eg4XxlM6Fz1DWp34PzxB6PLFdFsoewXC2C4g5GZ9J+10Mm8RaWf43DxwaG06i+8aV4R3+WeefbkzGHp0Bw==", "dependencies": { - "@superset-ui/chart-controls": "0.17.14", - "@superset-ui/core": "0.17.14", + "@superset-ui/chart-controls": "0.17.15", + "@superset-ui/core": "0.17.15", "d3": "^3.5.17", "d3-hierarchy": "^1.1.8", "prop-types": "^15.6.2" @@ -16353,24 +16343,24 @@ } }, "node_modules/@superset-ui/legacy-plugin-chart-pivot-table": { - "version": "0.17.14", - "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-pivot-table/-/legacy-plugin-chart-pivot-table-0.17.14.tgz", - "integrity": "sha512-Os0rESFeXH3BpBc8XNuf0LH1zfhS+kLoI3WxLGxn7dD9M/gXhYjz05Rpby95rFDiPr6/CpJBJS4zrWlxDF3qIg==", + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-pivot-table/-/legacy-plugin-chart-pivot-table-0.17.15.tgz", + "integrity": "sha512-N+k1gHw5HbEGD8KrVogEz7O70y2ZjlUaLLbB63Fl4wfLeP4D9FkpEJmgWA3f7g2aQq3Wd1PD4ByQ2CD8wEtbNw==", "dependencies": { - "@superset-ui/chart-controls": "0.17.14", - "@superset-ui/core": "0.17.14", + "@superset-ui/chart-controls": "0.17.15", + "@superset-ui/core": "0.17.15", "d3": "^3.5.17", "datatables.net-bs": "^1.10.15", "prop-types": "^15.6.2" } }, "node_modules/@superset-ui/legacy-plugin-chart-rose": { - "version": "0.17.14", - "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-rose/-/legacy-plugin-chart-rose-0.17.14.tgz", - "integrity": "sha512-GpGfJx/aXKiqKo5TqpgzUA50OKKnzVq4rR11scByxVYazTmHOL37MQIqyf8n/mCixzCvh3jSQ64PFMyum/aFsQ==", + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-rose/-/legacy-plugin-chart-rose-0.17.15.tgz", + "integrity": "sha512-4VpZTpVyDmfko1n31q2jHDpZlIIMy2aM2INS5TxPpph245CevqYZcrLH3GDwIco119TcINlUD07s88k4MDFrEA==", "dependencies": { - "@superset-ui/chart-controls": "0.17.14", - "@superset-ui/core": "0.17.14", + "@superset-ui/chart-controls": "0.17.15", + "@superset-ui/core": "0.17.15", "d3": "^3.5.17", "nvd3": "1.8.6", "prop-types": "^15.6.2" @@ -16380,12 +16370,12 @@ } }, "node_modules/@superset-ui/legacy-plugin-chart-sankey": { - "version": "0.17.14", - "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-sankey/-/legacy-plugin-chart-sankey-0.17.14.tgz", - "integrity": "sha512-0tbnzevrQ3dp6YJ1oMa0+Ho+LxXke/thsnq6p4XbsRgujdJ98/1wMSkt7U4OAK+K8RW1eQYZiJivnJW6kisemw==", + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-sankey/-/legacy-plugin-chart-sankey-0.17.15.tgz", + "integrity": "sha512-KNMlpyWgYOEVo6vU2gcf8aWl8NpZMOoL4CzW45TkOd6wzwvtH0ZtU0M1PeGJVXzdgvha+NzxNBZ1adga7TMuhg==", "dependencies": { - "@superset-ui/chart-controls": "0.17.14", - "@superset-ui/core": "0.17.14", + "@superset-ui/chart-controls": "0.17.15", + "@superset-ui/core": "0.17.15", "d3": "^3.5.17", "d3-sankey": "^0.4.2", "prop-types": "^15.6.2" @@ -16395,47 +16385,47 @@ } }, "node_modules/@superset-ui/legacy-plugin-chart-sankey-loop": { - "version": "0.17.14", - "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-sankey-loop/-/legacy-plugin-chart-sankey-loop-0.17.14.tgz", - "integrity": "sha512-dnoEOMXhYiVU/dAL4P+Sd1ZsxwSUlqKMSj9TJtG2J7Kke8/GvTNz6/RDB4ndjB+DyKNFEfNhsFF13VKD0YvuRQ==", + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-sankey-loop/-/legacy-plugin-chart-sankey-loop-0.17.15.tgz", + "integrity": "sha512-U6glpKz+mEyeQbjNzZh2UqDJPGpEFadjOajPwWOOej3c383/KaHSntaydbN15ZD+m2f9QkvqQFCsP4kvfm0muA==", "dependencies": { - "@superset-ui/chart-controls": "0.17.14", - "@superset-ui/core": "0.17.14", + "@superset-ui/chart-controls": "0.17.15", + "@superset-ui/core": "0.17.15", "d3-sankey-diagram": "^0.7.3", "d3-selection": "^1.4.0", "prop-types": "^15.6.2" } }, "node_modules/@superset-ui/legacy-plugin-chart-sunburst": { - "version": "0.17.14", - "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-sunburst/-/legacy-plugin-chart-sunburst-0.17.14.tgz", - "integrity": "sha512-P8FW+wdrLN5uC/br52/ykLxKsdV12FCbjXyL+6LnVAYU9KWLttS+fhtsCTrOKf9od1cXUDuZKJ8KKt/ktRy9ag==", + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-sunburst/-/legacy-plugin-chart-sunburst-0.17.15.tgz", + "integrity": "sha512-Fb8arcmPapk2KYZyRM7DE7R4rBlZsSjzjIk8ObA10UJ30CsppzA/rEyYweXQd3ge6RUiBeIED81+1+CXnGUs8w==", "dependencies": { - "@superset-ui/chart-controls": "0.17.14", - "@superset-ui/core": "0.17.14", + "@superset-ui/chart-controls": "0.17.15", + "@superset-ui/core": "0.17.15", "d3": "^3.5.17", "prop-types": "^15.6.2" } }, "node_modules/@superset-ui/legacy-plugin-chart-treemap": { - "version": "0.17.14", - "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-treemap/-/legacy-plugin-chart-treemap-0.17.14.tgz", - "integrity": "sha512-T4qLlLUs/1PIT8Hf4iEMvR8h4Mbz8sWxLvvZTOPWtsgX/uqh11yMKNO4qR5O5kavVsOnepJI0msOWccRXNHQdQ==", + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-treemap/-/legacy-plugin-chart-treemap-0.17.15.tgz", + "integrity": "sha512-R0GrXtgYhJtMhRCoMGtPSby8Q+CdnPJiNU8/MoDxziyJwQtXzNEQFyACA7s4phlvDvC559KLJ3037vrc1/Sl6A==", "dependencies": { - "@superset-ui/chart-controls": "0.17.14", - "@superset-ui/core": "0.17.14", + "@superset-ui/chart-controls": "0.17.15", + "@superset-ui/core": "0.17.15", "d3-hierarchy": "^1.1.8", "d3-selection": "^1.4.0", "prop-types": "^15.6.2" } }, "node_modules/@superset-ui/legacy-plugin-chart-world-map": { - "version": "0.17.14", - "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-world-map/-/legacy-plugin-chart-world-map-0.17.14.tgz", - "integrity": "sha512-ZGYSMsmsY1QJpflqKxYHI+elq94cKLwizoID6wCV7/wHA0nAcqHiDyisRnzmOmS+x7msZx5VH0XbVoiyGAgp+g==", + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-world-map/-/legacy-plugin-chart-world-map-0.17.15.tgz", + "integrity": "sha512-Ts9F25wqhJZUQhSH47kkKQ/ab02n25vMf1QbU9oryRCJnwWc55xxNeT0lPbdr6FmjFew83+WdkSAL8137Onv7w==", "dependencies": { - "@superset-ui/chart-controls": "0.17.14", - "@superset-ui/core": "0.17.14", + "@superset-ui/chart-controls": "0.17.15", + "@superset-ui/core": "0.17.15", "d3": "^3.5.17", "d3-array": "^2.4.0", "d3-color": "^1.4.1", @@ -16460,13 +16450,13 @@ "integrity": "sha512-p2sTHSLCJI2QKunbGb7ocOh7DgTAn8IrLx21QRc/BSnodXM4sv6aLQlnfpvehFMLZEfBc6g9pH9SWQccFYfJ9Q==" }, "node_modules/@superset-ui/legacy-preset-chart-big-number": { - "version": "0.17.14", - "resolved": "https://registry.npmjs.org/@superset-ui/legacy-preset-chart-big-number/-/legacy-preset-chart-big-number-0.17.14.tgz", - "integrity": "sha512-4zPlW2cLHr0PZBc15/3IdJshLG2HfR29qkiS8aEwiUkuyqt/6leaVldaLBrHFqFRJQTF5to0gf+H/X9r5ceV2g==", + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@superset-ui/legacy-preset-chart-big-number/-/legacy-preset-chart-big-number-0.17.15.tgz", + "integrity": "sha512-hYB3LRgzhfSecsqM+0MTSjc6hjpOGuGEdLBTcPW4hli6UODoy+XUG0o+22LxFBW/sYqGgWIsVi0mF7pseJnAbQ==", "dependencies": { "@data-ui/xy-chart": "^0.0.84", - "@superset-ui/chart-controls": "0.17.14", - "@superset-ui/core": "0.17.14", + "@superset-ui/chart-controls": "0.17.15", + "@superset-ui/core": "0.17.15", "@types/d3-color": "^1.2.2", "@types/shortid": "^0.0.29", "d3-color": "^1.2.3", @@ -16502,13 +16492,13 @@ } }, "node_modules/@superset-ui/legacy-preset-chart-nvd3": { - "version": "0.17.14", - "resolved": "https://registry.npmjs.org/@superset-ui/legacy-preset-chart-nvd3/-/legacy-preset-chart-nvd3-0.17.14.tgz", - "integrity": "sha512-0Fxh4RfT8x+jXrHp39xMRW8MCmMQvjxykTrBwRAeykGBsueGC5aeqOieCk1OTDtbmn+vgw7cUKUyR22JegZlug==", + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@superset-ui/legacy-preset-chart-nvd3/-/legacy-preset-chart-nvd3-0.17.15.tgz", + "integrity": "sha512-skUHQ3i9AhfPNHofkes49ZnaBZcbr5MNyXxvT8CiGa+MP80n+vgt+i5V12kIwxPWRIFwIUpcNxDRtlfE4PjpGg==", "dependencies": { "@data-ui/xy-chart": "^0.0.84", - "@superset-ui/chart-controls": "0.17.14", - "@superset-ui/core": "0.17.14", + "@superset-ui/chart-controls": "0.17.15", + "@superset-ui/core": "0.17.15", "d3": "^3.5.17", "d3-tip": "^0.9.1", "dompurify": "^2.0.6", @@ -16525,12 +16515,12 @@ } }, "node_modules/@superset-ui/plugin-chart-echarts": { - "version": "0.17.14", - "resolved": "https://registry.npmjs.org/@superset-ui/plugin-chart-echarts/-/plugin-chart-echarts-0.17.14.tgz", - "integrity": "sha512-WwK6L4G+9bCUFOW1LRrNupSQP0qo8u1uQsjA1ZjLIxZmJr765ltFqgDDOVCZRtzyuhB6uXGs6nWkoytoMIZ1mQ==", + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@superset-ui/plugin-chart-echarts/-/plugin-chart-echarts-0.17.15.tgz", + "integrity": "sha512-wryWvEcKd4MaUvdNMhpCwZ/CY7y38HXnH1muHnNEE4d2PoHKwMN5WXqVQYnE1c90ljTih3kbR3ALPVPSJWGG4g==", "dependencies": { - "@superset-ui/chart-controls": "0.17.14", - "@superset-ui/core": "0.17.14", + "@superset-ui/chart-controls": "0.17.15", + "@superset-ui/core": "0.17.15", "@types/mathjs": "^6.0.7", "d3-array": "^1.2.0", "echarts": "^5.0.2", @@ -16541,13 +16531,13 @@ } }, "node_modules/@superset-ui/plugin-chart-table": { - "version": "0.17.14", - "resolved": "https://registry.npmjs.org/@superset-ui/plugin-chart-table/-/plugin-chart-table-0.17.14.tgz", - "integrity": "sha512-RjXt95yUmBJJ5P1xk3fH1orKEqBYFPlUdcDFQuDnv0R6E3V3K09ObT/umJ+jXqZ+XPBMfbbUivaIJrpT2S38Uw==", + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@superset-ui/plugin-chart-table/-/plugin-chart-table-0.17.15.tgz", + "integrity": "sha512-JT8gw16389RF/lY27CchnL0Yo7/U/o6HrWkz46CMGnFnHbY0fq+aqZd7Rqqz0RbTkRS3paWeZdy2nf9MMYsa1g==", "dependencies": { "@emotion/core": "^10.0.28", - "@superset-ui/chart-controls": "0.17.14", - "@superset-ui/core": "0.17.14", + "@superset-ui/chart-controls": "0.17.15", + "@superset-ui/core": "0.17.15", "@types/d3-array": "^2.0.0", "@types/react-table": "^7.0.19", "d3-array": "^2.4.0", @@ -16573,12 +16563,12 @@ } }, "node_modules/@superset-ui/plugin-chart-word-cloud": { - "version": "0.17.14", - "resolved": "https://registry.npmjs.org/@superset-ui/plugin-chart-word-cloud/-/plugin-chart-word-cloud-0.17.14.tgz", - "integrity": "sha512-1WZam4x8rNrdtqCxUNami0jijKv2OAvX2XJF7IXq+Hb9+8PXBEHCRgwUIzf3iOjdujtFE+INHcQyeAmJV4uEXA==", + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@superset-ui/plugin-chart-word-cloud/-/plugin-chart-word-cloud-0.17.15.tgz", + "integrity": "sha512-3amMqmF5+HntzcZAP+TdAEtlBvQbq4VZRAwon/+IHcAnHnBlSYNCdjaI3lU/7udIFrMtmkMcPeaQE2lDbjuW3g==", "dependencies": { - "@superset-ui/chart-controls": "0.17.14", - "@superset-ui/core": "0.17.14", + "@superset-ui/chart-controls": "0.17.15", + "@superset-ui/core": "0.17.15", "@types/d3-cloud": "^1.2.1", "@types/d3-scale": "^2.0.2", "d3-cloud": "^1.2.5", @@ -16612,14 +16602,14 @@ } }, "node_modules/@superset-ui/preset-chart-xy": { - "version": "0.17.14", - "resolved": "https://registry.npmjs.org/@superset-ui/preset-chart-xy/-/preset-chart-xy-0.17.14.tgz", - "integrity": "sha512-jYKzITop6knzh9262ZwsYMv2URFB9s69wx6n+wxUqzj7wQgpOARtmyo43tGU0UPkYAJD5c70jbROlyUD/Xr5cg==", + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@superset-ui/preset-chart-xy/-/preset-chart-xy-0.17.15.tgz", + "integrity": "sha512-6V2oIIuYcfHWRcPRuiHdMv7HpD7XdpuB08zDJADIFyV0QRM0RVpGW9kee3j8KyjecXIVtMvNyI81c/2P/kwEdg==", "dependencies": { "@data-ui/theme": "^0.0.84", "@data-ui/xy-chart": "^0.0.84", - "@superset-ui/chart-controls": "0.17.14", - "@superset-ui/core": "0.17.14", + "@superset-ui/chart-controls": "0.17.15", + "@superset-ui/core": "0.17.15", "@vx/axis": "^0.0.198", "@vx/legend": "^0.0.198", "@vx/scale": "^0.0.197", @@ -22011,7 +22001,6 @@ "@types/node": "*", "anymatch": "^3.0.3", "fb-watchman": "^2.0.0", - "fsevents": "^2.1.2", "graceful-fs": "^4.2.4", "jest-regex-util": "^26.0.0", "jest-serializer": "^26.6.2", @@ -23825,7 +23814,6 @@ "anymatch": "^2.0.0", "async-each": "^1.0.0", "braces": "^2.3.0", - "fsevents": "^1.2.2", "glob-parent": "^3.1.0", "inherits": "^2.0.1", "is-binary-path": "^1.0.0", @@ -24641,7 +24629,6 @@ "integrity": "sha512-gnB85c3MGC7Nm9I/FkiasNBOKjOiO1RNuXXarQms37q4QMpWdlbBgD/VnOStA2faG1dpXMv31RFApjX1/QdgWQ==", "dev": true, "dependencies": { - "colors": "^1.1.2", "object-assign": "^4.1.0", "string-width": "^4.2.0" }, @@ -28258,8 +28245,7 @@ "esprima": "^3.1.3", "estraverse": "^4.2.0", "esutils": "^2.0.2", - "optionator": "^0.8.1", - "source-map": "~0.6.1" + "optionator": "^0.8.1" }, "bin": { "escodegen": "bin/escodegen.js", @@ -32261,7 +32247,6 @@ "version": "4.5.2", "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-4.5.2.tgz", "integrity": "sha512-q5oYdzjKUIPQVjOosjgvCHQOv9Ett9CYYHlgvJeXG0qQvdSojnBq4vAdQBwn1+yGveAwHCoe/rMR86ozX3+c2A==", - "dev": true, "dependencies": { "@types/html-minifier-terser": "^5.0.0", "@types/tapable": "^1.0.5", @@ -34351,7 +34336,6 @@ "@types/node": "*", "anymatch": "^3.0.3", "fb-watchman": "^2.0.0", - "fsevents": "^2.1.2", "graceful-fs": "^4.2.4", "jest-regex-util": "^26.0.0", "jest-serializer": "^26.6.2", @@ -35192,7 +35176,6 @@ "@jest/types": "^24.9.0", "anymatch": "^2.0.0", "fb-watchman": "^2.0.0", - "fsevents": "^1.2.7", "graceful-fs": "^4.1.15", "invariant": "^2.2.4", "jest-serializer": "^24.9.0", @@ -35966,7 +35949,6 @@ "@types/node": "*", "anymatch": "^3.0.3", "fb-watchman": "^2.0.0", - "fsevents": "^2.1.2", "graceful-fs": "^4.2.4", "jest-regex-util": "^26.0.0", "jest-serializer": "^26.6.2", @@ -37613,7 +37595,6 @@ "@types/node": "*", "anymatch": "^3.0.3", "fb-watchman": "^2.0.0", - "fsevents": "^2.1.2", "graceful-fs": "^4.2.4", "jest-regex-util": "^26.0.0", "jest-serializer": "^26.6.2", @@ -37936,7 +37917,6 @@ "@types/node": "*", "anymatch": "^3.0.3", "fb-watchman": "^2.0.0", - "fsevents": "^2.1.2", "graceful-fs": "^4.2.4", "jest-regex-util": "^26.0.0", "jest-serializer": "^26.6.2", @@ -38307,7 +38287,6 @@ "@types/node": "*", "anymatch": "^3.0.3", "fb-watchman": "^2.0.0", - "fsevents": "^2.1.2", "graceful-fs": "^4.2.4", "jest-regex-util": "^26.0.0", "jest-serializer": "^26.6.2", @@ -39468,8 +39447,7 @@ "esprima": "^4.0.1", "estraverse": "^4.2.0", "esutils": "^2.0.2", - "optionator": "^0.8.1", - "source-map": "~0.6.1" + "optionator": "^0.8.1" }, "bin": { "escodegen": "bin/escodegen.js", @@ -39990,11 +39968,8 @@ "dependencies": { "errno": "^0.1.1", "graceful-fs": "^4.1.2", - "image-size": "~0.5.0", "make-dir": "^2.1.0", "mime": "^1.4.1", - "native-request": "^1.0.5", - "source-map": "~0.6.0", "tslib": "^1.10.0" }, "bin": { @@ -45692,9 +45667,6 @@ "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.23.0.tgz", "integrity": "sha512-c29LVsqOaLbBHuIbsTxaKENh1N2EQBOHaWv7gkHN4dgRbxSREqDnDbtFJYdpPauS4YCplMSNCABQ6Eeor69bAA==", "dev": true, - "dependencies": { - "clipboard": "^2.0.0" - }, "optionalDependencies": { "clipboard": "^2.0.0" } @@ -47295,34 +47267,6 @@ "node": ">=0.8.0" } }, - "node_modules/react-dev-utils/node_modules/chokidar": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz", - "integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==", - "dev": true, - "dependencies": { - "anymatch": "~3.1.1", - "braces": "~3.0.2", - "fsevents": "~2.3.1", - "glob-parent": "~5.1.0", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.5.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.1" - } - }, - "node_modules/react-dev-utils/node_modules/cli-width": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz", - "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==", - "dev": true - }, "node_modules/react-dev-utils/node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -48568,9 +48512,6 @@ "version": "1.22.0", "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.22.0.tgz", "integrity": "sha512-lLJ/Wt9yy0AiSYBf212kK3mM5L8ycwlyTlSxHBAneXLR0nzFMlZ5y7riFPF3E33zXOF2IH95xdY5jIyZbM9z/w==", - "dependencies": { - "clipboard": "^2.0.0" - }, "optionalDependencies": { "clipboard": "^2.0.0" } @@ -51491,8 +51432,7 @@ "esprima": "^4.0.1", "estraverse": "^4.2.0", "esutils": "^2.0.2", - "optionator": "^0.8.1", - "source-map": "~0.6.1" + "optionator": "^0.8.1" }, "bin": { "escodegen": "bin/escodegen.js", @@ -54890,10 +54830,8 @@ "integrity": "sha512-aWAgTW4MoSJzZPAicljkO1hsi1oKj/RRq/OJQh2PKI2UKL04c2Bs+MBOB+BBABHTXJpf9mCwHN7ANCvYsvY2sg==", "dev": true, "dependencies": { - "chokidar": "^3.4.1", "graceful-fs": "^4.1.2", - "neo-async": "^2.5.0", - "watchpack-chokidar2": "^2.0.0" + "neo-async": "^2.5.0" }, "optionalDependencies": { "chokidar": "^3.4.1", @@ -55807,7 +55745,6 @@ "anymatch": "^2.0.0", "async-each": "^1.0.1", "braces": "^2.3.2", - "fsevents": "^1.2.7", "glob-parent": "^3.1.0", "inherits": "^2.0.3", "is-binary-path": "^1.0.0", @@ -72011,19 +71948,19 @@ } }, "@superset-ui/chart-controls": { - "version": "0.17.14", - "resolved": "https://registry.npmjs.org/@superset-ui/chart-controls/-/chart-controls-0.17.14.tgz", - "integrity": "sha512-YY9Gn40bRbZr4ivCQcP8E+9+maWcpoENtCQm3dPNgwVaa8wmZ03dR+VMkIsM5G3VWOHl6T+nSCyo5R/qTFlh5g==", + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@superset-ui/chart-controls/-/chart-controls-0.17.15.tgz", + "integrity": "sha512-D0KoG5QvE3gxDnnN3lrLaQOXLQOCk8HBfQLXqAafGJDxIjatfAopty+7lz6Yzu859/OCBJK5AJybLm7fW5JtTg==", "requires": { - "@superset-ui/core": "0.17.14", + "@superset-ui/core": "0.17.15", "lodash": "^4.17.15", "prop-types": "^15.7.2" } }, "@superset-ui/core": { - "version": "0.17.14", - "resolved": "https://registry.npmjs.org/@superset-ui/core/-/core-0.17.14.tgz", - "integrity": "sha512-wdzCaDG8DO02wheBWyVd1q5EUV0RuEUjVSNKVm0aiZzBxcv95mlS62mgN24VdxDiL1Zca1+MJ4/bCz/K3wZ08w==", + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@superset-ui/core/-/core-0.17.15.tgz", + "integrity": "sha512-6SVtSQgdZVnhfpEwPOLmQhePsET8jOKjuUJ5kY6OCTk8e7R2ghFsHKwiCdJa5T7/+F7ghQ2kKDzns1VQyhx+oA==", "requires": { "@babel/runtime": "^7.1.2", "@emotion/core": "^10.0.28", @@ -72106,12 +72043,12 @@ } }, "@superset-ui/legacy-plugin-chart-calendar": { - "version": "0.17.14", - "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-calendar/-/legacy-plugin-chart-calendar-0.17.14.tgz", - "integrity": "sha512-+xykD1FdquEfcmSvtDkR/NuiPlu6QYEIFLZ3H41U/AdzQb5n+kkgCG0M883qdfkQlbaGsZtjnjIoqotWclmwMQ==", + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-calendar/-/legacy-plugin-chart-calendar-0.17.15.tgz", + "integrity": "sha512-GIDY1ihvS24tV7IQYQKZJQaxlOvQ45RGfPMhi9bOmphVaV1X/sWwlBZK0LbL00kAzQJyOgvC+tE1+8y4ZoHrvg==", "requires": { - "@superset-ui/chart-controls": "0.17.14", - "@superset-ui/core": "0.17.14", + "@superset-ui/chart-controls": "0.17.15", + "@superset-ui/core": "0.17.15", "d3-array": "^2.0.3", "d3-selection": "^1.4.0", "d3-tip": "^0.9.1", @@ -72129,24 +72066,24 @@ } }, "@superset-ui/legacy-plugin-chart-chord": { - "version": "0.17.14", - "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-chord/-/legacy-plugin-chart-chord-0.17.14.tgz", - "integrity": "sha512-QNeUnUR9Z/TDb2Q+lYIzUtCyKVM/tG0iLceE6kWHtlxCH3QI0aw43bhDS6wK9LLbBzURQezGStxLeJaIwmsmuA==", + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-chord/-/legacy-plugin-chart-chord-0.17.15.tgz", + "integrity": "sha512-1coV7lCw5T1AnaDaRVaHWvwkCZDJFLHItHLby0dsnQ8tYgBTVOocC7GC34EESmirwfYSh/yutAV8uyNU4g3MMA==", "requires": { - "@superset-ui/chart-controls": "0.17.14", - "@superset-ui/core": "0.17.14", + "@superset-ui/chart-controls": "0.17.15", + "@superset-ui/core": "0.17.15", "d3": "^3.5.17", "prop-types": "^15.6.2", "react": "^16.13.1" } }, "@superset-ui/legacy-plugin-chart-country-map": { - "version": "0.17.14", - "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-country-map/-/legacy-plugin-chart-country-map-0.17.14.tgz", - "integrity": "sha512-qtjWyxPwWNEhNzXxx1h81u7DBdr44UP41JPHRkLsWoWQweecR9Q8nWCSFEVcE9+7ehAxGigtbXEHVoix4L1mzw==", + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-country-map/-/legacy-plugin-chart-country-map-0.17.15.tgz", + "integrity": "sha512-e1ve2hm9BAXihOwLkJeZ46N7E0h3VUBOUjF4Q087WHC/n4Mwh+JEcD8/xWwrrQ+HLZ9QhaRQNeTc2EjuZjfTKA==", "requires": { - "@superset-ui/chart-controls": "0.17.14", - "@superset-ui/core": "0.17.14", + "@superset-ui/chart-controls": "0.17.15", + "@superset-ui/core": "0.17.15", "d3": "^3.5.17", "d3-array": "^2.0.3", "prop-types": "^15.6.2" @@ -72163,34 +72100,34 @@ } }, "@superset-ui/legacy-plugin-chart-event-flow": { - "version": "0.17.14", - "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-event-flow/-/legacy-plugin-chart-event-flow-0.17.14.tgz", - "integrity": "sha512-A/4XpGJtBDQ1qEj5sS/wuMI4McF8XLW2h3gV6HNLga6H3Z2SV6OLb4mP15frQlCQ8Rmvf3DALT5hy5afnI2K4w==", + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-event-flow/-/legacy-plugin-chart-event-flow-0.17.15.tgz", + "integrity": "sha512-iYxkUysd/3Xvfi459ER3R+JKo5AZHiAf9YanXsh1W9UvWdfRgtFuef+lr+ZTUT2S7CMS8PsFqczs51DXyMha5w==", "requires": { "@data-ui/event-flow": "^0.0.84", - "@superset-ui/chart-controls": "0.17.14", - "@superset-ui/core": "0.17.14", + "@superset-ui/chart-controls": "0.17.15", + "@superset-ui/core": "0.17.15", "prop-types": "^15.6.2" } }, "@superset-ui/legacy-plugin-chart-force-directed": { - "version": "0.17.14", - "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-force-directed/-/legacy-plugin-chart-force-directed-0.17.14.tgz", - "integrity": "sha512-If1y45YKtQZbqc+XPJYtrgAZVuQgWgIjvQa9eQe09J+tAJQuLO9bo0SeqhuHRXUJQzge3AkItURdu+zdi/Z/3A==", + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-force-directed/-/legacy-plugin-chart-force-directed-0.17.15.tgz", + "integrity": "sha512-EB4oKcGDIJ5qoICOmXIsOKkyPNOHnwujp9iDcTEDjxDt70jBoLRtEnUjJDXvMW9Fx2a5RncIFczYfVG5imgw8Q==", "requires": { - "@superset-ui/chart-controls": "0.17.14", - "@superset-ui/core": "0.17.14", + "@superset-ui/chart-controls": "0.17.15", + "@superset-ui/core": "0.17.15", "d3": "^3.5.17", "prop-types": "^15.7.2" } }, "@superset-ui/legacy-plugin-chart-heatmap": { - "version": "0.17.14", - "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-heatmap/-/legacy-plugin-chart-heatmap-0.17.14.tgz", - "integrity": "sha512-6DClVIQNUtmqIuhlq9JrSjm8OmcEp0YHN4yNT0yTxoV16LYA+T8SCcMt3nJB8DjpZwJLd/JKLcuE2ijxe8qGxQ==", + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-heatmap/-/legacy-plugin-chart-heatmap-0.17.15.tgz", + "integrity": "sha512-AXLMn8UE3UoDhAdAOiicSwAvQijWCPnTeBsKSy6s3iHMPpAgMzcm2ZhoNlc0r40cKs4zTzsytB91/l/1qoHqEw==", "requires": { - "@superset-ui/chart-controls": "0.17.14", - "@superset-ui/core": "0.17.14", + "@superset-ui/chart-controls": "0.17.15", + "@superset-ui/core": "0.17.15", "d3": "^3.5.17", "d3-svg-legend": "^1.x", "d3-tip": "^0.9.1", @@ -72198,14 +72135,14 @@ } }, "@superset-ui/legacy-plugin-chart-histogram": { - "version": "0.17.14", - "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-histogram/-/legacy-plugin-chart-histogram-0.17.14.tgz", - "integrity": "sha512-zmcxm92huKldnDFj+Wi2L0Swpf4vPXO4Bx3rMxLguDVkmXpGl++axmaSl8V0Wkmvx/80cPYBWcwO/pUxY8m1XA==", + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-histogram/-/legacy-plugin-chart-histogram-0.17.15.tgz", + "integrity": "sha512-cyzbFKj5vOn+bp8Q/ZEDufuJ2G+7ujt+z5TUevVTWXcCDxbQ59XcDLsn7itfNzMmOyrLPNz786eG/yWdozqpgA==", "requires": { "@data-ui/histogram": "^0.0.84", "@data-ui/theme": "^0.0.84", - "@superset-ui/chart-controls": "0.17.14", - "@superset-ui/core": "0.17.14", + "@superset-ui/chart-controls": "0.17.15", + "@superset-ui/core": "0.17.15", "@vx/legend": "^0.0.198", "@vx/responsive": "^0.0.199", "@vx/scale": "^0.0.197", @@ -72273,12 +72210,12 @@ } }, "@superset-ui/legacy-plugin-chart-horizon": { - "version": "0.17.14", - "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-horizon/-/legacy-plugin-chart-horizon-0.17.14.tgz", - "integrity": "sha512-qxO1SklS6UX3OzM8RmnXYDvhEwMeU7ptidZbknBBmyA66JUn2ewwym4kWnbi0QT+v5ModMZpiLiEme1ZmfExhA==", + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-horizon/-/legacy-plugin-chart-horizon-0.17.15.tgz", + "integrity": "sha512-8qW5gsP+hL0S0RESlwIuCsvroN3SJcCo8wtxS1NURrvUK85SBZx4pNzrVf+OMDBtb1WYzUge9JkF6I5G4vqLKQ==", "requires": { - "@superset-ui/chart-controls": "0.17.14", - "@superset-ui/core": "0.17.14", + "@superset-ui/chart-controls": "0.17.15", + "@superset-ui/core": "0.17.15", "d3-array": "^2.0.3", "d3-scale": "^3.0.1", "prop-types": "^15.6.2" @@ -72307,12 +72244,12 @@ } }, "@superset-ui/legacy-plugin-chart-map-box": { - "version": "0.17.14", - "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-map-box/-/legacy-plugin-chart-map-box-0.17.14.tgz", - "integrity": "sha512-rOeybfBISuiWYtxsv52CPlgb0cAdjIFahS1W8Y8U8a0idYCNoypBmsa9WLrG4v+MBXCB2l4cgELMW8lurRBcCQ==", + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-map-box/-/legacy-plugin-chart-map-box-0.17.15.tgz", + "integrity": "sha512-2iYN5QTKyyPmXARo9B0pMaSvlyXnbfiw3BdS5I0kGzhGGf2XV03aM1wrsZ0gNJxXtIvFL9XJ3sa6qjKFo1vsQw==", "requires": { - "@superset-ui/chart-controls": "0.17.14", - "@superset-ui/core": "0.17.14", + "@superset-ui/chart-controls": "0.17.15", + "@superset-ui/core": "0.17.15", "immutable": "^3.8.2", "mapbox-gl": "^0.53.0", "prop-types": "^15.6.2", @@ -72329,118 +72266,118 @@ } }, "@superset-ui/legacy-plugin-chart-paired-t-test": { - "version": "0.17.14", - "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-paired-t-test/-/legacy-plugin-chart-paired-t-test-0.17.14.tgz", - "integrity": "sha512-co4UG6dYMbZk1hhsI5JgbFHw3lLGmA2nG46T3nbn2ySJa23CYyQg8yCQHiJa/7SSKP0I5jFkmgD0JAOcvI9bHg==", + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-paired-t-test/-/legacy-plugin-chart-paired-t-test-0.17.15.tgz", + "integrity": "sha512-RO0L+p3E8FZ4e9cdJreFPsiXz0yhBX7eTar3rMjA6TWnCm1Lc/RQPjxi6EqiY39gbY/I8d4dYgBiFWCKdDiYJw==", "requires": { - "@superset-ui/chart-controls": "0.17.14", - "@superset-ui/core": "0.17.14", + "@superset-ui/chart-controls": "0.17.15", + "@superset-ui/core": "0.17.15", "distributions": "^1.0.0", "prop-types": "^15.6.2", "reactable": "^1.1.0" } }, "@superset-ui/legacy-plugin-chart-parallel-coordinates": { - "version": "0.17.14", - "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-parallel-coordinates/-/legacy-plugin-chart-parallel-coordinates-0.17.14.tgz", - "integrity": "sha512-9xmCLtfHF9pYSEz4RwydhiXU3xNkw2ZirMGa4CTWSXVZlEWr794lnUNtWvlunFNz4JhJClKoTNiZXHIFa+kBzg==", + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-parallel-coordinates/-/legacy-plugin-chart-parallel-coordinates-0.17.15.tgz", + "integrity": "sha512-JT0mjItlu6T2Rs6nGzbS9z8BWeWmTok7TQT4JMonMjzqWNlGEPXLR89SnAIh3Nz8wZX6ilZ0YjteXTujnivErA==", "requires": { - "@superset-ui/chart-controls": "0.17.14", - "@superset-ui/core": "0.17.14", + "@superset-ui/chart-controls": "0.17.15", + "@superset-ui/core": "0.17.15", "d3": "^3.5.17", "prop-types": "^15.7.2" } }, "@superset-ui/legacy-plugin-chart-partition": { - "version": "0.17.14", - "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-partition/-/legacy-plugin-chart-partition-0.17.14.tgz", - "integrity": "sha512-avTFsI7VWv9yxOkgAtl7ov85t4bZj57bjj8ivZrSyeWQOuQerHBVlNQr3Hb+C5uG4aUgjez5jXEOEB/iBbyfUA==", + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-partition/-/legacy-plugin-chart-partition-0.17.15.tgz", + "integrity": "sha512-xQM/Eg4XxlM6Fz1DWp34PzxB6PLFdFsoewXC2C4g5GZ9J+10Mm8RaWf43DxwaG06i+8aV4R3+WeefbkzGHp0Bw==", "requires": { - "@superset-ui/chart-controls": "0.17.14", - "@superset-ui/core": "0.17.14", + "@superset-ui/chart-controls": "0.17.15", + "@superset-ui/core": "0.17.15", "d3": "^3.5.17", "d3-hierarchy": "^1.1.8", "prop-types": "^15.6.2" } }, "@superset-ui/legacy-plugin-chart-pivot-table": { - "version": "0.17.14", - "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-pivot-table/-/legacy-plugin-chart-pivot-table-0.17.14.tgz", - "integrity": "sha512-Os0rESFeXH3BpBc8XNuf0LH1zfhS+kLoI3WxLGxn7dD9M/gXhYjz05Rpby95rFDiPr6/CpJBJS4zrWlxDF3qIg==", + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-pivot-table/-/legacy-plugin-chart-pivot-table-0.17.15.tgz", + "integrity": "sha512-N+k1gHw5HbEGD8KrVogEz7O70y2ZjlUaLLbB63Fl4wfLeP4D9FkpEJmgWA3f7g2aQq3Wd1PD4ByQ2CD8wEtbNw==", "requires": { - "@superset-ui/chart-controls": "0.17.14", - "@superset-ui/core": "0.17.14", + "@superset-ui/chart-controls": "0.17.15", + "@superset-ui/core": "0.17.15", "d3": "^3.5.17", "datatables.net-bs": "^1.10.15", "prop-types": "^15.6.2" } }, "@superset-ui/legacy-plugin-chart-rose": { - "version": "0.17.14", - "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-rose/-/legacy-plugin-chart-rose-0.17.14.tgz", - "integrity": "sha512-GpGfJx/aXKiqKo5TqpgzUA50OKKnzVq4rR11scByxVYazTmHOL37MQIqyf8n/mCixzCvh3jSQ64PFMyum/aFsQ==", + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-rose/-/legacy-plugin-chart-rose-0.17.15.tgz", + "integrity": "sha512-4VpZTpVyDmfko1n31q2jHDpZlIIMy2aM2INS5TxPpph245CevqYZcrLH3GDwIco119TcINlUD07s88k4MDFrEA==", "requires": { - "@superset-ui/chart-controls": "0.17.14", - "@superset-ui/core": "0.17.14", + "@superset-ui/chart-controls": "0.17.15", + "@superset-ui/core": "0.17.15", "d3": "^3.5.17", "nvd3": "1.8.6", "prop-types": "^15.6.2" } }, "@superset-ui/legacy-plugin-chart-sankey": { - "version": "0.17.14", - "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-sankey/-/legacy-plugin-chart-sankey-0.17.14.tgz", - "integrity": "sha512-0tbnzevrQ3dp6YJ1oMa0+Ho+LxXke/thsnq6p4XbsRgujdJ98/1wMSkt7U4OAK+K8RW1eQYZiJivnJW6kisemw==", + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-sankey/-/legacy-plugin-chart-sankey-0.17.15.tgz", + "integrity": "sha512-KNMlpyWgYOEVo6vU2gcf8aWl8NpZMOoL4CzW45TkOd6wzwvtH0ZtU0M1PeGJVXzdgvha+NzxNBZ1adga7TMuhg==", "requires": { - "@superset-ui/chart-controls": "0.17.14", - "@superset-ui/core": "0.17.14", + "@superset-ui/chart-controls": "0.17.15", + "@superset-ui/core": "0.17.15", "d3": "^3.5.17", "d3-sankey": "^0.4.2", "prop-types": "^15.6.2" } }, "@superset-ui/legacy-plugin-chart-sankey-loop": { - "version": "0.17.14", - "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-sankey-loop/-/legacy-plugin-chart-sankey-loop-0.17.14.tgz", - "integrity": "sha512-dnoEOMXhYiVU/dAL4P+Sd1ZsxwSUlqKMSj9TJtG2J7Kke8/GvTNz6/RDB4ndjB+DyKNFEfNhsFF13VKD0YvuRQ==", + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-sankey-loop/-/legacy-plugin-chart-sankey-loop-0.17.15.tgz", + "integrity": "sha512-U6glpKz+mEyeQbjNzZh2UqDJPGpEFadjOajPwWOOej3c383/KaHSntaydbN15ZD+m2f9QkvqQFCsP4kvfm0muA==", "requires": { - "@superset-ui/chart-controls": "0.17.14", - "@superset-ui/core": "0.17.14", + "@superset-ui/chart-controls": "0.17.15", + "@superset-ui/core": "0.17.15", "d3-sankey-diagram": "^0.7.3", "d3-selection": "^1.4.0", "prop-types": "^15.6.2" } }, "@superset-ui/legacy-plugin-chart-sunburst": { - "version": "0.17.14", - "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-sunburst/-/legacy-plugin-chart-sunburst-0.17.14.tgz", - "integrity": "sha512-P8FW+wdrLN5uC/br52/ykLxKsdV12FCbjXyL+6LnVAYU9KWLttS+fhtsCTrOKf9od1cXUDuZKJ8KKt/ktRy9ag==", + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-sunburst/-/legacy-plugin-chart-sunburst-0.17.15.tgz", + "integrity": "sha512-Fb8arcmPapk2KYZyRM7DE7R4rBlZsSjzjIk8ObA10UJ30CsppzA/rEyYweXQd3ge6RUiBeIED81+1+CXnGUs8w==", "requires": { - "@superset-ui/chart-controls": "0.17.14", - "@superset-ui/core": "0.17.14", + "@superset-ui/chart-controls": "0.17.15", + "@superset-ui/core": "0.17.15", "d3": "^3.5.17", "prop-types": "^15.6.2" } }, "@superset-ui/legacy-plugin-chart-treemap": { - "version": "0.17.14", - "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-treemap/-/legacy-plugin-chart-treemap-0.17.14.tgz", - "integrity": "sha512-T4qLlLUs/1PIT8Hf4iEMvR8h4Mbz8sWxLvvZTOPWtsgX/uqh11yMKNO4qR5O5kavVsOnepJI0msOWccRXNHQdQ==", + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-treemap/-/legacy-plugin-chart-treemap-0.17.15.tgz", + "integrity": "sha512-R0GrXtgYhJtMhRCoMGtPSby8Q+CdnPJiNU8/MoDxziyJwQtXzNEQFyACA7s4phlvDvC559KLJ3037vrc1/Sl6A==", "requires": { - "@superset-ui/chart-controls": "0.17.14", - "@superset-ui/core": "0.17.14", + "@superset-ui/chart-controls": "0.17.15", + "@superset-ui/core": "0.17.15", "d3-hierarchy": "^1.1.8", "d3-selection": "^1.4.0", "prop-types": "^15.6.2" } }, "@superset-ui/legacy-plugin-chart-world-map": { - "version": "0.17.14", - "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-world-map/-/legacy-plugin-chart-world-map-0.17.14.tgz", - "integrity": "sha512-ZGYSMsmsY1QJpflqKxYHI+elq94cKLwizoID6wCV7/wHA0nAcqHiDyisRnzmOmS+x7msZx5VH0XbVoiyGAgp+g==", + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@superset-ui/legacy-plugin-chart-world-map/-/legacy-plugin-chart-world-map-0.17.15.tgz", + "integrity": "sha512-Ts9F25wqhJZUQhSH47kkKQ/ab02n25vMf1QbU9oryRCJnwWc55xxNeT0lPbdr6FmjFew83+WdkSAL8137Onv7w==", "requires": { - "@superset-ui/chart-controls": "0.17.14", - "@superset-ui/core": "0.17.14", + "@superset-ui/chart-controls": "0.17.15", + "@superset-ui/core": "0.17.15", "d3": "^3.5.17", "d3-array": "^2.4.0", "d3-color": "^1.4.1", @@ -72464,13 +72401,13 @@ } }, "@superset-ui/legacy-preset-chart-big-number": { - "version": "0.17.14", - "resolved": "https://registry.npmjs.org/@superset-ui/legacy-preset-chart-big-number/-/legacy-preset-chart-big-number-0.17.14.tgz", - "integrity": "sha512-4zPlW2cLHr0PZBc15/3IdJshLG2HfR29qkiS8aEwiUkuyqt/6leaVldaLBrHFqFRJQTF5to0gf+H/X9r5ceV2g==", + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@superset-ui/legacy-preset-chart-big-number/-/legacy-preset-chart-big-number-0.17.15.tgz", + "integrity": "sha512-hYB3LRgzhfSecsqM+0MTSjc6hjpOGuGEdLBTcPW4hli6UODoy+XUG0o+22LxFBW/sYqGgWIsVi0mF7pseJnAbQ==", "requires": { "@data-ui/xy-chart": "^0.0.84", - "@superset-ui/chart-controls": "0.17.14", - "@superset-ui/core": "0.17.14", + "@superset-ui/chart-controls": "0.17.15", + "@superset-ui/core": "0.17.15", "@types/d3-color": "^1.2.2", "@types/shortid": "^0.0.29", "d3-color": "^1.2.3", @@ -72503,13 +72440,13 @@ } }, "@superset-ui/legacy-preset-chart-nvd3": { - "version": "0.17.14", - "resolved": "https://registry.npmjs.org/@superset-ui/legacy-preset-chart-nvd3/-/legacy-preset-chart-nvd3-0.17.14.tgz", - "integrity": "sha512-0Fxh4RfT8x+jXrHp39xMRW8MCmMQvjxykTrBwRAeykGBsueGC5aeqOieCk1OTDtbmn+vgw7cUKUyR22JegZlug==", + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@superset-ui/legacy-preset-chart-nvd3/-/legacy-preset-chart-nvd3-0.17.15.tgz", + "integrity": "sha512-skUHQ3i9AhfPNHofkes49ZnaBZcbr5MNyXxvT8CiGa+MP80n+vgt+i5V12kIwxPWRIFwIUpcNxDRtlfE4PjpGg==", "requires": { "@data-ui/xy-chart": "^0.0.84", - "@superset-ui/chart-controls": "0.17.14", - "@superset-ui/core": "0.17.14", + "@superset-ui/chart-controls": "0.17.15", + "@superset-ui/core": "0.17.15", "d3": "^3.5.17", "d3-tip": "^0.9.1", "dompurify": "^2.0.6", @@ -72523,12 +72460,12 @@ } }, "@superset-ui/plugin-chart-echarts": { - "version": "0.17.14", - "resolved": "https://registry.npmjs.org/@superset-ui/plugin-chart-echarts/-/plugin-chart-echarts-0.17.14.tgz", - "integrity": "sha512-WwK6L4G+9bCUFOW1LRrNupSQP0qo8u1uQsjA1ZjLIxZmJr765ltFqgDDOVCZRtzyuhB6uXGs6nWkoytoMIZ1mQ==", + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@superset-ui/plugin-chart-echarts/-/plugin-chart-echarts-0.17.15.tgz", + "integrity": "sha512-wryWvEcKd4MaUvdNMhpCwZ/CY7y38HXnH1muHnNEE4d2PoHKwMN5WXqVQYnE1c90ljTih3kbR3ALPVPSJWGG4g==", "requires": { - "@superset-ui/chart-controls": "0.17.14", - "@superset-ui/core": "0.17.14", + "@superset-ui/chart-controls": "0.17.15", + "@superset-ui/core": "0.17.15", "@types/mathjs": "^6.0.7", "d3-array": "^1.2.0", "echarts": "^5.0.2", @@ -72536,13 +72473,13 @@ } }, "@superset-ui/plugin-chart-table": { - "version": "0.17.14", - "resolved": "https://registry.npmjs.org/@superset-ui/plugin-chart-table/-/plugin-chart-table-0.17.14.tgz", - "integrity": "sha512-RjXt95yUmBJJ5P1xk3fH1orKEqBYFPlUdcDFQuDnv0R6E3V3K09ObT/umJ+jXqZ+XPBMfbbUivaIJrpT2S38Uw==", + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@superset-ui/plugin-chart-table/-/plugin-chart-table-0.17.15.tgz", + "integrity": "sha512-JT8gw16389RF/lY27CchnL0Yo7/U/o6HrWkz46CMGnFnHbY0fq+aqZd7Rqqz0RbTkRS3paWeZdy2nf9MMYsa1g==", "requires": { "@emotion/core": "^10.0.28", - "@superset-ui/chart-controls": "0.17.14", - "@superset-ui/core": "0.17.14", + "@superset-ui/chart-controls": "0.17.15", + "@superset-ui/core": "0.17.15", "@types/d3-array": "^2.0.0", "@types/react-table": "^7.0.19", "d3-array": "^2.4.0", @@ -72565,12 +72502,12 @@ } }, "@superset-ui/plugin-chart-word-cloud": { - "version": "0.17.14", - "resolved": "https://registry.npmjs.org/@superset-ui/plugin-chart-word-cloud/-/plugin-chart-word-cloud-0.17.14.tgz", - "integrity": "sha512-1WZam4x8rNrdtqCxUNami0jijKv2OAvX2XJF7IXq+Hb9+8PXBEHCRgwUIzf3iOjdujtFE+INHcQyeAmJV4uEXA==", + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@superset-ui/plugin-chart-word-cloud/-/plugin-chart-word-cloud-0.17.15.tgz", + "integrity": "sha512-3amMqmF5+HntzcZAP+TdAEtlBvQbq4VZRAwon/+IHcAnHnBlSYNCdjaI3lU/7udIFrMtmkMcPeaQE2lDbjuW3g==", "requires": { - "@superset-ui/chart-controls": "0.17.14", - "@superset-ui/core": "0.17.14", + "@superset-ui/chart-controls": "0.17.15", + "@superset-ui/core": "0.17.15", "@types/d3-cloud": "^1.2.1", "@types/d3-scale": "^2.0.2", "d3-cloud": "^1.2.5", @@ -72602,14 +72539,14 @@ } }, "@superset-ui/preset-chart-xy": { - "version": "0.17.14", - "resolved": "https://registry.npmjs.org/@superset-ui/preset-chart-xy/-/preset-chart-xy-0.17.14.tgz", - "integrity": "sha512-jYKzITop6knzh9262ZwsYMv2URFB9s69wx6n+wxUqzj7wQgpOARtmyo43tGU0UPkYAJD5c70jbROlyUD/Xr5cg==", + "version": "0.17.15", + "resolved": "https://registry.npmjs.org/@superset-ui/preset-chart-xy/-/preset-chart-xy-0.17.15.tgz", + "integrity": "sha512-6V2oIIuYcfHWRcPRuiHdMv7HpD7XdpuB08zDJADIFyV0QRM0RVpGW9kee3j8KyjecXIVtMvNyI81c/2P/kwEdg==", "requires": { "@data-ui/theme": "^0.0.84", "@data-ui/xy-chart": "^0.0.84", - "@superset-ui/chart-controls": "0.17.14", - "@superset-ui/core": "0.17.14", + "@superset-ui/chart-controls": "0.17.15", + "@superset-ui/core": "0.17.15", "@vx/axis": "^0.0.198", "@vx/legend": "^0.0.198", "@vx/scale": "^0.0.197", @@ -86230,7 +86167,6 @@ "version": "4.5.2", "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-4.5.2.tgz", "integrity": "sha512-q5oYdzjKUIPQVjOosjgvCHQOv9Ett9CYYHlgvJeXG0qQvdSojnBq4vAdQBwn1+yGveAwHCoe/rMR86ozX3+c2A==", - "dev": true, "requires": { "@types/html-minifier-terser": "^5.0.0", "@types/tapable": "^1.0.5", @@ -98659,26 +98595,6 @@ } } }, - "chokidar": { - "version": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz", - "integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==", - "dev": true, - "requires": { - "anymatch": "~3.1.1", - "braces": "~3.0.2", - "fsevents": "~2.3.1", - "glob-parent": "~5.1.0", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.5.0" - } - }, - "cli-width": { - "version": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz", - "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==", - "dev": true - }, "cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", diff --git a/superset-frontend/package.json b/superset-frontend/package.json index 43128294c1..0762309734 100644 --- a/superset-frontend/package.json +++ b/superset-frontend/package.json @@ -65,34 +65,34 @@ "@babel/runtime-corejs3": "^7.12.5", "@data-ui/sparkline": "^0.0.84", "@emotion/core": "^10.0.35", - "@superset-ui/chart-controls": "^0.17.14", - "@superset-ui/core": "^0.17.14", - "@superset-ui/legacy-plugin-chart-calendar": "^0.17.14", - "@superset-ui/legacy-plugin-chart-chord": "^0.17.14", - "@superset-ui/legacy-plugin-chart-country-map": "^0.17.14", - "@superset-ui/legacy-plugin-chart-event-flow": "^0.17.14", - "@superset-ui/legacy-plugin-chart-force-directed": "^0.17.14", - "@superset-ui/legacy-plugin-chart-heatmap": "^0.17.14", - "@superset-ui/legacy-plugin-chart-histogram": "^0.17.14", - "@superset-ui/legacy-plugin-chart-horizon": "^0.17.14", - "@superset-ui/legacy-plugin-chart-map-box": "^0.17.14", - "@superset-ui/legacy-plugin-chart-paired-t-test": "^0.17.14", - "@superset-ui/legacy-plugin-chart-parallel-coordinates": "^0.17.14", - "@superset-ui/legacy-plugin-chart-partition": "^0.17.14", - "@superset-ui/legacy-plugin-chart-pivot-table": "^0.17.14", - "@superset-ui/legacy-plugin-chart-rose": "^0.17.14", - "@superset-ui/legacy-plugin-chart-sankey": "^0.17.14", - "@superset-ui/legacy-plugin-chart-sankey-loop": "^0.17.14", - "@superset-ui/legacy-plugin-chart-sunburst": "^0.17.14", - "@superset-ui/legacy-plugin-chart-treemap": "^0.17.14", - "@superset-ui/legacy-plugin-chart-world-map": "^0.17.14", - "@superset-ui/legacy-preset-chart-big-number": "^0.17.14", + "@superset-ui/chart-controls": "^0.17.15", + "@superset-ui/core": "^0.17.15", + "@superset-ui/legacy-plugin-chart-calendar": "^0.17.15", + "@superset-ui/legacy-plugin-chart-chord": "^0.17.15", + "@superset-ui/legacy-plugin-chart-country-map": "^0.17.15", + "@superset-ui/legacy-plugin-chart-event-flow": "^0.17.15", + "@superset-ui/legacy-plugin-chart-force-directed": "^0.17.15", + "@superset-ui/legacy-plugin-chart-heatmap": "^0.17.15", + "@superset-ui/legacy-plugin-chart-histogram": "^0.17.15", + "@superset-ui/legacy-plugin-chart-horizon": "^0.17.15", + "@superset-ui/legacy-plugin-chart-map-box": "^0.17.15", + "@superset-ui/legacy-plugin-chart-paired-t-test": "^0.17.15", + "@superset-ui/legacy-plugin-chart-parallel-coordinates": "^0.17.15", + "@superset-ui/legacy-plugin-chart-partition": "^0.17.15", + "@superset-ui/legacy-plugin-chart-pivot-table": "^0.17.15", + "@superset-ui/legacy-plugin-chart-rose": "^0.17.15", + "@superset-ui/legacy-plugin-chart-sankey": "^0.17.15", + "@superset-ui/legacy-plugin-chart-sankey-loop": "^0.17.15", + "@superset-ui/legacy-plugin-chart-sunburst": "^0.17.15", + "@superset-ui/legacy-plugin-chart-treemap": "^0.17.15", + "@superset-ui/legacy-plugin-chart-world-map": "^0.17.15", + "@superset-ui/legacy-preset-chart-big-number": "^0.17.15", "@superset-ui/legacy-preset-chart-deckgl": "^0.4.6", - "@superset-ui/legacy-preset-chart-nvd3": "^0.17.14", - "@superset-ui/plugin-chart-echarts": "^0.17.14", - "@superset-ui/plugin-chart-table": "^0.17.14", - "@superset-ui/plugin-chart-word-cloud": "^0.17.14", - "@superset-ui/preset-chart-xy": "^0.17.14", + "@superset-ui/legacy-preset-chart-nvd3": "^0.17.15", + "@superset-ui/plugin-chart-echarts": "^0.17.15", + "@superset-ui/plugin-chart-table": "^0.17.15", + "@superset-ui/plugin-chart-word-cloud": "^0.17.15", + "@superset-ui/preset-chart-xy": "^0.17.15", "@vx/responsive": "^0.0.195", "abortcontroller-polyfill": "^1.1.9", "antd": "^4.9.4", diff --git a/superset-frontend/spec/javascripts/filters/utils_spec.ts b/superset-frontend/spec/javascripts/filters/utils_spec.ts index 453152b415..13258a348c 100644 --- a/superset-frontend/spec/javascripts/filters/utils_spec.ts +++ b/superset-frontend/spec/javascripts/filters/utils_spec.ts @@ -107,9 +107,13 @@ describe('Filter utils', () => { expect(getSelectExtraFormData('testCol', ['value'], true, false)).toEqual( { append_form_data: { - extras: { - where: '1 = 0', - }, + adhoc_filters: [ + { + clause: 'WHERE', + expressionType: 'SQL', + sqlExpression: '1 = 0', + }, + ], }, }, ); diff --git a/superset-frontend/src/dashboard/components/FiltersBadge/selectors.ts b/superset-frontend/src/dashboard/components/FiltersBadge/selectors.ts index 89eea4bc9c..895eb26f0e 100644 --- a/superset-frontend/src/dashboard/components/FiltersBadge/selectors.ts +++ b/superset-frontend/src/dashboard/components/FiltersBadge/selectors.ts @@ -22,6 +22,7 @@ import { NativeFiltersState } from 'src/dashboard/reducers/types'; import { DataMaskStateWithId } from 'src/dataMask/types'; import { Layout } from '../../types'; import { getTreeCheckedItems } from '../nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/utils'; +import { FilterValue } from '../nativeFilters/types'; export enum IndicatorStatus { Unset = 'UNSET', @@ -52,7 +53,7 @@ const selectIndicatorValue = ( columnKey: string, filter: Filter, datasource: Datasource, -): string[] => { +): FilterValue => { const values = filter.columns[columnKey]; const arrValues = Array.isArray(values) ? values : [values]; @@ -132,7 +133,7 @@ const getRejectedColumns = (chart: any): Set => export type Indicator = { column?: string; name: string; - value: string[]; + value: FilterValue; status: IndicatorStatus; path: string[]; }; @@ -185,20 +186,22 @@ export const selectNativeIndicatorsForChart = ( const rejectedColumns = getRejectedColumns(chart); const getStatus = ( - value: string[], + value: FilterValue, isAffectedByScope: boolean, column?: string, ): IndicatorStatus => { + // a filter is only considered unset if it's value is null + const hasValue = value !== null; if (!isAffectedByScope) { return IndicatorStatus.Unset; } - if (!column) { + if (!column && hasValue) { // Filter without datasource return IndicatorStatus.Applied; } if (column && rejectedColumns.has(column)) return IndicatorStatus.Incompatible; - if (column && appliedColumns.has(column) && value.length > 0) { + if (column && appliedColumns.has(column) && hasValue) { return IndicatorStatus.Applied; } return IndicatorStatus.Unset; diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterValue.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterValue.tsx index b2b45fc42c..0ec03f847f 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterValue.tsx +++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterValue.tsx @@ -60,7 +60,7 @@ const FilterValue: React.FC = ({ column = {}, }: Partial<{ datasetId: number; column: { name?: string } }> = target; const { name: groupby } = column; - const hasDataSource = !!(datasetId && groupby); + const hasDataSource = !!datasetId; const [loading, setLoading] = useState(hasDataSource); useEffect(() => { const newFormData = getFormData({ @@ -137,7 +137,7 @@ const FilterValue: React.FC = ({ width={220} formData={formData} // For charts that don't have datasource we need workaround for empty placeholder - queriesData={hasDataSource ? state : [{ data: [null] }]} + queriesData={hasDataSource ? state : [{ data: [{}] }]} chartType={filterType} behaviors={[Behavior.NATIVE_FILTER]} hooks={{ setDataMask }} diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/ControlItems.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/ControlItems.tsx index 12c6b23f7a..189781e664 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/ControlItems.tsx +++ b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/ControlItems.tsx @@ -48,7 +48,6 @@ const ControlItems: FC = ({ const controlPanelRegistry = getChartControlPanelRegistry(); const controlItems = getControlItems(controlPanelRegistry.get(filterType)) ?? []; - return ( <> {controlItems diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx index 761dc927f8..8cdc1b9fd4 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx +++ b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx @@ -78,6 +78,8 @@ export interface FiltersConfigFormProps { parentFilters: { id: string; title: string }[]; } +const FILTERS_WITH_ONLY_DATASOURCE = ['filter_timegrain', 'filter_timecolumn']; + /** * The configuration form for a specific filter. * Assigns field values to `filters[filterId]` in the form. @@ -104,17 +106,21 @@ export const FiltersConfigForm: React.FC = ({ // @ts-ignore const hasDatasource = !!nativeFilterItems[formFilter?.filterType]?.value ?.datasourceCount; + const hasColumn = + hasDatasource && + !FILTERS_WITH_ONLY_DATASOURCE.includes(formFilter?.filterType); const hasFilledDatasource = - (formFilter?.dataset && formFilter?.column) || !hasDatasource; + !hasDatasource || + (formFilter?.dataset?.value && (formFilter?.column || !hasColumn)); - useBackendFormUpdate(form, filterId, filterToEdit, hasDatasource); + useBackendFormUpdate(form, filterId, filterToEdit, hasDatasource, hasColumn); const initDatasetId = filterToEdit?.targets[0]?.datasetId; const initColumn = filterToEdit?.targets[0]?.column?.name; const newFormData = getFormData({ datasetId: formFilter?.dataset?.value, - groupby: formFilter?.column, + groupby: hasColumn ? formFilter?.column : undefined, defaultValue: formFilter?.defaultValue, ...formFilter, }); @@ -204,22 +210,24 @@ export const FiltersConfigForm: React.FC = ({ }} /> - {t('Column')}} - rules={[{ required: !removed, message: t('Field is required') }]} - data-test="field-input" - > - - + {hasColumn && ( + {t('Column')}} + rules={[{ required: !removed, message: t('Field is required') }]} + data-test="field-input" + > + + + )} )} {hasFilledDatasource && ( diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/state.ts b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/state.ts index 242d049f25..9d33636b13 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/state.ts +++ b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/state.ts @@ -31,6 +31,7 @@ export const useBackendFormUpdate = ( filterId: string, filterToEdit?: Filter, hasDatasource?: boolean, + hasColumn?: boolean, ) => { const forceUpdate = useForceUpdate(); const formFilter = (form.getFieldValue('filters') || {})[filterId]; @@ -42,13 +43,17 @@ export const useBackendFormUpdate = ( } // No need to check data set change because it cascading update column // So check that column exists is enough - if (!formFilter?.column) { + if (hasColumn && !formFilter?.column) { setFilterFieldValues(form, filterId, { defaultValueQueriesData: [], defaultValue: resolvedDefaultValue, }); return; } + if (!formFilter?.dataset?.value) { + // no need to make chart data request if no dataset is defined + return; + } const formData = getFormData({ datasetId: formFilter?.dataset?.value, groupby: formFilter?.column, @@ -63,7 +68,8 @@ export const useBackendFormUpdate = ( if ( filterToEdit?.filterType === formFilter?.filterType && filterToEdit?.targets[0].datasetId === formFilter?.dataset?.value && - formFilter?.column === filterToEdit?.targets[0].column?.name + (!hasColumn || + formFilter?.column === filterToEdit?.targets[0].column?.name) ) { resolvedDefaultValue = filterToEdit?.defaultValue; } diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/utils.ts b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/utils.ts index f3815fa978..4b3588f542 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/utils.ts +++ b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/utils.ts @@ -19,7 +19,7 @@ import { FormInstance } from 'antd/lib/form'; import shortid from 'shortid'; import { FilterRemoval, NativeFiltersForm } from './types'; -import { Filter, FilterConfiguration } from '../types'; +import { Filter, FilterConfiguration, Target } from '../types'; export const REMOVAL_DELAY_SECS = 5; @@ -132,14 +132,12 @@ export const createHandleSave = ( const formInputs = values.filters[id]; // if user didn't open a filter, return the original config if (!formInputs) return filterConfigMap[id]; - let target = {}; + const target: Partial = {}; + if (formInputs.dataset) { + target.datasetId = formInputs.dataset.value; + } if (formInputs.dataset && formInputs.column) { - target = { - datasetId: formInputs.dataset.value, - column: { - name: formInputs.column, - }, - }; + target.column = { name: formInputs.column }; } return { id, diff --git a/superset-frontend/src/dashboard/components/nativeFilters/types.ts b/superset-frontend/src/dashboard/components/nativeFilters/types.ts index f104523441..d816b0ae32 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/types.ts +++ b/superset-frontend/src/dashboard/components/nativeFilters/types.ts @@ -37,10 +37,12 @@ export interface Target { // clarityColumns?: Column[]; } +export type FilterValue = string | number | (string | number)[] | null; + export interface Filter { cascadeParentIds: string[]; - defaultValue: any; - currentValue?: any; + defaultValue: FilterValue; + currentValue?: FilterValue; isInstant: boolean; id: string; // randomly generated at filter creation name: string; diff --git a/superset-frontend/src/dashboard/components/nativeFilters/utils.ts b/superset-frontend/src/dashboard/components/nativeFilters/utils.ts index f3a21694b4..1d72de99e6 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/utils.ts +++ b/superset-frontend/src/dashboard/components/nativeFilters/utils.ts @@ -44,12 +44,12 @@ export const getFormData = ({ cascadingFilters?: object; groupby?: string; }): Partial => { - let otherProps: { datasource?: string; groupby?: string[] } = {}; - if (datasetId && groupby) { - otherProps = { - datasource: `${datasetId}__table`, - groupby: [groupby], - }; + const otherProps: { datasource?: string; groupby?: string[] } = {}; + if (datasetId) { + otherProps.datasource = `${datasetId}__table`; + } + if (groupby) { + otherProps.groupby = [groupby]; } return { ...controlValues, diff --git a/superset-frontend/src/filters/components/Range/RangeFilterPlugin.tsx b/superset-frontend/src/filters/components/Range/RangeFilterPlugin.tsx index 0df41a2922..e628509f64 100644 --- a/superset-frontend/src/filters/components/Range/RangeFilterPlugin.tsx +++ b/superset-frontend/src/filters/components/Range/RangeFilterPlugin.tsx @@ -16,18 +16,13 @@ * specific language governing permissions and limitations * under the License. */ -import { styled, t, DataMask, Behavior } from '@superset-ui/core'; +import { t, DataMask, Behavior } from '@superset-ui/core'; import React, { useEffect, useState } from 'react'; import { Slider } from 'src/common/components'; import { PluginFilterRangeProps } from './types'; -import { PluginFilterStylesProps } from '../types'; +import { Styles } from '../common'; import { getRangeExtraFormData } from '../../utils'; -const Styles = styled.div` - height: ${({ height }) => height}; - width: ${({ width }) => width}; -`; - export default function RangeFilterPlugin(props: PluginFilterRangeProps) { const { data, diff --git a/superset-frontend/src/filters/components/Range/buildQuery.ts b/superset-frontend/src/filters/components/Range/buildQuery.ts index ed12e0c99f..d0ed52454e 100644 --- a/superset-frontend/src/filters/components/Range/buildQuery.ts +++ b/superset-frontend/src/filters/components/Range/buildQuery.ts @@ -43,6 +43,7 @@ export default function buildQuery(formData: QueryFormData) { return buildQueryContext(formData, baseQueryObject => [ { ...baseQueryObject, + apply_fetch_values_predicate: true, columns: [], groupby: [], metrics: [ diff --git a/superset-frontend/src/filters/components/Range/index.ts b/superset-frontend/src/filters/components/Range/index.ts index 0fe431097b..59a92f0111 100644 --- a/superset-frontend/src/filters/components/Range/index.ts +++ b/superset-frontend/src/filters/components/Range/index.ts @@ -26,7 +26,7 @@ export default class RangeFilterPlugin extends ChartPlugin { constructor() { const metadata = new ChartMetadata({ name: t('Range filter'), - description: 'Range filter plugin using AntD', + description: t('Range filter plugin using AntD'), behaviors: [Behavior.CROSS_FILTER, Behavior.NATIVE_FILTER], thumbnail, }); diff --git a/superset-frontend/src/filters/components/Select/SelectFilterPlugin.tsx b/superset-frontend/src/filters/components/Select/SelectFilterPlugin.tsx index d9b8e0b167..7238c2faa8 100644 --- a/superset-frontend/src/filters/components/Select/SelectFilterPlugin.tsx +++ b/superset-frontend/src/filters/components/Select/SelectFilterPlugin.tsx @@ -16,18 +16,13 @@ * specific language governing permissions and limitations * under the License. */ -import { styled, Behavior, DataMask, t } from '@superset-ui/core'; +import { Behavior, DataMask, t, tn, ensureIsArray } from '@superset-ui/core'; import React, { useEffect, useState } from 'react'; import { Select } from 'src/common/components'; import { PluginFilterSelectProps } from './types'; -import { PluginFilterStylesProps } from '../types'; +import { Styles, StyledSelect } from '../common'; import { getSelectExtraFormData } from '../../utils'; -const Styles = styled.div` - height: ${({ height }) => height}; - width: ${({ width }) => width}; -`; - const { Option } = Select; export default function PluginFilterSelect(props: PluginFilterSelectProps) { @@ -50,13 +45,9 @@ export default function PluginFilterSelect(props: PluginFilterSelectProps) { const handleChange = ( value?: (number | string)[] | number | string | null, ) => { - let resultValue: (number | string)[]; - // Works only with arrays even for single select - if (!Array.isArray(value)) { - resultValue = value ? [value] : []; - } else { - resultValue = value; - } + const resultValue: (number | string)[] = ensureIsArray( + value, + ); setValues(resultValue); const [col] = groupby; @@ -89,25 +80,32 @@ export default function PluginFilterSelect(props: PluginFilterSelectProps) { useEffect(() => { handleChange(currentValue ?? []); - }, [JSON.stringify(currentValue)]); + }, [ + JSON.stringify(currentValue), + multiSelect, + enableEmptyFilter, + inverseSelection, + ]); useEffect(() => { handleChange(defaultValue ?? []); - // I think after Config Modal update some filter it re-creates default value for all other filters - // so we can process it like this `JSON.stringify` or start to use `Immer` - }, [JSON.stringify(defaultValue)]); + }, [ + JSON.stringify(defaultValue), + multiSelect, + enableEmptyFilter, + inverseSelection, + ]); const placeholderText = (data || []).length === 0 ? t('No data') - : t(`%d option%s`, data.length, data.length === 1 ? '' : 's'); + : tn('%s option', '%s options', data.length, data.length); return ( - + ); } diff --git a/superset-frontend/src/filters/components/Select/buildQuery.ts b/superset-frontend/src/filters/components/Select/buildQuery.ts index 7cca60102f..5093d515d9 100644 --- a/superset-frontend/src/filters/components/Select/buildQuery.ts +++ b/superset-frontend/src/filters/components/Select/buildQuery.ts @@ -36,6 +36,7 @@ export default function buildQuery(formData: QueryFormData) { return buildQueryContext(formData, baseQueryObject => [ { ...baseQueryObject, + apply_fetch_values_predicate: true, groupby: baseQueryObject.columns, }, ]); diff --git a/superset-frontend/src/filters/components/Select/index.ts b/superset-frontend/src/filters/components/Select/index.ts index 0c68a63259..73b9ffa992 100644 --- a/superset-frontend/src/filters/components/Select/index.ts +++ b/superset-frontend/src/filters/components/Select/index.ts @@ -26,7 +26,7 @@ export default class FilterSelectPlugin extends ChartPlugin { constructor() { const metadata = new ChartMetadata({ name: t('Select filter'), - description: 'Select filter plugin using AntD', + description: t('Select filter plugin using AntD'), behaviors: [Behavior.CROSS_FILTER, Behavior.NATIVE_FILTER], thumbnail, }); diff --git a/superset-frontend/src/filters/components/Time/TimeFilterPlugin.tsx b/superset-frontend/src/filters/components/Time/TimeFilterPlugin.tsx index cf005268f4..469d3e7535 100644 --- a/superset-frontend/src/filters/components/Time/TimeFilterPlugin.tsx +++ b/superset-frontend/src/filters/components/Time/TimeFilterPlugin.tsx @@ -19,14 +19,12 @@ import { styled, DataMask, Behavior } from '@superset-ui/core'; import React, { useState, useEffect } from 'react'; import DateFilterControl from 'src/explore/components/controls/DateFilterControl'; -import { PluginFilterStylesProps } from '../types'; import { PluginFilterTimeProps } from './types'; +import { Styles } from '../common'; const DEFAULT_VALUE = 'Last week'; -const Styles = styled.div` - height: ${({ height }) => height}px; - width: ${({ width }) => width}px; +const TimeFilterStyles = styled(Styles)` overflow-x: scroll; `; @@ -69,12 +67,12 @@ export default function TimeFilterPlugin(props: PluginFilterTimeProps) { return ( // @ts-ignore - + - + ); } diff --git a/superset-frontend/src/filters/components/Time/index.ts b/superset-frontend/src/filters/components/Time/index.ts index 1a0b7aa5d5..4099e400e2 100644 --- a/superset-frontend/src/filters/components/Time/index.ts +++ b/superset-frontend/src/filters/components/Time/index.ts @@ -25,7 +25,7 @@ export default class TimeFilterPlugin extends ChartPlugin { constructor() { const metadata = new ChartMetadata({ name: t('Time filter'), - description: 'Custom time filter plugin', + description: t('Custom time filter plugin'), behaviors: [Behavior.CROSS_FILTER, Behavior.NATIVE_FILTER], thumbnail, datasourceCount: 0, diff --git a/superset-frontend/src/filters/components/TimeColumn/TimeColumnFilterPlugin.tsx b/superset-frontend/src/filters/components/TimeColumn/TimeColumnFilterPlugin.tsx new file mode 100644 index 0000000000..2f63c26976 --- /dev/null +++ b/superset-frontend/src/filters/components/TimeColumn/TimeColumnFilterPlugin.tsx @@ -0,0 +1,110 @@ +/** + * 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 { + Behavior, + DataMask, + ensureIsArray, + GenericDataType, + t, + tn, +} from '@superset-ui/core'; +import React, { useEffect, useState } from 'react'; +import { Select } from 'src/common/components'; +import { Styles, StyledSelect } from '../common'; +import { PluginFilterTimeColumnProps } from './types'; + +const { Option } = Select; + +export default function PluginFilterTimeColumn( + props: PluginFilterTimeColumnProps, +) { + const { behaviors, data, formData, height, width, setDataMask } = props; + const { defaultValue, currentValue, inputRef } = formData; + + const [value, setValue] = useState(defaultValue ?? []); + + const handleChange = (value?: string[] | string | null) => { + const resultValue: string[] = ensureIsArray(value); + setValue(resultValue); + + const dataMask = { + extraFormData: { + override_form_data: { + granularity_sqla: resultValue.length ? resultValue[0] : null, + }, + }, + currentState: { + value: resultValue.length ? resultValue : null, + }, + }; + + const dataMaskObject: DataMask = {}; + if (behaviors.includes(Behavior.NATIVE_FILTER)) { + dataMaskObject.nativeFilters = dataMask; + } + + if (behaviors.includes(Behavior.CROSS_FILTER)) { + dataMaskObject.crossFilters = dataMask; + } + + setDataMask(dataMaskObject); + }; + + useEffect(() => { + handleChange(currentValue ?? null); + }, [JSON.stringify(currentValue)]); + + useEffect(() => { + handleChange(defaultValue ?? null); + // I think after Config Modal update some filter it re-creates default value for all other filters + // so we can process it like this `JSON.stringify` or start to use `Immer` + }, [JSON.stringify(defaultValue)]); + + const timeColumns = (data || []).filter( + row => row.dtype === GenericDataType.TEMPORAL, + ); + + const placeholderText = + timeColumns.length === 0 + ? t('No time columns') + : tn('%s option', '%s options', timeColumns.length, timeColumns.length); + return ( + + + {timeColumns.map( + (row: { column_name: string; verbose_name: string | null }) => { + const { column_name: columnName, verbose_name: verboseName } = row; + return ( + + ); + }, + )} + + + ); +} diff --git a/superset-frontend/src/filters/components/TimeColumn/buildQuery.ts b/superset-frontend/src/filters/components/TimeColumn/buildQuery.ts new file mode 100644 index 0000000000..1cc839c4cb --- /dev/null +++ b/superset-frontend/src/filters/components/TimeColumn/buildQuery.ts @@ -0,0 +1,44 @@ +/** + * 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, QueryFormData } from '@superset-ui/core'; + +/** + * The buildQuery function is used to create an instance of QueryContext that's + * sent to the chart data endpoint. In addition to containing information of which + * datasource to use, it specifies the type (e.g. full payload, samples, query) and + * format (e.g. CSV or JSON) of the result and whether or not to force refresh the data from + * the datasource as opposed to using a cached copy of the data, if available. + * + * More importantly though, QueryContext contains a property `queries`, which is an array of + * QueryObjects specifying individual data requests to be made. A QueryObject specifies which + * columns, metrics and filters, among others, to use during the query. Usually it will be enough + * to specify just one query based on the baseQueryObject, but for some more advanced use cases + * it is possible to define post processing operations in the QueryObject, or multiple queries + * if a viz needs multiple different result sets. + */ +export default function buildQuery(formData: QueryFormData) { + return buildQueryContext(formData, baseQueryObject => [ + { + result_type: 'columns', + columns: [], + metrics: [], + orderby: [], + }, + ]); +} diff --git a/superset-frontend/src/filters/components/TimeColumn/controlPanel.ts b/superset-frontend/src/filters/components/TimeColumn/controlPanel.ts new file mode 100644 index 0000000000..5b7bc3dc3b --- /dev/null +++ b/superset-frontend/src/filters/components/TimeColumn/controlPanel.ts @@ -0,0 +1,25 @@ +/** + * 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 { ControlPanelConfig } from '@superset-ui/chart-controls'; + +const config: ControlPanelConfig = { + controlPanelSections: [], +}; + +export default config; diff --git a/superset-frontend/src/filters/components/TimeColumn/images/thumbnail.png b/superset-frontend/src/filters/components/TimeColumn/images/thumbnail.png new file mode 100644 index 0000000000000000000000000000000000000000..7afef30bd4e6e4f85723208bf9f429647d03d3e5 GIT binary patch literal 5658 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 literal 0 HcmV?d00001 diff --git a/superset-frontend/src/filters/components/TimeColumn/index.ts b/superset-frontend/src/filters/components/TimeColumn/index.ts new file mode 100644 index 0000000000..ac09b6580e --- /dev/null +++ b/superset-frontend/src/filters/components/TimeColumn/index.ts @@ -0,0 +1,42 @@ +/** + * 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 { Behavior, ChartMetadata, ChartPlugin, t } from '@superset-ui/core'; +import buildQuery from './buildQuery'; +import controlPanel from './controlPanel'; +import transformProps from './transformProps'; +import thumbnail from './images/thumbnail.png'; + +export default class FilterTimeColumnPlugin extends ChartPlugin { + constructor() { + const metadata = new ChartMetadata({ + name: t('Time column'), + description: t('Time column filter plugin'), + behaviors: [Behavior.CROSS_FILTER, Behavior.NATIVE_FILTER], + thumbnail, + }); + + super({ + buildQuery, + controlPanel, + loadChart: () => import('./TimeColumnFilterPlugin'), + metadata, + transformProps, + }); + } +} diff --git a/superset-frontend/src/filters/components/TimeColumn/transformProps.ts b/superset-frontend/src/filters/components/TimeColumn/transformProps.ts new file mode 100644 index 0000000000..e6ae61f946 --- /dev/null +++ b/superset-frontend/src/filters/components/TimeColumn/transformProps.ts @@ -0,0 +1,36 @@ +/** + * 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 } from '@superset-ui/core'; +import { DEFAULT_FORM_DATA } from './types'; + +export default function transformProps(chartProps: ChartProps) { + const { behaviors, formData, height, hooks, queriesData, width } = chartProps; + const { setDataMask = () => {} } = hooks; + + const { data } = queriesData[0]; + + return { + behaviors, + width, + height, + data, + formData: { ...DEFAULT_FORM_DATA, ...formData }, + setDataMask, + }; +} diff --git a/superset-frontend/src/filters/components/TimeColumn/types.ts b/superset-frontend/src/filters/components/TimeColumn/types.ts new file mode 100644 index 0000000000..954d686167 --- /dev/null +++ b/superset-frontend/src/filters/components/TimeColumn/types.ts @@ -0,0 +1,48 @@ +/** + * 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 { + QueryFormData, + DataRecord, + SetDataMaskHook, + Behavior, +} from '@superset-ui/core'; +import { RefObject } from 'react'; +import { PluginFilterStylesProps } from '../types'; + +interface PluginFilterTimeColumnCustomizeProps { + defaultValue?: string[] | null; + currentValue?: string[] | null; + inputRef?: RefObject; +} + +export type PluginFilterTimeColumnQueryFormData = QueryFormData & + PluginFilterStylesProps & + PluginFilterTimeColumnCustomizeProps; + +export type PluginFilterTimeColumnProps = PluginFilterStylesProps & { + behaviors: Behavior[]; + data: DataRecord[]; + setDataMask: SetDataMaskHook; + formData: PluginFilterTimeColumnQueryFormData; +}; + +export const DEFAULT_FORM_DATA: PluginFilterTimeColumnCustomizeProps = { + defaultValue: null, + currentValue: null, +}; diff --git a/superset-frontend/src/filters/components/TimeGrain/TimeGrainFilterPlugin.tsx b/superset-frontend/src/filters/components/TimeGrain/TimeGrainFilterPlugin.tsx new file mode 100644 index 0000000000..ce890712d4 --- /dev/null +++ b/superset-frontend/src/filters/components/TimeGrain/TimeGrainFilterPlugin.tsx @@ -0,0 +1,93 @@ +/** + * 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 { ensureIsArray, QueryObjectExtras, t, tn } from '@superset-ui/core'; +import React, { useEffect, useState } from 'react'; +import { Select } from 'src/common/components'; +import { Styles, StyledSelect } from '../common'; +import { PluginFilterTimeGrainProps } from './types'; + +const { Option } = Select; + +export default function PluginFilterTimegrain( + props: PluginFilterTimeGrainProps, +) { + const { data, formData, height, width, setDataMask } = props; + const { defaultValue, currentValue, inputRef } = formData; + + const [value, setValue] = useState(defaultValue ?? []); + + const handleChange = (values: string[] | string | undefined | null) => { + const resultValue: string[] = ensureIsArray(values); + const [timeGrain] = resultValue; + + const extras: QueryObjectExtras = {}; + if (timeGrain) { + extras.time_grain_sqla = timeGrain; + } + setValue(resultValue); + setDataMask({ + nativeFilters: { + extraFormData: { + override_form_data: { + extras, + }, + }, + currentState: { + value: resultValue.length ? resultValue : null, + }, + }, + }); + }; + + useEffect(() => { + handleChange(currentValue ?? []); + }, [JSON.stringify(currentValue)]); + + useEffect(() => { + handleChange(defaultValue ?? []); + // I think after Config Modal update some filter it re-creates default value for all other filters + // so we can process it like this `JSON.stringify` or start to use `Immer` + }, [JSON.stringify(defaultValue)]); + + const placeholderText = + (data || []).length === 0 + ? t('No data') + : tn('%s option', '%s options', data.length, data.length); + return ( + + + {(data || []).map((row: { name: string; duration: string }) => { + const { name, duration } = row; + return ( + + ); + })} + + + ); +} diff --git a/superset-frontend/src/filters/components/TimeGrain/buildQuery.ts b/superset-frontend/src/filters/components/TimeGrain/buildQuery.ts new file mode 100644 index 0000000000..5a20aef2a8 --- /dev/null +++ b/superset-frontend/src/filters/components/TimeGrain/buildQuery.ts @@ -0,0 +1,44 @@ +/** + * 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, QueryFormData } from '@superset-ui/core'; + +/** + * The buildQuery function is used to create an instance of QueryContext that's + * sent to the chart data endpoint. In addition to containing information of which + * datasource to use, it specifies the type (e.g. full payload, samples, query) and + * format (e.g. CSV or JSON) of the result and whether or not to force refresh the data from + * the datasource as opposed to using a cached copy of the data, if available. + * + * More importantly though, QueryContext contains a property `queries`, which is an array of + * QueryObjects specifying individual data requests to be made. A QueryObject specifies which + * columns, metrics and filters, among others, to use during the query. Usually it will be enough + * to specify just one query based on the baseQueryObject, but for some more advanced use cases + * it is possible to define post processing operations in the QueryObject, or multiple queries + * if a viz needs multiple different result sets. + */ +export default function buildQuery(formData: QueryFormData) { + return buildQueryContext(formData, () => [ + { + result_type: 'timegrains', + columns: [], + metrics: [], + orderby: [], + }, + ]); +} diff --git a/superset-frontend/src/filters/components/TimeGrain/controlPanel.ts b/superset-frontend/src/filters/components/TimeGrain/controlPanel.ts new file mode 100644 index 0000000000..5b7bc3dc3b --- /dev/null +++ b/superset-frontend/src/filters/components/TimeGrain/controlPanel.ts @@ -0,0 +1,25 @@ +/** + * 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 { ControlPanelConfig } from '@superset-ui/chart-controls'; + +const config: ControlPanelConfig = { + controlPanelSections: [], +}; + +export default config; diff --git a/superset-frontend/src/filters/components/TimeGrain/images/thumbnail.png b/superset-frontend/src/filters/components/TimeGrain/images/thumbnail.png new file mode 100644 index 0000000000000000000000000000000000000000..7afef30bd4e6e4f85723208bf9f429647d03d3e5 GIT binary patch literal 5658 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 literal 0 HcmV?d00001 diff --git a/superset-frontend/src/filters/components/TimeGrain/index.ts b/superset-frontend/src/filters/components/TimeGrain/index.ts new file mode 100644 index 0000000000..9839c7dacc --- /dev/null +++ b/superset-frontend/src/filters/components/TimeGrain/index.ts @@ -0,0 +1,42 @@ +/** + * 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 { Behavior, ChartMetadata, ChartPlugin, t } from '@superset-ui/core'; +import buildQuery from './buildQuery'; +import controlPanel from './controlPanel'; +import transformProps from './transformProps'; +import thumbnail from './images/thumbnail.png'; + +export default class FilterTimeGrainPlugin extends ChartPlugin { + constructor() { + const metadata = new ChartMetadata({ + name: t('Time grain'), + description: t('Time grain filter plugin'), + behaviors: [Behavior.CROSS_FILTER, Behavior.NATIVE_FILTER], + thumbnail, + }); + + super({ + buildQuery, + controlPanel, + loadChart: () => import('./TimeGrainFilterPlugin'), + metadata, + transformProps, + }); + } +} diff --git a/superset-frontend/src/filters/components/TimeGrain/transformProps.ts b/superset-frontend/src/filters/components/TimeGrain/transformProps.ts new file mode 100644 index 0000000000..b7aef808f6 --- /dev/null +++ b/superset-frontend/src/filters/components/TimeGrain/transformProps.ts @@ -0,0 +1,35 @@ +/** + * 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 } from '@superset-ui/core'; +import { DEFAULT_FORM_DATA } from './types'; + +export default function transformProps(chartProps: ChartProps) { + const { formData, height, hooks, queriesData, width } = chartProps; + const { setDataMask = () => {} } = hooks; + + const { data } = queriesData[0]; + + return { + width, + height, + data, + formData: { ...DEFAULT_FORM_DATA, ...formData }, + setDataMask, + }; +} diff --git a/superset-frontend/src/filters/components/TimeGrain/types.ts b/superset-frontend/src/filters/components/TimeGrain/types.ts new file mode 100644 index 0000000000..a1f3f39698 --- /dev/null +++ b/superset-frontend/src/filters/components/TimeGrain/types.ts @@ -0,0 +1,42 @@ +/** + * 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 { QueryFormData, DataRecord, SetDataMaskHook } from '@superset-ui/core'; +import { RefObject } from 'react'; +import { PluginFilterStylesProps } from '../types'; + +interface PluginFilterTimeGrainCustomizeProps { + defaultValue?: string[] | null; + currentValue?: string[] | null; + inputRef?: RefObject; +} + +export type PluginFilterTimeGrainQueryFormData = QueryFormData & + PluginFilterStylesProps & + PluginFilterTimeGrainCustomizeProps; + +export type PluginFilterTimeGrainProps = PluginFilterStylesProps & { + data: DataRecord[]; + setDataMask: SetDataMaskHook; + formData: PluginFilterTimeGrainQueryFormData; +}; + +export const DEFAULT_FORM_DATA: PluginFilterTimeGrainCustomizeProps = { + defaultValue: null, + currentValue: null, +}; diff --git a/superset-frontend/src/filters/components/common.ts b/superset-frontend/src/filters/components/common.ts new file mode 100644 index 0000000000..ebaca99e3d --- /dev/null +++ b/superset-frontend/src/filters/components/common.ts @@ -0,0 +1,30 @@ +/** + * 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 { styled } from '@superset-ui/core'; +import { Select } from 'src/common/components'; +import { PluginFilterStylesProps } from './types'; + +export const Styles = styled.div` + height: ${({ height }) => height}; + width: ${({ width }) => width}; +`; + +export const StyledSelect = styled(Select)` + width: 100%; +`; diff --git a/superset-frontend/src/filters/components/index.ts b/superset-frontend/src/filters/components/index.ts index 1139f77414..662b7a8b59 100644 --- a/superset-frontend/src/filters/components/index.ts +++ b/superset-frontend/src/filters/components/index.ts @@ -19,3 +19,5 @@ export { default as SelectFilterPlugin } from './Select'; export { default as RangeFilterPlugin } from './Range'; export { default as TimeFilterPlugin } from './Time'; +export { default as TimeColumnFilterPlugin } from './TimeColumn'; +export { default as TimeGrainFilterPlugin } from './TimeGrain'; diff --git a/superset-frontend/src/filters/utils.ts b/superset-frontend/src/filters/utils.ts index 364cd9c9ab..005a151693 100644 --- a/superset-frontend/src/filters/utils.ts +++ b/superset-frontend/src/filters/utils.ts @@ -26,9 +26,13 @@ export const getSelectExtraFormData = ( ) => ({ append_form_data: emptyFilter ? { - extras: { - where: '1 = 0', - }, + adhoc_filters: [ + { + expressionType: 'SQL', + clause: 'WHERE', + sqlExpression: '1 = 0', + }, + ], } : { filters: diff --git a/superset-frontend/src/visualizations/presets/MainPreset.js b/superset-frontend/src/visualizations/presets/MainPreset.js index 901d9bb32a..b18069e503 100644 --- a/superset-frontend/src/visualizations/presets/MainPreset.js +++ b/superset-frontend/src/visualizations/presets/MainPreset.js @@ -63,6 +63,8 @@ import { SelectFilterPlugin, RangeFilterPlugin, TimeFilterPlugin, + TimeColumnFilterPlugin, + TimeGrainFilterPlugin, } from 'src/filters/components/'; import FilterBoxChartPlugin from '../FilterBox/FilterBoxChartPlugin'; import TimeTableChartPlugin from '../TimeTable/TimeTableChartPlugin'; @@ -115,6 +117,8 @@ export default class MainPreset extends Preset { new SelectFilterPlugin().configure({ key: 'filter_select' }), new RangeFilterPlugin().configure({ key: 'filter_range' }), new TimeFilterPlugin().configure({ key: 'filter_time' }), + new TimeColumnFilterPlugin().configure({ key: 'filter_timecolumn' }), + new TimeGrainFilterPlugin().configure({ key: 'filter_timegrain' }), ], }); } diff --git a/superset/charts/schemas.py b/superset/charts/schemas.py index 61f41f66ab..7703df7fcd 100644 --- a/superset/charts/schemas.py +++ b/superset/charts/schemas.py @@ -908,6 +908,11 @@ class ChartDataQueryObjectSchema(Schema): allow_none=True, example={"__time_range": "1 year ago : now"}, ) + apply_fetch_values_predicate = fields.Boolean( + description="Add fetch values predicate (where clause) to query " + "if defined in datasource", + allow_none=True, + ) filters = fields.List(fields.Nested(ChartDataFilterSchema), allow_none=True) granularity = fields.String( description="Name of temporal column used for time filtering. For legacy Druid " diff --git a/superset/common/query_object.py b/superset/common/query_object.py index 4b5f6aaa1c..607f1e8d83 100644 --- a/superset/common/query_object.py +++ b/superset/common/query_object.py @@ -73,6 +73,7 @@ class QueryObject: annotation_layers: List[Dict[str, Any]] applied_time_extras: Dict[str, str] + apply_fetch_values_predicate: bool granularity: Optional[str] from_dttm: Optional[datetime] to_dttm: Optional[datetime] @@ -100,6 +101,7 @@ class QueryObject: result_type: Optional[ChartDataResultType] = None, annotation_layers: Optional[List[Dict[str, Any]]] = None, applied_time_extras: Optional[Dict[str, str]] = None, + apply_fetch_values_predicate: bool = False, granularity: Optional[str] = None, metrics: Optional[List[Union[Dict[str, Any], str]]] = None, groupby: Optional[List[str]] = None, @@ -127,6 +129,7 @@ class QueryObject: ) self.result_type = result_type annotation_layers = annotation_layers or [] + self.apply_fetch_values_predicate = apply_fetch_values_predicate or False metrics = metrics or [] columns = columns or [] groupby = groupby or [] @@ -262,6 +265,7 @@ class QueryObject: def to_dict(self) -> Dict[str, Any]: query_object_dict = { + "apply_fetch_values_predicate": self.apply_fetch_values_predicate, "granularity": self.granularity, "groupby": self.groupby, "from_dttm": self.from_dttm, @@ -291,18 +295,24 @@ class QueryObject: """ cache_dict = self.to_dict() cache_dict.update(extra) + + # TODO: the below KVs can all be cleaned up and moved to `to_dict()` at some + # predetermined point in time when orgs are aware that the previously + # chached results will be invalidated. + if not self.apply_fetch_values_predicate: + del cache_dict["apply_fetch_values_predicate"] if self.datasource: cache_dict["datasource"] = self.datasource.uid if self.result_type: cache_dict["result_type"] = self.result_type - - for k in ["from_dttm", "to_dttm"]: - del cache_dict[k] if self.time_range: cache_dict["time_range"] = self.time_range if self.post_processing: cache_dict["post_processing"] = self.post_processing + for k in ["from_dttm", "to_dttm"]: + del cache_dict[k] + annotation_fields = [ "annotationType", "descriptionColumns", diff --git a/superset/connectors/druid/models.py b/superset/connectors/druid/models.py index 078369a7f3..884d4bc32d 100644 --- a/superset/connectors/druid/models.py +++ b/superset/connectors/druid/models.py @@ -1139,11 +1139,17 @@ class DruidDatasource(Model, BaseDatasource): client: Optional["PyDruid"] = None, order_desc: bool = True, is_rowcount: bool = False, + apply_fetch_values_predicate: bool = False, ) -> str: """Runs a query against Druid and returns a dataframe.""" - # is_rowcount is only supported on SQL connector + # is_rowcount and apply_fetch_values_predicate is only + # supported on SQL connector if is_rowcount: raise SupersetException("is_rowcount is not supported on Druid connector") + if apply_fetch_values_predicate: + raise SupersetException( + "apply_fetch_values_predicate is not supported on Druid connector" + ) # TODO refactor into using a TBD Query object client = client or self.cluster.get_pydruid_client() diff --git a/superset/connectors/sqla/models.py b/superset/connectors/sqla/models.py index e1e1b9bad8..254f52a304 100644 --- a/superset/connectors/sqla/models.py +++ b/superset/connectors/sqla/models.py @@ -48,7 +48,7 @@ from sqlalchemy import ( from sqlalchemy.orm import backref, Query, relationship, RelationshipProperty, Session from sqlalchemy.schema import UniqueConstraint from sqlalchemy.sql import column, ColumnElement, literal_column, table, text -from sqlalchemy.sql.expression import Label, Select, TextAsFrom +from sqlalchemy.sql.expression import Label, Select, TextAsFrom, TextClause from sqlalchemy.types import TypeEngine from superset import app, db, is_feature_enabled, security_manager @@ -720,6 +720,18 @@ class SqlaTable( # pylint: disable=too-many-public-methods,too-many-instance-at except (TypeError, json.JSONDecodeError): return {} + def get_fetch_values_predicate(self) -> TextClause: + tp = self.get_template_processor() + try: + return text(tp.process_template(self.fetch_values_predicate)) + except TemplateError as ex: + raise QueryObjectValidationError( + _( + "Error in jinja expression in fetch values predicate: %(msg)s", + msg=ex.message, + ) + ) + def values_for_column(self, column_name: str, limit: int = 10000) -> List[Any]: """Runs query against sqla to retrieve some sample values for the given column. @@ -737,16 +749,7 @@ class SqlaTable( # pylint: disable=too-many-public-methods,too-many-instance-at qry = qry.limit(limit) if self.fetch_values_predicate: - tp = self.get_template_processor() - try: - qry = qry.where(text(tp.process_template(self.fetch_values_predicate))) - except TemplateError as ex: - raise QueryObjectValidationError( - _( - "Error in jinja expression in fetch values predicate: %(msg)s", - msg=ex.message, - ) - ) + qry = qry.where(self.get_fetch_values_predicate()) engine = self.database.get_sqla_engine() sql = "{}".format(qry.compile(engine, compile_kwargs={"literal_binds": True})) @@ -899,6 +902,7 @@ class SqlaTable( # pylint: disable=too-many-public-methods,too-many-instance-at extras: Optional[Dict[str, Any]] = None, order_desc: bool = True, is_rowcount: bool = False, + apply_fetch_values_predicate: bool = False, ) -> SqlaQuery: """Querying any sqla table from this common interface""" template_kwargs = { @@ -1133,6 +1137,8 @@ class SqlaTable( # pylint: disable=too-many-public-methods,too-many-instance-at ) ) having_clause_and += [sa.text("({})".format(having))] + if apply_fetch_values_predicate and self.fetch_values_predicate: + qry = qry.where(self.get_fetch_values_predicate()) if granularity: qry = qry.where(and_(*(time_filters + where_clause_and))) else: diff --git a/superset/db_engine_specs/base.py b/superset/db_engine_specs/base.py index 36ac219612..3052ff7b4d 100644 --- a/superset/db_engine_specs/base.py +++ b/superset/db_engine_specs/base.py @@ -40,7 +40,7 @@ from typing import ( import pandas as pd import sqlparse from flask import g -from flask_babel import lazy_gettext as _ +from flask_babel import gettext as __, lazy_gettext as _ from sqlalchemy import column, DateTime, select from sqlalchemy.engine.base import Engine from sqlalchemy.engine.interfaces import Compiled, Dialect @@ -77,23 +77,23 @@ QueryStatus = utils.QueryStatus config = app.config builtin_time_grains: Dict[Optional[str], str] = { - None: "Time Column", - "PT1S": "second", - "PT1M": "minute", - "PT5M": "5 minute", - "PT10M": "10 minute", - "PT15M": "15 minute", - "PT0.5H": "half hour", - "PT1H": "hour", - "P1D": "day", - "P1W": "week", - "P1M": "month", - "P0.25Y": "quarter", - "P1Y": "year", - "1969-12-28T00:00:00Z/P1W": "week_start_sunday", - "1969-12-29T00:00:00Z/P1W": "week_start_monday", - "P1W/1970-01-03T00:00:00Z": "week_ending_saturday", - "P1W/1970-01-04T00:00:00Z": "week_ending_sunday", + None: __("Original value"), + "PT1S": __("Second"), + "PT1M": __("Minute"), + "PT5M": __("5 minute"), + "PT10M": __("10 minute"), + "PT15M": __("15 minute"), + "PT0.5H": __("Half hour"), + "PT1H": __("Hour"), + "P1D": __("Day"), + "P1W": __("Week"), + "P1M": __("Month"), + "P0.25Y": __("Quarter"), + "P1Y": __("Year"), + "1969-12-28T00:00:00Z/P1W": __("Week starting sunday"), + "1969-12-29T00:00:00Z/P1W": __("Week starting monday"), + "P1W/1970-01-03T00:00:00Z": __("Week ending saturday"), + "P1W/1970-01-04T00:00:00Z": __("Week_ending sunday"), } diff --git a/superset/utils/core.py b/superset/utils/core.py index 4c48f73d08..893592bbc8 100644 --- a/superset/utils/core.py +++ b/superset/utils/core.py @@ -1042,12 +1042,16 @@ def merge_extra_form_data(form_data: Dict[str, Any]) -> None: and add applied time extras to the payload. """ time_extras = { + "granularity": "__granularity", + "granularity_sqla": "__granularity", "time_range": "__time_range", - "granularity_sqla": "__time_col", + } + allowed_extra_overrides: Dict[str, Optional[str]] = { "time_grain_sqla": "__time_grain", "druid_time_origin": "__time_origin", - "granularity": "__granularity", + "time_range_endpoints": None, } + applied_time_extras = form_data.get("applied_time_extras", {}) form_data["applied_time_extras"] = applied_time_extras extra_form_data = form_data.pop("extra_form_data", {}) @@ -1060,12 +1064,20 @@ def merge_extra_form_data(form_data: Dict[str, Any]) -> None: time_extra = time_extras.get(key) if time_extra: applied_time_extras[time_extra] = value + extras = form_data.get("extras", {}) + for key, value in allowed_extra_overrides.items(): + extra = extras.get(key) + if value and extra: + applied_time_extras[value] = extra + form_data.update(extras) adhoc_filters = form_data.get("adhoc_filters", []) form_data["adhoc_filters"] = adhoc_filters + append_adhoc_filters = append_form_data.get("adhoc_filters", []) + adhoc_filters.extend({"isExtra": True, **fltr} for fltr in append_adhoc_filters) if append_filters: adhoc_filters.extend( - [to_adhoc({"isExtra": True, **fltr}) for fltr in append_filters if fltr] + to_adhoc({"isExtra": True, **fltr}) for fltr in append_filters if fltr ) diff --git a/tests/core_tests.py b/tests/core_tests.py index 111964aeba..fb1721deeb 100644 --- a/tests/core_tests.py +++ b/tests/core_tests.py @@ -107,7 +107,7 @@ class TestCore(SupersetTestCase): self.login(username="admin") slc = self.get_slice("Girls", db.session) resp = self.get_resp("/superset/slice/{}/".format(slc.id)) - assert "Time Column" in resp + assert "Original value" in resp assert "List Roles" in resp # Testing overrides diff --git a/tests/dashboard_utils.py b/tests/dashboard_utils.py index 6944b63c3f..311dd5965a 100644 --- a/tests/dashboard_utils.py +++ b/tests/dashboard_utils.py @@ -17,7 +17,7 @@ """Utils to provide dashboards for tests""" import json -from typing import Any, Dict, List +from typing import Any, Dict, List, Optional from pandas import DataFrame @@ -34,6 +34,7 @@ def create_table_for_dashboard( database: Database, dtype: Dict[str, Any], table_description: str = "", + fetch_values_predicate: Optional[str] = None, ) -> SqlaTable: df.to_sql( table_name, @@ -51,6 +52,8 @@ def create_table_for_dashboard( ) if not table: table = table_source(table_name=table_name) + if fetch_values_predicate: + table.fetch_values_predicate = fetch_values_predicate table.database = database table.description = table_description db.session.merge(table) diff --git a/tests/databases/commands_tests.py b/tests/databases/commands_tests.py index 2e2caaedcc..5594b56f5b 100644 --- a/tests/databases/commands_tests.py +++ b/tests/databases/commands_tests.py @@ -225,7 +225,7 @@ class TestExportDatabasesCommand(SupersetTestCase): "default_endpoint": None, "description": "", "extra": None, - "fetch_values_predicate": None, + "fetch_values_predicate": "123 = 123", "filter_select_enabled": True, "main_dttm_col": "ds", "metrics": [ diff --git a/tests/fixtures/birth_names_dashboard.py b/tests/fixtures/birth_names_dashboard.py index d07bbf43e4..a9880aa4dc 100644 --- a/tests/fixtures/birth_names_dashboard.py +++ b/tests/fixtures/birth_names_dashboard.py @@ -18,7 +18,7 @@ import json import string from datetime import date, datetime from random import choice, getrandbits, randint, random, uniform -from typing import Any, Dict, List +from typing import Any, Dict, List, Optional import pandas as pd import pytest @@ -31,7 +31,7 @@ from superset.models.core import Database from superset.models.dashboard import Dashboard from superset.models.slice import Slice from superset.utils.core import get_example_database -from tests.dashboard_utils import create_dashboard, create_table_for_dashboard +from tests.dashboard_utils import create_table_for_dashboard from tests.test_app import app @@ -63,7 +63,13 @@ def _load_data(): "state": String(10), "name": String(255), } - table = _create_table(df, table_name, database, dtype) + table = _create_table( + df=df, + table_name=table_name, + database=database, + dtype=dtype, + fetch_values_predicate="123 = 123", + ) from superset.examples.birth_names import create_slices, create_dashboard @@ -75,9 +81,19 @@ def _load_data(): def _create_table( - df: DataFrame, table_name: str, database: "Database", dtype: Dict[str, Any] + df: DataFrame, + table_name: str, + database: "Database", + dtype: Dict[str, Any], + fetch_values_predicate: Optional[str] = None, ): - table = create_table_for_dashboard(df, table_name, database, dtype) + table = create_table_for_dashboard( + df=df, + table_name=table_name, + database=database, + dtype=dtype, + fetch_values_predicate=fetch_values_predicate, + ) from superset.examples.birth_names import _add_table_metrics, _set_table_metadata _set_table_metadata(table, database) diff --git a/tests/query_context_tests.py b/tests/query_context_tests.py index 67fb8d59ed..c7ec3271dd 100644 --- a/tests/query_context_tests.py +++ b/tests/query_context_tests.py @@ -302,11 +302,44 @@ class TestQueryContext(SupersetTestCase): payload["result_type"] = ChartDataResultType.QUERY.value query_context = ChartDataQueryContextSchema().load(payload) responses = query_context.get_payload() - self.assertEqual(len(responses), 1) + assert len(responses) == 1 response = responses["queries"][0] - self.assertEqual(len(response), 2) - self.assertEqual(response["language"], "sql") - self.assertIn("SELECT", response["query"]) + assert len(response) == 2 + assert response["language"] == "sql" + assert "SELECT" in response["query"] + + @pytest.mark.usefixtures("load_birth_names_dashboard_with_slices") + def test_fetch_values_predicate_in_query(self): + """ + Ensure that fetch values predicate is added to query + """ + self.login(username="admin") + payload = get_query_context("birth_names") + payload["result_type"] = ChartDataResultType.QUERY.value + payload["queries"][0]["apply_fetch_values_predicate"] = True + query_context = ChartDataQueryContextSchema().load(payload) + responses = query_context.get_payload() + assert len(responses) == 1 + response = responses["queries"][0] + assert len(response) == 2 + assert response["language"] == "sql" + assert "123 = 123" in response["query"] + + @pytest.mark.usefixtures("load_birth_names_dashboard_with_slices") + def test_fetch_values_predicate_not_in_query(self): + """ + Ensure that fetch values predicate is not added to query + """ + self.login(username="admin") + payload = get_query_context("birth_names") + payload["result_type"] = ChartDataResultType.QUERY.value + query_context = ChartDataQueryContextSchema().load(payload) + responses = query_context.get_payload() + assert len(responses) == 1 + response = responses["queries"][0] + assert len(response) == 2 + assert response["language"] == "sql" + assert "123 = 123" not in response["query"] def test_query_object_unknown_fields(self): """ diff --git a/tests/utils_tests.py b/tests/utils_tests.py index d810c40f2d..ee373c25cb 100644 --- a/tests/utils_tests.py +++ b/tests/utils_tests.py @@ -924,15 +924,38 @@ class TestUtils(SupersetTestCase): "time_range": "Last 10 days", "extra_form_data": { "append_form_data": { - "filters": [{"col": "foo", "op": "IN", "val": "bar"}] + "filters": [{"col": "foo", "op": "IN", "val": ["bar"]}], + "adhoc_filters": [ + { + "expressionType": "SQL", + "clause": "WHERE", + "sqlExpression": "1 = 0", + } + ], }, "override_form_data": {"time_range": "Last 100 years",}, }, } merge_extra_form_data(form_data) assert form_data["applied_time_extras"] == {"__time_range": "Last 100 years"} + adhoc_filters = form_data["adhoc_filters"] + assert adhoc_filters[0] == { + "clause": "WHERE", + "expressionType": "SQL", + "isExtra": True, + "sqlExpression": "1 = 0", + } + converted_filter = adhoc_filters[1] + del converted_filter["filterOptionName"] + assert converted_filter == { + "clause": "WHERE", + "comparator": ["bar"], + "expressionType": "SIMPLE", + "isExtra": True, + "operator": "IN", + "subject": "foo", + } assert form_data["time_range"] == "Last 100 years" - assert len(form_data["adhoc_filters"]) == 1 def test_ssl_certificate_parse(self): parsed_certificate = parse_ssl_cert(ssl_certificate)