Compare commits

..
112 Commits
Author SHA1 Message Date
Ville BrofeldtandGitHub 87a895cc4a feat(native-filters): add refresh button to default value picker (#14375)
* feat(native-filters): add refresh button to default value picker

* skip flaky test
2021-04-27 19:18:34 +03:00
umeandGitHub d645312c7f chore: Improve Japanese translation (#14339) 2021-04-27 09:00:25 -07:00
Kamil GabryjelskiandGitHub 41ccebce91 feat(native-filters): Use datasets in dashboard as default options for native filters (#14374)
* Use defaultOptions in dataset picker

* Remove console log

* Temporarily skip failing test
2021-04-27 18:04:57 +03:00
ʈᵃᵢandGitHub 1ec743f29e chore(docker-compose): use dev image for docker-compose-non-dev.yml (#14342) 2021-04-27 08:32:53 -04:00
Kamil GabryjelskiandGitHub 20ab0869fa feat(native-filters): Implement adhoc filters and time picker in Range and Select native filters (#14313)
* Implement adhoc filters in Range and Select native filters

* Add time picker

* Remove additional filters from datamask

* Create separate stylesheet for AdhocFilterControl in native filters

* Rename Time picker to Time range

* Fix columns in AdhocFilter empty when creating a new filter

* Skip flaky test
2021-04-27 11:08:05 +02:00
simcha90andGitHub 03e4a5b6b7 fix(native-filters): Update filter saving (#14370)
* fix:fix get permission function

* fix: not reload charts after save filters

* fix: not reload charts after save filters

* fix: temp commit type

* lint: add typing
2021-04-27 11:20:04 +03:00
Michael S. MolinaandGitHub d0be1ff79e chore: Moves Tabs to the components folder (#14136) 2021-04-27 00:15:21 -07:00
22f9e12a3b chore: bump 0.17.38 (#14355)
* chore: bump 0.17.37

* chore: update package-lock

* chore: revert echarts upgrade

* bump echarts package to 0.17.38

Co-authored-by: Ville Brofeldt <ville.v.brofeldt@gmail.com>
2021-04-27 09:30:39 +03:00
Phillip Kelley-DotsonandGitHub 69f2af9fb6 refactor(addslicecontainer): move slice container panel from bootstrap panel to ant-d (#14035)
* slice boostrap panel to ant-d

* remove panel

* remove space

* fix lint

* fix addslicecontainer

* Update AddSliceContainer.tsx
2021-04-26 22:13:49 -07:00
Sam Faber-ManningandGitHub 6898dd916f update default cron settings for new alerts and reports (#14363) 2021-04-26 18:11:15 -07:00
Michael S. MolinaandGitHub 4fbb572568 refactor: Bootstrap to AntD - Form - iteration 1 (#14106) 2021-04-26 15:03:53 -07:00
Ben ReinhartandGitHub 8dd0620fd3 chore: add some basic instrumentation to Node WebSocket server (#14354)
* chore: add some basic instrumentation

* Switch to statsd using hot-shots

* Cleanup a few leftover bits
2021-04-26 14:05:10 -07:00
Ben ReinhartandGitHub 2a1235c0c2 fix: Cleanup serialization and hashing code (#14317) 2021-04-26 14:04:40 -07:00
umeandGitHub ebc938059b fix: pybabel extract fails (#14338) 2021-04-26 13:59:04 -07:00
Lily KuangandGitHub 876779865c feat(alert/report): update content format radio buttons (#14235)
* update content format selection ui

* translations

* update test
2021-04-26 11:33:55 -07:00
Ville BrofeldtandGitHub d7fc2031b1 feat(filter-box): sort by metric on backend (#14340) 2021-04-26 21:06:19 +03:00
Daniel Vaz GasparandGitHub 45e209d487 fix: flaky test for alerts and reports (#14347) 2021-04-26 18:56:48 +01:00
8a0d321084 fix(native-filters): allowClear only when required not checked (#14353)
* fix(native-filters): allowClear only when required not checked

* Update superset-frontend/src/filters/components/Select/controlPanel.ts

Co-authored-by: Kamil Gabryjelski <kamil.gabryjelski@gmail.com>

Co-authored-by: Kamil Gabryjelski <kamil.gabryjelski@gmail.com>
2021-04-26 20:48:17 +03:00
Rob DiCiuccioandGitHub d435163d13 chore: Add Redis password option to helm chart (#14274)
* Add redis password option to helm chart

* Bump chart version
2021-04-26 10:36:41 -07:00
Daniel Vaz GasparandGitHub 437be4b689 ci: set remote URL to https and bump sha (#14350)
* ci: set remote URL to https and bump sha

* update gitmodules
2021-04-26 17:43:32 +01:00
Rob DiCiuccioandGitHub 6875a1a9e2 Make g.user attribute access safe for public users (#14287) 2021-04-26 08:50:50 -07:00
simcha90andGitHub 7ff35dfdfb fix(native-filters): Fix indicators (#14334)
* fix:fix get permission function

* fix: hide featured filters

* test: fix FF in tests

* test: fix FF in tests

* fix: fix unset cross filters
2021-04-26 13:22:11 +03:00
Eran LevyandGitHub b8356a64ee chore(docker-compose): bump redis version 2021-04-25 22:06:51 -06:00
Amit MiranandGitHub 1faaf199ad chore(docs): remove .py from db migrate -m (#14331)
no need to state the python extension 
before: add_metadata_column_to_annotation_model.py.py
after: add_metadata_column_to_annotation_model.py
2021-04-26 07:02:02 +03:00
Chris CariniandGitHub 4d2c9324be Fixing spelling: clint -> client (#14323) 2021-04-25 22:39:28 +03:00
simcha90andGitHub 3e8bf96642 fix(native-filters): Fix first loading of charts (#14332)
* fix:fix get permission function

* fix: fix unnecessary loading for native filters

* test: fix mocks
2021-04-25 13:58:53 +03:00
b0f8f6b6ad fix(hive): Use parquet rather than textfile when uploading CSV files to Hive (#14240)
* fix(hive): Use parquet rather than textfile when uploading CSV files

* [csv/excel]: Use stream rather than temporary file

Co-authored-by: John Bodley <john.bodley@airbnb.com>
2021-04-24 18:17:30 +12:00
Ville BrofeldtandGitHub e392e2ed39 feat(native-filters): add option to create value in select filter (#14314)
* feat(native-filters): add option to create value in select filter

* address comments
2021-04-24 08:26:24 +03:00
David Aaron SuddjianandGitHub 91ba897f8e fix(dashboard): Add caching for dashboard datasets (#14306)
* fix(dashboard): [WIP] add caching back in to the dashboard dataset api

* caching works! remove log message

* remove unused full_data method

* add caching to the charts endpoint as well

* spread the cache love

* lint

* Revert "spread the cache love"

This reverts commit ef322a3b0df7d35446a60141ad98288102547a52.

* Revert "add caching to the charts endpoint as well"

This reverts commit d3d1584989324efe56d08c081570149454ddf212.

* it's a list
2021-04-23 21:04:45 -07:00
a8781c5313 fix(hive): Update CSV to Hive upload prefix (#14255)
* fix(hive): Update CSV to Hive upload prefix

* Trigger notification

Co-authored-by: John Bodley <john.bodley@airbnb.com>
2021-04-24 13:20:31 +12:00
Beto DealmeidaandGitHub 919fd496a9 WIP (#14252) 2021-04-23 16:59:44 -07:00
Michael S. MolinaandGitHub aada73302f chore: Moves spec files to the src folder - iteration 3 (#14202) 2021-04-23 16:19:12 -07:00
Michael S. MolinaandGitHub 1bc73f2cba chore: Moves spec files to the src folder - iteration 2 (#14201) 2021-04-23 16:18:46 -07:00
Michael S. MolinaandGitHub 98b450aa76 chore: Moves spec files to the src folder - iteration 1 (#14200) 2021-04-23 16:18:16 -07:00
Erik RitterandGitHub 76fdd072ba fix: unbreak CI (#14319) 2021-04-23 15:04:04 -07:00
Beto DealmeidaandGitHub e7ad03d44f feat: add endpoint to fetch available DBs (#14208)
* feat: add endpoint to fetch available DBs

* Fix lint
2021-04-23 10:51:47 -07:00
Beto DealmeidaandGitHub ffcacc3393 fix: new import/export CLI (#13921)
* fix: CLI for import/export

* Add tests

* Remove debug
2021-04-23 10:50:49 -07:00
Michael S. MolinaandGitHub 58534b36c5 chore: Improves Icons storybook (#14193) 2021-04-23 09:57:12 -07:00
ʈᵃᵢandGitHub e913ef3261 docs: add publish step (#14304) 2021-04-23 10:43:58 -06:00
Ville BrofeldtandGitHub 2b57ebaffd feat(native-filters): add tooltip to control values (#14312) 2021-04-23 19:29:51 +03:00
Yongjie ZhaoandGitHub 67535bb320 refactor: reorganize dateFilterUtils.tx (#14309)
* refactor: reorganize dateFilterUtils.tx

* move spec to src dirctory
2021-04-23 16:05:50 +08:00
Yongjie ZhaoandGitHub d1afca4fa1 fix: custom TimeRange can not input value (#14084) 2021-04-23 15:20:37 +08:00
Michael S. MolinaandGitHub b963624e12 refactor: Boostrap to AntD - Row/Col (#14100) 2021-04-22 20:57:17 -07:00
Hugh A. Miles IIandGitHub 01de3096b3 chore: starter make file (#13970)
* starter make file

* yea

* update docs

* lit

* remove venv from comamnds

* venv
2021-04-22 17:54:12 -04:00
Michael S. MolinaandGitHub 3e23c103dc chore: Moves WarningIconWithTooltip to own folder (#14123) 2021-04-22 13:50:11 -07:00
zuzana-vejandGitHub 86233d1676 chore: SQLLab row limit warning using Alert component (#14298) 2021-04-22 10:12:46 -07:00
Daniel Vaz GasparandGitHub 38a7c537ff feat: add alerts & reports to docker compose (#14267)
* feat: add alerts & reports to docker compose

* change to firefox

* add missing package
2021-04-22 17:42:52 +01:00
Ville BrofeldtandGitHub c760030b83 fix(sqla): timeseries limit not applied when using columns (#14297) 2021-04-22 10:38:28 +03:00
Ville BrofeldtandGitHub fe1d32dc2a fix(db2): change name and add legacy alias (#14295) 2021-04-22 09:56:22 +03:00
Beto DealmeidaandGitHub 5d3191bb61 feat: catch errors on do_ping (#14250) 2021-04-21 18:43:40 -04:00
Lyndsi Kay WilliamsandGitHub 70cfb7752c chore: Code cleanup in DatabaseModal (#14196) 2021-04-21 13:41:50 -04:00
Jesse YangandGitHub 2dd20df03d fix(dashboard): draft dashboards should be viewable (#14207)
* fix(dashboard): draft dashboards should have open access

* Remove a duplicate test
2021-04-21 09:54:51 -07:00
852e840575 fix(explore): CUSTOM SQL tab should automatically update (#14194)
* fix(explore): CUSTOM SQL tab should automatically update

* fix(explore): CUSTOM SQL tab should automatically update

* fix: lint

* fix(explore): default value

Co-authored-by: Yongjie Zhao <yongjiezhao@apache.org>

Co-authored-by: liuyaozong <liuyaozong@baijiahulian.com>
Co-authored-by: stephenLYZ <vueact@gmail.com>
Co-authored-by: Yongjie Zhao <yongjiezhao@apache.org>
2021-04-21 14:30:18 +08:00
Yongjie ZhaoandGitHub 0dfb32cf08 fix: incorrect module reference (#14258) 2021-04-21 10:37:24 +08:00
Ben ReinhartandGitHub 3ef63171a9 chore: WebSocket server improvements (#14257)
* Update some types and resolve conflicts

* Logger improvements

* Ensure logger can log exception objects
* Remove logging output in tests (for now)

* Add License
2021-04-20 17:28:08 -07:00
Lyndsi Kay WilliamsandGitHub a846015f4d fix: Center each import icon and add a tooltip II (#14192) 2021-04-20 19:59:48 -04:00
392d8a8107 fix: Handle bad permission errors for bigquery test connections (#14147)
* starter make file

* yea

* move messaging to config

* Delete Makefile

* remove

* checkout

* check for db generic errors

* checkout bad files

* add proper message

* add docs for new permissions codes

* Update superset/errors.py

Co-authored-by: AAfghahi <48933336+AAfghahi@users.noreply.github.com>

* Update superset/errors.py

Co-authored-by: AAfghahi <48933336+AAfghahi@users.noreply.github.com>

* rename var

* starter regex

* fix

* fix

* fix linting

* update test

* yerp

* fixed test

* added regex

* Apply suggestions from code review

Co-authored-by: Beto Dealmeida <roberto@dealmeida.net>

* address comments

* update docs

* prettier

* fux

* add space

* Update errors.py

* Update types.ts

Co-authored-by: AAfghahi <48933336+AAfghahi@users.noreply.github.com>
Co-authored-by: Beto Dealmeida <roberto@dealmeida.net>
2021-04-20 19:19:36 -04:00
Elizabeth ThompsonandGitHub ff665fa5a7 feat: restyle database modal (#14092)
* restyle database modal

* change name of tab to Basic

* update test with RTL better RTL render statement

* change color and position of required asterisk

* refactor db logic
2021-04-20 18:21:07 -04:00
Erik RitterandGitHub 97e086051c chore: bump superset-ui (#14253) 2021-04-20 15:16:58 -07:00
13d4902711 feat(native-filters): select group by support (#14217)
* chore: initial commit

* feat: groupby filter

Co-authored-by: Simcha Shats <simcha.shats@nielsen.com>
2021-04-20 18:52:33 +03:00
Michael S. MolinaandGitHub 42fb2286ad chore: Moves Dropdown to the components folder (#14126) 2021-04-20 08:48:28 -07:00
Michael S. MolinaandGitHub d1b458c4c5 chore: Moves Radio to the components folder (#14133) 2021-04-20 08:48:10 -07:00
Michael S. MolinaandGitHub 8441590812 chore: Moves Tooltip to the components folder (#14137) 2021-04-20 08:47:47 -07:00
Michael S. MolinaandGitHub ec79b7be1f chore: Moves the staticPages folder to the assets folder (#14167) 2021-04-20 08:47:24 -07:00
Ville BrofeldtandGitHub 55bf72aead chore(prophet): bump prophet to 1.0.1 (#14228) 2021-04-20 15:55:55 +03:00
Ville BrofeldtandGitHub 0807ab44a5 fix(native-filters): merge_extra_form_data extras processing (#14244)
* fix: merge_extra_form_data extras processing

* move props that are later moved back in viz.py
2021-04-20 14:24:33 +03:00
simcha90andGitHub 7e5440a359 test(native-filters): Filter config modal test (#14245)
* test: add tests for filter bar

* test: merge filter bar tests with master

* test: add test for filter set

* test: filter set tests

* test: merge with master

* test: fix tests for filter bar

* test: filter config modal

* test: add select filter

* feat: filter config modal

* lint: fix lint

* lint: fix TS

* test: test testWithId
2021-04-20 14:07:08 +03:00
Kamil GabryjelskiandGitHub 6119d8e998 Fix filter edit popover not opening in DnD mode (#14243) 2021-04-20 11:45:48 +02:00
simcha90andGitHub d386e66f59 test(native-filters): add integration tests for filter bar (#14098)
* test: add tests for filter bar

* test: merge filter bar tests with master

* test: add test for filter set

* test: filter set tests

* test: merge with master

* test: fix tests for filter bar

* fix: fix CR notes

* fix: fix CR notes
2021-04-20 12:24:12 +03:00
simcha90andGitHub 9d67b46576 fix(native-filters): fix remove native filters (#14218)
* fix:fix get permission function

* fix: clean data mask on chart removing

* refactor: fix reducer
2021-04-20 09:48:23 +03:00
Rob DiCiuccioandGitHub 25922e341f Add Preset code owners for ephemeral test env workflows (#14238) 2021-04-19 22:19:18 -07:00
Beto DealmeidaandGitHub 13bf023100 feat: improve engine spec discoverability (#14204)
* feat: improve engine spec discoverability

* Address comments

* Fix tests
2021-04-19 17:24:22 -07:00
Michael S. MolinaandGitHub c2d11ac53e chore: Moves InfoTooltip to the components folder (#14128) 2021-04-19 16:25:29 -07:00
Carlos Fidel Selva OchoaandGitHub 1448f78406 fix: Use utils.json_iso_dttm_ser to dump jsons when async query execution (#13830)
* Use utils.json_iso_dttm_ser to dump jsons

If encoding is not `None`, the default encoder `utils.json_iso_dttm_ser` is not used for binary data and instead tries to encode to the default 'utf-8'. 
This fixes https://github.com/apache/superset/issues/13829

* Change to comply with tox -m pre-commit
2021-04-19 21:04:58 +08:00
Đặng Minh DũngandGitHub 11e0f4cb2d feat: TrinoEngineSpec.adjust_database_uri (#14122)
* feat: TrinoEngine implement adjust_database_uri

Signed-off-by: Đặng Minh Dũng <dungdm93@live.com>

* test: TrinoEngine implement adjust_database_uri

Signed-off-by: Đặng Minh Dũng <dungdm93@live.com>
2021-04-19 13:10:12 +03:00
Amit MiranandGitHub ca359402bd chore: bump package.json (#14222)
* chore: bump package.json

* chore: bump package.json and lock
2021-04-19 06:52:24 +03:00
jawabuuandGitHub 1cc3b9613e Add superset helm repository (#14223) 2021-04-18 19:59:38 -07:00
simcha90andGitHub c01f8101eb fix(cross-filters): Fix missed metadata (#14220)
* fix:fix get permission function

* fix: fix missed metadata case
2021-04-18 18:46:38 +03:00
jawabuuandGitHub 61325635da ci: use git submodules for Chart Actions (#14211)
* Add chart-action submodules

* use local github actions for chart actions

* Run actions checkout for local checkout

* Run lint when PR is edited

* Remove path filter and dummy value

* Fix fetch-depth

* Test chart version bump

* Update maintainer to pass validation

* Update maintainer to pass validation
2021-04-17 19:13:36 +03:00
Michael S. MolinaandGitHub 77a9cc7088 chore: Moves Collapse to the components folder (#14124) 2021-04-16 15:55:04 -07:00
Michael S. MolinaandGitHub b83ee46d0f chore: Moves Modal to the components folder (#14130) 2021-04-16 15:49:53 -07:00
c7112d1c48 feat: error messages for Presto connections (#14172)
* chore: rename connection errors

* feat: error messages for Presto connections

* Add unit tests

* Update docs/src/pages/docs/Miscellaneous/issue_codes.mdx

Co-authored-by: AAfghahi <48933336+AAfghahi@users.noreply.github.com>

Co-authored-by: AAfghahi <48933336+AAfghahi@users.noreply.github.com>
2021-04-16 15:49:47 -04:00
AAfghahiandGitHub df04c3af21 feat: error messages when connecting to mssql (#14171)
* database errors for mssql

* revisions
2021-04-16 09:43:42 -07:00
Craig RuedaandGitHub 8db7be16da fix: Switching to local codecov script (#14170)
* Switching to local codecov script

* Adding license / update instructions

* Fixing FE build

* Fixing FE codecov test
2021-04-16 09:26:50 -07:00
Erik RitterandGitHub a3e302374b fix: Add extra requires for shillelagh (#14180)
* fix: Add extra requires for shillelagh

* Update google-sheets.mdx

* Update index.mdx
2021-04-16 09:16:35 -07:00
01f13c5678 chore: type some SQL Lab components (#14178)
* chore: type some SQL Lab components

* Update superset-frontend/src/SqlLab/components/QueryHistory.tsx

Co-authored-by: Michael S. Molina <70410625+michael-s-molina@users.noreply.github.com>

Co-authored-by: Michael S. Molina <70410625+michael-s-molina@users.noreply.github.com>
2021-04-16 09:16:16 -07:00
jawabuuandGitHub c3e89d53c2 feat: publish superset helm chart (#14163)
* Create initial helm-release action for superset

* Add lintconf to ensure chart passes validation

* Add lint-test job

* Add apache licence headers

* Run job for master only

* Move helm-lint to separate workflow

* Helm release for master & helm dir changes only

* Dummy change to test linter
2021-04-16 09:13:43 -07:00
a49e0b2037 feat: Adding encrypted field factory (#14109)
* First cut at adding enc type factory

* Finalized enc type factory

* Adding unit test

* PyLinting

* Adding license

* Apply suggestions from code review

Co-authored-by: Jesse Yang <jesse.yang@airbnb.com>

* Moving things from enc -> encrypt

* CI commit

* One more fix

* Tweaking config name

* Fixing broken test

* Fixing broken test again

Co-authored-by: Jesse Yang <jesse.yang@airbnb.com>
2021-04-16 09:01:18 -07:00
Ville BrofeldtandGitHub 7e0e9ac3fc feat(viz): add mixed and radar chart (#14197) 2021-04-16 23:59:32 +08:00
Ville BrofeldtandGitHub fe21de3fc4 fix(viz): time shift read-only error (#14191) 2021-04-16 16:48:06 +03:00
Kamil GabryjelskiandGitHub cab110e354 Enable the new pivot table (#14187) 2021-04-16 10:46:50 +02:00
Michael S. MolinaandGitHub be78cd1a1f chore: Configures Jest to ignore storybook files when collecting coverage statistics (#14164) 2021-04-15 23:17:31 -07:00
Michael S. MolinaandGitHub 018caa528a chore: Moves Switch to the components folder (#14135) 2021-04-15 22:54:26 -07:00
Michael S. MolinaandGitHub e4c8084285 chore: Moves DropdownButton to the components folder (#14127) 2021-04-15 22:46:18 -07:00
Michael S. MolinaandGitHub ec75dc178b chore: Moves CronPicker to the components folder (#14125) 2021-04-15 22:44:12 -07:00
Phillip Kelley-DotsonandGitHub 38a1f65646 chore(toggle thumbnails): use localstorage for toggle (#14013)
* use localstorage for toggle

* fix lint

* add check
2021-04-15 22:03:46 -07:00
df7e2b6a8e feat(alert/report): chart as csv format attachment for email and slack (#13828)
* add ui for setting report format

* refactor default notification format

* init csv data alert report

* add report format to report_schedule model

* add ALERTS_ATTACH_REPORTS feature flag

* fix lint

* update check image tag

* fix migrations

Co-authored-by: samtfm <sam@preset.io>
2021-04-15 14:07:49 -07:00
Beto DealmeidaandGitHub 21c6efea67 chore: rename connection errors (#14169) 2021-04-15 10:57:02 -07:00
Beto DealmeidaandGitHub c1cb3619ab feat: script to benchmark DB migrations (#13561) 2021-04-15 10:55:35 -07:00
Ben ReinhartandGitHub 3294f77ca5 feat: Add health endpoint to WebSocket server (#14110) 2021-04-15 09:42:01 -07:00
Phillip Kelley-DotsonandGitHub fbf0149d8b refactor(userInfo): userinfo panel to styled component (#14090)
* migrate component

* fix lint

* remove collapse

* fix test
2021-04-15 09:24:34 -07:00
19d2e10aff chore: update RELEASING readme (#14152)
* update releasing readme

* Update RELEASING/README.md

Co-authored-by: Erik Ritter <erik.ritter@airbnb.com>

Co-authored-by: Erik Ritter <erik.ritter@airbnb.com>
2021-04-15 08:58:46 -07:00
AAfghahiandGitHub eadff5f41e feat: invalid DB name error messages (MySQL/Postgres/Redshift) (#14146)
* initial DB custom errors for mysql

* added redshift and postgres
2021-04-15 08:02:47 -07:00
8ef572a412 refactor(native-filters): update dataMask and ExtraFormData schema (#13983)
* refactor: updates usage of `ownFilters` to `ownState`

* refactor: update dataMask (final)

* lint: fix lint

* refactor: revert feat

* fix: fix missed chart configuration

* add filter set migration

* apply new changes

* fix migration revision

* update migration

* fix jest mock

* js lint

* fix test types

* update tests and types

* remove append_form_data from tests

* fix findExistingFilterSet tests

* add migration test

Co-authored-by: Ville Brofeldt <ville.v.brofeldt@gmail.com>
2021-04-15 17:43:29 +03:00
Ville BrofeldtandGitHub 68e11cd47f fix(dashboard): filter set hydration not working (#14129) 2021-04-15 06:09:12 +03:00
AAfghahiandGitHub f1acb2f974 horizontal scroll (#14140) 2021-04-14 16:31:13 -07:00
Jesse YangandGitHub 6755083e3a fix(dashboard): incorrect perm for users with multiple roles (#14148) 2021-04-14 16:04:09 -07:00
Lyndsi Kay WilliamsandGitHub 36bd6d8303 feat: FE: Import for Queries II (#14091)
* Copied changes over

* Tests passing

* Import testing complete
2021-04-14 16:02:35 -07:00
Beto DealmeidaandGitHub 21f973f0bd feat: error messages when connecting to MSSQL (#14093)
* feat: error messages when connecting to MSSQL

* Address comments
2021-04-14 10:57:58 -07:00
ef1f048d81 feat: add Echarts gauge chart (#14072)
* feat: echarts gauge chart

* fix

* change plugin order

Co-authored-by: root <root@superset.ikrsnik.devonly.net>
2021-04-14 09:25:26 -07:00
GeidoandGitHub 474f1e2044 test: Add tests for Dashboard Header and HeaderActionsDropdown components (#13973)
* Add tests for HeaderActionsDropdown - WIP

* Fix trigger node

* Add types

* Clean up

* Add tests for Header

* Delete obsolete tests

* Add factory and clean up

* Add opposite case

* Fix file name

* Include latest changes
2021-04-14 06:54:24 -07:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
a548b69201 build(deps): bump urijs from 1.19.4 to 1.19.6 in /superset-frontend (#13393)
Bumps [urijs](https://github.com/medialize/URI.js) from 1.19.4 to 1.19.6.
- [Release notes](https://github.com/medialize/URI.js/releases)
- [Changelog](https://github.com/medialize/URI.js/blob/gh-pages/CHANGELOG.md)
- [Commits](https://github.com/medialize/URI.js/compare/v1.19.4...v1.19.6)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-04-13 23:15:27 -07:00
468 changed files with 21312 additions and 10503 deletions
+5
View File
@@ -1,3 +1,8 @@
# Notify all committers of DB migration changes, per SIP-59
# https://github.com/apache/superset/issues/13351
/superset/migrations/ @apache/superset-committers
# Notify Preset team when ephemeral env settings are changed
.github/workflows/ecs-task-definition.json @robdiciuccio @craig-rueda @benjreinhart
.github/workflows/docker-ephemeral-env.yml @robdiciuccio @craig-rueda @benjreinhart
.github/workflows/ephemeral*.yml @robdiciuccio @craig-rueda @benjreinhart
+1 -6
View File
@@ -131,12 +131,7 @@ testdata() {
codecov() {
say "::group::Upload code coverage"
local codecovScript="${HOME}/codecov.sh"
# download bash script if needed
if [[ ! -f "$codecovScript" ]]; then
curl -s https://codecov.io/bash >"$codecovScript"
fi
bash "$codecovScript" "$@"
bash ".github/workflows/codecov.sh" "$@"
say "::endgroup::"
}
+1903
View File
File diff suppressed because it is too large Load Diff
+15 -2
View File
@@ -9,14 +9,15 @@ on:
- "docs/**"
jobs:
docs:
name: docs
build-deploy:
name: Build & Deploy
runs-on: ubuntu-20.04
steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@v2
with:
persist-credentials: false
submodules: recursive
- name: npm install
working-directory: ./docs
run: |
@@ -29,3 +30,15 @@ jobs:
working-directory: ./docs
run: |
npm run build
- name: deploy docs
if: github.ref == 'refs/heads/master'
uses: ./.github/actions/github-action-push-to-another-repository
env:
API_TOKEN_GITHUB: ${{ secrets.SUPERSET_SITE_BUILD }}
with:
source-directory: './docs/public'
destination-github-username: 'apache'
destination-repository-name: 'superset-site'
target-branch: 'asf-site'
commit-message: "deploying docs: ${{ github.event.head_commit.message }} (apache/superset@${{ github.sha }})"
user-email: dev@superset.apache.org
+1 -2
View File
@@ -44,5 +44,4 @@ jobs:
- name: Upload code coverage
if: steps.check.outcome == 'failure'
working-directory: ./superset-frontend
run: |
bash <(curl -s https://codecov.io/bash) -c -F javascript
run: ../.github/workflows/codecov.sh -c -F javascript
+46
View File
@@ -0,0 +1,46 @@
name: Lint and Test Charts
on:
pull_request:
types: [opened, edited, reopened, synchronize]
jobs:
lint-test:
runs-on: ubuntu-latest
steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@v2
with:
persist-credentials: false
submodules: recursive
fetch-depth: 0
- name: Set up Helm
uses: azure/setup-helm@v1
with:
version: v3.5.4
- uses: actions/setup-python@v2
with:
python-version: 3.7
- name: Set up chart-testing
uses: ./.github/actions/chart-testing-action
- name: Run chart-testing (list-changed)
id: list-changed
run: |
changed=$(ct list-changed --print-config)
if [[ -n "$changed" ]]; then
echo "::set-output name=changed::true"
fi
env:
CT_CHART_DIRS: helm
CT_SINCE: HEAD
- name: Run chart-testing (lint)
run: ct lint --print-config
env:
CT_CHART_DIRS: helm
CT_LINT_CONF: lintconf.yaml
CT_SINCE: HEAD
@@ -0,0 +1,37 @@
name: Release Charts
on:
push:
branches:
- 'master'
paths:
- 'helm/**'
jobs:
release:
runs-on: ubuntu-latest
steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@v2
with:
persist-credentials: false
submodules: recursive
fetch-depth: 0
- name: Configure Git
run: |
git config user.name "$GITHUB_ACTOR"
git config user.email "$GITHUB_ACTOR@users.noreply.github.com"
- name: Install Helm
uses: azure/setup-helm@v1
with:
version: v3.5.4
- name: Run chart-releaser
uses: ./.github/actions/chart-releaser-action
with:
charts_dir: helm
env:
CR_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
CR_RELEASE_NAME_TEMPLATE: "superset-helm-chart-{{ .Version }}"
@@ -81,7 +81,7 @@ jobs:
- name: Upload code coverage
if: steps.check.outcome == 'failure'
run: |
bash <(curl -s https://codecov.io/bash) -c -F python -F presto
bash .github/workflows/codecov.sh -c -F python -F presto
test-postgres-hive:
if: github.event.pull_request.draft == false
@@ -156,4 +156,4 @@ jobs:
- name: Upload code coverage
if: steps.check.outcome == 'failure'
run: |
bash <(curl -s https://codecov.io/bash) -c -F python -F hive
bash .github/workflows/codecov.sh -c -F python -F hive
@@ -70,7 +70,7 @@ jobs:
- name: Upload code coverage
if: steps.check.outcome == 'failure'
run: |
bash <(curl -s https://codecov.io/bash) -c -F python -F mysql
bash .github/workflows/codecov.sh -c -F python -F mysql
test-postgres:
if: github.event.pull_request.draft == false
@@ -134,7 +134,7 @@ jobs:
- name: Upload code coverage
if: steps.check.outcome == 'failure'
run: |
bash <(curl -s https://codecov.io/bash) -c -F python -F postgres
bash .github/workflows/codecov.sh -c -F python -F postgres
test-sqlite:
if: github.event.pull_request.draft == false
@@ -190,4 +190,4 @@ jobs:
- name: Upload code coverage
if: steps.check.outcome == 'failure'
run: |
bash <(curl -s https://codecov.io/bash) -c -F python -F sqlite
bash .github/workflows/codecov.sh -c -F python -F sqlite
+9
View File
@@ -30,3 +30,12 @@
[submodule ".github/actions/comment-on-pr"]
path = .github/actions/comment-on-pr
url = https://github.com/unsplash/comment-on-pr
[submodule ".github/actions/chart-testing-action"]
path = .github/actions/chart-testing-action
url = https://github.com/helm/chart-testing-action
[submodule ".github/actions/chart-releaser-action"]
path = .github/actions/chart-releaser-action
url = https://github.com/helm/chart-releaser-action
[submodule ".github/actions/github-action-push-to-another-repository"]
path = .github/actions/github-action-push-to-another-repository
url = https://github.com/cpina/github-action-push-to-another-repository
+1 -1
View File
@@ -81,7 +81,7 @@ confidence=
# --enable=similarities". If you want to run only the classes checker, but have
# no Warning level messages displayed, use"--disable=all --enable=classes
# --disable=W"
disable=long-builtin,dict-view-method,intern-builtin,suppressed-message,no-absolute-import,unpacking-in-except,apply-builtin,delslice-method,indexing-exception,old-raise-syntax,print-statement,cmp-builtin,reduce-builtin,useless-suppression,coerce-method,input-builtin,cmp-method,raw_input-builtin,nonzero-method,backtick,basestring-builtin,setslice-method,reload-builtin,oct-method,map-builtin-not-iterating,execfile-builtin,old-octal-literal,zip-builtin-not-iterating,buffer-builtin,getslice-method,metaclass-assignment,xrange-builtin,long-suffix,round-builtin,range-builtin-not-iterating,next-method-called,parameter-unpacking,unicode-builtin,unichr-builtin,import-star-module-level,raising-string,filter-builtin-not-iterating,using-cmp-argument,coerce-builtin,file-builtin,old-division,hex-method,missing-docstring,too-many-lines,ungrouped-imports,import-outside-toplevel,raise-missing-from,super-with-arguments,bad-option-value
disable=long-builtin,dict-view-method,intern-builtin,suppressed-message,no-absolute-import,unpacking-in-except,apply-builtin,delslice-method,indexing-exception,old-raise-syntax,print-statement,cmp-builtin,reduce-builtin,useless-suppression,coerce-method,input-builtin,cmp-method,raw_input-builtin,nonzero-method,backtick,basestring-builtin,setslice-method,reload-builtin,oct-method,map-builtin-not-iterating,execfile-builtin,old-octal-literal,zip-builtin-not-iterating,buffer-builtin,getslice-method,metaclass-assignment,xrange-builtin,long-suffix,round-builtin,range-builtin-not-iterating,next-method-called,parameter-unpacking,unicode-builtin,unichr-builtin,import-star-module-level,raising-string,filter-builtin-not-iterating,using-cmp-argument,coerce-builtin,file-builtin,old-division,hex-method,missing-docstring,too-many-lines,ungrouped-imports,import-outside-toplevel,raise-missing-from,super-with-arguments,bad-option-value,too-few-public-methods
[REPORTS]
+17 -1
View File
@@ -449,6 +449,22 @@ superset load-examples
# Note that your page may not have css at this point.
# See instructions below how to build the front-end assets.
FLASK_ENV=development superset run -p 8088 --with-threads --reload --debugger
Or you can install via our Makefile
```bash
# Create a virtual environment and activate it (recommended)
$ python3 -m venv venv # setup a python3 virtualenv
$ source venv/bin/activate
# install pip packages + pre-commit
$ make install
# Install superset pip packages and setup env only
$ make superset
# Setup pre-commit only
$ make pre-commit
```
**Note: the FLASK_APP env var should not need to be set, as it's currently controlled
@@ -1121,7 +1137,7 @@ Submissions will be considered for submission (or removal) on a case-by-case bas
1. Generate the migration file
```bash
superset db migrate -m 'add_metadata_column_to_annotation_model.py'
superset db migrate -m 'add_metadata_column_to_annotation_model'
```
This will generate a file in `migrations/version/{SHA}_this_will_be_in_the_migration_filename.py`.
+17
View File
@@ -123,10 +123,27 @@ ENTRYPOINT ["/usr/bin/docker-entrypoint.sh"]
# Dev image...
######################################################################
FROM lean AS dev
ARG GECKODRIVER_VERSION=v0.28.0
ARG FIREFOX_VERSION=88.0
COPY ./requirements/*.txt ./docker/requirements-*.txt/ /app/requirements/
USER root
RUN apt-get update -y \
&& apt-get install -y --no-install-recommends libnss3 libdbus-glib-1-2 libgtk-3-0 libx11-xcb1
# Install GeckoDriver WebDriver
RUN wget https://github.com/mozilla/geckodriver/releases/download/${GECKODRIVER_VERSION}/geckodriver-${GECKODRIVER_VERSION}-linux64.tar.gz -O /tmp/geckodriver.tar.gz && \
tar xvfz /tmp/geckodriver.tar.gz -C /tmp && \
mv /tmp/geckodriver /usr/local/bin/geckodriver && \
rm /tmp/geckodriver.tar.gz
# Install Firefox
RUN wget https://download-installer.cdn.mozilla.net/pub/firefox/releases/${FIREFOX_VERSION}/linux-x86_64/en-US/firefox-${FIREFOX_VERSION}.tar.bz2 -O /opt/firefox.tar.bz2 && \
tar xvf /opt/firefox.tar.bz2 -C /opt && \
ln -s /opt/firefox/firefox /usr/local/bin/firefox
# Cache everything for dev purposes...
RUN cd /app \
&& pip install --no-cache -r requirements/docker.txt \
+49
View File
@@ -0,0 +1,49 @@
#
# 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.
#
.PHONY: install superset venv pre-commit
install: superset pre-commit
superset:
# Install external dependencies
pip install -r requirements/local.txt
# Install Superset in editable (development) mode
pip install -e .
# Create an admin user in your metadata database
superset fab create-admin
# Initialize the database
superset db upgrade
# Create default roles and permissions
superset init
# Load some data to play with
superset load-examples
venv:
# Create a virtual environment and activate it (recommended)
python3 -m venv venv # setup a python3 virtualenv
source venv/bin/activate
pre-commit:
# setup pre commit dependencies
pip3 install -r requirements/integration.txt
pre-commit install
+6
View File
@@ -126,6 +126,12 @@ Example:
python changelog.py --previous_version 0.37 --current_version 0.38 changelog
```
You can get a list of pull requests with labels started with blocking, risk, hold, revert and security by using the parameter `--risk`.
Example:
```bash
python changelog.py --previous_version 0.37 --current_version 0.38 changelog --access_token {GITHUB_TOKEN} --risk
```
The script will checkout both branches and compare all the PR's, copy the output and paste it on the `CHANGELOG.md`
Then, in `UPDATING.md`, a file that contains a list of notifications around
+2
View File
@@ -27,6 +27,8 @@ assists people when migrating to a new version.
- [13980](https://github.com/apache/superset/pull/13980): Data health checks no longer use the metadata database as an interim cache. Though non-breaking, deployments which implement complex logic should likely memoize the callback function. Refer to documentation in the confg.py file for more detail.
- [14255](https://github.com/apache/superset/pull/14255): The default `CSV_TO_HIVE_UPLOAD_DIRECTORY_FUNC` callable logic has been updated to leverage the specified database and schema to ensure the upload S3 key prefix is unique. Previously tables generated via upload from CSV with the same name but differ schema and/or cluster would use the same S3 key prefix. Note this change does not impact previously imported tables.
### Breaking Changes
### Potential Downtime
### Deprecations
+2 -2
View File
@@ -14,7 +14,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
x-superset-image: &superset-image apache/superset:latest
x-superset-image: &superset-image apache/superset:latest-dev
x-superset-depends-on: &superset-depends-on
- db
- redis
@@ -26,7 +26,7 @@ x-superset-volumes: &superset-volumes
version: "3.7"
services:
redis:
image: redis:3.2
image: redis:latest
container_name: superset_cache
restart: unless-stopped
volumes:
+23 -4
View File
@@ -20,11 +20,12 @@
# development environments. Also note that superset_config_docker.py is imported
# as a final step as a means to override "defaults" configured here
#
import logging
import os
from datetime import timedelta
from cachelib.file import FileSystemCache
from celery.schedules import crontab
logger = logging.getLogger()
@@ -70,13 +71,31 @@ RESULTS_BACKEND = FileSystemCache("/app/superset_home/sqllab")
class CeleryConfig(object):
BROKER_URL = f"redis://{REDIS_HOST}:{REDIS_PORT}/{REDIS_CELERY_DB}"
CELERY_IMPORTS = ("superset.sql_lab",)
CELERY_IMPORTS = ("superset.sql_lab", "superset.tasks")
CELERY_RESULT_BACKEND = f"redis://{REDIS_HOST}:{REDIS_PORT}/{REDIS_RESULTS_DB}"
CELERY_ANNOTATIONS = {"tasks.add": {"rate_limit": "10/s"}}
CELERY_TASK_PROTOCOL = 1
CELERYD_LOG_LEVEL = "DEBUG"
CELERYD_PREFETCH_MULTIPLIER = 1
CELERY_ACKS_LATE = False
CELERYBEAT_SCHEDULE = {
"reports.scheduler": {
"task": "reports.scheduler",
"schedule": crontab(minute="*", hour="*"),
},
"reports.prune_log": {
"task": "reports.prune_log",
"schedule": crontab(minute=10, hour=0),
},
}
CELERY_CONFIG = CeleryConfig
FEATURE_FLAGS = {"ALERT_REPORTS": True}
ALERT_REPORTS_NOTIFICATION_DRY_RUN = True
WEBDRIVER_BASEURL = "http://superset:8088/"
# The base URL for the email report hyperlinks.
WEBDRIVER_BASEURL_USER_FRIENDLY = WEBDRIVER_BASEURL
SQLLAB_CTAS_NO_LIMIT = True
#
+4 -2
View File
@@ -23,7 +23,6 @@ Here's the source to the documentation hosted at
The site runs on the Gatsby framework and uses docz for it's
`Documentation` subsection.
## Getting Started
```bash
@@ -35,7 +34,10 @@ npm run start
## To Publish
To publish, the static site that Gatsby generates needs to be pushed
Github Actions CI automatically publishes the site after changes are
merged to master.
To manually publish, the static site that Gatsby generates needs to be pushed
to the `asf-site` branch on the
[apache/superset-site](https://github.com/apache/superset-site/)
repository. No need to PR here, simply `git push`.
@@ -10,8 +10,8 @@ version: 1
Google Sheets has a very limited
[SQL API](https://developers.google.com/chart/interactive/docs/querylanguage). The recommended
connector library for Google Sheets is [gsheetsdb](https://github.com/betodealmeida/gsheets-db-api).
connector library for Google Sheets is [shillelagh](https://github.com/betodealmeida/shillelagh).
There are a few steps involved in connecting Superset to Google Sheets. This
[tutorial](https://preset.io/blog/2020-06-01-connect-superset-google-sheets/) has the most upto date
[tutorial](https://preset.io/blog/2020-06-01-connect-superset-google-sheets/) has the most up to date
instructions on setting up this connection.
@@ -37,7 +37,7 @@ A list of some of the recommended packages.
|[Dremio](/docs/databases/dremio)|```pip install sqlalchemy_dremio```|```dremio://user:pwd@host:31010/```|
|[Elasticsearch](/docs/databases/elasticsearch)|```pip install elasticsearch-dbapi```|```elasticsearch+http://{user}:{password}@{host}:9200/```|
|[Exasol](/docs/databases/exasol)|```pip install sqlalchemy-exasol```|```exa+pyodbc://{username}:{password}@{hostname}:{port}/my_schema?CONNECTIONLCALL=en_US.UTF-8&driver=EXAODBC```|
|[Google Sheets](/docs/databases/google-sheets)|```pip install gsheetsdb```|```gsheets://```|
|[Google Sheets](/docs/databases/google-sheets)|```pip install shillelagh[gsheetsapi]```|```gsheets://```|
|[Hologres](/docs/databases/hologres)|```pip install psycopg2```|```postgresql+psycopg2://<UserName>:<DBPassword>@<Database Host>/<Database Name>```|
|[IBM Db2](/docs/databases/ibm-db2)|```pip install ibm_db_sa```|```db2+ibm_db://```|
|[MySQL](/docs/databases/mysql)|```pip install mysqlclient```|```mysql://<UserName>:<DBPassword>@<Database Host>/<Database Name>```|
@@ -147,7 +147,9 @@ that the username is typed correctly and exists in the database.
The password provided when connecting to a database is not valid.
```
The user provided a password that is incorrect. Please check that the password is typed correctly.
The user provided a password that is incorrect. Please check that the
password is typed correctly.
## Issue 1014
@@ -157,3 +159,27 @@ Either the username or the password used are incorrect.
Either the username provided does not exist or the password was written incorrectly. Please
check that the username and password were typed correctly.
## Issue 1015
```
Either the database is spelled incorrectly or does not exist.
```
Either the database was written incorrectly or it does not exist. Check that it was typed correctly.
## Issue 1016
```
The schema was deleted or renamed in the database.
```
The schema was either removed or renamed. Check that the schema is typed correctly and exists.
## Issue 1017
```
The user doesn't have the proper permissions to connect to the database
```
We were unable to connect to your database. Please confirm that your service account has the Viewer and Job User roles on the project.
@@ -66,7 +66,7 @@ If you are seeing timeouts (504 Gateway Time-out) when loading dashboard or expl
probably behind gateway or proxy server (such as Nginx). If it did not receive a timely response
from Superset server (which is processing long queries), these web servers will send 504 status code
to clients directly. Superset has a client-side timeout limit to address this issue. If query didnt
come back within clint-side timeout (60 seconds by default), Superset will display warning message
come back within client-side timeout (60 seconds by default), Superset will display warning message
to avoid gateway timeout message. If you have a longer gateway timeout limit, you can change the
timeout settings in **superset_config.py**:
@@ -8,7 +8,7 @@ version: 1
## Running on Kubernetes
Running on Kubernetes is supported with the provided [Helm](helm.sh/) chart included in the Github repository under [helm/superset](https://github.com/apache/superset/tree/master/helm/superset).
Running on Kubernetes is supported with the provided [Helm](https://helm.sh/) chart found in the official [Superset helm repository](https://apache.github.io/superset/index.yaml).
### Prerequisites
@@ -17,6 +17,20 @@ Running on Kubernetes is supported with the provided [Helm](helm.sh/) chart incl
### Running
1. Add the Superset helm repository
```sh
helm repo add superset https://apache.github.io/superset
"superset" has been added to your repositories
```
1. View charts in repo
```sh
helm search repo superset
NAME CHART VERSION APP VERSION DESCRIPTION
superset/superset 0.1.1 1.0 Apache Superset is a modern, enterprise-ready b...
```
1. Configure your setting overrides
Just like any typical Helm chart, you'll need to craft a `values.yaml` file that would define/override any of the values exposed into the default [values.yaml](https://github.com/apache/superset/tree/master/helm/superset/values.yaml), or from any of the dependent charts it depends on:
@@ -29,8 +43,7 @@ More info down below on some important overrides you might need.
1. Install and run
```sh
# From the root of the repository
helm upgrade --install --values my-values.yaml my-superset helm/superset
helm upgrade --install --values my-values.yaml superset superset/superset
```
You should see various pods popping up, such as:
+4 -4
View File
@@ -19,10 +19,10 @@ appVersion: "1.0"
description: Apache Superset is a modern, enterprise-ready business intelligence web application
name: superset
maintainers:
- name: Chuan-Yen Chiang
email: cychiang0823@gmail.com
url: https://github.com/cychiang
version: 0.1.0
- name: craig-rueda
email: craig@craigrueda.com
url: https://github.com/craig-rueda
version: 0.1.2
dependencies:
- name: postgresql
version: 10.2.0
+2 -2
View File
@@ -63,8 +63,8 @@ CACHE_CONFIG = {
'CACHE_KEY_PREFIX': 'superset_',
'CACHE_REDIS_HOST': env('REDIS_HOST'),
'CACHE_REDIS_PORT': env('REDIS_PORT'),
'CACHE_REDIS_DB': 1,
'CACHE_REDIS_URL': f"redis://{env('REDIS_HOST')}:{env('REDIS_PORT')}/1"
'CACHE_REDIS_PASSWORD': env('REDIS_PASSWORD'),
'CACHE_REDIS_DB': env('REDIS_DB', 1),
}
DATA_CACHE_CONFIG = CACHE_CONFIG
+58
View File
@@ -0,0 +1,58 @@
#
# 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.
#
---
rules:
braces:
min-spaces-inside: 0
max-spaces-inside: 0
min-spaces-inside-empty: -1
max-spaces-inside-empty: -1
brackets:
min-spaces-inside: -1
max-spaces-inside: -1
min-spaces-inside-empty: -1
max-spaces-inside-empty: -1
colons:
max-spaces-before: 0
max-spaces-after: 1
commas:
max-spaces-before: 0
min-spaces-after: 1
max-spaces-after: 1
comments:
require-starting-space: false
min-spaces-from-content: -1
document-end: disable
document-start: disable # No --- to start a file
empty-lines:
max: 2
max-start: 0
max-end: 0
hyphens:
max-spaces-after: 1
indentation:
spaces: consistent
indent-sequences: whatever # - list indentation will handle both indentation and without
check-multi-line-strings: false
key-duplicates: enable
line-length: disable # Lines can be any length
new-line-at-end-of-file: enable
new-lines:
type: unix
trailing-spaces: enable
truthy:
level: warning
+4 -6
View File
@@ -109,6 +109,8 @@ geographiclib==1.50
# via geopy
geopy==2.0.0
# via apache-superset
graphlib-backport==1.0.3
# via apache-superset
gunicorn==20.0.4
# via apache-superset
holidays==0.10.3
@@ -120,11 +122,7 @@ idna==2.10
# email-validator
# yarl
importlib-metadata==2.1.1
# via
# -r requirements/base.in
# jsonschema
# kombu
# markdown
# via -r requirements/base.in
isodate==0.6.0
# via apache-superset
itsdangerous==1.1.0
@@ -268,6 +266,7 @@ sqlalchemy==1.3.20
# via
# alembic
# apache-superset
# flask-appbuilder
# flask-sqlalchemy
# marshmallow-sqlalchemy
# sqlalchemy-utils
@@ -277,7 +276,6 @@ typing-extensions==3.7.4.3
# via
# aiohttp
# apache-superset
# yarl
urllib3==1.25.11
# via selenium
vine==1.3.0
+295 -32
View File
@@ -6,38 +6,301 @@
# pip-compile-multi
#
-r base.txt
-e file:. # via -r requirements/base.in
boto3==1.16.10 # via tabulator
botocore==1.19.10 # via boto3, s3transfer
cached-property==1.5.2 # via tableschema
certifi==2020.6.20 # via requests
deprecated==1.2.11 # via pygithub
et-xmlfile==1.0.1 # via openpyxl
flask-cors==3.0.9 # via -r requirements/development.in
future==0.18.2 # via pyhive
ijson==3.1.2.post0 # via tabulator
jdcal==1.4.1 # via openpyxl
jmespath==0.10.0 # via boto3, botocore
jsonlines==1.2.0 # via tabulator
linear-tsv==1.1.0 # via tabulator
mysqlclient==1.4.2.post1 # via -r requirements/development.in
openpyxl==3.0.5 # via tabulator
pillow==7.2.0 # via -r requirements/development.in
psycopg2-binary==2.8.5 # via -r requirements/development.in
pydruid==0.6.1 # via -r requirements/development.in
pygithub==1.54.1 # via -r requirements/development.in
pyhive[hive]==0.6.3 # via -r requirements/development.in
requests==2.24.0 # via pydruid, pygithub, tableschema, tabulator
rfc3986==1.4.0 # via tableschema
s3transfer==0.3.3 # via boto3
sasl==0.2.1 # via pyhive, thrift-sasl
tableschema==1.20.0 # via -r requirements/development.in
tabulator==1.52.5 # via tableschema
thrift-sasl==0.4.2 # via pyhive
thrift==0.13.0 # via -r requirements/development.in, pyhive, thrift-sasl
unicodecsv==0.14.1 # via tableschema, tabulator
wrapt==1.12.1 # via deprecated
xlrd==1.2.0 # via tabulator
-e file:.
# via -r requirements/base.in
# via slackclient
# via flask-migrate
# via kombu
# via flask-appbuilder
# via aiohttp
# via
# aiohttp
# jsonschema
# via flask-babel
# via apache-superset
# via celery
# via apache-superset
boto3==1.16.10
# via tabulator
botocore==1.19.10
# via
# boto3
# s3transfer
# via flask-compress
cached-property==1.5.2
# via tableschema
# via apache-superset
# via apache-superset
certifi==2020.6.20
# via requests
# via cryptography
# via
# aiohttp
# requests
# tabulator
# via
# apache-superset
# flask
# flask-appbuilder
# tableschema
# tabulator
# via
# apache-superset
# flask-appbuilder
# via apache-superset
# via holidays
# via apache-superset
# via apache-superset
# via apache-superset
# via retry
# via python3-openid
deprecated==1.2.11
# via pygithub
# via email-validator
# via flask-appbuilder
et-xmlfile==1.0.1
# via openpyxl
# via apache-superset
# via flask-appbuilder
# via apache-superset
# via apache-superset
flask-cors==3.0.9
# via -r requirements/development.in
# via flask-appbuilder
# via flask-appbuilder
# via apache-superset
# via flask-appbuilder
# via
# flask-appbuilder
# flask-migrate
# via apache-superset
# via
# apache-superset
# flask-appbuilder
# via
# apache-superset
# flask-appbuilder
# flask-babel
# flask-caching
# flask-compress
# flask-cors
# flask-jwt-extended
# flask-login
# flask-migrate
# flask-openid
# flask-sqlalchemy
# flask-wtf
future==0.18.2
# via pyhive
# via geopy
# via apache-superset
# via apache-superset
# via apache-superset
# via apache-superset
# via
# email-validator
# requests
# yarl
ijson==3.1.2.post0
# via tabulator
# via -r requirements/base.in
# via
# apache-superset
# tableschema
# via
# flask
# flask-wtf
jdcal==1.4.1
# via openpyxl
# via
# flask
# flask-babel
jmespath==0.10.0
# via
# boto3
# botocore
jsonlines==1.2.0
# via tabulator
# via
# flask-appbuilder
# tableschema
# via celery
# via holidays
linear-tsv==1.1.0
# via tabulator
# via alembic
# via apache-superset
# via
# jinja2
# mako
# wtforms
# via flask-appbuilder
# via flask-appbuilder
# via
# flask-appbuilder
# marshmallow-enum
# marshmallow-sqlalchemy
# via apache-superset
# via
# aiohttp
# yarl
mysqlclient==1.4.2.post1
# via -r requirements/development.in
# via croniter
# via
# pandas
# pyarrow
openpyxl==3.0.5
# via tabulator
# via bleach
# via apache-superset
# via apache-superset
# via apache-superset
# via apache-superset
pillow==7.2.0
# via -r requirements/development.in
# via apache-superset
# via flask-appbuilder
psycopg2-binary==2.8.5
# via -r requirements/development.in
# via retry
# via apache-superset
# via cffi
pydruid==0.6.1
# via -r requirements/development.in
pygithub==1.54.1
# via -r requirements/development.in
pyhive[hive]==0.6.3
# via -r requirements/development.in
# via
# apache-superset
# flask-appbuilder
# flask-jwt-extended
# pygithub
# via convertdate
# via
# apache-superset
# packaging
# via
# -r requirements/base.in
# jsonschema
# via
# alembic
# apache-superset
# botocore
# croniter
# flask-appbuilder
# holidays
# pandas
# pyhive
# tableschema
# via apache-superset
# via alembic
# via apache-superset
# via flask-openid
# via
# babel
# celery
# convertdate
# flask-babel
# pandas
# via
# apache-superset
# apispec
# via apache-superset
requests==2.24.0
# via
# pydruid
# pygithub
# tableschema
# tabulator
# via apache-superset
rfc3986==1.4.0
# via tableschema
s3transfer==0.3.3
# via boto3
sasl==0.2.1
# via
# pyhive
# thrift-sasl
# via apache-superset
# via apache-superset
# via
# bleach
# cryptography
# flask-cors
# flask-jwt-extended
# flask-talisman
# holidays
# isodate
# jsonlines
# jsonschema
# linear-tsv
# packaging
# pathlib2
# polyline
# prison
# pyrsistent
# python-dateutil
# sasl
# sqlalchemy-utils
# tableschema
# tabulator
# thrift
# thrift-sasl
# wtforms-json
# via apache-superset
# via
# apache-superset
# flask-appbuilder
# via
# alembic
# apache-superset
# flask-appbuilder
# flask-sqlalchemy
# marshmallow-sqlalchemy
# sqlalchemy-utils
# tabulator
# via apache-superset
tableschema==1.20.0
# via -r requirements/development.in
tabulator==1.52.5
# via tableschema
thrift-sasl==0.4.2
# via pyhive
thrift==0.13.0
# via
# -r requirements/development.in
# pyhive
# thrift-sasl
# via
# aiohttp
# apache-superset
unicodecsv==0.14.1
# via
# tableschema
# tabulator
# via
# botocore
# requests
# selenium
# via
# amqp
# celery
# via bleach
# via
# flask
# flask-jwt-extended
wrapt==1.12.1
# via deprecated
# via apache-superset
# via
# flask-wtf
# wtforms-json
xlrd==1.2.0
# via tabulator
# via aiohttp
# via importlib-metadata
# The following packages are considered to be unsafe in a requirements file:
# setuptools
+201 -6
View File
@@ -6,12 +6,207 @@
# pip-compile-multi
#
-r base.txt
-e file:. # via -r requirements/base.in
gevent==20.9.0 # via -r requirements/docker.in
greenlet==0.4.17 # via gevent
psycopg2-binary==2.8.6 # via -r requirements/docker.in
zope.event==4.5.0 # via gevent
zope.interface==5.1.2 # via gevent
-e file:.
# via -r requirements/base.in
# via slackclient
# via flask-migrate
# via kombu
# via flask-appbuilder
# via aiohttp
# via
# aiohttp
# jsonschema
# via flask-babel
# via apache-superset
# via celery
# via apache-superset
# via flask-compress
# via apache-superset
# via apache-superset
# via cryptography
# via aiohttp
# via
# apache-superset
# flask
# flask-appbuilder
# via
# apache-superset
# flask-appbuilder
# via apache-superset
# via holidays
# via apache-superset
# via apache-superset
# via apache-superset
# via retry
# via python3-openid
# via email-validator
# via flask-appbuilder
# via apache-superset
# via flask-appbuilder
# via apache-superset
# via apache-superset
# via flask-appbuilder
# via flask-appbuilder
# via apache-superset
# via flask-appbuilder
# via
# flask-appbuilder
# flask-migrate
# via apache-superset
# via
# apache-superset
# flask-appbuilder
# via
# apache-superset
# flask-appbuilder
# flask-babel
# flask-caching
# flask-compress
# flask-jwt-extended
# flask-login
# flask-migrate
# flask-openid
# flask-sqlalchemy
# flask-wtf
# via geopy
# via apache-superset
gevent==20.9.0
# via -r requirements/docker.in
greenlet==0.4.17
# via gevent
# via apache-superset
# via apache-superset
# via apache-superset
# via
# email-validator
# yarl
# via -r requirements/base.in
# via apache-superset
# via
# flask
# flask-wtf
# via
# flask
# flask-babel
# via flask-appbuilder
# via celery
# via holidays
# via alembic
# via apache-superset
# via
# jinja2
# mako
# wtforms
# via flask-appbuilder
# via flask-appbuilder
# via
# flask-appbuilder
# marshmallow-enum
# marshmallow-sqlalchemy
# via apache-superset
# via
# aiohttp
# yarl
# via croniter
# via
# pandas
# pyarrow
# via bleach
# via apache-superset
# via apache-superset
# via apache-superset
# via apache-superset
# via apache-superset
# via flask-appbuilder
psycopg2-binary==2.8.6
# via -r requirements/docker.in
# via retry
# via apache-superset
# via cffi
# via
# apache-superset
# flask-appbuilder
# flask-jwt-extended
# via convertdate
# via
# apache-superset
# packaging
# via
# -r requirements/base.in
# jsonschema
# via
# alembic
# apache-superset
# croniter
# flask-appbuilder
# holidays
# pandas
# via apache-superset
# via alembic
# via apache-superset
# via flask-openid
# via
# babel
# celery
# convertdate
# flask-babel
# pandas
# via
# apache-superset
# apispec
# via apache-superset
# via apache-superset
# via apache-superset
# via apache-superset
# via
# bleach
# cryptography
# flask-jwt-extended
# flask-talisman
# holidays
# isodate
# jsonschema
# packaging
# pathlib2
# polyline
# prison
# pyrsistent
# python-dateutil
# sqlalchemy-utils
# wtforms-json
# via apache-superset
# via
# apache-superset
# flask-appbuilder
# via
# alembic
# apache-superset
# flask-appbuilder
# flask-sqlalchemy
# marshmallow-sqlalchemy
# sqlalchemy-utils
# via apache-superset
# via
# aiohttp
# apache-superset
# via selenium
# via
# amqp
# celery
# via bleach
# via
# flask
# flask-jwt-extended
# via apache-superset
# via
# flask-wtf
# wtforms-json
# via aiohttp
# via importlib-metadata
zope.event==4.5.0
# via gevent
zope.interface==5.1.2
# via gevent
# The following packages are considered to be unsafe in a requirements file:
# setuptools
+52 -22
View File
@@ -5,28 +5,58 @@
#
# pip-compile-multi
#
appdirs==1.4.4 # via virtualenv
cfgv==3.2.0 # via pre-commit
click==7.1.2 # via pip-compile-multi, pip-tools
distlib==0.3.1 # via virtualenv
filelock==3.0.12 # via tox, virtualenv
identify==1.5.9 # via pre-commit
importlib-metadata==2.1.1 # via pluggy, pre-commit, tox, virtualenv
nodeenv==1.5.0 # via pre-commit
packaging==20.4 # via tox
pip-compile-multi==2.1.0 # via -r requirements/integration.in
pip-tools==5.3.1 # via pip-compile-multi
pluggy==0.13.1 # via tox
pre-commit==2.8.2 # via -r requirements/integration.in
py==1.9.0 # via tox
pyparsing==2.4.7 # via packaging
pyyaml==5.4.1 # via pre-commit
six==1.15.0 # via packaging, pip-tools, tox, virtualenv
toml==0.10.2 # via pre-commit, tox
toposort==1.5 # via pip-compile-multi
tox==3.20.1 # via -r requirements/integration.in
virtualenv==20.1.0 # via pre-commit, tox
zipp==3.4.0 # via importlib-metadata
appdirs==1.4.4
# via virtualenv
cfgv==3.2.0
# via pre-commit
click==7.1.2
# via
# pip-compile-multi
# pip-tools
distlib==0.3.1
# via virtualenv
filelock==3.0.12
# via
# tox
# virtualenv
identify==1.5.9
# via pre-commit
nodeenv==1.5.0
# via pre-commit
packaging==20.4
# via tox
pip-compile-multi==2.1.0
# via -r requirements/integration.in
pip-tools==5.3.1
# via pip-compile-multi
pluggy==0.13.1
# via tox
pre-commit==2.8.2
# via -r requirements/integration.in
py==1.9.0
# via tox
pyparsing==2.4.7
# via packaging
pyyaml==5.4.1
# via pre-commit
six==1.15.0
# via
# packaging
# pip-tools
# tox
# virtualenv
toml==0.10.2
# via
# pre-commit
# tox
toposort==1.5
# via pip-compile-multi
tox==3.20.1
# via -r requirements/integration.in
virtualenv==20.1.0
# via
# pre-commit
# tox
# The following packages are considered to be unsafe in a requirements file:
# pip
+264 -1
View File
@@ -6,7 +6,270 @@
# pip-compile-multi
#
-r development.txt
-e file:. # via -r requirements/base.in
-e file:.
# via -r requirements/base.in
# via slackclient
# via flask-migrate
# via kombu
# via flask-appbuilder
# via aiohttp
# via
# aiohttp
# jsonschema
# via flask-babel
# via apache-superset
# via celery
# via apache-superset
# via tabulator
# via
# boto3
# s3transfer
# via flask-compress
# via tableschema
# via apache-superset
# via apache-superset
# via requests
# via cryptography
# via
# aiohttp
# requests
# tabulator
# via
# apache-superset
# flask
# flask-appbuilder
# tableschema
# tabulator
# via
# apache-superset
# flask-appbuilder
# via apache-superset
# via holidays
# via apache-superset
# via apache-superset
# via apache-superset
# via retry
# via python3-openid
# via pygithub
# via email-validator
# via flask-appbuilder
# via openpyxl
# via apache-superset
# via flask-appbuilder
# via apache-superset
# via apache-superset
# via -r requirements/development.in
# via flask-appbuilder
# via flask-appbuilder
# via apache-superset
# via flask-appbuilder
# via
# flask-appbuilder
# flask-migrate
# via apache-superset
# via
# apache-superset
# flask-appbuilder
# via
# apache-superset
# flask-appbuilder
# flask-babel
# flask-caching
# flask-compress
# flask-cors
# flask-jwt-extended
# flask-login
# flask-migrate
# flask-openid
# flask-sqlalchemy
# flask-wtf
# via pyhive
# via geopy
# via apache-superset
# via apache-superset
# via apache-superset
# via apache-superset
# via
# email-validator
# requests
# yarl
# via tabulator
# via -r requirements/base.in
# via
# apache-superset
# tableschema
# via
# flask
# flask-wtf
# via openpyxl
# via
# flask
# flask-babel
# via
# boto3
# botocore
# via tabulator
# via
# flask-appbuilder
# tableschema
# via celery
# via holidays
# via tabulator
# via alembic
# via apache-superset
# via
# jinja2
# mako
# wtforms
# via flask-appbuilder
# via flask-appbuilder
# via
# flask-appbuilder
# marshmallow-enum
# marshmallow-sqlalchemy
# via apache-superset
# via
# aiohttp
# yarl
# via -r requirements/development.in
# via croniter
# via
# pandas
# pyarrow
# via tabulator
# via bleach
# via apache-superset
# via apache-superset
# via apache-superset
# via apache-superset
# via -r requirements/development.in
# via apache-superset
# via flask-appbuilder
# via -r requirements/development.in
# via retry
# via apache-superset
# via cffi
# via -r requirements/development.in
# via -r requirements/development.in
# via -r requirements/development.in
# via
# apache-superset
# flask-appbuilder
# flask-jwt-extended
# pygithub
# via convertdate
# via
# apache-superset
# packaging
# via
# -r requirements/base.in
# jsonschema
# via
# alembic
# apache-superset
# botocore
# croniter
# flask-appbuilder
# holidays
# pandas
# pyhive
# tableschema
# via apache-superset
# via alembic
# via apache-superset
# via flask-openid
# via
# babel
# celery
# convertdate
# flask-babel
# pandas
# via
# apache-superset
# apispec
# via apache-superset
# via
# pydruid
# pygithub
# tableschema
# tabulator
# via apache-superset
# via tableschema
# via boto3
# via
# pyhive
# thrift-sasl
# via apache-superset
# via apache-superset
# via
# bleach
# cryptography
# flask-cors
# flask-jwt-extended
# flask-talisman
# holidays
# isodate
# jsonlines
# jsonschema
# linear-tsv
# packaging
# pathlib2
# polyline
# prison
# pyrsistent
# python-dateutil
# sasl
# sqlalchemy-utils
# tableschema
# tabulator
# thrift
# thrift-sasl
# wtforms-json
# via apache-superset
# via
# apache-superset
# flask-appbuilder
# via
# alembic
# apache-superset
# flask-appbuilder
# flask-sqlalchemy
# marshmallow-sqlalchemy
# sqlalchemy-utils
# tabulator
# via apache-superset
# via -r requirements/development.in
# via tableschema
# via pyhive
# via
# -r requirements/development.in
# pyhive
# thrift-sasl
# via
# aiohttp
# apache-superset
# via
# tableschema
# tabulator
# via
# botocore
# requests
# selenium
# via
# amqp
# celery
# via bleach
# via
# flask
# flask-jwt-extended
# via deprecated
# via apache-superset
# via
# flask-wtf
# wtforms-json
# via tabulator
# via aiohttp
# via importlib-metadata
# The following packages are considered to be unsafe in a requirements file:
# setuptools
+1
View File
@@ -26,6 +26,7 @@ ipython==7.16.1
openapi-spec-validator
openpyxl
parameterized
pyfakefs
pyhive[presto]>=0.6.3
pylint
pytest
+387 -34
View File
@@ -1,4 +1,4 @@
# SHA1:9d449781bc4ef88cd346b9dd5db55240472d5f0c
# SHA1:1b285a0aa0e721283892b052553751d44f5dd81f
#
# This file is autogenerated by pip-compile-multi
# To update, run:
@@ -7,39 +7,392 @@
#
-r development.txt
-r integration.txt
-e file:. # via -r requirements/base.in
appnope==0.1.0 # via ipython
astroid==2.4.2 # via pylint
backcall==0.2.0 # via ipython
coverage==5.3 # via pytest-cov
docker==4.3.1 # via -r requirements/testing.in
flask-testing==0.8.0 # via -r requirements/testing.in
freezegun==1.0.0 # via -r requirements/testing.in
iniconfig==1.1.1 # via pytest
ipdb==0.13.4 # via -r requirements/testing.in
ipython-genutils==0.2.0 # via traitlets
ipython==7.16.1 # via -r requirements/testing.in, ipdb
isort==5.6.4 # via pylint
jedi==0.17.2 # via ipython
lazy-object-proxy==1.4.3 # via astroid
mccabe==0.6.1 # via pylint
openapi-spec-validator==0.2.9 # via -r requirements/testing.in
parameterized==0.7.4 # via -r requirements/testing.in
parso==0.7.1 # via jedi
pexpect==4.8.0 # via ipython
pickleshare==0.7.5 # via ipython
prompt-toolkit==3.0.8 # via ipython
ptyprocess==0.6.0 # via pexpect
pygments==2.7.2 # via ipython
pyhive[hive,presto]==0.6.3 # via -r requirements/development.in, -r requirements/testing.in
pylint==2.6.0 # via -r requirements/testing.in
pytest-cov==2.10.1 # via -r requirements/testing.in
pytest==6.1.2 # via -r requirements/testing.in, pytest-cov
statsd==3.3.0 # via -r requirements/testing.in
traitlets==5.0.5 # via ipython
typed-ast==1.4.1 # via astroid
wcwidth==0.2.5 # via prompt-toolkit
websocket-client==0.57.0 # via docker
-e file:.
# via -r requirements/base.in
# via slackclient
# via flask-migrate
# via kombu
# via flask-appbuilder
# via virtualenv
appnope==0.1.0
# via ipython
astroid==2.4.2
# via pylint
# via aiohttp
# via
# aiohttp
# jsonschema
# pytest
# via flask-babel
backcall==0.2.0
# via ipython
# via apache-superset
# via celery
# via apache-superset
# via tabulator
# via
# boto3
# s3transfer
# via flask-compress
# via tableschema
# via apache-superset
# via apache-superset
# via requests
# via cryptography
# via pre-commit
# via
# aiohttp
# requests
# tabulator
# via
# apache-superset
# flask
# flask-appbuilder
# pip-compile-multi
# pip-tools
# tableschema
# tabulator
# via
# apache-superset
# flask-appbuilder
# via apache-superset
# via holidays
coverage==5.3
# via pytest-cov
# via apache-superset
# via apache-superset
# via apache-superset
# via
# ipython
# retry
# via python3-openid
# via pygithub
# via virtualenv
# via email-validator
docker==4.3.1
# via -r requirements/testing.in
# via flask-appbuilder
# via openpyxl
# via
# tox
# virtualenv
# via apache-superset
# via flask-appbuilder
# via apache-superset
# via apache-superset
# via -r requirements/development.in
# via flask-appbuilder
# via flask-appbuilder
# via apache-superset
# via flask-appbuilder
# via
# flask-appbuilder
# flask-migrate
# via apache-superset
flask-testing==0.8.0
# via -r requirements/testing.in
# via
# apache-superset
# flask-appbuilder
# via
# apache-superset
# flask-appbuilder
# flask-babel
# flask-caching
# flask-compress
# flask-cors
# flask-jwt-extended
# flask-login
# flask-migrate
# flask-openid
# flask-sqlalchemy
# flask-testing
# flask-wtf
freezegun==1.0.0
# via -r requirements/testing.in
# via pyhive
# via geopy
# via apache-superset
# via apache-superset
# via apache-superset
# via apache-superset
# via pre-commit
# via
# email-validator
# requests
# yarl
# via tabulator
# via -r requirements/base.in
iniconfig==1.1.1
# via pytest
ipdb==0.13.4
# via -r requirements/testing.in
ipython-genutils==0.2.0
# via traitlets
ipython==7.16.1
# via
# -r requirements/testing.in
# ipdb
# via
# apache-superset
# tableschema
isort==5.6.4
# via pylint
# via
# flask
# flask-wtf
# via openpyxl
jedi==0.17.2
# via ipython
# via
# flask
# flask-babel
# via
# boto3
# botocore
# via tabulator
# via
# flask-appbuilder
# openapi-spec-validator
# tableschema
# via celery
# via holidays
lazy-object-proxy==1.4.3
# via astroid
# via tabulator
# via alembic
# via apache-superset
# via
# jinja2
# mako
# wtforms
# via flask-appbuilder
# via flask-appbuilder
# via
# flask-appbuilder
# marshmallow-enum
# marshmallow-sqlalchemy
mccabe==0.6.1
# via pylint
# via apache-superset
# via
# aiohttp
# yarl
# via -r requirements/development.in
# via croniter
# via pre-commit
# via
# pandas
# pyarrow
openapi-spec-validator==0.2.9
# via -r requirements/testing.in
# via
# -r requirements/testing.in
# tabulator
# via
# bleach
# pytest
# tox
# via apache-superset
parameterized==0.7.4
# via -r requirements/testing.in
# via apache-superset
parso==0.7.1
# via jedi
# via apache-superset
pexpect==4.8.0
# via ipython
# via apache-superset
pickleshare==0.7.5
# via ipython
# via -r requirements/development.in
# via -r requirements/integration.in
# via pip-compile-multi
# via
# pytest
# tox
# via apache-superset
# via -r requirements/integration.in
# via flask-appbuilder
prompt-toolkit==3.0.8
# via ipython
# via -r requirements/development.in
ptyprocess==0.6.0
# via pexpect
# via
# pytest
# retry
# tox
# via apache-superset
# via cffi
# via -r requirements/development.in
pyfakefs==4.4.0
# via -r requirements/testing.in
# via -r requirements/development.in
pygments==2.7.2
# via ipython
pyhive[hive,presto]==0.6.3
# via
# -r requirements/development.in
# -r requirements/testing.in
# via
# apache-superset
# flask-appbuilder
# flask-jwt-extended
# pygithub
pylint==2.6.0
# via -r requirements/testing.in
# via convertdate
# via
# apache-superset
# packaging
# via
# -r requirements/base.in
# jsonschema
pytest-cov==2.10.1
# via -r requirements/testing.in
pytest==6.1.2
# via
# -r requirements/testing.in
# pytest-cov
# via
# alembic
# apache-superset
# botocore
# croniter
# flask-appbuilder
# freezegun
# holidays
# pandas
# pyhive
# tableschema
# via apache-superset
# via alembic
# via apache-superset
# via flask-openid
# via
# babel
# celery
# convertdate
# flask-babel
# pandas
# via
# apache-superset
# apispec
# openapi-spec-validator
# pre-commit
# via apache-superset
# via
# docker
# pydruid
# pygithub
# pyhive
# tableschema
# tabulator
# via apache-superset
# via tableschema
# via boto3
# via
# pyhive
# thrift-sasl
# via apache-superset
# via apache-superset
# via
# astroid
# bleach
# cryptography
# docker
# flask-cors
# flask-jwt-extended
# flask-talisman
# holidays
# isodate
# jsonlines
# jsonschema
# linear-tsv
# openapi-spec-validator
# packaging
# pathlib2
# pip-tools
# polyline
# prison
# pyrsistent
# python-dateutil
# sasl
# sqlalchemy-utils
# tableschema
# tabulator
# thrift
# thrift-sasl
# tox
# virtualenv
# websocket-client
# wtforms-json
# via apache-superset
# via
# apache-superset
# flask-appbuilder
# via
# alembic
# apache-superset
# flask-appbuilder
# flask-sqlalchemy
# marshmallow-sqlalchemy
# sqlalchemy-utils
# tabulator
# via apache-superset
statsd==3.3.0
# via -r requirements/testing.in
# via -r requirements/development.in
# via tableschema
# via pyhive
# via
# -r requirements/development.in
# pyhive
# thrift-sasl
# via
# pre-commit
# pylint
# pytest
# tox
# via pip-compile-multi
# via -r requirements/integration.in
traitlets==5.0.5
# via ipython
# via
# aiohttp
# apache-superset
# via
# tableschema
# tabulator
# via
# botocore
# requests
# selenium
# via
# amqp
# celery
# via
# pre-commit
# tox
wcwidth==0.2.5
# via prompt-toolkit
# via bleach
websocket-client==0.57.0
# via docker
# via
# flask
# flask-jwt-extended
# via
# astroid
# deprecated
# via apache-superset
# via
# flask-wtf
# wtforms-json
# via tabulator
# via aiohttp
# via importlib-metadata
# The following packages are considered to be unsafe in a requirements file:
# pip
+215
View File
@@ -0,0 +1,215 @@
# 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 importlib.util
import logging
import re
import time
from collections import defaultdict
from inspect import getsource
from pathlib import Path
from types import ModuleType
from typing import Dict, List, Set, Type
import click
from flask_appbuilder import Model
from flask_migrate import downgrade, upgrade
from graphlib import TopologicalSorter # pylint: disable=wrong-import-order
from sqlalchemy import inspect
from superset import db
from superset.utils.mock_data import add_sample_rows
logger = logging.getLogger(__name__)
def import_migration_script(filepath: Path) -> ModuleType:
"""
Import migration script as if it were a module.
"""
spec = importlib.util.spec_from_file_location(filepath.stem, filepath)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module) # type: ignore
return module
def extract_modified_tables(module: ModuleType) -> Set[str]:
"""
Extract the tables being modified by a migration script.
This function uses a simple approach of looking at the source code of
the migration script looking for patterns. It could be improved by
actually traversing the AST.
"""
tables: Set[str] = set()
for function in {"upgrade", "downgrade"}:
source = getsource(getattr(module, function))
tables.update(re.findall(r'alter_table\(\s*"(\w+?)"\s*\)', source, re.DOTALL))
tables.update(re.findall(r'add_column\(\s*"(\w+?)"\s*,', source, re.DOTALL))
tables.update(re.findall(r'drop_column\(\s*"(\w+?)"\s*,', source, re.DOTALL))
return tables
def find_models(module: ModuleType) -> List[Type[Model]]:
"""
Find all models in a migration script.
"""
models: List[Type[Model]] = []
tables = extract_modified_tables(module)
# add models defined explicitly in the migration script
queue = list(module.__dict__.values())
while queue:
obj = queue.pop()
if hasattr(obj, "__tablename__"):
tables.add(obj.__tablename__)
elif isinstance(obj, list):
queue.extend(obj)
elif isinstance(obj, dict):
queue.extend(obj.values())
# add implicit models
# pylint: disable=no-member, protected-access
for obj in Model._decl_class_registry.values():
if hasattr(obj, "__table__") and obj.__table__.fullname in tables:
models.append(obj)
# sort topologically so we can create entities in order and
# maintain relationships (eg, create a database before creating
# a slice)
sorter = TopologicalSorter()
for model in models:
inspector = inspect(model)
dependent_tables: List[str] = []
for column in inspector.columns.values():
for foreign_key in column.foreign_keys:
dependent_tables.append(foreign_key.target_fullname.split(".")[0])
sorter.add(model.__tablename__, *dependent_tables)
order = list(sorter.static_order())
models.sort(key=lambda model: order.index(model.__tablename__))
return models
@click.command()
@click.argument("filepath")
@click.option("--limit", default=1000, help="Maximum number of entities.")
@click.option("--force", is_flag=True, help="Do not prompt for confirmation.")
@click.option("--no-auto-cleanup", is_flag=True, help="Do not remove created models.")
def main(
filepath: str, limit: int = 1000, force: bool = False, no_auto_cleanup: bool = False
) -> None:
auto_cleanup = not no_auto_cleanup
session = db.session()
print(f"Importing migration script: {filepath}")
module = import_migration_script(Path(filepath))
revision: str = getattr(module, "revision", "")
down_revision: str = getattr(module, "down_revision", "")
if not revision or not down_revision:
raise Exception(
"Not a valid migration script, couldn't find down_revision/revision"
)
print(f"Migration goes from {down_revision} to {revision}")
current_revision = db.engine.execute(
"SELECT version_num FROM alembic_version"
).scalar()
print(f"Current version of the DB is {current_revision}")
print("\nIdentifying models used in the migration:")
models = find_models(module)
model_rows: Dict[Type[Model], int] = {}
for model in models:
rows = session.query(model).count()
print(f"- {model.__name__} ({rows} rows in table {model.__tablename__})")
model_rows[model] = rows
session.close()
if current_revision != down_revision:
if not force:
click.confirm(
"\nRunning benchmark will downgrade the Superset DB to "
f"{down_revision} and upgrade to {revision} again. There may "
"be data loss in downgrades. Continue?",
abort=True,
)
downgrade(revision=down_revision)
print("Benchmarking migration")
results: Dict[str, float] = {}
start = time.time()
upgrade(revision=revision)
duration = time.time() - start
results["Current"] = duration
print(f"Migration on current DB took: {duration:.2f} seconds")
min_entities = 10
new_models: Dict[Type[Model], List[Model]] = defaultdict(list)
while min_entities <= limit:
downgrade(revision=down_revision)
print(f"Running with at least {min_entities} entities of each model")
for model in models:
missing = min_entities - model_rows[model]
if missing > 0:
print(f"- Adding {missing} entities to the {model.__name__} model")
try:
added_models = add_sample_rows(session, model, missing)
except Exception:
session.rollback()
raise
model_rows[model] = min_entities
session.commit()
if auto_cleanup:
new_models[model].extend(added_models)
start = time.time()
upgrade(revision=revision)
duration = time.time() - start
print(f"Migration for {min_entities}+ entities took: {duration:.2f} seconds")
results[f"{min_entities}+"] = duration
min_entities *= 10
if auto_cleanup:
print("Cleaning up DB")
# delete in reverse order of creation to handle relationships
for model, entities in list(new_models.items())[::-1]:
session.query(model).filter(
model.id.in_(entity.id for entity in entities)
).delete(synchronize_session=False)
session.commit()
if current_revision != revision and not force:
click.confirm(f"\nRevert DB to {revision}?", abort=True)
upgrade(revision=revision)
print("Reverted")
print("\nResults:\n")
for label, duration in results.items():
print(f"{label}: {duration:.2f} s")
if __name__ == "__main__":
from superset.app import create_app
app = create_app()
with app.app_context():
# pylint: disable=no-value-for-parameter
main()
+1 -1
View File
@@ -30,7 +30,7 @@ combine_as_imports = true
include_trailing_comma = true
line_length = 88
known_first_party = superset
known_third_party =alembic,apispec,backoff,bleach,cachelib,celery,click,colorama,contextlib2,cron_descriptor,croniter,cryptography,dateutil,flask,flask_appbuilder,flask_babel,flask_caching,flask_compress,flask_jwt_extended,flask_login,flask_migrate,flask_sqlalchemy,flask_talisman,flask_testing,flask_wtf,freezegun,geohash,geopy,holidays,humanize,isodate,jinja2,jwt,markdown,markupsafe,marshmallow,marshmallow_enum,msgpack,numpy,pandas,parameterized,parsedatetime,pathlib2,pgsanity,pkg_resources,polyline,prison,pyarrow,pyhive,pyparsing,pytest,pytz,redis,requests,retry,selenium,setuptools,simplejson,slack,sqlalchemy,sqlalchemy_utils,sqlparse,typing_extensions,werkzeug,wtforms,wtforms_json,yaml
known_third_party =alembic,apispec,backoff,bleach,cachelib,celery,click,colorama,contextlib2,cron_descriptor,croniter,cryptography,dateutil,flask,flask_appbuilder,flask_babel,flask_caching,flask_compress,flask_jwt_extended,flask_login,flask_migrate,flask_sqlalchemy,flask_talisman,flask_testing,flask_wtf,freezegun,geohash,geopy,graphlib,holidays,humanize,isodate,jinja2,jwt,markdown,markupsafe,marshmallow,marshmallow_enum,msgpack,numpy,pandas,parameterized,parsedatetime,pathlib2,pgsanity,pkg_resources,polyline,prison,pyarrow,pyhive,pyparsing,pytest,pytz,redis,requests,retry,selenium,setuptools,simplejson,slack,sqlalchemy,sqlalchemy_utils,sqlparse,typing_extensions,werkzeug,wtforms,wtforms_json,yaml
multi_line_output = 3
order_by_type = false
+4 -3
View File
@@ -82,6 +82,7 @@ setup(
"flask-migrate",
"flask-wtf",
"geopy",
"graphlib-backport",
"gunicorn>=20.0.2, <20.1",
"humanize",
"isodate",
@@ -103,7 +104,7 @@ setup(
"selenium>=3.141.0",
"simplejson>=3.15.0",
"slackclient==2.5.0", # PINNED! slack changes file upload api in the future versions
"sqlalchemy>=1.3.16, <2.0, !=1.3.21",
"sqlalchemy>=1.3.16, <1.4, !=1.3.21",
"sqlalchemy-utils>=0.36.6,<0.37",
"sqlparse==0.3.0", # PINNED! see https://github.com/andialbrecht/sqlparse/issues/562
"typing-extensions>=3.7.4.3,<4", # needed to support typing.Literal on py37
@@ -132,7 +133,7 @@ setup(
"exasol": ["sqlalchemy-exasol>=2.1.0, <2.2"],
"excel": ["xlrd>=1.2.0, <1.3"],
"firebird": ["sqlalchemy-firebird>=0.7.0, <0.8"],
"gsheets": ["shillelagh>=0.2, <0.3"],
"gsheets": ["shillelagh[gsheetsapi]>=0.2, <0.3"],
"hana": ["hdbcli==2.4.162", "sqlalchemy_hana==0.4.0"],
"hive": ["pyhive[hive]>=0.6.1", "tableschema", "thrift>=0.11.0, <1.0.0"],
"impala": ["impyla>0.16.2, <0.17"],
@@ -144,7 +145,7 @@ setup(
"postgres": ["psycopg2-binary==2.8.5"],
"presto": ["pyhive[presto]>=0.4.0"],
"trino": ["sqlalchemy-trino>=0.2"],
"prophet": ["fbprophet>=0.7.1, <0.8", "pystan<3.0"],
"prophet": ["prophet>=1.0.1, <1.1", "pystan<3.0"],
"redshift": ["sqlalchemy-redshift>=0.8.1, < 0.9"],
"snowflake": ["snowflake-sqlalchemy>=1.2.3, <1.3"],
"teradata": ["sqlalchemy-teradata==0.9.0.dev0"],
@@ -52,21 +52,23 @@ describe('Nativefilters', () => {
it('should show filter bar and allow user to create filters ', () => {
cy.get('[data-test="filter-bar"]').should('be.visible');
cy.get('[data-test="collapse"]').click();
cy.get('[data-test="create-filter"]').click();
cy.get('[data-test="filter-bar__expand-button"]').click();
cy.get('[data-test="filter-bar__create-filter"]').click();
cy.get('.ant-modal').should('be.visible');
cy.get('.ant-modal')
.find('[data-test="name-input"]')
.find('[data-test="filters-config-modal__name-input"]')
.click()
.type('Country name');
cy.get('.ant-modal')
.find('[data-test="datasource-input"]')
.find('[data-test="filters-config-modal__datasource-input"]')
.click()
.type('wb_health_population');
cy.get('.ant-modal [data-test="datasource-input"] .Select__menu')
cy.get(
'.ant-modal [data-test="filters-config-modal__datasource-input"] .Select__menu',
)
.contains('wb_health_population')
.click();
@@ -90,14 +92,14 @@ describe('Nativefilters', () => {
it('should filter dashboard with selected filter value', () => {
cy.get('[data-test="form-item-value"]').should('be.visible').click();
cy.get('.ant-select-selection-search').type('Hong Kong{enter}');
cy.get('[data-test="filter-apply-button"]').click();
cy.get('[data-test="filter-bar__apply-button"]').click();
cy.get('.treemap').within(() => {
cy.contains('HKG').should('be.visible');
cy.contains('USA').should('not.exist');
});
});
xit('default value is respected after revisit', () => {
cy.get('[data-test="create-filter"]').click();
cy.get('[data-test="filter-bar__create-filter"]').click();
cy.get('.ant-modal').should('be.visible');
// TODO: replace with proper wait for filter to finish loading
cy.wait(1000);
@@ -118,7 +120,7 @@ describe('Nativefilters', () => {
cy.contains('Sweden');
});
it('should allow for deleted filter restore', () => {
cy.get('[data-test="create-filter"]').click();
cy.get('[data-test="filter-bar__create-filter"]').click();
cy.get('.ant-modal').should('be.visible');
cy.get('.ant-tabs-nav-list').within(() => {
cy.get('.ant-tabs-tab-remove').click();
@@ -132,7 +134,7 @@ describe('Nativefilters', () => {
});
it('should stop filtering when filter is removed', () => {
cy.get('[data-test="create-filter"]').click();
cy.get('[data-test="filter-bar__create-filter"]').click();
cy.get('.ant-modal').should('be.visible');
cy.get('.ant-tabs-nav-list').within(() => {
cy.get('.ant-tabs-tab-remove').click();
@@ -149,21 +151,23 @@ describe('Nativefilters', () => {
describe('Parent Filters', () => {
it('should allow for creating parent filters ', () => {
cy.get('[data-test="filter-bar"]').should('be.visible');
cy.get('[data-test="collapse"]').click();
cy.get('[data-test="create-filter"]').click();
cy.get('[data-test="filter-bar__expand-button"]').click();
cy.get('[data-test="filter-bar__create-filter"]').click();
cy.get('.ant-modal').should('be.visible');
cy.get('.ant-modal')
.find('[data-test="name-input"]')
.find('[data-test="filters-config-modal__name-input"]')
.click()
.type('Country name');
cy.get('.ant-modal')
.find('[data-test="datasource-input"]')
.find('[data-test="filters-config-modal__datasource-input"]')
.click()
.type('wb_health_population');
cy.get('.ant-modal [data-test="datasource-input"] .Select__menu')
cy.get(
'.ant-modal [data-test="filters-config-modal__datasource-input"] .Select__menu',
)
.contains('wb_health_population')
.click();
@@ -180,23 +184,25 @@ describe('Nativefilters', () => {
.should('be.visible')
.click();
cy.get('[data-test="create-filter"]').click();
cy.get('[data-test="filter-bar__create-filter"]').click();
cy.get('.ant-modal').first().should('be.visible');
cy.get('[data-test=add-filter-button]').first().click();
cy.get('.ant-modal')
.find('[data-test="name-input"]')
.find('[data-test="filters-config-modal__name-input"]')
.last()
.click()
.type('Region Name');
cy.get('.ant-modal')
.find('[data-test="datasource-input"]')
.find('[data-test="filters-config-modal__datasource-input"]')
.last()
.click()
.type('wb_health_population');
cy.get('.ant-modal [data-test="datasource-input"] .Select__menu')
cy.get(
'.ant-modal [data-test="filters-config-modal__datasource-input"] .Select__menu',
)
.last()
.contains('wb_health_population')
.click();
@@ -250,7 +256,7 @@ describe('Nativefilters', () => {
});
it('should stop filtering when parent filter is removed', () => {
cy.get('[data-test="create-filter"]').click();
cy.get('[data-test="filter-bar__create-filter"]').click();
cy.get('.ant-modal').should('be.visible');
cy.get('.ant-tabs-nav-list').within(() => {
cy.get('.ant-tabs-tab-remove').click({ multiple: true });
@@ -0,0 +1,63 @@
/**
* 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.
*/
describe('Visualization > Gauge', () => {
const GAUGE_FORM_DATA = {
datasource: '2__table',
viz_type: 'gauge_chart',
metric: 'count',
adhoc_filters: [],
slice_id: 49,
row_limit: 10,
};
function verify(formData) {
cy.visitChartByParams(JSON.stringify(formData));
cy.verifySliceSuccess({ waitAlias: '@getJson' });
}
beforeEach(() => {
cy.login();
cy.intercept('POST', '/api/v1/chart/data*').as('getJson');
});
it('should work', () => {
verify(GAUGE_FORM_DATA);
cy.get('.chart-container .gauge_chart canvas').should('have.length', 1);
});
it('should work with simple filter', () => {
verify({
...GAUGE_FORM_DATA,
adhoc_filters: [
{
expressionType: 'SIMPLE',
subject: 'country_code',
operator: '==',
comparator: 'USA',
clause: 'WHERE',
sqlExpression: null,
isExtra: false,
isNew: false,
filterOptionName: 'filter_jaemvkxd5h_ku22m3wyo',
},
],
});
cy.get('.chart-container .gauge_chart canvas').should('have.length', 1);
});
});
+2 -2
View File
@@ -20,7 +20,7 @@ module.exports = {
testRegex: '(\\/spec|\\/src)\\/.*(_spec|\\.test)\\.(j|t)sx?$',
moduleNameMapper: {
'\\.(css|less)$': '<rootDir>/spec/__mocks__/styleMock.js',
'\\.(gif|ttf|eot)$': '<rootDir>/spec/__mocks__/fileMock.js',
'\\.(gif|ttf|eot|png)$': '<rootDir>/spec/__mocks__/fileMock.js',
'\\.svg$': '<rootDir>/spec/__mocks__/svgrMock.js',
'^src/(.*)$': '<rootDir>/src/$1',
'^spec/(.*)$': '<rootDir>/spec/$1',
@@ -28,7 +28,7 @@ module.exports = {
testEnvironment: 'jsdom',
setupFilesAfterEnv: ['<rootDir>/spec/helpers/setup.ts'],
testURL: 'http://localhost',
collectCoverageFrom: ['src/**/*.{js,jsx,ts,tsx}'],
collectCoverageFrom: ['src/**/*.{js,jsx,ts,tsx}', '!**/*.stories.*'],
coverageDirectory: '<rootDir>/coverage/',
transform: {
'^.+\\.jsx?$': 'babel-jest',
+602 -514
View File
File diff suppressed because it is too large Load Diff
+29 -28
View File
@@ -65,34 +65,35 @@
"@babel/runtime-corejs3": "^7.12.5",
"@data-ui/sparkline": "^0.0.84",
"@emotion/core": "^10.0.35",
"@superset-ui/chart-controls": "^0.17.30",
"@superset-ui/core": "^0.17.30",
"@superset-ui/legacy-plugin-chart-calendar": "^0.17.30",
"@superset-ui/legacy-plugin-chart-chord": "^0.17.30",
"@superset-ui/legacy-plugin-chart-country-map": "^0.17.31",
"@superset-ui/legacy-plugin-chart-event-flow": "^0.17.30",
"@superset-ui/legacy-plugin-chart-force-directed": "^0.17.30",
"@superset-ui/legacy-plugin-chart-heatmap": "^0.17.30",
"@superset-ui/legacy-plugin-chart-histogram": "^0.17.30",
"@superset-ui/legacy-plugin-chart-horizon": "^0.17.30",
"@superset-ui/legacy-plugin-chart-map-box": "^0.17.30",
"@superset-ui/legacy-plugin-chart-paired-t-test": "^0.17.30",
"@superset-ui/legacy-plugin-chart-parallel-coordinates": "^0.17.30",
"@superset-ui/legacy-plugin-chart-partition": "^0.17.30",
"@superset-ui/legacy-plugin-chart-pivot-table": "^0.17.30",
"@superset-ui/legacy-plugin-chart-rose": "^0.17.30",
"@superset-ui/legacy-plugin-chart-sankey": "^0.17.30",
"@superset-ui/legacy-plugin-chart-sankey-loop": "^0.17.30",
"@superset-ui/legacy-plugin-chart-sunburst": "^0.17.30",
"@superset-ui/legacy-plugin-chart-treemap": "^0.17.30",
"@superset-ui/legacy-plugin-chart-world-map": "^0.17.30",
"@superset-ui/legacy-preset-chart-big-number": "^0.17.30",
"@superset-ui/chart-controls": "^0.17.36",
"@superset-ui/core": "^0.17.32",
"@superset-ui/legacy-plugin-chart-calendar": "^0.17.36",
"@superset-ui/legacy-plugin-chart-chord": "^0.17.36",
"@superset-ui/legacy-plugin-chart-country-map": "^0.17.36",
"@superset-ui/legacy-plugin-chart-event-flow": "^0.17.36",
"@superset-ui/legacy-plugin-chart-force-directed": "^0.17.36",
"@superset-ui/legacy-plugin-chart-heatmap": "^0.17.36",
"@superset-ui/legacy-plugin-chart-histogram": "^0.17.36",
"@superset-ui/legacy-plugin-chart-horizon": "^0.17.36",
"@superset-ui/legacy-plugin-chart-map-box": "^0.17.36",
"@superset-ui/legacy-plugin-chart-paired-t-test": "^0.17.36",
"@superset-ui/legacy-plugin-chart-parallel-coordinates": "^0.17.36",
"@superset-ui/legacy-plugin-chart-partition": "^0.17.36",
"@superset-ui/legacy-plugin-chart-pivot-table": "^0.17.36",
"@superset-ui/legacy-plugin-chart-rose": "^0.17.36",
"@superset-ui/legacy-plugin-chart-sankey": "^0.17.36",
"@superset-ui/legacy-plugin-chart-sankey-loop": "^0.17.36",
"@superset-ui/legacy-plugin-chart-sunburst": "^0.17.36",
"@superset-ui/legacy-plugin-chart-treemap": "^0.17.36",
"@superset-ui/legacy-plugin-chart-world-map": "^0.17.36",
"@superset-ui/legacy-preset-chart-big-number": "^0.17.36",
"@superset-ui/legacy-preset-chart-deckgl": "^0.4.6",
"@superset-ui/legacy-preset-chart-nvd3": "^0.17.30",
"@superset-ui/plugin-chart-echarts": "^0.17.30",
"@superset-ui/plugin-chart-table": "^0.17.30",
"@superset-ui/plugin-chart-word-cloud": "^0.17.30",
"@superset-ui/preset-chart-xy": "^0.17.30",
"@superset-ui/legacy-preset-chart-nvd3": "^0.17.36",
"@superset-ui/plugin-chart-echarts": "^0.17.38",
"@superset-ui/plugin-chart-pivot-table": "^0.17.36",
"@superset-ui/plugin-chart-table": "^0.17.37",
"@superset-ui/plugin-chart-word-cloud": "^0.17.36",
"@superset-ui/preset-chart-xy": "^0.17.36",
"@vx/responsive": "^0.0.195",
"abortcontroller-polyfill": "^1.1.9",
"antd": "^4.9.4",
@@ -174,7 +175,7 @@
"regenerator-runtime": "^0.13.5",
"rison": "^0.1.1",
"shortid": "^2.2.6",
"urijs": "^1.19.4",
"urijs": "^1.19.6",
"use-immer": "^0.4.2",
"use-query-params": "^1.1.9"
},
+1 -1
View File
@@ -20,7 +20,7 @@ export default {
id: 1234,
slug: 'dashboardSlug',
metadata: {
filter_configuration: [
native_filter_configuration: [
{
id: 'DefaultsID',
filterType: 'filter_select',
+35 -40
View File
@@ -16,10 +16,12 @@
* specific language governing permissions and limitations
* under the License.
*/
import { ExtraFormData } from '@superset-ui/core';
import { NativeFiltersState } from 'src/dashboard/reducers/types';
import { DataMaskStateWithId } from '../../src/dataMask/types';
export const nativeFilters: NativeFiltersState = {
isInitialized: true,
filterSets: {},
filters: {
'NATIVE_FILTER-e7Q8zKixx': {
@@ -76,49 +78,44 @@ export const nativeFilters: NativeFiltersState = {
};
export const dataMaskWith2Filters: DataMaskStateWithId = {
crossFilters: {},
ownFilters: {},
nativeFilters: {
'NATIVE_FILTER-e7Q8zKixx': {
id: 'NATIVE_FILTER-e7Q8zKixx',
extraFormData: {
append_form_data: {
filters: [
{
col: 'region',
op: 'IN',
val: ['East Asia & Pacific'],
},
],
'NATIVE_FILTER-e7Q8zKixx': {
id: 'NATIVE_FILTER-e7Q8zKixx',
ownState: {},
extraFormData: {
filters: [
{
col: 'region',
op: 'IN',
val: ['East Asia & Pacific'],
},
},
currentState: {
value: ['East Asia & Pacific'],
},
],
},
'NATIVE_FILTER-x9QPw0so1': {
id: 'NATIVE_FILTER-x9QPw0so1',
extraFormData: {},
currentState: {},
filterState: {
value: ['East Asia & Pacific'],
},
},
'NATIVE_FILTER-x9QPw0so1': {
id: 'NATIVE_FILTER-x9QPw0so1',
ownState: {},
extraFormData: {},
filterState: {},
},
};
export const extraFormData = {
append_form_data: {
filters: [
{
col: 'ethnic_minority',
op: 'IN',
val: 'No, not an ethnic minority',
},
],
},
export const extraFormData: ExtraFormData = {
filters: [
{
col: 'ethnic_minority',
op: 'IN',
val: ['No, not an ethnic minority'],
},
],
};
export const NATIVE_FILTER_ID = 'NATIVE_FILTER-p4LImrSgA';
export const singleNativeFiltersState = {
isInitialized: true,
filters: {
[NATIVE_FILTER_ID]: {
id: [NATIVE_FILTER_ID],
@@ -136,14 +133,12 @@ export const singleNativeFiltersState = {
},
};
export const dataMaskWith1Filter = {
nativeFilters: {
[NATIVE_FILTER_ID]: {
id: NATIVE_FILTER_ID,
extraFormData,
currentState: {
value: ['No, not an ethnic minority'],
},
export const dataMaskWith1Filter: DataMaskStateWithId = {
[NATIVE_FILTER_ID]: {
id: NATIVE_FILTER_ID,
extraFormData,
filterState: {
value: ['No, not an ethnic minority'],
},
},
};
+31
View File
@@ -124,3 +124,34 @@ export const getMockStoreWithNativeFilters = () =>
},
},
});
export const stateWithoutNativeFilters = {
...mockState,
charts: {
...mockState.charts,
[sliceIdWithAppliedFilter]: {
...mockState.charts[sliceId],
queryResponse: {
status: 'success',
applied_filters: [{ column: 'region' }],
rejected_filters: [],
},
},
[sliceIdWithRejectedFilter]: {
...mockState.charts[sliceId],
queryResponse: {
status: 'success',
applied_filters: [],
rejected_filters: [{ column: 'region', reason: 'not_in_datasource' }],
},
},
},
dashboardInfo: {
dash_edit_perm: true,
metadata: {
native_filter_configuration: [],
},
},
dataMask: {},
nativeFilters: { filters: {}, filterSets: {} },
};
@@ -31,6 +31,7 @@ import {
import { sliceId } from 'spec/fixtures/mockChartQueries';
import { dashboardFilters } from 'spec/fixtures/mockDashboardFilters';
import { dashboardWithFilter } from 'spec/fixtures/mockDashboardLayout';
import { FeatureFlag } from 'src/featureFlags';
describe('FiltersBadge', () => {
// there's this bizarre "active filters" thing
@@ -158,6 +159,10 @@ describe('FiltersBadge', () => {
});
it('shows the indicator when filters have been applied', () => {
// @ts-ignore
global.featureFlags = {
[FeatureFlag.DASHBOARD_NATIVE_FILTERS]: true,
};
const store = getMockStoreWithNativeFilters();
// start with basic dashboard state, dispatch an event to simulate query completion
store.dispatch({
@@ -182,6 +187,10 @@ describe('FiltersBadge', () => {
});
it("shows a warning when there's a rejected filter", () => {
// @ts-ignore
global.featureFlags = {
[FeatureFlag.DASHBOARD_NATIVE_FILTERS]: true,
};
const store = getMockStoreWithNativeFilters();
// start with basic dashboard state, dispatch an event to simulate query completion
store.dispatch({
@@ -1,174 +0,0 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import React from 'react';
import { shallow } from 'enzyme';
import { Menu, NoAnimationDropdown } from 'src/common/components';
import RefreshIntervalModal from 'src/dashboard/components/RefreshIntervalModal';
import HeaderActionsDropdown from 'src/dashboard/components/HeaderActionsDropdown';
import SaveModal from 'src/dashboard/components/SaveModal';
import CssEditor from 'src/dashboard/components/CssEditor';
import fetchMock from 'fetch-mock';
import ShareMenuItems from 'src/dashboard/components/menu/ShareMenuItems';
fetchMock.get('glob:*/csstemplateasyncmodelview/api/read', {});
describe('HeaderActionsDropdown', () => {
const props = {
addSuccessToast: () => {},
addDangerToast: () => {},
customCss: '',
dashboardId: 1,
dashboardInfo: {},
dashboardTitle: 'Title',
editMode: false,
expandedSlices: {},
filters: {},
forceRefreshAllCharts: () => {},
hasUnsavedChanges: false,
isLoading: false,
layout: {},
onChange: () => {},
onSave: () => {},
refreshFrequency: 200,
setRefreshFrequency: () => {},
shouldPersistRefreshFrequency: true,
showPropertiesModal: () => {},
startPeriodicRender: () => {},
updateCss: () => {},
userCanEdit: false,
userCanSave: false,
lastModifiedTime: 0,
};
function setup(overrideProps) {
const wrapper = shallow(
<HeaderActionsDropdown {...props} {...overrideProps} />,
);
const menu = shallow(
<div>{wrapper.find(NoAnimationDropdown).props().overlay}</div>,
);
return { wrapper, menu };
}
describe('readonly-user', () => {
const overrideProps = { userCanSave: false, userCanShare: false };
it('should render the DropdownButton', () => {
const { wrapper } = setup(overrideProps);
expect(wrapper.find(NoAnimationDropdown)).toExist();
});
it('should not render the SaveModal', () => {
const { menu } = setup(overrideProps);
expect(menu.find(SaveModal)).not.toExist();
});
it('should render available Menu items', () => {
const { menu } = setup(overrideProps);
expect(menu.find(Menu.Item)).toHaveLength(4);
});
it('should render the RefreshIntervalModal', () => {
const { menu } = setup(overrideProps);
expect(menu.find(RefreshIntervalModal)).toExist();
});
it('should not render the ShareMenuItems', () => {
const { menu } = setup(overrideProps);
expect(menu.find(ShareMenuItems)).not.toExist();
});
it('should not render the CssEditor', () => {
const { menu } = setup(overrideProps);
expect(menu.find(CssEditor)).not.toExist();
});
});
describe('write-user', () => {
const overrideProps = { userCanSave: true, userCanShare: true };
it('should render the DropdownButton', () => {
const { wrapper } = setup(overrideProps);
expect(wrapper.find(NoAnimationDropdown)).toExist();
});
it('should render the SaveModal', () => {
const { menu } = setup(overrideProps);
expect(menu.find(SaveModal)).toExist();
});
it('should render available Menu items', () => {
const { menu } = setup(overrideProps);
expect(menu.find(Menu.Item)).toHaveLength(5);
});
it('should render the RefreshIntervalModal', () => {
const { menu } = setup(overrideProps);
expect(menu.find(RefreshIntervalModal)).toExist();
});
it('should render the ShareMenuItems', () => {
const { menu } = setup(overrideProps);
expect(menu.find(ShareMenuItems)).toExist();
});
it('should not render the CssEditor', () => {
const { menu } = setup(overrideProps);
expect(menu.find(CssEditor)).not.toExist();
});
});
describe('write-user-with-edit-mode', () => {
const overrideProps = {
userCanSave: true,
editMode: true,
userCanShare: true,
};
it('should render the DropdownButton', () => {
const { wrapper } = setup(overrideProps);
expect(wrapper.find(NoAnimationDropdown)).toExist();
});
it('should render the SaveModal', () => {
const { menu } = setup(overrideProps);
expect(menu.find(SaveModal)).toExist();
});
it('should render available MenuItems', () => {
const { menu } = setup(overrideProps);
expect(menu.find(Menu.Item)).toHaveLength(6);
});
it('should render the RefreshIntervalModal', () => {
const { menu } = setup(overrideProps);
expect(menu.find(RefreshIntervalModal)).toExist();
});
it('should render the ShareMenuItems', () => {
const { menu } = setup(overrideProps);
expect(menu.find(ShareMenuItems)).toExist();
});
it('should render the CssEditor', () => {
const { menu } = setup(overrideProps);
expect(menu.find(CssEditor)).toExist();
});
});
});
@@ -1,244 +0,0 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import React from 'react';
import { styledMount as mount } from 'spec/helpers/theming';
import Header from 'src/dashboard/components/Header';
import EditableTitle from 'src/components/EditableTitle';
import FaveStar from 'src/components/FaveStar';
import PublishedStatus from 'src/dashboard/components/PublishedStatus';
import HeaderActionsDropdown from 'src/dashboard/components/HeaderActionsDropdown';
import Button from 'src/components/Button';
import UndoRedoKeyListeners from 'src/dashboard/components/UndoRedoKeyListeners';
describe('Header', () => {
const props = {
addSuccessToast: () => {},
addDangerToast: () => {},
addWarningToast: () => {},
dashboardInfo: {
id: 1,
dash_edit_perm: true,
dash_save_perm: true,
userId: 1,
metadata: {},
common: {
conf: {},
},
},
dashboardTitle: 'title',
charts: {},
layout: {},
filters: {},
expandedSlices: {},
css: '',
customCss: '',
isStarred: false,
isLoading: false,
lastModifiedTime: 0,
refreshFrequency: 0,
shouldPersistRefreshFrequency: false,
onSave: () => {},
onChange: () => {},
fetchFaveStar: () => {},
fetchCharts: () => {},
saveFaveStar: () => {},
savePublished: () => {},
isPublished: false,
updateDashboardTitle: () => {},
editMode: false,
setEditMode: () => {},
showBuilderPane: () => {},
updateCss: () => {},
setColorSchemeAndUnsavedChanges: () => {},
logEvent: () => {},
setRefreshFrequency: () => {},
hasUnsavedChanges: false,
maxUndoHistoryExceeded: false,
// redux
onUndo: () => {},
onRedo: () => {},
undoLength: 0,
redoLength: 0,
setMaxUndoHistoryExceeded: () => {},
maxUndoHistoryToast: () => {},
dashboardInfoChanged: () => {},
dashboardTitleChanged: () => {},
};
function setup(overrideProps) {
const wrapper = mount(<Header {...props} {...overrideProps} />);
return wrapper;
}
describe('read-only-user', () => {
const overrideProps = {
dashboardInfo: {
...props.dashboardInfo,
id: 1,
dash_edit_perm: false,
dash_save_perm: false,
userId: 1,
},
};
it('should render the EditableTitle', () => {
const wrapper = setup(overrideProps);
expect(wrapper.find(EditableTitle)).toExist();
});
it('should render the PublishedStatus', () => {
const wrapper = setup(overrideProps);
expect(wrapper.find(PublishedStatus)).toExist();
});
it('should render the FaveStar', () => {
const wrapper = setup(overrideProps);
expect(wrapper.find(FaveStar)).toExist();
});
it('should render the HeaderActionsDropdown', () => {
const wrapper = setup(overrideProps);
expect(wrapper.find(HeaderActionsDropdown)).toExist();
});
it('should not set up undo/redo', () => {
const wrapper = setup(overrideProps);
expect(wrapper.find(UndoRedoKeyListeners)).not.toExist();
});
});
describe('write-user', () => {
const overrideProps = {
editMode: false,
dashboardInfo: {
...props.dashboardInfo,
id: 1,
dash_edit_perm: true,
dash_save_perm: true,
userId: 1,
},
};
it('should render the EditableTitle', () => {
const wrapper = setup(overrideProps);
expect(wrapper.find(EditableTitle)).toExist();
});
it('should render the PublishedStatus', () => {
const wrapper = setup(overrideProps);
expect(wrapper.find(PublishedStatus)).toExist();
});
it('should render the FaveStar', () => {
const wrapper = setup(overrideProps);
expect(wrapper.find(FaveStar)).toExist();
});
it('should render the HeaderActionsDropdown', () => {
const wrapper = setup(overrideProps);
expect(wrapper.find(HeaderActionsDropdown)).toExist();
});
it('should not set up undo/redo', () => {
const wrapper = setup(overrideProps);
expect(wrapper.find(UndoRedoKeyListeners)).not.toExist();
});
});
describe('write-user-with-edit-mode', () => {
const overrideProps = {
editMode: true,
dashboardInfo: {
...props.dashboardInfo,
id: 1,
dash_edit_perm: true,
dash_save_perm: true,
userId: 1,
},
};
it('should render the EditableTitle', () => {
const wrapper = setup(overrideProps);
expect(wrapper.find(EditableTitle)).toExist();
});
it('should render the FaveStar', () => {
const wrapper = setup(overrideProps);
expect(wrapper.find(FaveStar)).toExist();
});
it('should render the PublishedStatus', () => {
const wrapper = setup(overrideProps);
expect(wrapper.find(PublishedStatus)).toExist();
});
it('should render the HeaderActionsDropdown', () => {
const wrapper = setup(overrideProps);
expect(wrapper.find(HeaderActionsDropdown)).toExist();
});
it('should render five Buttons', () => {
const wrapper = setup(overrideProps);
expect(wrapper.find(Button)).toHaveLength(4);
});
it('should set up undo/redo', () => {
const wrapper = setup(overrideProps);
expect(wrapper.find(UndoRedoKeyListeners)).toExist();
});
});
describe('logged-out-user', () => {
const overrideProps = {
dashboardInfo: {
...props.dashboardInfo,
id: 1,
dash_edit_perm: false,
dash_save_perm: false,
userId: null,
},
};
it('should render the EditableTitle', () => {
const wrapper = setup(overrideProps);
expect(wrapper.find(EditableTitle)).toExist();
});
it('should render the PublishedStatus', () => {
const wrapper = setup(overrideProps);
expect(wrapper.find(PublishedStatus)).toExist();
});
it('should not render the FaveStar', () => {
const wrapper = setup(overrideProps);
expect(wrapper.find(FaveStar)).not.toExist();
});
it('should render the HeaderActionsDropdown', () => {
const wrapper = setup(overrideProps);
expect(wrapper.find(HeaderActionsDropdown)).toExist();
});
it('should not set up undo/redo', () => {
const wrapper = setup(overrideProps);
expect(wrapper.find(UndoRedoKeyListeners)).not.toExist();
});
});
});
@@ -27,7 +27,7 @@ import {
ThemeProvider,
} from '@superset-ui/core';
import Modal from 'src/common/components/Modal';
import Modal from 'src/components/Modal';
import PropertiesModal from 'src/dashboard/components/PropertiesModal';
import { mockStore } from 'spec/fixtures/mockStore';
@@ -23,7 +23,7 @@ import sinon from 'sinon';
import { DndProvider } from 'react-dnd';
import { HTML5Backend } from 'react-dnd-html5-backend';
import { LineEditableTabs } from 'src/common/components/Tabs';
import { LineEditableTabs } from 'src/components/Tabs';
import { Modal } from 'src/common/components';
import fetchMock from 'fetch-mock';
import { styledMount as mount } from 'spec/helpers/theming';
@@ -16,23 +16,21 @@
* specific language governing permissions and limitations
* under the License.
*/
import { DataMaskStateWithId, DataMaskType } from 'src/dataMask/types';
import { DataMaskStateWithId } from 'src/dataMask/types';
import { NativeFiltersState } from 'src/dashboard/reducers/types';
export const mockDataMaskInfo: DataMaskStateWithId = {
[DataMaskType.CrossFilters]: {},
[DataMaskType.OwnFilters]: {},
[DataMaskType.NativeFilters]: {
DefaultsID: {
id: 'DefaultId',
currentState: {
value: [],
},
DefaultsID: {
id: 'DefaultId',
ownState: {},
filterState: {
value: [],
},
},
};
export const nativeFiltersInfo: NativeFiltersState = {
isInitialized: true,
filterSets: {
'set-id': {
id: 'DefaultsID',
@@ -52,6 +52,7 @@ describe('getFormDataWithExtraFilters', () => {
},
sliceId: chartId,
nativeFilters: {
isInitialized: true,
filterSets: {},
filters: {
[filterId]: ({
@@ -64,14 +65,11 @@ describe('getFormDataWithExtraFilters', () => {
},
},
dataMask: {
crossFilters: {},
ownFilters: {},
nativeFilters: {
[filterId]: {
id: filterId,
extraFormData: {},
currentState: {},
},
[filterId]: {
id: filterId,
extraFormData: {},
filterState: {},
ownState: {},
},
},
layout: (dashboardLayout.present as unknown) as {
@@ -24,7 +24,7 @@ import thunk from 'redux-thunk';
import { act } from 'react-dom/test-utils';
import sinon from 'sinon';
import { supersetTheme, ThemeProvider } from '@superset-ui/core';
import Modal from 'src/common/components/Modal';
import Modal from 'src/components/Modal';
import ChangeDatasourceModal from 'src/datasource/ChangeDatasourceModal';
import waitForComponentToPaint from 'spec/helpers/waitForComponentToPaint';
import mockDatasource from 'spec/fixtures/mockDatasource';
@@ -21,10 +21,10 @@ import { shallow } from 'enzyme';
import configureStore from 'redux-mock-store';
import fetchMock from 'fetch-mock';
import thunk from 'redux-thunk';
import { Radio } from 'src/common/components/Radio';
import { Radio } from 'src/components/Radio';
import Icon from 'src/components/Icon';
import Tabs from 'src/common/components/Tabs';
import Tabs from 'src/components/Tabs';
import DatasourceEditor from 'src/datasource/DatasourceEditor';
import Field from 'src/CRUD/Field';
import mockDatasource from 'spec/fixtures/mockDatasource';
@@ -27,7 +27,7 @@ import sinon from 'sinon';
import { supersetTheme, ThemeProvider } from '@superset-ui/core';
import waitForComponentToPaint from 'spec/helpers/waitForComponentToPaint';
import Modal from 'src/common/components/Modal';
import Modal from 'src/components/Modal';
import DatasourceModal from 'src/datasource/DatasourceModal';
import DatasourceEditor from 'src/datasource/DatasourceEditor';
import * as featureFlags from 'src/featureFlags';
@@ -20,7 +20,7 @@
import React from 'react';
import sinon from 'sinon';
import { shallow } from 'enzyme';
import { Tooltip } from 'src/common/components/Tooltip';
import { Tooltip } from 'src/components/Tooltip';
import AdhocMetricEditPopoverTitle from 'src/explore/components/controls/MetricControl/AdhocMetricEditPopoverTitle';
@@ -29,7 +29,7 @@ import {
ControlPanelsContainer,
ControlPanelsContainerProps,
} from 'src/explore/components/ControlPanelsContainer';
import Collapse from 'src/common/components/Collapse';
import Collapse from 'src/components/Collapse';
describe('ControlPanelsContainer', () => {
let wrapper;
@@ -25,7 +25,7 @@ import DatasourceModal from 'src/datasource/DatasourceModal';
import ChangeDatasourceModal from 'src/datasource/ChangeDatasourceModal';
import DatasourceControl from 'src/explore/components/controls/DatasourceControl';
import Icon from 'src/components/Icon';
import { Tooltip } from 'src/common/components/Tooltip';
import { Tooltip } from 'src/components/Tooltip';
const defaultProps = {
name: 'datasource',
@@ -20,7 +20,7 @@ import React from 'react';
import { shallow } from 'enzyme';
import Label from 'src/components/Label';
import { Tooltip } from 'src/common/components/Tooltip';
import { Tooltip } from 'src/components/Tooltip';
import RowCountLabel from 'src/explore/components/RowCountLabel';
describe('RowCountLabel', () => {
@@ -25,7 +25,7 @@ import { Provider } from 'react-redux';
import { shallow } from 'enzyme';
import { styledMount as mount } from 'spec/helpers/theming';
import { FormControl } from 'react-bootstrap';
import { Radio } from 'src/common/components/Radio';
import { Radio } from 'src/components/Radio';
import Button from 'src/components/Button';
import sinon from 'sinon';
import fetchMock from 'fetch-mock';
@@ -21,7 +21,8 @@ import sinon from 'sinon';
import { shallow } from 'enzyme';
import { getChartMetadataRegistry, ChartMetadata } from '@superset-ui/core';
import VizTypeControl from 'src/explore/components/controls/VizTypeControl';
import Modal from 'src/common/components/Modal';
import Modal from 'src/components/Modal';
import { Input } from 'src/common/components';
const defaultProps = {
name: 'viz_type',
@@ -65,7 +66,7 @@ describe('VizTypeControl', () => {
});
it('filters images based on text input', () => {
expect(wrapper.find('img')).toHaveLength(2);
wrapper.find('FormControl').simulate('change', {
wrapper.find(Input).simulate('change', {
target: {
value: 'vis2',
},
@@ -26,10 +26,6 @@ import {
shouldUseLegacyApi,
getSimpleSQLExpression,
} from 'src/explore/exploreUtils';
import {
buildTimeRangeString,
formatTimeRange,
} from 'src/explore/dateFilterUtils';
import { DashboardStandaloneMode } from 'src/dashboard/util/constants';
import * as hostNamesConfig from 'src/utils/hostNamesConfig';
import { getChartMetadataRegistry } from '@superset-ui/core';
@@ -264,40 +260,6 @@ describe('exploreUtils', () => {
});
});
describe('buildTimeRangeString', () => {
it('generates proper time range string', () => {
expect(
buildTimeRangeString('2010-07-30T00:00:00', '2020-07-30T00:00:00'),
).toBe('2010-07-30T00:00:00 : 2020-07-30T00:00:00');
expect(buildTimeRangeString('', '2020-07-30T00:00:00')).toBe(
' : 2020-07-30T00:00:00',
);
expect(buildTimeRangeString('', '')).toBe(' : ');
});
});
describe('formatTimeRange', () => {
it('generates a readable time range', () => {
expect(formatTimeRange('Last 7 days')).toBe('Last 7 days');
expect(formatTimeRange('No filter')).toBe('No filter');
expect(formatTimeRange('Yesterday : Tomorrow')).toBe(
'Yesterday < col < Tomorrow',
);
expect(
formatTimeRange('2010-07-30T00:00:00 : 2020-07-30T00:00:00', [
'inclusive',
'exclusive',
]),
).toBe('2010-07-30 ≤ col < 2020-07-30');
expect(
formatTimeRange('2010-07-30T01:00:00 : ', ['exclusive', 'inclusive']),
).toBe('2010-07-30T01:00:00 < col ≤ ∞');
expect(formatTimeRange(' : 2020-07-30T00:00:00')).toBe(
'-∞ < col < 2020-07-30',
);
});
});
describe('getSimpleSQLExpression', () => {
it('returns empty string when subject is undefined', () => {
expect(getSimpleSQLExpression(undefined, '=', 10)).toBe('');
@@ -35,64 +35,56 @@ describe('Filter utils', () => {
describe('getRangeExtraFormData', () => {
it('getRangeExtraFormData - col: "testCol", lower: 1, upper: 2', () => {
expect(getRangeExtraFormData('testCol', 1, 2)).toEqual({
append_form_data: {
filters: [
{
col: 'testCol',
op: '>=',
val: 1,
},
{
col: 'testCol',
op: '<=',
val: 2,
},
],
},
filters: [
{
col: 'testCol',
op: '>=',
val: 1,
},
{
col: 'testCol',
op: '<=',
val: 2,
},
],
});
});
it('getRangeExtraFormData - col: "testCol", lower: 0, upper: 0', () => {
expect(getRangeExtraFormData('testCol', 0, 0)).toEqual({
append_form_data: {
filters: [
{
col: 'testCol',
op: '>=',
val: 0,
},
{
col: 'testCol',
op: '<=',
val: 0,
},
],
},
filters: [
{
col: 'testCol',
op: '>=',
val: 0,
},
{
col: 'testCol',
op: '<=',
val: 0,
},
],
});
});
it('getRangeExtraFormData - col: "testCol", lower: null, upper: 2', () => {
expect(getRangeExtraFormData('testCol', null, 2)).toEqual({
append_form_data: {
filters: [
{
col: 'testCol',
op: '<=',
val: 2,
},
],
},
filters: [
{
col: 'testCol',
op: '<=',
val: 2,
},
],
});
});
it('getRangeExtraFormData - col: "testCol", lower: 1, upper: undefined', () => {
expect(getRangeExtraFormData('testCol', 1, undefined)).toEqual({
append_form_data: {
filters: [
{
col: 'testCol',
op: '>=',
val: 1,
},
],
},
filters: [
{
col: 'testCol',
op: '>=',
val: 1,
},
],
});
});
});
@@ -101,68 +93,56 @@ describe('Filter utils', () => {
expect(
getSelectExtraFormData('testCol', ['value'], false, false),
).toEqual({
append_form_data: {
filters: [
{
col: 'testCol',
op: 'IN',
val: ['value'],
},
],
},
filters: [
{
col: 'testCol',
op: 'IN',
val: ['value'],
},
],
});
});
it('getSelectExtraFormData - col: "testCol", value: ["value"], emptyFilter: true, inverseSelection: false', () => {
expect(getSelectExtraFormData('testCol', ['value'], true, false)).toEqual(
{
append_form_data: {
adhoc_filters: [
{
clause: 'WHERE',
expressionType: 'SQL',
sqlExpression: '1 = 0',
},
],
},
adhoc_filters: [
{
clause: 'WHERE',
expressionType: 'SQL',
sqlExpression: '1 = 0',
},
],
},
);
});
it('getSelectExtraFormData - col: "testCol", value: ["value"], emptyFilter: false, inverseSelection: true', () => {
expect(getSelectExtraFormData('testCol', ['value'], false, true)).toEqual(
{
append_form_data: {
filters: [
{
col: 'testCol',
op: 'NOT IN',
val: ['value'],
},
],
},
filters: [
{
col: 'testCol',
op: 'NOT IN',
val: ['value'],
},
],
},
);
});
it('getSelectExtraFormData - col: "testCol", value: [], emptyFilter: false, inverseSelection: false', () => {
expect(getSelectExtraFormData('testCol', [], false, false)).toEqual({
append_form_data: {
filters: [],
},
filters: [],
});
});
it('getSelectExtraFormData - col: "testCol", value: undefined, emptyFilter: false, inverseSelection: false', () => {
expect(
getSelectExtraFormData('testCol', undefined, false, false),
).toEqual({
append_form_data: {
filters: [],
},
filters: [],
});
});
it('getSelectExtraFormData - col: "testCol", value: null, emptyFilter: false, inverseSelection: false', () => {
expect(getSelectExtraFormData('testCol', null, false, false)).toEqual({
append_form_data: {
filters: [],
},
filters: [],
});
});
});
@@ -17,10 +17,10 @@
* under the License.
*/
import React from 'react';
import { Col, Row } from 'react-bootstrap';
import { Row, Col } from 'src/common/components';
import { shallow } from 'enzyme';
import App from 'src/profile/components/App';
import Tabs from 'src/common/components/Tabs';
import Tabs from 'src/components/Tabs';
import { user } from './fixtures';
@@ -18,7 +18,6 @@
*/
import React from 'react';
import Gravatar from 'react-gravatar';
import { Panel } from 'react-bootstrap';
import { mount } from 'enzyme';
import UserInfo from 'src/profile/components/UserInfo';
@@ -37,7 +36,7 @@ describe('UserInfo', () => {
});
it('renders a Panel', () => {
const wrapper = mount(<UserInfo {...mockedProps} />);
expect(wrapper.find(Panel)).toExist();
expect(wrapper.find('.panel')).toExist();
});
it('renders 5 icons', () => {
const wrapper = mount(<UserInfo {...mockedProps} />);
@@ -18,7 +18,7 @@
*/
import React from 'react';
import { shallow } from 'enzyme';
import { Radio } from 'src/common/components/Radio';
import { Radio } from 'src/components/Radio';
import { AutoComplete, Input } from 'src/common/components';
import { SaveDatasetModal } from 'src/SqlLab/components/SaveDatasetModal';
@@ -21,7 +21,7 @@ import { FormControl } from 'react-bootstrap';
import { shallow } from 'enzyme';
import * as sinon from 'sinon';
import SaveQuery from 'src/SqlLab/components/SaveQuery';
import Modal from 'src/common/components/Modal';
import Modal from 'src/components/Modal';
import Button from 'src/components/Button';
describe('SavedQuery', () => {
@@ -26,7 +26,7 @@ import sinon from 'sinon';
import { act } from 'react-dom/test-utils';
import fetchMock from 'fetch-mock';
import { supersetTheme, ThemeProvider } from '@superset-ui/core';
import { EditableTabs } from 'src/common/components/Tabs';
import { EditableTabs } from 'src/components/Tabs';
import TabbedSqlEditors from 'src/SqlLab/components/TabbedSqlEditors';
import SqlEditor from 'src/SqlLab/components/SqlEditor';
@@ -21,7 +21,7 @@ import { mount, shallow } from 'enzyme';
import { Provider } from 'react-redux';
import configureStore from 'redux-mock-store';
import { supersetTheme, ThemeProvider } from '@superset-ui/core';
import Collapse from 'src/common/components/Collapse';
import Collapse from 'src/components/Collapse';
import { IconTooltip } from 'src/components/IconTooltip';
import TableElement from 'src/SqlLab/components/TableElement';
+1 -1
View File
@@ -20,7 +20,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import { FormGroup, HelpBlock, FormControl } from 'react-bootstrap';
import { Tooltip } from 'src/common/components/Tooltip';
import { Tooltip } from 'src/components/Tooltip';
import FormLabel from 'src/components/FormLabel';
import './crud.less';
@@ -21,7 +21,7 @@ import PropTypes from 'prop-types';
import { ClassNames } from '@emotion/core';
import { styled, useTheme } from '@superset-ui/core';
import { Tooltip } from 'src/common/components/Tooltip';
import { Tooltip } from 'src/components/Tooltip';
const propTypes = {
column: PropTypes.object.isRequired,
@@ -17,40 +17,37 @@
* under the License.
*/
import React from 'react';
import PropTypes from 'prop-types';
import Alert from 'src/components/Alert';
import { t } from '@superset-ui/core';
import QueryTable from './QueryTable';
import { Query } from '../types';
const propTypes = {
queries: PropTypes.array.isRequired,
actions: PropTypes.object.isRequired,
displayLimit: PropTypes.number.isRequired,
};
interface QueryHistoryProps {
queries: Query[];
actions: Record<string, unknown>;
displayLimit: number;
}
const QueryHistory = props => {
if (props.queries.length > 0) {
return (
<QueryTable
columns={[
'state',
'started',
'duration',
'progress',
'rows',
'sql',
'output',
'actions',
]}
queries={props.queries}
actions={props.actions}
displayLimit={props.displayLimit}
/>
);
}
return <Alert type="info" message={t('No query history yet...')} />;
};
QueryHistory.propTypes = propTypes;
const QueryHistory = ({ queries, actions, displayLimit }: QueryHistoryProps) =>
queries.length > 0 ? (
<QueryTable
columns={[
'state',
'started',
'duration',
'progress',
'rows',
'sql',
'output',
'actions',
]}
queries={queries}
actions={actions}
displayLimit={displayLimit}
/>
) : (
<Alert type="info" message={t('No query history yet...')} />
);
export default QueryHistory;
@@ -17,21 +17,19 @@
* under the License.
*/
import React from 'react';
import PropTypes from 'prop-types';
import Label from 'src/components/Label';
import { STATE_TYPE_MAP } from '../constants';
import { Query } from '../types';
const propTypes = {
query: PropTypes.object.isRequired,
};
interface QueryStateLabelProps {
query: Query;
}
export default function QueryStateLabel({ query }) {
const type = STATE_TYPE_MAP[query.state];
export default function QueryStateLabel({ query }: QueryStateLabelProps) {
return (
<Label className="m-r-3" type={type}>
<Label className="m-r-3" type={STATE_TYPE_MAP[query.state]}>
{query.state}
</Label>
);
}
QueryStateLabel.propTypes = propTypes;
@@ -506,7 +506,9 @@ export default class ResultSet extends React.PureComponent<
const limitReached = results?.displayLimitReached;
return (
<ReturnedRows>
{!limitReached && <span>{t(`%s rows returned`, rows)}</span>}
{!limitReached && (
<Alert type="warning" message={t(`%s rows returned`, rows)} />
)}
{limitReached && (
<Alert
type="warning"
@@ -25,7 +25,7 @@ import Icon from 'src/components/Icon';
import {
DropdownButton,
DropdownButtonProps,
} from 'src/common/components/DropdownButton';
} from 'src/components/DropdownButton';
interface Props {
allowAsync: boolean;
@@ -19,9 +19,9 @@
import React, { FunctionComponent } from 'react';
import { AutoCompleteProps } from 'antd/lib/auto-complete';
import { Radio } from 'src/common/components/Radio';
import { Radio } from 'src/components/Radio';
import { AutoComplete, Input } from 'src/common/components';
import StyledModal from 'src/common/components/Modal';
import StyledModal from 'src/components/Modal';
import Button from 'src/components/Button';
import { styled, t } from '@superset-ui/core';
import { RadioChangeEvent } from 'antd/lib/radio';
@@ -17,12 +17,13 @@
* under the License.
*/
import React, { useState } from 'react';
import { FormControl, FormGroup, Row, Col } from 'react-bootstrap';
import { Row, Col } from 'src/common/components';
import { FormControl, FormGroup } from 'react-bootstrap';
import { t, supersetTheme, styled } from '@superset-ui/core';
import Button from 'src/components/Button';
import FormLabel from 'src/components/FormLabel';
import Modal from 'src/common/components/Modal';
import Modal from 'src/components/Modal';
import Icon from 'src/components/Icon';
const Styles = styled.span`
@@ -114,7 +115,7 @@ export default function SaveQuery({
const renderModalBody = () => (
<FormGroup bsSize="small">
<Row>
<Col md={12}>
<Col xs={24}>
<small>
<FormLabel htmlFor="embed-height">{t('Name')}</FormLabel>
</small>
@@ -123,7 +124,7 @@ export default function SaveQuery({
</Row>
<br />
<Row>
<Col md={12}>
<Col xs={24}>
<small>
<FormLabel htmlFor="embed-height">{t('Description')}</FormLabel>
</small>
@@ -140,7 +141,7 @@ export default function SaveQuery({
<br />
<div>
<Row>
<Col md={12}>
<Col xs={24}>
<small>{saveQueryWarning}</small>
</Col>
</Row>
@@ -18,7 +18,8 @@
*/
import React, { FunctionComponent, useState } from 'react';
import Form, { FormProps, FormValidation } from 'react-jsonschema-form';
import { Col, FormControl, FormGroup, Row } from 'react-bootstrap';
import { Row, Col } from 'src/common/components';
import { FormControl, FormGroup } from 'react-bootstrap';
import { t, styled } from '@superset-ui/core';
import * as chrono from 'chrono-node';
import ModalTrigger from 'src/components/ModalTrigger';
@@ -140,7 +141,7 @@ const ScheduleQueryButton: FunctionComponent<ScheduleQueryButtonProps> = ({
const renderModalBody = () => (
<FormGroup>
<StyledRow>
<Col md={12}>
<Col xs={24}>
<FormLabel className="control-label" htmlFor="embed-height">
{t('Label')}
</FormLabel>
@@ -153,7 +154,7 @@ const ScheduleQueryButton: FunctionComponent<ScheduleQueryButtonProps> = ({
</Col>
</StyledRow>
<StyledRow>
<Col md={12}>
<Col xs={24}>
<FormLabel className="control-label" htmlFor="embed-height">
{t('Description')}
</FormLabel>
@@ -166,7 +167,7 @@ const ScheduleQueryButton: FunctionComponent<ScheduleQueryButtonProps> = ({
</Col>
</StyledRow>
<Row>
<Col md={12}>
<Col xs={24}>
<div className="json-schema">
<Form
schema={getJSONSchema()}
@@ -179,7 +180,7 @@ const ScheduleQueryButton: FunctionComponent<ScheduleQueryButtonProps> = ({
</Row>
{scheduleQueryWarning && (
<Row>
<Col md={12}>
<Col xs={24}>
<small>{scheduleQueryWarning}</small>
</Col>
</Row>
@@ -19,7 +19,7 @@
import React, { createRef } from 'react';
import shortid from 'shortid';
import Alert from 'src/components/Alert';
import Tabs from 'src/common/components/Tabs';
import Tabs from 'src/components/Tabs';
import { t, styled } from '@superset-ui/core';
import { isFeatureEnabled, FeatureFlag } from 'src/featureFlags';
@@ -23,12 +23,11 @@ import { CSSTransition } from 'react-transition-group';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import PropTypes from 'prop-types';
import { Form } from 'react-bootstrap';
import Split from 'react-split';
import { t, styled, supersetTheme } from '@superset-ui/core';
import debounce from 'lodash/debounce';
import throttle from 'lodash/throttle';
import StyledModal from 'src/common/components/Modal';
import StyledModal from 'src/components/Modal';
import Mousetrap from 'mousetrap';
import Button from 'src/components/Button';
import Timer from 'src/components/Timer';
@@ -57,8 +56,14 @@ import {
setActiveSouthPaneTab,
updateSavedQuery,
validateQuery,
} from '../actions/sqlLab';
} from 'src/SqlLab/actions/sqlLab';
import {
STATE_TYPE_MAP,
SQL_EDITOR_GUTTER_HEIGHT,
SQL_EDITOR_GUTTER_MARGIN,
SQL_TOOLBAR_HEIGHT,
} from 'src/SqlLab/constants';
import { FeatureFlag, isFeatureEnabled } from 'src/featureFlags';
import TemplateParamsEditor from './TemplateParamsEditor';
import ConnectedSouthPane from './SouthPane/state';
import SaveQuery from './SaveQuery';
@@ -67,14 +72,7 @@ import EstimateQueryCostButton from './EstimateQueryCostButton';
import ShareSqlLabQuery from './ShareSqlLabQuery';
import SqlEditorLeftBar from './SqlEditorLeftBar';
import AceEditorWrapper from './AceEditorWrapper';
import {
STATE_TYPE_MAP,
SQL_EDITOR_GUTTER_HEIGHT,
SQL_EDITOR_GUTTER_MARGIN,
SQL_TOOLBAR_HEIGHT,
} from '../constants';
import RunQueryActionButton from './RunQueryActionButton';
import { FeatureFlag, isFeatureEnabled } from '../../featureFlags';
const LIMIT_DROPDOWN = [10, 100, 1000, 10000, 100000];
const SQL_EDITOR_PADDING = 10;
@@ -114,7 +112,7 @@ const StyledToolbar = styled.div`
margin-block-end: 0;
}
.leftItems form,
.leftItems,
.rightItems {
display: flex;
align-items: center;
@@ -599,62 +597,60 @@ class SqlEditor extends React.PureComponent {
return (
<StyledToolbar className="sql-toolbar" id="js-sql-toolbar">
<div className="leftItems">
<Form inline>
<span>
<RunQueryActionButton
allowAsync={
this.props.database
? this.props.database.allow_run_async
: false
}
queryState={this.props.latestQuery?.state}
runQuery={this.runQuery}
selectedText={qe.selectedText}
stopQuery={this.stopQuery}
sql={this.state.sql}
overlayCreateAsMenu={showMenu ? runMenuBtn : null}
/>
</span>
{isFeatureEnabled(FeatureFlag.ESTIMATE_QUERY_COST) &&
this.props.database &&
this.props.database.allows_cost_estimate && (
<span>
<EstimateQueryCostButton
dbId={qe.dbId}
schema={qe.schema}
sql={qe.sql}
getEstimate={this.getQueryCostEstimate}
queryCostEstimate={qe.queryCostEstimate}
selectedText={qe.selectedText}
tooltip={t('Estimate the cost before running a query')}
/>
</span>
)}
<span>
<LimitSelectStyled>
<Dropdown overlay={this.renderQueryLimit()} trigger="click">
<a onClick={e => e.preventDefault()}>
<span>LIMIT:</span>
<span>
{this.convertToNumWithSpaces(
this.props.queryEditor.queryLimit ||
this.props.defaultQueryLimit,
)}
</span>
<Icon name="triangle-down" />
</a>
</Dropdown>
</LimitSelectStyled>
</span>
{this.props.latestQuery && (
<Timer
startTime={this.props.latestQuery.startDttm}
endTime={this.props.latestQuery.endDttm}
state={STATE_TYPE_MAP[this.props.latestQuery.state]}
isRunning={this.props.latestQuery.state === 'running'}
/>
<span>
<RunQueryActionButton
allowAsync={
this.props.database
? this.props.database.allow_run_async
: false
}
queryState={this.props.latestQuery?.state}
runQuery={this.runQuery}
selectedText={qe.selectedText}
stopQuery={this.stopQuery}
sql={this.state.sql}
overlayCreateAsMenu={showMenu ? runMenuBtn : null}
/>
</span>
{isFeatureEnabled(FeatureFlag.ESTIMATE_QUERY_COST) &&
this.props.database &&
this.props.database.allows_cost_estimate && (
<span>
<EstimateQueryCostButton
dbId={qe.dbId}
schema={qe.schema}
sql={qe.sql}
getEstimate={this.getQueryCostEstimate}
queryCostEstimate={qe.queryCostEstimate}
selectedText={qe.selectedText}
tooltip={t('Estimate the cost before running a query')}
/>
</span>
)}
</Form>
<span>
<LimitSelectStyled>
<Dropdown overlay={this.renderQueryLimit()} trigger="click">
<a onClick={e => e.preventDefault()}>
<span>LIMIT:</span>
<span>
{this.convertToNumWithSpaces(
this.props.queryEditor.queryLimit ||
this.props.defaultQueryLimit,
)}
</span>
<Icon name="triangle-down" />
</a>
</Dropdown>
</LimitSelectStyled>
</span>
{this.props.latestQuery && (
<Timer
startTime={this.props.latestQuery.startDttm}
endTime={this.props.latestQuery.endDttm}
state={STATE_TYPE_MAP[this.props.latestQuery.state]}
isRunning={this.props.latestQuery.state === 'running'}
/>
)}
</div>
<div className="rightItems">
<span>
@@ -20,7 +20,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import Button from 'src/components/Button';
import { t, styled, css } from '@superset-ui/core';
import Collapse from 'src/common/components/Collapse';
import Collapse from 'src/components/Collapse';
import TableElement from './TableElement';
import TableSelector from '../../components/TableSelector';
@@ -17,12 +17,13 @@
* under the License.
*/
import React from 'react';
import PropTypes from 'prop-types';
export default function TabStatusIcon(props) {
return <div className={`circle ${props.tabState}`} />;
import { QueryState } from '../types';
interface TabStatusIconProps {
tabState: QueryState;
}
TabStatusIcon.propTypes = {
tabState: PropTypes.string.isRequired,
};
export default function TabStatusIcon({ tabState }: TabStatusIconProps) {
return <div className={`circle ${tabState}`} />;
}
@@ -18,8 +18,8 @@
*/
import React from 'react';
import PropTypes from 'prop-types';
import { EditableTabs } from 'src/common/components/Tabs';
import { Dropdown } from 'src/common/components/Dropdown';
import { Dropdown } from 'src/components/Dropdown';
import { EditableTabs } from 'src/components/Tabs';
import { Menu } from 'src/common/components';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
@@ -28,7 +28,7 @@ import { styled, t } from '@superset-ui/core';
import { isFeatureEnabled, FeatureFlag } from 'src/featureFlags';
import { areArraysShallowEqual } from 'src/reduxUtils';
import { Tooltip } from 'src/common/components/Tooltip';
import { Tooltip } from 'src/components/Tooltip';
import { detectOS } from 'src/utils/common';
import * as Actions from '../actions/sqlLab';
import SqlEditor from './SqlEditor';
@@ -19,13 +19,13 @@
import React from 'react';
import PropTypes from 'prop-types';
import Card from 'src/common/components/Card';
import Collapse from 'src/common/components/Collapse';
import Collapse from 'src/components/Collapse';
import ButtonGroup from 'src/components/ButtonGroup';
import shortid from 'shortid';
import { t, styled } from '@superset-ui/core';
import { debounce } from 'lodash';
import { Tooltip } from 'src/common/components/Tooltip';
import { Tooltip } from 'src/components/Tooltip';
import CopyToClipboard from '../../components/CopyToClipboard';
import { IconTooltip } from '../../components/IconTooltip';
import ColumnElement from './ColumnElement';
@@ -25,7 +25,7 @@ import { debounce } from 'lodash';
import ModalTrigger from 'src/components/ModalTrigger';
import { ConfigEditor } from 'src/components/AsyncAceEditor';
import { FAST_DEBOUNCE } from 'src/constants';
import { Tooltip } from 'src/common/components/Tooltip';
import { Tooltip } from 'src/components/Tooltip';
const StyledConfigEditor = styled(ConfigEditor)`
&.ace_editor {
+2 -1
View File
@@ -294,7 +294,8 @@ div.Workspace {
.queryPane {
flex: 1 1 auto;
padding-left: 10px;
overflow: visible;
overflow-y: visible;
overflow-x: scroll;
}
.schemaPane-enter-done,
+10 -8
View File
@@ -23,6 +23,15 @@ export type Column = {
name: string;
};
export type QueryState =
| 'stopped'
| 'failed'
| 'pending'
| 'running'
| 'scheduled'
| 'success'
| 'timed_out';
export type Query = {
cached: boolean;
ctas: boolean;
@@ -48,14 +57,7 @@ export type Query = {
schema: string;
sql: string;
sqlEditorId: string;
state:
| 'stopped'
| 'failed'
| 'pending'
| 'running'
| 'scheduled'
| 'success'
| 'timed_out';
state: QueryState;
tab: string | null;
tempSchema: string | null;
tempTable: string;
@@ -17,10 +17,9 @@
* under the License.
*/
import React from 'react';
import { Panel } from 'react-bootstrap';
import Button from 'src/components/Button';
import Select from 'src/components/Select';
import { t } from '@superset-ui/core';
import { styled, t } from '@superset-ui/core';
import VizTypeControl from '../explore/components/controls/VizTypeControl';
@@ -41,6 +40,14 @@ export type AddSliceContainerState = {
};
const styleSelectContainer = { width: 600, marginBottom: '10px' };
const StyledContainer = styled.div`
border-radius: ${({ theme }) => theme.gridUnit}px;
background-color: ${({ theme }) => theme.colors.grayscale.light5};
padding: ${({ theme }) => theme.gridUnit * 6}px;
h3 {
padding-bottom: ${({ theme }) => theme.gridUnit * 3}px;
}
`;
export default class AddSliceContainer extends React.PureComponent<
AddSliceContainerProps,
@@ -88,69 +95,63 @@ export default class AddSliceContainer extends React.PureComponent<
render() {
return (
<div className="container">
<Panel>
<Panel.Heading>
<h3>{t('Create a new chart')}</h3>
</Panel.Heading>
<Panel.Body>
<div>
<p>{t('Choose a dataset')}</p>
<div style={styleSelectContainer}>
<Select
clearable={false}
ignoreAccents={false}
name="select-datasource"
onChange={this.changeDatasource}
options={this.props.datasources}
placeholder={t('Choose a dataset')}
value={
this.state.datasourceValue
? {
value: this.state.datasourceValue,
}
: undefined
}
width={600}
/>
</div>
<span className="text-muted">
{t(
'If the dataset you are looking for is not available in the list, follow the instructions on how to add it in the Superset tutorial.',
)}{' '}
<a
href="https://superset.apache.org/docs/creating-charts-dashboards/first-dashboard#adding-a-new-table"
rel="noopener noreferrer"
target="_blank"
>
<i className="fa fa-external-link" />
</a>
</span>
</div>
<br />
<div>
<p>{t('Choose a visualization type')}</p>
<VizTypeControl
name="select-vis-type"
onChange={this.changeVisType}
value={this.state.visType}
labelType="primary"
/>
</div>
<br />
<hr />
<Button
buttonStyle="primary"
disabled={this.isBtnDisabled()}
onClick={this.gotoSlice}
<StyledContainer className="container">
<h3>{t('Create a new chart')}</h3>
<div>
<p>{t('Choose a dataset')}</p>
<div style={styleSelectContainer}>
<Select
clearable={false}
ignoreAccents={false}
name="select-datasource"
onChange={this.changeDatasource}
options={this.props.datasources}
placeholder={t('Choose a dataset')}
value={
this.state.datasourceValue
? {
value: this.state.datasourceValue,
}
: undefined
}
width={600}
/>
</div>
<span className="text-muted">
{t(
'If the dataset you are looking for is not available in the list, follow the instructions on how to add it in the Superset tutorial.',
)}{' '}
<a
href="https://superset.apache.org/docs/creating-charts-dashboards/first-dashboard#adding-a-new-table"
rel="noopener noreferrer"
target="_blank"
>
{t('Create new chart')}
</Button>
<br />
<br />
</Panel.Body>
</Panel>
</div>
<i className="fa fa-external-link" />
</a>
</span>
</div>
<br />
<div>
<p>{t('Choose a visualization type')}</p>
<VizTypeControl
name="select-vis-type"
onChange={this.changeVisType}
value={this.state.visType}
labelType="primary"
/>
</div>
<br />
<hr />
<Button
buttonStyle="primary"
disabled={this.isBtnDisabled()}
onClick={this.gotoSlice}
>
{t('Create new chart')}
</Button>
<br />
<br />
</StyledContainer>
);
}
}
@@ -0,0 +1,109 @@
<!--
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.
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=q, initial-scale=1.0" />
<link
rel="icon"
type="image/png"
href="<%= require('../../../images/favicon.png')%>"
/>
<link rel="preconnect" href="https://fonts.gstatic.com" />
<link
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500&display=swap"
rel="stylesheet"
/>
<style>
html {
height: 100%;
}
body {
color: #1985a0;
font-family: 'Inter', sans-serif;
height: 100%;
margin: 0;
display: flex;
align-items: stretch;
}
h1 {
font-weight: 600;
font-size: 88px;
margin: 0;
}
p {
font-weight: 500;
font-size: 24px;
line-height: 40px;
width: 490px;
}
.button {
-webkit-appearance: button;
-moz-appearance: button;
appearance: button;
background-color: #1985a0; /* Green */
border: none;
color: white;
padding: 16px 38px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 11px;
border-radius: 4px;
text-transform: uppercase;
}
.error-page-content {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
max-width: 1350px;
margin: auto;
width: 100%;
padding: 56px;
}
img {
width: 540px;
}
</style>
<title>404: Not found | Superset</title>
</head>
<body>
<div class="error-page-content">
<section>
<h1>Page not found</h1>
<p>
Sorry, we cannot find t he page you are looking for. You may have
mistyped the address or the page may have moved.
</p>
<a href="/" class="button">Back to home</a>
</section>
<img
alt="404"
src="<%= require('../../../images/error404.png')%>"
width="540"
/>
</div>
</body>
</html>
@@ -0,0 +1,108 @@
<!--
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.
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=q, initial-scale=1.0" />
<link
rel="icon"
type="image/png"
href="<%= require('../../../images/favicon.png')%>"
/>
<link
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500&display=swap"
rel="stylesheet"
/>
<style>
html {
height: 100%;
}
body {
color: #1985a0;
font-family: 'Inter', sans-serif;
height: 100%;
margin: 0;
display: flex;
align-items: stretch;
}
h1 {
font-weight: 600;
font-size: 88px;
margin: 0;
}
p {
font-weight: 500;
font-size: 24px;
line-height: 40px;
width: 490px;
}
.button {
-webkit-appearance: button;
-moz-appearance: button;
appearance: button;
background-color: #1985a0; /* Green */
border: none;
color: white;
padding: 16px 38px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 11px;
border-radius: 4px;
text-transform: uppercase;
}
.error-page-content {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
max-width: 1350px;
margin: auto;
width: 100%;
padding: 56px;
}
img {
width: 540px;
}
</style>
<title>500: Internal server error | S uperset</title>
</head>
<body>
<div class="error-page-content">
<section>
<h1>Internal server error</h1>
<p>
Sorry, something went wrong. We are fixing the mistake now. Try again
later or go back to home.
</p>
<a href="/" class="button">Back to home</a>
</section>
<img
alt="500"
src="<%= require('../../../images/error500.png')%>"
width="540"
/>
</div>
</body>
</html>
+11
View File
@@ -49,6 +49,7 @@ const propTypes = {
timeout: PropTypes.number,
vizType: PropTypes.string.isRequired,
triggerRender: PropTypes.bool,
isFiltersInitialized: PropTypes.bool,
// state
chartAlert: PropTypes.string,
chartStatus: PropTypes.string,
@@ -62,6 +63,7 @@ const propTypes = {
onQuery: PropTypes.func,
onFilterMenuOpen: PropTypes.func,
onFilterMenuClose: PropTypes.func,
ownState: PropTypes.object,
};
const BLANK = {};
@@ -119,6 +121,13 @@ class Chart extends React.PureComponent {
}
runQuery() {
if (
this.props.dashboardId && // we on dashboard screen
isFeatureEnabled(FeatureFlag.DASHBOARD_NATIVE_FILTERS) &&
!this.props.isFiltersInitialized
) {
return;
}
if (this.props.chartId > 0 && isFeatureEnabled(FeatureFlag.CLIENT_CACHE)) {
// Load saved chart with a GET request
this.props.actions.getSavedChart(
@@ -127,6 +136,7 @@ class Chart extends React.PureComponent {
this.props.timeout,
this.props.chartId,
this.props.dashboardId,
this.props.ownState,
);
} else {
// Create chart with POST request
@@ -136,6 +146,7 @@ class Chart extends React.PureComponent {
this.props.timeout,
this.props.chartId,
this.props.dashboardId,
this.props.ownState,
);
}
}
@@ -37,4 +37,9 @@ function mapDispatchToProps(dispatch) {
};
}
export default connect(null, mapDispatchToProps)(Chart);
export default connect(
({ nativeFilters }) => ({
isFiltersInitialized: nativeFilters?.isInitialized,
}),
mapDispatchToProps,
)(Chart);
@@ -45,7 +45,7 @@ const propTypes = {
setDataMask: PropTypes.func,
onFilterMenuOpen: PropTypes.func,
onFilterMenuClose: PropTypes.func,
ownCurrentState: PropTypes.object,
ownState: PropTypes.object,
};
const BLANK = {};
@@ -94,7 +94,8 @@ class ChartRenderer extends React.Component {
return (
this.hasQueryResponseChange ||
nextProps.annotationData !== this.props.annotationData ||
nextProps.ownCurrentState !== this.props.ownCurrentState ||
nextProps.ownState !== this.props.ownState ||
nextProps.filterState !== this.props.filterState ||
nextProps.height !== this.props.height ||
nextProps.width !== this.props.width ||
nextProps.triggerRender ||
@@ -184,7 +185,8 @@ class ChartRenderer extends React.Component {
annotationData,
datasource,
initialValues,
ownCurrentState,
ownState,
filterState,
formData,
queriesResponse,
} = this.props;
@@ -224,9 +226,10 @@ class ChartRenderer extends React.Component {
datasource={datasource}
initialValues={initialValues}
formData={formData}
ownCurrentState={ownCurrentState}
ownState={ownState}
filterState={filterState}
hooks={this.hooks}
behaviors={[Behavior.CROSS_FILTER]}
behaviors={[Behavior.INTERACTIVE_CHART]}
queriesData={queriesResponse}
onRenderSuccess={this.handleRenderSuccess}
onRenderFailure={this.handleRenderFailure}
+27 -2
View File
@@ -161,6 +161,7 @@ const v1ChartDataRequest = async (
force,
requestParams,
setDataMask,
ownState,
) => {
const payload = buildV1ChartDataPayload({
formData,
@@ -168,6 +169,7 @@ const v1ChartDataRequest = async (
resultFormat,
force,
setDataMask,
ownState,
});
// The dashboard id is added to query params for tracking purposes
@@ -205,6 +207,7 @@ export async function getChartDataRequest({
force = false,
method = 'POST',
requestParams = {},
ownState = {},
}) {
let querySettings = {
...requestParams,
@@ -235,6 +238,7 @@ export async function getChartDataRequest({
force,
querySettings,
setDataMask,
ownState,
);
}
@@ -351,6 +355,7 @@ export function exploreJSON(
key,
method,
dashboardId,
ownState,
) {
return async dispatch => {
const logStart = Logger.getTimestamp();
@@ -373,6 +378,7 @@ export function exploreJSON(
force,
method,
requestParams,
ownState,
});
dispatch(chartUpdateStarted(controller, formData, key));
@@ -470,6 +476,7 @@ export function getSavedChart(
timeout = 60,
key,
dashboardId,
ownState,
) {
/*
* Perform a GET request to `/explore_json`.
@@ -481,7 +488,15 @@ export function getSavedChart(
* GET /explore_json?{"chart_id":1,"extra_filters":"..."}
*
*/
return exploreJSON(formData, force, timeout, key, 'GET', dashboardId);
return exploreJSON(
formData,
force,
timeout,
key,
'GET',
dashboardId,
ownState,
);
}
export const POST_CHART_FORM_DATA = 'POST_CHART_FORM_DATA';
@@ -491,6 +506,7 @@ export function postChartFormData(
timeout = 60,
key,
dashboardId,
ownState,
) {
/*
* Perform a POST request to `/explore_json`.
@@ -498,7 +514,15 @@ export function postChartFormData(
* This will post the form data to the endpoint, returning a new chart.
*
*/
return exploreJSON(formData, force, timeout, key, 'POST', dashboardId);
return exploreJSON(
formData,
force,
timeout,
key,
'POST',
dashboardId,
ownState,
);
}
export function redirectSQLLab(formData) {
@@ -537,6 +561,7 @@ export function refreshChart(chartKey, force, dashboardId) {
timeout,
chart.id,
dashboardId,
getState().dataMask[chart.id]?.ownState,
),
);
};

Some files were not shown because too many files have changed in this diff Show More