diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 0e506cf9fb920..f821eb35246bc 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,6 +1,6 @@ --- name: Bug report -about: Create a report to help us improve +about: Create a report to help us improve Superset's stability! For feature requests please open a discussion at https://github.com/apache/superset/discussions/categories/ideas labels: "#bug" --- diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index 8e6e0da9c9597..0000000000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -name: Feature request -about: Suggest an idea for this project -labels: "#enhancement" - ---- - -Github Discussions is our new home for discussing features and improvements! - -https://github.com/apache/superset/discussions/categories/ideas - -We'd like to keep Github Issues focuses on bugs and SIP's (Superset Improvement Proposals)! - -Please note that feature requests opened as Github Issues will be moved to Discussions. diff --git a/.github/ISSUE_TEMPLATE/sip.md b/.github/ISSUE_TEMPLATE/sip.md index e2a536b45f8f1..c2b0a14b91400 100644 --- a/.github/ISSUE_TEMPLATE/sip.md +++ b/.github/ISSUE_TEMPLATE/sip.md @@ -1,7 +1,9 @@ --- name: SIP -about: Superset Improvement Proposal [See SIP-0](https://github.com/apache/superset/issues/5602) +about: Superset Improvement Proposal (See SIP-0: https://github.com/apache/superset/issues/5602) labels: "#SIP" +title: "[SIP] Your Title Here (do not add SIP number)" +asignees: "apache/superset-committers" --- diff --git a/.github/workflows/docker_build_push.sh b/.github/workflows/docker_build_push.sh index aeac344807133..b969813627c55 100755 --- a/.github/workflows/docker_build_push.sh +++ b/.github/workflows/docker_build_push.sh @@ -50,12 +50,27 @@ docker build --target lean \ -t "${REPO_NAME}:${SHA}" \ -t "${REPO_NAME}:${REFSPEC}" \ -t "${REPO_NAME}:${LATEST_TAG}" \ + --build-arg PY_VER="3.8-slim"\ --label "sha=${SHA}" \ --label "built_at=$(date)" \ --label "target=lean" \ --label "build_actor=${GITHUB_ACTOR}" \ . +# +# Build the "lean39" image +# +docker build --target lean \ + -t "${REPO_NAME}:${SHA}-py39" \ + -t "${REPO_NAME}:${REFSPEC}-py39" \ + -t "${REPO_NAME}:${LATEST_TAG}-py39" \ + --build-arg PY_VER="3.9-slim"\ + --label "sha=${SHA}" \ + --label "built_at=$(date)" \ + --label "target=lean39" \ + --label "build_actor=${GITHUB_ACTOR}" \ + . + # # Build the "websocket" image # @@ -65,7 +80,7 @@ docker build \ -t "${REPO_NAME}:${LATEST_TAG}-websocket" \ --label "sha=${SHA}" \ --label "built_at=$(date)" \ - --label "target=lean" \ + --label "target=websocket" \ --label "build_actor=${GITHUB_ACTOR}" \ superset-websocket diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5edd7804ae39a..c8f72d2b22b6a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -126,7 +126,7 @@ Here's a list of repositories that contain Superset-related packages: ## Types of Contributions -### Report Bug +### Report a Bug The best way to report a bug is to file an issue on GitHub. Please include: @@ -138,15 +138,17 @@ The best way to report a bug is to file an issue on GitHub. Please include: When posting Python stack traces, please quote them using [Markdown blocks](https://help.github.com/articles/creating-and-highlighting-code-blocks/). +_Please note that feature requests opened as Github Issues will be moved to Discussions._ + ### Submit Ideas or Feature Requests -The best way is to file an issue on GitHub: +The best way is to start an ["Ideas" Discussion thread](https://github.com/apache/superset/discussions/categories/ideas) on GitHub: - Explain in detail how it would work. - Keep the scope as narrow as possible, to make it easier to implement. -- Remember that this is a volunteer-driven project, and that contributions are welcome :) +- Remember that this is a volunteer-driven project, and that your contributions are as welcome as anyone's :) -For large features or major changes to codebase, please create **Superset Improvement Proposal (SIP)**. See template from [SIP-0](https://github.com/apache/superset/issues/5602) +To propose large features or major changes to codebase, and help usher in those changes, please create a **Superset Improvement Proposal (SIP)**. See template from [SIP-0](https://github.com/apache/superset/issues/5602) ### Fix Bugs diff --git a/RELEASING/Dockerfile.from_local_tarball b/RELEASING/Dockerfile.from_local_tarball index ff7eb5653602d..4860db64287cc 100644 --- a/RELEASING/Dockerfile.from_local_tarball +++ b/RELEASING/Dockerfile.from_local_tarball @@ -24,7 +24,7 @@ ENV LANG=C.UTF-8 \ RUN apt-get update -y -# Install dependencies to fix `curl https support error` and `elaying package configuration warning` +# Install dependencies to fix `curl https support error` and `delaying package configuration warning` RUN apt-get install -y apt-transport-https apt-utils # Install superset dependencies diff --git a/RELEASING/Dockerfile.from_svn_tarball b/RELEASING/Dockerfile.from_svn_tarball index b88481f40d10e..3deea5b8d3541 100644 --- a/RELEASING/Dockerfile.from_svn_tarball +++ b/RELEASING/Dockerfile.from_svn_tarball @@ -24,7 +24,7 @@ ENV LANG=C.UTF-8 \ RUN apt-get update -y -# Install dependencies to fix `curl https support error` and `elaying package configuration warning` +# Install dependencies to fix `curl https support error` and `delaying package configuration warning` RUN apt-get install -y apt-transport-https apt-utils # Install superset dependencies diff --git a/docs/docs/contributing/types-of-contributions.mdx b/docs/docs/contributing/types-of-contributions.mdx index a9fa907f553de..cb6a5a5d863d0 100644 --- a/docs/docs/contributing/types-of-contributions.mdx +++ b/docs/docs/contributing/types-of-contributions.mdx @@ -19,15 +19,17 @@ The best way to report a bug is to file an issue on GitHub. Please include: When posting Python stack traces, please quote them using [Markdown blocks](https://help.github.com/articles/creating-and-highlighting-code-blocks/). +_Please note that feature requests opened as Github Issues will be moved to Discussions._ + ### Submit Ideas or Feature Requests -The best way is to file an issue on GitHub: +The best way is to start an ["Ideas" Discussion thread](https://github.com/apache/superset/discussions/categories/ideas) on GitHub: - Explain in detail how it would work. - Keep the scope as narrow as possible, to make it easier to implement. -- Remember that this is a volunteer-driven project, and that contributions are welcome :) +- Remember that this is a volunteer-driven project, and that your contributions are as welcome as anyone's :) -For large features or major changes to codebase, please create **Superset Improvement Proposal (SIP)**. See template from [SIP-0](https://github.com/apache/superset/issues/5602) +To propose large features or major changes to codebase, and help usher in those changes, please create a **Superset Improvement Proposal (SIP)**. See template from [SIP-0](https://github.com/apache/superset/issues/5602) ### Fix Bugs diff --git a/docs/docs/installation/alerts-reports.mdx b/docs/docs/installation/alerts-reports.mdx index 580fb9965a540..09f680e6e7ab9 100644 --- a/docs/docs/installation/alerts-reports.mdx +++ b/docs/docs/installation/alerts-reports.mdx @@ -7,7 +7,7 @@ version: 2 ## Alerts and Reports -(version 1.0.1 and above) +*This covers versions 1.0.1 to current.* Users can configure automated alerts and reports to send dashboards or charts to an email recipient or Slack channel. @@ -20,21 +20,28 @@ Alerts and reports are disabled by default. To turn them on, you need to do some #### Commons -##### In your `superset_config.py` +##### In your `superset_config.py` or `superset_config_docker.py` - `"ALERT_REPORTS"` [feature flag](https://superset.apache.org/docs/installation/configuring-superset#feature-flags) must be turned to True. -- `CELERYBEAT_SCHEDULE` in CeleryConfig must contain schedule for `reports.scheduler`. +- `beat_schedule` in CeleryConfig must contain schedule for `reports.scheduler`. - At least one of those must be configured, depending on what you want to use: - emails: `SMTP_*` settings - Slack messages: `SLACK_API_TOKEN` +###### Disable dry-run mode + +Screenshots will be taken but no messages actually sent as long as `ALERT_REPORTS_NOTIFICATION_DRY_RUN = True`, its default value in `config.py`. To disable dry-run mode and start receiving email/Slack notifications, set `ALERT_REPORTS_NOTIFICATION_DRY_RUN` to `False` in [superset config](https://github.com/apache/superset/blob/master/docker/pythonpath_dev/superset_config.py). + ##### In your `Dockerfile` - You must install a headless browser, for taking screenshots of the charts and dashboards. Only Firefox and Chrome are currently supported. > If you choose Chrome, you must also change the value of `WEBDRIVER_TYPE` to `"chrome"` in your `superset_config.py`. -Note : All the components required (headless browser, redis, postgres db, celery worker and celery beat) are present in the docker image if you are following [Installing Superset Locally](https://superset.apache.org/docs/installation/installing-superset-using-docker-compose/). -All you need to do is add the required config (See `Detailed Config`). Set `ALERT_REPORTS_NOTIFICATION_DRY_RUN` to `False` in [superset config](https://github.com/apache/superset/blob/master/docker/pythonpath_dev/superset_config.py) to disable dry-run mode and start receiving email/slack notifications. +Note: All the components required (Firefox headless browser, Redis, Postgres db, celery worker and celery beat) are present in the *dev* docker image if you are following [Installing Superset Locally](https://superset.apache.org/docs/installation/installing-superset-using-docker-compose/). +All you need to do is add the required config variables described in this guide (See `Detailed Config`). + +If you are running a non-dev docker image, e.g., a stable release like `apache/superset:2.0.1`, that image does not include a headless browser. Only the `superset_worker` container needs this headless browser to browse to the target chart or dashboard. +You can either install and configure the headless browser - see "Custom Dockerfile" section below - or when deploying via `docker-compose`, modify your `docker-compose.yml` file to use a dev image for the worker container and a stable release image for the `superset_app` container. #### Slack integration @@ -52,21 +59,23 @@ To send alerts and reports to Slack channels, you need to create a new Slack App 6. The app should now be installed in your workspace, and a "Bot User OAuth Access Token" should have been created. Copy that token in the `SLACK_API_TOKEN` variable of your `superset_config.py`. 7. Restart the service (or run `superset init`) to pull in the new configuration. -Note: when you configure an alert or a report, the Slack channel list take channel names without the leading '#' e.g. use `alerts` instead of `#alerts`. +Note: when you configure an alert or a report, the Slack channel list takes channel names without the leading '#' e.g. use `alerts` instead of `#alerts`. -#### Kubernetes specific +#### Kubernetes-specific - You must have a `celery beat` pod running. If you're using the chart included in the GitHub repository under [helm/superset](https://github.com/apache/superset/tree/master/helm/superset), you need to put `supersetCeleryBeat.enabled = true` in your values override. - You can see the dedicated docs about [Kubernetes installation](/docs/installation/running-on-kubernetes) for more generic details. #### Docker-compose specific -##### You must have in your`docker-compose.yaml` +##### You must have in your `docker-compose.yml` -- a redis message broker +- A Redis message broker - PostgreSQL DB instead of SQLlite -- one or more `celery worker` -- a single `celery beat` +- One or more `celery worker` +- A single `celery beat` + +This process also works in a Docker swarm environment, you would just need to add `Deploy:` to the Superset, Redis and Postgres services along with your specific configs for your swarm. ### Detailed config @@ -76,7 +85,11 @@ You can find documentation about each field in the default `config.py` in the Gi You need to replace default values with your custom Redis, Slack and/or SMTP config. -In the `CeleryConfig`, only the `CELERYBEAT_SCHEDULE` is relative to this feature, the rest of the `CeleryConfig` can be changed for your needs. +Superset uses Celery beat and Celery worker(s) to send alerts and reports. +- The beat is the scheduler that tells the worker when to perform its tasks. This schedule is defined when you create the alert or report. +- The worker will process the tasks that need to be performed when an alert or report is fired. + +In the `CeleryConfig`, only the `beat_schedule` is relevant to this feature, the rest of the `CeleryConfig` can be changed for your needs. ```python from celery.schedules import crontab @@ -124,14 +137,15 @@ SCREENSHOT_LOAD_WAIT = 600 SLACK_API_TOKEN = "xoxb-" # Email configuration -SMTP_HOST = "smtp.sendgrid.net" #change to your host +SMTP_HOST = "smtp.sendgrid.net" # change to your host +SMTP_PORT = 2525 # your port, e.g. 587 SMTP_STARTTLS = True SMTP_SSL_SERVER_AUTH = True # If your using an SMTP server with a valid certificate SMTP_SSL = False -SMTP_USER = "your_user" -SMTP_PORT = 2525 # your port eg. 587 -SMTP_PASSWORD = "your_password" +SMTP_USER = "your_user" # use the empty string "" if using an unauthenticated SMTP server +SMTP_PASSWORD = "your_password" # use the empty string "" if using an unauthenticated SMTP server SMTP_MAIL_FROM = "noreply@youremail.com" +EMAIL_REPORTS_SUBJECT_PREFIX = "[Superset] " # optional - overwrites default value in config.py of "[Report] " # WebDriver configuration # If you use Firefox, you can stick with default values @@ -149,19 +163,70 @@ WEBDRIVER_OPTION_ARGS = [ ] # This is for internal use, you can keep http -WEBDRIVER_BASEURL="http://superset:8088" -# This is the link sent to the recipient, change to your domain eg. https://superset.mydomain.com -WEBDRIVER_BASEURL_USER_FRIENDLY="http://localhost:8088" +WEBDRIVER_BASEURL = "http://superset:8088" +# This is the link sent to the recipient. Change to your domain, e.g. https://superset.mydomain.com +WEBDRIVER_BASEURL_USER_FRIENDLY = "http://localhost:8088" +``` + +You also need +to specify on behalf of which username to render the dashboards. In general dashboards and charts +are not accessible to unauthorized requests, that is why the worker needs to take over credentials +of an existing user to take a snapshot. + +By default, Alerts and Reports are executed as the user that the `THUMBNAIL_SELENIUM_USER` config +parameter is set to. To change this user, just change the config as follows: + +```python +THUMBNAIL_SELENIUM_USER = 'username_with_permission_to_access_dashboards' +``` + +In addition, it's also possible to execute the reports as the report owners/creators. This is typically +needed if there isn't a central service account that has access to all objects or databases (e.g. +when using user impersonation on database connections). For this there's the config flag +`ALERTS_REPORTS_EXECUTE_AS` which makes it possible to customize how alerts and reports are executed. +To first try to execute as the creator in the owners list (if present), then fall +back to the creator, then the last modifier in the owners list (if present), then the +last modifier, then an owner (giving priority to the last modifier and then the +creator if either is contained within the list of owners, otherwise the first owner +will be used) and finally `THUMBNAIL_SELENIUM_USER`, set as follows: + +```python +from superset.reports.types import ReportScheduleExecutor + +ALERT_REPORTS_EXECUTE_AS = [ + ReportScheduleExecutor.CREATOR_OWNER, + ReportScheduleExecutor.CREATOR, + ReportScheduleExecutor.MODIFIER_OWNER, + ReportScheduleExecutor.MODIFIER, + ReportScheduleExecutor.OWNER, + ReportScheduleExecutor.SELENIUM, +] ``` + +**Important notes** + +- Be mindful of the concurrency setting for celery (using `-c 4`). Selenium/webdriver instances can + consume a lot of CPU / memory on your servers. +- In some cases, if you notice a lot of leaked geckodriver processes, try running your celery + processes with `celery worker --pool=prefork --max-tasks-per-child=128 ...` +- It is recommended to run separate workers for the `sql_lab` and `email_reports` tasks. This can be + done using the `queue` field in `task_annotations`. +- Adjust `WEBDRIVER_BASEURL` in your configuration file if celery workers can’t access Superset via + its default value of `http://0.0.0.0:8080/`. + + ### Custom Dockerfile -A webdriver (and headless browser) is needed to capture screenshots of the charts and dashboards which are then sent to the recipient. As the base superset image does not have a webdriver installed, we need to extend it and install the webdriver. +If you're running the dev version of a released Superset image, like `apache/superset:2.0.1-dev`, you should be set with the above. + +But if you're building your own image, or starting with a non-dev version, a webdriver (and headless browser) is needed to capture screenshots of the charts and dashboards which are then sent to the recipient. +Here's how you can modify your Dockerfile to take the screenshots either with Firefox or Chrome. #### Using Firefox ```docker -FROM apache/superset:1.0.1 +FROM apache/superset:2.0.1 USER root @@ -182,7 +247,7 @@ USER superset #### Using Chrome ```docker -FROM apache/superset:1.0.1 +FROM apache/superset:2.0.1 USER root @@ -202,215 +267,7 @@ RUN pip install --no-cache gevent psycopg2 redis USER superset ``` -> Don't forget to set `WEBDRIVER_TYPE` and `WEBDRIVER_OPTION_ARGS` in your config if you use Chrome. - -### Summary of steps to turn on alerts and reporting: - -Using the templates below, - -1. Create a new directory and create the Dockerfile -2. Build the extended image using the Dockerfile -3. Create the `docker-compose.yaml` file in the same directory -4. Create a new subdirectory called `config` -5. Create the `superset_config.py` file in the `config` subdirectory -6. Run the image using `docker-compose up` in the same directory as the `docker-compose.py` file -7. In a new terminal window, upgrade the DB by running `docker exec -it superset-1.0.1-extended superset db upgrade` -8. Then run `docker exec -it superset-1.0.1-extended superset init` -9. Then setup your admin user if need be, `docker exec -it superset-1.0.1-extended superset fab create-admin` -10. Finally, restart the running instance - `CTRL-C`, then `docker-compose up` - -(note: v 1.0.1 is current at time of writing, you can change the version number to the latest version if a newer version is available) - -### Docker compose - -The docker compose file lists the services that will be used when running the image. The specific services needed for alerts and reporting are outlined below. - -#### Redis message broker - -To ferry requests between the celery worker and the Superset instance, we use a message broker. This template uses Redis. - -#### Replacing SQLite with Postgres - -While it might be possible to use SQLite for alerts and reporting, it is highly recommended using a more production ready DB for Superset in general. Our template uses Postgres. - -#### Celery worker - -The worker will process the tasks that need to be performed when an alert or report is fired. - -#### Celery beat - -The beat is the scheduler that tells the worker when to perform its tasks. This schedule is defined when you create the alert or report. - -#### Full `docker-compose.yaml` configuration - -The Redis, Postgres, Celery worker and Celery beat services are defined in the template: - -Config for `docker-compose.yaml`: - -```docker -version: '3.6' -services: - redis: - image: redis:6.0.9-buster - restart: on-failure - volumes: - - redis:/data - postgres: - image: postgres - restart: on-failure - environment: - POSTGRES_DB: superset - POSTGRES_PASSWORD: superset - POSTGRES_USER: superset - volumes: - - db:/var/lib/postgresql/data - worker: - image: superset-1.0.1-extended - restart: on-failure - healthcheck: - disable: true - depends_on: - - superset - - postgres - - redis - command: "celery --app=superset.tasks.celery_app:app worker --pool=gevent --concurrency=500" - volumes: - - ./config/:/app/pythonpath/ - beat: - image: superset-1.0.1-extended - restart: on-failure - healthcheck: - disable: true - depends_on: - - superset - - postgres - - redis - command: "celery --app=superset.tasks.celery_app:app beat --pidfile /tmp/celerybeat.pid --schedule /tmp/celerybeat-schedule" - volumes: - - ./config/:/app/pythonpath/ - superset: - image: superset-1.0.1-extended - restart: on-failure - environment: - - SUPERSET_PORT=8088 - ports: - - "8088:8088" - depends_on: - - postgres - - redis - command: gunicorn --bind 0.0.0.0:8088 --access-logfile - --error-logfile - --workers 5 --worker-class gthread --threads 4 --timeout 200 --limit-request-line 4094 --limit-request-field_size 8190 superset.app:create_app() - volumes: - - ./config/:/app/pythonpath/ -volumes: - db: - external: true - redis: - external: false -``` - -### Summary - -With the extended image created by using the `Dockerfile`, and then running that image using `docker-compose.yaml`, plus the required configurations in the `superset_config.py` you should now have alerts and reporting working correctly. - -- The above templates also work in a Docker swarm environment, you would just need to add `Deploy:` to the Superset, Redis and Postgres services along with your specific configs for your swarm - -# Old Reports feature - -## Scheduling and Emailing Reports - -(version 0.38 and below) - -### Email Reports - -Email reports allow users to schedule email reports for: - -- chart and dashboard visualization (attachment or inline) -- chart data (CSV attachment on inline table) - -Enable email reports in your `superset_config.py` file: - -```python -ENABLE_SCHEDULED_EMAIL_REPORTS = True -``` - -This flag enables some permissions that are stored in your database, so you'll want to run `superset init` again if you are running this in a dev environment. -Now you will find two new items in the navigation bar that allow you to schedule email reports: - -- **Manage > Dashboard Emails** -- **Manage > Chart Email Schedules** - -Schedules are defined in [crontab format](https://crontab.guru/) and each schedule can have a list -of recipients (all of them can receive a single mail, or separate mails). For audit purposes, all -outgoing mails can have a mandatory BCC. - -In order get picked up you need to configure a celery worker and a celery beat (see section above -“Celery Tasks”). Your celery configuration also needs an entry `email_reports.schedule_hourly` for -`CELERYBEAT_SCHEDULE`. - -To send emails you need to configure SMTP settings in your `superset_config.py` configuration file. - -```python -EMAIL_NOTIFICATIONS = True - -SMTP_HOST = "email-smtp.eu-west-1.amazonaws.com" -SMTP_STARTTLS = True -SMTP_SSL = False -SMTP_USER = "smtp_username" -SMTP_PORT = 25 -SMTP_PASSWORD = os.environ.get("SMTP_PASSWORD") -SMTP_MAIL_FROM = "insights@komoot.com" -``` - -To render dashboards you need to install a local browser on your Superset instance: - -- [geckodriver](https://github.com/mozilla/geckodriver) for Firefox -- [chromedriver](http://chromedriver.chromium.org/) for Chrome - -You'll need to adjust the `WEBDRIVER_TYPE` accordingly in your configuration. You also need -to specify on behalf of which username to render the dashboards. In general dashboards and charts -are not accessible to unauthorized requests, that is why the worker needs to take over credentials -of an existing user to take a snapshot. - -By default, Alerts and Reports are executed as the user that the `THUMBNAIL_SELENIUM_USER` config -parameter is set to. To change this user, just change the config as follows: - -```python -THUMBNAIL_SELENIUM_USER = 'username_with_permission_to_access_dashboards' -``` - -In addition, it's also possible to execute the reports as the report owners/creators. This is typically -needed if there isn't a central service account that has access to all objects or databases (e.g. -when using user impersonation on database connections). For this there's the config flag -`ALERTS_REPORTS_EXECUTE_AS` which makes it possible to customize how alerts and reports are executed. -To first try to execute as the creator in the owners list (if present), then fall -back to the creator, then the last modifier in the owners list (if present), then the -last modifier, then an owner (giving priority to the last modifier and then the -creator if either is contained within the list of owners, otherwise the first owner -will be used) and finally `THUMBNAIL_SELENIUM_USER`, set as follows: - -```python -from superset.reports.types import ReportScheduleExecutor - -ALERT_REPORTS_EXECUTE_AS = [ - ReportScheduleExecutor.CREATOR_OWNER, - ReportScheduleExecutor.CREATOR, - ReportScheduleExecutor.MODIFIER_OWNER, - ReportScheduleExecutor.MODIFIER, - ReportScheduleExecutor.OWNER, - ReportScheduleExecutor.SELENIUM, -] -``` - -**Important notes** - -- Be mindful of the concurrency setting for celery (using `-c 4`). Selenium/webdriver instances can - consume a lot of CPU / memory on your servers. -- In some cases, if you notice a lot of leaked geckodriver processes, try running your celery - processes with `celery worker --pool=prefork --max-tasks-per-child=128 ...` -- It is recommended to run separate workers for the `sql_lab` and `email_reports` tasks. This can be - done using the `queue` field in `task_annotations`. -- Adjust `WEBDRIVER_BASEURL` in your configuration file if celery workers can’t access Superset via - its default value of `http://0.0.0.0:8080/`. +Don't forget to set `WEBDRIVER_TYPE` and `WEBDRIVER_OPTION_ARGS` in your config if you use Chrome. ### Schedule Reports diff --git a/docs/docs/installation/installing-superset-using-docker-compose.mdx b/docs/docs/installation/installing-superset-using-docker-compose.mdx index 7be1156f16b0f..ae53085947a7f 100644 --- a/docs/docs/installation/installing-superset-using-docker-compose.mdx +++ b/docs/docs/installation/installing-superset-using-docker-compose.mdx @@ -84,9 +84,11 @@ and wait for the `superset_node` container to finish building the assets. #### Configuring Docker Compose -The following is for users who want to configure how Superset starts up in Docker Compose; otherwise, you can skip to the next section. +The following is for users who want to configure how Superset runs in Docker Compose; otherwise, you can skip to the next section. -You can configure the Docker Compose settings for dev and non-dev mode with `docker/.env` and `docker/.env-non-dev` respectively. These environment files set the environment for most containers in the Docker Compose setup, and some variables affect multiple containers and others only single ones. +You can install additional python packages and apply config overrides by following the steps mentioned in [docker/README.md](https://github.com/apache/superset/tree/master/docker#configuration) + +You can configure the Docker Compose environment varirables for dev and non-dev mode with `docker/.env` and `docker/.env-non-dev` respectively. These environment files set the environment for most containers in the Docker Compose setup, and some variables affect multiple containers and others only single ones. One important variable is `SUPERSET_LOAD_EXAMPLES` which determines whether the `superset_init` container will load example data and visualizations into the database and Superset. These examples are quite helpful for most people, but probably unnecessary for experienced users. The loading process can sometimes take a few minutes and a good amount of CPU, so you may want to disable it on a resource-constrained device. diff --git a/docs/static/resources/openapi.json b/docs/static/resources/openapi.json index 8279811b53dc1..86060e5470a19 100644 --- a/docs/static/resources/openapi.json +++ b/docs/static/resources/openapi.json @@ -746,7 +746,7 @@ "type": "array" }, "metrics": { - "description": "Aggregate expressions. Metrics can be passed as both references to datasource metrics (strings), or ad-hoc metricswhich are defined only within the query object. See `ChartDataAdhocMetricSchema` for the structure of ad-hoc metrics. When metrics is undefined or null, the query is executed without a groupby. However, when metrics is an array (length >= 0), a groupby clause is added to the query.", + "description": "Aggregate expressions. Metrics can be passed as both references to datasource metrics (strings), or ad-hoc metrics which are defined only within the query object. See `ChartDataAdhocMetricSchema` for the structure of ad-hoc metrics. When metrics is undefined or null, the query is executed without a groupby. However, when metrics is an array (length >= 0), a groupby clause is added to the query.", "items": {}, "nullable": true, "type": "array" @@ -1309,7 +1309,7 @@ "type": "boolean" }, "metrics": { - "description": "Aggregate expressions. Metrics can be passed as both references to datasource metrics (strings), or ad-hoc metricswhich are defined only within the query object. See `ChartDataAdhocMetricSchema` for the structure of ad-hoc metrics.", + "description": "Aggregate expressions. Metrics can be passed as both references to datasource metrics (strings), or ad-hoc metrics which are defined only within the query object. See `ChartDataAdhocMetricSchema` for the structure of ad-hoc metrics.", "items": {}, "nullable": true, "type": "array" @@ -1968,7 +1968,7 @@ "type": "string" }, "query_context_generation": { - "description": "The query context generation represents whether the query_contextis user generated or not so that it does not update user modfiedstate.", + "description": "The query context generation represents whether the query_contexts user generated or not so that it does not update user modfiedstate.", "nullable": true, "type": "boolean" }, @@ -2075,7 +2075,7 @@ "type": "string" }, "query_context_generation": { - "description": "The query context generation represents whether the query_contextis user generated or not so that it does not update user modfiedstate.", + "description": "The query context generation represents whether the query_contexts user generated or not so that it does not update user modfiedstate.", "nullable": true, "type": "boolean" }, @@ -2760,7 +2760,7 @@ "type": "string" }, "query_context_generation": { - "description": "The query context generation represents whether the query_contextis user generated or not so that it does not update user modfiedstate.", + "description": "The query context generation represents whether the query_contexts user generated or not so that it does not update user modfiedstate.", "nullable": true, "type": "boolean" }, @@ -2867,7 +2867,7 @@ "type": "string" }, "query_context_generation": { - "description": "The query context generation represents whether the query_contextis user generated or not so that it does not update user modfiedstate.", + "description": "The query context generation represents whether the query_contexts user generated or not so that it does not update user modfiedstate.", "nullable": true, "type": "boolean" }, diff --git a/docs/yarn.lock b/docs/yarn.lock index adbc78a209134..8d7fe7c4d0126 100644 --- a/docs/yarn.lock +++ b/docs/yarn.lock @@ -10907,9 +10907,9 @@ typescript@^4.3.5: integrity sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA== ua-parser-js@^0.7.30: - version "0.7.31" - resolved "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.31.tgz" - integrity sha512-qLK/Xe9E2uzmYI3qLeOmI0tEOt+TBBQyUIAh4aAgU05FVYzeZrKUdkAZfBNVGRaHVgV0TDkdEngJSw/SyQchkQ== + version "0.7.33" + resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.33.tgz#1d04acb4ccef9293df6f70f2c3d22f3030d8b532" + integrity sha512-s8ax/CeZdK9R/56Sui0WM6y9OFREJarMRHqLB2EwkovemBxNQ+Bqu8GAsUnVcXKgphb++ghr/B2BZx4mahujPw== unbox-primitive@^1.0.1: version "1.0.1" diff --git a/helm/superset/Chart.yaml b/helm/superset/Chart.yaml index 63816fbc7a2e2..2de0f2636b269 100644 --- a/helm/superset/Chart.yaml +++ b/helm/superset/Chart.yaml @@ -29,7 +29,7 @@ maintainers: - name: craig-rueda email: craig@craigrueda.com url: https://github.com/craig-rueda -version: 0.8.3 +version: 0.8.4 dependencies: - name: postgresql version: 12.1.6 diff --git a/helm/superset/README.md b/helm/superset/README.md index 52a55b472c5d0..d777b8ba45b9e 100644 --- a/helm/superset/README.md +++ b/helm/superset/README.md @@ -23,7 +23,7 @@ NOTE: This file is generated by helm-docs: https://github.com/norwoodj/helm-docs # superset -![Version: 0.8.3](https://img.shields.io/badge/Version-0.8.3-informational?style=flat-square) +![Version: 0.8.4](https://img.shields.io/badge/Version-0.8.4-informational?style=flat-square) Apache Superset is a modern, enterprise-ready business intelligence web application @@ -107,6 +107,7 @@ helm install my-superset superset/superset | service.type | string | `"ClusterIP"` | | | serviceAccount.annotations | object | `{}` | | | serviceAccount.create | bool | `false` | Create custom service account for Superset. If create: true and name is not provided, `superset.fullname` will be used. | +| supersetCeleryBeat.affinity | object | `{}` | Affinity to be added to supersetCeleryBeat deployment | | supersetCeleryBeat.command | list | a `celery beat` command | Command | | supersetCeleryBeat.containerSecurityContext | object | `{}` | | | supersetCeleryBeat.deploymentAnnotations | object | `{}` | Annotations to be added to supersetCeleryBeat deployment | @@ -117,9 +118,11 @@ helm install my-superset superset/superset | supersetCeleryBeat.podLabels | object | `{}` | Labels to be added to supersetCeleryBeat pods | | supersetCeleryBeat.podSecurityContext | object | `{}` | | | supersetCeleryBeat.resources | object | `{}` | Resource settings for the CeleryBeat pods - these settings overwrite might existing values from the global resources object defined above. | +| supersetCeleryBeat.topologySpreadConstraints | list | `[]` | TopologySpreadConstrains to be added to supersetCeleryBeat deployments | +| supersetCeleryFlower.affinity | object | `{}` | Affinity to be added to supersetCeleryFlower deployment | | supersetCeleryFlower.command | list | a `celery flower` command | Command | | supersetCeleryFlower.containerSecurityContext | object | `{}` | | -| supersetCeleryFlower.deploymentAnnotations | object | `{}` | Annotations to be added to supersetCeleryBeat deployment | +| supersetCeleryFlower.deploymentAnnotations | object | `{}` | Annotations to be added to supersetCeleryFlower deployment | | supersetCeleryFlower.enabled | bool | `false` | Enables a Celery flower deployment (management UI to monitor celery jobs) WARNING: on superset 1.x, this requires a Superset image that has `flower<1.0.0` installed (which is NOT the case of the default images) flower>=1.0.0 requires Celery 5+ which Superset 1.5 does not support | | supersetCeleryFlower.initContainers | list | a container waiting for postgres and redis | List of init containers | | supersetCeleryFlower.livenessProbe.failureThreshold | int | `3` | | @@ -129,8 +132,8 @@ helm install my-superset superset/superset | supersetCeleryFlower.livenessProbe.periodSeconds | int | `5` | | | supersetCeleryFlower.livenessProbe.successThreshold | int | `1` | | | supersetCeleryFlower.livenessProbe.timeoutSeconds | int | `1` | | -| supersetCeleryFlower.podAnnotations | object | `{}` | Annotations to be added to supersetCeleryBeat pods | -| supersetCeleryFlower.podLabels | object | `{}` | Labels to be added to supersetCeleryBeat pods | +| supersetCeleryFlower.podAnnotations | object | `{}` | Annotations to be added to supersetCeleryFlower pods | +| supersetCeleryFlower.podLabels | object | `{}` | Labels to be added to supersetCeleryFlower pods | | supersetCeleryFlower.podSecurityContext | object | `{}` | | | supersetCeleryFlower.readinessProbe.failureThreshold | int | `3` | | | supersetCeleryFlower.readinessProbe.httpGet.path | string | `"/api/workers"` | | @@ -151,6 +154,8 @@ helm install my-superset superset/superset | supersetCeleryFlower.startupProbe.periodSeconds | int | `5` | | | supersetCeleryFlower.startupProbe.successThreshold | int | `1` | | | supersetCeleryFlower.startupProbe.timeoutSeconds | int | `1` | | +| supersetCeleryFlower.topologySpreadConstraints | list | `[]` | TopologySpreadConstrains to be added to supersetCeleryFlower deployments | +| supersetNode.affinity | object | `{}` | Affinity to be added to supersetNode deployment | | supersetNode.command | list | See `values.yaml` | Startup command | | supersetNode.connections.db_host | string | `"{{ template \"superset.fullname\" . }}-postgresql"` | | | supersetNode.connections.db_name | string | `"superset"` | | @@ -192,6 +197,8 @@ helm install my-superset superset/superset | supersetNode.startupProbe.successThreshold | int | `1` | | | supersetNode.startupProbe.timeoutSeconds | int | `1` | | | supersetNode.strategy | object | `{}` | | +| supersetNode.topologySpreadConstraints | list | `[]` | TopologySpreadConstrains to be added to supersetNode deployments | +| supersetWebsockets.affinity | object | `{}` | Affinity to be added to supersetWebsockets deployment | | supersetWebsockets.command | list | `[]` | | | supersetWebsockets.config | object | see `values.yaml` | The config.json to pass to the server, see https://github.com/apache/superset/tree/master/superset-websocket Note that the configuration can also read from environment variables (which will have priority), see https://github.com/apache/superset/blob/master/superset-websocket/src/config.ts for a list of supported variables | | supersetWebsockets.containerSecurityContext | object | `{}` | | @@ -232,6 +239,7 @@ helm install my-superset superset/superset | supersetWebsockets.startupProbe.successThreshold | int | `1` | | | supersetWebsockets.startupProbe.timeoutSeconds | int | `1` | | | supersetWebsockets.strategy | object | `{}` | | +| supersetWebsockets.topologySpreadConstraints | list | `[]` | TopologySpreadConstrains to be added to supersetWebsockets deployments | | supersetWorker.command | list | a `celery worker` command | Worker startup command | | supersetWorker.containerSecurityContext | object | `{}` | | | supersetWorker.deploymentAnnotations | object | `{}` | Annotations to be added to supersetWorker deployment | @@ -253,3 +261,4 @@ helm install my-superset superset/superset | supersetWorker.startupProbe | object | `{}` | No startup/readiness probes by default since we don't really care about its startup time (it doesn't serve traffic) | | supersetWorker.strategy | object | `{}` | | | tolerations | list | `[]` | | +| topologySpreadConstraints | list | `[]` | TopologySpreadConstrains to be added to all deployments | diff --git a/helm/superset/templates/deployment-beat.yaml b/helm/superset/templates/deployment-beat.yaml index d4242425fe392..a69b2b5b4a3b9 100644 --- a/helm/superset/templates/deployment-beat.yaml +++ b/helm/superset/templates/deployment-beat.yaml @@ -122,9 +122,23 @@ spec: nodeSelector: {{- toYaml . | nindent 8 }} {{- end }} - {{- with .Values.affinity }} + {{- if or .Values.affinity .Values.supersetCeleryBeat.affinity }} affinity: - {{- toYaml . | nindent 8 }} + {{- with .Values.affinity }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.supersetCeleryBeat.affinity }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + {{- if or .Values.topologySpreadConstraints .Values.supersetCeleryBeat.topologySpreadConstraints }} + topologySpreadConstraints: + {{- with .Values.topologySpreadConstraints }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.supersetCeleryBeat.topologySpreadConstraints }} + {{- toYaml . | nindent 8 }} + {{- end }} {{- end }} {{- with .Values.tolerations }} tolerations: diff --git a/helm/superset/templates/deployment-flower.yaml b/helm/superset/templates/deployment-flower.yaml index 197aa5822fdcf..1961ee12b291a 100644 --- a/helm/superset/templates/deployment-flower.yaml +++ b/helm/superset/templates/deployment-flower.yaml @@ -121,9 +121,23 @@ spec: nodeSelector: {{- toYaml . | nindent 8 }} {{- end }} - {{- with .Values.affinity }} + {{- if or .Values.affinity .Values.supersetCeleryFlower.affinity }} affinity: - {{- toYaml . | nindent 8 }} + {{- with .Values.affinity }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.supersetCeleryFlower.affinity }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + {{- if or .Values.topologySpreadConstraints .Values.supersetCeleryFlower.topologySpreadConstraints }} + topologySpreadConstraints: + {{- with .Values.topologySpreadConstraints }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.supersetCeleryFlower.topologySpreadConstraints }} + {{- toYaml . | nindent 8 }} + {{- end }} {{- end }} {{- with .Values.tolerations }} tolerations: diff --git a/helm/superset/templates/deployment-worker.yaml b/helm/superset/templates/deployment-worker.yaml index 178b5ac26f2e0..33023c93ff4c9 100644 --- a/helm/superset/templates/deployment-worker.yaml +++ b/helm/superset/templates/deployment-worker.yaml @@ -139,9 +139,23 @@ spec: nodeSelector: {{- toYaml . | nindent 8 }} {{- end }} - {{- with .Values.affinity }} + {{- if or .Values.affinity .Values.supersetWorker.affinity }} affinity: + {{- with .Values.affinity }} {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.supersetWorker.affinity }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + {{- if or .Values.topologySpreadConstraints .Values.supersetWorker.topologySpreadConstraints }} + topologySpreadConstraints: + {{- with .Values.topologySpreadConstraints }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.supersetWorker.topologySpreadConstraints }} + {{- toYaml . | nindent 8 }} + {{- end }} {{- end }} {{- with .Values.tolerations }} tolerations: diff --git a/helm/superset/templates/deployment-ws.yaml b/helm/superset/templates/deployment-ws.yaml index 1713ee74c5337..0bbc822ef9150 100644 --- a/helm/superset/templates/deployment-ws.yaml +++ b/helm/superset/templates/deployment-ws.yaml @@ -120,9 +120,23 @@ spec: nodeSelector: {{- toYaml . | nindent 8 }} {{- end }} - {{- with .Values.affinity }} + {{- if or .Values.affinity .Values.supersetWebsockets.affinity }} affinity: + {{- with .Values.affinity }} {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.supersetWebsockets.affinity }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + {{- if or .Values.topologySpreadConstraints .Values.supersetWebsockets.topologySpreadConstraints }} + topologySpreadConstraints: + {{- with .Values.topologySpreadConstraints }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.supersetWebsockets.topologySpreadConstraints }} + {{- toYaml . | nindent 8 }} + {{- end }} {{- end }} {{- with .Values.tolerations }} tolerations: diff --git a/helm/superset/templates/deployment.yaml b/helm/superset/templates/deployment.yaml index 8869280f67b83..278326e6244c6 100644 --- a/helm/superset/templates/deployment.yaml +++ b/helm/superset/templates/deployment.yaml @@ -150,9 +150,23 @@ spec: nodeSelector: {{- toYaml . | nindent 8 }} {{- end }} - {{- with .Values.affinity }} + {{- if or .Values.affinity .Values.supersetNode.affinity }} affinity: + {{- with .Values.affinity }} {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.supersetNode.affinity }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + {{- if or .Values.topologySpreadConstraints .Values.supersetNode.topologySpreadConstraints }} + topologySpreadConstraints: + {{- with .Values.topologySpreadConstraints }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.supersetNode.topologySpreadConstraints }} + {{- toYaml . | nindent 8 }} + {{- end }} {{- end }} {{- with .Values.tolerations }} tolerations: diff --git a/helm/superset/values.yaml b/helm/superset/values.yaml index 143d6c13f18e9..ff5dd0ed0ab80 100644 --- a/helm/superset/values.yaml +++ b/helm/superset/values.yaml @@ -283,6 +283,10 @@ supersetNode: deploymentAnnotations: {} # -- Labels to be added to supersetNode deployment deploymentLabels: {} + # -- Affinity to be added to supersetNode deployment + affinity: {} + # -- TopologySpreadConstrains to be added to supersetNode deployments + topologySpreadConstraints: [] # -- Annotations to be added to supersetNode pods podAnnotations: {} # -- Labels to be added to supersetNode pods @@ -426,6 +430,10 @@ supersetCeleryBeat: - dockerize -wait "tcp://$DB_HOST:$DB_PORT" -wait "tcp://$REDIS_HOST:$REDIS_PORT" -timeout 120s # -- Annotations to be added to supersetCeleryBeat deployment deploymentAnnotations: {} + # -- Affinity to be added to supersetCeleryBeat deployment + affinity: {} + # -- TopologySpreadConstrains to be added to supersetCeleryBeat deployments + topologySpreadConstraints: [] # -- Annotations to be added to supersetCeleryBeat pods podAnnotations: {} # -- Labels to be added to supersetCeleryBeat pods @@ -498,11 +506,15 @@ supersetCeleryFlower: - /bin/sh - -c - dockerize -wait "tcp://$DB_HOST:$DB_PORT" -wait "tcp://$REDIS_HOST:$REDIS_PORT" -timeout 120s - # -- Annotations to be added to supersetCeleryBeat deployment + # -- Annotations to be added to supersetCeleryFlower deployment deploymentAnnotations: {} - # -- Annotations to be added to supersetCeleryBeat pods + # -- Affinity to be added to supersetCeleryFlower deployment + affinity: {} + # -- TopologySpreadConstrains to be added to supersetCeleryFlower deployments + topologySpreadConstraints: [] + # -- Annotations to be added to supersetCeleryFlower pods podAnnotations: {} - # -- Labels to be added to supersetCeleryBeat pods + # -- Labels to be added to supersetCeleryFlower pods podLabels: {} # -- Resource settings for the CeleryBeat pods - these settings overwrite might existing values from the global resources object defined above. resources: @@ -558,6 +570,10 @@ supersetWebsockets: command: [] resources: {} deploymentAnnotations: {} + # -- Affinity to be added to supersetWebsockets deployment + affinity: {} + # -- TopologySpreadConstrains to be added to supersetWebsockets deployments + topologySpreadConstraints: [] podAnnotations: {} podLabels: {} strategy: {} @@ -765,3 +781,6 @@ nodeSelector: {} tolerations: [] affinity: {} + +# -- TopologySpreadConstrains to be added to all deployments +topologySpreadConstraints: [] diff --git a/scripts/cancel_github_workflows.py b/scripts/cancel_github_workflows.py index 720dc05cbef22..4d30d34adf405 100755 --- a/scripts/cancel_github_workflows.py +++ b/scripts/cancel_github_workflows.py @@ -143,7 +143,7 @@ def print_commit(commit: Dict[str, Any], branch: str) -> None: "--include-last/--skip-last", default=False, show_default=True, - help="Whether to also cancel the lastest run.", + help="Whether to also cancel the latest run.", ) @click.option( "--include-running/--skip-running", diff --git a/scripts/permissions_cleanup.py b/scripts/permissions_cleanup.py index 99d192919c6c4..5ca75e394cccf 100644 --- a/scripts/permissions_cleanup.py +++ b/scripts/permissions_cleanup.py @@ -24,7 +24,7 @@ def cleanup_permissions() -> None: pvms = security_manager.get_session.query( security_manager.permissionview_model ).all() - print("# of permission view menues is: {}".format(len(pvms))) + print("# of permission view menus is: {}".format(len(pvms))) pvms_dict = defaultdict(list) for pvm in pvms: pvms_dict[(pvm.permission, pvm.view_menu)].append(pvm) @@ -43,9 +43,9 @@ def cleanup_permissions() -> None: pvms = security_manager.get_session.query( security_manager.permissionview_model ).all() - print("Stage 1: # of permission view menues is: {}".format(len(pvms))) + print("Stage 1: # of permission view menus is: {}".format(len(pvms))) - # 2. Clean up None permissions or view menues + # 2. Clean up None permissions or view menus pvms = security_manager.get_session.query( security_manager.permissionview_model ).all() @@ -57,15 +57,15 @@ def cleanup_permissions() -> None: pvms = security_manager.get_session.query( security_manager.permissionview_model ).all() - print("Stage 2: # of permission view menues is: {}".format(len(pvms))) + print("Stage 2: # of permission view menus is: {}".format(len(pvms))) - # 3. Delete empty permission view menues from roles + # 3. Delete empty permission view menus from roles roles = security_manager.get_session.query(security_manager.role_model).all() for role in roles: role.permissions = [p for p in role.permissions if p] security_manager.get_session.commit() - # 4. Delete empty roles from permission view menues + # 4. Delete empty roles from permission view menus pvms = security_manager.get_session.query( security_manager.permissionview_model ).all() diff --git a/scripts/python_tests.sh b/scripts/python_tests.sh index 6491a3f6f9d46..c3f27d17f78c4 100755 --- a/scripts/python_tests.sh +++ b/scripts/python_tests.sh @@ -19,7 +19,7 @@ set -e # Temporary fix, probably related with https://bugs.launchpad.net/ubuntu/+source/opencv/+bug/1890170 -# MySQL was failling with: +# MySQL was failing with: # from . import _mysql # ImportError: /lib/x86_64-linux-gnu/libstdc++.so.6: cannot allocate memory in static TLS block export LD_PRELOAD=/lib/x86_64-linux-gnu/libstdc++.so.6 diff --git a/scripts/tests/run.sh b/scripts/tests/run.sh index 24233010107dd..2c3b5bf359733 100755 --- a/scripts/tests/run.sh +++ b/scripts/tests/run.sh @@ -24,7 +24,7 @@ set -e # function reset_db() { echo -------------------- - echo Reseting test DB + echo Resetting test DB echo -------------------- docker-compose stop superset-tests-worker superset || true RESET_DB_CMD="psql \"postgresql://${DB_USER}:${DB_PASSWORD}@127.0.0.1:5432\" <<-EOF diff --git a/setup.cfg b/setup.cfg index c4cd568c51160..a9470d51bd8b0 100644 --- a/setup.cfg +++ b/setup.cfg @@ -17,9 +17,9 @@ [metadata] name = Superset summary = a data exploration platform -description-file = README.md +description_file = README.md author = Apache Superset Dev -author-email = dev@superset.apache.org +author_email = dev@superset.apache.org license = Apache License, Version 2.0 [files] diff --git a/superset-frontend/.storybook/preview.jsx b/superset-frontend/.storybook/preview.jsx index a83b6e102e500..967e96a40ddc3 100644 --- a/superset-frontend/.storybook/preview.jsx +++ b/superset-frontend/.storybook/preview.jsx @@ -87,5 +87,5 @@ addParameters({ ], }, }, - controls: { expanded: true }, + controls: { expanded: true, sort: 'alpha' }, }); diff --git a/superset-frontend/cypress-base/cypress/integration/alerts_and_reports/alerts.test.ts b/superset-frontend/cypress-base/cypress/integration/alerts_and_reports/alerts.test.ts index 03af055a27ace..a695541ceecd9 100644 --- a/superset-frontend/cypress-base/cypress/integration/alerts_and_reports/alerts.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/alerts_and_reports/alerts.test.ts @@ -23,10 +23,6 @@ describe('Alert list view', () => { cy.visit(ALERT_LIST); }); - beforeEach(() => { - cy.preserveLogin(); - }); - it('should load alert lists', () => { cy.getBySel('listview-table').should('be.visible'); cy.getBySel('sort-header').eq(1).contains('Last run'); diff --git a/superset-frontend/cypress-base/cypress/integration/alerts_and_reports/reports.test.ts b/superset-frontend/cypress-base/cypress/integration/alerts_and_reports/reports.test.ts index 12fe43a165a4d..e267d76f6f7ed 100644 --- a/superset-frontend/cypress-base/cypress/integration/alerts_and_reports/reports.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/alerts_and_reports/reports.test.ts @@ -23,10 +23,6 @@ describe('Report list view', () => { cy.visit(REPORT_LIST); }); - beforeEach(() => { - cy.preserveLogin(); - }); - it('should load report lists', () => { cy.getBySel('listview-table').should('be.visible'); cy.getBySel('sort-header').eq(1).contains('Last run'); diff --git a/superset-frontend/cypress-base/cypress/integration/chart_list/chartlist.applitools.test.ts b/superset-frontend/cypress-base/cypress/integration/chart_list/chartlist.applitools.test.ts index 60bf87ed1d349..92ad94bb7da69 100644 --- a/superset-frontend/cypress-base/cypress/integration/chart_list/chartlist.applitools.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/chart_list/chartlist.applitools.test.ts @@ -20,7 +20,6 @@ import { CHART_LIST } from 'cypress/utils/urls'; describe('charts list view', () => { beforeEach(() => { - cy.login(); cy.visit(CHART_LIST); }); diff --git a/superset-frontend/cypress-base/cypress/integration/chart_list/filter.test.ts b/superset-frontend/cypress-base/cypress/integration/chart_list/filter.test.ts index 1b225ec4b07d1..acd11669bea18 100644 --- a/superset-frontend/cypress-base/cypress/integration/chart_list/filter.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/chart_list/filter.test.ts @@ -23,92 +23,35 @@ import { setFilter } from '../explore/utils'; describe('Charts filters', () => { before(() => { cy.visit(CHART_LIST); + setGridMode('card'); }); beforeEach(() => { - cy.preserveLogin(); clearAllInputs(); }); - describe('card-view', () => { - before(() => { - setGridMode('card'); - }); - - xit('should filter by owners correctly', () => { - setFilter('Owner', 'alpha user'); - cy.getBySel('styled-card').should('not.exist'); - setFilter('Owner', 'admin user'); - cy.getBySel('styled-card').should('exist'); - }); - - xit('should filter by created by correctly', () => { - setFilter('Created by', 'alpha user'); - cy.getBySel('styled-card').should('not.exist'); - setFilter('Created by', 'admin user'); - cy.getBySel('styled-card').should('exist'); - }); - - it('should filter by viz type correctly', () => { - setFilter('Chart type', 'Area Chart (legacy)'); - cy.getBySel('styled-card').should('have.length', 3); - setFilter('Chart type', 'Bubble Chart'); - cy.getBySel('styled-card').should('have.length', 2); - }); - - it('should filter by datasource correctly', () => { - setFilter('Dataset', 'energy_usage'); - cy.getBySel('styled-card').should('have.length', 3); - setFilter('Dataset', 'unicode_test'); - cy.getBySel('styled-card').should('have.length', 1); - }); - - it('should filter by dashboards correctly', () => { - setFilter('Dashboards', 'Unicode Test'); - cy.getBySel('styled-card').should('have.length', 1); - setFilter('Dashboards', 'Tabbed Dashboard'); - cy.getBySel('styled-card').should('have.length', 9); - }); + it('should allow filtering by "Owner"', () => { + setFilter('Owner', 'alpha user'); + setFilter('Owner', 'admin user'); }); - describe('list-view', () => { - before(() => { - setGridMode('list'); - }); - - xit('should filter by owners correctly', () => { - setFilter('Owner', 'alpha user'); - cy.getBySel('table-row').should('not.exist'); - setFilter('Owner', 'admin user'); - cy.getBySel('table-row').should('exist'); - }); - - xit('should filter by created by correctly', () => { - setFilter('Created by', 'alpha user'); - cy.getBySel('table-row').should('not.exist'); - setFilter('Created by', 'admin user'); - cy.getBySel('table-row').should('exist'); - }); + it('should allow filtering by "Created by" correctly', () => { + setFilter('Created by', 'alpha user'); + setFilter('Created by', 'admin user'); + }); - it('should filter by viz type correctly', () => { - setFilter('Chart type', 'Area Chart (legacy)'); - cy.getBySel('table-row').should('have.length', 3); - setFilter('Chart type', 'Bubble Chart'); - cy.getBySel('table-row').should('have.length', 2); - }); + it('should allow filtering by "Chart type" correctly', () => { + setFilter('Chart type', 'Area Chart (legacy)'); + setFilter('Chart type', 'Bubble Chart'); + }); - it('should filter by datasource correctly', () => { - setFilter('Dataset', 'energy_usage'); - cy.getBySel('table-row').should('have.length', 3); - setFilter('Dataset', 'unicode_test'); - cy.getBySel('table-row').should('have.length', 1); - }); + it('should allow filtering by "Dataset" correctly', () => { + setFilter('Dataset', 'energy_usage'); + setFilter('Dataset', 'unicode_test'); + }); - it('should filter by dashboards correctly', () => { - setFilter('Dashboards', 'Unicode Test'); - cy.getBySel('table-row').should('have.length', 1); - setFilter('Dashboards', 'Tabbed Dashboard'); - cy.getBySel('table-row').should('have.length', 9); - }); + it('should allow filtering by "Dashboards" correctly', () => { + setFilter('Dashboards', 'Unicode Test'); + setFilter('Dashboards', 'Tabbed Dashboard'); }); }); diff --git a/superset-frontend/cypress-base/cypress/integration/chart_list/list.test.ts b/superset-frontend/cypress-base/cypress/integration/chart_list/list.test.ts index 29b3d16b1482f..460b2cc02b468 100644 --- a/superset-frontend/cypress-base/cypress/integration/chart_list/list.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/chart_list/list.test.ts @@ -54,10 +54,6 @@ function visitChartList() { } describe('Charts list', () => { - beforeEach(() => { - cy.preserveLogin(); - }); - describe.skip('Cross-referenced dashboards', () => { beforeEach(() => { cy.createSampleDashboards([0, 1, 2, 3]); diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/_skip.controls.test.ts b/superset-frontend/cypress-base/cypress/integration/dashboard/_skip.controls.test.ts index 085ebb15876f9..4a65d68cf5883 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard/_skip.controls.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/dashboard/_skip.controls.test.ts @@ -27,7 +27,6 @@ import { isLegacyResponse } from '../../utils/vizPlugins'; describe.skip('Dashboard top-level controls', () => { beforeEach(() => { - cy.login(); cy.visit(WORLD_HEALTH_DASHBOARD); }); diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/_skip.filter.test.ts b/superset-frontend/cypress-base/cypress/integration/dashboard/_skip.filter.test.ts index f5b617393a3c7..6ae5d1e5d6fe9 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard/_skip.filter.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/dashboard/_skip.filter.test.ts @@ -27,7 +27,6 @@ import { WORLD_HEALTH_CHARTS } from './utils'; describe.skip('Dashboard filter', () => { before(() => { - cy.login(); cy.visit(WORLD_HEALTH_DASHBOARD); }); diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/_skip.key_value.test.ts b/superset-frontend/cypress-base/cypress/integration/dashboard/_skip.key_value.test.ts index 52bc4cd60b321..2fc640e86165b 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard/_skip.key_value.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/dashboard/_skip.key_value.test.ts @@ -27,9 +27,6 @@ interface QueryString { describe.skip('nativefilter url param key', () => { // const urlParams = { param1: '123', param2: 'abc' }; - before(() => { - cy.login(); - }); let initialFilterKey: string; it('should have cachekey in nativefilter param', () => { diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/_skip.url_params.test.ts b/superset-frontend/cypress-base/cypress/integration/dashboard/_skip.url_params.test.ts index a072cf1207db2..686c9e7536c99 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard/_skip.url_params.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/dashboard/_skip.url_params.test.ts @@ -23,8 +23,6 @@ import { WORLD_HEALTH_CHARTS } from './utils'; describe.skip('Dashboard form data', () => { const urlParams = { param1: '123', param2: 'abc' }; before(() => { - cy.login(); - cy.visit(WORLD_HEALTH_DASHBOARD, { qs: urlParams }); }); diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/dashboard.applitools.test.ts b/superset-frontend/cypress-base/cypress/integration/dashboard/dashboard.applitools.test.ts index 3269334e8c406..297702bce2507 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard/dashboard.applitools.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/dashboard/dashboard.applitools.test.ts @@ -22,7 +22,6 @@ import { WORLD_HEALTH_CHARTS } from './utils'; describe('Dashboard load', () => { beforeEach(() => { - cy.login(); cy.visit(WORLD_HEALTH_DASHBOARD); WORLD_HEALTH_CHARTS.forEach(waitForChartLoad); }); diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/drilltodetail.test.ts b/superset-frontend/cypress-base/cypress/integration/dashboard/drilltodetail.test.ts index 91485ce19bcfb..2ab4966d57d08 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard/drilltodetail.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/dashboard/drilltodetail.test.ts @@ -133,7 +133,6 @@ function testTimeChart(vizType: string) { describe('Drill to detail modal', () => { beforeEach(() => { - cy.preserveLogin(); closeModal(); }); diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/editmode.test.ts b/superset-frontend/cypress-base/cypress/integration/dashboard/editmode.test.ts index 34e6d2dc10b37..4251b6a7ae502 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard/editmode.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/dashboard/editmode.test.ts @@ -182,10 +182,6 @@ function openExplore(chartName: string) { } describe('Dashboard edit', () => { - beforeEach(() => { - cy.preserveLogin(); - }); - describe('Color consistency', () => { beforeEach(() => { visitResetTabbedDashboard(); diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/load.test.ts b/superset-frontend/cypress-base/cypress/integration/dashboard/load.test.ts index cd8ab210c622e..487b2c7f0e17a 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard/load.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/dashboard/load.test.ts @@ -21,14 +21,6 @@ import { waitForChartLoad } from 'cypress/utils'; import { WORLD_HEALTH_CHARTS, interceptLog } from './utils'; describe('Dashboard load', () => { - before(() => { - cy.login(); - }); - - beforeEach(() => { - cy.preserveLogin(); - }); - it('should load dashboard', () => { cy.visit(WORLD_HEALTH_DASHBOARD); WORLD_HEALTH_CHARTS.forEach(waitForChartLoad); diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/nativeFilters.test.ts b/superset-frontend/cypress-base/cypress/integration/dashboard/nativeFilters.test.ts index ff6939e9afd85..b378388da3143 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard/nativeFilters.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/dashboard/nativeFilters.test.ts @@ -128,6 +128,7 @@ function prepareDashboardFilters( label_colors: {}, shared_label_colors: {}, color_scheme_domain: [], + cross_filters_enabled: false, positions: { DASHBOARD_VERSION_KEY: 'v2', ROOT_ID: { type: 'ROOT', id: 'ROOT_ID', children: ['GRID_ID'] }, @@ -203,9 +204,10 @@ function openVerticalFilterBar() { function setFilterBarOrientation(orientation: 'vertical' | 'horizontal') { cy.getBySel('filterbar-orientation-icon').click(); cy.wait(250); - cy.getBySel('dropdown-selectable-info') + cy.getBySel('dropdown-selectable-icon-submenu') .contains('Orientation of filter bar') - .should('exist'); + .should('exist') + .trigger('mouseover'); if (orientation === 'vertical') { cy.get('.ant-dropdown-menu-item-selected') @@ -234,14 +236,6 @@ function openMoreFilters(intercetFilterState = true) { } describe('Horizontal FilterBar', () => { - before(() => { - cy.login(); - }); - - beforeEach(() => { - cy.preserveLogin(); - }); - it('should go from vertical to horizontal and the opposite', () => { visitDashboard(); openVerticalFilterBar(); @@ -412,10 +406,6 @@ describe('Horizontal FilterBar', () => { }); describe('Native filters', () => { - beforeEach(() => { - cy.preserveLogin(); - }); - describe('Nativefilters tests initial state required', () => { beforeEach(() => { cy.createSampleDashboards([0]); diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/tabs.test.ts b/superset-frontend/cypress-base/cypress/integration/dashboard/tabs.test.ts index 323a8e7f4da7d..ac076a2200f26 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard/tabs.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/dashboard/tabs.test.ts @@ -53,7 +53,6 @@ describe('Dashboard tabs', () => { }); beforeEach(() => { - cy.preserveLogin(); resetTabs(); }); diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard_list/dashboardlist.applitools.test.ts b/superset-frontend/cypress-base/cypress/integration/dashboard_list/dashboardlist.applitools.test.ts index 5f457ff49ae42..4e9c84d6ea028 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard_list/dashboardlist.applitools.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/dashboard_list/dashboardlist.applitools.test.ts @@ -20,7 +20,6 @@ import { DASHBOARD_LIST } from 'cypress/utils/urls'; describe('dashboard list view', () => { beforeEach(() => { - cy.login(); cy.visit(DASHBOARD_LIST); }); diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard_list/filter.test.ts b/superset-frontend/cypress-base/cypress/integration/dashboard_list/filter.test.ts index 47e14755cb1b4..4654b3b5c2634 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard_list/filter.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/dashboard_list/filter.test.ts @@ -23,64 +23,25 @@ import { setFilter } from '../dashboard/utils'; describe('Dashboards filters', () => { before(() => { cy.visit(DASHBOARD_LIST); + setGridMode('card'); }); beforeEach(() => { - cy.preserveLogin(); clearAllInputs(); }); - describe('card-view', () => { - before(() => { - setGridMode('card'); - }); - - xit('should filter by owners correctly', () => { - setFilter('Owner', 'alpha user'); - cy.getBySel('styled-card').should('not.exist'); - setFilter('Owner', 'admin user'); - cy.getBySel('styled-card').should('exist'); - }); - - xit('should filter by created by correctly', () => { - setFilter('Created by', 'alpha user'); - cy.getBySel('styled-card').should('not.exist'); - setFilter('Created by', 'admin user'); - cy.getBySel('styled-card').should('exist'); - }); - - it('should filter by published correctly', () => { - setFilter('Status', 'Published'); - cy.getBySel('styled-card').should('have.length', 3); - setFilter('Status', 'Draft'); - cy.getBySel('styled-card').should('have.length', 2); - }); + it('should allow filtering by "Owner" correctly', () => { + setFilter('Owner', 'alpha user'); + setFilter('Owner', 'admin user'); }); - describe('list-view', () => { - before(() => { - setGridMode('list'); - }); - - xit('should filter by owners correctly', () => { - setFilter('Owner', 'alpha user'); - cy.getBySel('table-row').should('not.exist'); - setFilter('Owner', 'admin user'); - cy.getBySel('table-row').should('exist'); - }); - - xit('should filter by created by correctly', () => { - setFilter('Created by', 'alpha user'); - cy.getBySel('table-row').should('not.exist'); - setFilter('Created by', 'admin user'); - cy.getBySel('table-row').should('exist'); - }); + it('should allow filtering by "Created by" correctly', () => { + setFilter('Created by', 'alpha user'); + setFilter('Created by', 'admin user'); + }); - it('should filter by published correctly', () => { - setFilter('Status', 'Published'); - cy.getBySel('table-row').should('have.length', 3); - setFilter('Status', 'Draft'); - cy.getBySel('table-row').should('have.length', 2); - }); + it('should allow filtering by "Status" correctly', () => { + setFilter('Status', 'Published'); + setFilter('Status', 'Draft'); }); }); diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard_list/list.test.ts b/superset-frontend/cypress-base/cypress/integration/dashboard_list/list.test.ts index aeee9ba4997b1..9bc6eed224578 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard_list/list.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/dashboard_list/list.test.ts @@ -46,10 +46,6 @@ function confirmDelete() { } describe('Dashboards list', () => { - beforeEach(() => { - cy.preserveLogin(); - }); - describe('list mode', () => { before(() => { cy.visit(DASHBOARD_LIST); diff --git a/superset-frontend/cypress-base/cypress/integration/database/modal.test.ts b/superset-frontend/cypress-base/cypress/integration/database/modal.test.ts index c94adcc2bd74a..a3260250aa47f 100644 --- a/superset-frontend/cypress-base/cypress/integration/database/modal.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/database/modal.test.ts @@ -32,7 +32,6 @@ describe('Add database', () => { }); beforeEach(() => { - cy.preserveLogin(); closeModal(); cy.getBySel('btn-create-database').click(); }); diff --git a/superset-frontend/cypress-base/cypress/integration/dataset/dataset_list.test.ts b/superset-frontend/cypress-base/cypress/integration/dataset/dataset_list.test.ts index 9e55d01c3c3f5..e78c328ec5104 100644 --- a/superset-frontend/cypress-base/cypress/integration/dataset/dataset_list.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/dataset/dataset_list.test.ts @@ -24,10 +24,6 @@ describe('Dataset list', () => { cy.visit(DATASET_LIST_PATH); }); - beforeEach(() => { - cy.preserveLogin(); - }); - it('should open Explore on dataset name click', () => { cy.intercept('**/api/v1/explore/**').as('explore'); cy.get('[data-test="listview-table"] [data-test="internal-link"]') diff --git a/superset-frontend/cypress-base/cypress/integration/explore/AdhocMetrics.test.ts b/superset-frontend/cypress-base/cypress/integration/explore/AdhocMetrics.test.ts index deb829a092dca..e97ac74c3f2a2 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/AdhocMetrics.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/explore/AdhocMetrics.test.ts @@ -18,7 +18,6 @@ */ describe('AdhocMetrics', () => { beforeEach(() => { - cy.login(); cy.intercept('POST', '/superset/explore_json/**').as('postJson'); cy.intercept('GET', '/superset/explore_json/**').as('getJson'); cy.visitChartByName('Num Births Trend'); diff --git a/superset-frontend/cypress-base/cypress/integration/explore/_skip.AdhocFilters.test.ts b/superset-frontend/cypress-base/cypress/integration/explore/_skip.AdhocFilters.test.ts index 1dca8f6e10460..8eb12a95b14f7 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/_skip.AdhocFilters.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/explore/_skip.AdhocFilters.test.ts @@ -18,7 +18,6 @@ */ describe.skip('AdhocFilters', () => { beforeEach(() => { - cy.login(); cy.intercept('GET', '/superset/filter/table/*/name').as('filterValues'); cy.intercept('POST', '/superset/explore_json/**').as('postJson'); cy.intercept('GET', '/superset/explore_json/**').as('getJson'); diff --git a/superset-frontend/cypress-base/cypress/integration/explore/advanced_analytics.test.ts b/superset-frontend/cypress-base/cypress/integration/explore/advanced_analytics.test.ts index f38fdbd3a92d1..fd207a64e3124 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/advanced_analytics.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/explore/advanced_analytics.test.ts @@ -18,7 +18,6 @@ */ describe('Advanced analytics', () => { beforeEach(() => { - cy.login(); cy.intercept('POST', '/superset/explore_json/**').as('postJson'); cy.intercept('GET', '/superset/explore_json/**').as('getJson'); cy.intercept('PUT', '/api/v1/explore/**').as('putExplore'); diff --git a/superset-frontend/cypress-base/cypress/integration/explore/annotations.test.ts b/superset-frontend/cypress-base/cypress/integration/explore/annotations.test.ts index 448a676f67307..a10295af964fe 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/annotations.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/explore/annotations.test.ts @@ -18,7 +18,6 @@ */ describe('Annotations', () => { beforeEach(() => { - cy.login(); cy.intercept('POST', '/superset/explore_json/**').as('postJson'); cy.intercept('GET', '/superset/explore_json/**').as('getJson'); }); diff --git a/superset-frontend/cypress-base/cypress/integration/explore/chart.test.js b/superset-frontend/cypress-base/cypress/integration/explore/chart.test.js index 7c8cb855c78b7..cade5fab24ad3 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/chart.test.js +++ b/superset-frontend/cypress-base/cypress/integration/explore/chart.test.js @@ -92,7 +92,6 @@ describe('Cross-referenced dashboards', () => { beforeEach(() => { interceptFiltering(); - cy.preserveLogin(); cy.createSampleDashboards(SAMPLE_DASHBOARDS_INDEXES); cy.createSampleCharts([0]); cy.visit(CHART_LIST); @@ -125,7 +124,6 @@ describe('Cross-referenced dashboards', () => { describe('No Results', () => { beforeEach(() => { - cy.login(); cy.intercept('POST', '/superset/explore_json/**').as('getJson'); }); diff --git a/superset-frontend/cypress-base/cypress/integration/explore/control.test.ts b/superset-frontend/cypress-base/cypress/integration/explore/control.test.ts index f447780e2b2b6..faee1f6f4ee41 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/control.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/explore/control.test.ts @@ -23,10 +23,6 @@ import { interceptChart } from 'cypress/utils'; import { FORM_DATA_DEFAULTS, NUM_METRIC } from './visualizations/shared.helper'; describe('Datasource control', () => { - beforeEach(() => { - cy.preserveLogin(); - }); - const newMetricName = `abc${Date.now()}`; it('should allow edit dataset', () => { @@ -89,7 +85,6 @@ describe('Datasource control', () => { describe('Color scheme control', () => { beforeEach(() => { - cy.login(); interceptChart({ legacy: true }).as('chartData'); cy.visitChartByName('Num Births Trend'); @@ -120,7 +115,6 @@ describe('Color scheme control', () => { }); describe('VizType control', () => { beforeEach(() => { - cy.login(); interceptChart({ legacy: false }).as('tableChartData'); interceptChart({ legacy: true }).as('lineChartData'); }); @@ -147,7 +141,6 @@ describe('VizType control', () => { describe('Test datatable', () => { beforeEach(() => { - cy.login(); interceptChart({ legacy: false }).as('tableChartData'); interceptChart({ legacy: true }).as('lineChartData'); cy.visitChartByName('Daily Totals'); @@ -174,7 +167,6 @@ describe('Test datatable', () => { describe('Time range filter', () => { beforeEach(() => { - cy.login(); interceptChart({ legacy: true }).as('chartData'); }); @@ -288,7 +280,6 @@ describe('Time range filter', () => { describe('Groupby control', () => { it('Set groupby', () => { - cy.login(); interceptChart({ legacy: true }).as('chartData'); cy.visitChartByName('Num Births Trend'); diff --git a/superset-frontend/cypress-base/cypress/integration/explore/explore.applitools.test.ts b/superset-frontend/cypress-base/cypress/integration/explore/explore.applitools.test.ts index 64d77b4d6854a..4e951c2560e15 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/explore.applitools.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/explore/explore.applitools.test.ts @@ -20,7 +20,6 @@ import { FORM_DATA_DEFAULTS, NUM_METRIC } from './visualizations/shared.helper'; describe('explore view', () => { beforeEach(() => { - cy.login(); cy.intercept('POST', '/superset/explore_json/**').as('getJson'); }); diff --git a/superset-frontend/cypress-base/cypress/integration/explore/filter_box.test.js b/superset-frontend/cypress-base/cypress/integration/explore/filter_box.test.js index b9844274e2d04..a4ca5ddcf2ef9 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/filter_box.test.js +++ b/superset-frontend/cypress-base/cypress/integration/explore/filter_box.test.js @@ -27,7 +27,6 @@ describe('Edit FilterBox Chart', () => { } beforeEach(() => { - cy.login(); cy.intercept('POST', '/superset/explore_json/**').as('getJson'); }); diff --git a/superset-frontend/cypress-base/cypress/integration/explore/link.test.ts b/superset-frontend/cypress-base/cypress/integration/explore/link.test.ts index 7a31d7cbb81f1..1e13c7d7ed3fb 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/link.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/explore/link.test.ts @@ -30,7 +30,6 @@ const apiURL = (endpoint: string, queryObject: Record) => describe('Test explore links', () => { beforeEach(() => { - cy.login(); interceptChart({ legacy: true }).as('chartData'); }); diff --git a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/area.test.js b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/area.test.js index a8af76a651b23..c95127dd1ebd5 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/area.test.js +++ b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/area.test.js @@ -18,7 +18,6 @@ */ describe('Visualization > Area', () => { beforeEach(() => { - cy.preserveLogin(); cy.intercept('POST', '/superset/explore_json/**').as('getJson'); }); diff --git a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/big_number.test.js b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/big_number.test.js index 5701ed81044ce..2882f6ab4af28 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/big_number.test.js +++ b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/big_number.test.js @@ -20,7 +20,6 @@ import { interceptChart } from 'cypress/utils'; describe('Visualization > Big Number with Trendline', () => { beforeEach(() => { - cy.preserveLogin(); interceptChart({ legacy: false }).as('chartData'); }); diff --git a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/big_number_total.test.js b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/big_number_total.test.js index 8ef01b7a4e679..d53436acd0317 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/big_number_total.test.js +++ b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/big_number_total.test.js @@ -21,7 +21,6 @@ import { FORM_DATA_DEFAULTS, NUM_METRIC } from './shared.helper'; describe('Visualization > Big Number Total', () => { beforeEach(() => { - cy.preserveLogin(); interceptChart({ legacy: false }).as('chartData'); }); diff --git a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/box_plot.test.js b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/box_plot.test.js index d88ef7562726a..323dc5c24e410 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/box_plot.test.js +++ b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/box_plot.test.js @@ -18,7 +18,6 @@ */ describe('Visualization > Box Plot', () => { beforeEach(() => { - cy.preserveLogin(); cy.intercept('POST', '/api/v1/chart/data*').as('getJson'); }); diff --git a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/bubble.test.js b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/bubble.test.js index 9a0e4ca2b9ef2..f3a0dcd2d4eec 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/bubble.test.js +++ b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/bubble.test.js @@ -18,7 +18,6 @@ */ describe('Visualization > Bubble', () => { beforeEach(() => { - cy.preserveLogin(); cy.intercept('POST', '/superset/explore_json/**').as('getJson'); }); diff --git a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/compare.test.js b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/compare.test.js index d319944b31744..136e48d5adec2 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/compare.test.js +++ b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/compare.test.js @@ -18,7 +18,6 @@ */ describe('Visualization > Compare', () => { beforeEach(() => { - cy.preserveLogin(); cy.intercept('POST', '/superset/explore_json/**').as('getJson'); }); diff --git a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/dist_bar.test.js b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/dist_bar.test.js index 0a81ab78f7aee..770e1e1c04d38 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/dist_bar.test.js +++ b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/dist_bar.test.js @@ -20,7 +20,6 @@ import { FORM_DATA_DEFAULTS, NUM_METRIC } from './shared.helper'; describe('Visualization > Distribution bar chart', () => { beforeEach(() => { - cy.preserveLogin(); cy.intercept('POST', '/superset/explore_json/**').as('getJson'); }); diff --git a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/download_chart.test.js b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/download_chart.test.js index 6f0643cc8fc43..668e9c789f617 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/download_chart.test.js +++ b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/download_chart.test.js @@ -22,7 +22,6 @@ describe('Download Chart > Distribution bar chart', () => { const VIZ_DEFAULTS = { ...FORM_DATA_DEFAULTS, viz_type: 'dist_bar' }; beforeEach(() => { - cy.login(); cy.intercept('POST', '/superset/explore_json/**').as('getJson'); }); diff --git a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/dual_line.test.js b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/dual_line.test.js index be9b26739b146..d31196b9564b7 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/dual_line.test.js +++ b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/dual_line.test.js @@ -18,7 +18,6 @@ */ describe('Visualization > Dual Line', () => { beforeEach(() => { - cy.preserveLogin(); cy.intercept('POST', '/superset/explore_json/**').as('getJson'); }); diff --git a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/gauge.test.js b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/gauge.test.js index 023b3aeaa4249..e704705c6a572 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/gauge.test.js +++ b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/gauge.test.js @@ -19,7 +19,6 @@ describe('Visualization > Gauge', () => { beforeEach(() => { - cy.preserveLogin(); cy.intercept('POST', '/api/v1/chart/data*').as('getJson'); }); diff --git a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/graph.test.ts b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/graph.test.ts index 76883ca87695a..ff8eaa629ff48 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/graph.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/graph.test.ts @@ -28,7 +28,6 @@ type adhocFilter = { describe('Visualization > Graph', () => { beforeEach(() => { - cy.preserveLogin(); cy.intercept('POST', '/api/v1/chart/data*').as('getJson'); }); diff --git a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/histogram.test.ts b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/histogram.test.ts index 5a8576df2e6f8..ba197cf4cd543 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/histogram.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/histogram.test.ts @@ -20,7 +20,6 @@ import { QueryFormData } from '@superset-ui/core'; describe('Visualization > Histogram', () => { beforeEach(() => { - cy.preserveLogin(); cy.intercept('POST', '/superset/explore_json/**').as('getJson'); }); diff --git a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/line.test.ts b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/line.test.ts index 7f55529a68ea1..5cc398c7f3ef7 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/line.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/line.test.ts @@ -20,7 +20,6 @@ import { FORM_DATA_DEFAULTS, NUM_METRIC, SIMPLE_FILTER } from './shared.helper'; describe('Visualization > Line', () => { beforeEach(() => { - cy.preserveLogin(); cy.intercept('POST', '/superset/explore_json/**').as('getJson'); }); diff --git a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/pie.test.js b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/pie.test.js index 77f502e172088..f853cf12848a8 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/pie.test.js +++ b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/pie.test.js @@ -18,7 +18,6 @@ */ describe('Visualization > Pie', () => { beforeEach(() => { - cy.preserveLogin(); cy.intercept('POST', '/api/v1/chart/data*').as('getJson'); }); diff --git a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/pivot_table.test.js b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/pivot_table.test.js index dbf74472acddb..dfef462fc9e61 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/pivot_table.test.js +++ b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/pivot_table.test.js @@ -18,7 +18,6 @@ */ describe('Visualization > Pivot Table', () => { beforeEach(() => { - cy.preserveLogin(); cy.intercept('POST', '/superset/explore_json/**').as('getJson'); }); diff --git a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/sankey.test.js b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/sankey.test.js index b0da5cd808a7b..e5139bee1c01b 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/sankey.test.js +++ b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/sankey.test.js @@ -18,7 +18,6 @@ */ describe('Visualization > Sankey', () => { beforeEach(() => { - cy.preserveLogin(); cy.intercept('POST', '/superset/explore_json/**').as('getJson'); }); diff --git a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/sunburst.test.js b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/sunburst.test.js index a3e556d5909f8..03090db9c4ed8 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/sunburst.test.js +++ b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/sunburst.test.js @@ -18,7 +18,6 @@ */ describe('Visualization > Sunburst', () => { beforeEach(() => { - cy.preserveLogin(); cy.intercept('POST', '/superset/explore_json/**').as('getJson'); }); diff --git a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/table.test.ts b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/table.test.ts index b91df4a45f0d8..46030bfb35949 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/table.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/table.test.ts @@ -28,7 +28,6 @@ import { // Table describe('Visualization > Table', () => { beforeEach(() => { - cy.preserveLogin(); interceptChart({ legacy: false }).as('chartData'); }); diff --git a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/time_table.js b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/time_table.js index ef9863a56f8b8..5c8672192a8e5 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/time_table.js +++ b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/time_table.js @@ -20,7 +20,6 @@ import { FORM_DATA_DEFAULTS, NUM_METRIC } from './shared.helper'; describe('Visualization > Time TableViz', () => { beforeEach(() => { - cy.preserveLogin(); cy.intercept('POST', '/superset/explore_json/**').as('getJson'); }); diff --git a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/treemap.test.js b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/treemap.test.js index 9b7ea9819022a..158aa7b39b15e 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/treemap.test.js +++ b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/treemap.test.js @@ -18,7 +18,6 @@ */ describe('Visualization > Treemap', () => { beforeEach(() => { - cy.preserveLogin(); cy.intercept('POST', '/superset/explore_json/**').as('getJson'); }); diff --git a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/world_map.test.js b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/world_map.test.js index 4afb5f54ff751..f92fbf58efcc0 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/world_map.test.js +++ b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/world_map.test.js @@ -18,7 +18,6 @@ */ describe('Visualization > World Map', () => { beforeEach(() => { - cy.preserveLogin(); cy.intercept('POST', '/superset/explore_json/**').as('getJson'); }); diff --git a/superset-frontend/cypress-base/cypress/integration/sqllab/_skip.sourcePanel.index.test.js b/superset-frontend/cypress-base/cypress/integration/sqllab/_skip.sourcePanel.index.test.js index 00f4c1988c761..be455a4a99b7f 100644 --- a/superset-frontend/cypress-base/cypress/integration/sqllab/_skip.sourcePanel.index.test.js +++ b/superset-frontend/cypress-base/cypress/integration/sqllab/_skip.sourcePanel.index.test.js @@ -20,7 +20,6 @@ import { selectResultsTab } from './sqllab.helper'; describe.skip('SqlLab datasource panel', () => { beforeEach(() => { - cy.login(); cy.visit('/superset/sqllab'); }); diff --git a/superset-frontend/cypress-base/cypress/integration/sqllab/query.test.ts b/superset-frontend/cypress-base/cypress/integration/sqllab/query.test.ts index f75a29bc886d7..f4db901bb64cf 100644 --- a/superset-frontend/cypress-base/cypress/integration/sqllab/query.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/sqllab/query.test.ts @@ -25,7 +25,6 @@ function parseClockStr(node: JQuery) { describe('SqlLab query panel', () => { beforeEach(() => { - cy.login(); cy.visit('/superset/sqllab'); }); diff --git a/superset-frontend/cypress-base/cypress/integration/sqllab/sqllab.applitools.test.ts b/superset-frontend/cypress-base/cypress/integration/sqllab/sqllab.applitools.test.ts index 31b4472516f31..fdbaefb158f1d 100644 --- a/superset-frontend/cypress-base/cypress/integration/sqllab/sqllab.applitools.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/sqllab/sqllab.applitools.test.ts @@ -19,7 +19,6 @@ describe('SqlLab view', () => { beforeEach(() => { - cy.login(); cy.visit('/superset/sqllab'); }); diff --git a/superset-frontend/cypress-base/cypress/integration/sqllab/tabs.test.ts b/superset-frontend/cypress-base/cypress/integration/sqllab/tabs.test.ts index 0f08593022a6d..34f8844d49a0c 100644 --- a/superset-frontend/cypress-base/cypress/integration/sqllab/tabs.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/sqllab/tabs.test.ts @@ -18,7 +18,6 @@ */ describe('SqlLab query tabs', () => { beforeEach(() => { - cy.login(); cy.visit('/superset/sqllab'); }); diff --git a/superset-frontend/cypress-base/cypress/support/index.d.ts b/superset-frontend/cypress-base/cypress/support/index.d.ts index 603c490ebfc2e..124d72bddd006 100644 --- a/superset-frontend/cypress-base/cypress/support/index.d.ts +++ b/superset-frontend/cypress-base/cypress/support/index.d.ts @@ -29,7 +29,6 @@ declare namespace Cypress { * Login test user. */ login(): void; - preserveLogin(): void; /** * diff --git a/superset-frontend/cypress-base/cypress/support/index.ts b/superset-frontend/cypress-base/cypress/support/index.ts index e3909338ffc6a..456ca7ebc5c77 100644 --- a/superset-frontend/cypress-base/cypress/support/index.ts +++ b/superset-frontend/cypress-base/cypress/support/index.ts @@ -22,7 +22,6 @@ import '@applitools/eyes-cypress/commands'; require('cy-verify-downloads').addCustomCommand(); const BASE_EXPLORE_URL = '/explore/?form_data='; -const TokenName = Cypress.env('TOKEN_NAME'); let DASHBOARD_FIXTURES: Record[] = []; let CHART_FIXTURES: Record[] = []; @@ -40,6 +39,7 @@ Cypress.Commands.add('loadDashboardFixtures', () => before(() => { cy.login(); + Cypress.Cookies.defaults({ preserve: 'session' }); cy.loadChartFixtures(); cy.loadDashboardFixtures(); }); @@ -50,7 +50,6 @@ beforeEach(() => { }); Cypress.Commands.add('cleanDashboards', () => { - cy.login(); cy.getDashboards().then((sampleDashboards?: Record[]) => { const deletableDashboards = []; for (let i = 0; i < DASHBOARD_FIXTURES.length; i += 1) { @@ -72,7 +71,6 @@ Cypress.Commands.add('cleanDashboards', () => { 'access_token', )}`, 'Content-Type': 'application/json', - Authorization: `Bearer ${TokenName}`, 'X-CSRFToken': `${window.localStorage.getItem('access_token')}`, Referer: `${Cypress.config().baseUrl}/`, }, @@ -82,7 +80,6 @@ Cypress.Commands.add('cleanDashboards', () => { }); Cypress.Commands.add('cleanCharts', () => { - cy.login(); cy.getCharts().then((sampleCharts?: Record[]) => { const deletableCharts = []; for (let i = 0; i < CHART_FIXTURES.length; i += 1) { @@ -104,7 +101,6 @@ Cypress.Commands.add('cleanCharts', () => { 'access_token', )}`, 'Content-Type': 'application/json', - Authorization: `Bearer ${TokenName}`, 'X-CSRFToken': `${window.localStorage.getItem('access_token')}`, Referer: `${Cypress.config().baseUrl}/`, }, @@ -144,10 +140,6 @@ Cypress.Commands.add('login', () => { }); }); -Cypress.Commands.add('preserveLogin', () => { - Cypress.Cookies.preserveOnce('session'); -}); - Cypress.Commands.add('visitChartByName', name => { cy.request(`/chart/api/read?_flt_3_slice_name=${name}`).then(response => { cy.visit(`${BASE_EXPLORE_URL}{"slice_id": ${response.body.pks[0]}}`); @@ -187,7 +179,6 @@ Cypress.Commands.add( Cookie: `csrf_access_token=${accessToken}`, 'X-CSRFToken': accessToken, }), - ...(TokenName && { Authorization: `Bearer ${TokenName}` }), 'Content-Type': 'application/json', Referer: `${Cypress.config().baseUrl}/`, }, @@ -258,7 +249,6 @@ Cypress.Commands.add('createSampleDashboards', (indexes?: number[]) => 'access_token', )}`, 'Content-Type': 'application/json', - Authorization: `Bearer ${TokenName}`, 'X-CSRFToken': `${window.localStorage.getItem('access_token')}`, Referer: `${Cypress.config().baseUrl}/`, }, @@ -282,7 +272,6 @@ Cypress.Commands.add('createSampleCharts', (indexes?: number[]) => 'access_token', )}`, 'Content-Type': 'application/json', - Authorization: `Bearer ${TokenName}`, 'X-CSRFToken': `${window.localStorage.getItem('access_token')}`, Referer: `${Cypress.config().baseUrl}/`, }, @@ -318,7 +307,6 @@ Cypress.Commands.add( 'access_token', )}`, 'Content-Type': 'application/json', - Authorization: `Bearer ${TokenName}`, 'X-CSRFToken': `${window.localStorage.getItem('access_token')}`, Referer: `${Cypress.config().baseUrl}/`, }, @@ -326,18 +314,15 @@ Cypress.Commands.add( .then(resp => resp), ); -Cypress.Commands.add('getDashboards', () => - cy - .request({ - method: 'GET', - url: `api/v1/dashboard/`, - headers: { - 'Content-Type': 'application/json', - Authorization: `Bearer ${TokenName}`, - }, - }) - .then(resp => resp.body.result), -); +Cypress.Commands.add('getDashboards', () => { + cy.request({ + method: 'GET', + url: `api/v1/dashboard/`, + headers: { + 'Content-Type': 'application/json', + }, + }).then(resp => resp.body.result); +}); Cypress.Commands.add('getDashboard', (dashboardId: string | number) => cy @@ -346,7 +331,6 @@ Cypress.Commands.add('getDashboard', (dashboardId: string | number) => url: `api/v1/dashboard/${dashboardId}`, headers: { 'Content-Type': 'application/json', - Authorization: `Bearer ${TokenName}`, }, }) .then(resp => resp.body.result), @@ -362,7 +346,6 @@ Cypress.Commands.add( body, headers: { 'Content-Type': 'application/json', - Authorization: `Bearer ${TokenName}`, }, }) .then(resp => resp.body.result), @@ -379,7 +362,6 @@ Cypress.Commands.add('deleteChart', (id: number, failOnStatusCode = false) => 'access_token', )}`, 'Content-Type': 'application/json', - Authorization: `Bearer ${TokenName}`, 'X-CSRFToken': `${window.localStorage.getItem('access_token')}`, Referer: `${Cypress.config().baseUrl}/`, }, @@ -394,7 +376,6 @@ Cypress.Commands.add('getCharts', () => url: `api/v1/chart/`, headers: { 'Content-Type': 'application/json', - Authorization: `Bearer ${TokenName}`, }, }) .then(resp => resp.body.result), diff --git a/superset-frontend/cypress-base/cypress/utils/index.ts b/superset-frontend/cypress-base/cypress/utils/index.ts index b685cc01e898a..2f06efc22c25e 100644 --- a/superset-frontend/cypress-base/cypress/utils/index.ts +++ b/superset-frontend/cypress-base/cypress/utils/index.ts @@ -34,7 +34,11 @@ export function toggleBulkSelect() { } export function clearAllInputs() { - cy.get('[aria-label="close-circle"]').click({ multiple: true, force: true }); + cy.get('body').then($body => { + if ($body.find('.ant-select-clear').length) { + cy.get('.ant-select-clear').click({ multiple: true, force: true }); + } + }); } const toSlicelike = ($chart: JQuery): Slice => ({ diff --git a/superset-frontend/package-lock.json b/superset-frontend/package-lock.json index d8708544725e8..bd990f5473aaa 100644 --- a/superset-frontend/package-lock.json +++ b/superset-frontend/package-lock.json @@ -97,9 +97,9 @@ "re-resizable": "^6.6.1", "react": "^16.13.1", "react-ace": "^10.1.0", - "react-checkbox-tree": "^1.5.1", + "react-checkbox-tree": "^1.8.0", "react-color": "^2.13.8", - "react-datetime": "^3.0.4", + "react-datetime": "^3.2.0", "react-diff-viewer": "^3.1.1", "react-dnd": "^11.1.3", "react-dnd-html5-backend": "^11.1.3", @@ -107,7 +107,7 @@ "react-draggable": "^4.4.3", "react-gravatar": "^2.6.1", "react-hot-loader": "^4.12.20", - "react-intersection-observer": "^8.26.2", + "react-intersection-observer": "^9.4.1", "react-js-cron": "^1.2.0", "react-json-tree": "^0.17.0", "react-jsonschema-form": "^1.2.0", @@ -48966,17 +48966,28 @@ "integrity": "sha1-ThTsxkAZAdod33aBqiTjOwDa3Og=" }, "node_modules/react-checkbox-tree": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/react-checkbox-tree/-/react-checkbox-tree-1.5.1.tgz", - "integrity": "sha512-fBLMVpd7/YXavzIBz+3OMS5eo2oZLW9PlTY4M1zrJ3TdZRzgILicSzRj6V5VKKm80y8uQXn60skn98pwn3i3Ig==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/react-checkbox-tree/-/react-checkbox-tree-1.8.0.tgz", + "integrity": "sha512-ufC4aorihOvjLpvY1beab2hjVLGZbDTFRzw62foG0+th+KX7e/sdmWu/nD1ZS/U5Yr0rWGwedGH5GOtR0IkUXw==", "dependencies": { "classnames": "^2.2.5", "lodash": "^4.17.10", - "nanoid": "^2.0.0", + "nanoid": "^3.0.0", "prop-types": "^15.5.8" }, "peerDependencies": { - "react": "^15.3.0 || ^16.0.0" + "react": "^15.3.0 || ^16.0.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/react-checkbox-tree/node_modules/nanoid": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, "node_modules/react-color": { @@ -49001,15 +49012,15 @@ } }, "node_modules/react-datetime": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/react-datetime/-/react-datetime-3.0.4.tgz", - "integrity": "sha512-v6MVwCve+DRaLN2f22LTO5TlrPpkUXumPkp1zfrbhaFtSYGl2grZ2JtwJfLxRj/T4ACyePAV4srCR6cMSiQ/Iw==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/react-datetime/-/react-datetime-3.2.0.tgz", + "integrity": "sha512-w5XdeNIGzBht9CadaZIJhKUhEcDTgH0XokKxGPCxeeJRYL7B3HIKA8CM6Q0xej2JFJt0n5d+zi3maMwaY3262A==", "dependencies": { "prop-types": "^15.5.7" }, "peerDependencies": { "moment": "^2.16.0", - "react": "^16.5.0" + "react": "^16.5.0 || ^17.0.0 || ^18.0.0" } }, "node_modules/react-diff-viewer": { @@ -49268,14 +49279,11 @@ } }, "node_modules/react-intersection-observer": { - "version": "8.26.2", - "resolved": "https://registry.npmjs.org/react-intersection-observer/-/react-intersection-observer-8.26.2.tgz", - "integrity": "sha512-GmSjLNK+oV7kS+BHfrJSaA4wF61ELA33gizKHmN+tk59UT6/aW8kkqvlrFGPwxGoaIzLKS2evfG5fgkw5MIIsg==", - "dependencies": { - "tiny-invariant": "^1.1.0" - }, + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/react-intersection-observer/-/react-intersection-observer-9.4.1.tgz", + "integrity": "sha512-IXpIsPe6BleFOEHKzKh5UjwRUaz/JYS0lT/HPsupWEQou2hDqjhLMStc5zyE3eQVT4Fk3FufM8Fw33qW1uyeiw==", "peerDependencies": { - "react": "^15.0.0 || ^16.0.0 || ^17.0.0" + "react": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0" } }, "node_modules/react-is": { @@ -99393,14 +99401,21 @@ } }, "react-checkbox-tree": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/react-checkbox-tree/-/react-checkbox-tree-1.5.1.tgz", - "integrity": "sha512-fBLMVpd7/YXavzIBz+3OMS5eo2oZLW9PlTY4M1zrJ3TdZRzgILicSzRj6V5VKKm80y8uQXn60skn98pwn3i3Ig==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/react-checkbox-tree/-/react-checkbox-tree-1.8.0.tgz", + "integrity": "sha512-ufC4aorihOvjLpvY1beab2hjVLGZbDTFRzw62foG0+th+KX7e/sdmWu/nD1ZS/U5Yr0rWGwedGH5GOtR0IkUXw==", "requires": { "classnames": "^2.2.5", "lodash": "^4.17.10", - "nanoid": "^2.0.0", + "nanoid": "^3.0.0", "prop-types": "^15.5.8" + }, + "dependencies": { + "nanoid": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==" + } } }, "react-color": { @@ -99422,9 +99437,9 @@ "requires": {} }, "react-datetime": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/react-datetime/-/react-datetime-3.0.4.tgz", - "integrity": "sha512-v6MVwCve+DRaLN2f22LTO5TlrPpkUXumPkp1zfrbhaFtSYGl2grZ2JtwJfLxRj/T4ACyePAV4srCR6cMSiQ/Iw==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/react-datetime/-/react-datetime-3.2.0.tgz", + "integrity": "sha512-w5XdeNIGzBht9CadaZIJhKUhEcDTgH0XokKxGPCxeeJRYL7B3HIKA8CM6Q0xej2JFJt0n5d+zi3maMwaY3262A==", "requires": { "prop-types": "^15.5.7" } @@ -99627,12 +99642,10 @@ } }, "react-intersection-observer": { - "version": "8.26.2", - "resolved": "https://registry.npmjs.org/react-intersection-observer/-/react-intersection-observer-8.26.2.tgz", - "integrity": "sha512-GmSjLNK+oV7kS+BHfrJSaA4wF61ELA33gizKHmN+tk59UT6/aW8kkqvlrFGPwxGoaIzLKS2evfG5fgkw5MIIsg==", - "requires": { - "tiny-invariant": "^1.1.0" - } + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/react-intersection-observer/-/react-intersection-observer-9.4.1.tgz", + "integrity": "sha512-IXpIsPe6BleFOEHKzKh5UjwRUaz/JYS0lT/HPsupWEQou2hDqjhLMStc5zyE3eQVT4Fk3FufM8Fw33qW1uyeiw==", + "requires": {} }, "react-is": { "version": "16.6.3", diff --git a/superset-frontend/package.json b/superset-frontend/package.json index fb93dbf61d533..80116d4eb045e 100644 --- a/superset-frontend/package.json +++ b/superset-frontend/package.json @@ -161,9 +161,9 @@ "re-resizable": "^6.6.1", "react": "^16.13.1", "react-ace": "^10.1.0", - "react-checkbox-tree": "^1.5.1", + "react-checkbox-tree": "^1.8.0", "react-color": "^2.13.8", - "react-datetime": "^3.0.4", + "react-datetime": "^3.2.0", "react-diff-viewer": "^3.1.1", "react-dnd": "^11.1.3", "react-dnd-html5-backend": "^11.1.3", @@ -171,7 +171,7 @@ "react-draggable": "^4.4.3", "react-gravatar": "^2.6.1", "react-hot-loader": "^4.12.20", - "react-intersection-observer": "^8.26.2", + "react-intersection-observer": "^9.4.1", "react-js-cron": "^1.2.0", "react-json-tree": "^0.17.0", "react-jsonschema-form": "^1.2.0", diff --git a/superset-frontend/packages/superset-ui-chart-controls/src/sections/echartsTimeSeriesQuery.tsx b/superset-frontend/packages/superset-ui-chart-controls/src/sections/echartsTimeSeriesQuery.tsx index 296f8d9da820f..cd58780d892d2 100644 --- a/superset-frontend/packages/superset-ui-chart-controls/src/sections/echartsTimeSeriesQuery.tsx +++ b/superset-frontend/packages/superset-ui-chart-controls/src/sections/echartsTimeSeriesQuery.tsx @@ -20,7 +20,6 @@ import { hasGenericChartAxes, t } from '@superset-ui/core'; import { ControlPanelSectionConfig, ControlSetRow } from '../types'; import { contributionModeControl, - emitFilterControl, xAxisSortControl, xAxisSortAscControl, } from '../shared-controls'; @@ -30,7 +29,6 @@ const controlsWithoutXAxis: ControlSetRow[] = [ ['groupby'], [contributionModeControl], ['adhoc_filters'], - emitFilterControl, ['limit'], ['timeseries_limit_metric'], ['order_desc'], diff --git a/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/ColumnConfigControl.tsx b/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/ColumnConfigControl.tsx index 55c560cb7935e..548dd4ae4d7fe 100644 --- a/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/ColumnConfigControl.tsx +++ b/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/ColumnConfigControl.tsx @@ -40,7 +40,6 @@ export type ColumnConfigControlProps = queryResponse?: ChartDataResponseResult; configFormLayout?: ColumnConfigFormLayout; appliedColumnNames?: string[]; - emitFilter: boolean; }; /** @@ -57,24 +56,8 @@ export default function ColumnConfigControl({ value, onChange, configFormLayout = DEFAULT_CONFIG_FORM_LAYOUT, - emitFilter, ...props }: ColumnConfigControlProps) { - if (emitFilter) { - Object.values(configFormLayout).forEach(array_of_array => { - if (!array_of_array.some(arr => arr.includes('emitTarget'))) { - array_of_array.push(['emitTarget']); - } - }); - } else { - Object.values(configFormLayout).forEach(array_of_array => { - const index = array_of_array.findIndex(arr => arr.includes('emitTarget')); - if (index > -1) { - array_of_array.splice(index, 1); - } - }); - } - const { colnames: _colnames, coltypes: _coltypes } = queryResponse || {}; let colnames: string[] = []; let coltypes: GenericDataType[] = []; diff --git a/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx b/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx index fffadb449ac40..ecdee5be1f28a 100644 --- a/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx +++ b/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/ColumnConfigControl/constants.tsx @@ -35,7 +35,6 @@ export type SharedColumnConfigProp = | 'colorPositiveNegative' | 'columnWidth' | 'fractionDigits' - | 'emitTarget' | 'd3NumberFormat' | 'd3SmallNumberFormat' | 'd3TimeFormat' @@ -43,17 +42,6 @@ export type SharedColumnConfigProp = | 'truncateLongCells' | 'showCellBars'; -const emitTarget: ControlFormItemSpec<'Input'> = { - controlType: 'Input', - label: t('Emit Target'), - description: t( - 'If you wish to specify a different target column than the original column, it can be entered here', - ), - defaultValue: '', - debounceDelay: 500, - validators: undefined, -}; - const d3NumberFormat: ControlFormItemSpec<'Select'> = { controlType: 'Select', label: t('D3 format'), @@ -156,7 +144,6 @@ const truncateLongCells: ControlFormItemSpec<'Checkbox'> = { */ export const SHARED_COLUMN_CONFIG_PROPS = { d3NumberFormat, - emitTarget, d3SmallNumberFormat: { ...d3NumberFormat, label: t('Small number format'), diff --git a/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/customControls.tsx b/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/customControls.tsx index 5ece20ac06001..979912e58f1da 100644 --- a/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/customControls.tsx +++ b/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/customControls.tsx @@ -20,12 +20,10 @@ import { ContributionType, ensureIsArray, - FeatureFlag, getColumnLabel, getMetricLabel, isDefined, isEqualArray, - isFeatureEnabled, QueryFormColumn, QueryFormMetric, t, @@ -33,23 +31,6 @@ import { import { ControlPanelState, ControlState, ControlStateMapping } from '../types'; import { isTemporalColumn } from '../utils'; -export const emitFilterControl = isFeatureEnabled( - FeatureFlag.DASHBOARD_CROSS_FILTERS, -) - ? [ - { - name: 'emit_filter', - config: { - type: 'CheckboxControl', - label: t('Enable dashboard cross filters'), - default: false, - renderTrigger: true, - description: t('Enable dashboard cross filters'), - }, - }, - ] - : []; - export const contributionModeControl = { name: 'contributionMode', config: { diff --git a/superset-frontend/packages/superset-ui-core/src/chart/models/ChartProps.ts b/superset-frontend/packages/superset-ui-core/src/chart/models/ChartProps.ts index 5e4f044942a6b..e02aeca4f54de 100644 --- a/superset-frontend/packages/superset-ui-core/src/chart/models/ChartProps.ts +++ b/superset-frontend/packages/superset-ui-core/src/chart/models/ChartProps.ts @@ -144,6 +144,8 @@ export default class ChartProps { inContextMenu?: boolean; + emitCrossFilters?: boolean; + theme: SupersetTheme; constructor(config: ChartPropsConfig & { formData?: FormData } = {}) { @@ -164,6 +166,7 @@ export default class ChartProps { isRefreshing, inputRef, inContextMenu = false, + emitCrossFilters = false, theme, } = config; this.width = width; @@ -184,6 +187,7 @@ export default class ChartProps { this.isRefreshing = isRefreshing; this.inputRef = inputRef; this.inContextMenu = inContextMenu; + this.emitCrossFilters = emitCrossFilters; this.theme = theme; } } @@ -207,6 +211,7 @@ ChartProps.createSelector = function create(): ChartPropsSelector { input => input.isRefreshing, input => input.inputRef, input => input.inContextMenu, + input => input.emitCrossFilters, input => input.theme, ( annotationData, @@ -225,6 +230,7 @@ ChartProps.createSelector = function create(): ChartPropsSelector { isRefreshing, inputRef, inContextMenu, + emitCrossFilters, theme, ) => new ChartProps({ @@ -244,6 +250,7 @@ ChartProps.createSelector = function create(): ChartPropsSelector { isRefreshing, inputRef, inContextMenu, + emitCrossFilters, theme, }), ); diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/EchartsBoxPlot.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/EchartsBoxPlot.tsx index 135d31317e227..4c18f7f7d6205 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/EchartsBoxPlot.tsx +++ b/superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/EchartsBoxPlot.tsx @@ -30,12 +30,12 @@ export default function EchartsBoxPlot(props: BoxPlotChartTransformedProps) { labelMap, groupby, selectedValues, - formData, refs, + emitCrossFilters, } = props; const handleChange = useCallback( (values: string[]) => { - if (!formData.emitFilter) { + if (!emitCrossFilters) { return; } diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts b/superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts index 95b8e6d966eeb..f1db7534d0860 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts @@ -28,7 +28,6 @@ import { D3_FORMAT_OPTIONS, D3_TIME_FORMAT_OPTIONS, sections, - emitFilterControl, ControlPanelConfig, getStandardizedControls, ControlState, @@ -77,7 +76,6 @@ const config: ControlPanelConfig = { ['groupby'], ['metrics'], ['adhoc_filters'], - emitFilterControl, ['series_limit'], ['series_limit_metric'], [ diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/transformProps.ts b/superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/transformProps.ts index 337807e229a60..54a1cbfd205ac 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/transformProps.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/transformProps.ts @@ -53,6 +53,7 @@ export default function transformProps( filterState, queriesData, inContextMenu, + emitCrossFilters, } = chartProps; const { data = [] } = queriesData[0]; const { setDataMask = () => {}, onContextMenu } = hooks; @@ -64,7 +65,6 @@ export default function transformProps( numberFormat, dateFormat, xTicksLayout, - emitFilter, legendOrientation = 'top', xAxisTitle, yAxisTitle, @@ -291,7 +291,7 @@ export default function transformProps( height, echartOptions, setDataMask, - emitFilter, + emitCrossFilters, labelMap, groupby, selectedValues, diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/types.ts b/superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/types.ts index dcbc9da17aa9b..6cdc57a26de01 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/types.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/types.ts @@ -30,7 +30,6 @@ export type BoxPlotQueryFormData = QueryFormData & { numberFormat?: string; whiskerOptions?: BoxPlotFormDataWhiskerOptions; xTickLayout?: BoxPlotFormXTickLayout; - emitFilter: boolean; } & TitleFormData; export type BoxPlotFormDataWhiskerOptions = @@ -48,7 +47,6 @@ export type BoxPlotFormXTickLayout = // @ts-ignore export const DEFAULT_FORM_DATA: BoxPlotQueryFormData = { - emitFilter: false, ...DEFAULT_TITLE_FORM_DATA, }; diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Funnel/EchartsFunnel.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/Funnel/EchartsFunnel.tsx index c492500e8e9a7..88ccae8ecc801 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Funnel/EchartsFunnel.tsx +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Funnel/EchartsFunnel.tsx @@ -30,12 +30,12 @@ export default function EchartsFunnel(props: FunnelChartTransformedProps) { labelMap, groupby, selectedValues, - formData, + emitCrossFilters, refs, } = props; const handleChange = useCallback( (values: string[]) => { - if (!formData.emitFilter) { + if (!emitCrossFilters) { return; } diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Funnel/controlPanel.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/Funnel/controlPanel.tsx index f8acdcf6bef74..929069b2ed220 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Funnel/controlPanel.tsx +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Funnel/controlPanel.tsx @@ -24,7 +24,6 @@ import { sections, sharedControls, ControlStateMapping, - emitFilterControl, getStandardizedControls, } from '@superset-ui/chart-controls'; import { DEFAULT_FORM_DATA, EchartsFunnelLabelTypeType } from './types'; @@ -45,7 +44,6 @@ const config: ControlPanelConfig = { ['groupby'], ['metric'], ['adhoc_filters'], - emitFilterControl, [ { name: 'row_limit', diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Funnel/transformProps.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Funnel/transformProps.ts index 30b5ccbfd9873..282bc42381cab 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Funnel/transformProps.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Funnel/transformProps.ts @@ -92,6 +92,7 @@ export default function transformProps( width, theme, inContextMenu, + emitCrossFilters, } = chartProps; const data: DataRecord[] = queriesData[0].data || []; @@ -110,7 +111,6 @@ export default function transformProps( numberFormat, showLabels, showLegend, - emitFilter, sliceId, }: EchartsFunnelFormData = { ...DEFAULT_LEGEND_FORM_DATA, @@ -238,7 +238,7 @@ export default function transformProps( height, echartOptions, setDataMask, - emitFilter, + emitCrossFilters, labelMap, groupby, selectedValues, diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Funnel/types.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Funnel/types.ts index 841722ce4bc5b..15adbc208041c 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Funnel/types.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Funnel/types.ts @@ -40,7 +40,6 @@ export type EchartsFunnelFormData = QueryFormData & gap: number; sort: 'descending' | 'ascending' | 'none' | undefined; orient: 'vertical' | 'horizontal' | undefined; - emitFilter: boolean; }; export enum EchartsFunnelLabelTypeType { @@ -70,7 +69,6 @@ export const DEFAULT_FORM_DATA: EchartsFunnelFormData = { sort: 'descending', orient: 'vertical', gap: 0, - emitFilter: false, }; export type FunnelChartTransformedProps = diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/EchartsGauge.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/EchartsGauge.tsx index 7ffb571b79481..8c4ca420d90b8 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/EchartsGauge.tsx +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/EchartsGauge.tsx @@ -30,12 +30,12 @@ export default function EchartsGauge(props: GaugeChartTransformedProps) { labelMap, groupby, selectedValues, - formData: { emitFilter }, + emitCrossFilters, refs, } = props; const handleChange = useCallback( (values: string[]) => { - if (!emitFilter) { + if (!emitCrossFilters) { return; } diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx index 7ffa62fda0ffa..1af718a989b1c 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/controlPanel.tsx @@ -23,7 +23,6 @@ import { ControlPanelConfig, D3_FORMAT_OPTIONS, sections, - emitFilterControl, getStandardizedControls, } from '@superset-ui/chart-controls'; import { DEFAULT_FORM_DATA } from './types'; @@ -46,7 +45,6 @@ const config: ControlPanelConfig = { ], ['metric'], ['adhoc_filters'], - emitFilterControl, [ { name: 'row_limit', diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/transformProps.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/transformProps.ts index d84078ad16eb2..b2e31c3cc1885 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/transformProps.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/transformProps.ts @@ -91,8 +91,16 @@ const calculateMax = (data: GaugeDataItemOption[]) => export default function transformProps( chartProps: EchartsGaugeChartProps, ): GaugeChartTransformedProps { - const { width, height, formData, queriesData, hooks, filterState, theme } = - chartProps; + const { + width, + height, + formData, + queriesData, + hooks, + filterState, + theme, + emitCrossFilters, + } = chartProps; const gaugeSeriesOptions = defaultGaugeSeriesOption(theme); @@ -117,7 +125,6 @@ export default function transformProps( intervals, intervalColorIndices, valueFormatter, - emitFilter, sliceId, }: EchartsGaugeFormData = { ...DEFAULT_GAUGE_FORM_DATA, ...formData }; const refs: Refs = {}; @@ -327,7 +334,7 @@ export default function transformProps( height, echartOptions, setDataMask, - emitFilter, + emitCrossFilters, labelMap: Object.fromEntries(columnsLabelMap), groupby, selectedValues: filterState.selectedValues || [], diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/types.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/types.ts index 9f2c08fd5f0b0..02cda2db7f641 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/types.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Gauge/types.ts @@ -52,7 +52,6 @@ export type EchartsGaugeFormData = QueryFormData & { intervals: string; intervalColorIndices: string; valueFormatter: string; - emitFilter: boolean; }; export const DEFAULT_FORM_DATA: Partial = { @@ -76,7 +75,6 @@ export const DEFAULT_FORM_DATA: Partial = { intervals: '', intervalColorIndices: '', valueFormatter: '{value}', - emitFilter: false, }; export interface EchartsGaugeChartProps diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/EchartsMixedTimeseries.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/EchartsMixedTimeseries.tsx index 1d1cd6547752d..b532c7d9da770 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/EchartsMixedTimeseries.tsx +++ b/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/EchartsMixedTimeseries.tsx @@ -39,6 +39,7 @@ export default function EchartsMixedTimeseries({ groupbyB, selectedValues, formData, + emitCrossFilters, seriesBreakdown, onContextMenu, xValueFormatter, @@ -52,10 +53,7 @@ export default function EchartsMixedTimeseries({ const handleChange = useCallback( (values: string[], seriesIndex: number) => { - const emitFilter = isFirstQuery(seriesIndex) - ? formData.emitFilter - : formData.emitFilterB; - if (!emitFilter) { + if (!emitCrossFilters) { return; } diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx index 6cbed6901bcd2..c1a3007785887 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx +++ b/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx @@ -24,7 +24,6 @@ import { ControlPanelSectionConfig, ControlSetRow, CustomControlItem, - emitFilterControl, getStandardizedControls, sections, sharedControls, @@ -79,14 +78,6 @@ function createQuerySection( config: sharedControls.adhoc_filters, }, ], - emitFilterControl.length > 0 - ? [ - { - ...emitFilterControl[0], - name: `emit_filter${controlSuffix}`, - }, - ] - : [], [ { name: `limit${controlSuffix}`, diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/transformProps.ts b/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/transformProps.ts index a39ca1d4d57eb..98367daf9a84e 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/transformProps.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/transformProps.ts @@ -95,6 +95,7 @@ export default function transformProps( datasource, theme, inContextMenu, + emitCrossFilters, } = chartProps; const { verboseMap = {} } = datasource; const { label_map: labelMap } = @@ -144,8 +145,6 @@ export default function transformProps( xAxisLabelRotation, groupby, groupbyB, - emitFilter, - emitFilterB, xAxis: xAxisOrig, xAxisTitle, yAxisTitle, @@ -504,8 +503,7 @@ export default function transformProps( height, echartOptions, setDataMask, - emitFilter, - emitFilterB, + emitCrossFilters, labelMap, labelMapB, groupby, diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/types.ts b/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/types.ts index a39e556cac6f9..3ec9b2a4b6d38 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/types.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/types.ts @@ -86,7 +86,6 @@ export type EchartsMixedTimeseriesFormData = QueryFormData & { yAxisIndexB?: number; groupby: QueryFormColumn[]; groupbyB: QueryFormColumn[]; - emitFilter: boolean; } & LegendFormData & TitleFormData; @@ -143,7 +142,6 @@ export type EchartsMixedTimeseriesChartTransformedProps = BaseTransformedProps & ContextMenuTransformedProps & CrossFilterTransformedProps & { - emitFilterB: boolean; groupbyB: QueryFormColumn[]; labelMapB: Record; seriesBreakdown: number; diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Pie/EchartsPie.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/Pie/EchartsPie.tsx index 6de4c8423dc49..9fecfeac0ef78 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Pie/EchartsPie.tsx +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Pie/EchartsPie.tsx @@ -30,12 +30,12 @@ export default function EchartsPie(props: PieChartTransformedProps) { labelMap, groupby, selectedValues, - formData, refs, + emitCrossFilters, } = props; const handleChange = useCallback( (values: string[]) => { - if (!formData.emitFilter) { + if (!emitCrossFilters) { return; } diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx index c9f0f79d19ec5..1a2d230b74976 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx @@ -25,7 +25,6 @@ import { D3_FORMAT_OPTIONS, D3_TIME_FORMAT_OPTIONS, sections, - emitFilterControl, getStandardizedControls, } from '@superset-ui/chart-controls'; import { DEFAULT_FORM_DATA } from './types'; @@ -52,7 +51,6 @@ const config: ControlPanelConfig = { ['groupby'], ['metric'], ['adhoc_filters'], - emitFilterControl, ['row_limit'], [ { diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Pie/transformProps.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Pie/transformProps.ts index 4261117082106..4db36e864e9d8 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Pie/transformProps.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Pie/transformProps.ts @@ -144,6 +144,7 @@ export default function transformProps( width, theme, inContextMenu, + emitCrossFilters, } = chartProps; const { data = [] } = queriesData[0]; const coltypeMapping = getColtypesMapping(queriesData[0]); @@ -166,7 +167,6 @@ export default function transformProps( showLabels, showLegend, showLabelsThreshold, - emitFilter, sliceId, showTotal, }: EchartsPieFormData = { @@ -339,11 +339,11 @@ export default function transformProps( height, echartOptions, setDataMask, - emitFilter, labelMap, groupby, selectedValues, onContextMenu, refs, + emitCrossFilters, }; } diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Pie/types.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Pie/types.ts index 4b45751a23cb0..d4acbb9517107 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Pie/types.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Pie/types.ts @@ -45,7 +45,6 @@ export type EchartsPieFormData = QueryFormData & numberFormat: string; dateFormat: string; showLabelsThreshold: number; - emitFilter: boolean; }; export enum EchartsPieLabelType { @@ -77,7 +76,6 @@ export const DEFAULT_FORM_DATA: EchartsPieFormData = { showLabels: true, labelsOutside: true, showLabelsThreshold: 5, - emitFilter: false, dateFormat: 'smart_date', }; diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Radar/EchartsRadar.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/Radar/EchartsRadar.tsx index 1291b69c12404..169240e8a45d0 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Radar/EchartsRadar.tsx +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Radar/EchartsRadar.tsx @@ -30,12 +30,12 @@ export default function EchartsRadar(props: RadarChartTransformedProps) { labelMap, groupby, selectedValues, - formData, + emitCrossFilters, refs, } = props; const handleChange = useCallback( (values: string[]) => { - if (!formData.emitFilter) { + if (!emitCrossFilters) { return; } diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx index 21cd853b4636e..68b9a17345ccf 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Radar/controlPanel.tsx @@ -31,7 +31,6 @@ import { D3_TIME_FORMAT_OPTIONS, sections, sharedControls, - emitFilterControl, ControlFormItemSpec, getStandardizedControls, } from '@superset-ui/chart-controls'; @@ -68,7 +67,6 @@ const config: ControlPanelConfig = { ['metrics'], ['timeseries_limit_metric'], ['adhoc_filters'], - emitFilterControl, [ { name: 'row_limit', diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Radar/transformProps.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Radar/transformProps.ts index 04c928036ca6b..f185859f4eee5 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Radar/transformProps.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Radar/transformProps.ts @@ -80,6 +80,7 @@ export default function transformProps( width, theme, inContextMenu, + emitCrossFilters, } = chartProps; const refs: Refs = {}; const { data = [] } = queriesData[0]; @@ -101,7 +102,6 @@ export default function transformProps( isCircle, columnConfig, sliceId, - emitFilter, }: EchartsRadarFormData = { ...DEFAULT_LEGEND_FORM_DATA, ...DEFAULT_RADAR_FORM_DATA, @@ -252,7 +252,7 @@ export default function transformProps( width, height, echartOptions, - emitFilter, + emitCrossFilters, setDataMask, labelMap: Object.fromEntries(columnsLabelMap), groupby, diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Radar/types.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Radar/types.ts index 97e3c1a32a855..ca7cdbd2c2db9 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Radar/types.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Radar/types.ts @@ -50,7 +50,6 @@ export type EchartsRadarFormData = QueryFormData & isCircle: boolean; numberFormat: string; dateFormat: string; - emitFilter: boolean; }; export enum EchartsRadarLabelType { @@ -73,7 +72,6 @@ export const DEFAULT_FORM_DATA: EchartsRadarFormData = { legendType: LegendType.Scroll, numberFormat: 'SMART_NUMBER', showLabels: true, - emitFilter: false, dateFormat: 'smart_date', isCircle: false, }; diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/EchartsSunburst.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/EchartsSunburst.tsx index 08f381b15d323..3dd8dc931aeb1 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/EchartsSunburst.tsx +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/EchartsSunburst.tsx @@ -38,13 +38,14 @@ export default function EchartsSunburst(props: SunburstTransformedProps) { formData, onContextMenu, refs, + emitCrossFilters, } = props; - const { emitFilter, columns } = formData; + const { columns } = formData; const handleChange = useCallback( (values: string[]) => { - if (!emitFilter) { + if (!emitCrossFilters) { return; } @@ -75,7 +76,7 @@ export default function EchartsSunburst(props: SunburstTransformedProps) { }, }); }, - [emitFilter, setDataMask, columns, labelMap], + [emitCrossFilters, setDataMask, columns, labelMap], ); const eventHandlers: EventHandlers = { diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/controlPanel.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/controlPanel.tsx index 9c4c5ae5bc46c..7ad3618a5ad92 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/controlPanel.tsx +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/controlPanel.tsx @@ -24,7 +24,6 @@ import { D3_FORMAT_DOCS, D3_FORMAT_OPTIONS, D3_TIME_FORMAT_OPTIONS, - emitFilterControl, getStandardizedControls, sections, } from '@superset-ui/chart-controls'; @@ -43,7 +42,6 @@ const config: ControlPanelConfig = { ['metric'], ['secondary_metric'], ['adhoc_filters'], - emitFilterControl, ['row_limit'], [ { diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/transformProps.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/transformProps.ts index 4677e1af694c8..9873d1dc324e6 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/transformProps.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/transformProps.ts @@ -163,6 +163,7 @@ export default function transformProps( width, theme, inContextMenu, + emitCrossFilters, } = chartProps; const { data = [] } = queriesData[0]; const coltypeMapping = getColtypesMapping(queriesData[0]); @@ -180,7 +181,6 @@ export default function transformProps( showLabelsThreshold, showTotal, sliceId, - emitFilter, } = formData; const refs: Refs = {}; const numberFormatter = getNumberFormatter(numberFormat); @@ -352,7 +352,7 @@ export default function transformProps( height, echartOptions, setDataMask, - emitFilter, + emitCrossFilters, labelMap: Object.fromEntries(columnsLabelMap), groupby, selectedValues: filterState.selectedValues || [], diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/types.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/types.ts index fdd834c94e6d6..91030fd7b5f0d 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/types.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/types.ts @@ -36,7 +36,6 @@ export type EchartsSunburstFormData = QueryFormData & { secondaryMetric?: QueryFormMetric; colorScheme?: string; linearColorScheme?: string; - emitFilter: boolean; }; export enum EchartsSunburstLabelType { @@ -51,7 +50,6 @@ export const DEFAULT_FORM_DATA: Partial = { labelType: EchartsSunburstLabelType.Key, showLabels: false, dateFormat: 'smart_date', - emitFilter: false, }; export interface EchartsSunburstChartProps diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/EchartsTimeseries.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/EchartsTimeseries.tsx index 2ffdb0e87bdc9..0cf7f3cf192cd 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/EchartsTimeseries.tsx +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/EchartsTimeseries.tsx @@ -49,8 +49,9 @@ export default function EchartsTimeseries({ xValueFormatter, xAxis, refs, + emitCrossFilters, }: TimeseriesChartTransformedProps) { - const { emitFilter, stack } = formData; + const { stack } = formData; const echartRef = useRef(null); // eslint-disable-next-line no-param-reassign refs.echartRef = echartRef; @@ -109,7 +110,7 @@ export default function EchartsTimeseries({ const handleChange = useCallback( (values: string[]) => { - if (!emitFilter) { + if (!emitCrossFilters) { return; } const groupbyValues = values.map(value => labelMap[value]); @@ -140,7 +141,7 @@ export default function EchartsTimeseries({ }, }); }, - [groupby, labelMap, setDataMask, emitFilter], + [groupby, labelMap, setDataMask, emitCrossFilters], ); const eventHandlers: EventHandlers = { diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/constants.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/constants.ts index 2590441ef67f6..67a3b234164db 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/constants.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/constants.ts @@ -57,7 +57,6 @@ export const DEFAULT_FORM_DATA: EchartsTimeseriesFormData = { zoomable: false, richTooltip: true, xAxisLabelRotation: 0, - emitFilter: false, groupby: [], showValue: false, onlyTotal: false, diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/transformProps.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/transformProps.ts index fa947b421b9fe..eadded44a9ac5 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/transformProps.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/transformProps.ts @@ -99,6 +99,7 @@ export default function transformProps( datasource, theme, inContextMenu, + emitCrossFilters, } = chartProps; const { verboseMap = {} } = datasource; const [queryData] = queriesData; @@ -134,7 +135,6 @@ export default function transformProps( richTooltip, xAxis: xAxisOrig, xAxisLabelRotation, - emitFilter, groupby, showValue, onlyTotal, @@ -448,7 +448,7 @@ export default function transformProps( return { echartOptions, - emitFilter, + emitCrossFilters, formData, groupby, height, diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/types.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/types.ts index 82a204e38d7f9..56527ebd63bf9 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/types.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/types.ts @@ -80,7 +80,6 @@ export type EchartsTimeseriesFormData = QueryFormData & { zoomable: boolean; richTooltip: boolean; xAxisLabelRotation: number; - emitFilter: boolean; groupby: QueryFormColumn[]; showValue: boolean; onlyTotal: boolean; diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Treemap/EchartsTreemap.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/Treemap/EchartsTreemap.tsx index 8559688939b06..0a2f01b4049c9 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Treemap/EchartsTreemap.tsx +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Treemap/EchartsTreemap.tsx @@ -29,7 +29,7 @@ import { TreemapTransformedProps } from './types'; export default function EchartsTreemap({ echartOptions, - formData, + emitCrossFilters, groupby, height, labelMap, @@ -41,7 +41,7 @@ export default function EchartsTreemap({ }: TreemapTransformedProps) { const handleChange = useCallback( (values: string[]) => { - if (!formData.emitFilter) { + if (!emitCrossFilters) { return; } diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Treemap/controlPanel.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/Treemap/controlPanel.tsx index befdce1b10dd2..dbe2e97e6ee9a 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Treemap/controlPanel.tsx +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Treemap/controlPanel.tsx @@ -24,7 +24,6 @@ import { D3_FORMAT_OPTIONS, D3_TIME_FORMAT_OPTIONS, sections, - emitFilterControl, getStandardizedControls, } from '@superset-ui/chart-controls'; import { DEFAULT_FORM_DATA } from './types'; @@ -55,7 +54,6 @@ const config: ControlPanelConfig = { }, ], ['adhoc_filters'], - emitFilterControl, ], }, { diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Treemap/transformProps.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Treemap/transformProps.ts index eb1b64ef30065..b220b55b3d3c1 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Treemap/transformProps.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Treemap/transformProps.ts @@ -117,6 +117,7 @@ export default function transformProps( filterState, theme, inContextMenu, + emitCrossFilters, } = chartProps; const { data = [] } = queriesData[0]; const { setDataMask = () => {}, onContextMenu } = hooks; @@ -133,7 +134,6 @@ export default function transformProps( showLabels, showUpperLabels, dashboardId, - emitFilter, sliceId, }: EchartsTreemapFormData = { ...DEFAULT_TREEMAP_FORM_DATA, @@ -288,7 +288,7 @@ export default function transformProps( height, echartOptions, setDataMask, - emitFilter, + emitCrossFilters, labelMap: Object.fromEntries(columnsLabelMap), groupby, selectedValues: filterState.selectedValues || [], diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Treemap/types.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Treemap/types.ts index 8d41b9d2e40bf..1d42988389182 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Treemap/types.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Treemap/types.ts @@ -43,7 +43,6 @@ export type EchartsTreemapFormData = QueryFormData & { numberFormat: string; dateFormat: string; dashboardId?: number; - emitFilter: boolean; }; export enum EchartsTreemapLabelType { @@ -66,7 +65,6 @@ export const DEFAULT_FORM_DATA: Partial = { showLabels: true, showUpperLabels: true, dateFormat: 'smart_date', - emitFilter: false, }; export interface TreemapSeriesCallbackDataParams extends CallbackDataParams { treePathInfo?: TreePathInfo[]; diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/types.ts b/superset-frontend/plugins/plugin-chart-echarts/src/types.ts index 5bd56eb8ed0d4..c24e2d84f46d1 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/types.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/types.ts @@ -130,12 +130,12 @@ export interface BaseTransformedProps { } export type CrossFilterTransformedProps = { - emitFilter: boolean; groupby: QueryFormColumn[]; labelMap: Record; setControlValue?: HandlerFunction; setDataMask: SetDataMaskHook; selectedValues: Record; + emitCrossFilters?: boolean; }; export type ContextMenuTransformedProps = { diff --git a/superset-frontend/plugins/plugin-chart-echarts/test/BoxPlot/buildQuery.test.ts b/superset-frontend/plugins/plugin-chart-echarts/test/BoxPlot/buildQuery.test.ts index 304f5b7065cfc..0d0f2f838990f 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/test/BoxPlot/buildQuery.test.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/test/BoxPlot/buildQuery.test.ts @@ -27,7 +27,6 @@ import { BoxPlotQueryFormData } from '../../src/BoxPlot/types'; describe('BoxPlot buildQuery', () => { const formData: BoxPlotQueryFormData = { ...DEFAULT_TITLE_FORM_DATA, - emitFilter: false, columns: [], datasource: '5__table', granularity_sqla: 'ds', diff --git a/superset-frontend/plugins/plugin-chart-echarts/test/MixedTimeseries/buildQuery.test.ts b/superset-frontend/plugins/plugin-chart-echarts/test/MixedTimeseries/buildQuery.test.ts index 3796870fd8839..066b796b59747 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/test/MixedTimeseries/buildQuery.test.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/test/MixedTimeseries/buildQuery.test.ts @@ -46,7 +46,6 @@ const formDataMixedChart = { row_limit: 10, timeseries_limit_metric: 'count', order_desc: true, - emit_filter: true, truncate_metric: true, show_empty_columns: true, // -- query b @@ -63,7 +62,6 @@ const formDataMixedChart = { row_limit_b: 100, timeseries_limit_metric_b: undefined, order_desc_b: false, - emit_filter_b: undefined, truncate_metric_b: true, show_empty_columns_b: true, // chart configs diff --git a/superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controlPanel.tsx b/superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controlPanel.tsx index e34394b3043a2..03904e54c83fc 100644 --- a/superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controlPanel.tsx +++ b/superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controlPanel.tsx @@ -18,7 +18,6 @@ */ import { ControlPanelConfig, - emitFilterControl, getStandardizedControls, sections, } from '@superset-ui/chart-controls'; @@ -65,7 +64,6 @@ const config: ControlPanelConfig = { [includeTimeControlSetItem], [showTotalsControlSetItem], ['adhoc_filters'], - emitFilterControl, ], }, { diff --git a/superset-frontend/plugins/plugin-chart-handlebars/src/types.ts b/superset-frontend/plugins/plugin-chart-handlebars/src/types.ts index 2a363059fa7d8..741d3b982c48b 100644 --- a/superset-frontend/plugins/plugin-chart-handlebars/src/types.ts +++ b/superset-frontend/plugins/plugin-chart-handlebars/src/types.ts @@ -51,7 +51,6 @@ export type HandlebarsQueryFormData = QueryFormData & all_columns?: QueryFormMetric[] | null; order_desc?: boolean; table_timestamp_format?: string; - emit_filter?: boolean; granularitySqla?: string; time_grain_sqla?: TimeGranularity; column_config?: Record; diff --git a/superset-frontend/plugins/plugin-chart-pivot-table/src/PivotTableChart.tsx b/superset-frontend/plugins/plugin-chart-pivot-table/src/PivotTableChart.tsx index 2d0b463c827b0..d9653686e11d6 100644 --- a/superset-frontend/plugins/plugin-chart-pivot-table/src/PivotTableChart.tsx +++ b/superset-frontend/plugins/plugin-chart-pivot-table/src/PivotTableChart.tsx @@ -136,7 +136,7 @@ export default function PivotTableChart(props: PivotTableProps) { colTotals, rowTotals, valueFormat, - emitFilter, + emitCrossFilters, setDataMask, selectedFilters, verboseMap, @@ -288,7 +288,7 @@ export default function PivotTableChart(props: PivotTableProps) { isSubtotal: boolean, isGrandTotal: boolean, ) => { - if (isSubtotal || isGrandTotal || !emitFilter) { + if (isSubtotal || isGrandTotal || !emitCrossFilters) { return; } @@ -328,7 +328,7 @@ export default function PivotTableChart(props: PivotTableProps) { } handleChange(updatedFilters); }, - [emitFilter, selectedFilters, handleChange], + [emitCrossFilters, selectedFilters, handleChange], ); const tableOptions = useMemo( @@ -337,7 +337,7 @@ export default function PivotTableChart(props: PivotTableProps) { clickColumnHeaderCallback: toggleFilter, colTotals, rowTotals, - highlightHeaderCellsOnHover: emitFilter, + highlightHeaderCellsOnHover: emitCrossFilters, highlightedHeaderCells: selectedFilters, omittedHighlightHeaderGroups: [METRIC_KEY], cellColorFormatters: { [METRIC_KEY]: metricColorFormatters }, @@ -346,7 +346,7 @@ export default function PivotTableChart(props: PivotTableProps) { [ colTotals, dateFormatters, - emitFilter, + emitCrossFilters, metricColorFormatters, rowTotals, selectedFilters, diff --git a/superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx b/superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx index 28d6361507fd8..1b01e37a4c110 100644 --- a/superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx +++ b/superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx @@ -32,7 +32,6 @@ import { D3_TIME_FORMAT_OPTIONS, sections, sharedControls, - emitFilterControl, Dataset, getStandardizedControls, } from '@superset-ui/chart-controls'; @@ -127,7 +126,6 @@ const config: ControlPanelConfig = { }, ], ['adhoc_filters'], - emitFilterControl, ['series_limit'], [ { diff --git a/superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/transformProps.ts b/superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/transformProps.ts index 546882274f0f5..43d73e6193ea4 100644 --- a/superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/transformProps.ts +++ b/superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/transformProps.ts @@ -80,6 +80,7 @@ export default function transformProps(chartProps: ChartProps) { hooks: { setDataMask = () => {}, onContextMenu }, filterState, datasource: { verboseMap = {}, columnFormats = {} }, + emitCrossFilters, } = chartProps; const { data, colnames, coltypes } = queriesData[0]; const { @@ -98,7 +99,6 @@ export default function transformProps(chartProps: ChartProps) { rowTotals, valueFormat, dateFormat, - emitFilter, metricsLayout, conditionalFormatting, timeGrainSqla, @@ -157,7 +157,7 @@ export default function transformProps(chartProps: ChartProps) { colTotals, rowTotals, valueFormat, - emitFilter, + emitCrossFilters, setDataMask, selectedFilters, verboseMap, diff --git a/superset-frontend/plugins/plugin-chart-pivot-table/src/types.ts b/superset-frontend/plugins/plugin-chart-pivot-table/src/types.ts index 9c0523b582b64..24d78e2dcaec5 100644 --- a/superset-frontend/plugins/plugin-chart-pivot-table/src/types.ts +++ b/superset-frontend/plugins/plugin-chart-pivot-table/src/types.ts @@ -65,7 +65,7 @@ interface PivotTableCustomizeProps { rowTotals: boolean; valueFormat: string; setDataMask: SetDataMaskHook; - emitFilter?: boolean; + emitCrossFilters?: boolean; selectedFilters?: SelectedFiltersType; verboseMap: JsonObject; columnFormats: JsonObject; diff --git a/superset-frontend/plugins/plugin-chart-pivot-table/test/plugin/transformProps.test.ts b/superset-frontend/plugins/plugin-chart-pivot-table/test/plugin/transformProps.test.ts index 26c938e371bcb..3edb4619afce0 100644 --- a/superset-frontend/plugins/plugin-chart-pivot-table/test/plugin/transformProps.test.ts +++ b/superset-frontend/plugins/plugin-chart-pivot-table/test/plugin/transformProps.test.ts @@ -38,7 +38,6 @@ describe('PivotTableChart transformProps', () => { colTotals: true, rowTotals: true, valueFormat: 'SMART_NUMBER', - emitFilter: false, metricsLayout: MetricsLayoutEnum.COLUMNS, viz_type: '', datasource: '', @@ -83,13 +82,13 @@ describe('PivotTableChart transformProps', () => { rowTotals: true, valueFormat: 'SMART_NUMBER', data: [{ name: 'Hulk', sum__num: 1, __timestamp: 599616000000 }], - emitFilter: false, setDataMask, selectedFilters: {}, verboseMap: {}, metricsLayout: MetricsLayoutEnum.COLUMNS, metricColorFormatters: [], dateFormatters: {}, + emitCrossFilters: false, columnFormats: {}, }); }); diff --git a/superset-frontend/plugins/plugin-chart-table/src/TableChart.tsx b/superset-frontend/plugins/plugin-chart-table/src/TableChart.tsx index 26019a972735a..465f7bdbff135 100644 --- a/superset-frontend/plugins/plugin-chart-table/src/TableChart.tsx +++ b/superset-frontend/plugins/plugin-chart-table/src/TableChart.tsx @@ -222,13 +222,13 @@ export default function TableChart( serverPaginationData, setDataMask, showCellBars = true, - emitFilter = false, sortDesc = false, filters, sticky = true, // whether to use sticky header columnColorFormatters, allowRearrangeColumns = false, onContextMenu, + emitCrossFilters, } = props; const timestampFormatter = useCallback( value => getTimeFormatterForGranularity(timeGrain)(value), @@ -243,7 +243,7 @@ export default function TableChart( const handleChange = useCallback( (filters: { [x: string]: DataRecordValue[] }) => { - if (!emitFilter) { + if (!emitCrossFilters) { return; } @@ -289,7 +289,7 @@ export default function TableChart( }, }); }, - [emitFilter, setDataMask], + [emitCrossFilters, setDataMask], ); // only take relevant page size options @@ -322,27 +322,21 @@ export default function TableChart( [filters], ); - function getEmitTarget(col: string) { - const meta = columnsMeta?.find(x => x.key === col); - return meta?.config?.emitTarget || col; - } - const toggleFilter = useCallback( function toggleFilter(key: string, val: DataRecordValue) { let updatedFilters = { ...(filters || {}) }; - const target = getEmitTarget(key); - if (filters && isActiveFilterValue(target, val)) { + if (filters && isActiveFilterValue(key, val)) { updatedFilters = {}; } else { updatedFilters = { - [target]: [val], + [key]: [val], }; } if ( - Array.isArray(updatedFilters[target]) && - updatedFilters[target].length === 0 + Array.isArray(updatedFilters[key]) && + updatedFilters[key].length === 0 ) { - delete updatedFilters[target]; + delete updatedFilters[key]; } handleChange(updatedFilters); }, @@ -396,7 +390,7 @@ export default function TableChart( getValueRange(key, alignPositiveNegative); let className = ''; - if (emitFilter) { + if (emitCrossFilters) { className += ' dt-is-filter'; } @@ -459,7 +453,7 @@ export default function TableChart( // show raw number in title in case of numeric values title: typeof value === 'number' ? String(value) : undefined, onClick: - emitFilter && !valueRange + emitCrossFilters && !valueRange ? () => toggleFilter(key, value) : undefined, className: [ @@ -567,7 +561,7 @@ export default function TableChart( [ defaultAlignPN, defaultColorPN, - emitFilter, + emitCrossFilters, getValueRange, isActiveFilterValue, isRawRecords, diff --git a/superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx b/superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx index e7e6b3d9852fe..35c5d3970a9ee 100644 --- a/superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx +++ b/superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx @@ -44,7 +44,6 @@ import { sharedControls, ControlPanelState, ControlState, - emitFilterControl, Dataset, ColumnMeta, defineSavedMetrics, @@ -369,7 +368,6 @@ const config: ControlPanelConfig = { }, }, ], - emitFilterControl, ], }, { @@ -488,7 +486,6 @@ const config: ControlPanelConfig = { queryResponse: chart?.queriesResponse?.[0] as | ChartDataResponseResult | undefined, - emitFilter: explore?.controls?.table_filter?.value, }; }, }, diff --git a/superset-frontend/plugins/plugin-chart-table/src/transformProps.ts b/superset-frontend/plugins/plugin-chart-table/src/transformProps.ts index bca48e63403cc..2fae16c31c87e 100644 --- a/superset-frontend/plugins/plugin-chart-table/src/transformProps.ts +++ b/superset-frontend/plugins/plugin-chart-table/src/transformProps.ts @@ -209,6 +209,7 @@ const transformProps = ( setDataMask = () => {}, onContextMenu, }, + emitCrossFilters, } = chartProps; const { @@ -217,7 +218,6 @@ const transformProps = ( show_cell_bars: showCellBars = true, include_search: includeSearch = false, page_length: pageLength, - emit_filter: emitFilter, server_pagination: serverPagination = false, server_page_length: serverPageLength = 10, order_desc: sortDesc = false, @@ -273,7 +273,7 @@ const transformProps = ( ? serverPageLength : getPageSize(pageLength, data.length, columns.length), filters: filterState.filters, - emitFilter, + emitCrossFilters, onChangeFilter, columnColorFormatters, timeGrain, diff --git a/superset-frontend/plugins/plugin-chart-table/src/types.ts b/superset-frontend/plugins/plugin-chart-table/src/types.ts index 1a6f06f4f886b..3a591e8682ed1 100644 --- a/superset-frontend/plugins/plugin-chart-table/src/types.ts +++ b/superset-frontend/plugins/plugin-chart-table/src/types.ts @@ -69,7 +69,6 @@ export type TableChartFormData = QueryFormData & { order_desc?: boolean; show_cell_bars?: boolean; table_timestamp_format?: string; - emit_filter?: boolean; time_grain_sqla?: TimeGranularity; column_config?: Record; allow_rearrange_columns?: boolean; @@ -108,7 +107,7 @@ export interface TableChartTransformedProps { // These are dashboard filters, don't be confused with in-chart search filter // enabled by `includeSearch` filters?: DataRecordFilters; - emitFilter?: boolean; + emitCrossFilters?: boolean; onChangeFilter?: ChartProps['hooks']['onAddFilter']; columnColorFormatters?: ColorFormatters; allowRearrangeColumns?: boolean; diff --git a/superset-frontend/spec/fixtures/mockDashboardState.js b/superset-frontend/spec/fixtures/mockDashboardState.js index b605443af6b02..0895ccf386955 100644 --- a/superset-frontend/spec/fixtures/mockDashboardState.js +++ b/superset-frontend/spec/fixtures/mockDashboardState.js @@ -113,6 +113,6 @@ export const overwriteConfirmMetadata = { slug: null, owners: [], json_metadata: - '{"timed_refresh_immune_slices":[],"expanded_slices":{},"refresh_frequency":0,"default_filters":"{}","color_scheme":"supersetColors","label_colors":{"0":"#FCC700","1":"#A868B7","15":"#3CCCCB","30":"#A38F79","45":"#8FD3E4","age":"#1FA8C9","Yes,":"#1FA8C9","Female":"#454E7C","Prefer":"#5AC189","No,":"#FF7F44","Male":"#666666","Prefer not to say":"#E04355","Ph.D.":"#FCC700","associate\'s degree":"#A868B7","bachelor\'s degree":"#3CCCCB","high school diploma or equivalent (GED)":"#A38F79","master\'s degree (non-professional)":"#8FD3E4","no high school (secondary school)":"#A1A6BD","professional degree (MBA, MD, JD, etc.)":"#ACE1C4","some college credit, no degree":"#FEC0A1","some high school":"#B2B2B2","trade, technical, or vocational training":"#EFA1AA","No, not an ethnic minority":"#1FA8C9","Yes, an ethnic minority":"#454E7C","":"#5AC189","Yes":"#FF7F44","No":"#666666","last_yr_income":"#E04355","More":"#A1A6BD","Less":"#ACE1C4","I":"#FEC0A1","expected_earn":"#B2B2B2","Yes: Willing To":"#EFA1AA","No: Not Willing to":"#FDE380","No Answer":"#D3B3DA","In an Office (with Other Developers)":"#9EE5E5","No Preference":"#D1C6BC","From Home":"#1FA8C9"},"show_native_filters":true,"color_scheme_domain":["#1FA8C9","#454E7C","#5AC189","#FF7F44","#666666","#E04355","#FCC700","#A868B7","#3CCCCB","#A38F79","#8FD3E4","#A1A6BD","#ACE1C4","#FEC0A1","#B2B2B2","#EFA1AA","#FDE380","#D3B3DA","#9EE5E5","#D1C6BC"],"shared_label_colors":{"Male":"#5ac19e","Female":"#1f86c9","":"#5AC189","Prefer not to say":"#47457c","No Answer":"#e05043","Yes, an ethnic minority":"#666666","No, not an ethnic minority":"#ffa444","age":"#1FA8C9"},"filter_scopes":{},"chart_configuration":{},"positions":{}}', + '{"timed_refresh_immune_slices":[],"expanded_slices":{},"refresh_frequency":0,"default_filters":"{}","color_scheme":"supersetColors","label_colors":{"0":"#FCC700","1":"#A868B7","15":"#3CCCCB","30":"#A38F79","45":"#8FD3E4","age":"#1FA8C9","Yes,":"#1FA8C9","Female":"#454E7C","Prefer":"#5AC189","No,":"#FF7F44","Male":"#666666","Prefer not to say":"#E04355","Ph.D.":"#FCC700","associate\'s degree":"#A868B7","bachelor\'s degree":"#3CCCCB","high school diploma or equivalent (GED)":"#A38F79","master\'s degree (non-professional)":"#8FD3E4","no high school (secondary school)":"#A1A6BD","professional degree (MBA, MD, JD, etc.)":"#ACE1C4","some college credit, no degree":"#FEC0A1","some high school":"#B2B2B2","trade, technical, or vocational training":"#EFA1AA","No, not an ethnic minority":"#1FA8C9","Yes, an ethnic minority":"#454E7C","":"#5AC189","Yes":"#FF7F44","No":"#666666","last_yr_income":"#E04355","More":"#A1A6BD","Less":"#ACE1C4","I":"#FEC0A1","expected_earn":"#B2B2B2","Yes: Willing To":"#EFA1AA","No: Not Willing to":"#FDE380","No Answer":"#D3B3DA","In an Office (with Other Developers)":"#9EE5E5","No Preference":"#D1C6BC","From Home":"#1FA8C9"},"show_native_filters":true,"color_scheme_domain":["#1FA8C9","#454E7C","#5AC189","#FF7F44","#666666","#E04355","#FCC700","#A868B7","#3CCCCB","#A38F79","#8FD3E4","#A1A6BD","#ACE1C4","#FEC0A1","#B2B2B2","#EFA1AA","#FDE380","#D3B3DA","#9EE5E5","#D1C6BC"],"shared_label_colors":{"Male":"#5ac19e","Female":"#1f86c9","":"#5AC189","Prefer not to say":"#47457c","No Answer":"#e05043","Yes, an ethnic minority":"#666666","No, not an ethnic minority":"#ffa444","age":"#1FA8C9"},"cross_filters_enabled":false,"filter_scopes":{},"chart_configuration":{},"positions":{}}', }, }; diff --git a/superset-frontend/src/SqlLab/actions/sqlLab.js b/superset-frontend/src/SqlLab/actions/sqlLab.js index c07ebfe683b5b..f1dc0ed15d85b 100644 --- a/superset-frontend/src/SqlLab/actions/sqlLab.js +++ b/superset-frontend/src/SqlLab/actions/sqlLab.js @@ -128,10 +128,22 @@ export function getUpToDateQuery(rootState, queryEditor, key) { sqlLab: { unsavedQueryEditor }, } = rootState; const id = key ?? queryEditor.id; - return { + const updatedQueryEditor = { ...queryEditor, ...(id === unsavedQueryEditor.id && unsavedQueryEditor), }; + + if ( + 'schema' in updatedQueryEditor && + !updatedQueryEditor.schemaOptions?.find( + ({ value }) => value === updatedQueryEditor.schema, + ) + ) { + // remove the deprecated schema option + delete updatedQueryEditor.schema; + } + + return updatedQueryEditor; } export function resetState() { diff --git a/superset-frontend/src/SqlLab/actions/sqlLab.test.js b/superset-frontend/src/SqlLab/actions/sqlLab.test.js index fb6ff470b40f0..ca1e68b5b2879 100644 --- a/superset-frontend/src/SqlLab/actions/sqlLab.test.js +++ b/superset-frontend/src/SqlLab/actions/sqlLab.test.js @@ -316,6 +316,54 @@ describe('async actions', () => { }); }); + describe('getUpToDateQuery', () => { + const id = 'randomidvalue2'; + const unsavedQueryEditor = { + id, + sql: 'some query here', + schemaOptions: [{ value: 'testSchema' }, { value: 'schema2' }], + }; + + it('returns payload with the updated queryEditor', () => { + const queryEditor = { + id, + name: 'Dummy query editor', + schema: 'testSchema', + }; + const state = { + sqlLab: { + tabHistory: [id], + queryEditors: [queryEditor], + unsavedQueryEditor, + }, + }; + expect(actions.getUpToDateQuery(state, queryEditor)).toEqual({ + ...queryEditor, + ...unsavedQueryEditor, + }); + }); + + it('ignores the deprecated schema option', () => { + const queryEditor = { + id, + name: 'Dummy query editor', + schema: 'oldSchema', + }; + const state = { + sqlLab: { + tabHistory: [id], + queryEditors: [queryEditor], + unsavedQueryEditor, + }, + }; + expect(actions.getUpToDateQuery(state, queryEditor)).toEqual({ + ...queryEditor, + ...unsavedQueryEditor, + schema: undefined, + }); + }); + }); + describe('postStopQuery', () => { const stopQueryEndpoint = 'glob:*/api/v1/query/stop'; fetchMock.post(stopQueryEndpoint, {}); diff --git a/superset-frontend/src/SqlLab/components/ShareSqlLabQuery/ShareSqlLabQuery.test.tsx b/superset-frontend/src/SqlLab/components/ShareSqlLabQuery/ShareSqlLabQuery.test.tsx index 6e9775c3a5bae..0883a6a9532ac 100644 --- a/superset-frontend/src/SqlLab/components/ShareSqlLabQuery/ShareSqlLabQuery.test.tsx +++ b/superset-frontend/src/SqlLab/components/ShareSqlLabQuery/ShareSqlLabQuery.test.tsx @@ -43,6 +43,7 @@ const mockQueryEditor = { autorun: false, sql: 'SELECT * FROM ...', remoteId: 999, + schemaOptions: [{ value: 'query_schema' }, { value: 'query_schema_updated' }], }; const disabled = { id: 'disabledEditorId', @@ -82,6 +83,7 @@ const standardProviderWithUnsaved: React.FC = ({ children }) => ( ...initialState, sqlLab: { ...initialState.sqlLab, + queryEditors: [mockQueryEditor], unsavedQueryEditor, }, })} @@ -123,7 +125,7 @@ describe('ShareSqlLabQuery', () => { }); }); const button = screen.getByRole('button'); - const { id, remoteId, ...expected } = mockQueryEditor; + const { id, remoteId, schemaOptions, ...expected } = mockQueryEditor; const storeQuerySpy = jest.spyOn(utils, 'storeQuery'); userEvent.click(button); expect(storeQuerySpy.mock.calls).toHaveLength(1); diff --git a/superset-frontend/src/SqlLab/components/SqlEditorLeftBar/SqlEditorLeftBar.test.jsx b/superset-frontend/src/SqlLab/components/SqlEditorLeftBar/SqlEditorLeftBar.test.jsx index fa8363f9e2aa0..33b9a56dfd6c7 100644 --- a/superset-frontend/src/SqlLab/components/SqlEditorLeftBar/SqlEditorLeftBar.test.jsx +++ b/superset-frontend/src/SqlLab/components/SqlEditorLeftBar/SqlEditorLeftBar.test.jsx @@ -41,15 +41,22 @@ const middlewares = [thunk]; const mockStore = configureStore(middlewares); const store = mockStore(initialState); -fetchMock.get('glob:*/api/v1/database/*/schemas/?*', { result: [] }); -fetchMock.get('glob:*/superset/tables/**', { - options: [ - { - label: 'ab_user', - value: 'ab_user', - }, - ], - tableLength: 1, +beforeEach(() => { + fetchMock.get('glob:*/api/v1/database/**', { result: [] }); + fetchMock.get('glob:*/api/v1/database/*/schemas/?*', { result: [] }); + fetchMock.get('glob:*/superset/tables/**', { + options: [ + { + label: 'ab_user', + value: 'ab_user', + }, + ], + tableLength: 1, + }); +}); + +afterEach(() => { + fetchMock.restore(); }); const renderAndWait = (props, store) => @@ -110,8 +117,9 @@ test('should toggle the table when the header is clicked', async () => { userEvent.click(header); await waitFor(() => { - expect(store.getActions()).toHaveLength(4); - expect(store.getActions()[3].type).toEqual('COLLAPSE_TABLE'); + expect(store.getActions()[store.getActions().length - 1].type).toEqual( + 'COLLAPSE_TABLE', + ); }); }); @@ -129,14 +137,77 @@ test('When changing database the table list must be updated', async () => { database_name: 'new_db', backend: 'postgresql', }} - queryEditor={{ ...mockedProps.queryEditor, schema: 'new_schema' }} + queryEditorId={defaultQueryEditor.id} tables={[{ ...mockedProps.tables[0], dbId: 2, name: 'new_table' }]} />, { useRedux: true, - initialState, + store: mockStore({ + ...initialState, + sqlLab: { + ...initialState.sqlLab, + unsavedQueryEditor: { + id: defaultQueryEditor.id, + schema: 'new_schema', + }, + }, + }), }, ); expect(await screen.findByText(/new_db/i)).toBeInTheDocument(); expect(await screen.findByText(/new_table/i)).toBeInTheDocument(); }); + +test('ignore schema api when current schema is deprecated', async () => { + const invalidSchemaName = 'None'; + await renderAndWait( + mockedProps, + mockStore({ + ...initialState, + sqlLab: { + ...initialState.sqlLab, + unsavedQueryEditor: { + id: defaultQueryEditor.id, + schema: invalidSchemaName, + }, + }, + }), + ); + + expect(await screen.findByText(/Database/i)).toBeInTheDocument(); + expect(screen.queryByText(/None/i)).not.toBeInTheDocument(); + expect(fetchMock.calls()).not.toContainEqual( + expect.arrayContaining([ + expect.stringContaining( + `/tables/${mockedProps.database.id}/${invalidSchemaName}/`, + ), + ]), + ); +}); + +test('fetches schema api when current schema is among the list', async () => { + const validSchema = 'schema1'; + await renderAndWait( + mockedProps, + mockStore({ + ...initialState, + sqlLab: { + ...initialState.sqlLab, + unsavedQueryEditor: { + id: defaultQueryEditor.id, + schema: validSchema, + schemaOptions: [{ name: validSchema, value: validSchema }], + }, + }, + }), + ); + + expect(await screen.findByText(/schema1/i)).toBeInTheDocument(); + expect(fetchMock.calls()).toContainEqual( + expect.arrayContaining([ + expect.stringContaining( + `/tables/${mockedProps.database.id}/${validSchema}/`, + ), + ]), + ); +}); diff --git a/superset-frontend/src/SqlLab/components/SqlEditorLeftBar/index.tsx b/superset-frontend/src/SqlLab/components/SqlEditorLeftBar/index.tsx index a96cb841167ad..247fc6c6a5993 100644 --- a/superset-frontend/src/SqlLab/components/SqlEditorLeftBar/index.tsx +++ b/superset-frontend/src/SqlLab/components/SqlEditorLeftBar/index.tsx @@ -117,7 +117,6 @@ const SqlEditorLeftBar = ({ }: SqlEditorLeftBarProps) => { const dispatch = useDispatch(); const queryEditor = useQueryEditor(queryEditorId, ['dbId', 'schema']); - const [emptyResultsWithSearch, setEmptyResultsWithSearch] = useState(false); const [userSelectedDb, setUserSelected] = useState( null, diff --git a/superset-frontend/src/SqlLab/hooks/useQueryEditor/index.ts b/superset-frontend/src/SqlLab/hooks/useQueryEditor/index.ts index 7044e77798fd2..7959d82b5f981 100644 --- a/superset-frontend/src/SqlLab/hooks/useQueryEditor/index.ts +++ b/superset-frontend/src/SqlLab/hooks/useQueryEditor/index.ts @@ -16,6 +16,7 @@ * specific language governing permissions and limitations * under the License. */ +import { useMemo } from 'react'; import pick from 'lodash/pick'; import { shallowEqual, useSelector } from 'react-redux'; import { SqlLabRootState, QueryEditor } from 'src/SqlLab/types'; @@ -24,7 +25,10 @@ export default function useQueryEditor( sqlEditorId: string, attributes: ReadonlyArray, ) { - return useSelector>( + const queryEditor = useSelector< + SqlLabRootState, + Pick + >( ({ sqlLab: { unsavedQueryEditor, queryEditors } }) => pick( { @@ -32,7 +36,32 @@ export default function useQueryEditor( ...(sqlEditorId === unsavedQueryEditor.id && unsavedQueryEditor), }, ['id'].concat(attributes), - ) as Pick, + ) as Pick, shallowEqual, ); + const { schema, schemaOptions } = useSelector< + SqlLabRootState, + Pick + >( + ({ sqlLab: { unsavedQueryEditor, queryEditors } }) => + pick( + { + ...queryEditors.find(({ id }) => id === sqlEditorId), + ...(sqlEditorId === unsavedQueryEditor.id && unsavedQueryEditor), + }, + ['schema', 'schemaOptions'], + ) as Pick, + shallowEqual, + ); + + const schemaOptionsMap = useMemo( + () => new Set(schemaOptions?.map(({ value }) => value)), + [schemaOptions], + ); + + if ('schema' in queryEditor && schema && !schemaOptionsMap.has(schema)) { + delete queryEditor.schema; + } + + return queryEditor as Pick; } diff --git a/superset-frontend/src/SqlLab/hooks/useQueryEditor/useQueryEditor.test.ts b/superset-frontend/src/SqlLab/hooks/useQueryEditor/useQueryEditor.test.ts index 23de4d68226cf..e8db4bd361fbd 100644 --- a/superset-frontend/src/SqlLab/hooks/useQueryEditor/useQueryEditor.test.ts +++ b/superset-frontend/src/SqlLab/hooks/useQueryEditor/useQueryEditor.test.ts @@ -70,7 +70,7 @@ test('includes id implicitly', () => { test('returns updated values from unsaved change', () => { const expectedSql = 'SELECT updated_column\nFROM updated_table\nWHERE'; const { result } = renderHook( - () => useQueryEditor(defaultQueryEditor.id, ['id', 'sql']), + () => useQueryEditor(defaultQueryEditor.id, ['id', 'sql', 'schema']), { wrapper: createWrapper({ useRedux: true, @@ -88,5 +88,31 @@ test('returns updated values from unsaved change', () => { }, ); expect(result.current.id).toEqual(defaultQueryEditor.id); + expect(result.current.schema).toEqual(defaultQueryEditor.schema); expect(result.current.sql).toEqual(expectedSql); }); + +test('skips the deprecated schema option', () => { + const expectedSql = 'SELECT updated_column\nFROM updated_table\nWHERE'; + const { result } = renderHook( + () => useQueryEditor(defaultQueryEditor.id, ['schema']), + { + wrapper: createWrapper({ + useRedux: true, + store: mockStore({ + ...initialState, + sqlLab: { + ...initialState.sqlLab, + unsavedQueryEditor: { + id: defaultQueryEditor.id, + sql: expectedSql, + schema: 'deprecated schema', + }, + }, + }), + }), + }, + ); + expect(result.current.schema).not.toEqual(defaultQueryEditor.schema); + expect(result.current.schema).toBeUndefined(); +}); diff --git a/superset-frontend/src/SqlLab/types.ts b/superset-frontend/src/SqlLab/types.ts index 7317ef0789d5a..14f21ee68a3b4 100644 --- a/superset-frontend/src/SqlLab/types.ts +++ b/superset-frontend/src/SqlLab/types.ts @@ -35,7 +35,7 @@ export interface QueryEditor { id: string; dbId?: number; name: string; - schema: string; + schema?: string; autorun: boolean; sql: string; remoteId: number | null; diff --git a/superset-frontend/src/components/Chart/Chart.jsx b/superset-frontend/src/components/Chart/Chart.jsx index aac44a5186c57..7e9f6aa482e19 100644 --- a/superset-frontend/src/components/Chart/Chart.jsx +++ b/superset-frontend/src/components/Chart/Chart.jsx @@ -77,6 +77,7 @@ const propTypes = { postTransformProps: PropTypes.func, datasetsStatus: PropTypes.oneOf(['loading', 'error', 'complete']), isInView: PropTypes.bool, + emitCrossFilters: PropTypes.bool, }; const BLANK = {}; diff --git a/superset-frontend/src/components/Chart/ChartRenderer.jsx b/superset-frontend/src/components/Chart/ChartRenderer.jsx index e1d3f7290adcb..588e2b4e4dfbe 100644 --- a/superset-frontend/src/components/Chart/ChartRenderer.jsx +++ b/superset-frontend/src/components/Chart/ChartRenderer.jsx @@ -62,6 +62,7 @@ const propTypes = { ownState: PropTypes.object, postTransformProps: PropTypes.func, source: PropTypes.oneOf([ChartSource.Dashboard, ChartSource.Explore]), + emitCrossFilters: PropTypes.bool, }; const BLANK = {}; @@ -142,7 +143,8 @@ class ChartRenderer extends React.Component { nextProps.sharedLabelColors !== this.props.sharedLabelColors || nextProps.formData.color_scheme !== this.props.formData.color_scheme || nextProps.formData.stack !== this.props.formData.stack || - nextProps.cacheBusterProp !== this.props.cacheBusterProp + nextProps.cacheBusterProp !== this.props.cacheBusterProp || + nextProps.emitCrossFilters !== this.props.emitCrossFilters ); } return false; @@ -223,7 +225,7 @@ class ChartRenderer extends React.Component { } render() { - const { chartAlert, chartStatus, chartId } = this.props; + const { chartAlert, chartStatus, chartId, emitCrossFilters } = this.props; // Skip chart rendering if (chartStatus === 'loading' || !!chartAlert || chartStatus === null) { @@ -341,6 +343,7 @@ class ChartRenderer extends React.Component { onRenderFailure={this.handleRenderFailure} noResults={noResultsComponent} postTransformProps={postTransformProps} + emitCrossFilters={emitCrossFilters} {...drillToDetailProps} /> diff --git a/superset-frontend/src/components/Checkbox/Checkbox.tsx b/superset-frontend/src/components/Checkbox/Checkbox.tsx index 7162929a967f0..249fca01841e1 100644 --- a/superset-frontend/src/components/Checkbox/Checkbox.tsx +++ b/superset-frontend/src/components/Checkbox/Checkbox.tsx @@ -24,6 +24,7 @@ export interface CheckboxProps { checked: boolean; onChange: (val?: boolean) => void; style?: React.CSSProperties; + className?: string; } const Styles = styled.span` @@ -33,7 +34,12 @@ const Styles = styled.span` } `; -export default function Checkbox({ checked, onChange, style }: CheckboxProps) { +export default function Checkbox({ + checked, + onChange, + style, + className, +}: CheckboxProps) { return ( {checked ? : } diff --git a/superset-frontend/src/components/Datasource/DatasourceEditor.test.jsx b/superset-frontend/src/components/Datasource/DatasourceEditor.test.jsx index 8d592d2d6eff7..9298287322692 100644 --- a/superset-frontend/src/components/Datasource/DatasourceEditor.test.jsx +++ b/superset-frontend/src/components/Datasource/DatasourceEditor.test.jsx @@ -24,13 +24,17 @@ import DatasourceEditor from 'src/components/Datasource/DatasourceEditor'; import mockDatasource from 'spec/fixtures/mockDatasource'; import * as featureFlags from 'src/featureFlags'; -jest.mock('src/components/Icons/Icon', () => ({ fileName, role, ...rest }) => ( - -)); +jest.mock('src/components/Icons/Icon', () => ({ + __esModule: true, + default: ({ fileName, role, ...rest }) => ( + + ), + StyledIcon: () => , +})); const props = { datasource: mockDatasource['7__table'], diff --git a/superset-frontend/src/components/DropdownSelectableIcon/index.tsx b/superset-frontend/src/components/DropdownSelectableIcon/index.tsx index b6c5d89a2e4e7..85c4284439f19 100644 --- a/superset-frontend/src/components/DropdownSelectableIcon/index.tsx +++ b/superset-frontend/src/components/DropdownSelectableIcon/index.tsx @@ -23,11 +23,20 @@ import { DropdownButton } from 'src/components/DropdownButton'; import { DropdownButtonProps } from 'antd/lib/dropdown'; import { Menu, MenuProps } from 'src/components/Menu'; +const { SubMenu } = Menu; + +type SubMenuItemProps = { key: string; label: string | React.ReactNode }; + export interface DropDownSelectableProps extends Pick { ref?: RefObject; icon: React.ReactNode; info?: string; - menuItems: { key: string; label: React.ReactNode }[]; + menuItems: { + key: string; + label: string | React.ReactNode; + children?: SubMenuItemProps[]; + divider?: boolean; + }[]; selectedKeys?: string[]; } @@ -67,17 +76,48 @@ const StyledMenu = styled(Menu)` color: ${theme.colors.grayscale.dark1}; background-color: ${theme.colors.primary.light5}; } - .ant-dropdown-menu-item > span.anticon { - float: right; - margin-right: 0; - font-size: ${theme.typography.sizes.xl}px; - } `} `; +const StyleMenuItem = styled(Menu.Item)<{ divider?: boolean }>` + display: flex; + justify-content: space-between; + > span { + width: 100%; + } + border-bottom: ${({ divider, theme }) => + divider ? `1px solid ${theme.colors.grayscale.light3};` : 'none;'}; +`; + +const StyleSubmenuItem = styled.div` + display: flex; + justify-content: space-between; + > span { + width: 100%; + } +`; + export default (props: DropDownSelectableProps) => { const theme = useTheme(); const { icon, info, menuItems, selectedKeys, onSelect } = props; + const menuItem = ( + label: string | React.ReactNode, + key: string, + divider?: boolean, + ) => ( + + + {label} + {selectedKeys?.includes(key) && ( + + )} + + + ); const overlayMenu = useMemo( () => ( @@ -86,14 +126,19 @@ export default (props: DropDownSelectableProps) => { {info} )} - {menuItems.map(m => ( - - {m.label} - {selectedKeys?.includes(m.key) && ( - - )} - - ))} + {menuItems.map(m => + m.children?.length ? ( + + {m.children.map(s => menuItem(s.label, s.key))} + + ) : ( + menuItem(m.label, m.key, m.divider) + ), + )} ), [info, menuItems], diff --git a/superset-frontend/src/components/FilterableTable/FilterableTable.test.tsx b/superset-frontend/src/components/FilterableTable/FilterableTable.test.tsx index 3135377cf7c2f..8cef35078dd06 100644 --- a/superset-frontend/src/components/FilterableTable/FilterableTable.test.tsx +++ b/superset-frontend/src/components/FilterableTable/FilterableTable.test.tsx @@ -21,7 +21,7 @@ import { ReactWrapper } from 'enzyme'; import { styledMount as mount } from 'spec/helpers/theming'; import FilterableTable, { MAX_COLUMNS_FOR_TABLE, - renderBigIntStrToNumber, + convertBigIntStrToNumber, } from 'src/components/FilterableTable'; import { render, screen } from 'spec/helpers/testing-library'; import userEvent from '@testing-library/user-event'; @@ -334,17 +334,17 @@ describe('FilterableTable sorting - RTL', () => { }); test('renders bigInt value in a number format', () => { - expect(renderBigIntStrToNumber('123')).toBe('123'); - expect(renderBigIntStrToNumber('some string value')).toBe( + expect(convertBigIntStrToNumber('123')).toBe('123'); + expect(convertBigIntStrToNumber('some string value')).toBe( 'some string value', ); - expect(renderBigIntStrToNumber('{ a: 123 }')).toBe('{ a: 123 }'); - expect(renderBigIntStrToNumber('"Not a Number"')).toBe('"Not a Number"'); + expect(convertBigIntStrToNumber('{ a: 123 }')).toBe('{ a: 123 }'); + expect(convertBigIntStrToNumber('"Not a Number"')).toBe('"Not a Number"'); // trim quotes for bigint string format - expect(renderBigIntStrToNumber('"-12345678901234567890"')).toBe( + expect(convertBigIntStrToNumber('"-12345678901234567890"')).toBe( '-12345678901234567890', ); - expect(renderBigIntStrToNumber('"12345678901234567890"')).toBe( + expect(convertBigIntStrToNumber('"12345678901234567890"')).toBe( '12345678901234567890', ); }); diff --git a/superset-frontend/src/components/FilterableTable/index.tsx b/superset-frontend/src/components/FilterableTable/index.tsx index 4d9098b2c2a40..e7e8f3ebf4c6b 100644 --- a/superset-frontend/src/components/FilterableTable/index.tsx +++ b/superset-frontend/src/components/FilterableTable/index.tsx @@ -63,13 +63,17 @@ function safeJsonObjectParse( } } -export function renderBigIntStrToNumber(value: string) { +export function convertBigIntStrToNumber(value: string | number) { if (typeof value === 'string' && /^"-?\d+"$/.test(value)) { return value.substring(1, value.length - 1); } return value; } +function renderBigIntStrToNumber(value: string | number) { + return <>{convertBigIntStrToNumber(value)}; +} + const GRID_POSITION_ADJUSTMENT = 4; const SCROLL_BAR_HEIGHT = 15; // This regex handles all possible number formats in javascript, including ints, floats, diff --git a/superset-frontend/src/components/Form/LabeledErrorBoundInput.test.jsx b/superset-frontend/src/components/Form/LabeledErrorBoundInput.test.jsx index 1202e31a1e382..a5cb80de2ff1a 100644 --- a/superset-frontend/src/components/Form/LabeledErrorBoundInput.test.jsx +++ b/superset-frontend/src/components/Form/LabeledErrorBoundInput.test.jsx @@ -81,13 +81,13 @@ describe('LabeledErrorBoundInput', () => { defaultProps.visibilityToggle = true; render(); - expect(await screen.findByRole('img', { name: /eye/i })).toBeVisible(); + expect(await screen.findByTestId('icon-eye')).toBeVisible(); }); it('becomes a password input if props.name === password (backwards compatibility)', async () => { defaultProps.name = 'password'; render(); - expect(await screen.findByRole('img', { name: /eye/i })).toBeVisible(); + expect(await screen.findByTestId('icon-eye')).toBeVisible(); }); }); diff --git a/superset-frontend/src/components/Form/LabeledErrorBoundInput.tsx b/superset-frontend/src/components/Form/LabeledErrorBoundInput.tsx index a99f5f89c8144..51cf104b271ca 100644 --- a/superset-frontend/src/components/Form/LabeledErrorBoundInput.tsx +++ b/superset-frontend/src/components/Form/LabeledErrorBoundInput.tsx @@ -18,9 +18,9 @@ */ import React from 'react'; import { Input, Tooltip } from 'antd'; -import { EyeInvisibleOutlined, EyeOutlined } from '@ant-design/icons'; import { styled, css, SupersetTheme, t } from '@superset-ui/core'; import InfoTooltip from 'src/components/InfoTooltip'; +import Icons from 'src/components/Icons'; import errorIcon from 'src/assets/images/icons/error.svg'; import FormItem from './FormItem'; import FormLabel from './FormLabel'; @@ -92,6 +92,12 @@ const StyledFormLabel = styled(FormLabel)` margin-bottom: 0; `; +const iconReset = css` + &.anticon > * { + line-height: 0; + } +`; + const LabeledErrorBoundInput = ({ label, validationMethods, @@ -128,11 +134,15 @@ const LabeledErrorBoundInput = ({ iconRender={visible => visible ? ( - + ) : ( - + ) } diff --git a/superset-frontend/src/components/ListView/ListView.test.jsx b/superset-frontend/src/components/ListView/ListView.test.jsx index 5faaa6d3c3440..c070fa926d861 100644 --- a/superset-frontend/src/components/ListView/ListView.test.jsx +++ b/superset-frontend/src/components/ListView/ListView.test.jsx @@ -35,7 +35,11 @@ import Pagination from 'src/components/Pagination/Wrapper'; import waitForComponentToPaint from 'spec/helpers/waitForComponentToPaint'; -jest.mock('src/components/Icons/Icon', () => () => ); +jest.mock('src/components/Icons/Icon', () => ({ + __esModule: true, + default: () => , + StyledIcon: () => , +})); function makeMockLocation(query) { const queryStr = encodeURIComponent(query); diff --git a/superset-frontend/src/components/ReportModal/HeaderReportDropdown/index.test.tsx b/superset-frontend/src/components/ReportModal/HeaderReportDropdown/index.test.tsx index af524a6b1e309..2d6d202799648 100644 --- a/superset-frontend/src/components/ReportModal/HeaderReportDropdown/index.test.tsx +++ b/superset-frontend/src/components/ReportModal/HeaderReportDropdown/index.test.tsx @@ -24,7 +24,11 @@ import HeaderReportDropdown, { HeaderReportProps } from '.'; let isFeatureEnabledMock: jest.MockInstance; -jest.mock('src/components/Icons/Icon', () => () => ); +jest.mock('src/components/Icons/Icon', () => ({ + __esModule: true, + default: () => , + StyledIcon: () => , +})); const createProps = () => ({ dashboardId: 1, diff --git a/superset-frontend/src/components/ReportModal/ReportModal.test.tsx b/superset-frontend/src/components/ReportModal/ReportModal.test.tsx index d33d7d62e1919..ad289cefe9a82 100644 --- a/superset-frontend/src/components/ReportModal/ReportModal.test.tsx +++ b/superset-frontend/src/components/ReportModal/ReportModal.test.tsx @@ -33,7 +33,11 @@ fetchMock.get(REPORT_ENDPOINT, {}); const NOOP = () => {}; -jest.mock('src/components/Icons/Icon', () => () => ); +jest.mock('src/components/Icons/Icon', () => ({ + __esModule: true, + default: () => , + StyledIcon: () => , +})); const defaultProps = { addDangerToast: NOOP, diff --git a/superset-frontend/src/components/Select/Select.test.tsx b/superset-frontend/src/components/Select/Select.test.tsx index 52f834d7cda0d..220ad4fe9875c 100644 --- a/superset-frontend/src/components/Select/Select.test.tsx +++ b/superset-frontend/src/components/Select/Select.test.tsx @@ -808,14 +808,21 @@ test('"Select All" is checked when unchecking a newly added option and all the o }); test('does not render "Select All" when there are 0 or 1 options', async () => { - render( + const { rerender } = render( , + ); expect(screen.queryByText(selectAllOptionLabel(1))).not.toBeInTheDocument(); - await type(`Kyle2{enter}`); + await type(`${NEW_OPTION}{enter}`); expect(screen.queryByText(selectAllOptionLabel(2))).toBeInTheDocument(); }); diff --git a/superset-frontend/src/components/Select/Select.tsx b/superset-frontend/src/components/Select/Select.tsx index 70ca4e6903342..68bc60871944d 100644 --- a/superset-frontend/src/components/Select/Select.tsx +++ b/superset-frontend/src/components/Select/Select.tsx @@ -178,8 +178,17 @@ const Select = forwardRef( }, [selectOptions, selectValue]); const selectAllEnabled = useMemo( - () => !isSingleMode && fullSelectOptions.length > 1 && !inputValue, - [fullSelectOptions, isSingleMode, inputValue], + () => + !isSingleMode && + selectOptions.length > 0 && + fullSelectOptions.length > 1 && + !inputValue, + [ + isSingleMode, + selectOptions.length, + fullSelectOptions.length, + inputValue, + ], ); const selectAllMode = useMemo( @@ -329,7 +338,7 @@ const Select = forwardRef( if ( !isSingleMode && ensureIsArray(value).length === fullSelectOptions.length && - fullSelectOptions.length > 0 + selectOptions.length > 0 ) { setSelectValue( labelInValue @@ -340,18 +349,24 @@ const Select = forwardRef( ] as AntdLabeledValue[]), ); } - }, [value, isSingleMode, labelInValue, fullSelectOptions.length]); + }, [ + value, + isSingleMode, + labelInValue, + fullSelectOptions.length, + selectOptions.length, + ]); useEffect(() => { const checkSelectAll = ensureIsArray(selectValue).some( v => getValue(v) === SELECT_ALL_VALUE, ); if (checkSelectAll && !selectAllMode) { - setSelectValue( - labelInValue - ? ([...fullSelectOptions, selectAllOption] as AntdLabeledValue[]) - : ([...fullSelectOptions, SELECT_ALL_VALUE] as AntdLabeledValue[]), + const optionsToSelect = fullSelectOptions.map(option => + labelInValue ? option : option.value, ); + optionsToSelect.push(labelInValue ? selectAllOption : SELECT_ALL_VALUE); + setSelectValue(optionsToSelect); } }, [selectValue, selectAllMode, labelInValue, fullSelectOptions]); @@ -467,6 +482,7 @@ const Select = forwardRef( {selectAllEnabled && (