From a12ccf2c1d3fe48f3e5e6fe5a08810aa3f57df37 Mon Sep 17 00:00:00 2001 From: Geido <60598000+geido@users.noreply.github.com> Date: Fri, 25 Oct 2024 19:11:28 +0300 Subject: [PATCH 001/307] fix(Jinja): Extra cache keys for Jinja columns (#30715) --- superset/connectors/sqla/models.py | 6 ++- tests/integration_tests/sqla_models_tests.py | 50 ++++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/superset/connectors/sqla/models.py b/superset/connectors/sqla/models.py index e8aa0d705b8f8..75354ad355d3d 100644 --- a/superset/connectors/sqla/models.py +++ b/superset/connectors/sqla/models.py @@ -116,7 +116,7 @@ ) from superset.utils import core as utils, json from superset.utils.backports import StrEnum -from superset.utils.core import GenericDataType, MediumText +from superset.utils.core import GenericDataType, is_adhoc_column, MediumText config = app.config metadata = Model.metadata # pylint: disable=no-member @@ -1980,6 +1980,10 @@ def has_extra_cache_key_calls(self, query_obj: QueryObjectDict) -> bool: templatable_statements.append(extras["where"]) if "having" in extras: templatable_statements.append(extras["having"]) + if "columns" in query_obj: + templatable_statements += [ + c["sqlExpression"] for c in query_obj["columns"] if is_adhoc_column(c) + ] if self.is_rls_supported: templatable_statements += [ f.clause for f in security_manager.get_rls_filters(self) diff --git a/tests/integration_tests/sqla_models_tests.py b/tests/integration_tests/sqla_models_tests.py index 2d7f6bf041bdd..79d4bf00ed028 100644 --- a/tests/integration_tests/sqla_models_tests.py +++ b/tests/integration_tests/sqla_models_tests.py @@ -911,6 +911,56 @@ def test_extra_cache_keys_in_sql_expression( assert extra_cache_keys == expected_cache_keys +@pytest.mark.usefixtures("app_context") +@pytest.mark.parametrize( + "sql_expression,expected_cache_keys,has_extra_cache_keys", + [ + ("'{{ current_username() }}'", ["abc"], True), + ("(user != 'abc')", [], False), + ], +) +@patch("superset.jinja_context.get_user_id", return_value=1) +@patch("superset.jinja_context.get_username", return_value="abc") +@patch("superset.jinja_context.get_user_email", return_value="abc@test.com") +def test_extra_cache_keys_in_columns( + mock_user_email, + mock_username, + mock_user_id, + sql_expression, + expected_cache_keys, + has_extra_cache_keys, +): + table = SqlaTable( + table_name="test_has_no_extra_cache_keys_table", + sql="SELECT 'abc' as user", + database=get_example_database(), + ) + base_query_obj = { + "granularity": None, + "from_dttm": None, + "to_dttm": None, + "groupby": [], + "metrics": [], + "is_timeseries": False, + "filter": [], + } + + query_obj = dict( + **base_query_obj, + columns=[ + { + "label": None, + "expressionType": "SQL", + "sqlExpression": sql_expression, + } + ], + ) + + extra_cache_keys = table.get_extra_cache_keys(query_obj) + assert table.has_extra_cache_key_calls(query_obj) == has_extra_cache_keys + assert extra_cache_keys == expected_cache_keys + + @pytest.mark.usefixtures("app_context") @pytest.mark.parametrize( "row,dimension,result", From 299cea060128ade18a8b22f0f79acdc2c8d00af5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 25 Oct 2024 15:03:49 -0600 Subject: [PATCH 002/307] build(deps-dev): bump http-proxy-middleware from 2.0.6 to 2.0.7 in /superset-frontend (#30709) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- superset-frontend/package-lock.json | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/superset-frontend/package-lock.json b/superset-frontend/package-lock.json index c19eafc75c2c4..83acfcd5349c3 100644 --- a/superset-frontend/package-lock.json +++ b/superset-frontend/package-lock.json @@ -28753,9 +28753,10 @@ "license": "MIT" }, "node_modules/http-proxy-middleware": { - "version": "2.0.6", + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.7.tgz", + "integrity": "sha512-fgVY8AV7qU7z/MmXJ/rxwbrtQH4jBQ9m7kp3llF0liB7glmFeVZFBepQb32T3y8n8k2+AEYuMPCpinYW+/CuRA==", "dev": true, - "license": "MIT", "dependencies": { "@types/http-proxy": "^1.17.8", "http-proxy": "^1.18.1", @@ -79802,7 +79803,9 @@ } }, "http-proxy-middleware": { - "version": "2.0.6", + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.7.tgz", + "integrity": "sha512-fgVY8AV7qU7z/MmXJ/rxwbrtQH4jBQ9m7kp3llF0liB7glmFeVZFBepQb32T3y8n8k2+AEYuMPCpinYW+/CuRA==", "dev": true, "requires": { "@types/http-proxy": "^1.17.8", From c03bf808643c1b35f4b6f7eb398d0408c29162a5 Mon Sep 17 00:00:00 2001 From: Max Forasteiro <18661016+maxforasteiro@users.noreply.github.com> Date: Sun, 27 Oct 2024 21:36:06 +0100 Subject: [PATCH 003/307] feat(helm-chart): Add extraLabels to all resources (#30710) --- helm/superset/Chart.yaml | 2 +- helm/superset/README.md | 3 ++- helm/superset/templates/configmap-superset.yaml | 3 +++ helm/superset/templates/deployment-beat.yaml | 6 ++++++ helm/superset/templates/deployment-flower.yaml | 6 ++++++ helm/superset/templates/deployment-worker.yaml | 6 ++++++ helm/superset/templates/deployment-ws.yaml | 6 ++++++ helm/superset/templates/deployment.yaml | 6 ++++++ helm/superset/templates/hpa-node.yaml | 3 +++ helm/superset/templates/hpa-worker.yaml | 3 +++ helm/superset/templates/ingress.yaml | 3 +++ helm/superset/templates/init-job.yaml | 4 ++++ helm/superset/templates/pdb-beat.yaml | 3 +++ helm/superset/templates/pdb-flower.yaml | 3 +++ helm/superset/templates/pdb-worker.yaml | 3 +++ helm/superset/templates/pdb-ws.yaml | 3 +++ helm/superset/templates/pdb.yaml | 3 +++ helm/superset/templates/secret-env.yaml | 3 +++ helm/superset/templates/secret-superset-config.yaml | 3 +++ helm/superset/templates/secret-ws.yaml | 3 +++ helm/superset/templates/service-flower.yaml | 3 +++ helm/superset/templates/service-ws.yaml | 3 +++ helm/superset/templates/service.yaml | 3 +++ helm/superset/templates/serviceaccount.yaml | 3 +++ helm/superset/values.yaml | 3 +++ 25 files changed, 88 insertions(+), 2 deletions(-) diff --git a/helm/superset/Chart.yaml b/helm/superset/Chart.yaml index 9ce9dd379be1b..2988973071a52 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.12.13 +version: 0.13.0 dependencies: - name: postgresql version: 12.1.6 diff --git a/helm/superset/README.md b/helm/superset/README.md index 5aeda56426aa7..796fddfd006ef 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.12.13](https://img.shields.io/badge/Version-0.12.13-informational?style=flat-square) +![Version: 0.13.0](https://img.shields.io/badge/Version-0.13.0-informational?style=flat-square) Apache Superset is a modern, enterprise-ready business intelligence web application @@ -69,6 +69,7 @@ On helm this can be set on `extraSecretEnv.SUPERSET_SECRET_KEY` or `configOverri | extraConfigs | object | `{}` | Extra files to mount on `/app/pythonpath` | | extraEnv | object | `{}` | Extra environment variables that will be passed into pods | | extraEnvRaw | list | `[]` | Extra environment variables in RAW format that will be passed into pods | +| extraLabels | object | `{}` | Labels to be added to all resources | | extraSecretEnv | object | `{}` | Extra environment variables to pass as secrets | | extraSecrets | object | `{}` | Extra files to mount on `/app/pythonpath` as secrets | | extraVolumeMounts | list | `[]` | | diff --git a/helm/superset/templates/configmap-superset.yaml b/helm/superset/templates/configmap-superset.yaml index 9ca29666d285a..fa0928c1fbc2c 100644 --- a/helm/superset/templates/configmap-superset.yaml +++ b/helm/superset/templates/configmap-superset.yaml @@ -28,6 +28,9 @@ metadata: chart: {{ template "superset.chart" . }} release: {{ .Release.Name }} heritage: {{ .Release.Service }} + {{- if .Values.extraLabels }} + {{- toYaml .Values.extraLabels | nindent 4 }} + {{- end }} data: {{- range $path, $config := .Values.extraConfigs }} {{ $path }}: | diff --git a/helm/superset/templates/deployment-beat.yaml b/helm/superset/templates/deployment-beat.yaml index df2fb1d2e909c..ff298f478d4d3 100644 --- a/helm/superset/templates/deployment-beat.yaml +++ b/helm/superset/templates/deployment-beat.yaml @@ -28,6 +28,9 @@ metadata: chart: {{ template "superset.chart" . }} release: {{ .Release.Name }} heritage: {{ .Release.Service }} + {{- if .Values.extraLabels }} + {{- toYaml .Values.extraLabels | nindent 4 }} + {{- end }} {{- if .Values.supersetCeleryBeat.deploymentAnnotations }} annotations: {{- toYaml .Values.supersetCeleryBeat.deploymentAnnotations | nindent 4 }} {{- end }} @@ -58,6 +61,9 @@ spec: labels: app: "{{ template "superset.name" . }}-celerybeat" release: {{ .Release.Name }} + {{- if .Values.extraLabels }} + {{- toYaml .Values.extraLabels | nindent 8 }} + {{- end }} {{- if .Values.supersetCeleryBeat.podLabels }} {{- toYaml .Values.supersetCeleryBeat.podLabels | nindent 8 }} {{- end }} diff --git a/helm/superset/templates/deployment-flower.yaml b/helm/superset/templates/deployment-flower.yaml index c03c8a19f6a29..179df9309dd49 100644 --- a/helm/superset/templates/deployment-flower.yaml +++ b/helm/superset/templates/deployment-flower.yaml @@ -28,6 +28,9 @@ metadata: chart: {{ template "superset.chart" . }} release: {{ .Release.Name }} heritage: {{ .Release.Service }} + {{- if .Values.extraLabels }} + {{- toYaml .Values.extraLabels | nindent 4 }} + {{- end }} {{- if .Values.supersetCeleryFlower.deploymentAnnotations }} annotations: {{- toYaml .Values.supersetCeleryFlower.deploymentAnnotations | nindent 4 }} {{- end }} @@ -47,6 +50,9 @@ spec: labels: app: "{{ template "superset.name" . }}-flower" release: {{ .Release.Name }} + {{- if .Values.extraLabels }} + {{- toYaml .Values.extraLabels | nindent 8 }} + {{- end }} {{- if .Values.supersetCeleryFlower.podLabels }} {{- toYaml .Values.supersetCeleryFlower.podLabels | nindent 8 }} {{- end }} diff --git a/helm/superset/templates/deployment-worker.yaml b/helm/superset/templates/deployment-worker.yaml index 214f9215f7295..96ee915f290ef 100644 --- a/helm/superset/templates/deployment-worker.yaml +++ b/helm/superset/templates/deployment-worker.yaml @@ -27,6 +27,9 @@ metadata: chart: {{ template "superset.chart" . }} release: {{ .Release.Name }} heritage: {{ .Release.Service }} + {{- if .Values.extraLabels }} + {{- toYaml .Values.extraLabels | nindent 4 }} + {{- end }} {{- if .Values.supersetWorker.deploymentLabels }} {{- toYaml .Values.supersetWorker.deploymentLabels | nindent 4 }} {{- end }} @@ -64,6 +67,9 @@ spec: labels: app: {{ template "superset.name" . }}-worker release: {{ .Release.Name }} + {{- if .Values.extraLabels }} + {{- toYaml .Values.extraLabels | nindent 8 }} + {{- end }} {{- if .Values.supersetWorker.podLabels }} {{- toYaml .Values.supersetWorker.podLabels | nindent 8 }} {{- end }} diff --git a/helm/superset/templates/deployment-ws.yaml b/helm/superset/templates/deployment-ws.yaml index f9ac663be936d..868b84309ffbb 100644 --- a/helm/superset/templates/deployment-ws.yaml +++ b/helm/superset/templates/deployment-ws.yaml @@ -28,6 +28,9 @@ metadata: chart: {{ template "superset.chart" . }} release: {{ .Release.Name }} heritage: {{ .Release.Service }} + {{- if .Values.extraLabels }} + {{- toYaml .Values.extraLabels | nindent 4 }} + {{- end }} {{- if .Values.supersetWebsockets.deploymentAnnotations }} annotations: {{- toYaml .Values.supersetWebsockets.deploymentAnnotations | nindent 4 }} {{- end }} @@ -50,6 +53,9 @@ spec: labels: app: "{{ template "superset.name" . }}-ws" release: {{ .Release.Name }} + {{- if .Values.extraLabels }} + {{- toYaml .Values.extraLabels | nindent 8 }} + {{- end }} {{- if .Values.supersetWebsockets.podLabels }} {{- toYaml .Values.supersetWebsockets.podLabels | nindent 8 }} {{- end }} diff --git a/helm/superset/templates/deployment.yaml b/helm/superset/templates/deployment.yaml index 60eddc4165a4a..444ec103da66c 100644 --- a/helm/superset/templates/deployment.yaml +++ b/helm/superset/templates/deployment.yaml @@ -27,6 +27,9 @@ metadata: chart: {{ template "superset.chart" . }} release: {{ .Release.Name }} heritage: {{ .Release.Service }} + {{- if .Values.extraLabels }} + {{- toYaml .Values.extraLabels | nindent 4 }} + {{- end }} {{- if .Values.supersetNode.deploymentLabels }} {{- toYaml .Values.supersetNode.deploymentLabels | nindent 4 }} {{- end }} @@ -66,6 +69,9 @@ spec: labels: app: {{ template "superset.name" . }} release: {{ .Release.Name }} + {{- if .Values.extraLabels }} + {{- toYaml .Values.extraLabels | nindent 8 }} + {{- end }} {{- if .Values.supersetNode.podLabels }} {{- toYaml .Values.supersetNode.podLabels | nindent 8 }} {{- end }} diff --git a/helm/superset/templates/hpa-node.yaml b/helm/superset/templates/hpa-node.yaml index aee2d1da78fd8..843620ea15e66 100644 --- a/helm/superset/templates/hpa-node.yaml +++ b/helm/superset/templates/hpa-node.yaml @@ -27,6 +27,9 @@ metadata: chart: {{ template "superset.chart" . }} release: {{ .Release.Name }} heritage: {{ .Release.Service }} + {{- if .Values.extraLabels }} + {{- toYaml .Values.extraLabels | nindent 4 }} + {{- end }} spec: scaleTargetRef: apiVersion: apps/v1 diff --git a/helm/superset/templates/hpa-worker.yaml b/helm/superset/templates/hpa-worker.yaml index f2fd2154a46a4..fd4f027cc6b39 100644 --- a/helm/superset/templates/hpa-worker.yaml +++ b/helm/superset/templates/hpa-worker.yaml @@ -27,6 +27,9 @@ metadata: chart: {{ template "superset.chart" . }} release: {{ .Release.Name }} heritage: {{ .Release.Service }} + {{- if .Values.extraLabels }} + {{- toYaml .Values.extraLabels | nindent 4 }} + {{- end }} spec: scaleTargetRef: apiVersion: apps/v1 diff --git a/helm/superset/templates/ingress.yaml b/helm/superset/templates/ingress.yaml index 749c29134e2cf..05acb20d6ffce 100644 --- a/helm/superset/templates/ingress.yaml +++ b/helm/superset/templates/ingress.yaml @@ -29,6 +29,9 @@ metadata: chart: {{ template "superset.chart" . }} release: {{ .Release.Name }} heritage: {{ .Release.Service }} + {{- if .Values.extraLabels }} + {{- toYaml .Values.extraLabels | nindent 4 }} + {{- end }} {{- with .Values.ingress.annotations }} annotations: {{- toYaml . | nindent 4 }} {{- end }} diff --git a/helm/superset/templates/init-job.yaml b/helm/superset/templates/init-job.yaml index ecc51490ef99f..0cb46e816b0ea 100644 --- a/helm/superset/templates/init-job.yaml +++ b/helm/superset/templates/init-job.yaml @@ -23,6 +23,10 @@ kind: Job metadata: name: {{ template "superset.fullname" . }}-init-db namespace: {{ .Release.Namespace }} + {{- if .Values.extraLabels }} + labels: + {{- toYaml .Values.extraLabels | nindent 4 }} + {{- end }} {{- if .Values.init.jobAnnotations }} annotations: {{- toYaml .Values.init.jobAnnotations | nindent 4 }} {{- end }} diff --git a/helm/superset/templates/pdb-beat.yaml b/helm/superset/templates/pdb-beat.yaml index de808b475c166..91cf5ddc58503 100644 --- a/helm/superset/templates/pdb-beat.yaml +++ b/helm/superset/templates/pdb-beat.yaml @@ -31,6 +31,9 @@ metadata: chart: {{ template "superset.chart" $ }} release: {{ $.Release.Name }} heritage: {{ $.Release.Service }} + {{- if .Values.extraLabels }} + {{- toYaml .Values.extraLabels | nindent 4 }} + {{- end }} spec: {{- if .minAvailable }} minAvailable: {{ .minAvailable }} diff --git a/helm/superset/templates/pdb-flower.yaml b/helm/superset/templates/pdb-flower.yaml index 363ec7a42aebd..241de3143cd7e 100644 --- a/helm/superset/templates/pdb-flower.yaml +++ b/helm/superset/templates/pdb-flower.yaml @@ -31,6 +31,9 @@ metadata: chart: {{ template "superset.chart" $ }} release: {{ $.Release.Name }} heritage: {{ $.Release.Service }} + {{- if .Values.extraLabels }} + {{- toYaml .Values.extraLabels | nindent 4 }} + {{- end }} spec: {{- if .minAvailable }} minAvailable: {{ .minAvailable }} diff --git a/helm/superset/templates/pdb-worker.yaml b/helm/superset/templates/pdb-worker.yaml index 163662261664d..d4ec768fba2a5 100644 --- a/helm/superset/templates/pdb-worker.yaml +++ b/helm/superset/templates/pdb-worker.yaml @@ -31,6 +31,9 @@ metadata: chart: {{ template "superset.chart" $ }} release: {{ $.Release.Name }} heritage: {{ $.Release.Service }} + {{- if .Values.extraLabels }} + {{- toYaml .Values.extraLabels | nindent 4 }} + {{- end }} spec: {{- if .minAvailable }} minAvailable: {{ .minAvailable }} diff --git a/helm/superset/templates/pdb-ws.yaml b/helm/superset/templates/pdb-ws.yaml index 647d6b49447d4..0e303880aa115 100644 --- a/helm/superset/templates/pdb-ws.yaml +++ b/helm/superset/templates/pdb-ws.yaml @@ -31,6 +31,9 @@ metadata: chart: {{ template "superset.chart" $ }} release: {{ $.Release.Name }} heritage: {{ $.Release.Service }} + {{- if .Values.extraLabels }} + {{- toYaml .Values.extraLabels | nindent 4 }} + {{- end }} spec: {{- if .minAvailable }} minAvailable: {{ .minAvailable }} diff --git a/helm/superset/templates/pdb.yaml b/helm/superset/templates/pdb.yaml index 0d825343d3147..3f86836f68d3b 100644 --- a/helm/superset/templates/pdb.yaml +++ b/helm/superset/templates/pdb.yaml @@ -31,6 +31,9 @@ metadata: chart: {{ template "superset.chart" $ }} release: {{ $.Release.Name }} heritage: {{ $.Release.Service }} + {{- if .Values.extraLabels }} + {{- toYaml .Values.extraLabels | nindent 4 }} + {{- end }} spec: {{- if .minAvailable }} minAvailable: {{ .minAvailable }} diff --git a/helm/superset/templates/secret-env.yaml b/helm/superset/templates/secret-env.yaml index 653799496076d..04169ad15050f 100644 --- a/helm/superset/templates/secret-env.yaml +++ b/helm/superset/templates/secret-env.yaml @@ -27,6 +27,9 @@ metadata: chart: {{ template "superset.chart" . }} release: "{{ .Release.Name }}" heritage: "{{ .Release.Service }}" + {{- if .Values.extraLabels }} + {{- toYaml .Values.extraLabels | nindent 4 }} + {{- end }} type: Opaque stringData: REDIS_HOST: {{ tpl .Values.supersetNode.connections.redis_host . | quote }} diff --git a/helm/superset/templates/secret-superset-config.yaml b/helm/superset/templates/secret-superset-config.yaml index 41a051fa03708..c672fe900b09e 100644 --- a/helm/superset/templates/secret-superset-config.yaml +++ b/helm/superset/templates/secret-superset-config.yaml @@ -27,6 +27,9 @@ metadata: chart: {{ template "superset.chart" . }} release: "{{ .Release.Name }}" heritage: "{{ .Release.Service }}" + {{- if .Values.extraLabels }} + {{- toYaml .Values.extraLabels | nindent 4 }} + {{- end }} type: Opaque stringData: superset_config.py: | diff --git a/helm/superset/templates/secret-ws.yaml b/helm/superset/templates/secret-ws.yaml index aaa9a24587a33..a559ac0056ada 100644 --- a/helm/superset/templates/secret-ws.yaml +++ b/helm/superset/templates/secret-ws.yaml @@ -28,6 +28,9 @@ metadata: chart: {{ template "superset.chart" . }} release: "{{ .Release.Name }}" heritage: "{{ .Release.Service }}" + {{- if .Values.extraLabels }} + {{- toYaml .Values.extraLabels | nindent 4 }} + {{- end }} type: Opaque stringData: config.json: | diff --git a/helm/superset/templates/service-flower.yaml b/helm/superset/templates/service-flower.yaml index 8c198891b0a57..c2bda0fb86ba3 100644 --- a/helm/superset/templates/service-flower.yaml +++ b/helm/superset/templates/service-flower.yaml @@ -28,6 +28,9 @@ metadata: chart: {{ template "superset.chart" . }} release: {{ .Release.Name }} heritage: {{ .Release.Service }} + {{- if .Values.extraLabels }} + {{- toYaml .Values.extraLabels | nindent 4 }} + {{- end }} {{- with .Values.supersetCeleryFlower.service.annotations }} annotations: {{- toYaml . | nindent 4 }} {{- end }} diff --git a/helm/superset/templates/service-ws.yaml b/helm/superset/templates/service-ws.yaml index 3dd02b77a6d2e..1517e2e5772e3 100644 --- a/helm/superset/templates/service-ws.yaml +++ b/helm/superset/templates/service-ws.yaml @@ -28,6 +28,9 @@ metadata: chart: {{ template "superset.chart" . }} release: {{ .Release.Name }} heritage: {{ .Release.Service }} + {{- if .Values.extraLabels }} + {{- toYaml .Values.extraLabels | nindent 4 }} + {{- end }} {{- with .Values.supersetWebsockets.service.annotations }} annotations: {{- toYaml . | nindent 4 }} {{- end }} diff --git a/helm/superset/templates/service.yaml b/helm/superset/templates/service.yaml index f20c80c78d9ce..e435961ba9b6d 100644 --- a/helm/superset/templates/service.yaml +++ b/helm/superset/templates/service.yaml @@ -27,6 +27,9 @@ metadata: chart: {{ template "superset.chart" . }} release: {{ .Release.Name }} heritage: {{ .Release.Service }} + {{- if .Values.extraLabels }} + {{- toYaml .Values.extraLabels | nindent 4 }} + {{- end }} {{- with .Values.service.annotations }} annotations: {{- toYaml . | nindent 4 }} {{- end }} diff --git a/helm/superset/templates/serviceaccount.yaml b/helm/superset/templates/serviceaccount.yaml index 0c2cfb30efa34..e92fc6202fa0b 100644 --- a/helm/superset/templates/serviceaccount.yaml +++ b/helm/superset/templates/serviceaccount.yaml @@ -32,6 +32,9 @@ metadata: kubernetes.io/cluster-service: "true" {{- end }} addonmanager.kubernetes.io/mode: Reconcile + {{- if .Values.extraLabels }} + {{- toYaml .Values.extraLabels | nindent 4 }} + {{- end }} {{- if .Values.serviceAccount.annotations }} annotations: {{- toYaml .Values.serviceAccount.annotations | nindent 4 }} {{- end }} diff --git a/helm/superset/values.yaml b/helm/superset/values.yaml index c0fcda027edb9..7bd2a7b20a287 100644 --- a/helm/superset/values.yaml +++ b/helm/superset/values.yaml @@ -27,6 +27,9 @@ nameOverride: ~ # -- Provide a name to override the full names of resources fullnameOverride: ~ +# -- Labels to be added to all resources +extraLabels: {} + # -- User ID directive. This user must have enough permissions to run the bootstrap script # Running containers as root is not recommended in production. Change this to another UID - e.g. 1000 to be more secure runAsUser: 0 From 09d3f60d85c1e1bf5f030191ee78522b8f414705 Mon Sep 17 00:00:00 2001 From: Vitor Avila <96086495+Vitor-Avila@users.noreply.github.com> Date: Tue, 29 Oct 2024 10:14:27 -0300 Subject: [PATCH 004/307] fix(Jinja): Extra cache keys for calculated columns and metrics using Jinja (#30735) --- superset/connectors/sqla/models.py | 51 +++++++----- tests/integration_tests/sqla_models_tests.py | 83 +++++++++++++++----- 2 files changed, 98 insertions(+), 36 deletions(-) diff --git a/superset/connectors/sqla/models.py b/superset/connectors/sqla/models.py index 75354ad355d3d..fb7409adba589 100644 --- a/superset/connectors/sqla/models.py +++ b/superset/connectors/sqla/models.py @@ -116,7 +116,6 @@ ) from superset.utils import core as utils, json from superset.utils.backports import StrEnum -from superset.utils.core import GenericDataType, is_adhoc_column, MediumText config = app.config metadata = Model.metadata # pylint: disable=no-member @@ -477,7 +476,7 @@ def data_for_slices( # pylint: disable=too-many-locals ] filtered_columns: list[Column] = [] - column_types: set[GenericDataType] = set() + column_types: set[utils.GenericDataType] = set() for column_ in data["columns"]: generic_type = column_.get("type_generic") if generic_type is not None: @@ -511,7 +510,7 @@ def data_for_slices( # pylint: disable=too-many-locals def filter_values_handler( # pylint: disable=too-many-arguments values: FilterValues | None, operator: str, - target_generic_type: GenericDataType, + target_generic_type: utils.GenericDataType, target_native_type: str | None = None, is_list_target: bool = False, db_engine_spec: builtins.type[BaseEngineSpec] | None = None, @@ -829,10 +828,10 @@ class TableColumn(AuditMixinNullable, ImportExportMixin, CertificationMixin, Mod advanced_data_type = Column(String(255)) groupby = Column(Boolean, default=True) filterable = Column(Boolean, default=True) - description = Column(MediumText()) + description = Column(utils.MediumText()) table_id = Column(Integer, ForeignKey("tables.id", ondelete="CASCADE")) is_dttm = Column(Boolean, default=False) - expression = Column(MediumText()) + expression = Column(utils.MediumText()) python_date_format = Column(String(255)) extra = Column(Text) @@ -892,21 +891,21 @@ def is_boolean(self) -> bool: """ Check if the column has a boolean datatype. """ - return self.type_generic == GenericDataType.BOOLEAN + return self.type_generic == utils.GenericDataType.BOOLEAN @property def is_numeric(self) -> bool: """ Check if the column has a numeric datatype. """ - return self.type_generic == GenericDataType.NUMERIC + return self.type_generic == utils.GenericDataType.NUMERIC @property def is_string(self) -> bool: """ Check if the column has a string datatype. """ - return self.type_generic == GenericDataType.STRING + return self.type_generic == utils.GenericDataType.STRING @property def is_temporal(self) -> bool: @@ -918,7 +917,7 @@ def is_temporal(self) -> bool: """ if self.is_dttm is not None: return self.is_dttm - return self.type_generic == GenericDataType.TEMPORAL + return self.type_generic == utils.GenericDataType.TEMPORAL @property def database(self) -> Database: @@ -935,7 +934,7 @@ def db_extra(self) -> dict[str, Any]: @property def type_generic(self) -> utils.GenericDataType | None: if self.is_dttm: - return GenericDataType.TEMPORAL + return utils.GenericDataType.TEMPORAL return ( column_spec.generic_type @@ -1038,12 +1037,12 @@ class SqlMetric(AuditMixinNullable, ImportExportMixin, CertificationMixin, Model metric_name = Column(String(255), nullable=False) verbose_name = Column(String(1024)) metric_type = Column(String(32)) - description = Column(MediumText()) + description = Column(utils.MediumText()) d3format = Column(String(128)) currency = Column(String(128)) warning_text = Column(Text) table_id = Column(Integer, ForeignKey("tables.id", ondelete="CASCADE")) - expression = Column(MediumText(), nullable=False) + expression = Column(utils.MediumText(), nullable=False) extra = Column(Text) table: Mapped[SqlaTable] = relationship( @@ -1185,7 +1184,7 @@ class SqlaTable( ) schema = Column(String(255)) catalog = Column(String(256), nullable=True, default=None) - sql = Column(MediumText()) + sql = Column(utils.MediumText()) is_sqllab_view = Column(Boolean, default=False) template_params = Column(Text) extra = Column(Text) @@ -1980,10 +1979,26 @@ def has_extra_cache_key_calls(self, query_obj: QueryObjectDict) -> bool: templatable_statements.append(extras["where"]) if "having" in extras: templatable_statements.append(extras["having"]) - if "columns" in query_obj: - templatable_statements += [ - c["sqlExpression"] for c in query_obj["columns"] if is_adhoc_column(c) - ] + if columns := query_obj.get("columns"): + calculated_columns: dict[str, Any] = { + c.column_name: c.expression for c in self.columns if c.expression + } + for column_ in columns: + if utils.is_adhoc_column(column_): + templatable_statements.append(column_["sqlExpression"]) + elif isinstance(column_, str) and column_ in calculated_columns: + templatable_statements.append(calculated_columns[column_]) + if metrics := query_obj.get("metrics"): + metrics_by_name: dict[str, Any] = { + m.metric_name: m.expression for m in self.metrics + } + for metric in metrics: + if utils.is_adhoc_metric(metric) and ( + sql := metric.get("sqlExpression") + ): + templatable_statements.append(sql) + elif isinstance(metric, str) and metric in metrics_by_name: + templatable_statements.append(metrics_by_name[metric]) if self.is_rls_supported: templatable_statements += [ f.clause for f in security_manager.get_rls_filters(self) @@ -2125,4 +2140,4 @@ class RowLevelSecurityFilter(Model, AuditMixinNullable): secondary=RLSFilterTables, backref="row_level_security_filters", ) - clause = Column(MediumText(), nullable=False) + clause = Column(utils.MediumText(), nullable=False) diff --git a/tests/integration_tests/sqla_models_tests.py b/tests/integration_tests/sqla_models_tests.py index 79d4bf00ed028..d4ca3bc1c1a47 100644 --- a/tests/integration_tests/sqla_models_tests.py +++ b/tests/integration_tests/sqla_models_tests.py @@ -15,11 +15,13 @@ # specific language governing permissions and limitations # under the License. # isort:skip_file +from __future__ import annotations + import re from datetime import datetime -from typing import Any, NamedTuple, Optional, Union +from typing import Any, Literal, NamedTuple, Optional, Union from re import Pattern -from unittest.mock import patch +from unittest.mock import Mock, patch import pytest import numpy as np @@ -913,54 +915,99 @@ def test_extra_cache_keys_in_sql_expression( @pytest.mark.usefixtures("app_context") @pytest.mark.parametrize( - "sql_expression,expected_cache_keys,has_extra_cache_keys", + "sql_expression,expected_cache_keys,has_extra_cache_keys,item_type", [ - ("'{{ current_username() }}'", ["abc"], True), - ("(user != 'abc')", [], False), + ("'{{ current_username() }}'", ["abc"], True, "columns"), + ("(user != 'abc')", [], False, "columns"), + ("{{ current_user_id() }}", [1], True, "metrics"), + ("COUNT(*)", [], False, "metrics"), ], ) @patch("superset.jinja_context.get_user_id", return_value=1) @patch("superset.jinja_context.get_username", return_value="abc") -@patch("superset.jinja_context.get_user_email", return_value="abc@test.com") -def test_extra_cache_keys_in_columns( - mock_user_email, - mock_username, - mock_user_id, - sql_expression, - expected_cache_keys, - has_extra_cache_keys, +def test_extra_cache_keys_in_adhoc_metrics_and_columns( + mock_username: Mock, + mock_user_id: Mock, + sql_expression: str, + expected_cache_keys: list[str | None], + has_extra_cache_keys: bool, + item_type: Literal["columns", "metrics"], ): table = SqlaTable( table_name="test_has_no_extra_cache_keys_table", sql="SELECT 'abc' as user", database=get_example_database(), ) - base_query_obj = { + base_query_obj: dict[str, Any] = { "granularity": None, "from_dttm": None, "to_dttm": None, "groupby": [], "metrics": [], + "columns": [], "is_timeseries": False, "filter": [], } - query_obj = dict( - **base_query_obj, - columns=[ + items: dict[str, Any] = { + item_type: [ { "label": None, "expressionType": "SQL", "sqlExpression": sql_expression, } ], - ) + } + + query_obj = {**base_query_obj, **items} extra_cache_keys = table.get_extra_cache_keys(query_obj) assert table.has_extra_cache_key_calls(query_obj) == has_extra_cache_keys assert extra_cache_keys == expected_cache_keys +@pytest.mark.usefixtures("app_context") +@patch("superset.jinja_context.get_user_id", return_value=1) +@patch("superset.jinja_context.get_username", return_value="abc") +def test_extra_cache_keys_in_dataset_metrics_and_columns( + mock_username: Mock, + mock_user_id: Mock, +): + table = SqlaTable( + table_name="test_has_no_extra_cache_keys_table", + sql="SELECT 'abc' as user", + database=get_example_database(), + columns=[ + TableColumn(column_name="user", type="VARCHAR(255)"), + TableColumn( + column_name="username", + type="VARCHAR(255)", + expression="{{ current_username() }}", + ), + ], + metrics=[ + SqlMetric( + metric_name="variable_profit", + expression="SUM(price) * {{ url_param('multiplier') }}", + ), + ], + ) + query_obj: dict[str, Any] = { + "granularity": None, + "from_dttm": None, + "to_dttm": None, + "groupby": [], + "columns": ["username"], + "metrics": ["variable_profit"], + "is_timeseries": False, + "filter": [], + } + + extra_cache_keys = table.get_extra_cache_keys(query_obj) + assert table.has_extra_cache_key_calls(query_obj) is True + assert set(extra_cache_keys) == {"abc", None} + + @pytest.mark.usefixtures("app_context") @pytest.mark.parametrize( "row,dimension,result", From eecb53780823460bd49e6db53ea1fe3960da1f14 Mon Sep 17 00:00:00 2001 From: Phil Dumbreck <29596014+padbk@users.noreply.github.com> Date: Tue, 29 Oct 2024 16:16:23 +0000 Subject: [PATCH 005/307] ci: Add Python 3.11 images to Docker Hub (#30733) --- .github/workflows/docker.yml | 2 +- .github/workflows/tag-release.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index c8c4756ea543c..287026c084412 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -21,7 +21,7 @@ jobs: steps: - id: set_matrix run: | - MATRIX_CONFIG=$(if [ "${{ github.event_name }}" == "pull_request" ]; then echo '["dev"]'; else echo '["dev", "lean", "py310", "websocket", "dockerize"]'; fi) + MATRIX_CONFIG=$(if [ "${{ github.event_name }}" == "pull_request" ]; then echo '["dev"]'; else echo '["dev", "lean", "py310", "websocket", "dockerize", "py311"]'; fi) echo "matrix_config=${MATRIX_CONFIG}" >> $GITHUB_OUTPUT echo $GITHUB_OUTPUT diff --git a/.github/workflows/tag-release.yml b/.github/workflows/tag-release.yml index 52e8067aaf819..ec06bc8e1cf63 100644 --- a/.github/workflows/tag-release.yml +++ b/.github/workflows/tag-release.yml @@ -42,7 +42,7 @@ jobs: runs-on: ubuntu-22.04 strategy: matrix: - build_preset: ["dev", "lean", "py310", "websocket", "dockerize"] + build_preset: ["dev", "lean", "py310", "websocket", "dockerize", "py311"] fail-fast: false steps: - name: Set up QEMU From b9ac800bfb087ee5c08bbfa41e9362d0cadf3f87 Mon Sep 17 00:00:00 2001 From: Sam Firke Date: Tue, 29 Oct 2024 13:00:46 -0400 Subject: [PATCH 006/307] docs(templating): Replace "true" with "1 = 1" and explain its purpose (#30743) --- docs/docs/configuration/sql-templating.mdx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/docs/docs/configuration/sql-templating.mdx b/docs/docs/configuration/sql-templating.mdx index 64caea2157579..39bea00d85b00 100644 --- a/docs/docs/configuration/sql-templating.mdx +++ b/docs/docs/configuration/sql-templating.mdx @@ -48,12 +48,15 @@ WHERE ( {% if to_dttm is not none %} dttm_col < '{{ to_dttm }}' AND {% endif %} - true + 1 = 1 ) ``` -Note how the Jinja parameters are called within double brackets in the query, and without in the -logic blocks. +The `1 = 1` at the end ensures a value is present for the `WHERE` clause even when +the time filter is not set. For many database engines, this could be replaced with `true`. + +Note that the Jinja parameters are called within _double_ brackets in the query and with +_single_ brackets in the logic blocks. To add custom functionality to the Jinja context, you need to overload the default Jinja context in your environment by defining the `JINJA_CONTEXT_ADDONS` in your superset configuration From fbd7c0ce0151383c30e38aef55439d6da8a8866a Mon Sep 17 00:00:00 2001 From: wugeer <1284057728@qq.com> Date: Wed, 30 Oct 2024 01:12:23 +0800 Subject: [PATCH 007/307] docs: rename Twitter to X in the INTHEWILD.md (#30738) --- RESOURCES/INTHEWILD.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RESOURCES/INTHEWILD.md b/RESOURCES/INTHEWILD.md index 4ec5b6ac1e1f9..1af6c1be8abeb 100644 --- a/RESOURCES/INTHEWILD.md +++ b/RESOURCES/INTHEWILD.md @@ -183,6 +183,6 @@ Join our growing community! - [komoot](https://www.komoot.com/) [@christophlingg] - [Let's Roam](https://www.letsroam.com/) - [Onebeat](https://1beat.com/) [@GuyAttia] -- [Twitter](https://twitter.com/) +- [X](https://x.com/) - [VLMedia](https://www.vlmedia.com.tr/) [@ibotheperfect] - [Yahoo!](https://yahoo.com/) From bdb79a0630844dd61aa8abed47585b58435ea013 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 29 Oct 2024 12:24:13 -0600 Subject: [PATCH 008/307] build(deps): bump cookie, cookie-parser and express in /superset-websocket/utils/client-ws-app (#30571) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .../utils/client-ws-app/package-lock.json | 76 +++++++++---------- .../utils/client-ws-app/package.json | 4 +- 2 files changed, 39 insertions(+), 41 deletions(-) diff --git a/superset-websocket/utils/client-ws-app/package-lock.json b/superset-websocket/utils/client-ws-app/package-lock.json index 22d435f46167b..8d84e04a3f9e5 100644 --- a/superset-websocket/utils/client-ws-app/package-lock.json +++ b/superset-websocket/utils/client-ws-app/package-lock.json @@ -8,9 +8,9 @@ "name": "client-ws-app", "version": "0.0.0", "dependencies": { - "cookie-parser": "~1.4.6", + "cookie-parser": "~1.4.7", "debug": "~4.3.7", - "express": "~4.21.0", + "express": "~4.21.1", "http-errors": "~2.0.0", "jsonwebtoken": "^9.0.2", "morgan": "~1.10.0", @@ -242,33 +242,25 @@ } }, "node_modules/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", "engines": { "node": ">= 0.6" } }, "node_modules/cookie-parser": { - "version": "1.4.6", - "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.6.tgz", - "integrity": "sha512-z3IzaNjdwUC2olLIB5/ITd0/setiaFMLYiZJle7xg5Fe9KWAceil7xszYfHHBtDFYLSgJduS2Ty0P1uJdPDJeA==", + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.7.tgz", + "integrity": "sha512-nGUvgXnotP3BsjiLX2ypbQnWoGUPIIfHQNZkkC668ntrzGWEZVW70HDEB1qnNGMicPje6EttlIgzo51YSwNQGw==", "dependencies": { - "cookie": "0.4.1", + "cookie": "0.7.2", "cookie-signature": "1.0.6" }, "engines": { "node": ">= 0.8.0" } }, - "node_modules/cookie-parser/node_modules/cookie": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", - "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==", - "engines": { - "node": ">= 0.6" - } - }, "node_modules/cookie-signature": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", @@ -382,16 +374,16 @@ } }, "node_modules/express": { - "version": "4.21.0", - "resolved": "https://registry.npmjs.org/express/-/express-4.21.0.tgz", - "integrity": "sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng==", + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz", + "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.6.0", + "cookie": "0.7.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", @@ -422,6 +414,14 @@ "node": ">= 0.10.0" } }, + "node_modules/express/node_modules/cookie": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/express/node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -1545,24 +1545,17 @@ "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==" }, "cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==" + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==" }, "cookie-parser": { - "version": "1.4.6", - "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.6.tgz", - "integrity": "sha512-z3IzaNjdwUC2olLIB5/ITd0/setiaFMLYiZJle7xg5Fe9KWAceil7xszYfHHBtDFYLSgJduS2Ty0P1uJdPDJeA==", + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.7.tgz", + "integrity": "sha512-nGUvgXnotP3BsjiLX2ypbQnWoGUPIIfHQNZkkC668ntrzGWEZVW70HDEB1qnNGMicPje6EttlIgzo51YSwNQGw==", "requires": { - "cookie": "0.4.1", + "cookie": "0.7.2", "cookie-signature": "1.0.6" - }, - "dependencies": { - "cookie": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", - "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==" - } } }, "cookie-signature": { @@ -1645,16 +1638,16 @@ "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" }, "express": { - "version": "4.21.0", - "resolved": "https://registry.npmjs.org/express/-/express-4.21.0.tgz", - "integrity": "sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng==", + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz", + "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==", "requires": { "accepts": "~1.3.8", "array-flatten": "1.1.1", "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.6.0", + "cookie": "0.7.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", @@ -1682,6 +1675,11 @@ "vary": "~1.1.2" }, "dependencies": { + "cookie": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==" + }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", diff --git a/superset-websocket/utils/client-ws-app/package.json b/superset-websocket/utils/client-ws-app/package.json index 787a238513af5..adfb201c46041 100644 --- a/superset-websocket/utils/client-ws-app/package.json +++ b/superset-websocket/utils/client-ws-app/package.json @@ -6,9 +6,9 @@ "start": "node ./bin/www" }, "dependencies": { - "cookie-parser": "~1.4.6", + "cookie-parser": "~1.4.7", "debug": "~4.3.7", - "express": "~4.21.0", + "express": "~4.21.1", "http-errors": "~2.0.0", "jsonwebtoken": "^9.0.2", "morgan": "~1.10.0", From 98c0fdc7e8e8e2fb77c467a3eb34f27887cb6b31 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 29 Oct 2024 12:24:42 -0600 Subject: [PATCH 009/307] build(deps-dev): bump webpack from 5.94.0 to 5.95.0 in /docs (#30480) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- docs/package.json | 2 +- docs/yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/package.json b/docs/package.json index f6aecc25da714..7482e666705f3 100644 --- a/docs/package.json +++ b/docs/package.json @@ -50,7 +50,7 @@ "@docusaurus/tsconfig": "^3.5.2", "@types/react": "^18.3.10", "typescript": "^5.6.2", - "webpack": "^5.94.0" + "webpack": "^5.95.0" }, "browserslist": { "production": [ diff --git a/docs/yarn.lock b/docs/yarn.lock index d5ce6f5a5877b..5455dd61f6791 100644 --- a/docs/yarn.lock +++ b/docs/yarn.lock @@ -10336,10 +10336,10 @@ webpack-sources@^3.2.3: resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== -webpack@^5.88.1, webpack@^5.94.0: - version "5.94.0" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.94.0.tgz#77a6089c716e7ab90c1c67574a28da518a20970f" - integrity sha512-KcsGn50VT+06JH/iunZJedYGUJS5FGjow8wb9c0v5n1Om8O1g4L6LjtfxwlXIATopoQu+vOXXa7gYisWxCoPyg== +webpack@^5.88.1, webpack@^5.95.0: + version "5.95.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.95.0.tgz#8fd8c454fa60dad186fbe36c400a55848307b4c0" + integrity sha512-2t3XstrKULz41MNMBF+cJ97TyHdyQ8HCt//pqErqDvNjU9YQBnZxIHa11VXsi7F3mb5/aO2tuDxdeTPdU7xu9Q== dependencies: "@types/estree" "^1.0.5" "@webassemblyjs/ast" "^1.12.1" From f2a9f311353dd39ef79cdfde661900ee022770f9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 29 Oct 2024 12:25:16 -0600 Subject: [PATCH 010/307] build(deps): bump cookie from 0.6.0 to 0.7.0 in /superset-websocket (#30536) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- superset-websocket/package-lock.json | 14 +++++++------- superset-websocket/package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/superset-websocket/package-lock.json b/superset-websocket/package-lock.json index bf54fba8bf9b6..78bcdae9f7402 100644 --- a/superset-websocket/package-lock.json +++ b/superset-websocket/package-lock.json @@ -9,7 +9,7 @@ "version": "0.0.1", "license": "Apache-2.0", "dependencies": { - "cookie": "^0.6.0", + "cookie": "^0.7.0", "hot-shots": "^10.0.0", "ioredis": "^4.28.0", "jsonwebtoken": "^9.0.2", @@ -2482,9 +2482,9 @@ "dev": true }, "node_modules/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.0.tgz", + "integrity": "sha512-qCf+V4dtlNhSRXGAZatc1TasyFO6GjohcOul807YOb5ik3+kQSnb4d7iajeCL8QHaJ4uZEjCgiCJerKXwdRVlQ==", "engines": { "node": ">= 0.6" } @@ -8337,9 +8337,9 @@ "dev": true }, "cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==" + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.0.tgz", + "integrity": "sha512-qCf+V4dtlNhSRXGAZatc1TasyFO6GjohcOul807YOb5ik3+kQSnb4d7iajeCL8QHaJ4uZEjCgiCJerKXwdRVlQ==" }, "create-jest": { "version": "29.7.0", diff --git a/superset-websocket/package.json b/superset-websocket/package.json index 7af0d3c57427b..47bf01856e82b 100644 --- a/superset-websocket/package.json +++ b/superset-websocket/package.json @@ -17,7 +17,7 @@ }, "license": "Apache-2.0", "dependencies": { - "cookie": "^0.6.0", + "cookie": "^0.7.0", "hot-shots": "^10.0.0", "ioredis": "^4.28.0", "jsonwebtoken": "^9.0.2", From 576ad85eb44419bc775d0d3ad9e3e9d0a97d0666 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=90=E1=BB=97=20Tr=E1=BB=8Dng=20H=E1=BA=A3i?= <41283691+hainenber@users.noreply.github.com> Date: Wed, 30 Oct 2024 01:27:20 +0700 Subject: [PATCH 011/307] chore(fe): replace deprecate aliased Jest matchers with corresponding substituents (#30355) Signed-off-by: hainenber Co-authored-by: Evan Rusackas --- superset-frontend/.eslintrc.js | 2 - .../useChangeEffect/useChangeEffect.test.ts | 10 ++--- .../useComponentDidMount.test.ts | 4 +- .../useComponentDidUpdate.test.ts | 4 +- .../color/LabelsColorMapSingleton.test.ts | 4 +- .../test/models/Registry.test.ts | 22 +++++----- .../test/query/buildQueryContext.test.ts | 2 +- .../translation/TranslatorSingleton.test.ts | 2 +- .../src/switchboard.test.ts | 2 +- .../ShareSqlLabQuery.test.tsx | 4 +- .../components/CronPicker/CronPicker.test.tsx | 2 +- .../DatabaseSelector.test.tsx | 12 ++--- .../DeleteModal/DeleteModal.test.tsx | 18 ++++---- .../src/components/FaveStar/FaveStar.test.tsx | 18 ++++---- .../src/components/ListView/ListView.test.tsx | 2 +- .../components/Pagination/Ellipsis.test.tsx | 8 ++-- .../src/components/Pagination/Item.test.tsx | 8 ++-- .../src/components/Pagination/Next.test.tsx | 8 ++-- .../src/components/Pagination/Prev.test.tsx | 8 ++-- .../DetailsPanel/DetailsPanel.test.tsx | 12 ++--- .../FilterIndicator/FilterIndicator.test.tsx | 4 +- .../components/Header/Header.test.tsx | 8 ++-- .../PropertiesModal/PropertiesModal.test.jsx | 2 +- .../PropertiesModal/PropertiesModal.test.tsx | 24 +++++----- .../SliceHeader/SliceHeader.test.tsx | 28 ++++++------ .../SliceHeaderControls.test.tsx | 42 +++++++++--------- .../components/gridComponents/Tab.test.tsx | 24 +++++----- .../DownloadAsImage.test.tsx | 8 ++-- .../components/menu/HoverMenu.test.tsx | 4 +- .../ShareMenuItems/ShareMenuItems.test.tsx | 38 ++++++++-------- .../FiltersConfigForm/ColumnSelect.test.tsx | 8 ++-- .../FilterScope/utils.test.ts | 14 +++--- .../getControlItemsMap.test.tsx | 16 +++---- .../reducers/dashboardFilters.test.js | 2 +- .../src/explore/components/Control.test.tsx | 4 +- .../DataTableControl/FilterInput.test.tsx | 4 +- .../DatasourcePanelItem.test.tsx | 6 +-- .../ExploreChartHeader.test.tsx | 20 ++++----- .../PropertiesModal/PropertiesModal.test.tsx | 42 +++++++++--------- .../CollectionControl.test.tsx | 15 ++++--- .../AdhocMetricEditPopover.test.tsx | 44 +++++++++---------- .../SelectAsyncControl.test.tsx | 8 ++-- .../VizTypeControl/VizTypeControl.test.tsx | 2 +- .../controls/withAsyncVerification.test.tsx | 12 ++--- .../exploreUtils/exploreUtils.test.jsx | 4 +- .../exploreUtils/shouldUseLegacyApi.test.ts | 18 ++++---- .../src/utils/cacheWrapper.test.ts | 10 ++--- superset-websocket/spec/index.test.ts | 24 +++++----- 48 files changed, 294 insertions(+), 293 deletions(-) diff --git a/superset-frontend/.eslintrc.js b/superset-frontend/.eslintrc.js index 700652a0171d3..9777651427545 100644 --- a/superset-frontend/.eslintrc.js +++ b/superset-frontend/.eslintrc.js @@ -280,7 +280,6 @@ module.exports = { 'theme-colors/no-literal-colors': 0, 'translation-vars/no-template-vars': 0, 'no-restricted-imports': 0, - 'jest/no-alias-methods': 0, 'react/no-void-elements': 0, }, }, @@ -371,7 +370,6 @@ module.exports = { 'react-prefer-function-component/react-prefer-function-component': 1, 'prettier/prettier': 'error', // disabling some things that come with the eslint 7->8 upgrade. Will address these in a separate PR - 'jest/no-alias-methods': 0, 'react/no-unknown-property': 0, 'react/no-void-elements': 0, 'react/function-component-definition': [ diff --git a/superset-frontend/packages/superset-ui-core/src/hooks/useChangeEffect/useChangeEffect.test.ts b/superset-frontend/packages/superset-ui-core/src/hooks/useChangeEffect/useChangeEffect.test.ts index 32c984e48769b..1c1a96125b92e 100644 --- a/superset-frontend/packages/superset-ui-core/src/hooks/useChangeEffect/useChangeEffect.test.ts +++ b/superset-frontend/packages/superset-ui-core/src/hooks/useChangeEffect/useChangeEffect.test.ts @@ -24,8 +24,8 @@ test('call callback the first time with undefined and value', () => { renderHook(props => useChangeEffect(props.value, props.callback), { initialProps: { value: 'value', callback }, }); - expect(callback).toBeCalledTimes(1); - expect(callback).nthCalledWith(1, undefined, 'value'); + expect(callback).toHaveBeenCalledTimes(1); + expect(callback).toHaveBeenNthCalledWith(1, undefined, 'value'); }); test('do not call callback 2 times if the value do not change', () => { @@ -37,7 +37,7 @@ test('do not call callback 2 times if the value do not change', () => { }, ); hook.rerender({ value: 'value', callback }); - expect(callback).toBeCalledTimes(1); + expect(callback).toHaveBeenCalledTimes(1); }); test('call callback whenever the value changes', () => { @@ -49,6 +49,6 @@ test('call callback whenever the value changes', () => { }, ); hook.rerender({ value: 'value-2', callback }); - expect(callback).toBeCalledTimes(2); - expect(callback).nthCalledWith(2, 'value', 'value-2'); + expect(callback).toHaveBeenCalledTimes(2); + expect(callback).toHaveBeenNthCalledWith(2, 'value', 'value-2'); }); diff --git a/superset-frontend/packages/superset-ui-core/src/hooks/useComponentDidMount/useComponentDidMount.test.ts b/superset-frontend/packages/superset-ui-core/src/hooks/useComponentDidMount/useComponentDidMount.test.ts index 6d7d6cd71282a..7edf9e723296b 100644 --- a/superset-frontend/packages/superset-ui-core/src/hooks/useComponentDidMount/useComponentDidMount.test.ts +++ b/superset-frontend/packages/superset-ui-core/src/hooks/useComponentDidMount/useComponentDidMount.test.ts @@ -22,7 +22,7 @@ import { useComponentDidMount } from './useComponentDidMount'; test('the effect should only be executed on the first render', () => { const effect = jest.fn(); const hook = renderHook(() => useComponentDidMount(effect)); - expect(effect).toBeCalledTimes(1); + expect(effect).toHaveBeenCalledTimes(1); hook.rerender(); - expect(effect).toBeCalledTimes(1); + expect(effect).toHaveBeenCalledTimes(1); }); diff --git a/superset-frontend/packages/superset-ui-core/src/hooks/useComponentDidUpdate/useComponentDidUpdate.test.ts b/superset-frontend/packages/superset-ui-core/src/hooks/useComponentDidUpdate/useComponentDidUpdate.test.ts index a1615ec2793c0..1c191b07beae0 100644 --- a/superset-frontend/packages/superset-ui-core/src/hooks/useComponentDidUpdate/useComponentDidUpdate.test.ts +++ b/superset-frontend/packages/superset-ui-core/src/hooks/useComponentDidUpdate/useComponentDidUpdate.test.ts @@ -24,8 +24,8 @@ test('the effect should not be executed on the first render', () => { const hook = renderHook(props => useComponentDidUpdate(props.effect), { initialProps: { effect }, }); - expect(effect).toBeCalledTimes(0); + expect(effect).toHaveBeenCalledTimes(0); const changedEffect = jest.fn(); hook.rerender({ effect: changedEffect }); - expect(changedEffect).toBeCalledTimes(1); + expect(changedEffect).toHaveBeenCalledTimes(1); }); diff --git a/superset-frontend/packages/superset-ui-core/test/color/LabelsColorMapSingleton.test.ts b/superset-frontend/packages/superset-ui-core/test/color/LabelsColorMapSingleton.test.ts index b93a416e7ffaa..17efe6692f3b5 100644 --- a/superset-frontend/packages/superset-ui-core/test/color/LabelsColorMapSingleton.test.ts +++ b/superset-frontend/packages/superset-ui-core/test/color/LabelsColorMapSingleton.test.ts @@ -192,7 +192,7 @@ describe('LabelsColorMap', () => { labelsColorMap.updateColorMap(categoricalNamespace, 'testColors'); const colorMap = labelsColorMap.getColorMap(); expect(Object.fromEntries(colorMap)).not.toEqual({}); - expect(getAnalogousColorsSpy).not.toBeCalled(); + expect(getAnalogousColorsSpy).not.toHaveBeenCalled(); }); it('should use analagous colors', () => { @@ -207,7 +207,7 @@ describe('LabelsColorMap', () => { labelsColorMap.updateColorMap(categoricalNamespace, 'testColors'); const colorMap = labelsColorMap.getColorMap(); expect(Object.fromEntries(colorMap)).not.toEqual({}); - expect(getAnalogousColorsSpy).toBeCalled(); + expect(getAnalogousColorsSpy).toHaveBeenCalled(); }); }); diff --git a/superset-frontend/packages/superset-ui-core/test/models/Registry.test.ts b/superset-frontend/packages/superset-ui-core/test/models/Registry.test.ts index 6f2067eec3129..7b3f2d1f89ebd 100644 --- a/superset-frontend/packages/superset-ui-core/test/models/Registry.test.ts +++ b/superset-frontend/packages/superset-ui-core/test/models/Registry.test.ts @@ -396,31 +396,31 @@ describe('Registry', () => { it('calls the listener when a value is registered', () => { registry.registerValue('foo', 'bar'); - expect(listener).toBeCalledWith(['foo']); + expect(listener).toHaveBeenCalledWith(['foo']); }); it('calls the listener when a loader is registered', () => { registry.registerLoader('foo', () => 'bar'); - expect(listener).toBeCalledWith(['foo']); + expect(listener).toHaveBeenCalledWith(['foo']); }); it('calls the listener when a value is overridden', () => { registry.registerValue('foo', 'bar'); listener.mockClear(); registry.registerValue('foo', 'baz'); - expect(listener).toBeCalledWith(['foo']); + expect(listener).toHaveBeenCalledWith(['foo']); }); it('calls the listener when a value is removed', () => { registry.registerValue('foo', 'bar'); listener.mockClear(); registry.remove('foo'); - expect(listener).toBeCalledWith(['foo']); + expect(listener).toHaveBeenCalledWith(['foo']); }); it('does not call the listener when a value is not actually removed', () => { registry.remove('foo'); - expect(listener).not.toBeCalled(); + expect(listener).not.toHaveBeenCalled(); }); it('calls the listener when registry is cleared', () => { @@ -428,13 +428,13 @@ describe('Registry', () => { registry.registerLoader('fluz', () => 'baz'); listener.mockClear(); registry.clear(); - expect(listener).toBeCalledWith(['foo', 'fluz']); + expect(listener).toHaveBeenCalledWith(['foo', 'fluz']); }); it('removes listeners correctly', () => { registry.removeListener(listener); registry.registerValue('foo', 'bar'); - expect(listener).not.toBeCalled(); + expect(listener).not.toHaveBeenCalled(); }); describe('with a broken listener', () => { @@ -456,10 +456,10 @@ describe('Registry', () => { registry.addListener(lastListener); registry.registerValue('foo', 'bar'); - expect(listener).toBeCalledWith(['foo']); - expect(errorListener).toBeCalledWith(['foo']); - expect(lastListener).toBeCalledWith(['foo']); - expect(console.error).toBeCalled(); + expect(listener).toHaveBeenCalledWith(['foo']); + expect(errorListener).toHaveBeenCalledWith(['foo']); + expect(lastListener).toHaveBeenCalledWith(['foo']); + expect(console.error).toHaveBeenCalled(); }); }); }); diff --git a/superset-frontend/packages/superset-ui-core/test/query/buildQueryContext.test.ts b/superset-frontend/packages/superset-ui-core/test/query/buildQueryContext.test.ts index 4fe70f9188158..4918da15866c0 100644 --- a/superset-frontend/packages/superset-ui-core/test/query/buildQueryContext.test.ts +++ b/superset-frontend/packages/superset-ui-core/test/query/buildQueryContext.test.ts @@ -138,7 +138,7 @@ describe('buildQueryContext', () => { }, () => [{}], ); - expect(spyNormalizeTimeColumn).toBeCalled(); + expect(spyNormalizeTimeColumn).toHaveBeenCalled(); spyNormalizeTimeColumn.mockRestore(); }); }); diff --git a/superset-frontend/packages/superset-ui-core/test/translation/TranslatorSingleton.test.ts b/superset-frontend/packages/superset-ui-core/test/translation/TranslatorSingleton.test.ts index af0d6f5915524..2aa78faeed267 100644 --- a/superset-frontend/packages/superset-ui-core/test/translation/TranslatorSingleton.test.ts +++ b/superset-frontend/packages/superset-ui-core/test/translation/TranslatorSingleton.test.ts @@ -80,7 +80,7 @@ describe('TranslatorSingleton', () => { expect(t('second')).toEqual('second'); resetTranslation(); expect(t('second')).toEqual('second'); - expect(console.warn).toBeCalledTimes(2); + expect(console.warn).toHaveBeenCalledTimes(2); restoreConsole(); }); }); diff --git a/superset-frontend/packages/superset-ui-switchboard/src/switchboard.test.ts b/superset-frontend/packages/superset-ui-switchboard/src/switchboard.test.ts index 9e36f541e1cd9..915fe0cc4234f 100644 --- a/superset-frontend/packages/superset-ui-switchboard/src/switchboard.test.ts +++ b/superset-frontend/packages/superset-ui-switchboard/src/switchboard.test.ts @@ -294,7 +294,7 @@ describe('comms', () => { }); port2.start(); - await expect(ours.get('someMethod')).rejects.toThrowError( + await expect(ours.get('someMethod')).rejects.toThrow( 'Unexpected response message', ); }); diff --git a/superset-frontend/src/SqlLab/components/ShareSqlLabQuery/ShareSqlLabQuery.test.tsx b/superset-frontend/src/SqlLab/components/ShareSqlLabQuery/ShareSqlLabQuery.test.tsx index ec77f08242010..d522d73d90203 100644 --- a/superset-frontend/src/SqlLab/components/ShareSqlLabQuery/ShareSqlLabQuery.test.tsx +++ b/superset-frontend/src/SqlLab/components/ShareSqlLabQuery/ShareSqlLabQuery.test.tsx @@ -127,7 +127,7 @@ describe('ShareSqlLabQuery', () => { const storeQuerySpy = jest.spyOn(utils, 'storeQuery'); userEvent.click(button); expect(storeQuerySpy.mock.calls).toHaveLength(1); - expect(storeQuerySpy).toBeCalledWith(expected); + expect(storeQuerySpy).toHaveBeenCalledWith(expected); storeQuerySpy.mockRestore(); }); @@ -142,7 +142,7 @@ describe('ShareSqlLabQuery', () => { const storeQuerySpy = jest.spyOn(utils, 'storeQuery'); userEvent.click(button); expect(storeQuerySpy.mock.calls).toHaveLength(1); - expect(storeQuerySpy).toBeCalledWith(expected); + expect(storeQuerySpy).toHaveBeenCalledWith(expected); storeQuerySpy.mockRestore(); }); }); diff --git a/superset-frontend/src/components/CronPicker/CronPicker.test.tsx b/superset-frontend/src/components/CronPicker/CronPicker.test.tsx index 9eef6f21f459b..48203a2dc8863 100644 --- a/superset-frontend/src/components/CronPicker/CronPicker.test.tsx +++ b/superset-frontend/src/components/CronPicker/CronPicker.test.tsx @@ -28,7 +28,7 @@ test('Should send correct props to ReactCronPicker', () => { myCustomProp: 'myCustomProp', }; render(); - expect(spy).toBeCalledWith( + expect(spy).toHaveBeenCalledWith( expect.objectContaining({ className: expect.any(String), locale: expect.anything(), diff --git a/superset-frontend/src/components/DatabaseSelector/DatabaseSelector.test.tsx b/superset-frontend/src/components/DatabaseSelector/DatabaseSelector.test.tsx index aa9cac748b06f..44d0bff0e04bd 100644 --- a/superset-frontend/src/components/DatabaseSelector/DatabaseSelector.test.tsx +++ b/superset-frontend/src/components/DatabaseSelector/DatabaseSelector.test.tsx @@ -219,9 +219,9 @@ test('Refresh should work', async () => { await waitFor(() => { expect(fetchMock.calls(databaseApiRoute).length).toBe(1); expect(fetchMock.calls(schemaApiRoute).length).toBe(1); - expect(props.handleError).toBeCalledTimes(0); - expect(props.onDbChange).toBeCalledTimes(0); - expect(props.onSchemaChange).toBeCalledTimes(0); + expect(props.handleError).toHaveBeenCalledTimes(0); + expect(props.onDbChange).toHaveBeenCalledTimes(0); + expect(props.onSchemaChange).toHaveBeenCalledTimes(0); }); // click schema reload @@ -230,9 +230,9 @@ test('Refresh should work', async () => { await waitFor(() => { expect(fetchMock.calls(databaseApiRoute).length).toBe(1); expect(fetchMock.calls(schemaApiRoute).length).toBe(2); - expect(props.handleError).toBeCalledTimes(0); - expect(props.onDbChange).toBeCalledTimes(0); - expect(props.onSchemaChange).toBeCalledTimes(0); + expect(props.handleError).toHaveBeenCalledTimes(0); + expect(props.onDbChange).toHaveBeenCalledTimes(0); + expect(props.onSchemaChange).toHaveBeenCalledTimes(0); }); }); diff --git a/superset-frontend/src/components/DeleteModal/DeleteModal.test.tsx b/superset-frontend/src/components/DeleteModal/DeleteModal.test.tsx index ae966f48ed263..7e9b3c439ebba 100644 --- a/superset-frontend/src/components/DeleteModal/DeleteModal.test.tsx +++ b/superset-frontend/src/components/DeleteModal/DeleteModal.test.tsx @@ -45,8 +45,8 @@ test('Calling "onHide"', () => { }; const modal = ; render(modal); - expect(props.onHide).toBeCalledTimes(0); - expect(props.onConfirm).toBeCalledTimes(0); + expect(props.onHide).toHaveBeenCalledTimes(0); + expect(props.onConfirm).toHaveBeenCalledTimes(0); // type "del" in the input userEvent.type(screen.getByTestId('delete-modal-input'), 'del'); @@ -55,8 +55,8 @@ test('Calling "onHide"', () => { // close the modal expect(screen.getByText('×')).toBeVisible(); userEvent.click(screen.getByText('×')); - expect(props.onHide).toBeCalledTimes(1); - expect(props.onConfirm).toBeCalledTimes(0); + expect(props.onHide).toHaveBeenCalledTimes(1); + expect(props.onConfirm).toHaveBeenCalledTimes(0); // confirm input has been cleared expect(screen.getByTestId('delete-modal-input')).toHaveValue(''); @@ -71,19 +71,19 @@ test('Calling "onConfirm" only after typing "delete" in the input', () => { open: true, }; render(); - expect(props.onHide).toBeCalledTimes(0); - expect(props.onConfirm).toBeCalledTimes(0); + expect(props.onHide).toHaveBeenCalledTimes(0); + expect(props.onConfirm).toHaveBeenCalledTimes(0); expect(screen.getByTestId('delete-modal-input')).toBeVisible(); - expect(props.onConfirm).toBeCalledTimes(0); + expect(props.onConfirm).toHaveBeenCalledTimes(0); // do not execute "onConfirm" if you have not typed "delete" userEvent.click(screen.getByText('Delete')); - expect(props.onConfirm).toBeCalledTimes(0); + expect(props.onConfirm).toHaveBeenCalledTimes(0); // execute "onConfirm" if you have typed "delete" userEvent.type(screen.getByTestId('delete-modal-input'), 'delete'); userEvent.click(screen.getByText('Delete')); - expect(props.onConfirm).toBeCalledTimes(1); + expect(props.onConfirm).toHaveBeenCalledTimes(1); // confirm input has been cleared expect(screen.getByTestId('delete-modal-input')).toHaveValue(''); diff --git a/superset-frontend/src/components/FaveStar/FaveStar.test.tsx b/superset-frontend/src/components/FaveStar/FaveStar.test.tsx index 028edde2e4e57..9bccc4b7c9833 100644 --- a/superset-frontend/src/components/FaveStar/FaveStar.test.tsx +++ b/superset-frontend/src/components/FaveStar/FaveStar.test.tsx @@ -37,20 +37,20 @@ test('render right content', async () => { screen.getByRole('img', { name: 'favorite-selected' }), ).toBeInTheDocument(); - expect(props.saveFaveStar).toBeCalledTimes(0); + expect(props.saveFaveStar).toHaveBeenCalledTimes(0); userEvent.click(screen.getByRole('button')); - expect(props.saveFaveStar).toBeCalledTimes(1); - expect(props.saveFaveStar).toBeCalledWith(props.itemId, true); + expect(props.saveFaveStar).toHaveBeenCalledTimes(1); + expect(props.saveFaveStar).toHaveBeenCalledWith(props.itemId, true); rerender(); expect( await findByRole('img', { name: 'favorite-unselected' }), ).toBeInTheDocument(); - expect(props.saveFaveStar).toBeCalledTimes(1); + expect(props.saveFaveStar).toHaveBeenCalledTimes(1); userEvent.click(screen.getByRole('button')); - expect(props.saveFaveStar).toBeCalledTimes(2); - expect(props.saveFaveStar).toBeCalledWith(props.itemId, false); + expect(props.saveFaveStar).toHaveBeenCalledTimes(2); + expect(props.saveFaveStar).toHaveBeenCalledWith(props.itemId, false); }); test('render content on tooltip', async () => { @@ -87,9 +87,9 @@ test('Call fetchFaveStar on first render and on itemId change', async () => { expect( await findByRole('img', { name: 'favorite-unselected' }), ).toBeInTheDocument(); - expect(props.fetchFaveStar).toBeCalledTimes(1); - expect(props.fetchFaveStar).toBeCalledWith(props.itemId); + expect(props.fetchFaveStar).toHaveBeenCalledTimes(1); + expect(props.fetchFaveStar).toHaveBeenCalledWith(props.itemId); rerender(); - expect(props.fetchFaveStar).toBeCalledTimes(2); + expect(props.fetchFaveStar).toHaveBeenCalledTimes(2); }); diff --git a/superset-frontend/src/components/ListView/ListView.test.tsx b/superset-frontend/src/components/ListView/ListView.test.tsx index ad76ad8c7a6cf..dd5b6de2a3241 100644 --- a/superset-frontend/src/components/ListView/ListView.test.tsx +++ b/superset-frontend/src/components/ListView/ListView.test.tsx @@ -61,7 +61,7 @@ test('redirects to first page when page index is invalid', async () => { }); await waitFor(() => { expect(window.location.search).toEqual('?pageIndex=0'); - expect(fetchData).toBeCalledTimes(2); + expect(fetchData).toHaveBeenCalledTimes(2); expect(fetchData).toHaveBeenCalledWith( expect.objectContaining({ pageIndex: 9 }), ); diff --git a/superset-frontend/src/components/Pagination/Ellipsis.test.tsx b/superset-frontend/src/components/Pagination/Ellipsis.test.tsx index 81c7301fa9ead..1caf0ae555a82 100644 --- a/superset-frontend/src/components/Pagination/Ellipsis.test.tsx +++ b/superset-frontend/src/components/Pagination/Ellipsis.test.tsx @@ -24,15 +24,15 @@ import { Ellipsis } from './Ellipsis'; test('Ellipsis - click when the button is enabled', () => { const click = jest.fn(); render(); - expect(click).toBeCalledTimes(0); + expect(click).toHaveBeenCalledTimes(0); userEvent.click(screen.getByRole('button')); - expect(click).toBeCalledTimes(1); + expect(click).toHaveBeenCalledTimes(1); }); test('Ellipsis - click when the button is disabled', () => { const click = jest.fn(); render(); - expect(click).toBeCalledTimes(0); + expect(click).toHaveBeenCalledTimes(0); userEvent.click(screen.getByRole('button')); - expect(click).toBeCalledTimes(0); + expect(click).toHaveBeenCalledTimes(0); }); diff --git a/superset-frontend/src/components/Pagination/Item.test.tsx b/superset-frontend/src/components/Pagination/Item.test.tsx index 08622f9def6cd..096053656e0db 100644 --- a/superset-frontend/src/components/Pagination/Item.test.tsx +++ b/superset-frontend/src/components/Pagination/Item.test.tsx @@ -28,9 +28,9 @@ test('Item - click when the item is not active', () => {
, ); - expect(click).toBeCalledTimes(0); + expect(click).toHaveBeenCalledTimes(0); userEvent.click(screen.getByRole('button')); - expect(click).toBeCalledTimes(1); + expect(click).toHaveBeenCalledTimes(1); expect(screen.getByTestId('test')).toBeInTheDocument(); }); @@ -41,8 +41,8 @@ test('Item - click when the item is active', () => {
, ); - expect(click).toBeCalledTimes(0); + expect(click).toHaveBeenCalledTimes(0); userEvent.click(screen.getByRole('button')); - expect(click).toBeCalledTimes(0); + expect(click).toHaveBeenCalledTimes(0); expect(screen.getByTestId('test')).toBeInTheDocument(); }); diff --git a/superset-frontend/src/components/Pagination/Next.test.tsx b/superset-frontend/src/components/Pagination/Next.test.tsx index bf675749cdea1..b50efb2da6ff0 100644 --- a/superset-frontend/src/components/Pagination/Next.test.tsx +++ b/superset-frontend/src/components/Pagination/Next.test.tsx @@ -24,15 +24,15 @@ import { Next } from './Next'; test('Next - click when the button is enabled', () => { const click = jest.fn(); render(); - expect(click).toBeCalledTimes(0); + expect(click).toHaveBeenCalledTimes(0); userEvent.click(screen.getByRole('button')); - expect(click).toBeCalledTimes(1); + expect(click).toHaveBeenCalledTimes(1); }); test('Next - click when the button is disabled', () => { const click = jest.fn(); render(); - expect(click).toBeCalledTimes(0); + expect(click).toHaveBeenCalledTimes(0); userEvent.click(screen.getByRole('button')); - expect(click).toBeCalledTimes(0); + expect(click).toHaveBeenCalledTimes(0); }); diff --git a/superset-frontend/src/components/Pagination/Prev.test.tsx b/superset-frontend/src/components/Pagination/Prev.test.tsx index e414fa48a84e5..8339a57e6ccd1 100644 --- a/superset-frontend/src/components/Pagination/Prev.test.tsx +++ b/superset-frontend/src/components/Pagination/Prev.test.tsx @@ -24,15 +24,15 @@ import { Prev } from './Prev'; test('Prev - click when the button is enabled', () => { const click = jest.fn(); render(); - expect(click).toBeCalledTimes(0); + expect(click).toHaveBeenCalledTimes(0); userEvent.click(screen.getByRole('button')); - expect(click).toBeCalledTimes(1); + expect(click).toHaveBeenCalledTimes(1); }); test('Prev - click when the button is disabled', () => { const click = jest.fn(); render(); - expect(click).toBeCalledTimes(0); + expect(click).toHaveBeenCalledTimes(0); userEvent.click(screen.getByRole('button')); - expect(click).toBeCalledTimes(0); + expect(click).toHaveBeenCalledTimes(0); }); diff --git a/superset-frontend/src/dashboard/components/FiltersBadge/DetailsPanel/DetailsPanel.test.tsx b/superset-frontend/src/dashboard/components/FiltersBadge/DetailsPanel/DetailsPanel.test.tsx index 6419d9e2ad6d3..460adbd81092f 100644 --- a/superset-frontend/src/dashboard/components/FiltersBadge/DetailsPanel/DetailsPanel.test.tsx +++ b/superset-frontend/src/dashboard/components/FiltersBadge/DetailsPanel/DetailsPanel.test.tsx @@ -123,10 +123,10 @@ test('Should render "appliedCrossFilterIndicators"', async () => { screen.getByRole('button', { name: 'Clinical Stage' }), ).toBeInTheDocument(); - expect(props.onHighlightFilterSource).toBeCalledTimes(0); + expect(props.onHighlightFilterSource).toHaveBeenCalledTimes(0); userEvent.click(screen.getByRole('button', { name: 'Clinical Stage' })); - expect(props.onHighlightFilterSource).toBeCalledTimes(1); - expect(props.onHighlightFilterSource).toBeCalledWith([ + expect(props.onHighlightFilterSource).toHaveBeenCalledTimes(1); + expect(props.onHighlightFilterSource).toHaveBeenCalledWith([ 'ROOT_ID', 'TABS-wUKya7eQ0Z', 'TAB-BCIJF4NvgQ', @@ -153,10 +153,10 @@ test('Should render "appliedIndicators"', async () => { expect(await screen.findByText('Applied filters (1)')).toBeInTheDocument(); expect(screen.getByRole('button', { name: 'Country' })).toBeInTheDocument(); - expect(props.onHighlightFilterSource).toBeCalledTimes(0); + expect(props.onHighlightFilterSource).toHaveBeenCalledTimes(0); userEvent.click(screen.getByRole('button', { name: 'Country' })); - expect(props.onHighlightFilterSource).toBeCalledTimes(1); - expect(props.onHighlightFilterSource).toBeCalledWith([ + expect(props.onHighlightFilterSource).toHaveBeenCalledTimes(1); + expect(props.onHighlightFilterSource).toHaveBeenCalledWith([ 'ROOT_ID', 'TABS-wUKya7eQ0Z', 'TAB-BCIJF4NvgQ', diff --git a/superset-frontend/src/dashboard/components/FiltersBadge/FilterIndicator/FilterIndicator.test.tsx b/superset-frontend/src/dashboard/components/FiltersBadge/FilterIndicator/FilterIndicator.test.tsx index 79340f41e72d3..563adfa8b8f69 100644 --- a/superset-frontend/src/dashboard/components/FiltersBadge/FilterIndicator/FilterIndicator.test.tsx +++ b/superset-frontend/src/dashboard/components/FiltersBadge/FilterIndicator/FilterIndicator.test.tsx @@ -51,9 +51,9 @@ test('Should call "onClick"', () => { const props = createProps(); render(); - expect(props.onClick).toBeCalledTimes(0); + expect(props.onClick).toHaveBeenCalledTimes(0); userEvent.click(screen.getByRole('button', { name: 'Vaccine Approach' })); - expect(props.onClick).toBeCalledTimes(1); + expect(props.onClick).toHaveBeenCalledTimes(1); }); test('Should render "value"', () => { diff --git a/superset-frontend/src/dashboard/components/Header/Header.test.tsx b/superset-frontend/src/dashboard/components/Header/Header.test.tsx index 79f9cdf308824..4c9f7bd0139bd 100644 --- a/superset-frontend/src/dashboard/components/Header/Header.test.tsx +++ b/superset-frontend/src/dashboard/components/Header/Header.test.tsx @@ -315,10 +315,10 @@ test('should NOT render the fave icon on anonymous user', () => { setup(anonymousUserProps); expect(() => screen.getByRole('img', { name: 'favorite-unselected' }), - ).toThrowError('Unable to find'); - expect(() => - screen.getByRole('img', { name: 'favorite-selected' }), - ).toThrowError('Unable to find'); + ).toThrow('Unable to find'); + expect(() => screen.getByRole('img', { name: 'favorite-selected' })).toThrow( + 'Unable to find', + ); }); test('should fave', async () => { diff --git a/superset-frontend/src/dashboard/components/PropertiesModal/PropertiesModal.test.jsx b/superset-frontend/src/dashboard/components/PropertiesModal/PropertiesModal.test.jsx index 297c78a2c55c2..0d8421f2522ba 100644 --- a/superset-frontend/src/dashboard/components/PropertiesModal/PropertiesModal.test.jsx +++ b/superset-frontend/src/dashboard/components/PropertiesModal/PropertiesModal.test.jsx @@ -143,7 +143,7 @@ describe.skip('PropertiesModal', () => { const spy = jest.spyOn(Modal, 'error'); expect(() => modalInstance.onColorSchemeChange('THIS_WILL_NOT_WORK'), - ).toThrowError('A valid color scheme is required'); + ).toThrow('A valid color scheme is required'); expect(spy).toHaveBeenCalled(); }); }); diff --git a/superset-frontend/src/dashboard/components/PropertiesModal/PropertiesModal.test.tsx b/superset-frontend/src/dashboard/components/PropertiesModal/PropertiesModal.test.tsx index 7025b94f1693c..37ad242b8d813 100644 --- a/superset-frontend/src/dashboard/components/PropertiesModal/PropertiesModal.test.tsx +++ b/superset-frontend/src/dashboard/components/PropertiesModal/PropertiesModal.test.tsx @@ -181,7 +181,7 @@ test('should render - FeatureFlag disabled', async () => { expect(screen.getAllByRole('textbox')).toHaveLength(4); expect(screen.getByRole('combobox')).toBeInTheDocument(); - expect(spyColorSchemeControlWrapper).toBeCalledWith( + expect(spyColorSchemeControlWrapper).toHaveBeenCalledWith( expect.objectContaining({ colorScheme: 'supersetColors' }), {}, ); @@ -222,7 +222,7 @@ test('should render - FeatureFlag enabled', async () => { expect(screen.getAllByRole('textbox')).toHaveLength(4); expect(screen.getAllByRole('combobox')).toHaveLength(3); - expect(spyColorSchemeControlWrapper).toBeCalledWith( + expect(spyColorSchemeControlWrapper).toHaveBeenCalledWith( expect.objectContaining({ colorScheme: 'supersetColors' }), {}, ); @@ -255,11 +255,11 @@ test('should close modal', async () => { await screen.findByTestId('dashboard-edit-properties-form'), ).toBeInTheDocument(); - expect(props.onHide).not.toBeCalled(); + expect(props.onHide).not.toHaveBeenCalled(); userEvent.click(screen.getByRole('button', { name: 'Cancel' })); - expect(props.onHide).toBeCalledTimes(1); + expect(props.onHide).toHaveBeenCalledTimes(1); userEvent.click(screen.getByRole('button', { name: 'Close' })); - expect(props.onHide).toBeCalledTimes(2); + expect(props.onHide).toHaveBeenCalledTimes(2); }); test('submitting with onlyApply:false', async () => { @@ -293,13 +293,13 @@ test('submitting with onlyApply:false', async () => { await screen.findByTestId('dashboard-edit-properties-form'), ).toBeInTheDocument(); - expect(props.onHide).not.toBeCalled(); - expect(props.onSubmit).not.toBeCalled(); + expect(props.onHide).not.toHaveBeenCalled(); + expect(props.onSubmit).not.toHaveBeenCalled(); userEvent.click(screen.getByRole('button', { name: 'Save' })); await waitFor(() => { - expect(props.onSubmit).toBeCalledTimes(1); - expect(props.onSubmit).toBeCalledWith({ + expect(props.onSubmit).toHaveBeenCalledTimes(1); + expect(props.onSubmit).toHaveBeenCalledWith({ certificationDetails: 'Sample certification', certifiedBy: 'John Doe', colorScheme: 'supersetColors', @@ -332,12 +332,12 @@ test('submitting with onlyApply:true', async () => { await screen.findByTestId('dashboard-edit-properties-form'), ).toBeInTheDocument(); - expect(props.onHide).not.toBeCalled(); - expect(props.onSubmit).not.toBeCalled(); + expect(props.onHide).not.toHaveBeenCalled(); + expect(props.onSubmit).not.toHaveBeenCalled(); userEvent.click(screen.getByRole('button', { name: 'Apply' })); await waitFor(() => { - expect(props.onSubmit).toBeCalledTimes(1); + expect(props.onSubmit).toHaveBeenCalledTimes(1); }); }); diff --git a/superset-frontend/src/dashboard/components/SliceHeader/SliceHeader.test.tsx b/superset-frontend/src/dashboard/components/SliceHeader/SliceHeader.test.tsx index f67d3076a1022..6dc0023b0cb8e 100644 --- a/superset-frontend/src/dashboard/components/SliceHeader/SliceHeader.test.tsx +++ b/superset-frontend/src/dashboard/components/SliceHeader/SliceHeader.test.tsx @@ -444,33 +444,33 @@ test('Correct actions to "SliceHeaderControls"', () => { const props = createProps(); render(, { useRedux: true, useRouter: true }); - expect(props.toggleExpandSlice).toBeCalledTimes(0); + expect(props.toggleExpandSlice).toHaveBeenCalledTimes(0); userEvent.click(screen.getByTestId('toggleExpandSlice')); - expect(props.toggleExpandSlice).toBeCalledTimes(1); + expect(props.toggleExpandSlice).toHaveBeenCalledTimes(1); - expect(props.forceRefresh).toBeCalledTimes(0); + expect(props.forceRefresh).toHaveBeenCalledTimes(0); userEvent.click(screen.getByTestId('forceRefresh')); - expect(props.forceRefresh).toBeCalledTimes(1); + expect(props.forceRefresh).toHaveBeenCalledTimes(1); - expect(props.logExploreChart).toBeCalledTimes(0); + expect(props.logExploreChart).toHaveBeenCalledTimes(0); userEvent.click(screen.getByTestId('exploreChart')); - expect(props.logExploreChart).toBeCalledTimes(1); + expect(props.logExploreChart).toHaveBeenCalledTimes(1); - expect(props.exportCSV).toBeCalledTimes(0); + expect(props.exportCSV).toHaveBeenCalledTimes(0); userEvent.click(screen.getByTestId('exportCSV')); - expect(props.exportCSV).toBeCalledTimes(1); + expect(props.exportCSV).toHaveBeenCalledTimes(1); - expect(props.addSuccessToast).toBeCalledTimes(0); + expect(props.addSuccessToast).toHaveBeenCalledTimes(0); userEvent.click(screen.getByTestId('addSuccessToast')); - expect(props.addSuccessToast).toBeCalledTimes(1); + expect(props.addSuccessToast).toHaveBeenCalledTimes(1); - expect(props.addDangerToast).toBeCalledTimes(0); + expect(props.addDangerToast).toHaveBeenCalledTimes(0); userEvent.click(screen.getByTestId('addDangerToast')); - expect(props.addDangerToast).toBeCalledTimes(1); + expect(props.addDangerToast).toHaveBeenCalledTimes(1); - expect(props.handleToggleFullSize).toBeCalledTimes(0); + expect(props.handleToggleFullSize).toHaveBeenCalledTimes(0); userEvent.click(screen.getByTestId('handleToggleFullSize')); - expect(props.handleToggleFullSize).toBeCalledTimes(1); + expect(props.handleToggleFullSize).toHaveBeenCalledTimes(1); }); test('Add extension to SliceHeader', () => { diff --git a/superset-frontend/src/dashboard/components/SliceHeaderControls/SliceHeaderControls.test.tsx b/superset-frontend/src/dashboard/components/SliceHeaderControls/SliceHeaderControls.test.tsx index 92a7563fc8dc8..cca28d4e45914 100644 --- a/superset-frontend/src/dashboard/components/SliceHeaderControls/SliceHeaderControls.test.tsx +++ b/superset-frontend/src/dashboard/components/SliceHeaderControls/SliceHeaderControls.test.tsx @@ -180,21 +180,21 @@ test('Should render default props', () => { test('Should "export to CSV"', async () => { const props = createProps(); renderWrapper(props); - expect(props.exportCSV).toBeCalledTimes(0); + expect(props.exportCSV).toHaveBeenCalledTimes(0); userEvent.hover(screen.getByText('Download')); userEvent.click(await screen.findByText('Export to .CSV')); - expect(props.exportCSV).toBeCalledTimes(1); - expect(props.exportCSV).toBeCalledWith(371); + expect(props.exportCSV).toHaveBeenCalledTimes(1); + expect(props.exportCSV).toHaveBeenCalledWith(371); }); test('Should "export to Excel"', async () => { const props = createProps(); renderWrapper(props); - expect(props.exportXLSX).toBeCalledTimes(0); + expect(props.exportXLSX).toHaveBeenCalledTimes(0); userEvent.hover(screen.getByText('Download')); userEvent.click(await screen.findByText('Export to Excel')); - expect(props.exportXLSX).toBeCalledTimes(1); - expect(props.exportXLSX).toBeCalledWith(371); + expect(props.exportXLSX).toHaveBeenCalledTimes(1); + expect(props.exportXLSX).toHaveBeenCalledWith(371); }); test('Export full CSV is under featureflag', async () => { @@ -214,11 +214,11 @@ test('Should "export full CSV"', async () => { }; const props = createProps('table'); renderWrapper(props); - expect(props.exportFullCSV).toBeCalledTimes(0); + expect(props.exportFullCSV).toHaveBeenCalledTimes(0); userEvent.hover(screen.getByText('Download')); userEvent.click(await screen.findByText('Export to full .CSV')); - expect(props.exportFullCSV).toBeCalledTimes(1); - expect(props.exportFullCSV).toBeCalledWith(371); + expect(props.exportFullCSV).toHaveBeenCalledTimes(1); + expect(props.exportFullCSV).toHaveBeenCalledWith(371); }); test('Should not show export full CSV if report is not table', async () => { @@ -248,11 +248,11 @@ test('Should "export full Excel"', async () => { }; const props = createProps('table'); renderWrapper(props); - expect(props.exportFullXLSX).toBeCalledTimes(0); + expect(props.exportFullXLSX).toHaveBeenCalledTimes(0); userEvent.hover(screen.getByText('Download')); userEvent.click(await screen.findByText('Export to full Excel')); - expect(props.exportFullXLSX).toBeCalledTimes(1); - expect(props.exportFullXLSX).toBeCalledWith(371); + expect(props.exportFullXLSX).toHaveBeenCalledTimes(1); + expect(props.exportFullXLSX).toHaveBeenCalledWith(371); }); test('Should not show export full Excel if report is not table', async () => { @@ -268,29 +268,29 @@ test('Should not show export full Excel if report is not table', async () => { test('Should "Show chart description"', () => { const props = createProps(); renderWrapper(props); - expect(props.toggleExpandSlice).toBeCalledTimes(0); + expect(props.toggleExpandSlice).toHaveBeenCalledTimes(0); userEvent.click(screen.getByText('Show chart description')); - expect(props.toggleExpandSlice).toBeCalledTimes(1); - expect(props.toggleExpandSlice).toBeCalledWith(371); + expect(props.toggleExpandSlice).toHaveBeenCalledTimes(1); + expect(props.toggleExpandSlice).toHaveBeenCalledWith(371); }); test('Should "Force refresh"', () => { const props = createProps(); renderWrapper(props); - expect(props.forceRefresh).toBeCalledTimes(0); + expect(props.forceRefresh).toHaveBeenCalledTimes(0); userEvent.click(screen.getByText('Force refresh')); - expect(props.forceRefresh).toBeCalledTimes(1); - expect(props.forceRefresh).toBeCalledWith(371, 26); - expect(props.addSuccessToast).toBeCalledTimes(1); + expect(props.forceRefresh).toHaveBeenCalledTimes(1); + expect(props.forceRefresh).toHaveBeenCalledWith(371, 26); + expect(props.addSuccessToast).toHaveBeenCalledTimes(1); }); test('Should "Enter fullscreen"', () => { const props = createProps(); renderWrapper(props); - expect(props.handleToggleFullSize).toBeCalledTimes(0); + expect(props.handleToggleFullSize).toHaveBeenCalledTimes(0); userEvent.click(screen.getByText('Enter fullscreen')); - expect(props.handleToggleFullSize).toBeCalledTimes(1); + expect(props.handleToggleFullSize).toHaveBeenCalledTimes(1); }); test('Drill to detail modal is under featureflag', () => { diff --git a/superset-frontend/src/dashboard/components/gridComponents/Tab.test.tsx b/superset-frontend/src/dashboard/components/gridComponents/Tab.test.tsx index 28802cc6072a3..5b6d9a7553847 100644 --- a/superset-frontend/src/dashboard/components/gridComponents/Tab.test.tsx +++ b/superset-frontend/src/dashboard/components/gridComponents/Tab.test.tsx @@ -116,7 +116,7 @@ test('Render tab (no content)', () => { useDnd: true, }); expect(screen.getByText('🚀 Aspiring Developers')).toBeInTheDocument(); - expect(EditableTitle).toBeCalledTimes(1); + expect(EditableTitle).toHaveBeenCalledTimes(1); expect(getByTestId('dragdroppable-object')).toBeInTheDocument(); }); @@ -129,7 +129,7 @@ test('Render tab (no content) editMode:true', () => { useDnd: true, }); expect(screen.getByText('🚀 Aspiring Developers')).toBeInTheDocument(); - expect(EditableTitle).toBeCalledTimes(1); + expect(EditableTitle).toHaveBeenCalledTimes(1); expect(getByTestId('dragdroppable-object')).toBeInTheDocument(); }); @@ -222,12 +222,12 @@ test('Edit table title', () => { useDnd: true, }); - expect(EditableTitle).toBeCalledTimes(1); + expect(EditableTitle).toHaveBeenCalledTimes(1); expect(getByTestId('dragdroppable-object')).toBeInTheDocument(); - expect(props.updateComponents).not.toBeCalled(); + expect(props.updateComponents).not.toHaveBeenCalled(); userEvent.click(screen.getByText('🚀 Aspiring Developers')); - expect(props.updateComponents).toBeCalled(); + expect(props.updateComponents).toHaveBeenCalled(); }); test('Render tab (with content)', () => { @@ -237,7 +237,7 @@ test('Render tab (with content)', () => { useRedux: true, useDnd: true, }); - expect(DashboardComponent).toBeCalledTimes(2); + expect(DashboardComponent).toHaveBeenCalledTimes(2); expect(DashboardComponent).toHaveBeenNthCalledWith( 1, expect.objectContaining({ @@ -316,7 +316,7 @@ test('Render tab (with content) editMode:true', () => { useRedux: true, useDnd: true, }); - expect(DashboardComponent).toBeCalledTimes(2); + expect(DashboardComponent).toHaveBeenCalledTimes(2); expect(DashboardComponent).toHaveBeenNthCalledWith( 1, expect.objectContaining({ @@ -369,14 +369,14 @@ test('Should call "handleDrop" and "handleTopDropTargetDrop"', () => { }, ); - expect(props.handleComponentDrop).not.toBeCalled(); + expect(props.handleComponentDrop).not.toHaveBeenCalled(); userEvent.click(getAllByTestId('MockDroppable')[0]); - expect(props.handleComponentDrop).toBeCalledTimes(1); - expect(props.onDropOnTab).not.toBeCalled(); + expect(props.handleComponentDrop).toHaveBeenCalledTimes(1); + expect(props.onDropOnTab).not.toHaveBeenCalled(); rerender(); userEvent.click(getAllByTestId('MockDroppable')[1]); - expect(props.onDropOnTab).toBeCalledTimes(1); - expect(props.handleComponentDrop).toBeCalledTimes(2); + expect(props.onDropOnTab).toHaveBeenCalledTimes(1); + expect(props.handleComponentDrop).toHaveBeenCalledTimes(2); }); test('Render tab content with no children, editMode: true, canEdit: true', () => { diff --git a/superset-frontend/src/dashboard/components/menu/DownloadMenuItems/DownloadAsImage.test.tsx b/superset-frontend/src/dashboard/components/menu/DownloadMenuItems/DownloadAsImage.test.tsx index 0242bd0091571..7e9d9226df7ab 100644 --- a/superset-frontend/src/dashboard/components/menu/DownloadMenuItems/DownloadAsImage.test.tsx +++ b/superset-frontend/src/dashboard/components/menu/DownloadMenuItems/DownloadAsImage.test.tsx @@ -47,15 +47,15 @@ test('Should call download image on click', async () => { const props = createProps(); renderComponent(); await waitFor(() => { - expect(downloadAsImage).toBeCalledTimes(0); - expect(props.addDangerToast).toBeCalledTimes(0); + expect(downloadAsImage).toHaveBeenCalledTimes(0); + expect(props.addDangerToast).toHaveBeenCalledTimes(0); }); userEvent.click(screen.getByRole('button', { name: 'Download as Image' })); await waitFor(() => { - expect(downloadAsImage).toBeCalledTimes(1); - expect(props.addDangerToast).toBeCalledTimes(0); + expect(downloadAsImage).toHaveBeenCalledTimes(1); + expect(props.addDangerToast).toHaveBeenCalledTimes(0); }); }); diff --git a/superset-frontend/src/dashboard/components/menu/HoverMenu.test.tsx b/superset-frontend/src/dashboard/components/menu/HoverMenu.test.tsx index b58afd12e71ed..b3c033e82d602 100644 --- a/superset-frontend/src/dashboard/components/menu/HoverMenu.test.tsx +++ b/superset-frontend/src/dashboard/components/menu/HoverMenu.test.tsx @@ -33,8 +33,8 @@ test('should call onHover when mouse enters and leaves', () => { const hoverMenu = screen.getByTestId('hover-menu'); userEvent.hover(hoverMenu); - expect(onHover).toBeCalledWith({ isHovered: true }); + expect(onHover).toHaveBeenCalledWith({ isHovered: true }); userEvent.unhover(hoverMenu); - expect(onHover).toBeCalledWith({ isHovered: false }); + expect(onHover).toHaveBeenCalledWith({ isHovered: false }); }); diff --git a/superset-frontend/src/dashboard/components/menu/ShareMenuItems/ShareMenuItems.test.tsx b/superset-frontend/src/dashboard/components/menu/ShareMenuItems/ShareMenuItems.test.tsx index 6b8ad4fe2d5c5..8420847acab4d 100644 --- a/superset-frontend/src/dashboard/components/menu/ShareMenuItems/ShareMenuItems.test.tsx +++ b/superset-frontend/src/dashboard/components/menu/ShareMenuItems/ShareMenuItems.test.tsx @@ -96,20 +96,20 @@ test('Click on "Copy dashboard URL" and succeed', async () => { ); await waitFor(() => { - expect(spy).toBeCalledTimes(0); - expect(props.addSuccessToast).toBeCalledTimes(0); - expect(props.addDangerToast).toBeCalledTimes(0); + expect(spy).toHaveBeenCalledTimes(0); + expect(props.addSuccessToast).toHaveBeenCalledTimes(0); + expect(props.addDangerToast).toHaveBeenCalledTimes(0); }); userEvent.click(screen.getByRole('button', { name: 'Copy dashboard URL' })); await waitFor(async () => { - expect(spy).toBeCalledTimes(1); + expect(spy).toHaveBeenCalledTimes(1); const value = await spy.mock.calls[0][0](); expect(value).toBe('http://localhost/superset/dashboard/p/123/'); - expect(props.addSuccessToast).toBeCalledTimes(1); - expect(props.addSuccessToast).toBeCalledWith('Copied to clipboard!'); - expect(props.addDangerToast).toBeCalledTimes(0); + expect(props.addSuccessToast).toHaveBeenCalledTimes(1); + expect(props.addSuccessToast).toHaveBeenCalledWith('Copied to clipboard!'); + expect(props.addDangerToast).toHaveBeenCalledTimes(0); }); }); @@ -124,20 +124,20 @@ test('Click on "Copy dashboard URL" and fail', async () => { ); await waitFor(() => { - expect(spy).toBeCalledTimes(0); - expect(props.addSuccessToast).toBeCalledTimes(0); - expect(props.addDangerToast).toBeCalledTimes(0); + expect(spy).toHaveBeenCalledTimes(0); + expect(props.addSuccessToast).toHaveBeenCalledTimes(0); + expect(props.addDangerToast).toHaveBeenCalledTimes(0); }); userEvent.click(screen.getByRole('button', { name: 'Copy dashboard URL' })); await waitFor(async () => { - expect(spy).toBeCalledTimes(1); + expect(spy).toHaveBeenCalledTimes(1); const value = await spy.mock.calls[0][0](); expect(value).toBe('http://localhost/superset/dashboard/p/123/'); - expect(props.addSuccessToast).toBeCalledTimes(0); - expect(props.addDangerToast).toBeCalledTimes(1); - expect(props.addDangerToast).toBeCalledWith( + expect(props.addSuccessToast).toHaveBeenCalledTimes(0); + expect(props.addDangerToast).toHaveBeenCalledTimes(1); + expect(props.addDangerToast).toHaveBeenCalledWith( 'Sorry, something went wrong. Try again later.', ); }); @@ -153,7 +153,7 @@ test('Click on "Share dashboard by email" and succeed', async () => { ); await waitFor(() => { - expect(props.addDangerToast).toBeCalledTimes(0); + expect(props.addDangerToast).toHaveBeenCalledTimes(0); expect(window.location.href).toBe(''); }); @@ -162,7 +162,7 @@ test('Click on "Share dashboard by email" and succeed', async () => { ); await waitFor(() => { - expect(props.addDangerToast).toBeCalledTimes(0); + expect(props.addDangerToast).toHaveBeenCalledTimes(0); expect(window.location.href).toBe( 'mailto:?Subject=Superset%20dashboard%20COVID%20Vaccine%20Dashboard%20&Body=Check%20out%20this%20dashboard%3A%20http%3A%2F%2Flocalhost%2Fsuperset%2Fdashboard%2Fp%2F123%2F', ); @@ -184,7 +184,7 @@ test('Click on "Share dashboard by email" and fail', async () => { ); await waitFor(() => { - expect(props.addDangerToast).toBeCalledTimes(0); + expect(props.addDangerToast).toHaveBeenCalledTimes(0); expect(window.location.href).toBe(''); }); @@ -194,8 +194,8 @@ test('Click on "Share dashboard by email" and fail', async () => { await waitFor(() => { expect(window.location.href).toBe(''); - expect(props.addDangerToast).toBeCalledTimes(1); - expect(props.addDangerToast).toBeCalledWith( + expect(props.addDangerToast).toHaveBeenCalledTimes(1); + expect(props.addDangerToast).toHaveBeenCalledWith( 'Sorry, something went wrong. Try again later.', ); }); diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/ColumnSelect.test.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/ColumnSelect.test.tsx index 1a1c6361f8ce9..163a12dc30a76 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/ColumnSelect.test.tsx +++ b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/ColumnSelect.test.tsx @@ -84,12 +84,12 @@ test('Should call "setFields" when "datasetId" changes', () => { const { rerender } = render(, { useRedux: true, }); - expect(props.form.setFields).not.toBeCalled(); + expect(props.form.setFields).not.toHaveBeenCalled(); props.datasetId = 456; rerender(); - expect(props.form.setFields).toBeCalled(); + expect(props.form.setFields).toHaveBeenCalled(); }); test('Should call "getClientErrorObject" when api returns an error', async () => { @@ -98,12 +98,12 @@ test('Should call "getClientErrorObject" when api returns an error', async () => props.datasetId = 789; const spy = jest.spyOn(uiCore, 'getClientErrorObject'); - expect(spy).not.toBeCalled(); + expect(spy).not.toHaveBeenCalled(); render(, { useRedux: true, }); await waitFor(() => { - expect(spy).toBeCalled(); + expect(spy).toHaveBeenCalled(); }); }); diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/utils.test.ts b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/utils.test.ts index 60ae8b8e5f45d..10ab8cf27f848 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/utils.test.ts +++ b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/utils.test.ts @@ -18058,7 +18058,7 @@ describe('Ensure buildTree does not throw runtime errors when encountering an in initiallyExcludedCharts, () => 'Fake title', ); - }).not.toThrowError(); + }).not.toThrow(); }); it('Avoids runtime error with invalid inputs', () => { @@ -18073,7 +18073,7 @@ describe('Ensure buildTree does not throw runtime errors when encountering an in initiallyExcludedCharts, () => 'Fake title', ); - }).not.toThrowError(); + }).not.toThrow(); expect(() => { buildTree( @@ -18086,7 +18086,7 @@ describe('Ensure buildTree does not throw runtime errors when encountering an in initiallyExcludedCharts, () => 'Fake title', ); - }).not.toThrowError(); + }).not.toThrow(); expect(() => { buildTree( @@ -18099,7 +18099,7 @@ describe('Ensure buildTree does not throw runtime errors when encountering an in initiallyExcludedCharts, () => 'Fake title', ); - }).not.toThrowError(); + }).not.toThrow(); expect(() => { buildTree( @@ -18112,7 +18112,7 @@ describe('Ensure buildTree does not throw runtime errors when encountering an in initiallyExcludedCharts, () => 'Fake title', ); - }).not.toThrowError(); + }).not.toThrow(); expect(() => { buildTree( @@ -18125,7 +18125,7 @@ describe('Ensure buildTree does not throw runtime errors when encountering an in initiallyExcludedCharts, () => 'Fake title', ); - }).not.toThrowError(); + }).not.toThrow(); expect(() => { buildTree( @@ -18138,6 +18138,6 @@ describe('Ensure buildTree does not throw runtime errors when encountering an in null, () => 'Fake title', ); - }).not.toThrowError(); + }).not.toThrow(); }); }); diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/getControlItemsMap.test.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/getControlItemsMap.test.tsx index 9d2fc12e0c00b..0c12135b333fc 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/getControlItemsMap.test.tsx +++ b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/getControlItemsMap.test.tsx @@ -160,11 +160,11 @@ test('Clicking on checkbox', () => { (getControlItems as jest.Mock).mockReturnValue(createControlItems()); const controlItemsMap = getControlItemsMap(props); renderControlItems(controlItemsMap); - expect(props.forceUpdate).not.toBeCalled(); - expect(setNativeFilterFieldValues).not.toBeCalled(); + expect(props.forceUpdate).not.toHaveBeenCalled(); + expect(setNativeFilterFieldValues).not.toHaveBeenCalled(); userEvent.click(screen.getByRole('checkbox')); - expect(setNativeFilterFieldValues).toBeCalled(); - expect(props.forceUpdate).toBeCalled(); + expect(setNativeFilterFieldValues).toHaveBeenCalled(); + expect(props.forceUpdate).toHaveBeenCalled(); }); test('Clicking on checkbox when resetConfig:false', () => { @@ -174,9 +174,9 @@ test('Clicking on checkbox when resetConfig:false', () => { ]); const controlItemsMap = getControlItemsMap(props); renderControlItems(controlItemsMap); - expect(props.forceUpdate).not.toBeCalled(); - expect(setNativeFilterFieldValues).not.toBeCalled(); + expect(props.forceUpdate).not.toHaveBeenCalled(); + expect(setNativeFilterFieldValues).not.toHaveBeenCalled(); userEvent.click(screen.getByRole('checkbox')); - expect(props.forceUpdate).toBeCalled(); - expect(setNativeFilterFieldValues).not.toBeCalled(); + expect(props.forceUpdate).toHaveBeenCalled(); + expect(setNativeFilterFieldValues).not.toHaveBeenCalled(); }); diff --git a/superset-frontend/src/dashboard/reducers/dashboardFilters.test.js b/superset-frontend/src/dashboard/reducers/dashboardFilters.test.js index a629e631937cd..a13db364cfb2f 100644 --- a/superset-frontend/src/dashboard/reducers/dashboardFilters.test.js +++ b/superset-frontend/src/dashboard/reducers/dashboardFilters.test.js @@ -131,6 +131,6 @@ describe('dashboardFilters reducer', () => { // when UPDATE_DASHBOARD_FILTERS_SCOPE is changed, applicable filters to a chart // might be changed. - expect(activeDashboardFilters.buildActiveFilters).toBeCalled(); + expect(activeDashboardFilters.buildActiveFilters).toHaveBeenCalled(); }); }); diff --git a/superset-frontend/src/explore/components/Control.test.tsx b/superset-frontend/src/explore/components/Control.test.tsx index 13fb156567045..ba08cf62da096 100644 --- a/superset-frontend/src/explore/components/Control.test.tsx +++ b/superset-frontend/src/explore/components/Control.test.tsx @@ -76,9 +76,9 @@ test('call setControlValue if isVisible is false', async () => { default: false, }), ); - expect(defaultProps.actions.setControlValue).not.toBeCalled(); + expect(defaultProps.actions.setControlValue).not.toHaveBeenCalled(); rerender(setup({ isVisible: false, default: false })); await waitFor(() => - expect(defaultProps.actions.setControlValue).toBeCalled(), + expect(defaultProps.actions.setControlValue).toHaveBeenCalled(), ); }); diff --git a/superset-frontend/src/explore/components/DataTableControl/FilterInput.test.tsx b/superset-frontend/src/explore/components/DataTableControl/FilterInput.test.tsx index 5cdb7a2a36d98..7108351be646b 100644 --- a/superset-frontend/src/explore/components/DataTableControl/FilterInput.test.tsx +++ b/superset-frontend/src/explore/components/DataTableControl/FilterInput.test.tsx @@ -30,8 +30,8 @@ test('Render a FilterInput', async () => { render(); expect(await screen.findByRole('textbox')).toBeInTheDocument(); - expect(onChangeHandler).toBeCalledTimes(0); + expect(onChangeHandler).toHaveBeenCalledTimes(0); userEvent.type(screen.getByRole('textbox'), 'test'); - expect(onChangeHandler).toBeCalledTimes(4); + expect(onChangeHandler).toHaveBeenCalledTimes(4); }); diff --git a/superset-frontend/src/explore/components/DatasourcePanel/DatasourcePanelItem.test.tsx b/superset-frontend/src/explore/components/DatasourcePanel/DatasourcePanelItem.test.tsx index 2fd4021868fe7..3ec64bf3266dd 100644 --- a/superset-frontend/src/explore/components/DatasourcePanel/DatasourcePanelItem.test.tsx +++ b/superset-frontend/src/explore/components/DatasourcePanel/DatasourcePanelItem.test.tsx @@ -124,8 +124,8 @@ test('can collapse metrics and columns', () => { { useDnd: true }, ); fireEvent.click(getByRole('button')); - expect(mockData.onCollapseMetricsChange).toBeCalled(); - expect(mockData.onCollapseColumnsChange).not.toBeCalled(); + expect(mockData.onCollapseMetricsChange).toHaveBeenCalled(); + expect(mockData.onCollapseColumnsChange).not.toHaveBeenCalled(); const startIndexOfColumnSection = mockData.metricSlice.length + 3; rerender( @@ -136,7 +136,7 @@ test('can collapse metrics and columns', () => { />, ); fireEvent.click(getByRole('button')); - expect(mockData.onCollapseColumnsChange).toBeCalled(); + expect(mockData.onCollapseColumnsChange).toHaveBeenCalled(); rerender( { render(, { useRedux: true, }); - expect(props.actions.redirectSQLLab).toBeCalledTimes(0); + expect(props.actions.redirectSQLLab).toHaveBeenCalledTimes(0); userEvent.click(screen.getByLabelText('Menu actions trigger')); userEvent.click( screen.getByRole('menuitem', { name: 'Edit chart properties' }), @@ -309,14 +309,14 @@ describe('Additional actions tests', () => { useRedux: true, }); - expect(getChartDataRequest).toBeCalledTimes(0); + expect(getChartDataRequest).toHaveBeenCalledTimes(0); userEvent.click(screen.getByLabelText('Menu actions trigger')); - expect(getChartDataRequest).toBeCalledTimes(0); + expect(getChartDataRequest).toHaveBeenCalledTimes(0); const menuItem = screen.getByText('View query').parentElement!; userEvent.click(menuItem); - await waitFor(() => expect(getChartDataRequest).toBeCalledTimes(1)); + await waitFor(() => expect(getChartDataRequest).toHaveBeenCalledTimes(1)); }); test('Should call onOpenInEditor when click on "Run in SQL Lab"', async () => { @@ -326,12 +326,12 @@ describe('Additional actions tests', () => { }); expect(await screen.findByText('Save')).toBeInTheDocument(); - expect(props.actions.redirectSQLLab).toBeCalledTimes(0); + expect(props.actions.redirectSQLLab).toHaveBeenCalledTimes(0); userEvent.click(screen.getByLabelText('Menu actions trigger')); - expect(props.actions.redirectSQLLab).toBeCalledTimes(0); + expect(props.actions.redirectSQLLab).toHaveBeenCalledTimes(0); userEvent.click(screen.getByRole('menuitem', { name: 'Run in SQL Lab' })); - expect(props.actions.redirectSQLLab).toBeCalledTimes(1); + expect(props.actions.redirectSQLLab).toHaveBeenCalledTimes(1); }); describe('Download', () => { @@ -354,16 +354,16 @@ describe('Additional actions tests', () => { useRedux: true, }); - expect(spy).toBeCalledTimes(0); + expect(spy).toHaveBeenCalledTimes(0); userEvent.click(screen.getByLabelText('Menu actions trigger')); - expect(spy).toBeCalledTimes(0); + expect(spy).toHaveBeenCalledTimes(0); userEvent.hover(screen.getByText('Download')); const downloadAsImageElement = await screen.findByText('Download as image'); userEvent.click(downloadAsImageElement); - expect(spy).toBeCalledTimes(1); + expect(spy).toHaveBeenCalledTimes(1); }); test('Should not export to CSV if canDownload=false', async () => { diff --git a/superset-frontend/src/explore/components/PropertiesModal/PropertiesModal.test.tsx b/superset-frontend/src/explore/components/PropertiesModal/PropertiesModal.test.tsx index fcdd6478d964a..a9855dc0e5813 100644 --- a/superset-frontend/src/explore/components/PropertiesModal/PropertiesModal.test.tsx +++ b/superset-frontend/src/explore/components/PropertiesModal/PropertiesModal.test.tsx @@ -171,14 +171,14 @@ test('"Close" button should call "onHide"', async () => { renderModal(props); await waitFor(() => { - expect(props.onHide).toBeCalledTimes(0); + expect(props.onHide).toHaveBeenCalledTimes(0); }); userEvent.click(screen.getByRole('button', { name: 'Close' })); await waitFor(() => { - expect(props.onHide).toBeCalledTimes(1); - expect(props.onSave).toBeCalledTimes(0); + expect(props.onHide).toHaveBeenCalledTimes(1); + expect(props.onSave).toHaveBeenCalledTimes(0); }); }); @@ -229,14 +229,14 @@ test('"Cancel" button should call "onHide"', async () => { renderModal(props); await waitFor(() => { - expect(props.onHide).toBeCalledTimes(0); + expect(props.onHide).toHaveBeenCalledTimes(0); }); userEvent.click(screen.getByRole('button', { name: 'Cancel' })); await waitFor(() => { - expect(props.onHide).toBeCalledTimes(1); - expect(props.onSave).toBeCalledTimes(0); + expect(props.onHide).toHaveBeenCalledTimes(1); + expect(props.onSave).toHaveBeenCalledTimes(0); }); }); @@ -244,16 +244,16 @@ test('"Save" button should call only "onSave"', async () => { const props = createProps(); renderModal(props); await waitFor(() => { - expect(props.onSave).toBeCalledTimes(0); - expect(props.onHide).toBeCalledTimes(0); + expect(props.onSave).toHaveBeenCalledTimes(0); + expect(props.onHide).toHaveBeenCalledTimes(0); expect(screen.getByRole('button', { name: 'Save' })).toBeEnabled(); }); userEvent.click(screen.getByRole('button', { name: 'Save' })); await waitFor(() => { - expect(props.onSave).toBeCalledTimes(1); - expect(props.onHide).toBeCalledTimes(1); + expect(props.onSave).toHaveBeenCalledTimes(1); + expect(props.onHide).toHaveBeenCalledTimes(1); }); }); @@ -289,7 +289,7 @@ test('"Name" should not be empty', async () => { userEvent.click(screen.getByRole('button', { name: 'Save' })); await waitFor(() => { - expect(props.onSave).toBeCalledTimes(0); + expect(props.onSave).toHaveBeenCalledTimes(0); }); }); @@ -307,8 +307,8 @@ test('"Name" should not be empty when saved', async () => { userEvent.click(screen.getByRole('button', { name: 'Save' })); await waitFor(() => { - expect(props.onSave).toBeCalledTimes(1); - expect(props.onSave).toBeCalledWith( + expect(props.onSave).toHaveBeenCalledTimes(1); + expect(props.onSave).toHaveBeenCalledWith( expect.objectContaining({ slice_name: 'Test chart new name' }), ); }); @@ -328,8 +328,8 @@ test('"Cache timeout" should not be empty when saved', async () => { userEvent.click(screen.getByRole('button', { name: 'Save' })); await waitFor(() => { - expect(props.onSave).toBeCalledTimes(1); - expect(props.onSave).toBeCalledWith( + expect(props.onSave).toHaveBeenCalledTimes(1); + expect(props.onSave).toHaveBeenCalledWith( expect.objectContaining({ cache_timeout: '1000' }), ); }); @@ -349,8 +349,8 @@ test('"Description" should not be empty when saved', async () => { userEvent.click(screen.getByRole('button', { name: 'Save' })); await waitFor(() => { - expect(props.onSave).toBeCalledTimes(1); - expect(props.onSave).toBeCalledWith( + expect(props.onSave).toHaveBeenCalledTimes(1); + expect(props.onSave).toHaveBeenCalledWith( expect.objectContaining({ description: 'Test description' }), ); }); @@ -370,8 +370,8 @@ test('"Certified by" should not be empty when saved', async () => { userEvent.click(screen.getByRole('button', { name: 'Save' })); await waitFor(() => { - expect(props.onSave).toBeCalledTimes(1); - expect(props.onSave).toBeCalledWith( + expect(props.onSave).toHaveBeenCalledTimes(1); + expect(props.onSave).toHaveBeenCalledWith( expect.objectContaining({ certified_by: 'Test certified by' }), ); }); @@ -393,8 +393,8 @@ test('"Certification details" should not be empty when saved', async () => { userEvent.click(screen.getByRole('button', { name: 'Save' })); await waitFor(() => { - expect(props.onSave).toBeCalledTimes(1); - expect(props.onSave).toBeCalledWith( + expect(props.onSave).toHaveBeenCalledTimes(1); + expect(props.onSave).toHaveBeenCalledWith( expect.objectContaining({ certification_details: 'Test certification details', }), diff --git a/superset-frontend/src/explore/components/controls/CollectionControl/CollectionControl.test.tsx b/superset-frontend/src/explore/components/controls/CollectionControl/CollectionControl.test.tsx index 008d97b7778ad..332cccadac49f 100644 --- a/superset-frontend/src/explore/components/controls/CollectionControl/CollectionControl.test.tsx +++ b/superset-frontend/src/explore/components/controls/CollectionControl/CollectionControl.test.tsx @@ -108,9 +108,12 @@ test('Should have add button', async () => { expect( await screen.findByRole('button', { name: 'plus-large' }), ).toBeInTheDocument(); - expect(props.onChange).toBeCalledTimes(0); + expect(props.onChange).toHaveBeenCalledTimes(0); userEvent.click(screen.getByRole('button', { name: 'plus-large' })); - expect(props.onChange).toBeCalledWith([{ key: 'hrYAZ5iBH' }, undefined]); + expect(props.onChange).toHaveBeenCalledWith([ + { key: 'hrYAZ5iBH' }, + undefined, + ]); }); test('Should have remove button', async () => { @@ -120,9 +123,9 @@ test('Should have remove button', async () => { expect( await screen.findByRole('button', { name: 'remove-item' }), ).toBeInTheDocument(); - expect(props.onChange).toBeCalledTimes(0); + expect(props.onChange).toHaveBeenCalledTimes(0); userEvent.click(screen.getByRole('button', { name: 'remove-item' })); - expect(props.onChange).toBeCalledWith([]); + expect(props.onChange).toHaveBeenCalledWith([]); }); test('Should have SortableDragger icon', async () => { @@ -136,7 +139,7 @@ test('Should call Control component', async () => { render(); expect(await screen.findByTestId('TestControl')).toBeInTheDocument(); - expect(props.onChange).toBeCalledTimes(0); + expect(props.onChange).toHaveBeenCalledTimes(0); userEvent.click(screen.getByTestId('TestControl')); - expect(props.onChange).toBeCalledWith([{ key: 'hrYAZ5iBH' }]); + expect(props.onChange).toHaveBeenCalledWith([{ key: 'hrYAZ5iBH' }]); }); diff --git a/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/AdhocMetricEditPopover.test.tsx b/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/AdhocMetricEditPopover.test.tsx index 1aa7e3acaa49e..c891c1b8ee3da 100644 --- a/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/AdhocMetricEditPopover.test.tsx +++ b/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/AdhocMetricEditPopover.test.tsx @@ -117,16 +117,16 @@ test('Should render correct elements for disallow ad-hoc metrics', () => { test('Clicking on "Close" should call onClose', () => { const props = createProps(); render(); - expect(props.onClose).toBeCalledTimes(0); + expect(props.onClose).toHaveBeenCalledTimes(0); userEvent.click(screen.getByRole('button', { name: 'Close' })); - expect(props.onClose).toBeCalledTimes(1); + expect(props.onClose).toHaveBeenCalledTimes(1); }); test('Clicking on "Save" should call onChange and onClose', async () => { const props = createProps(); render(); - expect(props.onChange).toBeCalledTimes(0); - expect(props.onClose).toBeCalledTimes(0); + expect(props.onChange).toHaveBeenCalledTimes(0); + expect(props.onClose).toHaveBeenCalledTimes(0); userEvent.click( screen.getByRole('combobox', { name: 'Select saved metrics', @@ -134,38 +134,38 @@ test('Clicking on "Save" should call onChange and onClose', async () => { ); await selectOption('sum'); userEvent.click(screen.getByRole('button', { name: 'Save' })); - expect(props.onChange).toBeCalledTimes(1); - expect(props.onClose).toBeCalledTimes(1); + expect(props.onChange).toHaveBeenCalledTimes(1); + expect(props.onClose).toHaveBeenCalledTimes(1); }); test('Clicking on "Save" should not call onChange and onClose', () => { const props = createProps(); render(); - expect(props.onChange).toBeCalledTimes(0); - expect(props.onClose).toBeCalledTimes(0); + expect(props.onChange).toHaveBeenCalledTimes(0); + expect(props.onClose).toHaveBeenCalledTimes(0); userEvent.click(screen.getByRole('button', { name: 'Save' })); - expect(props.onChange).toBeCalledTimes(0); - expect(props.onClose).toBeCalledTimes(0); + expect(props.onChange).toHaveBeenCalledTimes(0); + expect(props.onClose).toHaveBeenCalledTimes(0); }); test('Clicking on "Save" should call onChange and onClose for new metric', () => { const props = createProps(); render(); - expect(props.onChange).toBeCalledTimes(0); - expect(props.onClose).toBeCalledTimes(0); + expect(props.onChange).toHaveBeenCalledTimes(0); + expect(props.onClose).toHaveBeenCalledTimes(0); userEvent.click(screen.getByRole('button', { name: 'Save' })); - expect(props.onChange).toBeCalledTimes(1); - expect(props.onClose).toBeCalledTimes(1); + expect(props.onChange).toHaveBeenCalledTimes(1); + expect(props.onClose).toHaveBeenCalledTimes(1); }); test('Clicking on "Save" should call onChange and onClose for new title', () => { const props = createProps(); render(); - expect(props.onChange).toBeCalledTimes(0); - expect(props.onClose).toBeCalledTimes(0); + expect(props.onChange).toHaveBeenCalledTimes(0); + expect(props.onClose).toHaveBeenCalledTimes(0); userEvent.click(screen.getByRole('button', { name: 'Save' })); - expect(props.onChange).toBeCalledTimes(1); - expect(props.onClose).toBeCalledTimes(1); + expect(props.onChange).toHaveBeenCalledTimes(1); + expect(props.onClose).toHaveBeenCalledTimes(1); }); test('Should switch to tab:Simple', () => { @@ -180,11 +180,11 @@ test('Should switch to tab:Simple', () => { screen.queryByRole('tabpanel', { name: 'Simple' }), ).not.toBeInTheDocument(); - expect(props.getCurrentTab).toBeCalledTimes(1); + expect(props.getCurrentTab).toHaveBeenCalledTimes(1); const tab = screen.getByRole('tab', { name: 'Simple' }).parentElement!; userEvent.click(tab); - expect(props.getCurrentTab).toBeCalledTimes(2); + expect(props.getCurrentTab).toHaveBeenCalledTimes(2); expect( screen.queryByRole('tabpanel', { name: 'Saved' }), @@ -218,11 +218,11 @@ test('Should switch to tab:Custom SQL', () => { screen.queryByRole('tabpanel', { name: 'Custom SQL' }), ).not.toBeInTheDocument(); - expect(props.getCurrentTab).toBeCalledTimes(1); + expect(props.getCurrentTab).toHaveBeenCalledTimes(1); const tab = screen.getByRole('tab', { name: 'Custom SQL' }).parentElement!; userEvent.click(tab); - expect(props.getCurrentTab).toBeCalledTimes(2); + expect(props.getCurrentTab).toHaveBeenCalledTimes(2); expect( screen.queryByRole('tabpanel', { name: 'Saved' }), diff --git a/superset-frontend/src/explore/components/controls/SelectAsyncControl/SelectAsyncControl.test.tsx b/superset-frontend/src/explore/components/controls/SelectAsyncControl/SelectAsyncControl.test.tsx index b1f475caf5721..46e353b4968d2 100644 --- a/superset-frontend/src/explore/components/controls/SelectAsyncControl/SelectAsyncControl.test.tsx +++ b/superset-frontend/src/explore/components/controls/SelectAsyncControl/SelectAsyncControl.test.tsx @@ -91,9 +91,9 @@ test('Should send correct props to Select component - value props', async () => test('Should send correct props to Select component - function onChange multi:true', async () => { const props = createProps(); render(, { useRedux: true }); - expect(props.onChange).toBeCalledTimes(0); + expect(props.onChange).toHaveBeenCalledTimes(0); userEvent.click(await screen.findByText('onChange')); - expect(props.onChange).toBeCalledTimes(1); + expect(props.onChange).toHaveBeenCalledTimes(1); }); test('Should send correct props to Select component - function onChange multi:false', async () => { @@ -101,7 +101,7 @@ test('Should send correct props to Select component - function onChange multi:fa render(, { useRedux: true, }); - expect(props.onChange).toBeCalledTimes(0); + expect(props.onChange).toHaveBeenCalledTimes(0); userEvent.click(await screen.findByText('onChange')); - expect(props.onChange).toBeCalledTimes(1); + expect(props.onChange).toHaveBeenCalledTimes(1); }); diff --git a/superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeControl.test.tsx b/superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeControl.test.tsx index 7fdf59b78665d..e91e187ac0459 100644 --- a/superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeControl.test.tsx +++ b/superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeControl.test.tsx @@ -247,7 +247,7 @@ describe('VizTypeControl', () => { const visualizations = screen.getByTestId(getTestId('viz-row')); userEvent.click(within(visualizations).getByText('Bar Chart')); - expect(defaultProps.onChange).not.toBeCalled(); + expect(defaultProps.onChange).not.toHaveBeenCalled(); userEvent.dblClick(within(visualizations).getByText('Line Chart')); expect(defaultProps.onChange).toHaveBeenCalledWith( diff --git a/superset-frontend/src/explore/components/controls/withAsyncVerification.test.tsx b/superset-frontend/src/explore/components/controls/withAsyncVerification.test.tsx index 4f464361e1f31..dfb7319f65ee5 100644 --- a/superset-frontend/src/explore/components/controls/withAsyncVerification.test.tsx +++ b/superset-frontend/src/explore/components/controls/withAsyncVerification.test.tsx @@ -94,8 +94,8 @@ describe('VerifiedMetricsControl', () => { expect(wrapper.find(MetricsControl).length).toBe(1); - expect(verifier).toBeCalledTimes(1); - expect(verifier).toBeCalledWith( + expect(verifier).toHaveBeenCalledTimes(1); + expect(verifier).toHaveBeenCalledWith( expect.objectContaining({ savedMetrics: props.savedMetrics }), ); @@ -104,8 +104,8 @@ describe('VerifiedMetricsControl', () => { wrapper.setProps({ validMetric: ['abc'] }); }); - expect(verifier).toBeCalledTimes(2); - expect(verifier).toBeCalledWith( + expect(verifier).toHaveBeenCalledTimes(2); + expect(verifier).toHaveBeenCalledWith( expect.objectContaining({ validMetric: ['abc'] }), ); }); @@ -123,8 +123,8 @@ describe('VerifiedMetricsControl', () => { child.props().onChange?.(['abc']); expect(child.length).toBe(1); - expect(mockOnChange).toBeCalledTimes(1); - expect(mockOnChange).toBeCalledWith(['abc'], { + expect(mockOnChange).toHaveBeenCalledTimes(1); + expect(mockOnChange).toHaveBeenCalledWith(['abc'], { actions: defaultProps.actions, columns: defaultProps.columns, datasourceType: defaultProps.datasourceType, diff --git a/superset-frontend/src/explore/exploreUtils/exploreUtils.test.jsx b/superset-frontend/src/explore/exploreUtils/exploreUtils.test.jsx index b39468841bd1b..7e0a556d744e2 100644 --- a/superset-frontend/src/explore/exploreUtils/exploreUtils.test.jsx +++ b/superset-frontend/src/explore/exploreUtils/exploreUtils.test.jsx @@ -195,7 +195,7 @@ describe('exploreUtils', () => { const v1RequestPayload = buildV1ChartDataPayload({ formData: { ...formData, viz_type: 'my_custom_viz' }, }); - expect(v1RequestPayload).hasOwnProperty('queries'); + expect(v1RequestPayload.hasOwnProperty('queries')).toBeTruthy(); }); }); @@ -289,7 +289,7 @@ describe('exploreUtils', () => { exploreChart({ formData: { ...formData, viz_type: 'my_custom_viz' }, }); - expect(postFormSpy).toBeCalledTimes(1); + expect(postFormSpy).toHaveBeenCalledTimes(1); }); }); }); diff --git a/superset-frontend/src/explore/exploreUtils/shouldUseLegacyApi.test.ts b/superset-frontend/src/explore/exploreUtils/shouldUseLegacyApi.test.ts index adf42af3e84ca..f2e5b3157c7b9 100644 --- a/superset-frontend/src/explore/exploreUtils/shouldUseLegacyApi.test.ts +++ b/superset-frontend/src/explore/exploreUtils/shouldUseLegacyApi.test.ts @@ -23,11 +23,11 @@ test('Should return false', () => { const spy = jest.spyOn(Core, 'getChartMetadataRegistry'); const get = jest.fn(); spy.mockReturnValue({ get } as any); - expect(get).toBeCalledTimes(0); + expect(get).toHaveBeenCalledTimes(0); const [useLegacyApi] = getQuerySettings({ viz_type: 'name_test' }); expect(useLegacyApi).toBe(false); - expect(get).toBeCalledTimes(1); - expect(get).toBeCalledWith('name_test'); + expect(get).toHaveBeenCalledTimes(1); + expect(get).toHaveBeenCalledWith('name_test'); }); test('Should return true', () => { @@ -35,11 +35,11 @@ test('Should return true', () => { const get = jest.fn(); get.mockReturnValue({ useLegacyApi: true }); spy.mockReturnValue({ get } as any); - expect(get).toBeCalledTimes(0); + expect(get).toHaveBeenCalledTimes(0); const [useLegacyApi] = getQuerySettings({ viz_type: 'name_test' }); expect(useLegacyApi).toBe(true); - expect(get).toBeCalledTimes(1); - expect(get).toBeCalledWith('name_test'); + expect(get).toHaveBeenCalledTimes(1); + expect(get).toHaveBeenCalledWith('name_test'); }); test('Should return false when useLegacyApi:false', () => { @@ -47,9 +47,9 @@ test('Should return false when useLegacyApi:false', () => { const get = jest.fn(); get.mockReturnValue({ useLegacyApi: false }); spy.mockReturnValue({ get } as any); - expect(get).toBeCalledTimes(0); + expect(get).toHaveBeenCalledTimes(0); const [useLegacyApi] = getQuerySettings({ viz_type: 'name_test' }); expect(useLegacyApi).toBe(false); - expect(get).toBeCalledTimes(1); - expect(get).toBeCalledWith('name_test'); + expect(get).toHaveBeenCalledTimes(1); + expect(get).toHaveBeenCalledWith('name_test'); }); diff --git a/superset-frontend/src/utils/cacheWrapper.test.ts b/superset-frontend/src/utils/cacheWrapper.test.ts index f53d925e55d83..2d39a3b85dfd4 100644 --- a/superset-frontend/src/utils/cacheWrapper.test.ts +++ b/superset-frontend/src/utils/cacheWrapper.test.ts @@ -37,8 +37,8 @@ describe('cacheWrapper', () => { const returnedValue = wrappedFn(1, 2); expect(returnedValue).toEqual(fnResult); - expect(fn).toBeCalledTimes(1); - expect(fn).toBeCalledWith(1, 2); + expect(fn).toHaveBeenCalledTimes(1); + expect(fn).toHaveBeenCalledWith(1, 2); }); describe('subsequent calls', () => { @@ -48,14 +48,14 @@ describe('cacheWrapper', () => { expect(returnedValue1).toEqual(fnResult); expect(returnedValue2).toEqual(fnResult); - expect(fn).toBeCalledTimes(1); + expect(fn).toHaveBeenCalledTimes(1); }); it('fn is called multiple times for different arguments', () => { wrappedFn(1, 2); wrappedFn(1, 3); - expect(fn).toBeCalledTimes(2); + expect(fn).toHaveBeenCalledTimes(2); }); }); @@ -77,7 +77,7 @@ describe('cacheWrapper', () => { wrappedFn(1, 2); wrappedFn(1, 3); - expect(fn).toBeCalledTimes(1); + expect(fn).toHaveBeenCalledTimes(1); }); }); }); diff --git a/superset-websocket/spec/index.test.ts b/superset-websocket/spec/index.test.ts index 1643c9f6ac8b1..20a399d395c61 100644 --- a/superset-websocket/spec/index.test.ts +++ b/superset-websocket/spec/index.test.ts @@ -94,10 +94,10 @@ describe('server', () => { response as unknown as http.ServerResponse, ); - expect(writeHeadMock).toBeCalledTimes(1); + expect(writeHeadMock).toHaveBeenCalledTimes(1); expect(writeHeadMock).toHaveBeenLastCalledWith(200); - expect(endMock).toBeCalledTimes(1); + expect(endMock).toHaveBeenCalledTimes(1); expect(endMock).toHaveBeenLastCalledWith('OK'); }); @@ -123,10 +123,10 @@ describe('server', () => { response as unknown as http.ServerResponse, ); - expect(writeHeadMock).toBeCalledTimes(1); + expect(writeHeadMock).toHaveBeenCalledTimes(1); expect(writeHeadMock).toHaveBeenLastCalledWith(404); - expect(endMock).toBeCalledTimes(1); + expect(endMock).toHaveBeenCalledTimes(1); expect(endMock).toHaveBeenLastCalledWith('Not Found'); }); }); @@ -200,16 +200,16 @@ describe('server', () => { const sendMock = jest.spyOn(ws, 'send'); const socketInstance = { ws: ws, channel: channelId, pongTs: Date.now() }; - expect(statsdIncrementMock).toBeCalledTimes(0); + expect(statsdIncrementMock).toHaveBeenCalledTimes(0); server.trackClient(channelId, socketInstance); - expect(statsdIncrementMock).toBeCalledTimes(1); + expect(statsdIncrementMock).toHaveBeenCalledTimes(1); expect(statsdIncrementMock).toHaveBeenNthCalledWith( 1, 'ws_connected_client', ); server.processStreamResults(streamReturnValue); - expect(statsdIncrementMock).toBeCalledTimes(1); + expect(statsdIncrementMock).toHaveBeenCalledTimes(1); const message1 = `{"id":"1615426152415-0","channel_id":"${channelId}","job_id":"c9b99965-8f1e-4ce5-aa43-d6fc94d6a510","user_id":"1","status":"done","errors":[],"result_url":"/superset/explore_json/data/ejr-37281682b1282cdb8f25e0de0339b386"}`; const message2 = `{"id":"1615426152516-0","channel_id":"${channelId}","job_id":"f1e5bb1f-f2f1-4f21-9b2f-c9b91dcc9b59","user_id":"1","status":"done","errors":[],"result_url":"/api/v1/chart/data/qc-64e8452dc9907dd77746cb75a19202de"}`; @@ -221,9 +221,9 @@ describe('server', () => { const ws = new wsMock('localhost'); const sendMock = jest.spyOn(ws, 'send'); - expect(statsdIncrementMock).toBeCalledTimes(0); + expect(statsdIncrementMock).toHaveBeenCalledTimes(0); server.processStreamResults(streamReturnValue); - expect(statsdIncrementMock).toBeCalledTimes(0); + expect(statsdIncrementMock).toHaveBeenCalledTimes(0); expect(sendMock).not.toHaveBeenCalled(); }); @@ -236,16 +236,16 @@ describe('server', () => { const cleanChannelMock = jest.spyOn(server, 'cleanChannel'); const socketInstance = { ws: ws, channel: channelId, pongTs: Date.now() }; - expect(statsdIncrementMock).toBeCalledTimes(0); + expect(statsdIncrementMock).toHaveBeenCalledTimes(0); server.trackClient(channelId, socketInstance); - expect(statsdIncrementMock).toBeCalledTimes(1); + expect(statsdIncrementMock).toHaveBeenCalledTimes(1); expect(statsdIncrementMock).toHaveBeenNthCalledWith( 1, 'ws_connected_client', ); server.processStreamResults(streamReturnValue); - expect(statsdIncrementMock).toBeCalledTimes(2); + expect(statsdIncrementMock).toHaveBeenCalledTimes(2); expect(statsdIncrementMock).toHaveBeenNthCalledWith( 2, 'ws_client_send_error', From 60cd2550a71ddafdfe671be3533b48eee633b398 Mon Sep 17 00:00:00 2001 From: wugeer <1284057728@qq.com> Date: Wed, 30 Oct 2024 07:44:22 +0800 Subject: [PATCH 012/307] feat: cancel impala query on stop (#30412) --- superset/db_engine_specs/base.py | 20 ++++- superset/db_engine_specs/impala.py | 42 +++++++++- .../unit_tests/db_engine_specs/test_impala.py | 79 ++++++++++++++++++- 3 files changed, 135 insertions(+), 6 deletions(-) diff --git a/superset/db_engine_specs/base.py b/superset/db_engine_specs/base.py index dcdfff6c3f242..2e555e32f1cc9 100644 --- a/superset/db_engine_specs/base.py +++ b/superset/db_engine_specs/base.py @@ -58,8 +58,8 @@ from sqlalchemy.types import TypeEngine from sqlparse.tokens import CTE -from superset import sql_parse -from superset.constants import TimeGrain as TimeGrainConstants +from superset import db, sql_parse +from superset.constants import QUERY_CANCEL_KEY, TimeGrain as TimeGrainConstants from superset.databases.utils import get_table_metadata, make_url_safe from superset.errors import ErrorLevel, SupersetError, SupersetErrorType from superset.exceptions import DisallowedSQLFunction, OAuth2Error, OAuth2RedirectError @@ -437,6 +437,14 @@ class BaseEngineSpec: # pylint: disable=too-many-public-methods # Driver-specific exception that should be mapped to OAuth2RedirectError oauth2_exception = OAuth2RedirectError + # Does the query id related to the connection? + # The default value is True, which means that the query id is determined when + # the connection is created. + # When this is changed to false in a DB engine spec it means the query id + # is determined only after the specific query is executed and it will update + # the `cancel_query` value in the `extra` field of the `query` object + has_query_id_before_execute = True + @classmethod def is_oauth2_enabled(cls) -> bool: return ( @@ -1316,6 +1324,7 @@ def handle_cursor(cls, cursor: Any, query: Query) -> None: # TODO: Fix circular import error caused by importing sql_lab.Query @classmethod + # pylint: disable=consider-using-transaction def execute_with_cursor( cls, cursor: Any, @@ -1333,6 +1342,13 @@ def execute_with_cursor( """ logger.debug("Query %d: Running query: %s", query.id, sql) cls.execute(cursor, sql, query.database, async_=True) + if not cls.has_query_id_before_execute: + cancel_query_id = query.database.db_engine_spec.get_cancel_query_id( + cursor, query + ) + if cancel_query_id is not None: + query.set_extra_json_key(QUERY_CANCEL_KEY, cancel_query_id) + db.session.commit() logger.debug("Query %d: Handling cursor", query.id) cls.handle_cursor(cursor, query) diff --git a/superset/db_engine_specs/impala.py b/superset/db_engine_specs/impala.py index ea74df83164f0..ce34ae5648f20 100644 --- a/superset/db_engine_specs/impala.py +++ b/superset/db_engine_specs/impala.py @@ -21,8 +21,9 @@ import re import time from datetime import datetime -from typing import Any, TYPE_CHECKING +from typing import Any, Optional, TYPE_CHECKING +import requests from flask import current_app from sqlalchemy import types from sqlalchemy.engine.reflection import Inspector @@ -57,6 +58,8 @@ class ImpalaEngineSpec(BaseEngineSpec): TimeGrain.YEAR: "TRUNC({col}, 'YYYY')", } + has_query_id_before_execute = False + @classmethod def epoch_to_dttm(cls) -> str: return "from_unixtime({col})" @@ -91,7 +94,7 @@ def has_implicit_cancel(cls) -> bool: :see: handle_cursor """ - return True + return False @classmethod def execute( @@ -160,3 +163,38 @@ def handle_cursor(cls, cursor: Any, query: Query) -> None: except Exception: # pylint: disable=broad-except logger.debug("Call to status() failed ") return + + @classmethod + def get_cancel_query_id(cls, cursor: Any, query: Query) -> Optional[str]: + """ + Get Impala Query ID that will be used to cancel the running + queries to release impala resources. + + :param cursor: Cursor instance in which the query will be executed + :param query: Query instance + :return: Impala Query ID + """ + last_operation = getattr(cursor, "_last_operation", None) + if not last_operation: + return None + guid = last_operation.handle.operationId.guid[::-1].hex() + return f"{guid[-16:]}:{guid[:16]}" + + @classmethod + def cancel_query(cls, cursor: Any, query: Query, cancel_query_id: str) -> bool: + """ + Cancel query in the underlying database. + + :param cursor: New cursor instance to the db of the query + :param query: Query instance + :param cancel_query_id: impala db not need + :return: True if query cancelled successfully, False otherwise + """ + try: + impala_host = query.database.url_object.host + url = f"http://{impala_host}:25000/cancel_query?query_id={cancel_query_id}" + response = requests.post(url, timeout=3) + except Exception: # pylint: disable=broad-except + return False + + return bool(response and response.status_code == 200) diff --git a/tests/unit_tests/db_engine_specs/test_impala.py b/tests/unit_tests/db_engine_specs/test_impala.py index efaed81cba7ad..543db243684c5 100644 --- a/tests/unit_tests/db_engine_specs/test_impala.py +++ b/tests/unit_tests/db_engine_specs/test_impala.py @@ -17,9 +17,13 @@ from datetime import datetime from typing import Optional +from unittest.mock import Mock, patch import pytest +from superset.db_engine_specs.impala import ImpalaEngineSpec as spec +from superset.models.core import Database +from superset.models.sql_lab import Query from tests.unit_tests.db_engine_specs.utils import assert_convert_dttm from tests.unit_tests.fixtures.common import dttm # noqa: F401 @@ -37,6 +41,77 @@ def test_convert_dttm( expected_result: Optional[str], dttm: datetime, # noqa: F811 ) -> None: - from superset.db_engine_specs.impala import ImpalaEngineSpec as spec - assert_convert_dttm(spec, target_type, expected_result, dttm) + + +def test_get_cancel_query_id() -> None: + query = Query() + + cursor_mock = Mock() + last_operation_mock = Mock() + cursor_mock._last_operation = last_operation_mock + + guid = bytes(reversed(bytes.fromhex("9fbdba20000000006940643a2731718b"))) + last_operation_mock.handle.operationId.guid = guid + + assert ( + spec.get_cancel_query_id(cursor_mock, query) + == "6940643a2731718b:9fbdba2000000000" + ) + + +@patch("requests.post") +def test_cancel_query(post_mock: Mock) -> None: + query = Query() + database = Database( + database_name="test_impala", sqlalchemy_uri="impala://localhost:21050/default" + ) + query.database = database + + response_mock = Mock() + response_mock.status_code = 200 + post_mock.return_value = response_mock + + result = spec.cancel_query(None, query, "6940643a2731718b:9fbdba2000000000") + + post_mock.assert_called_once_with( + "http://localhost:25000/cancel_query?query_id=6940643a2731718b:9fbdba2000000000", + timeout=3, + ) + assert result is True + + +@patch("requests.post") +def test_cancel_query_failed(post_mock: Mock) -> None: + query = Query() + database = Database( + database_name="test_impala", sqlalchemy_uri="impala://localhost:21050/default" + ) + query.database = database + + response_mock = Mock() + response_mock.status_code = 500 + post_mock.return_value = response_mock + + result = spec.cancel_query(None, query, "6940643a2731718b:9fbdba2000000000") + + post_mock.assert_called_once_with( + "http://localhost:25000/cancel_query?query_id=6940643a2731718b:9fbdba2000000000", + timeout=3, + ) + assert result is False + + +@patch("requests.post") +def test_cancel_query_exception(post_mock: Mock) -> None: + query = Query() + database = Database( + database_name="test_impala", sqlalchemy_uri="impala://localhost:21050/default" + ) + query.database = database + + post_mock.side_effect = Exception("Network error") + + result = spec.cancel_query(None, query, "6940643a2731718b:9fbdba2000000000") + + assert result is False From a74ef412fbaa26a268b31a488da9bfb7b44ac6e0 Mon Sep 17 00:00:00 2001 From: Hung Date: Wed, 30 Oct 2024 08:05:45 +0700 Subject: [PATCH 013/307] fix(country-map): Rename incorrect Vietnam province name for Country Map (#30608) --- .../scripts/Country Map GeoJSON Generator.ipynb | 3 +++ .../src/countries/vietnam.geojson | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/superset-frontend/plugins/legacy-plugin-chart-country-map/scripts/Country Map GeoJSON Generator.ipynb b/superset-frontend/plugins/legacy-plugin-chart-country-map/scripts/Country Map GeoJSON Generator.ipynb index b3ad9631b3d1f..2969a7f96e43e 100644 --- a/superset-frontend/plugins/legacy-plugin-chart-country-map/scripts/Country Map GeoJSON Generator.ipynb +++ b/superset-frontend/plugins/legacy-plugin-chart-country-map/scripts/Country Map GeoJSON Generator.ipynb @@ -2648,6 +2648,9 @@ "replace_name(vietnam_copy, 'Hau Giang', 'Hậu Giang')\n", "replace_name(vietnam_copy, 'Ha Noi', 'Hà Nội')\n", "replace_name(vietnam_copy, 'Can Tho', 'Cần Thơ')\n", + "replace_name(vietnam_copy, 'Đông Nam Bộ', 'Đồng Nai')\n", + "replace_name(vietnam_copy, 'Đông Bắc', 'Bắc Kạn')\n", + "replace_name(vietnam_copy, 'Đồng Bằng Sông Hồng', 'Hưng Yên')\n", "for i in vietnam_copy['name']:\n", " print(i)" ] diff --git a/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/vietnam.geojson b/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/vietnam.geojson index 748ec3a64af7f..9ed539bc7b9f1 100644 --- a/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/vietnam.geojson +++ b/superset-frontend/plugins/legacy-plugin-chart-country-map/src/countries/vietnam.geojson @@ -39,7 +39,7 @@ { "type": "Feature", "properties": { "ISO": "VN-49", "NAME_1": "Vĩnh Long" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 105.996567502348185, 9.888559491461711 ], [ 105.93287194100003, 9.95538971600007 ], [ 105.838510089810569, 10.004751968856691 ], [ 105.692236363417408, 10.123180853713393 ], [ 105.707894321965341, 10.174547226873017 ], [ 105.727531365979701, 10.185631822550533 ], [ 105.818998651266725, 10.143127956989588 ], [ 105.867884555727642, 10.140725001757403 ], [ 105.900957472908999, 10.160103665152008 ], [ 105.914600050751687, 10.213950507010281 ], [ 105.882922397550544, 10.238936062049618 ], [ 105.849022658069146, 10.301438706830822 ], [ 105.984569940050676, 10.284178778727664 ], [ 106.100738560436184, 10.249090480841005 ], [ 106.15788821700005, 10.195379950000074 ], [ 106.182139519000032, 10.133042710000041 ], [ 106.246429884000065, 10.077460028000075 ], [ 106.134018182293232, 9.993679713847712 ], [ 106.132571242368897, 9.945827338161109 ], [ 105.996567502348185, 9.888559491461711 ] ] ] } }, { "type": "Feature", "properties": { "ISO": "VN-51", "NAME_1": "Trà Vinh" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 106.246429884000065, 10.077460028000075 ], [ 106.500987175000034, 9.834051825000074 ], [ 106.537852410000028, 9.751166083000044 ], [ 106.574961785000028, 9.739081122000073 ], [ 106.563161655000044, 9.614325262000079 ], [ 106.497243686000047, 9.549994208000044 ], [ 106.398203972000033, 9.542059637000079 ], [ 106.250336134000065, 9.63117096600007 ], [ 106.064707879000025, 9.804266669000071 ], [ 105.996567502348185, 9.888559491461711 ], [ 106.132571242368897, 9.945827338161109 ], [ 106.134018182293232, 9.993679713847712 ], [ 106.246429884000065, 10.077460028000075 ] ] ] } }, { "type": "Feature", "properties": { "ISO": "VN-50", "NAME_1": "Bến Tre" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ 106.422373893840074, 10.316961981110524 ], [ 106.480316602000073, 10.280829169000071 ], [ 106.720876498000052, 10.199693101000037 ], [ 106.797618035000028, 10.157212632000039 ], [ 106.791270379000025, 10.110174872000073 ], [ 106.737071160000028, 10.05414459800005 ], [ 106.704112175000034, 10.048895575000074 ], [ 106.69662519600007, 10.083644924000055 ], [ 106.668711785000028, 10.032416083000044 ], [ 106.684092644000032, 10.01203034100007 ], [ 106.664235873000052, 10.006089585000041 ], [ 106.648936394000032, 9.974351304000038 ], [ 106.607432488000029, 9.974839585000041 ], [ 106.468923373000052, 10.058986721000053 ], [ 106.359873894000032, 10.220689195000091 ], [ 106.292002800000034, 10.261704820000091 ], [ 106.349375847000033, 10.214829820000091 ], [ 106.36850019600007, 10.155910549000055 ], [ 106.461680535000028, 10.035711981000077 ], [ 106.696299675000034, 9.896551825000074 ], [ 106.668711785000028, 9.842840887000079 ], [ 106.676442905000044, 9.866766669000071 ], [ 106.662608269000032, 9.883734442000048 ], [ 106.637868686000047, 9.825995184000078 ], [ 106.586761915000068, 9.822943427000041 ], [ 106.504405144000032, 9.905462958000044 ], [ 106.395030144000032, 9.974351304000038 ], [ 106.136485222000033, 10.234564520000049 ], [ 105.954907667554778, 10.28851959939999 ], [ 105.973155143894758, 10.31334056231708 ], [ 106.003428581263961, 10.321071681412946 ], [ 106.10718834706455, 10.296250718495855 ], [ 106.354340039860915, 10.338975327149626 ], [ 106.422373893840074, 10.316961981110524 ] ] ], [ [ [ 106.498057488000029, 9.891180731000077 ], [ 106.544118686000047, 9.838039455000057 ], [ 106.535655144000032, 9.829169012000079 ], [ 106.422373894000032, 9.939032294000071 ], [ 106.498057488000029, 9.891180731000077 ] ] ] ] } }, -{ "type": "Feature", "properties": { "ISO": "VN-39", "NAME_1": "Đông Nam Bộ" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 106.997813347000033, 10.624904690000051 ], [ 106.984141472000033, 10.566880601000037 ], [ 106.964128881242857, 10.605376922007338 ], [ 106.892500259879057, 10.670073740810494 ], [ 106.836468193152541, 10.66083133799583 ], [ 106.757029250299638, 10.705393378501583 ], [ 106.751138136915415, 10.772495225474245 ], [ 106.793822869629707, 10.752625637463211 ], [ 106.828962844359751, 10.77086741839662 ], [ 106.877745396033163, 10.760790513971017 ], [ 106.885341830860739, 10.788179023343218 ], [ 106.832270136257762, 10.917344265525401 ], [ 106.787518345095521, 10.980673733505967 ], [ 106.787518345095521, 11.034675604995186 ], [ 106.827309197961085, 11.055527044937151 ], [ 106.902084995925804, 11.025968126128078 ], [ 106.954691604334016, 11.064001979807529 ], [ 106.974587029867507, 11.122422187234122 ], [ 106.933866001015076, 11.214742133242851 ], [ 106.964768507860299, 11.283626816924027 ], [ 107.080213657834008, 11.402740994001647 ], [ 107.104294875308199, 11.475423895996016 ], [ 107.308520136295215, 11.566219386815249 ], [ 107.382520787004694, 11.559501451131041 ], [ 107.398023715921681, 11.505964666735963 ], [ 107.458795200837812, 11.482529405307787 ], [ 107.443188918233943, 11.441214098152102 ], [ 107.456676467345062, 11.410414944094384 ], [ 107.52680138627494, 11.402508450004973 ], [ 107.609535354273135, 11.361684068365037 ], [ 107.548247105419534, 11.289156196001613 ], [ 107.430941604371526, 11.038086248781326 ], [ 107.459777052768743, 11.008837389234088 ], [ 107.531348911622956, 11.000129910367036 ], [ 107.557393832959008, 10.979666043153372 ], [ 107.588399692591679, 10.91176321050375 ], [ 107.5907768094022, 10.85086253527777 ], [ 107.516569452218391, 10.756062120570391 ], [ 107.482669711837673, 10.798410956500447 ], [ 107.457865024850946, 10.801511541924128 ], [ 107.342471551720678, 10.683740952882658 ], [ 107.300148553313022, 10.696401678794416 ], [ 107.288779737694711, 10.759007677262503 ], [ 107.266558873093459, 10.774433091813705 ], [ 107.151010370332301, 10.727665919946219 ], [ 107.133440382967251, 10.675214342068216 ], [ 107.040526157755949, 10.636792913861882 ], [ 107.025318916934452, 10.635272493031096 ], [ 107.013194207000026, 10.672674872000073 ], [ 106.984141472000033, 10.699367580000057 ], [ 106.97974694100003, 10.684759833000044 ], [ 107.01140384200005, 10.655259507000039 ], [ 106.997813347000033, 10.624904690000051 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "VN-39", "NAME_1": "Đồng Nai" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 106.997813347000033, 10.624904690000051 ], [ 106.984141472000033, 10.566880601000037 ], [ 106.964128881242857, 10.605376922007338 ], [ 106.892500259879057, 10.670073740810494 ], [ 106.836468193152541, 10.66083133799583 ], [ 106.757029250299638, 10.705393378501583 ], [ 106.751138136915415, 10.772495225474245 ], [ 106.793822869629707, 10.752625637463211 ], [ 106.828962844359751, 10.77086741839662 ], [ 106.877745396033163, 10.760790513971017 ], [ 106.885341830860739, 10.788179023343218 ], [ 106.832270136257762, 10.917344265525401 ], [ 106.787518345095521, 10.980673733505967 ], [ 106.787518345095521, 11.034675604995186 ], [ 106.827309197961085, 11.055527044937151 ], [ 106.902084995925804, 11.025968126128078 ], [ 106.954691604334016, 11.064001979807529 ], [ 106.974587029867507, 11.122422187234122 ], [ 106.933866001015076, 11.214742133242851 ], [ 106.964768507860299, 11.283626816924027 ], [ 107.080213657834008, 11.402740994001647 ], [ 107.104294875308199, 11.475423895996016 ], [ 107.308520136295215, 11.566219386815249 ], [ 107.382520787004694, 11.559501451131041 ], [ 107.398023715921681, 11.505964666735963 ], [ 107.458795200837812, 11.482529405307787 ], [ 107.443188918233943, 11.441214098152102 ], [ 107.456676467345062, 11.410414944094384 ], [ 107.52680138627494, 11.402508450004973 ], [ 107.609535354273135, 11.361684068365037 ], [ 107.548247105419534, 11.289156196001613 ], [ 107.430941604371526, 11.038086248781326 ], [ 107.459777052768743, 11.008837389234088 ], [ 107.531348911622956, 11.000129910367036 ], [ 107.557393832959008, 10.979666043153372 ], [ 107.588399692591679, 10.91176321050375 ], [ 107.5907768094022, 10.85086253527777 ], [ 107.516569452218391, 10.756062120570391 ], [ 107.482669711837673, 10.798410956500447 ], [ 107.457865024850946, 10.801511541924128 ], [ 107.342471551720678, 10.683740952882658 ], [ 107.300148553313022, 10.696401678794416 ], [ 107.288779737694711, 10.759007677262503 ], [ 107.266558873093459, 10.774433091813705 ], [ 107.151010370332301, 10.727665919946219 ], [ 107.133440382967251, 10.675214342068216 ], [ 107.040526157755949, 10.636792913861882 ], [ 107.025318916934452, 10.635272493031096 ], [ 107.013194207000026, 10.672674872000073 ], [ 106.984141472000033, 10.699367580000057 ], [ 106.97974694100003, 10.684759833000044 ], [ 107.01140384200005, 10.655259507000039 ], [ 106.997813347000033, 10.624904690000051 ] ] ] } }, { "type": "Feature", "properties": { "ISO": "VN-40", "NAME_1": "Bình Thuận" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ 108.905964763452928, 11.323376750700559 ], [ 108.838063998000052, 11.330755927000041 ], [ 108.787852410000028, 11.300685940000051 ], [ 108.729340040000068, 11.181545315000051 ], [ 108.656260613000029, 11.19281647300005 ], [ 108.57740319100003, 11.17914459800005 ], [ 108.531260613000029, 11.153265692000048 ], [ 108.500336134000065, 11.120835679000038 ], [ 108.47234134200005, 11.053168036000045 ], [ 108.36882571700005, 11.022772528000075 ], [ 108.34498131600003, 10.953802802000041 ], [ 108.315440300000034, 10.944322007000039 ], [ 108.30005944100003, 10.91282786700009 ], [ 108.285329623000052, 10.943345445000091 ], [ 108.258636915000068, 10.95180898600006 ], [ 108.106455925000034, 10.918158270000049 ], [ 108.06568444100003, 10.867987372000073 ], [ 107.998301629000025, 10.699367580000057 ], [ 107.882334832000026, 10.716986395000049 ], [ 107.768321160000028, 10.650213934000078 ], [ 107.586517774000072, 10.573513088000084 ], [ 107.516569452218391, 10.756062120570391 ], [ 107.5907768094022, 10.85086253527777 ], [ 107.588399692591679, 10.91176321050375 ], [ 107.544991490364964, 10.99214590101252 ], [ 107.476985304927837, 11.001447659082203 ], [ 107.430941604371526, 11.038086248781326 ], [ 107.511453485190145, 11.220865789724428 ], [ 107.597288038612021, 11.357575791689442 ], [ 107.756348098186152, 11.31491689739687 ], [ 108.010182733146564, 11.301481025129192 ], [ 108.045891147758198, 11.283704332189188 ], [ 108.0528674658608, 11.211021430194819 ], [ 108.066044955710083, 11.203399156046203 ], [ 108.131829054866955, 11.269364122356365 ], [ 108.250529819895235, 11.306519476892333 ], [ 108.324892205810613, 11.356258042974275 ], [ 108.338689813284191, 11.379305732573471 ], [ 108.314660271754121, 11.466897284282254 ], [ 108.341170281982897, 11.507928372396464 ], [ 108.386490513026729, 11.523844713362791 ], [ 108.513717888869451, 11.527720445142393 ], [ 108.580432164013132, 11.505215358801763 ], [ 108.620171340035256, 11.564023138956657 ], [ 108.666886835059358, 11.562834581450772 ], [ 108.704920688738753, 11.536712143950297 ], [ 108.721508824172872, 11.476638291923621 ], [ 108.762901645694342, 11.458603217464486 ], [ 108.771893345401509, 11.407779445764788 ], [ 108.867908156036549, 11.387987372119539 ], [ 108.905964763452928, 11.323376750700559 ] ] ], [ [ [ 108.942556186000047, 10.551947333000044 ], [ 108.958994988000029, 10.537543036000045 ], [ 108.960785352000073, 10.502875067000048 ], [ 108.930186394000032, 10.514553127000056 ], [ 108.929453972000033, 10.544826565000051 ], [ 108.942556186000047, 10.551947333000044 ] ] ] ] } }, { "type": "Feature", "properties": { "ISO": "VN-36", "NAME_1": "Ninh Thuận" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 109.20386803488185, 11.788682359303436 ], [ 109.242930535000028, 11.735663153000075 ], [ 109.13599694100003, 11.570217190000051 ], [ 109.067067905000044, 11.583807684000078 ], [ 109.043467644000032, 11.638495184000078 ], [ 109.020274285000028, 11.632798570000091 ], [ 109.04037519600007, 11.601507880000042 ], [ 109.04037519600007, 11.542873440000051 ], [ 109.012461785000028, 11.542873440000051 ], [ 109.028330925000034, 11.474269924000055 ], [ 109.022471550000034, 11.367621161000045 ], [ 109.005625847000033, 11.343654690000051 ], [ 108.96607506600003, 11.31476471600007 ], [ 108.933360222000033, 11.31118398600006 ], [ 108.905964763452928, 11.323376750700559 ], [ 108.867908156036549, 11.387987372119539 ], [ 108.778611281085716, 11.401965846746407 ], [ 108.762901645694342, 11.458603217464486 ], [ 108.715152622795244, 11.486301785199203 ], [ 108.6969625178059, 11.547770901206093 ], [ 108.620171340035256, 11.564023138956657 ], [ 108.606993850185972, 11.614381821763629 ], [ 108.610094435609653, 11.640142524058206 ], [ 108.683319939963212, 11.727113959041958 ], [ 108.637379592194407, 11.839200141173535 ], [ 108.681304559257967, 11.973171292021505 ], [ 108.694792108369086, 12.155330715340199 ], [ 108.719183384205792, 12.181143093578896 ], [ 108.792253858928404, 12.145538030855448 ], [ 108.890955844736425, 11.943121445897987 ], [ 109.0504293145612, 11.898033758850886 ], [ 109.085982701340527, 11.819382229106566 ], [ 109.114094680225264, 11.797962348383635 ], [ 109.20386803488185, 11.788682359303436 ] ] ] } }, { "type": "Feature", "properties": { "ISO": "VN-32", "NAME_1": "Phú Yên" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 109.237071160000028, 13.698594468000067 ], [ 109.247569207000026, 13.622707424000055 ], [ 109.303884311000047, 13.568793036000045 ], [ 109.28679446700005, 13.557603257000039 ], [ 109.29420006600003, 13.530340887000079 ], [ 109.218516472000033, 13.646958726000037 ], [ 109.210134311000047, 13.630804755000042 ], [ 109.28679446700005, 13.50922272300005 ], [ 109.314219597000033, 13.52289459800005 ], [ 109.303721550000034, 13.479885158000059 ], [ 109.339691602000073, 13.46548086100006 ], [ 109.307383660000028, 13.406805731000077 ], [ 109.273203972000033, 13.431057033000059 ], [ 109.30046634200005, 13.461371161000045 ], [ 109.262543165000068, 13.489325262000079 ], [ 109.245127800000034, 13.485174872000073 ], [ 109.232188347000033, 13.393133856000077 ], [ 109.280039910000028, 13.352769273000092 ], [ 109.299327019000032, 13.36469147300005 ], [ 109.307383660000028, 13.352769273000092 ], [ 109.305674675000034, 13.333889065000051 ], [ 109.28679446700005, 13.331040757000039 ], [ 109.29420006600003, 13.297552802000041 ], [ 109.273203972000033, 13.310614325000074 ], [ 109.258962436000047, 13.297552802000041 ], [ 109.29420006600003, 13.235500393000052 ], [ 109.303721550000034, 13.303168036000045 ], [ 109.318125847000033, 13.288885809000078 ], [ 109.307383660000028, 13.133042710000041 ], [ 109.328379754000025, 13.084662177000041 ], [ 109.465017123000052, 12.913316148000092 ], [ 109.462901238000029, 12.862127997000073 ], [ 109.43091881600003, 12.845119533000059 ], [ 109.450043165000068, 12.873236395000049 ], [ 109.438243035000028, 12.878607489000046 ], [ 109.384613477000073, 12.833970445000091 ], [ 109.342659540205545, 12.853091741990283 ], [ 109.195691765762319, 12.846813055877817 ], [ 109.073890415310359, 12.754079697819805 ], [ 109.03730350065598, 12.752658596317133 ], [ 108.861603632401682, 12.806996365489852 ], [ 108.739182164325371, 12.880351060153316 ], [ 108.660840692044246, 12.99623545969871 ], [ 108.665491571079087, 13.038997708577369 ], [ 108.687815790266484, 13.071295478503544 ], [ 108.845015496967562, 13.174570828081244 ], [ 108.87483279819503, 13.211312771467192 ], [ 108.821709425849292, 13.430498359012063 ], [ 108.825636835371597, 13.557519029279774 ], [ 108.909714389607359, 13.537830308421974 ], [ 108.977823927831935, 13.5425587018226 ], [ 109.080711704681391, 13.58707794808879 ], [ 109.163135614317127, 13.673300076037663 ], [ 109.237071160000028, 13.698594468000067 ] ] ] } }, @@ -56,8 +56,8 @@ { "type": "Feature", "properties": { "ISO": "VN-70", "NAME_1": "Vĩnh Phúc" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 105.429391440662414, 21.276437788273313 ], [ 105.457470330791068, 21.31172272382463 ], [ 105.392151319627658, 21.408771064133305 ], [ 105.343678827216081, 21.43468679515945 ], [ 105.317427199405699, 21.514139308782035 ], [ 105.460364210639739, 21.497163601518992 ], [ 105.577721389430508, 21.543827419699653 ], [ 105.764221633421585, 21.384922389756468 ], [ 105.779879591969575, 21.179120999434588 ], [ 105.762671339810424, 21.104965318194843 ], [ 105.670170525749143, 21.157623603446552 ], [ 105.494522333438908, 21.173694973144507 ], [ 105.455816685291722, 21.208576565456099 ], [ 105.429391440662414, 21.276437788273313 ] ] ] } }, { "type": "Feature", "properties": { "ISO": "VN-68", "NAME_1": "Phú Thọ" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 105.317427199405699, 21.514139308782035 ], [ 105.343678827216081, 21.43468679515945 ], [ 105.392151319627658, 21.408771064133305 ], [ 105.457780389153584, 21.300405585049702 ], [ 105.429391440662414, 21.276437788273313 ], [ 105.414682245289328, 21.307226874420678 ], [ 105.353807407585748, 21.301413276301616 ], [ 105.343162063278555, 21.238212999530276 ], [ 105.284871047061131, 21.191549181349615 ], [ 105.305955030999826, 21.126669419757889 ], [ 105.284871047061131, 21.054374091391196 ], [ 105.329881219742447, 20.981406969456032 ], [ 105.332671746803612, 20.918826809409723 ], [ 105.138109979092235, 20.940479234129327 ], [ 105.042043491613811, 21.00858877235396 ], [ 104.942256301087355, 21.053598945035276 ], [ 104.873629998925253, 21.137624823326917 ], [ 104.865775180779906, 21.250201930974299 ], [ 104.828516472557112, 21.329602769552139 ], [ 104.895127394913288, 21.365414536951278 ], [ 104.919311965174984, 21.397919013351782 ], [ 104.889959751041658, 21.567055976452139 ], [ 104.946597120860417, 21.640255642383977 ], [ 105.111754999393668, 21.703946845570442 ], [ 105.233194614639729, 21.618732407974221 ], [ 105.317427199405699, 21.514139308782035 ] ] ] } }, { "type": "Feature", "properties": { "ISO": "VN-HN", "NAME_1": "Hà Nội" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 105.785822382197125, 20.568305569346535 ], [ 105.679782343080603, 20.637655341021173 ], [ 105.629656203371042, 20.742119249004134 ], [ 105.515968051684183, 20.828625596893744 ], [ 105.505736119426331, 20.862499497953479 ], [ 105.533486363105112, 20.927120877126754 ], [ 105.504495884177686, 20.987246405996814 ], [ 105.437109817264229, 21.018562323092738 ], [ 105.307918735761007, 21.011921901774315 ], [ 105.290968866020307, 21.038199368006417 ], [ 105.286834750922992, 21.075561428117396 ], [ 105.305955030999826, 21.126669419757889 ], [ 105.284871047061131, 21.191549181349615 ], [ 105.343162063278555, 21.238212999530276 ], [ 105.353807407585748, 21.301413276301616 ], [ 105.414682245289328, 21.307226874420678 ], [ 105.455816685291722, 21.208576565456099 ], [ 105.494522333438908, 21.173694973144507 ], [ 105.670170525749143, 21.157623603446552 ], [ 105.762671339810424, 21.104965318194843 ], [ 105.779879591969575, 21.179120999434588 ], [ 105.772128126611733, 21.362468980259223 ], [ 105.805046014162201, 21.373088487044015 ], [ 105.84835086540005, 21.363631700242763 ], [ 105.920801223397689, 21.328052475940979 ], [ 105.94607099837782, 21.265782376055768 ], [ 105.920956252129315, 21.208731594187725 ], [ 105.922041456847694, 21.150466417291284 ], [ 105.939094680275218, 21.108918565239605 ], [ 106.010304803024212, 21.045692450046488 ], [ 106.012785271722862, 21.016908678492712 ], [ 106.004723748901824, 20.991303004929705 ], [ 105.912429641314873, 20.965929877162068 ], [ 105.895324741943227, 20.914356798427491 ], [ 105.924728632020731, 20.886709905737519 ], [ 105.915065138745092, 20.809634508026136 ], [ 105.956147901904103, 20.786819363322934 ], [ 105.981314324996049, 20.717185369908862 ], [ 106.007204217600531, 20.713232122864156 ], [ 105.976508417229638, 20.681011868203143 ], [ 105.825509882275185, 20.660341295414412 ], [ 105.785822382197125, 20.568305569346535 ] ] ] } }, -{ "type": "Feature", "properties": { "ISO": "VN-53", "NAME_1": "Đông Bắc" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 105.557515903735919, 21.950882676794095 ], [ 105.494987421432313, 22.101209418180076 ], [ 105.494677362170478, 22.268563544571919 ], [ 105.519843785262424, 22.340290432157701 ], [ 105.609295688944826, 22.469972439176729 ], [ 105.607021925821186, 22.517643947709985 ], [ 105.567644484105642, 22.592238878521414 ], [ 105.648466425085417, 22.677944240734121 ], [ 105.724947543594226, 22.724142970921378 ], [ 105.773833448954463, 22.713704332189138 ], [ 105.765255162195956, 22.617301947926535 ], [ 105.815122918587804, 22.505267441739022 ], [ 105.86147667840595, 22.47501089093987 ], [ 105.895014682681392, 22.474700833476675 ], [ 106.048183627972037, 22.540226549315776 ], [ 106.107921584113797, 22.530563056040194 ], [ 106.137738886240584, 22.43183523181051 ], [ 106.162078485233849, 22.408839219954018 ], [ 106.192980992079072, 22.406694648039547 ], [ 106.220266147764448, 22.320808416874911 ], [ 106.260005323786629, 22.262103990406843 ], [ 106.190448845637661, 22.111777249020804 ], [ 106.123476189874225, 22.054313056002741 ], [ 106.113967727128852, 21.948117988154593 ], [ 106.035936314109563, 21.928015855247509 ], [ 106.001468133847254, 21.887759915287859 ], [ 105.915530226738554, 21.834688218886185 ], [ 105.839152460117873, 21.814172674829081 ], [ 105.813727654607533, 21.779265244995031 ], [ 105.78706261564713, 21.827737739205304 ], [ 105.772903273866973, 21.977806098172891 ], [ 105.734869419288202, 22.019741522952927 ], [ 105.699832798244984, 22.033125719276484 ], [ 105.6450557803999, 22.019508978956196 ], [ 105.584387649170651, 21.956954657331551 ], [ 105.557515903735919, 21.950882676794095 ] ] ] } }, -{ "type": "Feature", "properties": { "ISO": "VN-66", "NAME_1": "Đồng Bằng Sông Hồng" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 106.257369826356353, 20.695894680395156 ], [ 106.206468540290871, 20.667214259830189 ], [ 106.138669061328073, 20.666826687101889 ], [ 106.112882522410416, 20.649566758998731 ], [ 106.112365756674308, 20.631609198006061 ], [ 106.059655796377854, 20.616623033026542 ], [ 106.02699629124578, 20.663286851207204 ], [ 106.030200230356286, 20.708090318313509 ], [ 105.981314324996049, 20.717185369908862 ], [ 105.956147901904103, 20.786819363322934 ], [ 105.915065138745092, 20.809634508026136 ], [ 105.924728632020731, 20.886709905737519 ], [ 105.895324741943227, 20.914356798427491 ], [ 105.912429641314873, 20.965929877162068 ], [ 106.022758824260279, 20.997736721572437 ], [ 106.152156610439192, 20.997814235938222 ], [ 106.159598015635879, 20.926190701139944 ], [ 106.125749952997865, 20.851208198499535 ], [ 106.126576776197226, 20.813536078227401 ], [ 106.257369826356353, 20.695894680395156 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "VN-53", "NAME_1": "Bắc Kạn" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 105.557515903735919, 21.950882676794095 ], [ 105.494987421432313, 22.101209418180076 ], [ 105.494677362170478, 22.268563544571919 ], [ 105.519843785262424, 22.340290432157701 ], [ 105.609295688944826, 22.469972439176729 ], [ 105.607021925821186, 22.517643947709985 ], [ 105.567644484105642, 22.592238878521414 ], [ 105.648466425085417, 22.677944240734121 ], [ 105.724947543594226, 22.724142970921378 ], [ 105.773833448954463, 22.713704332189138 ], [ 105.765255162195956, 22.617301947926535 ], [ 105.815122918587804, 22.505267441739022 ], [ 105.86147667840595, 22.47501089093987 ], [ 105.895014682681392, 22.474700833476675 ], [ 106.048183627972037, 22.540226549315776 ], [ 106.107921584113797, 22.530563056040194 ], [ 106.137738886240584, 22.43183523181051 ], [ 106.162078485233849, 22.408839219954018 ], [ 106.192980992079072, 22.406694648039547 ], [ 106.220266147764448, 22.320808416874911 ], [ 106.260005323786629, 22.262103990406843 ], [ 106.190448845637661, 22.111777249020804 ], [ 106.123476189874225, 22.054313056002741 ], [ 106.113967727128852, 21.948117988154593 ], [ 106.035936314109563, 21.928015855247509 ], [ 106.001468133847254, 21.887759915287859 ], [ 105.915530226738554, 21.834688218886185 ], [ 105.839152460117873, 21.814172674829081 ], [ 105.813727654607533, 21.779265244995031 ], [ 105.78706261564713, 21.827737739205304 ], [ 105.772903273866973, 21.977806098172891 ], [ 105.734869419288202, 22.019741522952927 ], [ 105.699832798244984, 22.033125719276484 ], [ 105.6450557803999, 22.019508978956196 ], [ 105.584387649170651, 21.956954657331551 ], [ 105.557515903735919, 21.950882676794095 ] ] ] } }, +{ "type": "Feature", "properties": { "ISO": "VN-66", "NAME_1": "Hưng Yên" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 106.257369826356353, 20.695894680395156 ], [ 106.206468540290871, 20.667214259830189 ], [ 106.138669061328073, 20.666826687101889 ], [ 106.112882522410416, 20.649566758998731 ], [ 106.112365756674308, 20.631609198006061 ], [ 106.059655796377854, 20.616623033026542 ], [ 106.02699629124578, 20.663286851207204 ], [ 106.030200230356286, 20.708090318313509 ], [ 105.981314324996049, 20.717185369908862 ], [ 105.956147901904103, 20.786819363322934 ], [ 105.915065138745092, 20.809634508026136 ], [ 105.924728632020731, 20.886709905737519 ], [ 105.895324741943227, 20.914356798427491 ], [ 105.912429641314873, 20.965929877162068 ], [ 106.022758824260279, 20.997736721572437 ], [ 106.152156610439192, 20.997814235938222 ], [ 106.159598015635879, 20.926190701139944 ], [ 106.125749952997865, 20.851208198499535 ], [ 106.126576776197226, 20.813536078227401 ], [ 106.257369826356353, 20.695894680395156 ] ] ] } }, { "type": "Feature", "properties": { "ISO": "VN-56", "NAME_1": "Bắc Ninh" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 106.152156610439192, 20.997814235938222 ], [ 106.004723748901824, 20.991303004929705 ], [ 106.010304803024212, 21.045692450046488 ], [ 105.939094680275218, 21.108918565239605 ], [ 105.922041456847694, 21.150466417291284 ], [ 105.920956252129315, 21.208731594187725 ], [ 105.944985792760065, 21.247488919178238 ], [ 106.046633335260196, 21.206431993541628 ], [ 106.227552525128885, 21.177880764185886 ], [ 106.298039178365343, 21.134059149909831 ], [ 106.315815871305347, 21.050524197133996 ], [ 106.295041944829848, 21.000527249532922 ], [ 106.22646732041045, 20.985515245232364 ], [ 106.152156610439192, 20.997814235938222 ] ] ] } }, { "type": "Feature", "properties": { "ISO": "VN-54", "NAME_1": "Bắc Giang" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 107.065330844742675, 21.360531113919762 ], [ 106.998616571397633, 21.314668281416061 ], [ 106.980633172882563, 21.230564886959939 ], [ 106.947870314963041, 21.189688829375939 ], [ 106.759199659736453, 21.161680203278763 ], [ 106.54582767121002, 21.193719590786486 ], [ 106.487950067041936, 21.228006903895505 ], [ 106.422165968784384, 21.23095245968824 ], [ 106.329510125991476, 21.18800934545493 ], [ 106.298039178365343, 21.134059149909831 ], [ 106.227552525128885, 21.177880764185886 ], [ 106.046633335260196, 21.206431993541628 ], [ 105.944985792760065, 21.247488919178238 ], [ 105.920801223397689, 21.328052475940979 ], [ 105.971082390939557, 21.408771064133305 ], [ 106.035471226116158, 21.419493922806282 ], [ 106.067148879317301, 21.461377672541516 ], [ 106.071903111139648, 21.502589626909753 ], [ 106.038726841170728, 21.620205186320277 ], [ 106.050354039207491, 21.632685045078745 ], [ 106.143785028356319, 21.620980333575517 ], [ 106.161303338877929, 21.602635198955227 ], [ 106.165489129919365, 21.51713654231753 ], [ 106.291941359406167, 21.477474879761871 ], [ 106.352919549897251, 21.423860581900328 ], [ 106.398704868934487, 21.411070664779345 ], [ 106.477976516303158, 21.448303534580418 ], [ 106.522108188941729, 21.544912625317409 ], [ 106.580399205159154, 21.599095363959862 ], [ 106.658740675641639, 21.607363593255229 ], [ 106.747727492229956, 21.549253445090415 ], [ 106.82792931468606, 21.597157498519721 ], [ 106.921980422358558, 21.445022081104128 ], [ 107.00683312384956, 21.441766466049557 ], [ 107.024093051952718, 21.376163234945295 ], [ 107.065330844742675, 21.360531113919762 ] ] ] } }, { "type": "Feature", "properties": { "ISO": "VN-69", "NAME_1": "Thái Nguyên" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 105.577721389430508, 21.543827419699653 ], [ 105.537052037421574, 21.578683172690262 ], [ 105.518293491651264, 21.635501410561631 ], [ 105.534364862248538, 21.866779283237292 ], [ 105.557515903735919, 21.950882676794095 ], [ 105.584387649170651, 21.956954657331551 ], [ 105.626865676309876, 22.010439764883245 ], [ 105.683709750804326, 22.030748603365339 ], [ 105.717196080035023, 22.030335191315999 ], [ 105.772903273866973, 21.977806098172891 ], [ 105.785305617360336, 21.83784048115325 ], [ 105.80690636613582, 21.780040392250271 ], [ 105.839152460117873, 21.814172674829081 ], [ 105.899407180197159, 21.825954902496733 ], [ 106.001468133847254, 21.887759915287859 ], [ 106.035936314109563, 21.928015855247509 ], [ 106.113967727128852, 21.948117988154593 ], [ 106.141924677281963, 21.805336004752803 ], [ 106.181353794042309, 21.785388902375928 ], [ 106.256698032787938, 21.684878241437673 ], [ 106.16750451062461, 21.57077667950017 ], [ 106.143785028356319, 21.620980333575517 ], [ 106.041517369131213, 21.628421738772204 ], [ 106.071903111139648, 21.502589626909753 ], [ 106.067148879317301, 21.461377672541516 ], [ 106.035471226116158, 21.419493922806282 ], [ 105.971082390939557, 21.408771064133305 ], [ 105.920801223397689, 21.328052475940979 ], [ 105.84835086540005, 21.363631700242763 ], [ 105.805046014162201, 21.373088487044015 ], [ 105.772128126611733, 21.362468980259223 ], [ 105.740037063159889, 21.417556057366141 ], [ 105.577721389430508, 21.543827419699653 ] ] ] } }, From eb14c762aff4a5e1b2225afdddaa3a983129a313 Mon Sep 17 00:00:00 2001 From: Yuvraj Rimal Date: Tue, 29 Oct 2024 21:29:33 -0400 Subject: [PATCH 014/307] docs: Update INTHEWILD.md with Medic (#30749) --- RESOURCES/INTHEWILD.md | 1 + 1 file changed, 1 insertion(+) diff --git a/RESOURCES/INTHEWILD.md b/RESOURCES/INTHEWILD.md index 1af6c1be8abeb..a28d432448157 100644 --- a/RESOURCES/INTHEWILD.md +++ b/RESOURCES/INTHEWILD.md @@ -155,6 +155,7 @@ Join our growing community! - [Care](https://www.getcare.io/) [@alandao2021] - [Living Goods](https://www.livinggoods.org) [@chelule] - [Maieutical Labs](https://maieuticallabs.it) [@xrmx] +- [Medic](https://medic.org) [@1yuv] - [REDCap Cloud](https://www.redcapcloud.com/) - [TrustMedis](https://trustmedis.com/) [@famasya] - [WeSure](https://www.wesure.cn/) From 73768f63134aacda43cba01ea55e6b2347b78733 Mon Sep 17 00:00:00 2001 From: Maxime Beauchemin Date: Tue, 29 Oct 2024 18:47:20 -0700 Subject: [PATCH 015/307] fix(explore): column data type tooltip format (#30588) --- .../src/components/labelUtils.tsx | 10 ++-------- .../test/components/labelUtils.test.tsx | 2 +- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/superset-frontend/packages/superset-ui-chart-controls/src/components/labelUtils.tsx b/superset-frontend/packages/superset-ui-chart-controls/src/components/labelUtils.tsx index 66b25416f8b52..03af5c13e8695 100644 --- a/superset-frontend/packages/superset-ui-chart-controls/src/components/labelUtils.tsx +++ b/superset-frontend/packages/superset-ui-chart-controls/src/components/labelUtils.tsx @@ -55,8 +55,7 @@ const TooltipSection = ({ text: ReactNode; }) => ( - {label} - {text} + {label}: {text} ); @@ -71,12 +70,7 @@ export const getColumnTypeTooltipNode = (column: ColumnMeta): ReactNode => { return null; } - return ( - - ); + return ; }; export const getColumnTooltipNode = ( diff --git a/superset-frontend/packages/superset-ui-chart-controls/test/components/labelUtils.test.tsx b/superset-frontend/packages/superset-ui-chart-controls/test/components/labelUtils.test.tsx index d32081b8988b8..9b5b760f79151 100644 --- a/superset-frontend/packages/superset-ui-chart-controls/test/components/labelUtils.test.tsx +++ b/superset-frontend/packages/superset-ui-chart-controls/test/components/labelUtils.test.tsx @@ -90,7 +90,7 @@ test('should get column datatype rendered as tooltip when column has a type', () , ); - expect(screen.getByText('Column datatype')).toBeVisible(); + expect(screen.getByText('Column type')).toBeVisible(); expect(screen.getByText('text')).toBeVisible(); }); From d5a98e0189d50a6ca27e81f8d0f738be1bb3f404 Mon Sep 17 00:00:00 2001 From: Geido <60598000+geido@users.noreply.github.com> Date: Wed, 30 Oct 2024 14:19:26 +0200 Subject: [PATCH 016/307] chore(Dashboard): Simplify scoping logic for cross/native filters (#30719) --- .../cypress/e2e/dashboard/utils.ts | 2 +- .../cypress/support/directories.ts | 4 +- .../src/dashboard/components/Dashboard.jsx | 25 +-- .../FilterScope/FilterScope.tsx | 65 +++---- .../FiltersConfigForm/FiltersConfigForm.tsx | 4 +- .../FiltersConfigModal/FiltersConfigModal.tsx | 4 +- .../Footer/CancelConfirmationAlert.tsx | 1 + .../nativeFilters/FiltersConfigModal/utils.ts | 1 - .../dashboard/util/getRelatedCharts.test.ts | 177 ++---------------- .../src/dashboard/util/getRelatedCharts.ts | 89 ++------- .../util/useFilterFocusHighlightStyles.ts | 3 - 11 files changed, 80 insertions(+), 295 deletions(-) diff --git a/superset-frontend/cypress-base/cypress/e2e/dashboard/utils.ts b/superset-frontend/cypress-base/cypress/e2e/dashboard/utils.ts index 7b89b75a4ba62..854f0a5880f3a 100644 --- a/superset-frontend/cypress-base/cypress/e2e/dashboard/utils.ts +++ b/superset-frontend/cypress-base/cypress/e2e/dashboard/utils.ts @@ -378,7 +378,7 @@ export function cancelNativeFilterSettings() { .should('be.visible') .should('have.text', 'There are unsaved changes.'); cy.get(nativeFilters.modal.footer) - .find(nativeFilters.modal.yesCancelButton) + .find(nativeFilters.modal.confirmCancelButton) .contains('cancel') .click({ force: true }); cy.get(nativeFilters.modal.container).should('not.exist'); diff --git a/superset-frontend/cypress-base/cypress/support/directories.ts b/superset-frontend/cypress-base/cypress/support/directories.ts index 77268a5e04734..b59aa1bf81963 100644 --- a/superset-frontend/cypress-base/cypress/support/directories.ts +++ b/superset-frontend/cypress-base/cypress/support/directories.ts @@ -322,7 +322,9 @@ export const nativeFilters = { footer: '.ant-modal-footer', saveButton: dataTestLocator('native-filter-modal-save-button'), cancelButton: dataTestLocator('native-filter-modal-cancel-button'), - yesCancelButton: '[type="button"]', + confirmCancelButton: dataTestLocator( + 'native-filter-modal-confirm-cancel-button', + ), alertXUnsavedFilters: '.ant-alert-message', tabsList: { filterItemsContainer: dataTestLocator('filter-title-container'), diff --git a/superset-frontend/src/dashboard/components/Dashboard.jsx b/superset-frontend/src/dashboard/components/Dashboard.jsx index 1953889c5d418..1a852edda89d3 100644 --- a/superset-frontend/src/dashboard/components/Dashboard.jsx +++ b/superset-frontend/src/dashboard/components/Dashboard.jsx @@ -212,7 +212,7 @@ class Dashboard extends PureComponent { applyFilters() { const { appliedFilters } = this; - const { activeFilters, ownDataCharts, datasources, slices } = this.props; + const { activeFilters, ownDataCharts, slices } = this.props; // refresh charts if a filter was removed, added, or changed @@ -231,22 +231,12 @@ class Dashboard extends PureComponent { ) { // filterKey is removed? affectedChartIds.push( - ...getRelatedCharts( - appliedFilters, - activeFilters, - slices, - datasources, - )[filterKey], + ...getRelatedCharts(appliedFilters, activeFilters, slices)[filterKey], ); } else if (!appliedFilterKeys.includes(filterKey)) { // filterKey is newly added? affectedChartIds.push( - ...getRelatedCharts( - activeFilters, - appliedFilters, - slices, - datasources, - )[filterKey], + ...getRelatedCharts(activeFilters, appliedFilters, slices)[filterKey], ); } else { // if filterKey changes value, @@ -261,12 +251,9 @@ class Dashboard extends PureComponent { ) ) { affectedChartIds.push( - ...getRelatedCharts( - activeFilters, - appliedFilters, - slices, - datasources, - )[filterKey], + ...getRelatedCharts(activeFilters, appliedFilters, slices)[ + filterKey + ], ); } diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/FilterScope.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/FilterScope.tsx index d5b554a2f5a03..682894acc294c 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/FilterScope.tsx +++ b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/FilterScope.tsx @@ -17,13 +17,8 @@ * under the License. */ -import { FC, useCallback, useRef, useState } from 'react'; -import { - NativeFilterScope, - styled, - t, - useComponentDidUpdate, -} from '@superset-ui/core'; +import { FC, useCallback, useEffect, useMemo, useRef, useState } from 'react'; +import { NativeFilterScope, styled, t } from '@superset-ui/core'; import { Radio } from 'src/components/Radio'; import { AntdForm, Typography } from 'src/components'; import { ScopingType } from './types'; @@ -32,7 +27,7 @@ import { getDefaultScopeValue, isScopingAll } from './utils'; type FilterScopeProps = { pathToFormValue?: string[]; - updateFormValues: (values: any) => void; + updateFormValues: (values: any, triggerFormChange?: boolean) => void; formFilterScope?: NativeFilterScope; forceUpdate: Function; filterScope?: NativeFilterScope; @@ -64,17 +59,19 @@ const FilterScope: FC = ({ chartId, initiallyExcludedCharts, }) => { - const [initialFilterScope] = useState( - filterScope || getDefaultScopeValue(chartId, initiallyExcludedCharts), + const initialFilterScope = useMemo( + () => filterScope || getDefaultScopeValue(chartId, initiallyExcludedCharts), + [chartId, filterScope, initiallyExcludedCharts], ); const lastSpecificScope = useRef(initialFilterScope); - const [initialScopingType] = useState( - isScopingAll(initialFilterScope, chartId) - ? ScopingType.All - : ScopingType.Specific, + const initialScopingType = useMemo( + () => + isScopingAll(initialFilterScope, chartId) + ? ScopingType.All + : ScopingType.Specific, + [chartId, initialFilterScope], ); - const [hasScopeBeenModified, setHasScopeBeenModified] = - useState(!!filterScope); + const [hasScopeBeenModified, setHasScopeBeenModified] = useState(false); const onUpdateFormValues = useCallback( (formValues: any) => { @@ -87,26 +84,24 @@ const FilterScope: FC = ({ [formScopingType, updateFormValues], ); - const updateScopes = useCallback(() => { - if (filterScope || hasScopeBeenModified) { - return; - } + const updateScopes = useCallback( + updatedFormValues => { + if (hasScopeBeenModified) { + return; + } - const newScope = getDefaultScopeValue(chartId, initiallyExcludedCharts); - updateFormValues({ - scope: newScope, - scoping: isScopingAll(newScope, chartId) - ? ScopingType.All - : ScopingType.Specific, - }); - }, [ - chartId, - filterScope, - hasScopeBeenModified, - initiallyExcludedCharts, - updateFormValues, - ]); - useComponentDidUpdate(updateScopes); + updateFormValues(updatedFormValues, false); + }, + [hasScopeBeenModified, updateFormValues], + ); + + useEffect(() => { + const updatedFormValues = { + scope: initialFilterScope, + scoping: initialScopingType, + }; + updateScopes(updatedFormValues); + }, [initialFilterScope, initialScopingType, updateScopes]); return ( diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx index b7c66412fa94e..e498d2cd6a1e5 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx +++ b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx @@ -583,9 +583,9 @@ const FiltersConfigForm = ( !datasetId || datasetDetails || formFilter?.dataset?.label; const updateFormValues = useCallback( - (values: any) => { + (values: any, triggerFormChange = true) => { setNativeFilterFieldValues(form, filterId, values); - formChanged(); + if (triggerFormChange) formChanged(); }, [filterId, form, formChanged], ); diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigModal.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigModal.tsx index 037f461bc5a37..649ac735de24a 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigModal.tsx +++ b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigModal.tsx @@ -297,7 +297,6 @@ function FiltersConfigModal({ setRemovedFilters, setOrderedFilters, setSaveAlertVisible, - filterChanges, filterId => { setFilterChanges(prev => ({ ...prev, @@ -510,7 +509,8 @@ function FiltersConfigModal({ unsavedFiltersIds.length > 0 || form.isFieldsTouched() || changed || - didChangeOrder + didChangeOrder || + Object.values(removedFilters).some(f => f?.isPending) ) { setSaveAlertVisible(true); } else { diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/Footer/CancelConfirmationAlert.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/Footer/CancelConfirmationAlert.tsx index b36769ada561b..16d15a06b0d71 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/Footer/CancelConfirmationAlert.tsx +++ b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/Footer/CancelConfirmationAlert.tsx @@ -61,6 +61,7 @@ export function CancelConfirmationAlert({ buttonSize="small" buttonStyle="primary" onClick={onConfirm} + data-test="native-filter-modal-confirm-cancel-button" > {t('Yes, cancel')} diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/utils.ts b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/utils.ts index f0d09d9aa3940..af51dedbe6ddf 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/utils.ts +++ b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/utils.ts @@ -170,7 +170,6 @@ export const createHandleRemoveItem = val: string[] | ((prevState: string[]) => string[]), ) => void, setSaveAlertVisible: Function, - filterChanges: FilterChangesType, removeFilter: (filterId: string) => void, ) => (filterId: string) => { diff --git a/superset-frontend/src/dashboard/util/getRelatedCharts.test.ts b/superset-frontend/src/dashboard/util/getRelatedCharts.test.ts index 94762e8f780dd..874b912d90ff8 100644 --- a/superset-frontend/src/dashboard/util/getRelatedCharts.test.ts +++ b/superset-frontend/src/dashboard/util/getRelatedCharts.test.ts @@ -19,11 +19,9 @@ import { AppliedCrossFilterType, - DatasourceType, Filter, NativeFilterType, } from '@superset-ui/core'; -import { DatasourcesState } from '../types'; import { getRelatedCharts } from './getRelatedCharts'; const slices = { @@ -32,48 +30,11 @@ const slices = { '3': { datasource: 'ds1', slice_id: 3 }, } as any; -const datasources: DatasourcesState = { - ds1: { - uid: 'ds1', - datasource_name: 'ds1', - table_name: 'table1', - description: '', - id: 100, - columns: [{ column_name: 'column1' }, { column_name: 'column2' }], - column_names: ['column1', 'column2'], - column_types: [], - type: DatasourceType.Table, - metrics: [], - column_formats: {}, - currency_formats: {}, - verbose_map: {}, - main_dttm_col: '', - filter_select_enabled: true, - }, - ds2: { - uid: 'ds2', - datasource_name: 'ds2', - table_name: 'table2', - description: '', - id: 200, - columns: [{ column_name: 'column3' }, { column_name: 'column4' }], - column_names: ['column3', 'column4'], - column_types: [], - type: DatasourceType.Table, - metrics: [], - column_formats: {}, - currency_formats: {}, - verbose_map: {}, - main_dttm_col: '', - filter_select_enabled: true, - }, -}; - -test('Return chart ids matching the dataset id with native filter', () => { +test('Return all chart ids in global scope with native filters', () => { const filters = { filterKey1: { filterType: 'filter_select', - chartsInScope: [1, 2], + chartsInScope: [1, 2, 3], scope: { excluded: [], rootPath: [], @@ -88,167 +49,67 @@ test('Return chart ids matching the dataset id with native filter', () => { } as unknown as Filter, }; - const result = getRelatedCharts(filters, null, slices, datasources); - expect(result).toEqual({ - filterKey1: [1], - }); -}); - -test('Return chart ids matching the dataset id with cross filter', () => { - const filters = { - '3': { - filterType: undefined, - scope: [1, 2], - targets: [], - values: null, - } as AppliedCrossFilterType, - }; - - const result = getRelatedCharts(filters, null, slices, datasources); + const result = getRelatedCharts(filters, null, slices); expect(result).toEqual({ - '3': [1], + filterKey1: [1, 2, 3], }); }); -test('Return chart ids matching the column name with native filter', () => { +test('Return only chart ids in specific scope with native filters', () => { const filters = { filterKey1: { filterType: 'filter_select', - chartsInScope: [1, 2], + chartsInScope: [1, 3], scope: { excluded: [], rootPath: [], }, targets: [ { - column: { name: 'column3' }, - datasetId: 999, + column: { name: 'column1' }, + datasetId: 100, }, ], type: NativeFilterType.NativeFilter, } as unknown as Filter, }; - const result = getRelatedCharts(filters, null, slices, datasources); + const result = getRelatedCharts(filters, null, slices); expect(result).toEqual({ - filterKey1: [2], + filterKey1: [1, 3], }); }); -test('Return chart ids matching the column name with cross filter', () => { +test('Return all chart ids with cross filter in global scope', () => { const filters = { - '1': { + '3': { filterType: undefined, - scope: [1, 2], + scope: [1, 2, 3], targets: [], - values: { - filters: [{ col: 'column3' }], - }, + values: null, } as AppliedCrossFilterType, }; - const result = getRelatedCharts(filters, null, slices, datasources); - expect(result).toEqual({ - '1': [2], - }); -}); - -test('Return chart ids when column display name matches with native filter', () => { - const filters = { - filterKey1: { - filterType: 'filter_select', - chartsInScope: [1, 2], - scope: { - excluded: [], - rootPath: [], - }, - targets: [ - { - column: { name: 'column4', displayName: 'column4' }, - datasetId: 999, - }, - ], - type: NativeFilterType.NativeFilter, - } as unknown as Filter, - }; - - const result = getRelatedCharts(filters, null, slices, datasources); + const result = getRelatedCharts(filters, null, slices); expect(result).toEqual({ - filterKey1: [2], + '3': [1, 2], }); }); -test('Return chart ids when column display name matches with cross filter', () => { +test('Return only chart ids in specific scope with cross filter', () => { const filters = { '1': { filterType: undefined, scope: [1, 2], targets: [], values: { - filters: [{ col: 'column4' }], + filters: [{ col: 'column3' }], }, } as AppliedCrossFilterType, }; - const result = getRelatedCharts(filters, null, slices, datasources); + const result = getRelatedCharts(filters, null, slices); expect(result).toEqual({ '1': [2], }); }); - -test('Return scope when filterType is not filter_select', () => { - const filters = { - filterKey1: { - filterType: 'filter_time', - chartsInScope: [3, 4], - } as Filter, - }; - - const result = getRelatedCharts(filters, null, slices, datasources); - expect(result).toEqual({ - filterKey1: [3, 4], - }); -}); - -test('Return an empty array if no matching charts found with native filter', () => { - const filters = { - filterKey1: { - filterType: 'filter_select', - chartsInScope: [1, 2], - scope: { - excluded: [], - rootPath: [], - }, - targets: [ - { - column: { name: 'nonexistent_column' }, - datasetId: 300, - }, - ], - type: NativeFilterType.NativeFilter, - } as unknown as Filter, - }; - - const result = getRelatedCharts(filters, null, slices, datasources); - expect(result).toEqual({ - filterKey1: [], - }); -}); - -test('Return an empty array if no matching charts found with cross filter', () => { - const filters = { - '1': { - filterType: undefined, - scope: [1, 2], - targets: [], - values: { - filters: [{ col: 'nonexistent_column' }], - }, - } as AppliedCrossFilterType, - }; - - const result = getRelatedCharts(filters, null, slices, datasources); - expect(result).toEqual({ - '1': [], - }); -}); diff --git a/superset-frontend/src/dashboard/util/getRelatedCharts.ts b/superset-frontend/src/dashboard/util/getRelatedCharts.ts index aba56ba3b6c19..a75d9a7173c99 100644 --- a/superset-frontend/src/dashboard/util/getRelatedCharts.ts +++ b/superset-frontend/src/dashboard/util/getRelatedCharts.ts @@ -20,56 +20,31 @@ import { AppliedCrossFilterType, AppliedNativeFilterType, - ensureIsArray, Filter, isAppliedCrossFilterType, isAppliedNativeFilterType, isNativeFilter, } from '@superset-ui/core'; import { Slice } from 'src/types/Chart'; -import { DatasourcesState } from '../types'; -function checkForExpression(formData?: Record) { - const groupby = ensureIsArray(formData?.groupby) ?? []; - const allColumns = ensureIsArray(formData?.all_columns) ?? []; - const checkColumns = groupby.concat(allColumns); - return checkColumns.some( - (col: string | Record) => - typeof col !== 'string' && col.expressionType !== undefined, - ); +function isGlobalScope(scope: number[], slices: Record) { + return scope.length === Object.keys(slices).length; } function getRelatedChartsForSelectFilter( nativeFilter: AppliedNativeFilterType | Filter, slices: Record, chartsInScope: number[], - datasources: DatasourcesState, ) { return Object.values(slices) .filter(slice => { - const { datasource, slice_id } = slice; - // not in scope, ignore - if (!chartsInScope.includes(slice_id)) return false; + const { slice_id } = slice; + // all have been selected, always apply + if (isGlobalScope(chartsInScope, slices)) return true; + // hand-picked in scope, always apply + if (chartsInScope.includes(slice_id)) return true; - const chartDatasource = datasource - ? datasources[datasource] - : Object.values(datasources).find(ds => ds.id === slice.datasource_id); - - const { column, datasetId } = nativeFilter.targets?.[0] ?? {}; - const datasourceColumnNames = chartDatasource?.column_names ?? []; - - // same datasource, always apply - if (chartDatasource?.id === datasetId) return true; - - // let backend deal with adhoc columns and jinja - const hasSqlExpression = checkForExpression(slice.form_data); - if (hasSqlExpression) { - return true; - } - - return datasourceColumnNames.some( - col => col === column?.name || col === column?.displayName, - ); + return false; }) .map(slice => slice.slice_id); } @@ -78,52 +53,23 @@ function getRelatedChartsForCrossFilter( crossFilter: AppliedCrossFilterType, slices: Record, scope: number[], - datasources: DatasourcesState, ): number[] { const sourceSlice = slices[filterKey]; - const filters = crossFilter?.values?.filters ?? []; if (!sourceSlice) return []; - const sourceDatasource = sourceSlice.datasource - ? datasources[sourceSlice.datasource] - : Object.values(datasources).find( - ds => ds.id === sourceSlice.datasource_id, - ); - return Object.values(slices) .filter(slice => { // cross-filter emitter if (slice.slice_id === Number(filterKey)) return false; - // not in scope, ignore - if (!scope.includes(slice.slice_id)) return false; - - const targetDatasource = slice.datasource - ? datasources[slice.datasource] - : Object.values(datasources).find(ds => ds.id === slice.datasource_id); - - // same datasource, always apply - if (targetDatasource === sourceDatasource) return true; - - const targetColumnNames = targetDatasource?.column_names ?? []; - - // let backend deal with adhoc columns and jinja - const hasSqlExpression = checkForExpression(slice.form_data); - if (hasSqlExpression) { - return true; - } - - for (const filter of filters) { - // let backend deal with adhoc columns - if ( - typeof filter.col !== 'string' && - filter.col.expressionType !== undefined - ) { - return true; - } - // shared column names, different datasources, apply filter - if (targetColumnNames.includes(filter.col)) return true; - } + // hand-picked in the scope, always apply + const fullScope = [ + ...scope.filter(s => String(s) !== filterKey), + Number(filterKey), + ]; + if (isGlobalScope(fullScope, slices)) return true; + // hand-picked in the scope, always apply + if (scope.includes(slice.slice_id)) return true; return false; }) @@ -140,7 +86,6 @@ export function getRelatedCharts( AppliedNativeFilterType | AppliedCrossFilterType | Filter > | null, slices: Record, - datasources: DatasourcesState, ) { const related = Object.entries(filters).reduce((acc, [filterKey, filter]) => { const isCrossFilter = @@ -168,7 +113,6 @@ export function getRelatedCharts( actualCrossFilter, slices, chartsInScope, - datasources, ), }; } @@ -186,7 +130,6 @@ export function getRelatedCharts( nativeFilter, slices, chartsInScope, - datasources, ), }; } diff --git a/superset-frontend/src/dashboard/util/useFilterFocusHighlightStyles.ts b/superset-frontend/src/dashboard/util/useFilterFocusHighlightStyles.ts index 74d31f60d6567..b28d0a3771eec 100644 --- a/superset-frontend/src/dashboard/util/useFilterFocusHighlightStyles.ts +++ b/superset-frontend/src/dashboard/util/useFilterFocusHighlightStyles.ts @@ -51,8 +51,6 @@ const useFilterFocusHighlightStyles = (chartId: number) => { dashboardFilters, ); - const datasources = - useSelector((state: RootState) => state.datasources) || {}; const slices = useSelector((state: RootState) => state.sliceEntities.slices) || {}; @@ -60,7 +58,6 @@ const useFilterFocusHighlightStyles = (chartId: number) => { nativeFilters.filters as Record, null, slices, - datasources, ); const highlightedFilterId = From e79778ac6df9000080ec7ee5b24d59bc46e44423 Mon Sep 17 00:00:00 2001 From: Vitor Avila <96086495+Vitor-Avila@users.noreply.github.com> Date: Wed, 30 Oct 2024 12:42:27 -0300 Subject: [PATCH 017/307] feat(dataset API): Add parameter to optionally render Jinja macros in API response (#30721) --- superset/datasets/api.py | 150 +++++++++++++++++- superset/datasets/schemas.py | 1 - tests/integration_tests/datasets/api_tests.py | 139 ++++++++++++++++ 3 files changed, 288 insertions(+), 2 deletions(-) diff --git a/superset/datasets/api.py b/superset/datasets/api.py index f8f6bdc0b9604..762727aafcdff 100644 --- a/superset/datasets/api.py +++ b/superset/datasets/api.py @@ -15,16 +15,24 @@ # specific language governing permissions and limitations # under the License. # pylint: disable=too-many-lines +from __future__ import annotations + import logging from datetime import datetime from io import BytesIO -from typing import Any +from typing import Any, Callable from zipfile import is_zipfile, ZipFile from flask import request, Response, send_file from flask_appbuilder.api import expose, protect, rison, safe +from flask_appbuilder.api.schemas import get_item_schema +from flask_appbuilder.const import ( + API_RESULT_RES_KEY, + API_SELECT_COLUMNS_RIS_KEY, +) from flask_appbuilder.models.sqla.interface import SQLAInterface from flask_babel import ngettext +from jinja2.exceptions import TemplateSyntaxError from marshmallow import ValidationError from superset import event_logger @@ -65,6 +73,8 @@ GetOrCreateDatasetSchema, openapi_spec_methods_override, ) +from superset.exceptions import SupersetTemplateException +from superset.jinja_context import BaseTemplateProcessor, get_template_processor from superset.utils import json from superset.utils.core import parse_boolean_string from superset.views.base import DatasourceFilter @@ -75,6 +85,7 @@ requires_json, statsd_metrics, ) +from superset.views.error_handling import handle_api_exception from superset.views.filters import BaseFilterRelatedUsers, FilterRelatedOwners logger = logging.getLogger(__name__) @@ -1056,3 +1067,140 @@ def warm_up_cache(self) -> Response: return self.response(200, result=result) except CommandException as ex: return self.response(ex.status, message=ex.message) + + @expose("/", methods=("GET",)) + @protect() + @safe + @rison(get_item_schema) + @statsd_metrics + @handle_api_exception + @event_logger.log_this_with_context( + action=lambda self, *args, **kwargs: f"{self.__class__.__name__}" f".get", + log_to_statsd=False, + ) + def get(self, pk: int, **kwargs: Any) -> Response: + """Get a dataset. + --- + get: + summary: Get a dataset + description: Get a dataset by ID + parameters: + - in: path + schema: + type: integer + description: The dataset ID + name: pk + - in: query + name: q + content: + application/json: + schema: + $ref: '#/components/schemas/get_item_schema' + - in: query + name: include_rendered_sql + description: >- + Should Jinja macros from sql, metrics and columns be rendered + and included in the response + schema: + type: boolean + responses: + 200: + description: Dataset object has been returned. + content: + application/json: + schema: + type: object + properties: + id: + description: The item id + type: string + result: + $ref: '#/components/schemas/{{self.__class__.__name__}}.get' + 400: + $ref: '#/components/responses/400' + 401: + $ref: '#/components/responses/401' + 422: + $ref: '#/components/responses/422' + 500: + $ref: '#/components/responses/500' + """ + item: SqlaTable | None = self.datamodel.get( + pk, + self._base_filters, + self.show_select_columns, + self.show_outer_default_load, + ) + if not item: + return self.response_404() + + response: dict[str, Any] = {} + args = kwargs.get("rison", {}) + select_cols = args.get(API_SELECT_COLUMNS_RIS_KEY, []) + pruned_select_cols = [col for col in select_cols if col in self.show_columns] + self.set_response_key_mappings( + response, + self.get, + args, + **{API_SELECT_COLUMNS_RIS_KEY: pruned_select_cols}, + ) + if pruned_select_cols: + show_model_schema = self.model2schemaconverter.convert(pruned_select_cols) + else: + show_model_schema = self.show_model_schema + + response["id"] = pk + response[API_RESULT_RES_KEY] = show_model_schema.dump(item, many=False) + + if parse_boolean_string(request.args.get("include_rendered_sql")): + try: + processor = get_template_processor(database=item.database) + response["result"] = self.render_dataset_fields( + response["result"], processor + ) + except SupersetTemplateException as ex: + return self.response_400(message=str(ex)) + return self.response(200, **response) + + @staticmethod + def render_dataset_fields( + data: dict[str, Any], processor: BaseTemplateProcessor + ) -> dict[str, Any]: + """ + Renders Jinja macros in the ``sql``, ``metrics`` and ``columns`` fields. + + :param data: Dataset info to be rendered + :param processor: A ``TemplateProcessor`` instance + :return: Rendered dataset data + """ + + def render_item_list(item_list: list[dict[str, Any]]) -> list[dict[str, Any]]: + return [ + { + **item, + "rendered_expression": processor.process_template( + item["expression"] + ), + } + if item.get("expression") + else item + for item in item_list + ] + + items: list[tuple[str, str, str, Callable[[Any], Any]]] = [ + ("query", "sql", "rendered_sql", processor.process_template), + ("metric", "metrics", "metrics", render_item_list), + ("calculated column", "columns", "columns", render_item_list), + ] + for item_type, key, new_key, func in items: + if not data.get(key): + continue + + try: + data[new_key] = func(data[key]) + except TemplateSyntaxError as ex: + raise SupersetTemplateException( + f"Unable to render expression from dataset {item_type}.", + ) from ex + + return data diff --git a/superset/datasets/schemas.py b/superset/datasets/schemas.py index 5b899d8402f23..4b7e92d7ff5bb 100644 --- a/superset/datasets/schemas.py +++ b/superset/datasets/schemas.py @@ -29,7 +29,6 @@ get_export_ids_schema = {"type": "array", "items": {"type": "integer"}} openapi_spec_methods_override = { - "get": {"get": {"summary": "Get a dataset detail information"}}, "get_list": { "get": { "summary": "Get a list of datasets", diff --git a/tests/integration_tests/datasets/api_tests.py b/tests/integration_tests/datasets/api_tests.py index 49110277bf328..b04d4cec73692 100644 --- a/tests/integration_tests/datasets/api_tests.py +++ b/tests/integration_tests/datasets/api_tests.py @@ -410,6 +410,145 @@ def test_get_dataset_item(self): assert len(response["result"]["columns"]) == 3 assert len(response["result"]["metrics"]) == 2 + def test_get_dataset_render_jinja(self): + """ + Dataset API: Test get dataset with the render parameter. + """ + database = get_example_database() + dataset = SqlaTable( + table_name="test_sql_table_with_jinja", + database=database, + schema=get_example_default_schema(), + main_dttm_col="default_dttm", + columns=[ + TableColumn( + column_name="my_user_id", + type="INTEGER", + is_dttm=False, + ), + TableColumn( + column_name="calculated_test", + type="VARCHAR(255)", + is_dttm=False, + expression="'{{ current_username() }}'", + ), + ], + metrics=[ + SqlMetric( + metric_name="param_test", + expression="{{ url_param('multiplier') }} * 1.4", + ) + ], + sql="SELECT {{ current_user_id() }} as my_user_id", + ) + db.session.add(dataset) + db.session.commit() + + self.login(ADMIN_USERNAME) + admin = self.get_user(ADMIN_USERNAME) + uri = ( + f"api/v1/dataset/{dataset.id}?" + "q=(columns:!(id,sql,columns.column_name,columns.expression,metrics.metric_name,metrics.expression))" + "&include_rendered_sql=true&multiplier=4" + ) + rv = self.get_assert_metric(uri, "get") + assert rv.status_code == 200 + response = json.loads(rv.data.decode("utf-8")) + + assert response["result"] == { + "id": dataset.id, + "sql": "SELECT {{ current_user_id() }} as my_user_id", + "rendered_sql": f"SELECT {admin.id} as my_user_id", + "columns": [ + { + "column_name": "my_user_id", + "expression": None, + }, + { + "column_name": "calculated_test", + "expression": "'{{ current_username() }}'", + "rendered_expression": f"'{admin.username}'", + }, + ], + "metrics": [ + { + "metric_name": "param_test", + "expression": "{{ url_param('multiplier') }} * 1.4", + "rendered_expression": "4 * 1.4", + }, + ], + } + + db.session.delete(dataset) + db.session.commit() + + def test_get_dataset_render_jinja_exceptions(self): + """ + Dataset API: Test get dataset with the render parameter + when rendering raises an exception. + """ + database = get_example_database() + dataset = SqlaTable( + table_name="test_sql_table_with_incorrect_jinja", + database=database, + schema=get_example_default_schema(), + main_dttm_col="default_dttm", + columns=[ + TableColumn( + column_name="my_user_id", + type="INTEGER", + is_dttm=False, + ), + TableColumn( + column_name="calculated_test", + type="VARCHAR(255)", + is_dttm=False, + expression="'{{ current_username() }'", + ), + ], + metrics=[ + SqlMetric( + metric_name="param_test", + expression="{{ url_param('multiplier') } * 1.4", + ) + ], + sql="SELECT {{ current_user_id() } as my_user_id", + ) + db.session.add(dataset) + db.session.commit() + + self.login(ADMIN_USERNAME) + + uri = f"api/v1/dataset/{dataset.id}?q=(columns:!(id,sql))&include_rendered_sql=true" + rv = self.get_assert_metric(uri, "get") + assert rv.status_code == 400 + response = json.loads(rv.data.decode("utf-8")) + assert response["message"] == "Unable to render expression from dataset query." + + uri = ( + f"api/v1/dataset/{dataset.id}?q=(columns:!(id,metrics.expression))" + "&include_rendered_sql=true&multiplier=4" + ) + rv = self.get_assert_metric(uri, "get") + assert rv.status_code == 400 + response = json.loads(rv.data.decode("utf-8")) + assert response["message"] == "Unable to render expression from dataset metric." + + uri = ( + f"api/v1/dataset/{dataset.id}?q=(columns:!(id,columns.expression))" + "&include_rendered_sql=true" + ) + rv = self.get_assert_metric(uri, "get") + assert rv.status_code == 400 + response = json.loads(rv.data.decode("utf-8")) + assert ( + response["message"] + == "Unable to render expression from dataset calculated column." + ) + + db.session.delete(dataset) + db.session.commit() + def test_get_dataset_distinct_schema(self): """ Dataset API: Test get dataset distinct schema From 4511e1c28daa805bffd5484aaefeaa96fde99c4d Mon Sep 17 00:00:00 2001 From: SaiSkandaTNI <156087948+SaiSkandaTNI@users.noreply.github.com> Date: Wed, 30 Oct 2024 22:45:43 +0530 Subject: [PATCH 018/307] docs: add Sarathi to users list (#30753) --- RESOURCES/INTHEWILD.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/RESOURCES/INTHEWILD.md b/RESOURCES/INTHEWILD.md index a28d432448157..d83628e18d6d2 100644 --- a/RESOURCES/INTHEWILD.md +++ b/RESOURCES/INTHEWILD.md @@ -165,9 +165,10 @@ Join our growing community! - [Symmetrics](https://www.symmetrics.fyi) - [bluquist](https://bluquist.com/) -### Government +### Government / Non-Profit - [City of Ann Arbor, MI](https://www.a2gov.org/) [@sfirke] - [RIS3 Strategy of CZ, MIT CR](https://www.ris3.cz/) [@RIS3CZ] +- [NRLM - Sarathi, India](https://pib.gov.in/PressReleasePage.aspx?PRID=1999586) ### Travel - [Agoda](https://www.agoda.com/) [@lostseaway, @maiake, @obombayo] From dc9dd5fabfd8cba107d065f886d6f5b25a102c51 Mon Sep 17 00:00:00 2001 From: Mark Stephan <146860933+MSTartan@users.noreply.github.com> Date: Wed, 30 Oct 2024 13:16:57 -0400 Subject: [PATCH 019/307] docs: Update INTHEWILD.md (#30747) --- RESOURCES/INTHEWILD.md | 1 + 1 file changed, 1 insertion(+) diff --git a/RESOURCES/INTHEWILD.md b/RESOURCES/INTHEWILD.md index d83628e18d6d2..6400adc11cfd4 100644 --- a/RESOURCES/INTHEWILD.md +++ b/RESOURCES/INTHEWILD.md @@ -103,6 +103,7 @@ Join our growing community! - [Oslandia](https://oslandia.com) - [Peak AI](https://www.peak.ai/) [@azhar22k] - [PeopleDoc](https://www.people-doc.com) [@rodo] +- [PlaidCloud](https://www.plaidcloud.com) - [Preset, Inc.](https://preset.io) - [PubNub](https://pubnub.com) [@jzucker2] - [ReadyTech](https://www.readytech.io) From 9bb69ab3113b635c06c02ee1e92158dc8c105279 Mon Sep 17 00:00:00 2001 From: Evan Rusackas Date: Wed, 30 Oct 2024 11:25:09 -0600 Subject: [PATCH 020/307] docs: Adding link to StarRocks official docs (#30757) --- docs/docs/configuration/databases.mdx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/docs/configuration/databases.mdx b/docs/docs/configuration/databases.mdx index 8f69cc8d6f670..49c9417df862c 100644 --- a/docs/docs/configuration/databases.mdx +++ b/docs/docs/configuration/databases.mdx @@ -1318,6 +1318,10 @@ Here's what the connection string looks like: starrocks://:@:/. ``` +:::note +StarRocks maintains their Superset docuementation [here](https://docs.starrocks.io/docs/integrations/BI_integrations/Superset/). +::: + #### Teradata The recommended connector library is From bc5da631c879f8bd2d2f6f4dfee9eda38aee6415 Mon Sep 17 00:00:00 2001 From: alexandrusoare <37236580+alexandrusoare@users.noreply.github.com> Date: Wed, 30 Oct 2024 20:18:49 +0200 Subject: [PATCH 021/307] refactor(Switch): Upgrade Switch to Ant Design 5 (#30731) --- .../src/SqlLab/components/SqlEditor/index.tsx | 7 ++-- .../src/components/Switch/Switch.stories.tsx | 5 ++- .../src/components/Switch/Switch.test.tsx | 41 +++++++++++++++++++ .../src/components/Switch/index.tsx | 12 ++---- superset-frontend/src/components/index.ts | 1 - .../CommonParameters.tsx | 4 +- .../DatabaseModal/SSHTunnelSwitch.test.tsx | 4 +- .../DatabaseModal/SSHTunnelSwitch.tsx | 4 +- superset-frontend/src/pages/Home/index.tsx | 4 +- superset-frontend/src/theme/index.ts | 4 ++ 10 files changed, 64 insertions(+), 22 deletions(-) create mode 100644 superset-frontend/src/components/Switch/Switch.test.tsx diff --git a/superset-frontend/src/SqlLab/components/SqlEditor/index.tsx b/superset-frontend/src/SqlLab/components/SqlEditor/index.tsx index 731053ac0b0b0..cab82cd02f5c2 100644 --- a/superset-frontend/src/SqlLab/components/SqlEditor/index.tsx +++ b/superset-frontend/src/SqlLab/components/SqlEditor/index.tsx @@ -56,7 +56,8 @@ import Mousetrap from 'mousetrap'; import Button from 'src/components/Button'; import Timer from 'src/components/Timer'; import ResizableSidebar from 'src/components/ResizableSidebar'; -import { AntdDropdown, AntdSwitch, Skeleton } from 'src/components'; +import { AntdDropdown, Skeleton } from 'src/components'; +import { Switch } from 'src/components/Switch'; import { Input } from 'src/components/Input'; import { Menu } from 'src/components/Menu'; import Icons from 'src/components/Icons'; @@ -698,7 +699,7 @@ const SqlEditor: FC = ({ {' '} {t('Render HTML')}{' '} - {' '} @@ -706,7 +707,7 @@ const SqlEditor: FC = ({ {' '} {t('Autocomplete')}{' '} - {' '} diff --git a/superset-frontend/src/components/Switch/Switch.stories.tsx b/superset-frontend/src/components/Switch/Switch.stories.tsx index 9e6a4061a478f..3e5d12d3ea34b 100644 --- a/superset-frontend/src/components/Switch/Switch.stories.tsx +++ b/superset-frontend/src/components/Switch/Switch.stories.tsx @@ -33,12 +33,15 @@ export const InteractiveSwitch = ({ checked, ...rest }: SwitchProps) => { /> ); }; +const defaultCheckedValue = true; InteractiveSwitch.args = { - checked: false, + checked: defaultCheckedValue, disabled: false, loading: false, title: 'Switch', + defaultChecked: defaultCheckedValue, + autoFocus: true, }; InteractiveSwitch.argTypes = { diff --git a/superset-frontend/src/components/Switch/Switch.test.tsx b/superset-frontend/src/components/Switch/Switch.test.tsx new file mode 100644 index 0000000000000..0e8e762d041ea --- /dev/null +++ b/superset-frontend/src/components/Switch/Switch.test.tsx @@ -0,0 +1,41 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { render, screen } from 'spec/helpers/testing-library'; +import { Switch } from '.'; + +const mockedProps = { + label: 'testLabel', + dataTest: 'dataTest', + checked: false, +}; + +test('should render', () => { + const { container } = render(); + expect(container).toBeInTheDocument(); +}); + +test('should have the correct checked prop', () => { + render(); + + const switchElement = screen.getByRole('switch'); + + expect(switchElement).toBeInTheDocument(); + expect(switchElement).not.toBeChecked(); +}); diff --git a/superset-frontend/src/components/Switch/index.tsx b/superset-frontend/src/components/Switch/index.tsx index 875b66f5871aa..b4d89e8505790 100644 --- a/superset-frontend/src/components/Switch/index.tsx +++ b/superset-frontend/src/components/Switch/index.tsx @@ -16,14 +16,8 @@ * specific language governing permissions and limitations * under the License. */ -import { styled } from '@superset-ui/core'; -import BaseSwitch, { SwitchProps } from 'antd/lib/switch'; +import { SwitchProps } from 'antd-v5/lib/switch'; +import { Switch as AntdSwitch } from 'antd-v5'; -const StyledSwitch = styled(BaseSwitch)` - .ant-switch-checked { - background-color: ${({ theme }) => theme.colors.primary.base}; - } -`; - -export const Switch = (props: SwitchProps) => ; +export const Switch = (props: SwitchProps) => ; export type { SwitchProps }; diff --git a/superset-frontend/src/components/index.ts b/superset-frontend/src/components/index.ts index 16b6138c18775..8b771da995ea0 100644 --- a/superset-frontend/src/components/index.ts +++ b/superset-frontend/src/components/index.ts @@ -67,7 +67,6 @@ export { Modal as AntdModal, Select as AntdSelect, Slider as AntdSlider, - Switch as AntdSwitch, Tabs as AntdTabs, Tooltip as AntdTooltip, } from 'antd'; diff --git a/superset-frontend/src/features/databases/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx b/superset-frontend/src/features/databases/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx index d2170de6f8f91..33a258d72445b 100644 --- a/superset-frontend/src/features/databases/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx +++ b/superset-frontend/src/features/databases/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx @@ -17,7 +17,7 @@ * under the License. */ import { SupersetTheme, t } from '@superset-ui/core'; -import { AntdSwitch } from 'src/components'; +import { Switch } from 'src/components/Switch'; import InfoTooltip from 'src/components/InfoTooltip'; import ValidatedInput from 'src/components/Form/LabeledErrorBoundInput'; import { FieldPropTypes } from '../../types'; @@ -296,7 +296,7 @@ export const forceSSLField = ({ sslForced, }: FieldPropTypes) => (
infoTooltip(theme)}> - { diff --git a/superset-frontend/src/features/databases/DatabaseModal/SSHTunnelSwitch.test.tsx b/superset-frontend/src/features/databases/DatabaseModal/SSHTunnelSwitch.test.tsx index 3001867036bc5..35fc05555b4bd 100644 --- a/superset-frontend/src/features/databases/DatabaseModal/SSHTunnelSwitch.test.tsx +++ b/superset-frontend/src/features/databases/DatabaseModal/SSHTunnelSwitch.test.tsx @@ -26,8 +26,8 @@ jest.mock('@superset-ui/core', () => ({ isFeatureEnabled: jest.fn().mockReturnValue(true), })); -jest.mock('src/components', () => ({ - AntdSwitch: ({ +jest.mock('src/components/Switch', () => ({ + Switch: ({ checked, onChange, }: { diff --git a/superset-frontend/src/features/databases/DatabaseModal/SSHTunnelSwitch.tsx b/superset-frontend/src/features/databases/DatabaseModal/SSHTunnelSwitch.tsx index fa0e8fe433a5d..623091f397ce5 100644 --- a/superset-frontend/src/features/databases/DatabaseModal/SSHTunnelSwitch.tsx +++ b/superset-frontend/src/features/databases/DatabaseModal/SSHTunnelSwitch.tsx @@ -23,7 +23,7 @@ import { isFeatureEnabled, FeatureFlag, } from '@superset-ui/core'; -import { AntdSwitch } from 'src/components'; +import { Switch } from 'src/components/Switch'; import InfoTooltip from 'src/components/InfoTooltip'; import { isEmpty } from 'lodash'; import { infoTooltip, toggleStyle } from './styles'; @@ -80,7 +80,7 @@ const SSHTunnelSwitch = ({ return isSSHTunnelEnabled ? (
infoTooltip(theme)}> -
- + {t('Thumbnails')}
diff --git a/superset-frontend/src/theme/index.ts b/superset-frontend/src/theme/index.ts index 857e95888f935..1ed1cc21a6d08 100644 --- a/superset-frontend/src/theme/index.ts +++ b/superset-frontend/src/theme/index.ts @@ -75,6 +75,10 @@ const baseConfig: ThemeConfig = { handleSizeHover: 10, handleLineWidthHover: 2, }, + Switch: { + colorPrimaryHover: supersetTheme.colors.primary.base, + colorTextTertiary: supersetTheme.colors.grayscale.light1, + }, }, }; From 849d426e06ebbf926bdecc9fca993ffeaadbe9fd Mon Sep 17 00:00:00 2001 From: Jack <41238731+fisjac@users.noreply.github.com> Date: Wed, 30 Oct 2024 14:56:22 -0500 Subject: [PATCH 022/307] feat(oauth): adding necessary changes to support bigquery oauth (#30674) --- .../CommonParameters.tsx | 22 ++++++++++++ .../DatabaseConnectionForm/EncryptedField.tsx | 7 ++-- .../OAuth2ClientField.tsx | 22 +++++++----- .../DatabaseConnectionForm/constants.ts | 3 ++ .../src/features/databases/types.ts | 2 ++ superset/commands/database/test_connection.py | 6 +++- superset/databases/api.py | 3 +- superset/databases/schemas.py | 19 +++-------- superset/databases/types.py | 34 +++++++++++++++++++ superset/db_engine_specs/base.py | 10 ++++-- superset/db_engine_specs/bigquery.py | 12 ++++--- superset/db_engine_specs/hive.py | 4 ++- superset/db_engine_specs/postgres.py | 11 +++++- superset/db_engine_specs/presto.py | 10 ++++-- superset/db_engine_specs/trino.py | 4 ++- superset/models/core.py | 31 ++++++++++++++--- .../db_engine_specs/postgres_tests.py | 6 ++-- .../db_engine_specs/presto_tests.py | 8 +++-- tests/unit_tests/models/core_test.py | 25 ++++++++++++++ 19 files changed, 191 insertions(+), 48 deletions(-) create mode 100644 superset/databases/types.py diff --git a/superset-frontend/src/features/databases/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx b/superset-frontend/src/features/databases/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx index 33a258d72445b..696f52baa0ae3 100644 --- a/superset-frontend/src/features/databases/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx +++ b/superset-frontend/src/features/databases/DatabaseModal/DatabaseConnectionForm/CommonParameters.tsx @@ -318,3 +318,25 @@ export const forceSSLField = ({ />
); + +export const projectIdfield = ({ + changeMethods, + getValidation, + validationErrors, + db, +}: FieldPropTypes) => ( + <> + + +); diff --git a/superset-frontend/src/features/databases/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx b/superset-frontend/src/features/databases/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx index 2b9223141a8b4..fd11cd3271025 100644 --- a/superset-frontend/src/features/databases/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx +++ b/superset-frontend/src/features/databases/DatabaseModal/DatabaseConnectionForm/EncryptedField.tsx @@ -57,10 +57,11 @@ export const EncryptedField = ({ db?.engine === 'gsheets' ? !isEditMode && !isPublic : !isEditMode; const isEncrypted = isEditMode && db?.masked_encrypted_extra !== '{}'; const encryptedField = db?.engine && encryptedCredentialsMap[db.engine]; + const paramValue = db?.parameters?.[encryptedField]; const encryptedValue = - typeof db?.parameters?.[encryptedField] === 'object' - ? JSON.stringify(db?.parameters?.[encryptedField]) - : db?.parameters?.[encryptedField]; + paramValue && typeof paramValue === 'object' + ? JSON.stringify(paramValue) + : paramValue; return ( {db?.engine === 'gsheets' && ( diff --git a/superset-frontend/src/features/databases/DatabaseModal/DatabaseConnectionForm/OAuth2ClientField.tsx b/superset-frontend/src/features/databases/DatabaseModal/DatabaseConnectionForm/OAuth2ClientField.tsx index ee0ffdeb33f51..fac3c33318db8 100644 --- a/superset-frontend/src/features/databases/DatabaseModal/DatabaseConnectionForm/OAuth2ClientField.tsx +++ b/superset-frontend/src/features/databases/DatabaseModal/DatabaseConnectionForm/OAuth2ClientField.tsx @@ -24,6 +24,14 @@ import { Input } from 'src/components/Input'; import { FormItem } from 'src/components/Form'; import { FieldPropTypes } from '../../types'; +const LABELS = { + CLIENT_ID: 'Client ID', + SECRET: 'Client Secret', + AUTH_URI: 'Authorization Request URI', + TOKEN_URI: 'Token Request URI', + SCOPE: 'Scope', +}; + interface OAuth2ClientInfo { id: string; secret: string; @@ -44,10 +52,6 @@ export const OAuth2ClientField = ({ changeMethods, db }: FieldPropTypes) => { scope: encryptedExtra.oauth2_client_info?.scope || '', }); - if (db?.engine_information?.supports_oauth2 !== true) { - return null; - } - const handleChange = (key: any) => (e: any) => { const updatedInfo = { ...oauth2ClientInfo, @@ -68,14 +72,14 @@ export const OAuth2ClientField = ({ changeMethods, db }: FieldPropTypes) => { return ( - + - + { onChange={handleChange('secret')} /> - + { onChange={handleChange('authorization_request_uri')} /> - + { onChange={handleChange('token_request_uri')} /> - + None: # pylint: disable=too-many-statements + def run(self) -> None: # pylint: disable=too-many-statements,too-many-branches self.validate() ex_str = "" ssh_tunnel = self._properties.get("ssh_tunnel") @@ -225,6 +225,10 @@ def ping(engine: Engine) -> bool: # bubble up the exception to return proper status code raise except Exception as ex: + if database.is_oauth2_enabled() and database.db_engine_spec.needs_oauth2( + ex + ): + database.start_oauth2_dance() event_logger.log_with_context( action=get_log_connection_action( "test_connection_error", ssh_tunnel, ex diff --git a/superset/databases/api.py b/superset/databases/api.py index 88188bed57b90..542daa93ae668 100644 --- a/superset/databases/api.py +++ b/superset/databases/api.py @@ -121,6 +121,7 @@ from superset.superset_typing import FlaskResponse from superset.utils import json from superset.utils.core import error_msg_from_exception, parse_js_uri_path_item +from superset.utils.decorators import transaction from superset.utils.oauth2 import decode_oauth2_state from superset.utils.ssh_tunnel import mask_password_info from superset.views.base_api import ( @@ -1341,6 +1342,7 @@ def validate_sql(self, pk: int) -> FlaskResponse: return self.response_404() @expose("/oauth2/", methods=["GET"]) + @transaction() @event_logger.log_this_with_context( action=lambda self, *args, **kwargs: f"{self.__class__.__name__}.oauth2", log_to_statsd=True, @@ -1428,7 +1430,6 @@ def oauth2(self) -> FlaskResponse: "refresh_token": token_response.get("refresh_token"), }, ) - # return blank page that closes itself return make_response( render_template("superset/oauth2.html", tab_id=state["tab_id"]), diff --git a/superset/databases/schemas.py b/superset/databases/schemas.py index 27eb043eb131b..ed4e67d3041ea 100644 --- a/superset/databases/schemas.py +++ b/superset/databases/schemas.py @@ -47,6 +47,11 @@ SSHTunnelMissingCredentials, ) from superset.constants import PASSWORD_MASK +from superset.databases.types import ( # pylint:disable=unused-import + EncryptedDict, # noqa: F401 + EncryptedField, + EncryptedString, # noqa: F401 +) from superset.databases.utils import make_url_safe from superset.db_engine_specs import get_engine_spec from superset.exceptions import CertificateException, SupersetSecurityException @@ -941,20 +946,6 @@ def validate_ssh_tunnel_credentials( return -class EncryptedField: # pylint: disable=too-few-public-methods - """ - A database field that should be stored in encrypted_extra. - """ - - -class EncryptedString(EncryptedField, fields.String): - pass - - -class EncryptedDict(EncryptedField, fields.Dict): - pass - - def encrypted_field_properties(self, field: Any, **_) -> dict[str, Any]: # type: ignore ret = {} if isinstance(field, EncryptedField): diff --git a/superset/databases/types.py b/superset/databases/types.py new file mode 100644 index 0000000000000..4ab4428604d93 --- /dev/null +++ b/superset/databases/types.py @@ -0,0 +1,34 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +# Field has been moved outside of the schemas.py file to +# allow for it to be imported from outside of app_context +from marshmallow import fields + + +class EncryptedField: # pylint: disable=too-few-public-methods + """ + A database field that should be stored in encrypted_extra. + """ + + +class EncryptedString(EncryptedField, fields.String): + pass + + +class EncryptedDict(EncryptedField, fields.Dict): + pass diff --git a/superset/db_engine_specs/base.py b/superset/db_engine_specs/base.py index 2e555e32f1cc9..a086f6eff7159 100644 --- a/superset/db_engine_specs/base.py +++ b/superset/db_engine_specs/base.py @@ -1707,10 +1707,13 @@ def select_star( # pylint: disable=too-many-arguments return sql @classmethod - def estimate_statement_cost(cls, statement: str, cursor: Any) -> dict[str, Any]: + def estimate_statement_cost( + cls, database: Database, statement: str, cursor: Any + ) -> dict[str, Any]: """ Generate a SQL query that estimates the cost of a given statement. + :param database: A Database object :param statement: A single SQL statement :param cursor: Cursor instance :return: Dictionary with different costs @@ -1781,6 +1784,7 @@ def estimate_query_cost( # pylint: disable=too-many-arguments cursor = conn.cursor() return [ cls.estimate_statement_cost( + database, cls.process_statement(statement, database), cursor, ) @@ -1809,8 +1813,9 @@ def get_url_for_impersonation( return url @classmethod - def update_impersonation_config( + def update_impersonation_config( # pylint: disable=too-many-arguments cls, + database: Database, connect_args: dict[str, Any], uri: str, username: str | None, @@ -1820,6 +1825,7 @@ def update_impersonation_config( Update a configuration dictionary that can set the correct properties for impersonating users + :param connect_args: a Database object :param connect_args: config to be updated :param uri: URI :param username: Effective username diff --git a/superset/db_engine_specs/bigquery.py b/superset/db_engine_specs/bigquery.py index 11175d7957445..70bc4bc845390 100644 --- a/superset/db_engine_specs/bigquery.py +++ b/superset/db_engine_specs/bigquery.py @@ -409,7 +409,11 @@ def df_to_sql( pandas_gbq.to_gbq(df, **to_gbq_kwargs) @classmethod - def _get_client(cls, engine: Engine) -> bigquery.Client: + def _get_client( + cls, + engine: Engine, + database: Database, # pylint: disable=unused-argument + ) -> bigquery.Client: """ Return the BigQuery client associated with an engine. """ @@ -453,7 +457,7 @@ def estimate_query_cost( # pylint: disable=too-many-arguments catalog=catalog, schema=schema, ) as engine: - client = cls._get_client(engine) + client = cls._get_client(engine, database) return [ cls.custom_estimate_statement_cost( cls.process_statement(statement, database), @@ -477,7 +481,7 @@ def get_default_catalog(cls, database: Database) -> str | None: return project with database.get_sqla_engine() as engine: - client = cls._get_client(engine) + client = cls._get_client(engine, database) return client.project @classmethod @@ -493,7 +497,7 @@ def get_catalog_names( """ engine: Engine with database.get_sqla_engine() as engine: - client = cls._get_client(engine) + client = cls._get_client(engine, database) projects = client.list_projects() return {project.project_id for project in projects} diff --git a/superset/db_engine_specs/hive.py b/superset/db_engine_specs/hive.py index e3cf128b7a2c6..6288866db93ee 100644 --- a/superset/db_engine_specs/hive.py +++ b/superset/db_engine_specs/hive.py @@ -537,8 +537,9 @@ def get_url_for_impersonation( return url @classmethod - def update_impersonation_config( + def update_impersonation_config( # pylint: disable=too-many-arguments cls, + database: Database, connect_args: dict[str, Any], uri: str, username: str | None, @@ -547,6 +548,7 @@ def update_impersonation_config( """ Update a configuration dictionary that can set the correct properties for impersonating users + :param database: the Database Object :param connect_args: :param uri: URI string :param impersonate_user: Flag indicating if impersonation is enabled diff --git a/superset/db_engine_specs/postgres.py b/superset/db_engine_specs/postgres.py index 70373927d521b..6281c6b3b0ff3 100644 --- a/superset/db_engine_specs/postgres.py +++ b/superset/db_engine_specs/postgres.py @@ -351,7 +351,16 @@ def get_allow_cost_estimate(cls, extra: dict[str, Any]) -> bool: return True @classmethod - def estimate_statement_cost(cls, statement: str, cursor: Any) -> dict[str, Any]: + def estimate_statement_cost( + cls, database: Database, statement: str, cursor: Any + ) -> dict[str, Any]: + """ + Run a SQL query that estimates the cost of a given statement. + :param database: A Database object + :param statement: A single SQL statement + :param cursor: Cursor instance + :return: JSON response from Trino + """ sql = f"EXPLAIN {statement}" cursor.execute(sql) diff --git a/superset/db_engine_specs/presto.py b/superset/db_engine_specs/presto.py index f0664564f872c..df5e1c643fa1f 100644 --- a/superset/db_engine_specs/presto.py +++ b/superset/db_engine_specs/presto.py @@ -365,9 +365,12 @@ def get_schema_from_engine_params( return parse.unquote(database.split("/")[1]) @classmethod - def estimate_statement_cost(cls, statement: str, cursor: Any) -> dict[str, Any]: + def estimate_statement_cost( + cls, database: Database, statement: str, cursor: Any + ) -> dict[str, Any]: """ Run a SQL query that estimates the cost of a given statement. + :param database: A Database object :param statement: A single SQL statement :param cursor: Cursor instance :return: JSON response from Trino @@ -945,8 +948,9 @@ def get_allow_cost_estimate(cls, extra: dict[str, Any]) -> bool: return version is not None and Version(version) >= Version("0.319") @classmethod - def update_impersonation_config( + def update_impersonation_config( # pylint: disable=too-many-arguments cls, + database: Database, connect_args: dict[str, Any], uri: str, username: str | None, @@ -955,6 +959,8 @@ def update_impersonation_config( """ Update a configuration dictionary that can set the correct properties for impersonating users + + :param connect_args: the Database object :param connect_args: config to be updated :param uri: URI string :param username: Effective username diff --git a/superset/db_engine_specs/trino.py b/superset/db_engine_specs/trino.py index 49615c39cba52..c473528217b5e 100644 --- a/superset/db_engine_specs/trino.py +++ b/superset/db_engine_specs/trino.py @@ -116,8 +116,9 @@ def get_extra_table_metadata( return metadata @classmethod - def update_impersonation_config( + def update_impersonation_config( # pylint: disable=too-many-arguments cls, + database: Database, connect_args: dict[str, Any], uri: str, username: str | None, @@ -126,6 +127,7 @@ def update_impersonation_config( """ Update a configuration dictionary that can set the correct properties for impersonating users + :param database: the Database object :param connect_args: config to be updated :param uri: URI string :param username: Effective username diff --git a/superset/models/core.py b/superset/models/core.py index 5d3a6ea74ddab..4181412727a27 100755 --- a/superset/models/core.py +++ b/superset/models/core.py @@ -29,6 +29,7 @@ from copy import deepcopy from datetime import datetime from functools import lru_cache +from inspect import signature from typing import Any, Callable, cast, TYPE_CHECKING import numpy @@ -510,12 +511,14 @@ def _get_sqla_engine( # pylint: disable=too-many-locals logger.debug("Database._get_sqla_engine(). Masked URL: %s", str(masked_url)) if self.impersonate_user: - self.db_engine_spec.update_impersonation_config( - connect_args, - str(sqlalchemy_url), - effective_username, - access_token, + # PR #30674 changed the signature of the method to include database. + # This ensures that the change is backwards compatible + args = [connect_args, str(sqlalchemy_url), effective_username, access_token] + args = self.add_database_to_signature( + self.db_engine_spec.update_impersonation_config, + args, ) + self.db_engine_spec.update_impersonation_config(*args) if connect_args: params["connect_args"] = connect_args @@ -543,6 +546,24 @@ def _get_sqla_engine( # pylint: disable=too-many-locals except Exception as ex: raise self.db_engine_spec.get_dbapi_mapped_exception(ex) from ex + def add_database_to_signature( + self, + func: Callable[..., None], + args: list[Any], + ) -> list[Any]: + """ + Examines a function signature looking for a database param. + If the signature requires a database, the function appends self in the + proper position. + """ + + # PR #30674 changed the signature of the method to include database. + # This ensures that the change is backwards compatible + sig = signature(func) + if "database" in (params := sig.parameters.keys()): + args.insert(list(params).index("database"), self) + return args + @contextmanager def get_raw_connection( self, diff --git a/tests/integration_tests/db_engine_specs/postgres_tests.py b/tests/integration_tests/db_engine_specs/postgres_tests.py index e4f9462d63069..a5ef1cdecab59 100644 --- a/tests/integration_tests/db_engine_specs/postgres_tests.py +++ b/tests/integration_tests/db_engine_specs/postgres_tests.py @@ -151,12 +151,13 @@ def test_estimate_statement_cost_select_star(self): DB Eng Specs (postgres): Test estimate_statement_cost select star """ + database = mock.Mock() cursor = mock.Mock() cursor.fetchone.return_value = ( "Seq Scan on birth_names (cost=0.00..1537.91 rows=75691 width=46)", ) sql = "SELECT * FROM birth_names" - results = PostgresEngineSpec.estimate_statement_cost(sql, cursor) + results = PostgresEngineSpec.estimate_statement_cost(database, sql, cursor) assert results == {"Start-up cost": 0.0, "Total cost": 1537.91} def test_estimate_statement_invalid_syntax(self): @@ -165,6 +166,7 @@ def test_estimate_statement_invalid_syntax(self): """ from psycopg2 import errors + database = mock.Mock() cursor = mock.Mock() cursor.execute.side_effect = errors.SyntaxError( """ @@ -175,7 +177,7 @@ def test_estimate_statement_invalid_syntax(self): ) sql = "DROP TABLE birth_names" with self.assertRaises(errors.SyntaxError): - PostgresEngineSpec.estimate_statement_cost(sql, cursor) + PostgresEngineSpec.estimate_statement_cost(database, sql, cursor) def test_query_cost_formatter_example_costs(self): """ diff --git a/tests/integration_tests/db_engine_specs/presto_tests.py b/tests/integration_tests/db_engine_specs/presto_tests.py index 798e31ee431a4..94e3ea62721a4 100644 --- a/tests/integration_tests/db_engine_specs/presto_tests.py +++ b/tests/integration_tests/db_engine_specs/presto_tests.py @@ -905,22 +905,26 @@ def test_select_star_presto_expand_data( ) def test_estimate_statement_cost(self): + mock_database = mock.MagicMock() mock_cursor = mock.MagicMock() estimate_json = {"a": "b"} mock_cursor.fetchone.return_value = [ '{"a": "b"}', ] result = PrestoEngineSpec.estimate_statement_cost( - "SELECT * FROM brth_names", mock_cursor + mock_database, + "SELECT * FROM brth_names", + mock_cursor, ) assert result == estimate_json def test_estimate_statement_cost_invalid_syntax(self): + mock_database = mock.MagicMock() mock_cursor = mock.MagicMock() mock_cursor.execute.side_effect = Exception() with self.assertRaises(Exception): PrestoEngineSpec.estimate_statement_cost( - "DROP TABLE brth_names", mock_cursor + mock_database, "DROP TABLE brth_names", mock_cursor ) def test_get_create_view(self): diff --git a/tests/unit_tests/models/core_test.py b/tests/unit_tests/models/core_test.py index 3c591d4466f74..452cbb6f56997 100644 --- a/tests/unit_tests/models/core_test.py +++ b/tests/unit_tests/models/core_test.py @@ -432,6 +432,31 @@ def test_get_sqla_engine_user_impersonation(mocker: MockerFixture) -> None: ) +def test_add_database_to_signature(): + args = ["param1", "param2"] + + def func_without_db(param1, param2): + pass + + def func_with_db_start(database, param1, param2): + pass + + def func_with_db_end(param1, param2, database): + pass + + database = Database( + database_name="my_db", + sqlalchemy_uri="trino://", + impersonate_user=True, + ) + args1 = database.add_database_to_signature(func_without_db, args.copy()) + assert args1 == ["param1", "param2"] + args2 = database.add_database_to_signature(func_with_db_start, args.copy()) + assert args2 == [database, "param1", "param2"] + args3 = database.add_database_to_signature(func_with_db_end, args.copy()) + assert args3 == ["param1", "param2", database] + + @with_feature_flags(IMPERSONATE_WITH_EMAIL_PREFIX=True) def test_get_sqla_engine_user_impersonation_email(mocker: MockerFixture) -> None: """ From a729f04695be75b5302781fbcebff6ef61a95c7e Mon Sep 17 00:00:00 2001 From: goto-loop <102797966+goto-loop@users.noreply.github.com> Date: Wed, 30 Oct 2024 21:59:06 +0100 Subject: [PATCH 023/307] fix(chart): apply number format in Box Plot tooltip only where necessary (#27142) --- .../plugin-chart-echarts/src/BoxPlot/transformProps.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 8150c3e3e14b6..5eb80b1a6fed5 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/transformProps.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/transformProps.ts @@ -229,10 +229,10 @@ export default function transformProps( `Median: ${numberFormatter(value[3])}`, `1st Quartile: ${numberFormatter(value[2])}`, `Min: ${numberFormatter(value[1])}`, - `# Observations: ${numberFormatter(value[7])}`, + `# Observations: ${value[7]}`, ]; if (value[8].length > 0) { - stats.push(`# Outliers: ${numberFormatter(value[8].length)}`); + stats.push(`# Outliers: ${value[8].length}`); } return headline + stats.join('
'); }, From 58edc798203c0070d0b3384e35e1d8da1838ef5f Mon Sep 17 00:00:00 2001 From: Richard Parsons <50666468+rparsonsbb@users.noreply.github.com> Date: Wed, 30 Oct 2024 18:58:28 -0400 Subject: [PATCH 024/307] fix(mssql db_engine_spec): adds uniqueidentifier to column_type_mappings (#30618) --- superset/db_engine_specs/mssql.py | 8 +++ superset/models/sql_types/mssql_sql_types.py | 61 +++++++++++++++++++ .../unit_tests/db_engine_specs/test_mssql.py | 2 + 3 files changed, 71 insertions(+) create mode 100644 superset/models/sql_types/mssql_sql_types.py diff --git a/superset/db_engine_specs/mssql.py b/superset/db_engine_specs/mssql.py index 464f6cf2b9c8d..5b8ba457bafa3 100644 --- a/superset/db_engine_specs/mssql.py +++ b/superset/db_engine_specs/mssql.py @@ -14,6 +14,8 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. +from __future__ import annotations + import logging import re from datetime import datetime @@ -27,6 +29,7 @@ from superset.constants import TimeGrain from superset.db_engine_specs.base import BaseEngineSpec, LimitMethod from superset.errors import SupersetErrorType +from superset.models.sql_types.mssql_sql_types import GUID from superset.utils.core import GenericDataType logger = logging.getLogger(__name__) @@ -87,6 +90,11 @@ class MssqlEngineSpec(BaseEngineSpec): SMALLDATETIME(), GenericDataType.TEMPORAL, ), + ( + re.compile(r"^uniqueidentifier.*", re.IGNORECASE), + GUID(), + GenericDataType.STRING, + ), ) custom_errors: dict[Pattern[str], tuple[str, SupersetErrorType, dict[str, Any]]] = { diff --git a/superset/models/sql_types/mssql_sql_types.py b/superset/models/sql_types/mssql_sql_types.py new file mode 100644 index 0000000000000..add40e31006ad --- /dev/null +++ b/superset/models/sql_types/mssql_sql_types.py @@ -0,0 +1,61 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +# pylint: disable=abstract-method +import uuid +from typing import Any, Optional + +from sqlalchemy.engine.interfaces import Dialect +from sqlalchemy.sql.sqltypes import CHAR +from sqlalchemy.sql.visitors import Visitable +from sqlalchemy.types import TypeDecorator + +# _compiler_dispatch is defined to help with type compilation + + +class GUID(TypeDecorator): + """ + A type for SQL Server's uniqueidentifier, stored as stringified UUIDs. + """ + + impl = CHAR + + @property + def python_type(self) -> type[uuid.UUID]: + """The Python type for this SQL type is `uuid.UUID`.""" + return uuid.UUID + + @classmethod + def _compiler_dispatch(cls, _visitor: Visitable, **_kw: Any) -> str: + """Return the SQL type for the GUID type, which is CHAR(36) in SQL Server.""" + return "CHAR(36)" + + def process_bind_param(self, value: str, dialect: Dialect) -> Optional[str]: + """Prepare the UUID value for binding to the database.""" + if value is None: + return None + if not isinstance(value, uuid.UUID): + return str(uuid.UUID(value)) # Convert to string UUID if needed + return str(value) + + def process_result_value( + self, value: Optional[str], dialect: Dialect + ) -> Optional[uuid.UUID]: + """Convert the string back to a UUID when retrieving from the database.""" + if value is None: + return None + return uuid.UUID(value) diff --git a/tests/unit_tests/db_engine_specs/test_mssql.py b/tests/unit_tests/db_engine_specs/test_mssql.py index 38a5603e4ec93..0a3760a47f1fa 100644 --- a/tests/unit_tests/db_engine_specs/test_mssql.py +++ b/tests/unit_tests/db_engine_specs/test_mssql.py @@ -27,6 +27,7 @@ from sqlalchemy.types import String, TypeEngine, UnicodeText from superset.errors import ErrorLevel, SupersetError, SupersetErrorType +from superset.models.sql_types.mssql_sql_types import GUID from superset.utils.core import GenericDataType from tests.unit_tests.db_engine_specs.utils import ( assert_column_spec, @@ -46,6 +47,7 @@ ("NCHAR(10)", UnicodeText, None, GenericDataType.STRING, False), ("NVARCHAR(10)", UnicodeText, None, GenericDataType.STRING, False), ("NTEXT", UnicodeText, None, GenericDataType.STRING, False), + ("uniqueidentifier", GUID, None, GenericDataType.STRING, False), ], ) def test_get_column_spec( From 31aad28a31c117ad9c5c5a1957b6043a75e93020 Mon Sep 17 00:00:00 2001 From: Enzo Martellucci <52219496+EnxDev@users.noreply.github.com> Date: Thu, 31 Oct 2024 15:57:49 +0100 Subject: [PATCH 025/307] refactor: Migrate SliceAdder to typescript (#30697) --- .../spec/fixtures/mockSliceEntities.js | 133 +++++++++++++++--- ...liceAdder.test.jsx => SliceAdder.test.tsx} | 100 ++++++++----- .../{SliceAdder.jsx => SliceAdder.tsx} | 115 +++++++++------ ...ragPreview.jsx => AddSliceDragPreview.tsx} | 53 ++++--- 4 files changed, 269 insertions(+), 132 deletions(-) rename superset-frontend/src/dashboard/components/{SliceAdder.test.jsx => SliceAdder.test.tsx} (67%) rename superset-frontend/src/dashboard/components/{SliceAdder.jsx => SliceAdder.tsx} (82%) rename superset-frontend/src/dashboard/components/dnd/{AddSliceDragPreview.jsx => AddSliceDragPreview.tsx} (72%) diff --git a/superset-frontend/spec/fixtures/mockSliceEntities.js b/superset-frontend/spec/fixtures/mockSliceEntities.js index 2737d35d01d40..1a7bdad02429f 100644 --- a/superset-frontend/spec/fixtures/mockSliceEntities.js +++ b/superset-frontend/spec/fixtures/mockSliceEntities.js @@ -17,6 +17,7 @@ * under the License. */ import { datasourceId } from 'spec/fixtures/mockDatasource'; +import { DatasourceType } from '@superset-ui/core'; import { sliceId } from './mockChartQueries'; export const filterId = 127; @@ -47,8 +48,8 @@ export const sliceEntitiesForChart = { }, viz_type: 'pie', datasource: datasourceId, - description: null, - description_markeddown: '', + description: '', + description_markdown: '', modified: '23 hours ago', changed_on: 1529453332615, }, @@ -79,10 +80,18 @@ export const sliceEntitiesForDashboard = { }, viz_type: 'filter_box', datasource: '2__table', - description: null, - description_markeddown: '', + description: '', + description_markdown: '', modified: '23 hours ago', changed_on: 1529453332615, + changed_on_humanized: '', + datasource_id: 0, + datasource_type: DatasourceType.Query, + datasource_url: '', + datasource_name: '', + owners: [{ id: 0 }], + created_by: { id: 0 }, + thumbnail_url: '', }, 128: { slice_id: 128, @@ -91,10 +100,18 @@ export const sliceEntitiesForDashboard = { form_data: {}, viz_type: 'big_number', datasource: '2__table', - description: null, - description_markeddown: '', + description: '', + description_markdown: '', modified: '23 hours ago', changed_on: 1529453332628, + changed_on_humanized: '', + datasource_id: 0, + datasource_type: DatasourceType.Query, + datasource_url: '', + datasource_name: '', + owners: [{ id: 0 }], + created_by: { id: 0 }, + thumbnail_url: '', }, 129: { slice_id: 129, @@ -103,10 +120,19 @@ export const sliceEntitiesForDashboard = { form_data: {}, viz_type: 'table', datasource: '2__table', - description: null, - description_markeddown: '', + description: '', + description_markdown: 'dd', modified: '23 hours ago', changed_on: 1529453332637, + changed_on_humanized: '', + + datasource_id: 0, + datasource_type: DatasourceType.Query, + datasource_url: '', + datasource_name: '', + owners: [{ id: 0 }], + created_by: { id: 0 }, + thumbnail_url: '', }, 130: { slice_id: 130, @@ -115,10 +141,19 @@ export const sliceEntitiesForDashboard = { form_data: {}, viz_type: 'line', datasource: '2__table', - description: null, - description_markeddown: '', + description: '', + description_markdown: '', modified: '23 hours ago', changed_on: 1529453332645, + changed_on_humanized: '', + + datasource_id: 0, + datasource_type: DatasourceType.SlTable, + datasource_url: '', + datasource_name: '', + owners: [{ id: 0 }], + created_by: { id: 0 }, + thumbnail_url: '', }, 131: { slice_id: 131, @@ -127,10 +162,19 @@ export const sliceEntitiesForDashboard = { form_data: {}, viz_type: 'world_map', datasource: '2__table', - description: null, - description_markeddown: '', + description: '', + description_markdown: '', modified: '23 hours ago', changed_on: 1529453332654, + changed_on_humanized: '', + + datasource_id: 0, + datasource_type: DatasourceType.Table, + datasource_url: '', + datasource_name: '', + owners: [{ id: 0 }], + created_by: { id: 0 }, + thumbnail_url: '', }, 132: { slice_id: 132, @@ -139,10 +183,19 @@ export const sliceEntitiesForDashboard = { form_data: {}, viz_type: 'bubble', datasource: '2__table', - description: null, - description_markeddown: '', + description: '', + description_markdown: '', modified: '23 hours ago', changed_on: 1529453332663, + changed_on_humanized: '', + + datasource_id: 0, + datasource_type: DatasourceType.Query, + datasource_url: '', + datasource_name: '', + owners: [{ id: 0 }], + created_by: { id: 0 }, + thumbnail_url: '', }, 133: { slice_id: 133, @@ -151,10 +204,19 @@ export const sliceEntitiesForDashboard = { form_data: {}, viz_type: 'sunburst_v2', datasource: '2__table', - description: null, - description_markeddown: '', + description: '', + description_markdown: '', modified: '23 hours ago', changed_on: 1529453332673, + changed_on_humanized: '', + + datasource_id: 0, + datasource_type: DatasourceType.Query, + datasource_url: '', + datasource_name: '', + owners: [{ id: 0 }], + created_by: { id: 0 }, + thumbnail_url: '', }, 134: { slice_id: 134, @@ -163,10 +225,19 @@ export const sliceEntitiesForDashboard = { form_data: {}, viz_type: 'area', datasource: '2__table', - description: null, - description_markeddown: '', + description: '', + description_markdown: '', modified: '23 hours ago', changed_on: 1529453332680, + changed_on_humanized: '', + + datasource_id: 0, + datasource_type: DatasourceType.Dataset, + datasource_url: '', + datasource_name: '', + owners: [{ id: 0 }], + created_by: { id: 0 }, + thumbnail_url: '', }, 135: { slice_id: 135, @@ -175,10 +246,19 @@ export const sliceEntitiesForDashboard = { form_data: {}, viz_type: 'box_plot', datasource: '2__table', - description: null, - description_markeddown: '', + description: '', + description_markdown: '', modified: '23 hours ago', changed_on: 1529453332688, + changed_on_humanized: '', + + datasource_id: 0, + datasource_type: DatasourceType.Table, + datasource_url: '', + datasource_name: '', + owners: [{ id: 0 }], + created_by: { id: 0 }, + thumbnail_url: '', }, 136: { slice_id: 136, @@ -187,10 +267,19 @@ export const sliceEntitiesForDashboard = { form_data: {}, viz_type: 'treemap_v2', datasource: '2__table', - description: null, - description_markeddown: '', + description: '', + description_markdown: '', modified: '23 hours ago', changed_on: 1529453332700, + changed_on_humanized: '', + + datasource_id: 0, + datasource_type: DatasourceType.Table, + datasource_url: '', + datasource_name: '', + owners: [{ id: 0 }], + created_by: { id: 0 }, + thumbnail_url: '', }, }, isLoading: false, diff --git a/superset-frontend/src/dashboard/components/SliceAdder.test.jsx b/superset-frontend/src/dashboard/components/SliceAdder.test.tsx similarity index 67% rename from superset-frontend/src/dashboard/components/SliceAdder.test.jsx rename to superset-frontend/src/dashboard/components/SliceAdder.test.tsx index 6ae0346edb43e..a0a6acb568684 100644 --- a/superset-frontend/src/dashboard/components/SliceAdder.test.jsx +++ b/superset-frontend/src/dashboard/components/SliceAdder.test.tsx @@ -16,35 +16,45 @@ * specific language governing permissions and limitations * under the License. */ -import { shallow } from 'enzyme'; +import { shallow, ShallowWrapper } from 'enzyme'; import sinon from 'sinon'; import SliceAdder, { ChartList, DEFAULT_SORT_KEY, + SliceAdderProps, } from 'src/dashboard/components/SliceAdder'; import { sliceEntitiesForDashboard as mockSliceEntities } from 'spec/fixtures/mockSliceEntities'; import { styledShallow } from 'spec/helpers/theming'; -jest.mock('lodash/debounce', () => fn => { - // eslint-disable-next-line no-param-reassign - fn.throttle = jest.fn(); - return fn; -}); +jest.mock( + 'lodash/debounce', + () => (fn: { throttle: jest.Mock }) => { + // eslint-disable-next-line no-param-reassign + fn.throttle = jest.fn(); + return fn; + }, +); describe('SliceAdder', () => { - const props = { - ...mockSliceEntities, + const props: SliceAdderProps = { + slices: { + ...mockSliceEntities.slices, + }, fetchSlices: jest.fn(), updateSlices: jest.fn(), selectedSliceIds: [127, 128], userId: 1, + dashboardId: 0, + editMode: false, + errorMessage: '', + isLoading: false, + lastUpdated: 0, }; const errorProps = { ...props, errorMessage: 'this is error', }; - describe('SliceAdder.sortByComparator', () => { it('should sort by timestamp descending', () => { const sortedTimestamps = Object.values(props.slices) @@ -84,72 +94,88 @@ describe('SliceAdder', () => { }); it('componentDidMount', () => { - sinon.spy(SliceAdder.prototype, 'componentDidMount'); - sinon.spy(props, 'fetchSlices'); - + const componentDidMountSpy = sinon.spy( + SliceAdder.prototype, + 'componentDidMount', + ); + const fetchSlicesSpy = sinon.spy(props, 'fetchSlices'); shallow(, { lifecycleExperimental: true, }); - expect(SliceAdder.prototype.componentDidMount.calledOnce).toBe(true); - expect(props.fetchSlices.calledOnce).toBe(true); - SliceAdder.prototype.componentDidMount.restore(); - props.fetchSlices.restore(); + expect(componentDidMountSpy.calledOnce).toBe(true); + + expect(fetchSlicesSpy.calledOnce).toBe(true); + + componentDidMountSpy.restore(); + fetchSlicesSpy.restore(); }); describe('UNSAFE_componentWillReceiveProps', () => { - let wrapper; + let wrapper: ShallowWrapper; + let setStateSpy: sinon.SinonSpy; + beforeEach(() => { wrapper = shallow(); wrapper.setState({ filteredSlices: Object.values(props.slices) }); - sinon.spy(wrapper.instance(), 'setState'); + setStateSpy = sinon.spy(wrapper.instance() as SliceAdder, 'setState'); }); afterEach(() => { - wrapper.instance().setState.restore(); + setStateSpy.restore(); }); it('fetch slices should update state', () => { - wrapper.instance().UNSAFE_componentWillReceiveProps({ + const instance = wrapper.instance() as SliceAdder; + instance.UNSAFE_componentWillReceiveProps({ ...props, lastUpdated: new Date().getTime(), }); - expect(wrapper.instance().setState.calledOnce).toBe(true); + expect(setStateSpy.calledOnce).toBe(true); - const stateKeys = Object.keys( - wrapper.instance().setState.lastCall.args[0], - ); + const stateKeys = Object.keys(setStateSpy.lastCall.args[0]); expect(stateKeys).toContain('filteredSlices'); }); it('select slices should update state', () => { - wrapper.instance().UNSAFE_componentWillReceiveProps({ + const instance = wrapper.instance() as SliceAdder; + + instance.UNSAFE_componentWillReceiveProps({ ...props, selectedSliceIds: [127], }); - expect(wrapper.instance().setState.calledOnce).toBe(true); - const stateKeys = Object.keys( - wrapper.instance().setState.lastCall.args[0], - ); + expect(setStateSpy.calledOnce).toBe(true); + + const stateKeys = Object.keys(setStateSpy.lastCall.args[0]); expect(stateKeys).toContain('selectedSliceIdsSet'); }); }); describe('should rerun filter and sort', () => { - let wrapper; - let spy; + let wrapper: ShallowWrapper; + let spy: jest.Mock; + beforeEach(() => { - spy = props.fetchSlices; - wrapper = shallow(); - wrapper.setState({ filteredSlices: Object.values(props.slices) }); + spy = jest.fn(); + const fetchSlicesProps: SliceAdderProps = { + ...props, + fetchSlices: spy, + }; + wrapper = shallow(); + wrapper.setState({ + filteredSlices: Object.values(fetchSlicesProps.slices), + }); }); + afterEach(() => { spy.mockReset(); }); it('searchUpdated', () => { const newSearchTerm = 'new search term'; - wrapper.instance().handleChange(newSearchTerm); + + (wrapper.instance() as SliceAdder).handleChange(newSearchTerm); + expect(spy).toHaveBeenCalled(); expect(spy).toHaveBeenCalledWith( props.userId, @@ -160,7 +186,9 @@ describe('SliceAdder', () => { it('handleSelect', () => { const newSortBy = 'viz_type'; - wrapper.instance().handleSelect(newSortBy); + + (wrapper.instance() as SliceAdder).handleSelect(newSortBy); + expect(spy).toHaveBeenCalled(); expect(spy).toHaveBeenCalledWith(props.userId, '', newSortBy); }); diff --git a/superset-frontend/src/dashboard/components/SliceAdder.jsx b/superset-frontend/src/dashboard/components/SliceAdder.tsx similarity index 82% rename from superset-frontend/src/dashboard/components/SliceAdder.jsx rename to superset-frontend/src/dashboard/components/SliceAdder.tsx index b610fe152ce13..09f6270f83088 100644 --- a/superset-frontend/src/dashboard/components/SliceAdder.jsx +++ b/superset-frontend/src/dashboard/components/SliceAdder.tsx @@ -18,9 +18,9 @@ */ /* eslint-env browser */ import { Component } from 'react'; -import PropTypes from 'prop-types'; import AutoSizer from 'react-virtualized-auto-sizer'; import { FixedSizeList as List } from 'react-window'; +// @ts-ignore import { createFilter } from 'react-search-input'; import { t, styled, css } from '@superset-ui/core'; import { Input } from 'src/components/Input'; @@ -41,31 +41,40 @@ import { NEW_CHART_ID, NEW_COMPONENTS_SOURCE_ID, } from 'src/dashboard/util/constants'; -import { slicePropShape } from 'src/dashboard/util/propShapes'; import { debounce, pickBy } from 'lodash'; import Checkbox from 'src/components/Checkbox'; import { InfoTooltipWithTrigger } from '@superset-ui/chart-controls'; +import { Dispatch } from 'redux'; +import { Slice } from 'src/dashboard/types'; import AddSliceCard from './AddSliceCard'; import AddSliceDragPreview from './dnd/AddSliceDragPreview'; import DragDroppable from './dnd/DragDroppable'; -const propTypes = { - fetchSlices: PropTypes.func.isRequired, - updateSlices: PropTypes.func.isRequired, - isLoading: PropTypes.bool.isRequired, - slices: PropTypes.objectOf(slicePropShape).isRequired, - lastUpdated: PropTypes.number.isRequired, - errorMessage: PropTypes.string, - userId: PropTypes.number.isRequired, - selectedSliceIds: PropTypes.arrayOf(PropTypes.number), - editMode: PropTypes.bool, - dashboardId: PropTypes.number, +export type SliceAdderProps = { + fetchSlices: ( + userId?: number, + filter_value?: string, + sortColumn?: string, + ) => Promise; + updateSlices: (slices: { + [id: number]: Slice; + }) => (dispatch: Dispatch) => void; + isLoading: boolean; + slices: Record; + lastUpdated: number; + errorMessage?: string; + userId: number; + selectedSliceIds?: number[]; + editMode?: boolean; + dashboardId: number; }; -const defaultProps = { - selectedSliceIds: [], - editMode: false, - errorMessage: '', +type SliceAdderState = { + filteredSlices: Slice[]; + searchTerm: string; + sortBy: keyof Slice; + selectedSliceIdsSet: Set; + showOnlyMyCharts: boolean; }; const KEYS_TO_FILTERS = ['slice_name', 'viz_type', 'datasource_name']; @@ -92,7 +101,7 @@ const Controls = styled.div` `} `; -const StyledSelect = styled(Select)` +const StyledSelect = styled(Select)<{ id?: string }>` margin-left: ${({ theme }) => theme.gridUnit * 2}px; min-width: 150px; `; @@ -124,22 +133,33 @@ export const ChartList = styled.div` min-height: 0; `; -class SliceAdder extends Component { - static sortByComparator(attr) { +class SliceAdder extends Component { + private slicesRequest?: AbortController | Promise; + + static sortByComparator(attr: keyof Slice) { const desc = attr === 'changed_on' ? -1 : 1; - return (a, b) => { - if (a[attr] < b[attr]) { + return (a: Slice, b: Slice) => { + const aValue = a[attr] ?? Number.MIN_SAFE_INTEGER; + const bValue = b[attr] ?? Number.MIN_SAFE_INTEGER; + + if (aValue < bValue) { return -1 * desc; } - if (a[attr] > b[attr]) { + if (aValue > bValue) { return 1 * desc; } return 0; }; } - constructor(props) { + static defaultProps = { + selectedSliceIds: [], + editMode: false, + errorMessage: '', + }; + + constructor(props: SliceAdderProps) { super(props); this.state = { filteredSlices: [], @@ -163,11 +183,15 @@ class SliceAdder extends Component { } componentDidMount() { - this.slicesRequest = this.props.fetchSlices(this.userIdForFetch()); + this.slicesRequest = this.props.fetchSlices( + this.userIdForFetch(), + '', + this.state.sortBy, + ); } - UNSAFE_componentWillReceiveProps(nextProps) { - const nextState = {}; + UNSAFE_componentWillReceiveProps(nextProps: SliceAdderProps) { + const nextState: SliceAdderState = {} as SliceAdderState; if (nextProps.lastUpdated !== this.props.lastUpdated) { nextState.filteredSlices = this.getFilteredSortedSlices( nextProps.slices, @@ -188,22 +212,27 @@ class SliceAdder extends Component { componentWillUnmount() { // Clears the redux store keeping only selected items - const selectedSlices = pickBy(this.props.slices, value => + const selectedSlices = pickBy(this.props.slices, (value: Slice) => this.state.selectedSliceIdsSet.has(value.slice_id), ); + this.props.updateSlices(selectedSlices); - if (this.slicesRequest && this.slicesRequest.abort) { + if (this.slicesRequest instanceof AbortController) { this.slicesRequest.abort(); } } - getFilteredSortedSlices(slices, searchTerm, sortBy, showOnlyMyCharts) { + getFilteredSortedSlices( + slices: SliceAdderProps['slices'], + searchTerm: string, + sortBy: keyof Slice, + showOnlyMyCharts: boolean, + ) { return Object.values(slices) .filter(slice => showOnlyMyCharts - ? (slice.owners && - slice.owners.find(owner => owner.id === this.props.userId)) || - (slice.created_by && slice.created_by.id === this.props.userId) + ? slice?.owners?.find(owner => owner.id === this.props.userId) || + slice?.created_by?.id === this.props.userId : true, ) .filter(createFilter(searchTerm, KEYS_TO_FILTERS)) @@ -219,7 +248,7 @@ class SliceAdder extends Component { ); }, 300); - searchUpdated(searchTerm) { + searchUpdated(searchTerm: string) { this.setState(prevState => ({ searchTerm, filteredSlices: this.getFilteredSortedSlices( @@ -231,7 +260,7 @@ class SliceAdder extends Component { })); } - handleSelect(sortBy) { + handleSelect(sortBy: keyof Slice) { this.setState(prevState => ({ sortBy, filteredSlices: this.getFilteredSortedSlices( @@ -248,9 +277,10 @@ class SliceAdder extends Component { ); } - rowRenderer({ key, index, style }) { + rowRenderer({ index, style }: { index: number; style: React.CSSProperties }) { const { filteredSlices, selectedSliceIdsSet } = this.state; const cellData = filteredSlices[index]; + const isSelected = selectedSliceIdsSet.has(cellData.slice_id); const type = CHART_TYPE; const id = NEW_CHART_ID; @@ -261,7 +291,7 @@ class SliceAdder extends Component { }; return ( 0 && ( - {({ height, width }) => ( + {({ height, width }: { height: number; width: number }) => ( this.state.filteredSlices[index].slice_id} > {this.rowRenderer} @@ -422,7 +450,4 @@ class SliceAdder extends Component { } } -SliceAdder.propTypes = propTypes; -SliceAdder.defaultProps = defaultProps; - export default SliceAdder; diff --git a/superset-frontend/src/dashboard/components/dnd/AddSliceDragPreview.jsx b/superset-frontend/src/dashboard/components/dnd/AddSliceDragPreview.tsx similarity index 72% rename from superset-frontend/src/dashboard/components/dnd/AddSliceDragPreview.jsx rename to superset-frontend/src/dashboard/components/dnd/AddSliceDragPreview.tsx index 375e2cdc3639a..dfd2d036880cd 100644 --- a/superset-frontend/src/dashboard/components/dnd/AddSliceDragPreview.jsx +++ b/superset-frontend/src/dashboard/components/dnd/AddSliceDragPreview.tsx @@ -16,17 +16,28 @@ * specific language governing permissions and limitations * under the License. */ -import PropTypes from 'prop-types'; -import { DragLayer } from 'react-dnd'; - +import { DragLayer, XYCoord } from 'react-dnd'; +import { Slice } from 'src/dashboard/types'; import AddSliceCard from '../AddSliceCard'; -import { slicePropShape } from '../../util/propShapes'; import { NEW_COMPONENT_SOURCE_TYPE, CHART_TYPE, } from '../../util/componentTypes'; -const staticCardStyles = { +interface DragItem { + index: number; + parentType: string; + type: string; +} + +interface AddSliceDragPreviewProps { + dragItem: DragItem | null; + slices: Slice[] | null; + isDragging: boolean; + currentOffset: XYCoord | null; +} + +const staticCardStyles: React.CSSProperties = { position: 'fixed', pointerEvents: 'none', top: 0, @@ -35,25 +46,12 @@ const staticCardStyles = { width: 376 - 2 * 16, }; -const propTypes = { - dragItem: PropTypes.shape({ - index: PropTypes.number.isRequired, - }), - slices: PropTypes.arrayOf(slicePropShape), - isDragging: PropTypes.bool.isRequired, - currentOffset: PropTypes.shape({ - x: PropTypes.number.isRequired, - y: PropTypes.number.isRequired, - }), -}; - -const defaultProps = { - currentOffset: null, - dragItem: null, - slices: null, -}; - -function AddSliceDragPreview({ dragItem, slices, isDragging, currentOffset }) { +const AddSliceDragPreview: React.FC = ({ + dragItem, + slices, + isDragging, + currentOffset, +}) => { if (!isDragging || !currentOffset || !dragItem || !slices) return null; const slice = slices[dragItem.index]; @@ -77,14 +75,11 @@ function AddSliceDragPreview({ dragItem, slices, isDragging, currentOffset }) { datasourceName={slice.datasource_name} /> ); -} - -AddSliceDragPreview.propTypes = propTypes; -AddSliceDragPreview.defaultProps = defaultProps; +}; // This injects these props into the component export default DragLayer(monitor => ({ - dragItem: monitor.getItem(), + dragItem: monitor.getItem() as DragItem | null, currentOffset: monitor.getSourceClientOffset(), isDragging: monitor.isDragging(), }))(AddSliceDragPreview); From 2518190b2d2d7f838944e4ebd0c064e1d93a0fb6 Mon Sep 17 00:00:00 2001 From: Daniel Lee Date: Thu, 31 Oct 2024 13:20:16 -0400 Subject: [PATCH 026/307] style(databases-upload-form): update Upload Form cosmetics (#30758) --- .../databases/UploadDataModel/index.tsx | 48 +++++++++++-------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/superset-frontend/src/features/databases/UploadDataModel/index.tsx b/superset-frontend/src/features/databases/UploadDataModel/index.tsx index ec28091e9b028..37f9e6a5e3f62 100644 --- a/superset-frontend/src/features/databases/UploadDataModel/index.tsx +++ b/superset-frontend/src/features/databases/UploadDataModel/index.tsx @@ -173,6 +173,12 @@ const allowedExtensionsToAccept = { columnar: '.parquet, .zip', }; +const extensionsToLabel: Record = { + csv: 'CSV', + excel: 'Excel', + columnar: 'Columnar', +}; + export const validateUploadFileExtension = ( file: UploadFile, allowedExtensions: string[], @@ -478,7 +484,7 @@ const UploadDataModal: FunctionComponent = ({ headers: { Accept: 'application/json' }, }) .then(() => { - addSuccessToast(t('Data Imported')); + addSuccessToast(t('Data imported')); setIsLoading(false); onClose(); }) @@ -565,9 +571,9 @@ const UploadDataModal: FunctionComponent = ({ }; const uploadTitles = { - csv: t('CSV Upload'), - excel: t('Excel Upload'), - columnar: t('Columnar Upload'), + csv: t('CSV upload'), + excel: t('Excel upload'), + columnar: t('Columnar upload'), }; const UploadTitle: FC = () => { @@ -616,9 +622,11 @@ const UploadDataModal: FunctionComponent = ({ key="general" > - + = ({ - + + + = ({ = ({ -

{t('File Settings')}

+

{t('File settings')}

{t( 'Adjust how spaces, blank lines, null values are handled and other file wide settings.', @@ -767,7 +777,7 @@ const UploadDataModal: FunctionComponent = ({ @@ -783,7 +793,7 @@ const UploadDataModal: FunctionComponent = ({ = ({ = ({ = ({ = ({ = ({ = ({ Date: Fri, 1 Nov 2024 11:39:43 +0200 Subject: [PATCH 027/307] fix(Dashboard): Sync/Async Dashboard Screenshot Generation and Default Cache (#30755) Co-authored-by: Michael S. Molina Co-authored-by: Michael S. Molina <70410625+michael-s-molina@users.noreply.github.com> --- .github/workflows/dependency-review.yml | 2 +- superset-frontend/package-lock.json | 332 +++++++++++++++++- superset-frontend/package.json | 1 + .../src/utils/featureFlags.ts | 2 + .../DownloadAsImage.test.tsx | 17 +- .../DownloadMenuItems/DownloadAsImage.tsx | 4 +- .../DownloadMenuItems/DownloadAsPdf.test.tsx | 73 ++++ .../menu/DownloadMenuItems/DownloadAsPdf.tsx | 55 +++ .../DownloadScreenshot.test.tsx | 5 +- .../DownloadMenuItems/DownloadScreenshot.tsx | 111 ++++-- .../menu/DownloadMenuItems/index.tsx | 54 ++- superset-frontend/src/types/dom-to-pdf.d.ts | 36 ++ superset-frontend/src/utils/downloadAsPdf.ts | 74 ++++ superset/config.py | 8 + superset/dashboards/api.py | 10 +- .../integration_tests/dashboards/api_tests.py | 55 ++- 16 files changed, 760 insertions(+), 79 deletions(-) create mode 100644 superset-frontend/src/dashboard/components/menu/DownloadMenuItems/DownloadAsPdf.test.tsx create mode 100644 superset-frontend/src/dashboard/components/menu/DownloadMenuItems/DownloadAsPdf.tsx create mode 100644 superset-frontend/src/types/dom-to-pdf.d.ts create mode 100644 superset-frontend/src/utils/downloadAsPdf.ts diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml index 773e7358345f1..11ed2d772093b 100644 --- a/.github/workflows/dependency-review.yml +++ b/.github/workflows/dependency-review.yml @@ -32,4 +32,4 @@ jobs: # license: https://applitools.com/legal/open-source-terms-of-use/ # pkg:npm/node-forge@1.3.1 # selecting BSD-3-Clause licensing terms for node-forge to ensure compatibility with Apache - allow-dependencies-licenses: pkg:npm/store2@2.14.2, pkg:npm/applitools/core, pkg:npm/applitools/core-base, pkg:npm/applitools/css-tree, pkg:npm/applitools/ec-client, pkg:npm/applitools/eg-socks5-proxy-server, pkg:npm/applitools/eyes, pkg:npm/applitools/eyes-cypress, pkg:npm/applitools/nml-client, pkg:npm/applitools/tunnel-client, pkg:npm/applitools/utils, pkg:npm/node-forge@1.3.1 + allow-dependencies-licenses: pkg:npm/store2@2.14.2, pkg:npm/applitools/core, pkg:npm/applitools/core-base, pkg:npm/applitools/css-tree, pkg:npm/applitools/ec-client, pkg:npm/applitools/eg-socks5-proxy-server, pkg:npm/applitools/eyes, pkg:npm/applitools/eyes-cypress, pkg:npm/applitools/nml-client, pkg:npm/applitools/tunnel-client, pkg:npm/applitools/utils, pkg:npm/node-forge@1.3.1, pkg:npm/rgbcolor diff --git a/superset-frontend/package-lock.json b/superset-frontend/package-lock.json index 83acfcd5349c3..a859168b7c846 100644 --- a/superset-frontend/package-lock.json +++ b/superset-frontend/package-lock.json @@ -71,6 +71,7 @@ "d3-scale": "^2.1.2", "dayjs": "^1.11.13", "dom-to-image-more": "^3.2.0", + "dom-to-pdf": "^0.3.2", "emotion-rgba": "0.0.12", "fast-glob": "^3.3.2", "fs-extra": "^11.2.0", @@ -13879,6 +13880,13 @@ "version": "6.9.7", "license": "MIT" }, + "node_modules/@types/raf": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/@types/raf/-/raf-3.4.3.tgz", + "integrity": "sha512-c4YAvMedbPZ5tEyxzQdMoOhhJ4RD3rngZIdwC2/qDN3d7JpEhB6fiBRKVY1lg5B7Wk+uPBjn5f39j1/2MY1oOw==", + "license": "MIT", + "optional": true + }, "node_modules/@types/range-parser": { "version": "1.2.4", "license": "MIT" @@ -17358,7 +17366,6 @@ }, "node_modules/atob": { "version": "2.1.2", - "dev": true, "license": "(MIT OR Apache-2.0)", "bin": { "atob": "bin/atob.js" @@ -18076,6 +18083,16 @@ "version": "1.0.0", "license": "MIT" }, + "node_modules/base64-arraybuffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", + "integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 0.6.0" + } + }, "node_modules/base64-js": { "version": "1.5.1", "funding": [ @@ -18543,6 +18560,18 @@ "node-int64": "^0.4.0" } }, + "node_modules/btoa": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/btoa/-/btoa-1.2.1.tgz", + "integrity": "sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g==", + "license": "(MIT OR Apache-2.0)", + "bin": { + "btoa": "bin/btoa.js" + }, + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/buf-compare": { "version": "1.0.1", "license": "MIT", @@ -19036,6 +19065,33 @@ ], "license": "CC-BY-4.0" }, + "node_modules/canvg": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/canvg/-/canvg-3.0.10.tgz", + "integrity": "sha512-qwR2FRNO9NlzTeKIPIKpnTY6fqwuYSequ8Ru8c0YkYU7U0oW+hLUvWadLvAu1Rl72OMNiFhoLu4f8eUjQ7l/+Q==", + "license": "MIT", + "optional": true, + "dependencies": { + "@babel/runtime": "^7.12.5", + "@types/raf": "^3.4.0", + "core-js": "^3.8.3", + "raf": "^3.4.1", + "regenerator-runtime": "^0.13.7", + "rgbcolor": "^1.0.1", + "stackblur-canvas": "^2.0.0", + "svg-pathdata": "^6.0.3" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/canvg/node_modules/regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", + "license": "MIT", + "optional": true + }, "node_modules/capture-exit": { "version": "2.0.0", "dev": true, @@ -20619,6 +20675,16 @@ "isobject": "^3.0.1" } }, + "node_modules/css-line-break": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz", + "integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==", + "license": "MIT", + "optional": true, + "dependencies": { + "utrie": "^1.0.2" + } + }, "node_modules/css-loader": { "version": "6.8.1", "dev": true, @@ -22609,10 +22675,25 @@ "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" } }, + "node_modules/dom-to-image": { + "version": "2.6.0", + "resolved": "git+ssh://git@github.com/dmapper/dom-to-image.git#a7c386a8ea813930f05449ac71ab4be0c262dff3", + "license": "MIT" + }, "node_modules/dom-to-image-more": { "version": "3.2.0", "license": "MIT" }, + "node_modules/dom-to-pdf": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/dom-to-pdf/-/dom-to-pdf-0.3.2.tgz", + "integrity": "sha512-eHLQ/IK+2PQlRjybQ9UHYwpiTd/YZFKqGFyRCjVvi6CPlH58drWQnxf7HBCVRUyAjOtI3RG0kvLidPhC7dOhcQ==", + "license": "MIT", + "dependencies": { + "dom-to-image": "git+https://github.com/dmapper/dom-to-image.git", + "jspdf": "^2.5.1" + } + }, "node_modules/dom-walk": { "version": "0.1.1" }, @@ -22640,6 +22721,13 @@ "url": "https://github.com/fb55/domhandler?sponsor=1" } }, + "node_modules/dompurify": { + "version": "2.5.7", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.5.7.tgz", + "integrity": "sha512-2q4bEI+coQM8f5ez7kt2xclg1XsecaV9ASJk/54vwlfRRNQfDqJz2pzQ8t0Ix/ToBpXlVjrRIx7pFC/o8itG2Q==", + "license": "(MPL-2.0 OR Apache-2.0)", + "optional": true + }, "node_modules/domutils": { "version": "3.1.0", "dev": true, @@ -25929,6 +26017,12 @@ "version": "6.0.0", "license": "MIT" }, + "node_modules/fflate": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz", + "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==", + "license": "MIT" + }, "node_modules/figures": { "version": "3.2.0", "dev": true, @@ -28659,6 +28753,20 @@ "node": ">=6" } }, + "node_modules/html2canvas": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz", + "integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==", + "license": "MIT", + "optional": true, + "dependencies": { + "css-line-break": "^2.1.0", + "text-segmentation": "^1.0.3" + }, + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/htmlparser2": { "version": "8.0.2", "dev": true, @@ -33251,6 +33359,24 @@ "node": "*" } }, + "node_modules/jspdf": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jspdf/-/jspdf-2.5.2.tgz", + "integrity": "sha512-myeX9c+p7znDWPk0eTrujCzNjT+CXdXyk7YmJq5nD5V7uLLKmSXnlQ/Jn/kuo3X09Op70Apm0rQSnFWyGK8uEQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.23.2", + "atob": "^2.1.2", + "btoa": "^1.2.1", + "fflate": "^0.8.1" + }, + "optionalDependencies": { + "canvg": "^3.0.6", + "core-js": "^3.6.0", + "dompurify": "^2.5.4", + "html2canvas": "^1.0.0-rc.5" + } + }, "node_modules/jsprim": { "version": "1.4.2", "dev": true, @@ -43191,7 +43317,7 @@ }, "node_modules/performance-now": { "version": "2.1.0", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/periscopic": { @@ -44746,7 +44872,7 @@ }, "node_modules/raf": { "version": "3.4.1", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "performance-now": "^2.1.0" @@ -48352,6 +48478,16 @@ "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", "dev": true }, + "node_modules/rgbcolor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/rgbcolor/-/rgbcolor-1.0.1.tgz", + "integrity": "sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 0.8.15" + } + }, "node_modules/rimraf": { "version": "6.0.1", "license": "ISC", @@ -50008,6 +50144,16 @@ "node": ">=8" } }, + "node_modules/stackblur-canvas": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/stackblur-canvas/-/stackblur-canvas-2.7.0.tgz", + "integrity": "sha512-yf7OENo23AGJhBriGx0QivY5JP6Y1HbrrDI6WLt6C5auYZXlQrheoY8hD4ibekFKz1HOfE48Ww8kMWMnJD/zcQ==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.1.14" + } + }, "node_modules/static-eval": { "version": "2.1.0", "license": "MIT", @@ -50563,6 +50709,16 @@ "dev": true, "license": "MIT" }, + "node_modules/svg-pathdata": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/svg-pathdata/-/svg-pathdata-6.0.3.tgz", + "integrity": "sha512-qsjeeq5YjBZ5eMdFuUa4ZosMLxgr5RZ+F+Y1OrDhuOCEInRMA3x74XdBtggJcj9kOeInz0WE+LgCPDkZFlBYJw==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/svgo": { "version": "3.2.0", "dev": true, @@ -51024,6 +51180,16 @@ "node": ">=0.10" } }, + "node_modules/text-segmentation": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz", + "integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==", + "license": "MIT", + "optional": true, + "dependencies": { + "utrie": "^1.0.2" + } + }, "node_modules/text-table": { "version": "0.2.0", "license": "MIT" @@ -52416,6 +52582,16 @@ "node": ">= 0.4.0" } }, + "node_modules/utrie": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz", + "integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==", + "license": "MIT", + "optional": true, + "dependencies": { + "base64-arraybuffer": "^1.0.2" + } + }, "node_modules/uuid": { "version": "3.4.0", "dev": true, @@ -58112,7 +58288,9 @@ } }, "plugins/legacy-preset-chart-nvd3/node_modules/dompurify": { - "version": "3.1.0", + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.1.7.tgz", + "integrity": "sha512-VaTstWtsneJY8xzy7DekmYWEOZcmzIe3Qb3zPd4STve1OBTa+e+WmS1ITQec1fZYXI3HCsOZZiSMpG6oxoWMWQ==", "license": "(MPL-2.0 OR Apache-2.0)" }, "plugins/plugin-chart-echarts": { @@ -68699,7 +68877,9 @@ }, "dependencies": { "dompurify": { - "version": "3.1.0" + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.1.7.tgz", + "integrity": "sha512-VaTstWtsneJY8xzy7DekmYWEOZcmzIe3Qb3zPd4STve1OBTa+e+WmS1ITQec1fZYXI3HCsOZZiSMpG6oxoWMWQ==" } } }, @@ -69831,6 +70011,12 @@ "@types/qs": { "version": "6.9.7" }, + "@types/raf": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/@types/raf/-/raf-3.4.3.tgz", + "integrity": "sha512-c4YAvMedbPZ5tEyxzQdMoOhhJ4RD3rngZIdwC2/qDN3d7JpEhB6fiBRKVY1lg5B7Wk+uPBjn5f39j1/2MY1oOw==", + "optional": true + }, "@types/range-parser": { "version": "1.2.4" }, @@ -72271,8 +72457,7 @@ "peer": true }, "atob": { - "version": "2.1.2", - "dev": true + "version": "2.1.2" }, "atomic-sleep": { "version": "1.0.0", @@ -72766,6 +72951,12 @@ "base16": { "version": "1.0.0" }, + "base64-arraybuffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", + "integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==", + "optional": true + }, "base64-js": { "version": "1.5.1" }, @@ -73091,6 +73282,11 @@ "node-int64": "^0.4.0" } }, + "btoa": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/btoa/-/btoa-1.2.1.tgz", + "integrity": "sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g==" + }, "buf-compare": { "version": "1.0.1" }, @@ -73396,6 +73592,30 @@ "caniuse-lite": { "version": "1.0.30001639" }, + "canvg": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/canvg/-/canvg-3.0.10.tgz", + "integrity": "sha512-qwR2FRNO9NlzTeKIPIKpnTY6fqwuYSequ8Ru8c0YkYU7U0oW+hLUvWadLvAu1Rl72OMNiFhoLu4f8eUjQ7l/+Q==", + "optional": true, + "requires": { + "@babel/runtime": "^7.12.5", + "@types/raf": "^3.4.0", + "core-js": "^3.38.1", + "raf": "^3.4.1", + "regenerator-runtime": "^0.13.7", + "rgbcolor": "^1.0.1", + "stackblur-canvas": "^2.0.0", + "svg-pathdata": "^6.0.3" + }, + "dependencies": { + "regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", + "optional": true + } + } + }, "capture-exit": { "version": "2.0.0", "dev": true, @@ -74471,6 +74691,15 @@ "isobject": "^3.0.1" } }, + "css-line-break": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz", + "integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==", + "optional": true, + "requires": { + "utrie": "^1.0.2" + } + }, "css-loader": { "version": "6.8.1", "dev": true, @@ -75800,9 +76029,22 @@ "entities": "^4.2.0" } }, + "dom-to-image": { + "version": "git+ssh://git@github.com/dmapper/dom-to-image.git#a7c386a8ea813930f05449ac71ab4be0c262dff3", + "from": "dom-to-image@git+https://github.com/dmapper/dom-to-image.git" + }, "dom-to-image-more": { "version": "3.2.0" }, + "dom-to-pdf": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/dom-to-pdf/-/dom-to-pdf-0.3.2.tgz", + "integrity": "sha512-eHLQ/IK+2PQlRjybQ9UHYwpiTd/YZFKqGFyRCjVvi6CPlH58drWQnxf7HBCVRUyAjOtI3RG0kvLidPhC7dOhcQ==", + "requires": { + "dom-to-image": "git+https://github.com/dmapper/dom-to-image.git", + "jspdf": "^2.5.1" + } + }, "dom-walk": { "version": "0.1.1" }, @@ -75816,6 +76058,12 @@ "domelementtype": "^2.3.0" } }, + "dompurify": { + "version": "2.5.7", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.5.7.tgz", + "integrity": "sha512-2q4bEI+coQM8f5ez7kt2xclg1XsecaV9ASJk/54vwlfRRNQfDqJz2pzQ8t0Ix/ToBpXlVjrRIx7pFC/o8itG2Q==", + "optional": true + }, "domutils": { "version": "3.1.0", "dev": true, @@ -77982,6 +78230,11 @@ "fetch-retry": { "version": "6.0.0" }, + "fflate": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz", + "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==" + }, "figures": { "version": "3.2.0", "dev": true, @@ -79740,6 +79993,16 @@ } } }, + "html2canvas": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz", + "integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==", + "optional": true, + "requires": { + "css-line-break": "^2.1.0", + "text-segmentation": "^1.0.3" + } + }, "htmlparser2": { "version": "8.0.2", "dev": true, @@ -82719,6 +82982,21 @@ "through": ">=2.2.7 <3" } }, + "jspdf": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jspdf/-/jspdf-2.5.2.tgz", + "integrity": "sha512-myeX9c+p7znDWPk0eTrujCzNjT+CXdXyk7YmJq5nD5V7uLLKmSXnlQ/Jn/kuo3X09Op70Apm0rQSnFWyGK8uEQ==", + "requires": { + "@babel/runtime": "^7.23.2", + "atob": "^2.1.2", + "btoa": "^1.2.1", + "canvg": "^3.0.6", + "core-js": "^3.38.1", + "dompurify": "^2.5.4", + "fflate": "^0.8.1", + "html2canvas": "^1.0.0-rc.5" + } + }, "jsprim": { "version": "1.4.2", "dev": true, @@ -88598,7 +88876,7 @@ }, "performance-now": { "version": "2.1.0", - "dev": true + "devOptional": true }, "periscopic": { "version": "3.1.0", @@ -89546,7 +89824,7 @@ }, "raf": { "version": "3.4.1", - "dev": true, + "devOptional": true, "requires": { "performance-now": "^2.1.0" } @@ -91831,6 +92109,12 @@ "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", "dev": true }, + "rgbcolor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/rgbcolor/-/rgbcolor-1.0.1.tgz", + "integrity": "sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw==", + "optional": true + }, "rimraf": { "version": "6.0.1", "requires": { @@ -92964,6 +93248,12 @@ } } }, + "stackblur-canvas": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/stackblur-canvas/-/stackblur-canvas-2.7.0.tgz", + "integrity": "sha512-yf7OENo23AGJhBriGx0QivY5JP6Y1HbrrDI6WLt6C5auYZXlQrheoY8hD4ibekFKz1HOfE48Ww8kMWMnJD/zcQ==", + "optional": true + }, "static-eval": { "version": "2.1.0", "requires": { @@ -93308,6 +93598,12 @@ "version": "2.0.4", "dev": true }, + "svg-pathdata": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/svg-pathdata/-/svg-pathdata-6.0.3.tgz", + "integrity": "sha512-qsjeeq5YjBZ5eMdFuUa4ZosMLxgr5RZ+F+Y1OrDhuOCEInRMA3x74XdBtggJcj9kOeInz0WE+LgCPDkZFlBYJw==", + "optional": true + }, "svgo": { "version": "3.2.0", "dev": true, @@ -93610,6 +93906,15 @@ "integrity": "sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==", "dev": true }, + "text-segmentation": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz", + "integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==", + "optional": true, + "requires": { + "utrie": "^1.0.2" + } + }, "text-table": { "version": "0.2.0" }, @@ -94483,6 +94788,15 @@ "version": "1.0.1", "dev": true }, + "utrie": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz", + "integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==", + "optional": true, + "requires": { + "base64-arraybuffer": "^1.0.2" + } + }, "uuid": { "version": "3.4.0", "dev": true diff --git a/superset-frontend/package.json b/superset-frontend/package.json index 736c294de0ea6..b373eb041bcfb 100644 --- a/superset-frontend/package.json +++ b/superset-frontend/package.json @@ -137,6 +137,7 @@ "d3-scale": "^2.1.2", "dayjs": "^1.11.13", "dom-to-image-more": "^3.2.0", + "dom-to-pdf": "^0.3.2", "emotion-rgba": "0.0.12", "fast-glob": "^3.3.2", "fs-extra": "^11.2.0", diff --git a/superset-frontend/packages/superset-ui-core/src/utils/featureFlags.ts b/superset-frontend/packages/superset-ui-core/src/utils/featureFlags.ts index 8801706c55ff6..be28944a9178d 100644 --- a/superset-frontend/packages/superset-ui-core/src/utils/featureFlags.ts +++ b/superset-frontend/packages/superset-ui-core/src/utils/featureFlags.ts @@ -60,6 +60,8 @@ export enum FeatureFlag { UseAnalagousColors = 'USE_ANALAGOUS_COLORS', ForceSqlLabRunAsync = 'SQLLAB_FORCE_RUN_ASYNC', SlackEnableAvatars = 'SLACK_ENABLE_AVATARS', + EnableDashboardScreenshotEndpoints = 'ENABLE_DASHBOARD_SCREENSHOT_ENDPOINTS', + EnableDashboardDownloadWebDriverScreenshot = 'ENABLE_DASHBOARD_DOWNLOAD_WEBDRIVER_SCREENSHOT', } export type ScheduleQueriesProps = { diff --git a/superset-frontend/src/dashboard/components/menu/DownloadMenuItems/DownloadAsImage.test.tsx b/superset-frontend/src/dashboard/components/menu/DownloadMenuItems/DownloadAsImage.test.tsx index 7e9d9226df7ab..8401ece73c4c2 100644 --- a/superset-frontend/src/dashboard/components/menu/DownloadMenuItems/DownloadAsImage.test.tsx +++ b/superset-frontend/src/dashboard/components/menu/DownloadMenuItems/DownloadAsImage.test.tsx @@ -23,13 +23,20 @@ import { Menu } from 'src/components/Menu'; import downloadAsImage from 'src/utils/downloadAsImage'; import DownloadAsImage from './DownloadAsImage'; +const mockAddDangerToast = jest.fn(); + jest.mock('src/utils/downloadAsImage', () => ({ __esModule: true, default: jest.fn(() => (_e: SyntheticEvent) => {}), })); +jest.mock('src/components/MessageToasts/withToasts', () => ({ + useToasts: () => ({ + addDangerToast: mockAddDangerToast, + }), +})); + const createProps = () => ({ - addDangerToast: jest.fn(), text: 'Download as Image', dashboardTitle: 'Test Dashboard', logEvent: jest.fn(), @@ -40,22 +47,24 @@ const renderComponent = () => {

, + { + useRedux: true, + }, ); }; test('Should call download image on click', async () => { - const props = createProps(); renderComponent(); await waitFor(() => { expect(downloadAsImage).toHaveBeenCalledTimes(0); - expect(props.addDangerToast).toHaveBeenCalledTimes(0); + expect(mockAddDangerToast).toHaveBeenCalledTimes(0); }); userEvent.click(screen.getByRole('button', { name: 'Download as Image' })); await waitFor(() => { expect(downloadAsImage).toHaveBeenCalledTimes(1); - expect(props.addDangerToast).toHaveBeenCalledTimes(0); + expect(mockAddDangerToast).toHaveBeenCalledTimes(0); }); }); diff --git a/superset-frontend/src/dashboard/components/menu/DownloadMenuItems/DownloadAsImage.tsx b/superset-frontend/src/dashboard/components/menu/DownloadMenuItems/DownloadAsImage.tsx index 0cb3f1fbb4f41..505a9b8184ae1 100644 --- a/superset-frontend/src/dashboard/components/menu/DownloadMenuItems/DownloadAsImage.tsx +++ b/superset-frontend/src/dashboard/components/menu/DownloadMenuItems/DownloadAsImage.tsx @@ -21,20 +21,20 @@ import { logging, t } from '@superset-ui/core'; import { Menu } from 'src/components/Menu'; import { LOG_ACTIONS_DASHBOARD_DOWNLOAD_AS_IMAGE } from 'src/logger/LogUtils'; import downloadAsImage from 'src/utils/downloadAsImage'; +import { useToasts } from 'src/components/MessageToasts/withToasts'; export default function DownloadAsImage({ text, logEvent, dashboardTitle, - addDangerToast, ...rest }: { text: string; - addDangerToast: Function; dashboardTitle: string; logEvent?: Function; }) { const SCREENSHOT_NODE_SELECTOR = '.dashboard'; + const { addDangerToast } = useToasts(); const onDownloadImage = async (e: SyntheticEvent) => { try { downloadAsImage(SCREENSHOT_NODE_SELECTOR, dashboardTitle, true)(e); diff --git a/superset-frontend/src/dashboard/components/menu/DownloadMenuItems/DownloadAsPdf.test.tsx b/superset-frontend/src/dashboard/components/menu/DownloadMenuItems/DownloadAsPdf.test.tsx new file mode 100644 index 0000000000000..56916f4b64763 --- /dev/null +++ b/superset-frontend/src/dashboard/components/menu/DownloadMenuItems/DownloadAsPdf.test.tsx @@ -0,0 +1,73 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { SyntheticEvent } from 'react'; +import { render, screen, waitFor } from 'spec/helpers/testing-library'; +import userEvent from '@testing-library/user-event'; +import { Menu } from 'src/components/Menu'; +import downloadAsPdf from 'src/utils/downloadAsPdf'; +import DownloadAsPdf from './DownloadAsPdf'; + +const mockAddDangerToast = jest.fn(); + +jest.mock('src/utils/downloadAsPdf', () => ({ + __esModule: true, + default: jest.fn(() => (_e: SyntheticEvent) => {}), +})); + +jest.mock('src/components/MessageToasts/withToasts', () => ({ + useToasts: () => ({ + addDangerToast: mockAddDangerToast, + }), +})); + +const createProps = () => ({ + text: 'Export as PDF', + dashboardTitle: 'Test Dashboard', + logEvent: jest.fn(), +}); + +const renderComponent = () => { + render( + + + , + { useRedux: true }, + ); +}; + +test('Should call download pdf on click', async () => { + renderComponent(); + await waitFor(() => { + expect(downloadAsPdf).toHaveBeenCalledTimes(0); + expect(mockAddDangerToast).toHaveBeenCalledTimes(0); + }); + + userEvent.click(screen.getByRole('button', { name: 'Export as PDF' })); + + await waitFor(() => { + expect(downloadAsPdf).toHaveBeenCalledTimes(1); + expect(mockAddDangerToast).toHaveBeenCalledTimes(0); + }); +}); + +test('Component is rendered with role="button"', async () => { + renderComponent(); + const button = screen.getByRole('button', { name: 'Export as PDF' }); + expect(button).toBeInTheDocument(); +}); diff --git a/superset-frontend/src/dashboard/components/menu/DownloadMenuItems/DownloadAsPdf.tsx b/superset-frontend/src/dashboard/components/menu/DownloadMenuItems/DownloadAsPdf.tsx new file mode 100644 index 0000000000000..a07a2e232c6dc --- /dev/null +++ b/superset-frontend/src/dashboard/components/menu/DownloadMenuItems/DownloadAsPdf.tsx @@ -0,0 +1,55 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { SyntheticEvent } from 'react'; +import { logging, t } from '@superset-ui/core'; +import { Menu } from 'src/components/Menu'; +import downloadAsPdf from 'src/utils/downloadAsPdf'; +import { LOG_ACTIONS_DASHBOARD_DOWNLOAD_AS_PDF } from 'src/logger/LogUtils'; +import { useToasts } from 'src/components/MessageToasts/withToasts'; + +export default function DownloadAsPdf({ + text, + logEvent, + dashboardTitle, + ...rest +}: { + text: string; + dashboardTitle: string; + logEvent?: Function; +}) { + const SCREENSHOT_NODE_SELECTOR = '.dashboard'; + const { addDangerToast } = useToasts(); + const onDownloadPdf = async (e: SyntheticEvent) => { + try { + downloadAsPdf(SCREENSHOT_NODE_SELECTOR, dashboardTitle, true)(e); + } catch (error) { + logging.error(error); + addDangerToast(t('Sorry, something went wrong. Try again later.')); + } + logEvent?.(LOG_ACTIONS_DASHBOARD_DOWNLOAD_AS_PDF); + }; + + return ( + +
+ {text} +
+
+ ); +} diff --git a/superset-frontend/src/dashboard/components/menu/DownloadMenuItems/DownloadScreenshot.test.tsx b/superset-frontend/src/dashboard/components/menu/DownloadMenuItems/DownloadScreenshot.test.tsx index e1851e6199db3..9c8922f6211f0 100644 --- a/superset-frontend/src/dashboard/components/menu/DownloadMenuItems/DownloadScreenshot.test.tsx +++ b/superset-frontend/src/dashboard/components/menu/DownloadMenuItems/DownloadScreenshot.test.tsx @@ -130,6 +130,9 @@ describe('DownloadScreenshot component', () => { await waitFor(() => { expect(mockAddInfoToast).toHaveBeenCalledWith( 'The screenshot is being generated. Please, do not leave the page.', + { + noDuplicate: true, + }, ); }); }); @@ -202,7 +205,7 @@ describe('DownloadScreenshot component', () => { // Wait for the successful image retrieval message await waitFor(() => { expect(mockAddSuccessToast).toHaveBeenCalledWith( - 'The screenshot is now being downloaded.', + 'The screenshot has been downloaded.', ); }); }); diff --git a/superset-frontend/src/dashboard/components/menu/DownloadMenuItems/DownloadScreenshot.tsx b/superset-frontend/src/dashboard/components/menu/DownloadMenuItems/DownloadScreenshot.tsx index 85f3e1d2c4962..17ec6ee8d8499 100644 --- a/superset-frontend/src/dashboard/components/menu/DownloadMenuItems/DownloadScreenshot.tsx +++ b/superset-frontend/src/dashboard/components/menu/DownloadMenuItems/DownloadScreenshot.tsx @@ -33,6 +33,7 @@ import { useSelector } from 'react-redux'; import { useToasts } from 'src/components/MessageToasts/withToasts'; import { last } from 'lodash'; import { getDashboardUrlParams } from 'src/utils/urlUtils'; +import { useCallback, useEffect, useRef } from 'react'; import { DownloadScreenshotFormat } from './types'; const RETRY_INTERVAL = 3000; @@ -53,21 +54,66 @@ export default function DownloadScreenshot({ const activeTabs = useSelector( (state: RootState) => state.dashboardState.activeTabs || undefined, ); - const anchor = useSelector( (state: RootState) => last(state.dashboardState.directPathToChild) || undefined, ); - const dataMask = useSelector( (state: RootState) => state.dataMask || undefined, ); - const { addDangerToast, addSuccessToast, addInfoToast } = useToasts(); + const currentIntervalIds = useRef([]); + + const printLoadingToast = () => + addInfoToast( + t('The screenshot is being generated. Please, do not leave the page.'), + { + noDuplicate: true, + }, + ); + + const printFailureToast = useCallback( + () => + addDangerToast( + t('The screenshot could not be downloaded. Please, try again later.'), + ), + [addDangerToast], + ); + + const printSuccessToast = useCallback( + () => addSuccessToast(t('The screenshot has been downloaded.')), + [addSuccessToast], + ); + + const stopIntervals = useCallback( + (message?: 'success' | 'failure') => { + currentIntervalIds.current.forEach(clearInterval); + + if (message === 'failure') { + printFailureToast(); + } + if (message === 'success') { + printSuccessToast(); + } + }, + [printFailureToast, printSuccessToast], + ); const onDownloadScreenshot = () => { let retries = 0; + const toastIntervalId = setInterval( + () => printLoadingToast(), + RETRY_INTERVAL, + ); + + currentIntervalIds.current = [ + ...(currentIntervalIds.current || []), + toastIntervalId, + ]; + + printLoadingToast(); + // this function checks if the image is ready const checkImageReady = (cacheKey: string) => SupersetClient.get({ @@ -85,6 +131,7 @@ export default function DownloadScreenshot({ a.click(); document.body.removeChild(a); window.URL.revokeObjectURL(url); + stopIntervals('success'); }) .catch(err => { if ((err as SupersetApiError).status === 404) { @@ -92,34 +139,15 @@ export default function DownloadScreenshot({ } }); - // this is the functions that handles the retries const fetchImageWithRetry = (cacheKey: string) => { - checkImageReady(cacheKey) - .then(() => { - addSuccessToast(t('The screenshot is now being downloaded.')); - }) - .catch(error => { - // we check how many retries have been made - if (retries < MAX_RETRIES) { - retries += 1; - addInfoToast( - t( - 'The screenshot is being generated. Please, do not leave the page.', - ), - { - noDuplicate: true, - }, - ); - setTimeout(() => fetchImageWithRetry(cacheKey), RETRY_INTERVAL); - } else { - addDangerToast( - t( - 'The screenshot could not be downloaded. Please, try again later.', - ), - ); - logging.error(error); - } - }); + if (retries >= MAX_RETRIES) { + stopIntervals('failure'); + logging.error('Max retries reached'); + return; + } + checkImageReady(cacheKey).catch(() => { + retries += 1; + }); }; SupersetClient.post({ @@ -136,18 +164,15 @@ export default function DownloadScreenshot({ if (!cacheKey) { throw new Error('No image URL in response'); } - addInfoToast( - t( - 'The screenshot is being generated. Please, do not leave the page.', - ), - ); + const retryIntervalId = setInterval(() => { + fetchImageWithRetry(cacheKey); + }, RETRY_INTERVAL); + currentIntervalIds.current.push(retryIntervalId); fetchImageWithRetry(cacheKey); }) .catch(error => { logging.error(error); - addDangerToast( - t('The screenshot could not be downloaded. Please, try again later.'), - ); + stopIntervals('failure'); }) .finally(() => { logEvent?.( @@ -158,6 +183,16 @@ export default function DownloadScreenshot({ }); }; + useEffect( + () => () => { + if (currentIntervalIds.current.length > 0) { + stopIntervals(); + } + currentIntervalIds.current = []; + }, + [stopIntervals], + ); + return (
diff --git a/superset-frontend/src/dashboard/components/menu/DownloadMenuItems/index.tsx b/superset-frontend/src/dashboard/components/menu/DownloadMenuItems/index.tsx index e0ec06d9b24eb..875537fb8e13b 100644 --- a/superset-frontend/src/dashboard/components/menu/DownloadMenuItems/index.tsx +++ b/superset-frontend/src/dashboard/components/menu/DownloadMenuItems/index.tsx @@ -17,8 +17,11 @@ * under the License. */ import { Menu } from 'src/components/Menu'; +import { FeatureFlag, isFeatureEnabled } from '@superset-ui/core'; import DownloadScreenshot from './DownloadScreenshot'; import { DownloadScreenshotFormat } from './types'; +import DownloadAsPdf from './DownloadAsPdf'; +import DownloadAsImage from './DownloadAsImage'; export interface DownloadMenuItemProps { pdfMenuItemTitle: string; @@ -34,25 +37,48 @@ const DownloadMenuItems = (props: DownloadMenuItemProps) => { imageMenuItemTitle, logEvent, dashboardId, + dashboardTitle, ...rest } = props; + const isWebDriverScreenshotEnabled = + isFeatureEnabled(FeatureFlag.EnableDashboardScreenshotEndpoints) && + isFeatureEnabled(FeatureFlag.EnableDashboardDownloadWebDriverScreenshot); return ( - - + {isWebDriverScreenshotEnabled ? ( + <> + + + + ) : ( + <> + + + + )} ); }; diff --git a/superset-frontend/src/types/dom-to-pdf.d.ts b/superset-frontend/src/types/dom-to-pdf.d.ts new file mode 100644 index 0000000000000..061e80d96cede --- /dev/null +++ b/superset-frontend/src/types/dom-to-pdf.d.ts @@ -0,0 +1,36 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +declare module 'dom-to-pdf' { + interface Image { + type: string; + quality: number; + } + + interface Options { + margin: number; + filename: string; + image: Image; + html2canvas: object; + excludeClassNames?: string[]; + } + + function domToPdf(elementToPrint: Element, options?: Options): Promise; + + export default domToPdf; +} diff --git a/superset-frontend/src/utils/downloadAsPdf.ts b/superset-frontend/src/utils/downloadAsPdf.ts new file mode 100644 index 0000000000000..bb769d1eb117f --- /dev/null +++ b/superset-frontend/src/utils/downloadAsPdf.ts @@ -0,0 +1,74 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { SyntheticEvent } from 'react'; +import domToPdf from 'dom-to-pdf'; +import { kebabCase } from 'lodash'; +import { logging, t } from '@superset-ui/core'; +import { addWarningToast } from 'src/components/MessageToasts/actions'; + +/** + * generate a consistent file stem from a description and date + * + * @param description title or description of content of file + * @param date date when file was generated + */ +const generateFileStem = (description: string, date = new Date()) => + `${kebabCase(description)}-${date.toISOString().replace(/[: ]/g, '-')}`; + +/** + * Create an event handler for turning an element into an image + * + * @param selector css selector of the parent element which should be turned into image + * @param description name or a short description of what is being printed. + * Value will be normalized, and a date as well as a file extension will be added. + * @param isExactSelector if false, searches for the closest ancestor that matches selector. + * @returns event handler + */ +export default function downloadAsPdf( + selector: string, + description: string, + isExactSelector = false, +) { + return (event: SyntheticEvent) => { + const elementToPrint = isExactSelector + ? document.querySelector(selector) + : event.currentTarget.closest(selector); + + if (!elementToPrint) { + return addWarningToast( + t('PDF download failed, please refresh and try again.'), + ); + } + + const options = { + margin: 10, + filename: `${generateFileStem(description)}.pdf`, + image: { type: 'jpeg', quality: 1 }, + html2canvas: { scale: 2 }, + excludeClassNames: ['header-controls'], + }; + return domToPdf(elementToPrint, options) + .then(() => { + // nothing to be done + }) + .catch((e: Error) => { + logging.error('PDF generation failed', e); + }); + }; +} diff --git a/superset/config.py b/superset/config.py index d19e30a5a5282..354e60c57186d 100644 --- a/superset/config.py +++ b/superset/config.py @@ -478,6 +478,14 @@ class D3TimeFormat(TypedDict, total=False): "PRESTO_EXPAND_DATA": False, # Exposes API endpoint to compute thumbnails "THUMBNAILS": False, + # Enable the endpoints to cache and retrieve dashboard screenshots via webdriver. + # Requires configuring Celery and a cache using THUMBNAIL_CACHE_CONFIG. + "ENABLE_DASHBOARD_SCREENSHOT_ENDPOINTS": False, + # Generate screenshots (PDF or JPG) of dashboards using the web driver. + # When disabled, screenshots are generated on the fly by the browser. + # This feature flag is used by the download feature in the dashboard view. + # It is dependent on ENABLE_DASHBOARD_SCREENSHOT_ENDPOINT being enabled. + "ENABLE_DASHBOARD_DOWNLOAD_WEBDRIVER_SCREENSHOT": False, "SHARE_QUERIES_VIA_KV_STORE": False, "TAGGING_SYSTEM": False, "SQLLAB_BACKEND_PERSISTENCE": True, diff --git a/superset/dashboards/api.py b/superset/dashboards/api.py index 733cc555a4314..a752091cc18e6 100644 --- a/superset/dashboards/api.py +++ b/superset/dashboards/api.py @@ -156,12 +156,18 @@ def wraps(self: BaseSupersetModelRestApi, id_or_slug: str) -> Response: class DashboardRestApi(BaseSupersetModelRestApi): datamodel = SQLAInterface(Dashboard) - @before_request(only=["thumbnail"]) + @before_request(only=["thumbnail", "cache_dashboard_screenshot", "screenshot"]) def ensure_thumbnails_enabled(self) -> Optional[Response]: if not is_feature_enabled("THUMBNAILS"): return self.response_404() return None + @before_request(only=["cache_dashboard_screenshot", "screenshot"]) + def ensure_screenshots_enabled(self) -> Optional[Response]: + if not is_feature_enabled("ENABLE_DASHBOARD_SCREENSHOT_ENDPOINTS"): + return self.response_404() + return None + include_route_methods = RouteMethod.REST_MODEL_VIEW_CRUD_SET | { RouteMethod.EXPORT, RouteMethod.IMPORT, @@ -1133,7 +1139,7 @@ def trigger_celery() -> WerkzeugResponse: dashboard_id=dashboard.id, dashboard_url=dashboard_url, cache_key=cache_key, - force=True, + force=False, thumb_size=thumb_size, window_size=window_size, ) diff --git a/tests/integration_tests/dashboards/api_tests.py b/tests/integration_tests/dashboards/api_tests.py index c3bbf97536f89..e02b5a116a39a 100644 --- a/tests/integration_tests/dashboards/api_tests.py +++ b/tests/integration_tests/dashboards/api_tests.py @@ -3025,7 +3025,9 @@ def _get_screenshot(self, dashboard_id, cache_key, download_format): return self.client.get(uri) @pytest.mark.usefixtures("create_dashboard_with_tag") - def test_cache_dashboard_screenshot_success(self): + @patch("superset.dashboards.api.is_feature_enabled") + def test_cache_dashboard_screenshot_success(self, is_feature_enabled): + is_feature_enabled.return_value = True self.login(ADMIN_USERNAME) dashboard = ( db.session.query(Dashboard) @@ -3036,7 +3038,9 @@ def test_cache_dashboard_screenshot_success(self): assert response.status_code == 202 @pytest.mark.usefixtures("create_dashboard_with_tag") - def test_cache_dashboard_screenshot_dashboard_validation(self): + @patch("superset.dashboards.api.is_feature_enabled") + def test_cache_dashboard_screenshot_dashboard_validation(self, is_feature_enabled): + is_feature_enabled.return_value = True self.login(ADMIN_USERNAME) dashboard = ( db.session.query(Dashboard) @@ -3052,7 +3056,9 @@ def test_cache_dashboard_screenshot_dashboard_validation(self): response = self._cache_screenshot(dashboard.id, invalid_payload) assert response.status_code == 400 - def test_cache_dashboard_screenshot_dashboard_not_found(self): + @patch("superset.dashboards.api.is_feature_enabled") + def test_cache_dashboard_screenshot_dashboard_not_found(self, is_feature_enabled): + is_feature_enabled.return_value = True self.login(ADMIN_USERNAME) non_existent_id = 999 response = self._cache_screenshot(non_existent_id) @@ -3061,10 +3067,14 @@ def test_cache_dashboard_screenshot_dashboard_not_found(self): @pytest.mark.usefixtures("create_dashboard_with_tag") @patch("superset.dashboards.api.cache_dashboard_screenshot") @patch("superset.dashboards.api.DashboardScreenshot.get_from_cache_key") - def test_screenshot_success_png(self, mock_get_cache, mock_cache_task): + @patch("superset.dashboards.api.is_feature_enabled") + def test_screenshot_success_png( + self, is_feature_enabled, mock_get_cache, mock_cache_task + ): """ Validate screenshot returns png """ + is_feature_enabled.return_value = True self.login(ADMIN_USERNAME) mock_cache_task.return_value = None mock_get_cache.return_value = BytesIO(b"fake image data") @@ -3087,12 +3097,14 @@ def test_screenshot_success_png(self, mock_get_cache, mock_cache_task): @patch("superset.dashboards.api.cache_dashboard_screenshot") @patch("superset.dashboards.api.build_pdf_from_screenshots") @patch("superset.dashboards.api.DashboardScreenshot.get_from_cache_key") + @patch("superset.dashboards.api.is_feature_enabled") def test_screenshot_success_pdf( - self, mock_get_from_cache, mock_build_pdf, mock_cache_task + self, is_feature_enabled, mock_get_from_cache, mock_build_pdf, mock_cache_task ): """ Validate screenshot can return pdf. """ + is_feature_enabled.return_value = True self.login(ADMIN_USERNAME) mock_cache_task.return_value = None mock_get_from_cache.return_value = BytesIO(b"fake image data") @@ -3115,7 +3127,11 @@ def test_screenshot_success_pdf( @pytest.mark.usefixtures("create_dashboard_with_tag") @patch("superset.dashboards.api.cache_dashboard_screenshot") @patch("superset.dashboards.api.DashboardScreenshot.get_from_cache_key") - def test_screenshot_not_in_cache(self, mock_get_cache, mock_cache_task): + @patch("superset.dashboards.api.is_feature_enabled") + def test_screenshot_not_in_cache( + self, is_feature_enabled, mock_get_cache, mock_cache_task + ): + is_feature_enabled.return_value = True self.login(ADMIN_USERNAME) mock_cache_task.return_value = None mock_get_cache.return_value = None @@ -3132,7 +3148,9 @@ def test_screenshot_not_in_cache(self, mock_get_cache, mock_cache_task): response = self._get_screenshot(dashboard.id, cache_key, "pdf") assert response.status_code == 404 - def test_screenshot_dashboard_not_found(self): + @patch("superset.dashboards.api.is_feature_enabled") + def test_screenshot_dashboard_not_found(self, is_feature_enabled): + is_feature_enabled.return_value = True self.login(ADMIN_USERNAME) non_existent_id = 999 response = self._get_screenshot(non_existent_id, "some_cache_key", "png") @@ -3141,7 +3159,11 @@ def test_screenshot_dashboard_not_found(self): @pytest.mark.usefixtures("create_dashboard_with_tag") @patch("superset.dashboards.api.cache_dashboard_screenshot") @patch("superset.dashboards.api.DashboardScreenshot.get_from_cache_key") - def test_screenshot_invalid_download_format(self, mock_get_cache, mock_cache_task): + @patch("superset.dashboards.api.is_feature_enabled") + def test_screenshot_invalid_download_format( + self, is_feature_enabled, mock_get_cache, mock_cache_task + ): + is_feature_enabled.return_value = True self.login(ADMIN_USERNAME) mock_cache_task.return_value = None mock_get_cache.return_value = BytesIO(b"fake png data") @@ -3158,3 +3180,20 @@ def test_screenshot_invalid_download_format(self, mock_get_cache, mock_cache_tas response = self._get_screenshot(dashboard.id, cache_key, "invalid") assert response.status_code == 404 + + @pytest.mark.usefixtures("create_dashboard_with_tag") + @patch("superset.dashboards.api.is_feature_enabled") + def test_cache_dashboard_screenshot_feature_disabled(self, is_feature_enabled): + is_feature_enabled.return_value = False + self.login(ADMIN_USERNAME) + + dashboard = ( + db.session.query(Dashboard) + .filter(Dashboard.dashboard_title == "dash with tag") + .first() + ) + + assert dashboard is not None + + response = self._cache_screenshot(dashboard.id) + assert response.status_code == 404 From 402c29c2bc1857812cc4330a604d2f0774200f14 Mon Sep 17 00:00:00 2001 From: Beto Dealmeida Date: Fri, 1 Nov 2024 07:11:01 -0400 Subject: [PATCH 028/307] fix: catalog migration w/o connection (#30773) --- superset/migrations/shared/catalogs.py | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/superset/migrations/shared/catalogs.py b/superset/migrations/shared/catalogs.py index b75214291b0d9..3f14598eb6e82 100644 --- a/superset/migrations/shared/catalogs.py +++ b/superset/migrations/shared/catalogs.py @@ -381,7 +381,17 @@ def upgrade_catalog_perms(engines: set[str] | None = None) -> None: # analytical DB. If we can't connect to the analytical DB during the migration # we should stop it, since we need the default catalog in order to update # existing models. - if default_catalog := database.get_default_catalog(): + try: + default_catalog = database.get_default_catalog() + except GenericDBException as ex: + logger.warning( + "Error fetching default catalog for database %s: %s", + database.database_name, + ex, + ) + continue + + if default_catalog: upgrade_database_catalogs(database, default_catalog, session) session.flush() @@ -558,7 +568,17 @@ def downgrade_catalog_perms(engines: set[str] | None = None) -> None: ) or not db_engine_spec.supports_catalog: continue - if default_catalog := database.get_default_catalog(): + try: + default_catalog = database.get_default_catalog() + except GenericDBException as ex: + logger.warning( + "Error fetching default catalog for database %s: %s", + database.database_name, + ex, + ) + continue + + if default_catalog: downgrade_database_catalogs(database, default_catalog, session) session.flush() From f19c4280c02a30930bce92fdf2ef59c51c27ea50 Mon Sep 17 00:00:00 2001 From: Daniel Vaz Gaspar Date: Fri, 1 Nov 2024 17:22:34 +0000 Subject: [PATCH 029/307] chore: bump werkzeug to address vulnerability (#30729) --- requirements/base.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements/base.txt b/requirements/base.txt index db5814bcd2892..f4f7a441d57d4 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -385,7 +385,7 @@ vine==5.1.0 # kombu wcwidth==0.2.13 # via prompt-toolkit -werkzeug==3.0.3 +werkzeug==3.0.6 # via # -r requirements/base.in # flask From fa9d2cefcc50d5d3e6ea77c8ec180ed184e0ac7d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Nov 2024 10:27:44 -0700 Subject: [PATCH 030/307] build(deps): bump JustinBeckwith/linkinator-action from 1.10.4 to 1.11.0 (#30802) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/superset-docs-verify.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/superset-docs-verify.yml b/.github/workflows/superset-docs-verify.yml index 3fe8662632061..4892936d52808 100644 --- a/.github/workflows/superset-docs-verify.yml +++ b/.github/workflows/superset-docs-verify.yml @@ -20,7 +20,7 @@ jobs: continue-on-error: true # This will make the job advisory (non-blocking, no red X) steps: - uses: actions/checkout@v4 - - uses: JustinBeckwith/linkinator-action@v1.10.4 + - uses: JustinBeckwith/linkinator-action@v1.11.0 with: paths: "**/*.md, **/*.mdx" linksToSkip: >- From 5d42dfb1e6c2fde554857c76e842d8120192a2f1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Nov 2024 10:37:19 -0700 Subject: [PATCH 031/307] build(deps-dev): bump eslint-import-resolver-typescript from 3.6.1 to 3.6.3 in /superset-frontend (#30805) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- superset-frontend/package-lock.json | 119 ++++++++++++++++++++++------ superset-frontend/package.json | 2 +- 2 files changed, 97 insertions(+), 24 deletions(-) diff --git a/superset-frontend/package-lock.json b/superset-frontend/package-lock.json index a859168b7c846..8f1be68209aff 100644 --- a/superset-frontend/package-lock.json +++ b/superset-frontend/package-lock.json @@ -230,7 +230,7 @@ "eslint": "^8.56.0", "eslint-config-airbnb": "^19.0.4", "eslint-config-prettier": "^7.2.0", - "eslint-import-resolver-typescript": "^3.6.1", + "eslint-import-resolver-typescript": "^3.6.3", "eslint-plugin-cypress": "^3.5.0", "eslint-plugin-file-progress": "^1.5.0", "eslint-plugin-import": "^2.24.2", @@ -7667,6 +7667,15 @@ "node": ">= 8" } }, + "node_modules/@nolyfill/is-core-module": { + "version": "1.0.39", + "resolved": "https://registry.npmjs.org/@nolyfill/is-core-module/-/is-core-module-1.0.39.tgz", + "integrity": "sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==", + "dev": true, + "engines": { + "node": ">=12.4.0" + } + }, "node_modules/@npmcli/agent": { "version": "2.2.2", "devOptional": true, @@ -24107,16 +24116,18 @@ "license": "MIT" }, "node_modules/eslint-import-resolver-typescript": { - "version": "3.6.1", + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.6.3.tgz", + "integrity": "sha512-ud9aw4szY9cCT1EWWdGv1L1XR6hh2PaRWif0j2QjQ0pgTY/69iw+W0Z4qZv5wHahOl8isEr+k/JnyAqNQkLkIA==", "dev": true, - "license": "ISC", "dependencies": { - "debug": "^4.3.4", - "enhanced-resolve": "^5.12.0", - "eslint-module-utils": "^2.7.4", - "fast-glob": "^3.3.1", - "get-tsconfig": "^4.5.0", - "is-core-module": "^2.11.0", + "@nolyfill/is-core-module": "1.0.39", + "debug": "^4.3.5", + "enhanced-resolve": "^5.15.0", + "eslint-module-utils": "^2.8.1", + "fast-glob": "^3.3.2", + "get-tsconfig": "^4.7.5", + "is-bun-module": "^1.0.2", "is-glob": "^4.0.3" }, "engines": { @@ -24127,7 +24138,16 @@ }, "peerDependencies": { "eslint": "*", - "eslint-plugin-import": "*" + "eslint-plugin-import": "*", + "eslint-plugin-import-x": "*" + }, + "peerDependenciesMeta": { + "eslint-plugin-import": { + "optional": true + }, + "eslint-plugin-import-x": { + "optional": true + } } }, "node_modules/eslint-import-resolver-typescript/node_modules/debug": { @@ -24172,9 +24192,10 @@ } }, "node_modules/eslint-module-utils": { - "version": "2.8.0", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.0.tgz", + "integrity": "sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==", "dev": true, - "license": "MIT", "dependencies": { "debug": "^3.2.7" }, @@ -27182,9 +27203,10 @@ } }, "node_modules/get-tsconfig": { - "version": "4.7.2", + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.8.1.tgz", + "integrity": "sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==", "dev": true, - "license": "MIT", "dependencies": { "resolve-pkg-maps": "^1.0.0" }, @@ -29598,6 +29620,27 @@ "dev": true, "license": "MIT" }, + "node_modules/is-bun-module": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-bun-module/-/is-bun-module-1.2.1.tgz", + "integrity": "sha512-AmidtEM6D6NmUiLOvvU7+IePxjEjOzra2h0pSrsfSAcXwl/83zLLXDByafUJy9k/rKK0pvXMLdwKwGHlX2Ke6Q==", + "dev": true, + "dependencies": { + "semver": "^7.6.3" + } + }, + "node_modules/is-bun-module/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/is-callable": { "version": "1.2.7", "license": "MIT", @@ -63563,6 +63606,12 @@ "fastq": "^1.6.0" } }, + "@nolyfill/is-core-module": { + "version": "1.0.39", + "resolved": "https://registry.npmjs.org/@nolyfill/is-core-module/-/is-core-module-1.0.39.tgz", + "integrity": "sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==", + "dev": true + }, "@npmcli/agent": { "version": "2.2.2", "devOptional": true, @@ -77110,15 +77159,18 @@ } }, "eslint-import-resolver-typescript": { - "version": "3.6.1", + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.6.3.tgz", + "integrity": "sha512-ud9aw4szY9cCT1EWWdGv1L1XR6hh2PaRWif0j2QjQ0pgTY/69iw+W0Z4qZv5wHahOl8isEr+k/JnyAqNQkLkIA==", "dev": true, "requires": { - "debug": "^4.3.4", - "enhanced-resolve": "^5.12.0", - "eslint-module-utils": "^2.7.4", - "fast-glob": "^3.3.1", - "get-tsconfig": "^4.5.0", - "is-core-module": "^2.11.0", + "@nolyfill/is-core-module": "1.0.39", + "debug": "^4.3.5", + "enhanced-resolve": "^5.15.0", + "eslint-module-utils": "^2.8.1", + "fast-glob": "^3.3.2", + "get-tsconfig": "^4.7.5", + "is-bun-module": "^1.0.2", "is-glob": "^4.0.3" }, "dependencies": { @@ -77148,7 +77200,9 @@ } }, "eslint-module-utils": { - "version": "2.8.0", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.0.tgz", + "integrity": "sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==", "dev": true, "requires": { "debug": "^3.2.7" @@ -78976,7 +79030,9 @@ } }, "get-tsconfig": { - "version": "4.7.2", + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.8.1.tgz", + "integrity": "sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==", "dev": true, "requires": { "resolve-pkg-maps": "^1.0.0" @@ -80523,6 +80579,23 @@ "version": "1.1.6", "dev": true }, + "is-bun-module": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-bun-module/-/is-bun-module-1.2.1.tgz", + "integrity": "sha512-AmidtEM6D6NmUiLOvvU7+IePxjEjOzra2h0pSrsfSAcXwl/83zLLXDByafUJy9k/rKK0pvXMLdwKwGHlX2Ke6Q==", + "dev": true, + "requires": { + "semver": "^7.6.3" + }, + "dependencies": { + "semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true + } + } + }, "is-callable": { "version": "1.2.7" }, diff --git a/superset-frontend/package.json b/superset-frontend/package.json index b373eb041bcfb..684e84134e476 100644 --- a/superset-frontend/package.json +++ b/superset-frontend/package.json @@ -296,7 +296,7 @@ "eslint": "^8.56.0", "eslint-config-airbnb": "^19.0.4", "eslint-config-prettier": "^7.2.0", - "eslint-import-resolver-typescript": "^3.6.1", + "eslint-import-resolver-typescript": "^3.6.3", "eslint-plugin-cypress": "^3.5.0", "eslint-plugin-file-progress": "^1.5.0", "eslint-plugin-import": "^2.24.2", From ccc2f66e92d5c2127aa586eaa4be2f7bb9a704e3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Nov 2024 10:37:46 -0700 Subject: [PATCH 032/307] build(deps-dev): bump eslint-plugin-testing-library from 6.2.2 to 6.4.0 in /superset-frontend (#30810) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- superset-frontend/package-lock.json | 17 ++++++++++------- superset-frontend/package.json | 2 +- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/superset-frontend/package-lock.json b/superset-frontend/package-lock.json index 8f1be68209aff..4483fb446558a 100644 --- a/superset-frontend/package-lock.json +++ b/superset-frontend/package-lock.json @@ -244,7 +244,7 @@ "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-prefer-function-component": "^3.3.0", "eslint-plugin-storybook": "^0.8.0", - "eslint-plugin-testing-library": "^6.2.2", + "eslint-plugin-testing-library": "^6.4.0", "eslint-plugin-theme-colors": "file:tools/eslint-plugin-theme-colors", "eslint-plugin-translation-vars": "file:tools/eslint-plugin-translation-vars", "exports-loader": "^5.0.0", @@ -24674,18 +24674,19 @@ } }, "node_modules/eslint-plugin-testing-library": { - "version": "6.2.2", + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-testing-library/-/eslint-plugin-testing-library-6.4.0.tgz", + "integrity": "sha512-yeWF+YgCgvNyPNI9UKnG0FjeE2sk93N/3lsKqcmR8dSfeXJwFT5irnWo7NjLf152HkRzfoFjh3LsBUrhvFz4eA==", "dev": true, - "license": "MIT", "dependencies": { - "@typescript-eslint/utils": "^5.58.0" + "@typescript-eslint/utils": "^5.62.0" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0", "npm": ">=6" }, "peerDependencies": { - "eslint": "^7.5.0 || ^8.0.0" + "eslint": "^7.5.0 || ^8.0.0 || ^9.0.0" } }, "node_modules/eslint-plugin-theme-colors": { @@ -77531,10 +77532,12 @@ } }, "eslint-plugin-testing-library": { - "version": "6.2.2", + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-testing-library/-/eslint-plugin-testing-library-6.4.0.tgz", + "integrity": "sha512-yeWF+YgCgvNyPNI9UKnG0FjeE2sk93N/3lsKqcmR8dSfeXJwFT5irnWo7NjLf152HkRzfoFjh3LsBUrhvFz4eA==", "dev": true, "requires": { - "@typescript-eslint/utils": "^5.58.0" + "@typescript-eslint/utils": "^5.62.0" } }, "eslint-plugin-theme-colors": { diff --git a/superset-frontend/package.json b/superset-frontend/package.json index 684e84134e476..13893986a036e 100644 --- a/superset-frontend/package.json +++ b/superset-frontend/package.json @@ -310,7 +310,7 @@ "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-prefer-function-component": "^3.3.0", "eslint-plugin-storybook": "^0.8.0", - "eslint-plugin-testing-library": "^6.2.2", + "eslint-plugin-testing-library": "^6.4.0", "eslint-plugin-theme-colors": "file:tools/eslint-plugin-theme-colors", "eslint-plugin-translation-vars": "file:tools/eslint-plugin-translation-vars", "exports-loader": "^5.0.0", From b3edbe45cf51026a8167421737b696da7ddf794f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Nov 2024 10:38:20 -0700 Subject: [PATCH 033/307] build(deps): bump ace-builds from 1.35.4 to 1.36.3 in /superset-frontend (#30804) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- superset-frontend/package-lock.json | 11 +++++++---- superset-frontend/package.json | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/superset-frontend/package-lock.json b/superset-frontend/package-lock.json index 4483fb446558a..543a498a0e0d8 100644 --- a/superset-frontend/package-lock.json +++ b/superset-frontend/package-lock.json @@ -59,7 +59,7 @@ "@visx/tooltip": "^3.0.0", "@visx/xychart": "^3.5.1", "abortcontroller-polyfill": "^1.7.5", - "ace-builds": "^1.35.4", + "ace-builds": "^1.36.3", "antd": "4.10.3", "antd-v5": "npm:antd@^5.18.0", "babel-plugin-typescript-to-proptypes": "^2.0.0", @@ -16055,8 +16055,9 @@ } }, "node_modules/ace-builds": { - "version": "1.35.4", - "license": "BSD-3-Clause" + "version": "1.36.3", + "resolved": "https://registry.npmjs.org/ace-builds/-/ace-builds-1.36.3.tgz", + "integrity": "sha512-YcdwV2IIaJSfjkWAR1NEYN5IxBiXefTgwXsJ//UlaFrjXDX5hQpvPFvEePHz2ZBUfvO54RjHeRUQGX8MS5HaMQ==" }, "node_modules/acorn": { "version": "8.11.3", @@ -71643,7 +71644,9 @@ } }, "ace-builds": { - "version": "1.35.4" + "version": "1.36.3", + "resolved": "https://registry.npmjs.org/ace-builds/-/ace-builds-1.36.3.tgz", + "integrity": "sha512-YcdwV2IIaJSfjkWAR1NEYN5IxBiXefTgwXsJ//UlaFrjXDX5hQpvPFvEePHz2ZBUfvO54RjHeRUQGX8MS5HaMQ==" }, "acorn": { "version": "8.11.3" diff --git a/superset-frontend/package.json b/superset-frontend/package.json index 13893986a036e..8d24867399600 100644 --- a/superset-frontend/package.json +++ b/superset-frontend/package.json @@ -125,7 +125,7 @@ "@visx/tooltip": "^3.0.0", "@visx/xychart": "^3.5.1", "abortcontroller-polyfill": "^1.7.5", - "ace-builds": "^1.35.4", + "ace-builds": "^1.36.3", "antd": "4.10.3", "antd-v5": "npm:antd@^5.18.0", "babel-plugin-typescript-to-proptypes": "^2.0.0", From ab95bff7b6ce55ec804a6d6411df7584ab442360 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Nov 2024 10:38:59 -0700 Subject: [PATCH 034/307] build(deps): bump @rjsf/validator-ajv8 from 5.19.4 to 5.22.3 in /superset-frontend (#30811) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- superset-frontend/package-lock.json | 28 ++++++++++++++-------------- superset-frontend/package.json | 2 +- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/superset-frontend/package-lock.json b/superset-frontend/package-lock.json index 543a498a0e0d8..eef1b1443c6f4 100644 --- a/superset-frontend/package-lock.json +++ b/superset-frontend/package-lock.json @@ -23,7 +23,7 @@ "@reduxjs/toolkit": "^1.9.3", "@rjsf/core": "^5.21.1", "@rjsf/utils": "^5.19.3", - "@rjsf/validator-ajv8": "^5.19.3", + "@rjsf/validator-ajv8": "^5.22.3", "@scarf/scarf": "^1.3.0", "@superset-ui/chart-controls": "file:./packages/superset-ui-chart-controls", "@superset-ui/core": "file:./packages/superset-ui-core", @@ -9602,9 +9602,9 @@ } }, "node_modules/@rjsf/utils": { - "version": "5.21.1", - "resolved": "https://registry.npmjs.org/@rjsf/utils/-/utils-5.21.1.tgz", - "integrity": "sha512-KEwEtIswzKE2WTLRxvh5vwMwvNMTHnRSxwaRlz3QKz5/iQr9XGJTWcmArjIN3y0ypfLk+X6qZsboamQBIhTV3w==", + "version": "5.22.3", + "resolved": "https://registry.npmjs.org/@rjsf/utils/-/utils-5.22.3.tgz", + "integrity": "sha512-/aWtYX2ruK3x/bGsePc25UEbSsJvLUAMQO1i306RQ3QQzWn4hbyenBfT4iMxh6Kaly6kmKavBlB7knpooCx4OQ==", "dependencies": { "json-schema-merge-allof": "^0.8.1", "jsonpointer": "^5.0.1", @@ -9625,9 +9625,9 @@ "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==" }, "node_modules/@rjsf/validator-ajv8": { - "version": "5.19.4", - "resolved": "https://registry.npmjs.org/@rjsf/validator-ajv8/-/validator-ajv8-5.19.4.tgz", - "integrity": "sha512-meatFQFif92mlFUcmywbDElWSOUdLg6rIowisNaquktUxTRce2TL9TPd7vgcMdwFI1h9NiFok5q6V8v3XyyLLQ==", + "version": "5.22.3", + "resolved": "https://registry.npmjs.org/@rjsf/validator-ajv8/-/validator-ajv8-5.22.3.tgz", + "integrity": "sha512-fHu+oPOckpSHMwKdPCP/h8TtcOJ4I45RxFR//cN1c+um6OtpE/0t9JkVWAtbQlNJffIrzacnJjH5NpGwssxjrA==", "dependencies": { "ajv": "^8.12.0", "ajv-formats": "^2.1.1", @@ -9638,7 +9638,7 @@ "node": ">=14" }, "peerDependencies": { - "@rjsf/utils": "^5.19.x" + "@rjsf/utils": "^5.22.x" } }, "node_modules/@rjsf/validator-ajv8/node_modules/ajv": { @@ -64845,9 +64845,9 @@ } }, "@rjsf/utils": { - "version": "5.21.1", - "resolved": "https://registry.npmjs.org/@rjsf/utils/-/utils-5.21.1.tgz", - "integrity": "sha512-KEwEtIswzKE2WTLRxvh5vwMwvNMTHnRSxwaRlz3QKz5/iQr9XGJTWcmArjIN3y0ypfLk+X6qZsboamQBIhTV3w==", + "version": "5.22.3", + "resolved": "https://registry.npmjs.org/@rjsf/utils/-/utils-5.22.3.tgz", + "integrity": "sha512-/aWtYX2ruK3x/bGsePc25UEbSsJvLUAMQO1i306RQ3QQzWn4hbyenBfT4iMxh6Kaly6kmKavBlB7knpooCx4OQ==", "requires": { "json-schema-merge-allof": "^0.8.1", "jsonpointer": "^5.0.1", @@ -64864,9 +64864,9 @@ } }, "@rjsf/validator-ajv8": { - "version": "5.19.4", - "resolved": "https://registry.npmjs.org/@rjsf/validator-ajv8/-/validator-ajv8-5.19.4.tgz", - "integrity": "sha512-meatFQFif92mlFUcmywbDElWSOUdLg6rIowisNaquktUxTRce2TL9TPd7vgcMdwFI1h9NiFok5q6V8v3XyyLLQ==", + "version": "5.22.3", + "resolved": "https://registry.npmjs.org/@rjsf/validator-ajv8/-/validator-ajv8-5.22.3.tgz", + "integrity": "sha512-fHu+oPOckpSHMwKdPCP/h8TtcOJ4I45RxFR//cN1c+um6OtpE/0t9JkVWAtbQlNJffIrzacnJjH5NpGwssxjrA==", "requires": { "ajv": "^8.12.0", "ajv-formats": "^2.1.1", diff --git a/superset-frontend/package.json b/superset-frontend/package.json index 8d24867399600..828a25b19d35d 100644 --- a/superset-frontend/package.json +++ b/superset-frontend/package.json @@ -89,7 +89,7 @@ "@reduxjs/toolkit": "^1.9.3", "@rjsf/core": "^5.21.1", "@rjsf/utils": "^5.19.3", - "@rjsf/validator-ajv8": "^5.19.3", + "@rjsf/validator-ajv8": "^5.22.3", "@scarf/scarf": "^1.3.0", "@superset-ui/chart-controls": "file:./packages/superset-ui-chart-controls", "@superset-ui/core": "file:./packages/superset-ui-core", From 3ec3f0a610807a6da4421fd5c0fb815bf3d023f3 Mon Sep 17 00:00:00 2001 From: yousoph Date: Fri, 1 Nov 2024 10:54:50 -0700 Subject: [PATCH 035/307] fix(explore): Update tooltip copy for rendering html in tables and pivot tables (#30682) Co-authored-by: Joe Li --- .../src/plugin/controlPanel.tsx | 18 +++++----- .../plugin-chart-table/src/controlPanel.tsx | 34 ++++++++++--------- 2 files changed, 28 insertions(+), 24 deletions(-) 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 e5dea8c4682a8..cda65f5527815 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 @@ -16,6 +16,13 @@ * specific language governing permissions and limitations * under the License. */ +import { + ControlPanelConfig, + D3_TIME_FORMAT_OPTIONS, + Dataset, + getStandardizedControls, + sharedControls, +} from '@superset-ui/chart-controls'; import { ensureIsArray, isAdhocColumn, @@ -25,13 +32,6 @@ import { t, validateNonEmpty, } from '@superset-ui/core'; -import { - ControlPanelConfig, - D3_TIME_FORMAT_OPTIONS, - sharedControls, - Dataset, - getStandardizedControls, -} from '@superset-ui/chart-controls'; import { MetricsLayoutEnum } from '../types'; const config: ControlPanelConfig = { @@ -436,7 +436,9 @@ const config: ControlPanelConfig = { label: t('Render columns in HTML format'), renderTrigger: true, default: true, - description: t('Render data in HTML format if applicable.'), + description: t( + 'Renders table cells as HTML when applicable. For example, HTML <a> tags will be rendered as hyperlinks.', + ), }, }, ], diff --git a/superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx b/superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx index 0d27c73c48c39..e67bdfcea0c89 100644 --- a/superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx +++ b/superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx @@ -18,32 +18,32 @@ * under the License. */ import { - ensureIsArray, - GenericDataType, - isAdhocColumn, - isPhysicalColumn, - QueryFormColumn, - QueryMode, - SMART_DATE_ID, - t, -} from '@superset-ui/core'; -import { + ColumnMeta, ColumnOption, ControlConfig, ControlPanelConfig, ControlPanelsContainerProps, - ControlStateMapping, - D3_TIME_FORMAT_OPTIONS, - QueryModeLabel, - sharedControls, ControlPanelState, ControlState, + ControlStateMapping, + D3_TIME_FORMAT_OPTIONS, Dataset, - ColumnMeta, defineSavedMetrics, getStandardizedControls, + QueryModeLabel, sections, + sharedControls, } from '@superset-ui/chart-controls'; +import { + ensureIsArray, + GenericDataType, + isAdhocColumn, + isPhysicalColumn, + QueryFormColumn, + QueryMode, + SMART_DATE_ID, + t, +} from '@superset-ui/core'; import { isEmpty } from 'lodash'; import { PAGE_SIZE_OPTIONS } from './consts'; @@ -466,7 +466,9 @@ const config: ControlPanelConfig = { label: t('Render columns in HTML format'), renderTrigger: true, default: true, - description: t('Render data in HTML format if applicable.'), + description: t( + 'Renders table cells as HTML when applicable. For example, HTML <a> tags will be rendered as hyperlinks.', + ), }, }, ], From d466383df26bcfd7bad15fa4ae88ebbbde0aa94a Mon Sep 17 00:00:00 2001 From: Elizabeth Thompson Date: Fri, 1 Nov 2024 15:08:42 -0700 Subject: [PATCH 036/307] fix: warning emits an error (#28524) --- .../utils/pandas_postprocessing/compare.py | 7 +- .../pandas_postprocessing/test_compare.py | 67 +++++++++++++++++++ 2 files changed, 73 insertions(+), 1 deletion(-) diff --git a/superset/utils/pandas_postprocessing/compare.py b/superset/utils/pandas_postprocessing/compare.py index b20682027f4a1..64442280b2af2 100644 --- a/superset/utils/pandas_postprocessing/compare.py +++ b/superset/utils/pandas_postprocessing/compare.py @@ -81,5 +81,10 @@ def compare( # pylint: disable=too-many-arguments df = pd.concat([df, diff_df], axis=1) if drop_original_columns: - df = df.drop(source_columns + compare_columns, axis=1) + level = ( + 0 + if isinstance(df.columns, pd.MultiIndex) and df.columns.nlevels > 1 + else None + ) + df = df.drop(source_columns + compare_columns, axis=1, level=level) return df diff --git a/tests/unit_tests/pandas_postprocessing/test_compare.py b/tests/unit_tests/pandas_postprocessing/test_compare.py index 9da8a31535470..a26aa11d290ea 100644 --- a/tests/unit_tests/pandas_postprocessing/test_compare.py +++ b/tests/unit_tests/pandas_postprocessing/test_compare.py @@ -14,6 +14,9 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. +import io +import sys + import pandas as pd from superset.constants import PandasPostprocessingCompare as PPC @@ -179,6 +182,70 @@ def test_compare_multi_index_column(): ) +def test_compare_multi_index_column_non_lex_sorted(): + index = pd.to_datetime(["2021-01-01", "2021-01-02", "2021-01-03"]) + index.name = "__timestamp" + + iterables = [["m1", "m2"], ["a", "b"], ["x", "y"]] + columns = pd.MultiIndex.from_product(iterables, names=[None, "level1", "level2"]) + + df = pd.DataFrame(index=index, columns=columns, data=1) + + # Define a non-lexicographical column order + # arrange them as m1, m2 instead of m2, m1 + new_columns_order = [ + ("m1", "a", "x"), + ("m1", "a", "y"), + ("m1", "b", "x"), + ("m1", "b", "y"), + ("m2", "a", "x"), + ("m2", "a", "y"), + ("m2", "b", "x"), + ("m2", "b", "y"), + ] + + df.columns = pd.MultiIndex.from_tuples( + new_columns_order, names=["level1", "level2", None] + ) + + # to capture stderr + stderr = sys.stderr + sys.stderr = io.StringIO() + + try: + post_df = pp.compare( + df, + source_columns=["m1"], + compare_columns=["m2"], + compare_type=PPC.DIFF, + drop_original_columns=True, + ) + assert sys.stderr.getvalue() == "" + finally: + sys.stderr = stderr + + flat_df = pp.flatten(post_df) + """ + __timestamp difference__m1__m2, a, x difference__m1__m2, a, y difference__m1__m2, b, x difference__m1__m2, b, y + 0 2021-01-01 0 0 0 0 + 1 2021-01-02 0 0 0 0 + 2 2021-01-03 0 0 0 0 + """ + assert flat_df.equals( + pd.DataFrame( + data={ + "__timestamp": pd.to_datetime( + ["2021-01-01", "2021-01-02", "2021-01-03"] + ), + "difference__m1__m2, a, x": [0, 0, 0], + "difference__m1__m2, a, y": [0, 0, 0], + "difference__m1__m2, b, x": [0, 0, 0], + "difference__m1__m2, b, y": [0, 0, 0], + } + ) + ) + + def test_compare_after_pivot(): pivot_df = pp.pivot( df=multiple_metrics_df, From b02d18a39e3ffb7cee2a6abd97a44393e33dc129 Mon Sep 17 00:00:00 2001 From: Ville Brofeldt <33317356+villebro@users.noreply.github.com> Date: Fri, 1 Nov 2024 15:24:51 -0700 Subject: [PATCH 037/307] fix(plugin-chart-echarts): sort tooltip correctly (#30819) --- .../src/MixedTimeseries/transformProps.ts | 87 ++++++++++--------- .../src/Timeseries/transformProps.ts | 52 ++++++----- .../plugin-chart-echarts/src/utils/series.ts | 19 ++++ .../test/utils/series.test.ts | 27 ++++++ 4 files changed, 122 insertions(+), 63 deletions(-) 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 e12cdfe6f8101..d4d19f9c2f6af 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/transformProps.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/transformProps.ts @@ -62,6 +62,7 @@ import { extractDataTotalValues, extractSeries, extractShowValueIndexes, + extractTooltipKeys, getAxisType, getColtypesMapping, getLegendProps, @@ -584,9 +585,13 @@ export default function transformProps( : params.value[0]; const forecastValue: any[] = richTooltip ? params : [params]; - if (richTooltip && tooltipSortByMetric) { - forecastValue.sort((a, b) => b.data[1] - a.data[1]); - } + const sortedKeys = extractTooltipKeys( + forecastValue, + // horizontal mode is not supported in mixed series chart + 1, + richTooltip, + tooltipSortByMetric, + ); const rows: string[][] = []; const forecastValues = @@ -594,44 +599,46 @@ export default function transformProps( const keys = Object.keys(forecastValues); let focusedRow; - keys.forEach(key => { - const value = forecastValues[key]; - // if there are no dimensions, key is a verbose name of a metric, - // otherwise it is a comma separated string where the first part is metric name - let formatterKey; - if (primarySeries.has(key)) { - formatterKey = - groupby.length === 0 ? inverted[key] : labelMap[key]?.[0]; - } else { - formatterKey = - groupbyB.length === 0 ? inverted[key] : labelMapB[key]?.[0]; - } - const tooltipFormatter = getFormatter( - customFormatters, - formatter, - metrics, - formatterKey, - !!contributionMode, - ); - const tooltipFormatterSecondary = getFormatter( - customFormattersSecondary, - formatterSecondary, - metricsB, - formatterKey, - !!contributionMode, - ); - const row = formatForecastTooltipSeries({ - ...value, - seriesName: key, - formatter: primarySeries.has(key) - ? tooltipFormatter - : tooltipFormatterSecondary, + sortedKeys + .filter(key => keys.includes(key)) + .forEach(key => { + const value = forecastValues[key]; + // if there are no dimensions, key is a verbose name of a metric, + // otherwise it is a comma separated string where the first part is metric name + let formatterKey; + if (primarySeries.has(key)) { + formatterKey = + groupby.length === 0 ? inverted[key] : labelMap[key]?.[0]; + } else { + formatterKey = + groupbyB.length === 0 ? inverted[key] : labelMapB[key]?.[0]; + } + const tooltipFormatter = getFormatter( + customFormatters, + formatter, + metrics, + formatterKey, + !!contributionMode, + ); + const tooltipFormatterSecondary = getFormatter( + customFormattersSecondary, + formatterSecondary, + metricsB, + formatterKey, + !!contributionMode, + ); + const row = formatForecastTooltipSeries({ + ...value, + seriesName: key, + formatter: primarySeries.has(key) + ? tooltipFormatter + : tooltipFormatterSecondary, + }); + rows.push(row); + if (key === focusedSeries) { + focusedRow = rows.length - 1; + } }); - rows.push(row); - if (key === focusedSeries) { - focusedRow = rows.length - 1; - } - }); return tooltipHtml(rows, tooltipFormatter(xValue), focusedRow); }, }, 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 c0da444bfe802..b552ceba5c49e 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/transformProps.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/transformProps.ts @@ -65,6 +65,7 @@ import { extractDataTotalValues, extractSeries, extractShowValueIndexes, + extractTooltipKeys, getAxisType, getColtypesMapping, getLegendProps, @@ -251,7 +252,7 @@ export default function transformProps( legendState, }); const seriesContexts = extractForecastSeriesContexts( - Object.values(rawSeries).map(series => series.name as string), + rawSeries.map(series => series.name as string), ); const isAreaExpand = stack === StackControlsValue.Expand; const xAxisDataType = dataTypes?.[xAxisLabel] ?? dataTypes?.[xAxisOrig]; @@ -543,11 +544,12 @@ export default function transformProps( ? params[0].value[xIndex] : params.value[xIndex]; const forecastValue: any[] = richTooltip ? params : [params]; - - if (richTooltip && tooltipSortByMetric) { - forecastValue.sort((a, b) => b.data[yIndex] - a.data[yIndex]); - } - + const sortedKeys = extractTooltipKeys( + forecastValue, + yIndex, + richTooltip, + tooltipSortByMetric, + ); const forecastValues: Record = extractForecastValuesFromTooltipParams(forecastValue, isHorizontal); @@ -570,24 +572,28 @@ export default function transformProps( const showPercentage = showTotal && !forcePercentFormatter; const keys = Object.keys(forecastValues); let focusedRow; - keys.forEach(key => { - const value = forecastValues[key]; - if (value.observation === 0 && stack) { - return; - } - const row = formatForecastTooltipSeries({ - ...value, - seriesName: key, - formatter, + sortedKeys + .filter(key => keys.includes(key)) + .forEach(key => { + const value = forecastValues[key]; + if (value.observation === 0 && stack) { + return; + } + const row = formatForecastTooltipSeries({ + ...value, + seriesName: key, + formatter, + }); + if (showPercentage && value.observation !== undefined) { + row.push( + percentFormatter.format(value.observation / (total || 1)), + ); + } + rows.push(row); + if (key === focusedSeries) { + focusedRow = rows.length - 1; + } }); - if (showPercentage && value.observation !== undefined) { - row.push(percentFormatter.format(value.observation / (total || 1))); - } - rows.push(row); - if (key === focusedSeries) { - focusedRow = rows.length - 1; - } - }); if (stack) { rows.reverse(); if (focusedRow !== undefined) { diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/utils/series.ts b/superset-frontend/plugins/plugin-chart-echarts/src/utils/series.ts index 13d36b71418ba..0aa0ae988ee98 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/utils/series.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/utils/series.ts @@ -642,3 +642,22 @@ export function getTimeCompareStackId( }) || defaultId ); } + +const TOOLTIP_SERIES_KEY = 'seriesId'; +export function extractTooltipKeys( + forecastValue: any[], + yIndex: number, + richTooltip?: boolean, + tooltipSortByMetric?: boolean, +): string[] { + if (richTooltip && tooltipSortByMetric) { + return forecastValue + .slice() + .sort((a, b) => b.data[yIndex] - a.data[yIndex]) + .map(value => value[TOOLTIP_SERIES_KEY]); + } + if (richTooltip) { + return forecastValue.map(s => s[TOOLTIP_SERIES_KEY]); + } + return [forecastValue[0][TOOLTIP_SERIES_KEY]]; +} diff --git a/superset-frontend/plugins/plugin-chart-echarts/test/utils/series.test.ts b/superset-frontend/plugins/plugin-chart-echarts/test/utils/series.test.ts index efc0ac745aedf..7054f6019ad30 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/test/utils/series.test.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/test/utils/series.test.ts @@ -31,6 +31,7 @@ import { extractGroupbyLabel, extractSeries, extractShowValueIndexes, + extractTooltipKeys, formatSeriesName, getAxisType, getChartPadding, @@ -1072,3 +1073,29 @@ describe('getTimeCompareStackId', () => { expect(result).toEqual('123'); }); }); + +const forecastValue = [ + { + data: [0, 1], + seriesId: 'foo', + }, + { + data: [0, 2], + seriesId: 'bar', + }, +]; + +test('extractTooltipKeys with rich tooltip', () => { + const result = extractTooltipKeys(forecastValue, 1, true, false); + expect(result).toEqual(['foo', 'bar']); +}); + +test('extractTooltipKeys with rich tooltip and sorting by metrics', () => { + const result = extractTooltipKeys(forecastValue, 1, true, true); + expect(result).toEqual(['bar', 'foo']); +}); + +test('extractTooltipKeys with non-rich tooltip', () => { + const result = extractTooltipKeys(forecastValue, 1, false, false); + expect(result).toEqual(['foo']); +}); From 29e3f4bcc4842ff19b6e6e420a09696b79341af0 Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Mon, 4 Nov 2024 12:39:09 +1100 Subject: [PATCH 038/307] feat: allow exporting all tabs to a single PDF in report (#30694) --- .../src/features/alerts/AlertReportModal.tsx | 25 +- superset/commands/report/create.py | 13 +- superset/commands/report/execute.py | 108 ++- .../fixtures/dashboard_with_tabs.py | 651 ++++++++++++++++++ tests/integration_tests/reports/api_tests.py | 79 +++ .../commands/report/execute_test.py | 145 ++++ 6 files changed, 995 insertions(+), 26 deletions(-) create mode 100644 tests/integration_tests/fixtures/dashboard_with_tabs.py diff --git a/superset-frontend/src/features/alerts/AlertReportModal.tsx b/superset-frontend/src/features/alerts/AlertReportModal.tsx index e136675e35a49..665d1af8629e2 100644 --- a/superset-frontend/src/features/alerts/AlertReportModal.tsx +++ b/superset-frontend/src/features/alerts/AlertReportModal.tsx @@ -823,10 +823,31 @@ const AlertReportModal: FunctionComponent = ({ }) .then(response => { const { tab_tree: tabTree, all_tabs: allTabs } = response.json.result; + tabTree.push({ + title: 'All Tabs', + // select tree only works with string value + value: JSON.stringify(Object.keys(allTabs)), + }); setTabOptions(tabTree); + const anchor = currentAlert?.extra?.dashboard?.anchor; - if (anchor && !(anchor in allTabs)) { - updateAnchorState(undefined); + if (anchor) { + try { + const parsedAnchor = JSON.parse(anchor); + if (Array.isArray(parsedAnchor)) { + // Check if all elements in parsedAnchor list are in allTabs + const isValidSubset = parsedAnchor.every(tab => tab in allTabs); + if (!isValidSubset) { + updateAnchorState(undefined); + } + } else { + throw new Error('Parsed value is not an array'); + } + } catch (error) { + if (!(anchor in allTabs)) { + updateAnchorState(undefined); + } + } } }) .catch(() => { diff --git a/superset/commands/report/create.py b/superset/commands/report/create.py index 2a67f640022d2..9191e5a17b966 100644 --- a/superset/commands/report/create.py +++ b/superset/commands/report/create.py @@ -143,10 +143,17 @@ def _validate_report_extra(self, exceptions: list[ValidationError]) -> None: position_data = json.loads(dashboard.position_json or "{}") active_tabs = dashboard_state.get("activeTabs") or [] - anchor = dashboard_state.get("anchor") invalid_tab_ids = set(active_tabs) - set(position_data.keys()) - if anchor and anchor not in position_data: - invalid_tab_ids.add(anchor) + + if anchor := dashboard_state.get("anchor"): + try: + anchor_list: list[str] = json.loads(anchor) + if _invalid_tab_ids := set(anchor_list) - set(position_data.keys()): + invalid_tab_ids.update(_invalid_tab_ids) + except json.JSONDecodeError: + if anchor not in position_data: + invalid_tab_ids.add(anchor) + if invalid_tab_ids: exceptions.append( ValidationError( diff --git a/superset/commands/report/execute.py b/superset/commands/report/execute.py index afc488df5640f..c81750daba407 100644 --- a/superset/commands/report/execute.py +++ b/superset/commands/report/execute.py @@ -49,6 +49,7 @@ REPORT_SCHEDULE_ERROR_NOTIFICATION_MARKER, ReportScheduleDAO, ) +from superset.dashboards.permalink.types import DashboardPermalinkState from superset.errors import ErrorLevel, SupersetError, SupersetErrorType from superset.exceptions import SupersetErrorsException, SupersetException from superset.extensions import feature_flag_manager, machine_auth_provider_factory @@ -206,11 +207,8 @@ def _get_url( if ( dashboard_state := self._report_schedule.extra.get("dashboard") ) and feature_flag_manager.is_feature_enabled("ALERT_REPORT_TABS"): - permalink_key = CreateDashboardPermalinkCommand( - dashboard_id=str(self._report_schedule.dashboard.uuid), - state=dashboard_state, - ).run() - return get_url_path("Superset.dashboard_permalink", key=permalink_key) + return self._get_tab_url(dashboard_state) + dashboard = self._report_schedule.dashboard dashboard_id_or_slug = ( dashboard.uuid if dashboard and dashboard.uuid else dashboard.id @@ -223,12 +221,70 @@ def _get_url( **kwargs, ) + def get_dashboard_urls( + self, user_friendly: bool = False, **kwargs: Any + ) -> list[str]: + """ + Retrieve the URL for the dashboard tabs, or return the dashboard URL if no tabs are available. + """ + force = "true" if self._report_schedule.force_screenshot else "false" + if ( + dashboard_state := self._report_schedule.extra.get("dashboard") + ) and feature_flag_manager.is_feature_enabled("ALERT_REPORT_TABS"): + if anchor := dashboard_state.get("anchor"): + try: + anchor_list: list[str] = json.loads(anchor) + return self._get_tabs_urls(anchor_list) + except json.JSONDecodeError: + logger.debug("Anchor value is not a list, Fall back to single tab") + return [self._get_tab_url(dashboard_state)] + + dashboard = self._report_schedule.dashboard + dashboard_id_or_slug = ( + dashboard.uuid if dashboard and dashboard.uuid else dashboard.id + ) + + return [ + get_url_path( + "Superset.dashboard", + user_friendly=user_friendly, + dashboard_id_or_slug=dashboard_id_or_slug, + force=force, + **kwargs, + ) + ] + + def _get_tab_url(self, dashboard_state: DashboardPermalinkState) -> str: + """ + Get one tab url + """ + permalink_key = CreateDashboardPermalinkCommand( + dashboard_id=str(self._report_schedule.dashboard.uuid), + state=dashboard_state, + ).run() + return get_url_path("Superset.dashboard_permalink", key=permalink_key) + + def _get_tabs_urls(self, tab_anchors: list[str]) -> list[str]: + """ + Get multple tabs urls + """ + return [ + self._get_tab_url( + { + "anchor": tab_anchor, + "dataMask": None, + "activeTabs": None, + "urlParams": None, + } + ) + for tab_anchor in tab_anchors + ] + def _get_screenshots(self) -> list[bytes]: """ Get chart or dashboard screenshots :raises: ReportScheduleScreenshotFailedError """ - url = self._get_url() _, username = get_executor( executor_types=app.config["ALERT_REPORTS_EXECUTE_AS"], model=self._report_schedule, @@ -236,31 +292,41 @@ def _get_screenshots(self) -> list[bytes]: user = security_manager.find_user(username) if self._report_schedule.chart: + url = self._get_url() window_width, window_height = app.config["WEBDRIVER_WINDOW"]["slice"] window_size = ( self._report_schedule.custom_width or window_width, self._report_schedule.custom_height or window_height, ) - screenshot: Union[ChartScreenshot, DashboardScreenshot] = ChartScreenshot( - url, - self._report_schedule.chart.digest, - window_size=window_size, - thumb_size=app.config["WEBDRIVER_WINDOW"]["slice"], - ) + screenshots: list[Union[ChartScreenshot, DashboardScreenshot]] = [ + ChartScreenshot( + url, + self._report_schedule.chart.digest, + window_size=window_size, + thumb_size=app.config["WEBDRIVER_WINDOW"]["slice"], + ) + ] else: + urls = self.get_dashboard_urls() window_width, window_height = app.config["WEBDRIVER_WINDOW"]["dashboard"] window_size = ( self._report_schedule.custom_width or window_width, self._report_schedule.custom_height or window_height, ) - screenshot = DashboardScreenshot( - url, - self._report_schedule.dashboard.digest, - window_size=window_size, - thumb_size=app.config["WEBDRIVER_WINDOW"]["dashboard"], - ) + screenshots = [ + DashboardScreenshot( + url, + self._report_schedule.dashboard.digest, + window_size=window_size, + thumb_size=app.config["WEBDRIVER_WINDOW"]["dashboard"], + ) + for url in urls + ] try: - image = screenshot.get_screenshot(user=user) + imges = [] + for screenshot in screenshots: + if imge := screenshot.get_screenshot(user=user): + imges.append(imge) except SoftTimeLimitExceeded as ex: logger.warning("A timeout occurred while taking a screenshot.") raise ReportScheduleScreenshotTimeout() from ex @@ -268,9 +334,9 @@ def _get_screenshots(self) -> list[bytes]: raise ReportScheduleScreenshotFailedError( f"Failed taking a screenshot {str(ex)}" ) from ex - if not image: + if not imges: raise ReportScheduleScreenshotFailedError() - return [image] + return imges def _get_pdf(self) -> bytes: """ diff --git a/tests/integration_tests/fixtures/dashboard_with_tabs.py b/tests/integration_tests/fixtures/dashboard_with_tabs.py new file mode 100644 index 0000000000000..44f10e1cc29af --- /dev/null +++ b/tests/integration_tests/fixtures/dashboard_with_tabs.py @@ -0,0 +1,651 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +import json + +import pytest + +from tests.integration_tests.dashboard_utils import create_dashboard +from tests.integration_tests.test_app import app + +MULTIPLE_TABS_TBL_NAME = "multiple_tabs" + + +@pytest.fixture(scope="session") +def load_mutltiple_tabs_dashboard(): + position_json = { + "CHART--0GPGmD-pO": { + "children": [], + "id": "CHART--0GPGmD-pO", + "meta": { + "chartId": 91, + "height": 56, + "sliceName": "Current Developers: Is this your first development job?", + "sliceNameOverride": "Is this your first development job?", + "uuid": "bfe5a8e6-146f-ef59-5e6c-13d519b236a8", + "width": 2, + }, + "parents": [ + "ROOT_ID", + "GRID_ID", + "TABS-L-d9eyOE-b", + "TAB-l_9I0aNYZ", + "ROW-b7USYEngT", + ], + "type": "CHART", + }, + "CHART--w_Br1tPP3": { + "children": [], + "id": "CHART--w_Br1tPP3", + "meta": { + "chartId": 85, + "height": 51, + "sliceName": "\u2708\ufe0f Relocation ability", + "uuid": "a6dd2d5a-2cdc-c8ec-f30c-85920f4f8a65", + "width": 3, + }, + "parents": [ + "ROOT_ID", + "GRID_ID", + "TABS-L-d9eyOE-b", + "TAB-YT6eNksV-", + "ROW-DR80aHJA2c", + ], + "type": "CHART", + }, + "CHART-0-zzTwBINh": { + "children": [], + "id": "CHART-0-zzTwBINh", + "meta": { + "chartId": 72, + "height": 55, + "sliceName": "Last Year Income Distribution", + "uuid": "a2ec5256-94b4-43c4-b8c7-b83f70c5d4df", + "width": 3, + }, + "parents": [ + "ROOT_ID", + "GRID_ID", + "TABS-L-d9eyOE-b", + "TAB-l_9I0aNYZ", + "ROW-b7USYEngT", + ], + "type": "CHART", + }, + "CHART-37fu7fO6Z0": { + "children": [], + "id": "CHART-37fu7fO6Z0", + "meta": { + "chartId": 93, + "height": 69, + "sliceName": "Degrees vs Income", + "uuid": "02f546ae-1bf4-bd26-8bc2-14b9279c8a62", + "width": 7, + }, + "parents": [ + "ROOT_ID", + "GRID_ID", + "TABS-L-d9eyOE-b", + "TAB-l_9I0aNYZ", + "ROW-kNjtGVFpp", + ], + "type": "CHART", + }, + "CHART-5QwNlSbXYU": { + "children": [], + "id": "CHART-5QwNlSbXYU", + "meta": { + "chartId": 90, + "height": 69, + "sliceName": "Commute Time", + "uuid": "097c05c9-2dd2-481d-813d-d6c0c12b4a3d", + "width": 5, + }, + "parents": [ + "ROOT_ID", + "GRID_ID", + "TABS-L-d9eyOE-b", + "TAB-l_9I0aNYZ", + "ROW-kNjtGVFpp", + ], + "type": "CHART", + }, + "CHART-FKuVqq4kaA": { + "children": [], + "id": "CHART-FKuVqq4kaA", + "meta": { + "chartId": 50, + "height": 50, + "sliceName": "Work Location Preference", + "sliceNameOverride": "Work Location Preference", + "uuid": "e6b09c28-98cf-785f-4caf-320fd4fca802", + "width": 3, + }, + "parents": [ + "ROOT_ID", + "GRID_ID", + "TABS-L-d9eyOE-b", + "TAB-YT6eNksV-", + "ROW-DR80aHJA2c", + ], + "type": "CHART", + }, + "CHART-JnpdZOhVer": { + "children": [], + "id": "CHART-JnpdZOhVer", + "meta": { + "chartId": 51, + "height": 50, + "sliceName": "Highest degree held", + "uuid": "9f7d2b9c-6b3a-69f9-f03e-d3a141514639", + "width": 2, + }, + "parents": [ + "ROOT_ID", + "GRID_ID", + "TABS-L-d9eyOE-b", + "TAB-YT6eNksV-", + "ROW--BIzjz9F0", + "COLUMN-IEKAo_QJlz", + ], + "type": "CHART", + }, + "CHART-LjfhrUkEef": { + "children": [], + "id": "CHART-LjfhrUkEef", + "meta": { + "chartId": 86, + "height": 68, + "sliceName": "First Time Developer & Commute Time", + "uuid": "067c4a1e-ae03-4c0c-8e2a-d2c0f4bf43c3", + "width": 5, + }, + "parents": [ + "ROOT_ID", + "GRID_ID", + "TABS-L-d9eyOE-b", + "TAB-l_9I0aNYZ", + "ROW-s3l4os7YY", + ], + "type": "CHART", + }, + "CHART-Q3pbwsH3id": { + "children": [], + "id": "CHART-Q3pbwsH3id", + "meta": { + "chartId": 79, + "height": 50, + "sliceName": "Are you an ethnic minority in your city?", + "sliceNameOverride": "Minority Status (in their city)", + "uuid": "def07750-b5c0-0b69-6228-cb2330916166", + "width": 3, + }, + "parents": [ + "ROOT_ID", + "GRID_ID", + "TABS-L-d9eyOE-b", + "TAB-AsMaxdYL_t", + "ROW-mOvr_xWm1", + ], + "type": "CHART", + }, + "CHART-QVql08s5Bv": { + "children": [], + "id": "CHART-QVql08s5Bv", + "meta": { + "chartId": 92, + "height": 56, + "sliceName": "First Time Developer?", + "uuid": "edc75073-8f33-4123-a28d-cd6dfb33cade", + "width": 3, + }, + "parents": [ + "ROOT_ID", + "GRID_ID", + "TABS-L-d9eyOE-b", + "TAB-l_9I0aNYZ", + "ROW-b7USYEngT", + ], + "type": "CHART", + }, + "CHART-UtSaz4pfV6": { + "children": [], + "id": "CHART-UtSaz4pfV6", + "meta": { + "chartId": 59, + "height": 50, + "sliceName": "Age distribution of respondents", + "uuid": "5f1ea868-604e-f69d-a241-5daa83ff33be", + "width": 3, + }, + "parents": [ + "ROOT_ID", + "GRID_ID", + "TABS-L-d9eyOE-b", + "TAB-AsMaxdYL_t", + "ROW-UsW-_RPAb", + "COLUMN-OJ5spdMmNh", + ], + "type": "CHART", + }, + "CHART-VvFbGxi3X_": { + "children": [], + "id": "CHART-VvFbGxi3X_", + "meta": { + "chartId": 41, + "height": 62, + "sliceName": "Top 15 Languages Spoken at Home", + "uuid": "03a74c97-52fc-cf87-233c-d4275f8c550c", + "width": 3, + }, + "parents": [ + "ROOT_ID", + "GRID_ID", + "TABS-L-d9eyOE-b", + "TAB-AsMaxdYL_t", + "ROW-UsW-_RPAb", + "COLUMN-OJ5spdMmNh", + ], + "type": "CHART", + }, + "CHART-XHncHuS5pZ": { + "children": [], + "id": "CHART-XHncHuS5pZ", + "meta": { + "chartId": 78, + "height": 41, + "sliceName": "Number of Aspiring Developers", + "sliceNameOverride": "What type of work would you prefer?", + "uuid": "a0e5329f-224e-6fc8-efd2-d37d0f546ee8", + "width": 2, + }, + "parents": [ + "ROOT_ID", + "GRID_ID", + "TABS-L-d9eyOE-b", + "TAB-YT6eNksV-", + "ROW-DR80aHJA2c", + ], + "type": "CHART", + }, + "CHART-YSzS5GOOLf": { + "children": [], + "id": "CHART-YSzS5GOOLf", + "meta": { + "chartId": 49, + "height": 54, + "sliceName": "Ethnic Minority & Gender", + "uuid": "4880e4f4-b701-4be0-86f3-e7e89432e83b", + "width": 3, + }, + "parents": [ + "ROOT_ID", + "GRID_ID", + "TABS-L-d9eyOE-b", + "TAB-AsMaxdYL_t", + "ROW-mOvr_xWm1", + ], + "type": "CHART", + }, + "CHART-ZECnzPz8Bi": { + "children": [], + "id": "CHART-ZECnzPz8Bi", + "meta": { + "chartId": 70, + "height": 74, + "sliceName": "Location of Current Developers", + "uuid": "5596e0f6-78a9-465d-8325-7139c794a06a", + "width": 7, + }, + "parents": [ + "ROOT_ID", + "GRID_ID", + "TABS-L-d9eyOE-b", + "TAB-l_9I0aNYZ", + "ROW-s3l4os7YY", + ], + "type": "CHART", + }, + "CHART-aytwlT4GAq": { + "children": [], + "id": "CHART-aytwlT4GAq", + "meta": { + "chartId": 83, + "height": 30, + "sliceName": "Breakdown of Developer Type", + "uuid": "b8386be8-f44e-6535-378c-2aa2ba461286", + "width": 6, + }, + "parents": [ + "ROOT_ID", + "GRID_ID", + "TABS-L-d9eyOE-b", + "TAB-AsMaxdYL_t", + "ROW-y-GwJPgxLr", + ], + "type": "CHART", + }, + "CHART-fLpTSAHpAO": { + "children": [], + "id": "CHART-fLpTSAHpAO", + "meta": { + "chartId": 60, + "height": 118, + "sliceName": "Country of Citizenship", + "uuid": "2ba66056-a756-d6a3-aaec-0c243fb7062e", + "width": 9, + }, + "parents": [ + "ROOT_ID", + "GRID_ID", + "TABS-L-d9eyOE-b", + "TAB-AsMaxdYL_t", + "ROW-UsW-_RPAb", + ], + "type": "CHART", + }, + "CHART-lQVSAw0Or3": { + "children": [], + "id": "CHART-lQVSAw0Or3", + "meta": { + "chartId": 94, + "height": 100, + "sliceName": "How do you prefer to work?", + "sliceNameOverride": "Preferred Employment Style vs Degree", + "uuid": "cb8998ab-9f93-4f0f-4e4b-3bfe4b0dea9d", + "width": 4, + }, + "parents": [ + "ROOT_ID", + "GRID_ID", + "TABS-L-d9eyOE-b", + "TAB-YT6eNksV-", + "ROW--BIzjz9F0", + ], + "type": "CHART", + }, + "CHART-o-JPAWMZK-": { + "children": [], + "id": "CHART-o-JPAWMZK-", + "meta": { + "chartId": 69, + "height": 50, + "sliceName": "Gender", + "uuid": "0f6b447c-828c-e71c-87ac-211bc412b214", + "width": 3, + }, + "parents": [ + "ROOT_ID", + "GRID_ID", + "TABS-L-d9eyOE-b", + "TAB-AsMaxdYL_t", + "ROW-mOvr_xWm1", + ], + "type": "CHART", + }, + "CHART-v22McUFMtx": { + "children": [], + "id": "CHART-v22McUFMtx", + "meta": { + "chartId": 71, + "height": 52, + "sliceName": "How much do you expect to earn? ($0 - 100k)", + "sliceNameOverride": "\ud83d\udcb2Expected Income (excluding outliers)", + "uuid": "6d0ceb30-2008-d19c-d285-cf77dc764433", + "width": 4, + }, + "parents": [ + "ROOT_ID", + "GRID_ID", + "TABS-L-d9eyOE-b", + "TAB-YT6eNksV-", + "ROW--BIzjz9F0", + "COLUMN-IEKAo_QJlz", + ], + "type": "CHART", + }, + "CHART-wxWVtlajRF": { + "children": [], + "id": "CHART-wxWVtlajRF", + "meta": { + "chartId": 82, + "height": 104, + "sliceName": "Preferred Employment Style", + "uuid": "bff88053-ccc4-92f2-d6f5-de83e950e8cd", + "width": 4, + }, + "parents": [ + "ROOT_ID", + "GRID_ID", + "TABS-L-d9eyOE-b", + "TAB-YT6eNksV-", + "ROW--BIzjz9F0", + ], + "type": "CHART", + }, + "COLUMN-IEKAo_QJlz": { + "children": ["CHART-JnpdZOhVer", "CHART-v22McUFMtx"], + "id": "COLUMN-IEKAo_QJlz", + "meta": {"background": "BACKGROUND_TRANSPARENT", "width": 4}, + "parents": [ + "ROOT_ID", + "GRID_ID", + "TABS-L-d9eyOE-b", + "TAB-YT6eNksV-", + "ROW--BIzjz9F0", + ], + "type": "COLUMN", + }, + "COLUMN-OJ5spdMmNh": { + "children": ["CHART-VvFbGxi3X_", "CHART-UtSaz4pfV6"], + "id": "COLUMN-OJ5spdMmNh", + "meta": {"background": "BACKGROUND_TRANSPARENT", "width": 3}, + "parents": [ + "ROOT_ID", + "GRID_ID", + "TABS-L-d9eyOE-b", + "TAB-AsMaxdYL_t", + "ROW-UsW-_RPAb", + ], + "type": "COLUMN", + }, + "DASHBOARD_VERSION_KEY": "v2", + "GRID_ID": { + "children": ["TABS-L-d9eyOE-b"], + "id": "GRID_ID", + "parents": ["ROOT_ID"], + "type": "GRID", + }, + "HEADER_ID": { + "id": "HEADER_ID", + "meta": {"text": "FCC New Coder Survey 2018"}, + "type": "HEADER", + }, + "MARKDOWN-BUmyHM2s0x": { + "children": [], + "id": "MARKDOWN-BUmyHM2s0x", + "meta": { + "code": "# Aspiring Developers\n\nThe mission of FreeCodeCamp is to \"help people learn to code for free\". With this in mind, it's no surprise that ~83% of this survey's respondents fall into the **Aspiring Developer** category.\n\nIn this tab, we use visualization to explore:\n\n- Interest in relocating for work\n- Preferences around work location & style\n- Distribution of expected income\n- Distribution of highest degree held\n- Heatmap of highest degree held vs employment style preference", + "height": 50, + "width": 4, + }, + "parents": [ + "ROOT_ID", + "GRID_ID", + "TABS-L-d9eyOE-b", + "TAB-YT6eNksV-", + "ROW-DR80aHJA2c", + ], + "type": "MARKDOWN", + }, + "MARKDOWN-NQmSPDOtpl": { + "children": [], + "id": "MARKDOWN-NQmSPDOtpl", + "meta": { + "code": "# Current Developers\n\nWhile majority of the students on FCC are Aspiring developers, there's a nontrivial minority that's there to continue leveling up their skills (17% of the survey respondents).\n\nBased on how respondents self-identified in the start of the survey, they were asked different questions. In this tab, we use visualizations to explore:\n\n- The buckets of commute team these developers encounter\n- The proportion of developers whose current job is their first developer job\n- Distribution of last year's income\n- The geographic distribution of these developers\n- The overlap between commute time and if their current job is their first developer job\n- Potential link between highest degree earned and last year's income", + "height": 56, + "width": 4, + }, + "parents": [ + "ROOT_ID", + "GRID_ID", + "TABS-L-d9eyOE-b", + "TAB-l_9I0aNYZ", + "ROW-b7USYEngT", + ], + "type": "MARKDOWN", + }, + "MARKDOWN-__u6CsUyfh": { + "children": [], + "id": "MARKDOWN-__u6CsUyfh", + "meta": { + "code": "## FreeCodeCamp New Coder Survey 2018\n\nEvery year, FCC surveys its user base (mostly budding software developers) to learn more about their interests, backgrounds, goals, job status, and socioeconomic features. This dashboard visualizes survey data from the 2018 survey.\n\n- [Survey link](https://freecodecamp.typeform.com/to/S3UeD9)\n- [Dataset](https://github.com/freeCodeCamp/2018-new-coder-survey)\n- [FCC Blog Post](https://www.freecodecamp.org/news/we-asked-20-000-people-who-they-are-and-how-theyre-learning-to-code-fff5d668969/)", + "height": 30, + "width": 6, + }, + "parents": [ + "ROOT_ID", + "GRID_ID", + "TABS-L-d9eyOE-b", + "TAB-AsMaxdYL_t", + "ROW-y-GwJPgxLr", + ], + "type": "MARKDOWN", + }, + "MARKDOWN-zc2mWxZeox": { + "children": [], + "id": "MARKDOWN-zc2mWxZeox", + "meta": { + "code": "# Demographics\n\nFreeCodeCamp is a completely-online community of people learning to code and consists of aspiring & current developers from all over the world. That doesn't necessarily mean that access to these types of opportunities are evenly distributed. \n\nThe following charts can begin to help us understand:\n\n- the original citizenship of the survey respondents\n- minority representation among both aspiring and current developers\n- their age distribution\n- household languages", + "height": 52, + "width": 3, + }, + "parents": [ + "ROOT_ID", + "GRID_ID", + "TABS-L-d9eyOE-b", + "TAB-AsMaxdYL_t", + "ROW-mOvr_xWm1", + ], + "type": "MARKDOWN", + }, + "ROOT_ID": {"children": ["GRID_ID"], "id": "ROOT_ID", "type": "ROOT"}, + "ROW--BIzjz9F0": { + "children": ["COLUMN-IEKAo_QJlz", "CHART-lQVSAw0Or3", "CHART-wxWVtlajRF"], + "id": "ROW--BIzjz9F0", + "meta": {"background": "BACKGROUND_TRANSPARENT"}, + "parents": ["ROOT_ID", "GRID_ID", "TABS-L-d9eyOE-b", "TAB-YT6eNksV-"], + "type": "ROW", + }, + "ROW-DR80aHJA2c": { + "children": [ + "MARKDOWN-BUmyHM2s0x", + "CHART-XHncHuS5pZ", + "CHART--w_Br1tPP3", + "CHART-FKuVqq4kaA", + ], + "id": "ROW-DR80aHJA2c", + "meta": {"background": "BACKGROUND_TRANSPARENT"}, + "parents": ["ROOT_ID", "GRID_ID", "TABS-L-d9eyOE-b", "TAB-YT6eNksV-"], + "type": "ROW", + }, + "ROW-UsW-_RPAb": { + "children": ["COLUMN-OJ5spdMmNh", "CHART-fLpTSAHpAO"], + "id": "ROW-UsW-_RPAb", + "meta": {"background": "BACKGROUND_TRANSPARENT"}, + "parents": ["ROOT_ID", "GRID_ID", "TABS-L-d9eyOE-b", "TAB-AsMaxdYL_t"], + "type": "ROW", + }, + "ROW-b7USYEngT": { + "children": [ + "MARKDOWN-NQmSPDOtpl", + "CHART--0GPGmD-pO", + "CHART-QVql08s5Bv", + "CHART-0-zzTwBINh", + ], + "id": "ROW-b7USYEngT", + "meta": {"background": "BACKGROUND_TRANSPARENT"}, + "parents": ["ROOT_ID", "GRID_ID", "TABS-L-d9eyOE-b", "TAB-l_9I0aNYZ"], + "type": "ROW", + }, + "ROW-kNjtGVFpp": { + "children": ["CHART-5QwNlSbXYU", "CHART-37fu7fO6Z0"], + "id": "ROW-kNjtGVFpp", + "meta": {"background": "BACKGROUND_TRANSPARENT"}, + "parents": ["ROOT_ID", "GRID_ID", "TABS-L-d9eyOE-b", "TAB-l_9I0aNYZ"], + "type": "ROW", + }, + "ROW-mOvr_xWm1": { + "children": [ + "MARKDOWN-zc2mWxZeox", + "CHART-Q3pbwsH3id", + "CHART-o-JPAWMZK-", + "CHART-YSzS5GOOLf", + ], + "id": "ROW-mOvr_xWm1", + "meta": {"background": "BACKGROUND_TRANSPARENT"}, + "parents": ["ROOT_ID", "GRID_ID", "TABS-L-d9eyOE-b", "TAB-AsMaxdYL_t"], + "type": "ROW", + }, + "ROW-s3l4os7YY": { + "children": ["CHART-LjfhrUkEef", "CHART-ZECnzPz8Bi"], + "id": "ROW-s3l4os7YY", + "meta": {"background": "BACKGROUND_TRANSPARENT"}, + "parents": ["ROOT_ID", "GRID_ID", "TABS-L-d9eyOE-b", "TAB-l_9I0aNYZ"], + "type": "ROW", + }, + "ROW-y-GwJPgxLr": { + "children": ["MARKDOWN-__u6CsUyfh", "CHART-aytwlT4GAq"], + "id": "ROW-y-GwJPgxLr", + "meta": {"background": "BACKGROUND_TRANSPARENT"}, + "parents": ["ROOT_ID", "GRID_ID", "TABS-L-d9eyOE-b", "TAB-AsMaxdYL_t"], + "type": "ROW", + }, + "TAB-AsMaxdYL_t": { + "children": ["ROW-y-GwJPgxLr", "ROW-mOvr_xWm1", "ROW-UsW-_RPAb"], + "id": "TAB-AsMaxdYL_t", + "meta": {"text": "Overview"}, + "parents": ["ROOT_ID", "GRID_ID", "TABS-L-d9eyOE-b"], + "type": "TAB", + }, + "TAB-YT6eNksV-": { + "children": ["ROW-DR80aHJA2c", "ROW--BIzjz9F0"], + "id": "TAB-YT6eNksV-", + "meta": {"text": "\ud83d\ude80 Aspiring Developers"}, + "parents": ["ROOT_ID", "GRID_ID", "TABS-L-d9eyOE-b"], + "type": "TAB", + }, + "TAB-l_9I0aNYZ": { + "children": ["ROW-b7USYEngT", "ROW-kNjtGVFpp", "ROW-s3l4os7YY"], + "id": "TAB-l_9I0aNYZ", + "meta": {"text": "\ud83d\udcbb Current Developers"}, + "parents": ["ROOT_ID", "GRID_ID", "TABS-L-d9eyOE-b"], + "type": "TAB", + }, + "TABS-L-d9eyOE-b": { + "children": ["TAB-AsMaxdYL_t", "TAB-YT6eNksV-", "TAB-l_9I0aNYZ"], + "id": "TABS-L-d9eyOE-b", + "meta": {}, + "parents": ["ROOT_ID", "GRID_ID"], + "type": "TABS", + }, + } + + with app.app_context(): + dash = create_dashboard( + "multi_tabs_test", "multiple tabs Test", json.dumps(position_json), None + ) + yield dash diff --git a/tests/integration_tests/reports/api_tests.py b/tests/integration_tests/reports/api_tests.py index 7664dc4584e0e..55b333b8137a1 100644 --- a/tests/integration_tests/reports/api_tests.py +++ b/tests/integration_tests/reports/api_tests.py @@ -49,6 +49,9 @@ load_birth_names_dashboard_with_slices, # noqa: F401 load_birth_names_data, # noqa: F401 ) +from tests.integration_tests.fixtures.dashboard_with_tabs import ( + load_mutltiple_tabs_dashboard, # noqa: F401 +) from tests.integration_tests.reports.utils import insert_report_schedule REPORTS_COUNT = 10 @@ -1972,3 +1975,79 @@ def test_report_schedule_logs_no_mutations(self): assert rv.status_code == 405 rv = self.client.delete(uri) assert rv.status_code == 405 + + @with_feature_flags(ALERT_REPORT_TABS=True) + @pytest.mark.usefixtures( + "load_birth_names_dashboard_with_slices", "create_report_schedules" + ) + def test_create_report_schedule_with_invalid_anchors(self): + """ + ReportSchedule Api: Test get report schedule 404s when feature is disabled + """ + report_schedule = db.session.query(Dashboard).first() + get_example_database() # noqa: F841 + anchors = ["TAB-AsMaxdYL_t", "TAB-YT6eNksV-", "TAB-l_9I0aNYZ"] + report_schedule_data = { + "type": ReportScheduleType.REPORT, + "name": "random_name1", + "description": "description", + "creation_method": ReportCreationMethod.ALERTS_REPORTS, + "crontab": "0 9 * * *", + "working_timeout": 3600, + "dashboard": report_schedule.id, + "extra": {"dashboard": {"anchor": json.dumps(anchors)}}, + } + + self.login(ADMIN_USERNAME) + uri = "api/v1/report/" + rv = self.post_assert_metric(uri, report_schedule_data, "post") + data = json.loads(rv.data.decode("utf-8")) + assert rv.status_code == 422 + assert "message" in data + assert "extra" in data["message"] + assert all(anchor in data["message"]["extra"][0] for anchor in anchors) is True + + @with_feature_flags(ALERT_REPORT_TABS=True) + @pytest.mark.usefixtures("load_mutltiple_tabs_dashboard", "create_report_schedules") + def test_create_report_schedule_with_multiple_anchors(self): + """ + ReportSchedule Api: Test report schedule with all tabs + """ + report_dashboard = ( + db.session.query(Dashboard) + .filter(Dashboard.slug == "multi_tabs_test") + .first() + ) + get_example_database() # noqa: F841 + + self.login(ADMIN_USERNAME) + tabs_uri = f"/api/v1/dashboard/{report_dashboard.id}/tabs" + rv = self.client.get(tabs_uri) + data = json.loads(rv.data.decode("utf-8")) + + tabs_keys = list(data.get("result").get("all_tabs").keys()) + extra_json = {"dashboard": {"anchor": json.dumps(tabs_keys)}} + + report_schedule_data = { + "type": ReportScheduleType.REPORT, + "name": "random_name2", + "description": "description", + "creation_method": ReportCreationMethod.ALERTS_REPORTS, + "crontab": "0 9 * * *", + "working_timeout": 3600, + "dashboard": report_dashboard.id, + "extra": extra_json, + } + + uri = "api/v1/report/" + rv = self.post_assert_metric(uri, report_schedule_data, "post") + data = json.loads(rv.data.decode("utf-8")) + assert rv.status_code == 201 + + report_schedule = ( + db.session.query(ReportSchedule) + .filter(ReportSchedule.dashboard_id == report_dashboard.id) + .first() + ) + + assert json.loads(report_schedule.extra_json) == extra_json diff --git a/tests/unit_tests/commands/report/execute_test.py b/tests/unit_tests/commands/report/execute_test.py index b7b545fd4a6e5..3d49bb0457d06 100644 --- a/tests/unit_tests/commands/report/execute_test.py +++ b/tests/unit_tests/commands/report/execute_test.py @@ -15,15 +15,21 @@ # specific language governing permissions and limitations # under the License. +import json +from unittest.mock import patch + +import pytest from pytest_mock import MockerFixture from superset.commands.report.execute import BaseReportState +from superset.dashboards.permalink.types import DashboardPermalinkState from superset.reports.models import ( ReportRecipientType, ReportSchedule, ReportSourceFormat, ) from superset.utils.core import HeaderDataType +from tests.integration_tests.conftest import with_feature_flags def test_log_data_with_chart(mocker: MockerFixture) -> None: @@ -220,3 +226,142 @@ def test_log_data_with_missing_values(mocker: MockerFixture) -> None: } assert result == expected_result + + +@pytest.mark.parametrize( + "anchors, permalink_side_effect, expected_uris", + [ + # Test user select multiple tabs to export in a dashboard report + ( + ["mock_tab_anchor_1", "mock_tab_anchor_2"], + ["url1", "url2"], + [ + "http://0.0.0.0:8080/superset/dashboard/p/url1/", + "http://0.0.0.0:8080/superset/dashboard/p/url2/", + ], + ), + # Test user select one tab to export in a dashboard report + ( + "mock_tab_anchor_1", + ["url1"], + ["http://0.0.0.0:8080/superset/dashboard/p/url1/"], + ), + ], +) +@patch( + "superset.commands.dashboard.permalink.create.CreateDashboardPermalinkCommand.run" +) +@with_feature_flags(ALERT_REPORT_TABS=True) +def test_get_dashboard_urls_with_multiple_tabs( + mock_run, mocker: MockerFixture, anchors, permalink_side_effect, expected_uris +) -> None: + mock_report_schedule: ReportSchedule = mocker.Mock(spec=ReportSchedule) + mock_report_schedule.chart = False + mock_report_schedule.chart_id = None + mock_report_schedule.dashboard_id = 123 + mock_report_schedule.type = "report_type" + mock_report_schedule.report_format = "report_format" + mock_report_schedule.owners = [1, 2] + mock_report_schedule.recipients = [] + mock_report_schedule.extra = { + "dashboard": { + "anchor": json.dumps(anchors) if isinstance(anchors, list) else anchors, + "dataMask": None, + "activeTabs": None, + "urlParams": None, + } + } + + class_instance: BaseReportState = BaseReportState( + mock_report_schedule, "January 1, 2021", "execution_id_example" + ) + class_instance._report_schedule = mock_report_schedule + mock_run.side_effect = permalink_side_effect + + result: list[str] = class_instance.get_dashboard_urls() + + assert result == expected_uris + + +@patch( + "superset.commands.dashboard.permalink.create.CreateDashboardPermalinkCommand.run" +) +@with_feature_flags(ALERT_REPORT_TABS=True) +def test_get_dashboard_urls_with_exporting_dashboard_only( + mock_run, + mocker: MockerFixture, +) -> None: + mock_report_schedule: ReportSchedule = mocker.Mock(spec=ReportSchedule) + mock_report_schedule.chart = False + mock_report_schedule.chart_id = None + mock_report_schedule.dashboard_id = 123 + mock_report_schedule.type = "report_type" + mock_report_schedule.report_format = "report_format" + mock_report_schedule.owners = [1, 2] + mock_report_schedule.recipients = [] + mock_report_schedule.extra = { + "dashboard": { + "anchor": "", + "dataMask": None, + "activeTabs": None, + "urlParams": None, + } + } + mock_run.return_value = "url1" + + class_instance: BaseReportState = BaseReportState( + mock_report_schedule, "January 1, 2021", "execution_id_example" + ) + class_instance._report_schedule = mock_report_schedule + + result: list[str] = class_instance.get_dashboard_urls() + + assert "http://0.0.0.0:8080/superset/dashboard/p/url1/" == result[0] + + +@patch( + "superset.commands.dashboard.permalink.create.CreateDashboardPermalinkCommand.run" +) +def test_get_tab_urls( + mock_run, + mocker: MockerFixture, +) -> None: + mock_report_schedule: ReportSchedule = mocker.Mock(spec=ReportSchedule) + mock_report_schedule.dashboard_id = 123 + + class_instance: BaseReportState = BaseReportState( + mock_report_schedule, "January 1, 2021", "execution_id_example" + ) + class_instance._report_schedule = mock_report_schedule + mock_run.side_effect = ["uri1", "uri2"] + tab_anchors = ["1", "2"] + result: list[str] = class_instance._get_tabs_urls(tab_anchors) + assert result == [ + "http://0.0.0.0:8080/superset/dashboard/p/uri1/", + "http://0.0.0.0:8080/superset/dashboard/p/uri2/", + ] + + +@patch( + "superset.commands.dashboard.permalink.create.CreateDashboardPermalinkCommand.run" +) +def test_get_tab_url( + mock_run, + mocker: MockerFixture, +) -> None: + mock_report_schedule: ReportSchedule = mocker.Mock(spec=ReportSchedule) + mock_report_schedule.dashboard_id = 123 + + class_instance: BaseReportState = BaseReportState( + mock_report_schedule, "January 1, 2021", "execution_id_example" + ) + class_instance._report_schedule = mock_report_schedule + mock_run.return_value = "uri" + dashboard_state = DashboardPermalinkState( + anchor="1", + dataMask=None, + activeTabs=None, + urlParams=None, + ) + result: str = class_instance._get_tab_url(dashboard_state) + assert result == "http://0.0.0.0:8080/superset/dashboard/p/uri/" From 5820d31b5c15d706fc26e6d6fb33b4ff1b16f4c3 Mon Sep 17 00:00:00 2001 From: Geido <60598000+geido@users.noreply.github.com> Date: Mon, 4 Nov 2024 16:08:44 +0200 Subject: [PATCH 039/307] fix(TimezoneSelector): Failing unit tests due to timezone change (#30828) --- .../TimezoneSelector.DaylightSavingTime.test.tsx | 5 ++++- .../TimezoneSelector/TimezoneSelector.test.tsx | 12 +++++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/superset-frontend/src/components/TimezoneSelector/TimezoneSelector.DaylightSavingTime.test.tsx b/superset-frontend/src/components/TimezoneSelector/TimezoneSelector.DaylightSavingTime.test.tsx index f30eeb2d52219..edb71341f240b 100644 --- a/superset-frontend/src/components/TimezoneSelector/TimezoneSelector.DaylightSavingTime.test.tsx +++ b/superset-frontend/src/components/TimezoneSelector/TimezoneSelector.DaylightSavingTime.test.tsx @@ -35,10 +35,13 @@ const loadComponent = (mockCurrentTime?: string) => { return new Promise>(resolve => { const { default: TimezoneSelector } = module.require('./index'); resolve(TimezoneSelector); - jest.useRealTimers(); }); }; +afterEach(() => { + jest.useRealTimers(); +}); + test('render timezones in correct order for daylight saving time', async () => { const TimezoneSelector = await loadComponent('2022-07-01'); const onTimezoneChange = jest.fn(); diff --git a/superset-frontend/src/components/TimezoneSelector/TimezoneSelector.test.tsx b/superset-frontend/src/components/TimezoneSelector/TimezoneSelector.test.tsx index cc422ba85e4b8..5083b6bcd0a60 100644 --- a/superset-frontend/src/components/TimezoneSelector/TimezoneSelector.test.tsx +++ b/superset-frontend/src/components/TimezoneSelector/TimezoneSelector.test.tsx @@ -35,7 +35,6 @@ const loadComponent = (mockCurrentTime?: string) => { return new Promise>(resolve => { const { default: TimezoneSelector } = module.require('./index'); resolve(TimezoneSelector); - jest.useRealTimers(); }); }; @@ -49,6 +48,10 @@ const openSelectMenu = () => { jest.spyOn(moment.tz, 'guess').mockReturnValue('America/New_York'); +afterEach(() => { + jest.useRealTimers(); +}); + test('use the timezone from `moment` if no timezone provided', async () => { const TimezoneSelector = await loadComponent('2022-01-01'); const onTimezoneChange = jest.fn(); @@ -96,10 +99,9 @@ test('render timezones in correct order for standard time', async () => { await waitForElementToBeRemoved(() => screen.queryByLabelText('Loading')); openSelectMenu(); const options = await getSelectOptions(); - expect(options[0]).toHaveTextContent('GMT -04:00 (Eastern Daylight Time)'); + expect(options[0]).toHaveTextContent('GMT -05:00 (Eastern Standard Time)'); expect(options[1]).toHaveTextContent('GMT -11:00 (Pacific/Pago_Pago)'); expect(options[2]).toHaveTextContent('GMT -10:00 (Hawaii Standard Time)'); - expect(options[3]).toHaveTextContent('GMT -09:30 (Pacific/Marquesas)'); }); test('can select a timezone values and returns canonical timezone name', async () => { @@ -116,8 +118,8 @@ test('can select a timezone values and returns canonical timezone name', async ( const searchInput = screen.getByRole('combobox'); // search for mountain time - await userEvent.type(searchInput, 'mou', { delay: 10 }); - const findTitle = 'GMT -06:00 (Mountain Daylight Time)'; + await userEvent.type(searchInput, 'mou'); + const findTitle = 'GMT -07:00 (Mountain Standard Time)'; const selectOption = await screen.findByTitle(findTitle); userEvent.click(selectOption); expect(onTimezoneChange).toHaveBeenCalledTimes(1); From 64f81407315247f233bae666859dfd14cdaced80 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Nov 2024 09:53:14 -0700 Subject: [PATCH 040/307] build(deps): bump antd from 5.20.5 to 5.21.6 in /docs (#30794) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Maxime Beauchemin --- .github/workflows/superset-docs-verify.yml | 1 + docs/package.json | 2 +- docs/yarn.lock | 258 ++++++++++----------- 3 files changed, 131 insertions(+), 130 deletions(-) diff --git a/.github/workflows/superset-docs-verify.yml b/.github/workflows/superset-docs-verify.yml index 4892936d52808..944fda8f9a3b1 100644 --- a/.github/workflows/superset-docs-verify.yml +++ b/.github/workflows/superset-docs-verify.yml @@ -46,6 +46,7 @@ jobs: https://wattbewerb.de/ https://timbr.ai/ https://opensource.org/license/apache-2-0 + https://www.plaidcloud.com/ build-deploy: name: Build & Deploy runs-on: ubuntu-22.04 diff --git a/docs/package.json b/docs/package.json index 7482e666705f3..9283ea56006a5 100644 --- a/docs/package.json +++ b/docs/package.json @@ -29,7 +29,7 @@ "@saucelabs/theme-github-codeblock": "^0.2.3", "@superset-ui/style": "^0.14.23", "@svgr/webpack": "^8.1.0", - "antd": "^5.20.5", + "antd": "^5.21.6", "buffer": "^6.0.3", "clsx": "^2.1.1", "docusaurus-plugin-less": "^2.0.2", diff --git a/docs/yarn.lock b/docs/yarn.lock index 5455dd61f6791..fa4f80ceaa73a 100644 --- a/docs/yarn.lock +++ b/docs/yarn.lock @@ -211,19 +211,19 @@ dependencies: "@ctrl/tinycolor" "^3.6.1" -"@ant-design/cssinjs-utils@^1.0.3": - version "1.0.3" - resolved "https://registry.yarnpkg.com/@ant-design/cssinjs-utils/-/cssinjs-utils-1.0.3.tgz#d68e46be9680cf9f416374a03aff0dd11bd1728d" - integrity sha512-BrztZZKuoYcJK8uEH40ylBemf/Mu/QPiDos56g2bv6eUoniQkgQHOCOvA3+pncoFO1TaS8xcUCIqGzDA0I+ZVQ== +"@ant-design/cssinjs-utils@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@ant-design/cssinjs-utils/-/cssinjs-utils-1.1.1.tgz#57abb43671023f937348bd33442862c60ac8e8b2" + integrity sha512-2HAiyGGGnM0es40SxdszeQAU5iWp41wBIInq+ONTCKjlSKOrzQfnw4JDtB8IBmqE6tQaEKwmzTP2LGdt5DSwYQ== dependencies: "@ant-design/cssinjs" "^1.21.0" "@babel/runtime" "^7.23.2" rc-util "^5.38.0" -"@ant-design/cssinjs@^1.21.0": - version "1.21.0" - resolved "https://registry.yarnpkg.com/@ant-design/cssinjs/-/cssinjs-1.21.0.tgz#de7289bfd71c7a494a28b96569ad88f999619105" - integrity sha512-gIilraPl+9EoKdYxnupxjHB/Q6IHNRjEXszKbDxZdsgv4sAZ9pjkCq8yanDWNvyfjp4leir2OVAJm0vxwKK8YA== +"@ant-design/cssinjs@^1.21.0", "@ant-design/cssinjs@^1.21.1": + version "1.21.1" + resolved "https://registry.yarnpkg.com/@ant-design/cssinjs/-/cssinjs-1.21.1.tgz#7320813c5f747e0cde52c388eff5198d78d57230" + integrity sha512-tyWnlK+XH7Bumd0byfbCiZNK43HEubMoCcu9VxwsAwiHdHTgWa+tMN0/yvxa+e8EzuFP1WdUNNPclRpVtD33lg== dependencies: "@babel/runtime" "^7.11.1" "@emotion/hash" "^0.8.0" @@ -231,7 +231,7 @@ classnames "^2.3.1" csstype "^3.1.3" rc-util "^5.35.0" - stylis "^4.0.13" + stylis "^4.3.3" "@ant-design/fast-color@^2.0.6": version "2.0.6" @@ -245,10 +245,10 @@ resolved "https://registry.yarnpkg.com/@ant-design/icons-svg/-/icons-svg-4.4.2.tgz#ed2be7fb4d82ac7e1d45a54a5b06d6cecf8be6f6" integrity sha512-vHbT+zJEVzllwP+CM+ul7reTEfBR0vgxFe7+lREAsAA7YGsYpboiq2sQNeQeRvh09GfQgs/GyFEvZpJ9cLXpXA== -"@ant-design/icons@^5.4.0": - version "5.4.0" - resolved "https://registry.yarnpkg.com/@ant-design/icons/-/icons-5.4.0.tgz#4bd8f335c68207cc06fe9943d164a81cdfcfbeac" - integrity sha512-QZbWC5xQYexCI5q4/fehSEkchJr5UGtvAJweT743qKUQQGs9IH2DehNLP49DJ3Ii9m9CijD2HN6fNy3WKhIFdA== +"@ant-design/icons@^5.4.0", "@ant-design/icons@^5.5.1": + version "5.5.1" + resolved "https://registry.yarnpkg.com/@ant-design/icons/-/icons-5.5.1.tgz#4ff57b2a0d3bafae3d990c2781fd857ead36c935" + integrity sha512-0UrM02MA2iDIgvLatWrj6YTCYe0F/cwXvVE0E2SqGrL7PZireQwgEKTKBisWpZyal5eXZLvuM98kju6YtYne8w== dependencies: "@ant-design/colors" "^7.0.0" "@ant-design/icons-svg" "^4.4.0" @@ -1274,10 +1274,10 @@ core-js-pure "^3.30.2" regenerator-runtime "^0.14.0" -"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.1", "@babel/runtime@^7.10.3", "@babel/runtime@^7.10.4", "@babel/runtime@^7.11.1", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.16.7", "@babel/runtime@^7.18.0", "@babel/runtime@^7.18.3", "@babel/runtime@^7.20.0", "@babel/runtime@^7.20.7", "@babel/runtime@^7.21.0", "@babel/runtime@^7.22.5", "@babel/runtime@^7.22.6", "@babel/runtime@^7.23.2", "@babel/runtime@^7.23.6", "@babel/runtime@^7.23.9", "@babel/runtime@^7.24.4", "@babel/runtime@^7.24.7", "@babel/runtime@^7.24.8", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4": - version "7.25.0" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.25.0.tgz#3af9a91c1b739c569d5d80cc917280919c544ecb" - integrity sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw== +"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.1", "@babel/runtime@^7.10.3", "@babel/runtime@^7.10.4", "@babel/runtime@^7.11.1", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.16.7", "@babel/runtime@^7.18.0", "@babel/runtime@^7.18.3", "@babel/runtime@^7.20.0", "@babel/runtime@^7.20.7", "@babel/runtime@^7.21.0", "@babel/runtime@^7.22.5", "@babel/runtime@^7.22.6", "@babel/runtime@^7.23.2", "@babel/runtime@^7.23.6", "@babel/runtime@^7.23.9", "@babel/runtime@^7.24.4", "@babel/runtime@^7.24.7", "@babel/runtime@^7.24.8", "@babel/runtime@^7.25.6", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4": + version "7.26.0" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.26.0.tgz#8600c2f595f277c60815256418b85356a65173c1" + integrity sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw== dependencies: regenerator-runtime "^0.14.0" @@ -2115,10 +2115,10 @@ classnames "^2.3.2" rc-util "^5.24.4" -"@rc-component/trigger@^2.0.0", "@rc-component/trigger@^2.1.1", "@rc-component/trigger@^2.2.1": - version "2.2.2" - resolved "https://registry.yarnpkg.com/@rc-component/trigger/-/trigger-2.2.2.tgz#7c8c27ce92cacbb32b1cda70f0533fe52202c41d" - integrity sha512-xDyi0fJ3IV6XJEReMOewS9PEnnuLHKz4rjbgIniDsJFHjL5nROuUlu64mfo90jglLDkQUxRwK7aTtumA65/zYQ== +"@rc-component/trigger@^2.0.0", "@rc-component/trigger@^2.1.1", "@rc-component/trigger@^2.2.3": + version "2.2.3" + resolved "https://registry.yarnpkg.com/@rc-component/trigger/-/trigger-2.2.3.tgz#b47e945115e2d0a7f7e067dbb9ed76c91c1b4385" + integrity sha512-X1oFIpKoXAMXNDYCviOmTfuNuYxE4h5laBsyCqVAVMjNHxoF3/uiyA7XdegK1XbCvBbCZ6P6byWrEoDRpKL8+A== dependencies: "@babel/runtime" "^7.23.2" "@rc-component/portal" "^1.1.0" @@ -3309,57 +3309,57 @@ ansi-styles@^6.1.0: resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== -antd@^5.20.5: - version "5.20.5" - resolved "https://registry.yarnpkg.com/antd/-/antd-5.20.5.tgz#a55d5023759b08e501cabef3700d59664453fce0" - integrity sha512-w/oVwoZAt5qP0PKhOkCmYXe06kXuoTh7UdQlltba/IzpbCCEh465z3Qw3i9HZY745HtOIS6ze707mVsORzN18g== +antd@^5.21.6: + version "5.21.6" + resolved "https://registry.yarnpkg.com/antd/-/antd-5.21.6.tgz#60d8eb442f7f8019bab198e30ea5a8d6d224a6ce" + integrity sha512-EviOde/VEu+OsIKH5t6YXTMmmNeg9R85m0W5zXAo+Np8Latg9q10691JvAqOTMpnrRmbdeKUQL1Krp69Bzbe/g== dependencies: "@ant-design/colors" "^7.1.0" - "@ant-design/cssinjs" "^1.21.0" - "@ant-design/cssinjs-utils" "^1.0.3" - "@ant-design/icons" "^5.4.0" + "@ant-design/cssinjs" "^1.21.1" + "@ant-design/cssinjs-utils" "^1.1.1" + "@ant-design/icons" "^5.5.1" "@ant-design/react-slick" "~1.1.2" - "@babel/runtime" "^7.24.8" + "@babel/runtime" "^7.25.6" "@ctrl/tinycolor" "^3.6.1" "@rc-component/color-picker" "~2.0.1" "@rc-component/mutate-observer" "^1.1.0" "@rc-component/qrcode" "~1.0.0" "@rc-component/tour" "~1.15.1" - "@rc-component/trigger" "^2.2.1" + "@rc-component/trigger" "^2.2.3" classnames "^2.5.1" copy-to-clipboard "^3.3.3" dayjs "^1.11.11" - rc-cascader "~3.28.0" + rc-cascader "~3.28.2" rc-checkbox "~3.3.0" - rc-collapse "~3.7.3" - rc-dialog "~9.5.2" + rc-collapse "~3.8.0" + rc-dialog "~9.6.0" rc-drawer "~7.2.0" rc-dropdown "~4.2.0" rc-field-form "~2.4.0" - rc-image "~7.9.0" + rc-image "~7.11.0" rc-input "~1.6.3" rc-input-number "~9.2.0" - rc-mentions "~2.15.0" - rc-menu "~9.14.1" - rc-motion "^2.9.2" - rc-notification "~5.6.0" - rc-pagination "~4.2.0" - rc-picker "~4.6.14" + rc-mentions "~2.16.1" + rc-menu "~9.15.1" + rc-motion "^2.9.3" + rc-notification "~5.6.2" + rc-pagination "~4.3.0" + rc-picker "~4.6.15" rc-progress "~4.0.0" rc-rate "~2.13.0" rc-resize-observer "^1.4.0" - rc-segmented "~2.3.0" - rc-select "~14.15.1" - rc-slider "~11.1.5" + rc-segmented "~2.5.0" + rc-select "~14.15.2" + rc-slider "~11.1.7" rc-steps "~6.0.1" rc-switch "~4.1.0" - rc-table "~7.45.7" - rc-tabs "~15.1.1" - rc-textarea "~1.8.1" - rc-tooltip "~6.2.0" + rc-table "~7.47.5" + rc-tabs "~15.3.0" + rc-textarea "~1.8.2" + rc-tooltip "~6.2.1" rc-tree "~5.9.0" rc-tree-select "~5.23.0" - rc-upload "~4.7.0" + rc-upload "~4.8.1" rc-util "^5.43.0" scroll-into-view-if-needed "^3.1.0" throttle-debounce "^5.0.2" @@ -8184,10 +8184,10 @@ raw-body@2.5.2: iconv-lite "0.4.24" unpipe "1.0.0" -rc-cascader@~3.28.0: - version "3.28.1" - resolved "https://registry.yarnpkg.com/rc-cascader/-/rc-cascader-3.28.1.tgz#ea8a3de60521290096bab7e3fbe8ca097b976468" - integrity sha512-9+8oHIMWVLHxuaapDiqFNmD9KSyKN/P4bo9x/MBuDbyTqP8f2/POmmZxdXWBO3yq/uE3pKyQCXYNUxrNfHRv2A== +rc-cascader@~3.28.2: + version "3.28.2" + resolved "https://registry.yarnpkg.com/rc-cascader/-/rc-cascader-3.28.2.tgz#91720d3498261a7bff9fffc953501a8830f601fb" + integrity sha512-8f+JgM83iLTvjgdkgU7GfI4qY8icXOBP0cGZjOdx2iJAkEe8ucobxDQAVE69UD/c3ehCxZlcgEHeD5hFmypbUw== dependencies: "@babel/runtime" "^7.12.5" array-tree-filter "^2.1.0" @@ -8205,20 +8205,20 @@ rc-checkbox@~3.3.0: classnames "^2.3.2" rc-util "^5.25.2" -rc-collapse@~3.7.3: - version "3.7.3" - resolved "https://registry.yarnpkg.com/rc-collapse/-/rc-collapse-3.7.3.tgz#68161683d8fd1004bef4eb281fc106f3c8dc16eb" - integrity sha512-60FJcdTRn0X5sELF18TANwtVi7FtModq649H11mYF1jh83DniMoM4MqY627sEKRCTm4+WXfGDcB7hY5oW6xhyw== +rc-collapse@~3.8.0: + version "3.8.0" + resolved "https://registry.yarnpkg.com/rc-collapse/-/rc-collapse-3.8.0.tgz#02bcf81e1601aa185cd3b9fab0ceefd8dc11aefb" + integrity sha512-YVBkssrKPBG09TGfcWWGj8zJBYD9G3XuTy89t5iUmSXrIXEAnO1M+qjUxRW6b4Qi0+wNWG6MHJF/+US+nmIlzA== dependencies: "@babel/runtime" "^7.10.1" classnames "2.x" rc-motion "^2.3.4" rc-util "^5.27.0" -rc-dialog@~9.5.2: - version "9.5.2" - resolved "https://registry.yarnpkg.com/rc-dialog/-/rc-dialog-9.5.2.tgz#4cf7cca23aedb6fd3d9344ea8ffd14daa94ee3a0" - integrity sha512-qVUjc8JukG+j/pNaHVSRa2GO2/KbV2thm7yO4hepQ902eGdYK913sGkwg/fh9yhKYV1ql3BKIN2xnud3rEXAPw== +rc-dialog@~9.6.0: + version "9.6.0" + resolved "https://registry.yarnpkg.com/rc-dialog/-/rc-dialog-9.6.0.tgz#dc7a255c6ad1cb56021c3a61c7de86ee88c7c371" + integrity sha512-ApoVi9Z8PaCQg6FsUzS8yvBEQy0ZL2PkuvAgrmohPkN3okps5WZ5WQWPc1RNuiOKaAYv8B97ACdsFU5LizzCqg== dependencies: "@babel/runtime" "^7.10.1" "@rc-component/portal" "^1.0.0-8" @@ -8256,15 +8256,15 @@ rc-field-form@~2.4.0: "@rc-component/async-validator" "^5.0.3" rc-util "^5.32.2" -rc-image@~7.9.0: - version "7.9.0" - resolved "https://registry.yarnpkg.com/rc-image/-/rc-image-7.9.0.tgz#2d700a5cf891bb3d0d800b7c38348927ebb9f49b" - integrity sha512-l4zqO5E0quuLMCtdKfBgj4Suv8tIS011F5k1zBBlK25iMjjiNHxA0VeTzGFtUZERSA45gvpXDg8/P6qNLjR25g== +rc-image@~7.11.0: + version "7.11.0" + resolved "https://registry.yarnpkg.com/rc-image/-/rc-image-7.11.0.tgz#18c77ea557a6fdbe26856c688a9aace1505c0e77" + integrity sha512-aZkTEZXqeqfPZtnSdNUnKQA0N/3MbgR7nUnZ+/4MfSFWPFHZau4p5r5ShaI0KPEMnNjv4kijSCFq/9wtJpwykw== dependencies: "@babel/runtime" "^7.11.2" "@rc-component/portal" "^1.0.2" classnames "^2.2.6" - rc-dialog "~9.5.2" + rc-dialog "~9.6.0" rc-motion "^2.6.2" rc-util "^5.34.1" @@ -8288,23 +8288,23 @@ rc-input@~1.6.0, rc-input@~1.6.3: classnames "^2.2.1" rc-util "^5.18.1" -rc-mentions@~2.15.0: - version "2.15.0" - resolved "https://registry.yarnpkg.com/rc-mentions/-/rc-mentions-2.15.0.tgz#ada022b32e68fa067a859ee0024c3f2aa7a9c871" - integrity sha512-f5v5i7VdqvBDXbphoqcQWmXDif2Msd2arritVoWybrVDuHE6nQ7XCYsybHbV//WylooK52BFDouFvyaRDtXZEw== +rc-mentions@~2.16.1: + version "2.16.1" + resolved "https://registry.yarnpkg.com/rc-mentions/-/rc-mentions-2.16.1.tgz#5e54ebe3ce6cd79838846ff1c8cfaf2e7aa15cec" + integrity sha512-GnhSTGP9Mtv6pqFFGQze44LlrtWOjHNrUUAcsdo9DnNAhN4pwVPEWy4z+2jpjkiGlJ3VoXdvMHcNDQdfI9fEaw== dependencies: "@babel/runtime" "^7.22.5" "@rc-component/trigger" "^2.0.0" classnames "^2.2.6" rc-input "~1.6.0" - rc-menu "~9.14.0" + rc-menu "~9.15.1" rc-textarea "~1.8.0" rc-util "^5.34.1" -rc-menu@~9.14.0, rc-menu@~9.14.1: - version "9.14.1" - resolved "https://registry.yarnpkg.com/rc-menu/-/rc-menu-9.14.1.tgz#5c2aea72bdce421e9d50bf721ad8b76c154ae66f" - integrity sha512-5wlRb3M8S4yGlWhSoEYJ7ZVRElyScdcpUHxgiLxkeig1tEdyKrnED3B2fhpN0Rrpdp9jyhnmZR/Lwq2fH5VvDQ== +rc-menu@~9.15.1: + version "9.15.1" + resolved "https://registry.yarnpkg.com/rc-menu/-/rc-menu-9.15.1.tgz#d8b38ea534a7f596a8da063881519e7eaafca698" + integrity sha512-UKporqU6LPfHnpPmtP6hdEK4iO5Q+b7BRv/uRpxdIyDGplZy9jwUjsnpev5bs3PQKB0H0n34WAPDfjAfn3kAPA== dependencies: "@babel/runtime" "^7.10.1" "@rc-component/trigger" "^2.0.0" @@ -8313,19 +8313,19 @@ rc-menu@~9.14.0, rc-menu@~9.14.1: rc-overflow "^1.3.1" rc-util "^5.27.0" -rc-motion@^2.0.0, rc-motion@^2.0.1, rc-motion@^2.3.0, rc-motion@^2.3.4, rc-motion@^2.4.3, rc-motion@^2.4.4, rc-motion@^2.6.1, rc-motion@^2.6.2, rc-motion@^2.9.0, rc-motion@^2.9.2: - version "2.9.2" - resolved "https://registry.yarnpkg.com/rc-motion/-/rc-motion-2.9.2.tgz#f7c6d480250df8a512d0cfdce07ff3da906958cf" - integrity sha512-fUAhHKLDdkAXIDLH0GYwof3raS58dtNUmzLF2MeiR8o6n4thNpSDQhOqQzWE4WfFZDCi9VEN8n7tiB7czREcyw== +rc-motion@^2.0.0, rc-motion@^2.0.1, rc-motion@^2.3.0, rc-motion@^2.3.4, rc-motion@^2.4.3, rc-motion@^2.4.4, rc-motion@^2.6.1, rc-motion@^2.6.2, rc-motion@^2.9.0, rc-motion@^2.9.3: + version "2.9.3" + resolved "https://registry.yarnpkg.com/rc-motion/-/rc-motion-2.9.3.tgz#b1bdaf816f1ccb3e4b3b0c531c3037a59286379e" + integrity sha512-rkW47ABVkic7WEB0EKJqzySpvDqwl60/tdkY7hWP7dYnh5pm0SzJpo54oW3TDUGXV5wfxXFmMkxrzRRbotQ0+w== dependencies: "@babel/runtime" "^7.11.1" classnames "^2.2.1" rc-util "^5.43.0" -rc-notification@~5.6.0: - version "5.6.0" - resolved "https://registry.yarnpkg.com/rc-notification/-/rc-notification-5.6.0.tgz#1639aa30686d79ee4bb8ace05a698a5a104aaa74" - integrity sha512-TGQW5T7waOxLwgJG7fXcw8l7AQiFOjaZ7ISF5PrU526nunHRNcTMuzKihQHaF4E/h/KfOCDk3Mv8eqzbu2e28w== +rc-notification@~5.6.2: + version "5.6.2" + resolved "https://registry.yarnpkg.com/rc-notification/-/rc-notification-5.6.2.tgz#8525b32d49dd96ec974acae61d1d1eabde61463a" + integrity sha512-Id4IYMoii3zzrG0lB0gD6dPgJx4Iu95Xu0BQrhHIbp7ZnAZbLqdqQ73aIWH0d0UFcElxwaKjnzNovTjo7kXz7g== dependencies: "@babel/runtime" "^7.10.1" classnames "2.x" @@ -8342,19 +8342,19 @@ rc-overflow@^1.3.1, rc-overflow@^1.3.2: rc-resize-observer "^1.0.0" rc-util "^5.37.0" -rc-pagination@~4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/rc-pagination/-/rc-pagination-4.2.0.tgz#b7222b429dec38f6c74e139a30ae7765e9a0b8a6" - integrity sha512-V6qeANJsT6tmOcZ4XiUmj8JXjRLbkusuufpuoBw2GiAn94fIixYjFLmbruD1Sbhn8fPLDnWawPp4CN37zQorvw== +rc-pagination@~4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/rc-pagination/-/rc-pagination-4.3.0.tgz#c6022f820aa3a45fd734ae33a2915d39597dce1d" + integrity sha512-UubEWA0ShnroQ1tDa291Fzw6kj0iOeF26IsUObxYTpimgj4/qPCWVFl18RLZE+0Up1IZg0IK4pMn6nB3mjvB7g== dependencies: "@babel/runtime" "^7.10.1" classnames "^2.3.2" rc-util "^5.38.0" -rc-picker@~4.6.14: - version "4.6.14" - resolved "https://registry.yarnpkg.com/rc-picker/-/rc-picker-4.6.14.tgz#86f6836794a593a54b929cfde201f42f02ef85b0" - integrity sha512-7DuTfUFdkxmsNpWQ0TWv6FPGna5e6KKC4nxtx3x9xhumLz7jb3fhlDdWQvqEL6tpt9DOb1+N5j+wB+lDOSS9kg== +rc-picker@~4.6.15: + version "4.6.15" + resolved "https://registry.yarnpkg.com/rc-picker/-/rc-picker-4.6.15.tgz#1531c9c382a295e2d1f1f38440d6678b09cd0468" + integrity sha512-OWZ1yrMie+KN2uEUfYCfS4b2Vu6RC1FWwNI0s+qypsc3wRt7g+peuZKVIzXCTaJwyyZruo80+akPg2+GmyiJjw== dependencies: "@babel/runtime" "^7.24.7" "@rc-component/trigger" "^2.0.0" @@ -8391,20 +8391,20 @@ rc-resize-observer@^1.0.0, rc-resize-observer@^1.1.0, rc-resize-observer@^1.3.1, rc-util "^5.38.0" resize-observer-polyfill "^1.5.1" -rc-segmented@~2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/rc-segmented/-/rc-segmented-2.3.0.tgz#b3fe080fb434a266c02e30bb62a47d2c6e094341" - integrity sha512-I3FtM5Smua/ESXutFfb8gJ8ZPcvFR+qUgeeGFQHBOvRiRKyAk4aBE5nfqrxXx+h8/vn60DQjOt6i4RNtrbOobg== +rc-segmented@~2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/rc-segmented/-/rc-segmented-2.5.0.tgz#3b5423adf57459345c77c39c7581fde786a16c11" + integrity sha512-B28Fe3J9iUFOhFJET3RoXAPFJ2u47QvLSYcZWC4tFYNGPEjug5LAxEasZlA/PpAxhdOPqGWsGbSj7ftneukJnw== dependencies: "@babel/runtime" "^7.11.1" classnames "^2.2.1" rc-motion "^2.4.4" rc-util "^5.17.0" -rc-select@~14.15.0, rc-select@~14.15.1: - version "14.15.1" - resolved "https://registry.yarnpkg.com/rc-select/-/rc-select-14.15.1.tgz#1c8ab356cfdf1b24e974d62aec752620845d95a7" - integrity sha512-mGvuwW1RMm1NCSI8ZUoRoLRK51R2Nb+QJnmiAvbDRcjh2//ulCkxeV6ZRFTECPpE1t2DPfyqZMPw90SVJzQ7wQ== +rc-select@~14.15.0, rc-select@~14.15.2: + version "14.15.2" + resolved "https://registry.yarnpkg.com/rc-select/-/rc-select-14.15.2.tgz#d85fcf3a708bdf837b003feeed653347b8980ad0" + integrity sha512-oNoXlaFmpqXYcQDzcPVLrEqS2J9c+/+oJuGrlXeVVX/gVgrbHa5YcyiRUXRydFjyuA7GP3elRuLF7Y3Tfwltlw== dependencies: "@babel/runtime" "^7.10.1" "@rc-component/trigger" "^2.1.1" @@ -8414,10 +8414,10 @@ rc-select@~14.15.0, rc-select@~14.15.1: rc-util "^5.16.1" rc-virtual-list "^3.5.2" -rc-slider@~11.1.5: - version "11.1.5" - resolved "https://registry.yarnpkg.com/rc-slider/-/rc-slider-11.1.5.tgz#9a596464a36d78feb90589fee4eb0bf7cec40584" - integrity sha512-b77H5PbjMKsvkYXAYIkn50QuFX6ICQmCTibDinI9q+BHx65/TV4TeU25+oadhSRzykxs0/vBWeKBwRyySOeWlg== +rc-slider@~11.1.7: + version "11.1.7" + resolved "https://registry.yarnpkg.com/rc-slider/-/rc-slider-11.1.7.tgz#3de333b1ec84d53a7bda2f816bb4779423628f09" + integrity sha512-ytYbZei81TX7otdC0QvoYD72XSlxvTihNth5OeZ6PMXyEDq/vHdWFulQmfDGyXK1NwKwSlKgpvINOa88uT5g2A== dependencies: "@babel/runtime" "^7.10.1" classnames "^2.2.5" @@ -8441,35 +8441,35 @@ rc-switch@~4.1.0: classnames "^2.2.1" rc-util "^5.30.0" -rc-table@~7.45.7: - version "7.45.7" - resolved "https://registry.yarnpkg.com/rc-table/-/rc-table-7.45.7.tgz#f7c509e05c677a30ad5b212750122da6f5318004" - integrity sha512-wi9LetBL1t1csxyGkMB2p3mCiMt+NDexMlPbXHvQFmBBAsMxrgNSAPwUci2zDLUq9m8QdWc1Nh8suvrpy9mXrg== +rc-table@~7.47.5: + version "7.47.5" + resolved "https://registry.yarnpkg.com/rc-table/-/rc-table-7.47.5.tgz#3c530200baa82346c7e72fe9b1dbd47d4aa15838" + integrity sha512-fzq+V9j/atbPIcvs3emuclaEoXulwQpIiJA6/7ey52j8+9cJ4P8DGmp4YzfUVDrb3qhgedcVeD6eRgUrokwVEQ== dependencies: "@babel/runtime" "^7.10.1" "@rc-component/context" "^1.4.0" classnames "^2.2.5" rc-resize-observer "^1.1.0" - rc-util "^5.37.0" + rc-util "^5.41.0" rc-virtual-list "^3.14.2" -rc-tabs@~15.1.1: - version "15.1.1" - resolved "https://registry.yarnpkg.com/rc-tabs/-/rc-tabs-15.1.1.tgz#99f4c7647e01d3e22216d94222d717e928ed98d0" - integrity sha512-Tc7bJvpEdkWIVCUL7yQrMNBJY3j44NcyWS48jF/UKMXuUlzaXK+Z/pEL5LjGcTadtPvVmNqA40yv7hmr+tCOAw== +rc-tabs@~15.3.0: + version "15.3.0" + resolved "https://registry.yarnpkg.com/rc-tabs/-/rc-tabs-15.3.0.tgz#3fcc332fbb9307d5eb147e0404daca871fb92a89" + integrity sha512-lzE18r+zppT/jZWOAWS6ntdkDUKHOLJzqMi5UAij1LeKwOaQaupupAoI9Srn73GRzVpmGznkECMRrzkRusC40A== dependencies: "@babel/runtime" "^7.11.2" classnames "2.x" rc-dropdown "~4.2.0" - rc-menu "~9.14.0" + rc-menu "~9.15.1" rc-motion "^2.6.2" rc-resize-observer "^1.0.0" rc-util "^5.34.1" -rc-textarea@~1.8.0, rc-textarea@~1.8.1: - version "1.8.1" - resolved "https://registry.yarnpkg.com/rc-textarea/-/rc-textarea-1.8.1.tgz#0313ed2e7980269e1bd4f3c203a4e9a84cad8e2d" - integrity sha512-bm36N2ZqwZAP60ZQg2OY9mPdqWC+m6UTjHc+CqEZOxb3Ia29BGHazY/s5bI8M4113CkqTzhtFUDNA078ZiOx3Q== +rc-textarea@~1.8.0, rc-textarea@~1.8.2: + version "1.8.2" + resolved "https://registry.yarnpkg.com/rc-textarea/-/rc-textarea-1.8.2.tgz#57a6847304551c1883fc3fb0c5076d587f70bf7f" + integrity sha512-UFAezAqltyR00a8Lf0IPAyTd29Jj9ee8wt8DqXyDMal7r/Cg/nDt3e1OOv3Th4W6mKaZijjgwuPXhAfVNTN8sw== dependencies: "@babel/runtime" "^7.10.1" classnames "^2.2.1" @@ -8477,10 +8477,10 @@ rc-textarea@~1.8.0, rc-textarea@~1.8.1: rc-resize-observer "^1.0.0" rc-util "^5.27.0" -rc-tooltip@~6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/rc-tooltip/-/rc-tooltip-6.2.0.tgz#4dd7575674137a5b14f118a5c16435d3f5e4a9c9" - integrity sha512-iS/3iOAvtDh9GIx1ulY7EFUXUtktFccNLsARo3NPgLf0QW9oT0w3dA9cYWlhqAKmD+uriEwdWz1kH0Qs4zk2Aw== +rc-tooltip@~6.2.1: + version "6.2.1" + resolved "https://registry.yarnpkg.com/rc-tooltip/-/rc-tooltip-6.2.1.tgz#9a8f0335c86443a0c20c2557933205f645a381b7" + integrity sha512-rws0duD/3sHHsD905Nex7FvoUGy2UBQRhTkKxeEvr2FB+r21HsOxcDJI0TzyO8NHhnAA8ILr8pfbSBg5Jj5KBg== dependencies: "@babel/runtime" "^7.11.2" "@rc-component/trigger" "^2.0.0" @@ -8508,16 +8508,16 @@ rc-tree@~5.9.0: rc-util "^5.16.1" rc-virtual-list "^3.5.1" -rc-upload@~4.7.0: - version "4.7.0" - resolved "https://registry.yarnpkg.com/rc-upload/-/rc-upload-4.7.0.tgz#719c6e66549844f4db8c57f066f2758c0a43b525" - integrity sha512-eUwxYNHlsYe5vYhKFAUGrQG95JrnPzY+BmPi1Daq39fWNl/eOc7v4UODuWrVp2LFkQBuV3cMCG/I68iub6oBrg== +rc-upload@~4.8.1: + version "4.8.1" + resolved "https://registry.yarnpkg.com/rc-upload/-/rc-upload-4.8.1.tgz#ac55f2bc101b95b52a6e47f3c18f0f55b54e16d2" + integrity sha512-toEAhwl4hjLAI1u8/CgKWt30BR06ulPa4iGQSMvSXoHzO88gPCslxqV/mnn4gJU7PDoltGIC9Eh+wkeudqgHyw== dependencies: "@babel/runtime" "^7.18.3" classnames "^2.2.5" rc-util "^5.2.0" -rc-util@^5.0.1, rc-util@^5.16.1, rc-util@^5.17.0, rc-util@^5.18.1, rc-util@^5.2.0, rc-util@^5.20.1, rc-util@^5.21.0, rc-util@^5.24.4, rc-util@^5.25.2, rc-util@^5.27.0, rc-util@^5.30.0, rc-util@^5.31.1, rc-util@^5.32.2, rc-util@^5.34.1, rc-util@^5.35.0, rc-util@^5.36.0, rc-util@^5.37.0, rc-util@^5.38.0, rc-util@^5.38.1, rc-util@^5.40.1, rc-util@^5.43.0: +rc-util@^5.0.1, rc-util@^5.16.1, rc-util@^5.17.0, rc-util@^5.18.1, rc-util@^5.2.0, rc-util@^5.20.1, rc-util@^5.21.0, rc-util@^5.24.4, rc-util@^5.25.2, rc-util@^5.27.0, rc-util@^5.30.0, rc-util@^5.31.1, rc-util@^5.32.2, rc-util@^5.34.1, rc-util@^5.35.0, rc-util@^5.36.0, rc-util@^5.37.0, rc-util@^5.38.0, rc-util@^5.38.1, rc-util@^5.40.1, rc-util@^5.41.0, rc-util@^5.43.0: version "5.43.0" resolved "https://registry.yarnpkg.com/rc-util/-/rc-util-5.43.0.tgz#bba91fbef2c3e30ea2c236893746f3e9b05ecc4c" integrity sha512-AzC7KKOXFqAdIBqdGWepL9Xn7cm3vnAmjlHqUnoQaTMZYhM4VlXGLkkHHxj/BZ7Td0+SOPKB4RGPboBVKT9htw== @@ -9668,10 +9668,10 @@ stylehacks@^6.1.1: browserslist "^4.23.0" postcss-selector-parser "^6.0.16" -stylis@^4.0.13: - version "4.3.2" - resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.3.2.tgz#8f76b70777dd53eb669c6f58c997bf0a9972e444" - integrity sha512-bhtUjWd/z6ltJiQwg0dUfxEJ+W+jdqQd8TbWLWyeIJHlnsqmGLRFFd8e5mA0AZi/zx90smXRlN66YMTcaSFifg== +stylis@^4.3.3: + version "4.3.4" + resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.3.4.tgz#ca5c6c4a35c4784e4e93a2a24dc4e9fa075250a4" + integrity sha512-osIBl6BGUmSfDkyH2mB7EFvCJntXDrLhKjHTRj/rK6xLH0yuPrHULDRQzKokSOD4VoorhtKpfcfW1GAntu8now== supports-color@^5.3.0: version "5.5.0" From 305b6df6e3e5aaa6d3faa8fa1a2d91fcb05b7c34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ferr=C3=A3o?= Date: Mon, 4 Nov 2024 17:54:47 +0100 Subject: [PATCH 041/307] feat(oauth2): add support for trino (#30081) --- superset/db_engine_specs/base.py | 46 +++---- superset/db_engine_specs/trino.py | 27 +++- superset/superset_typing.py | 4 + superset/utils/oauth2.py | 7 +- .../db_engine_specs/test_gsheets.py | 1 + .../unit_tests/db_engine_specs/test_trino.py | 117 ++++++++++++++---- tests/unit_tests/models/core_test.py | 1 + 7 files changed, 151 insertions(+), 52 deletions(-) diff --git a/superset/db_engine_specs/base.py b/superset/db_engine_specs/base.py index a086f6eff7159..8cabb1e5893ea 100644 --- a/superset/db_engine_specs/base.py +++ b/superset/db_engine_specs/base.py @@ -433,6 +433,7 @@ class BaseEngineSpec: # pylint: disable=too-many-public-methods oauth2_scope = "" oauth2_authorization_request_uri: str | None = None # pylint: disable=invalid-name oauth2_token_request_uri: str | None = None + oauth2_token_request_type = "data" # Driver-specific exception that should be mapped to OAuth2RedirectError oauth2_exception = OAuth2RedirectError @@ -525,6 +526,9 @@ def get_oauth2_config(cls) -> OAuth2ClientConfig | None: "token_request_uri", cls.oauth2_token_request_uri, ), + "request_content_type": db_engine_spec_config.get( + "request_content_type", cls.oauth2_token_request_type + ), } return config @@ -562,18 +566,16 @@ def get_oauth2_token( """ timeout = current_app.config["DATABASE_OAUTH2_TIMEOUT"].total_seconds() uri = config["token_request_uri"] - response = requests.post( - uri, - json={ - "code": code, - "client_id": config["id"], - "client_secret": config["secret"], - "redirect_uri": config["redirect_uri"], - "grant_type": "authorization_code", - }, - timeout=timeout, - ) - return response.json() + req_body = { + "code": code, + "client_id": config["id"], + "client_secret": config["secret"], + "redirect_uri": config["redirect_uri"], + "grant_type": "authorization_code", + } + if config["request_content_type"] == "data": + return requests.post(uri, data=req_body, timeout=timeout).json() + return requests.post(uri, json=req_body, timeout=timeout).json() @classmethod def get_oauth2_fresh_token( @@ -586,17 +588,15 @@ def get_oauth2_fresh_token( """ timeout = current_app.config["DATABASE_OAUTH2_TIMEOUT"].total_seconds() uri = config["token_request_uri"] - response = requests.post( - uri, - json={ - "client_id": config["id"], - "client_secret": config["secret"], - "refresh_token": refresh_token, - "grant_type": "refresh_token", - }, - timeout=timeout, - ) - return response.json() + req_body = { + "client_id": config["id"], + "client_secret": config["secret"], + "refresh_token": refresh_token, + "grant_type": "refresh_token", + } + if config["request_content_type"] == "data": + return requests.post(uri, data=req_body, timeout=timeout).json() + return requests.post(uri, json=req_body, timeout=timeout).json() @classmethod def get_allows_alias_in_select( diff --git a/superset/db_engine_specs/trino.py b/superset/db_engine_specs/trino.py index c473528217b5e..ad00557f650cc 100644 --- a/superset/db_engine_specs/trino.py +++ b/superset/db_engine_specs/trino.py @@ -27,11 +27,13 @@ import numpy as np import pandas as pd import pyarrow as pa -from flask import ctx, current_app, Flask, g +import requests +from flask import copy_current_request_context, ctx, current_app, Flask, g from sqlalchemy import text from sqlalchemy.engine.reflection import Inspector from sqlalchemy.engine.url import URL from sqlalchemy.exc import NoSuchTableError +from trino.exceptions import HttpError from superset import db from superset.constants import QUERY_CANCEL_KEY, QUERY_EARLY_CANCEL_KEY, USER_AGENT @@ -60,11 +62,28 @@ logger = logging.getLogger(__name__) +class CustomTrinoAuthErrorMeta(type): + def __instancecheck__(cls, instance: object) -> bool: + logger.info("is this being called?") + return isinstance( + instance, HttpError + ) and "error 401: b'Invalid credentials'" in str(instance) + + +class TrinoAuthError(HttpError, metaclass=CustomTrinoAuthErrorMeta): + pass + + class TrinoEngineSpec(PrestoBaseEngineSpec): engine = "trino" engine_name = "Trino" allows_alias_to_source_column = False + # OAuth 2.0 + supports_oauth2 = True + oauth2_exception = TrinoAuthError + oauth2_token_request_type = "data" + @classmethod def get_extra_table_metadata( cls, @@ -142,6 +161,10 @@ def update_impersonation_config( # pylint: disable=too-many-arguments # Set principal_username=$effective_username if backend_name == "trino" and username is not None: connect_args["user"] = username + if access_token is not None: + http_session = requests.Session() + http_session.headers.update({"Authorization": f"Bearer {access_token}"}) + connect_args["http_session"] = http_session @classmethod def get_url_for_impersonation( @@ -154,6 +177,7 @@ def get_url_for_impersonation( """ Return a modified URL with the username set. + :param access_token: Personal access token for OAuth2 :param url: SQLAlchemy URL object :param impersonate_user: Flag indicating if impersonation is enabled :param username: Effective username @@ -228,6 +252,7 @@ def execute_with_cursor( execute_result: dict[str, Any] = {} execute_event = threading.Event() + @copy_current_request_context def _execute( results: dict[str, Any], event: threading.Event, diff --git a/superset/superset_typing.py b/superset/superset_typing.py index 3a850e0acb672..c3c40cd31a918 100644 --- a/superset/superset_typing.py +++ b/superset/superset_typing.py @@ -149,6 +149,10 @@ class OAuth2ClientConfig(TypedDict): # expired access token. token_request_uri: str + # Not all identity providers expect json. Keycloak expects a form encoded request, + # which in the `requests` package context means using the `data` param, not `json`. + request_content_type: str + class OAuth2TokenResponse(TypedDict, total=False): """ diff --git a/superset/utils/oauth2.py b/superset/utils/oauth2.py index b889ef83c5e75..95db2921f6cd6 100644 --- a/superset/utils/oauth2.py +++ b/superset/utils/oauth2.py @@ -23,7 +23,7 @@ import backoff import jwt from flask import current_app, url_for -from marshmallow import EXCLUDE, fields, post_load, Schema +from marshmallow import EXCLUDE, fields, post_load, Schema, validate from superset import db from superset.distributed_lock import KeyValueDistributedLock @@ -192,3 +192,8 @@ class OAuth2ClientConfigSchema(Schema): ) authorization_request_uri = fields.String(required=True) token_request_uri = fields.String(required=True) + request_content_type = fields.String( + required=False, + load_default=lambda: "json", + validate=validate.OneOf(["json", "data"]), + ) diff --git a/tests/unit_tests/db_engine_specs/test_gsheets.py b/tests/unit_tests/db_engine_specs/test_gsheets.py index 5d2ddb807bbc1..4e17054db9e63 100644 --- a/tests/unit_tests/db_engine_specs/test_gsheets.py +++ b/tests/unit_tests/db_engine_specs/test_gsheets.py @@ -559,6 +559,7 @@ def oauth2_config() -> OAuth2ClientConfig: "redirect_uri": "http://localhost:8088/api/v1/oauth2/", "authorization_request_uri": "https://accounts.google.com/o/oauth2/v2/auth", "token_request_uri": "https://oauth2.googleapis.com/token", + "request_content_type": "json", } diff --git a/tests/unit_tests/db_engine_specs/test_trino.py b/tests/unit_tests/db_engine_specs/test_trino.py index 5a32cd05044cd..b616adfcf139e 100644 --- a/tests/unit_tests/db_engine_specs/test_trino.py +++ b/tests/unit_tests/db_engine_specs/test_trino.py @@ -45,7 +45,12 @@ SupersetDBAPIProgrammingError, ) from superset.sql_parse import Table -from superset.superset_typing import ResultSetColumnType, SQLAColumnType, SQLType +from superset.superset_typing import ( + OAuth2ClientConfig, + ResultSetColumnType, + SQLAColumnType, + SQLType, +) from superset.utils import json from superset.utils.core import GenericDataType from tests.unit_tests.db_engine_specs.utils import ( @@ -421,21 +426,23 @@ def test_execute_with_cursor_in_parallel(app, mocker: MockerFixture): def _mock_execute(*args, **kwargs): mock_cursor.query_id = query_id - mock_cursor.execute.side_effect = _mock_execute - with patch.dict( - "superset.config.DISALLOWED_SQL_FUNCTIONS", - {}, - clear=True, - ): - TrinoEngineSpec.execute_with_cursor( - cursor=mock_cursor, - sql="SELECT 1 FROM foo", - query=mock_query, - ) + with app.test_request_context("/some/place/"): + mock_cursor.execute.side_effect = _mock_execute - mock_query.set_extra_json_key.assert_called_once_with( - key=QUERY_CANCEL_KEY, value=query_id - ) + with patch.dict( + "superset.config.DISALLOWED_SQL_FUNCTIONS", + {}, + clear=True, + ): + TrinoEngineSpec.execute_with_cursor( + cursor=mock_cursor, + sql="SELECT 1 FROM foo", + query=mock_query, + ) + + mock_query.set_extra_json_key.assert_called_once_with( + key=QUERY_CANCEL_KEY, value=query_id + ) def test_execute_with_cursor_app_context(app, mocker: MockerFixture): @@ -446,23 +453,25 @@ def test_execute_with_cursor_app_context(app, mocker: MockerFixture): mock_cursor.query_id = None mock_query = mocker.MagicMock() - g.some_value = "some_value" def _mock_execute(*args, **kwargs): assert has_app_context() assert g.some_value == "some_value" - with patch.object(TrinoEngineSpec, "execute", side_effect=_mock_execute): - with patch.dict( - "superset.config.DISALLOWED_SQL_FUNCTIONS", - {}, - clear=True, - ): - TrinoEngineSpec.execute_with_cursor( - cursor=mock_cursor, - sql="SELECT 1 FROM foo", - query=mock_query, - ) + with app.test_request_context("/some/place/"): + g.some_value = "some_value" + + with patch.object(TrinoEngineSpec, "execute", side_effect=_mock_execute): + with patch.dict( + "superset.config.DISALLOWED_SQL_FUNCTIONS", + {}, + clear=True, + ): + TrinoEngineSpec.execute_with_cursor( + cursor=mock_cursor, + sql="SELECT 1 FROM foo", + query=mock_query, + ) def test_get_columns(mocker: MockerFixture): @@ -784,3 +793,57 @@ def test_where_latest_partition( ) == f"""SELECT * FROM table \nWHERE partition_key = {expected_value}""" ) + + +@pytest.fixture +def oauth2_config() -> OAuth2ClientConfig: + """ + Config for Trino OAuth2. + """ + return { + "id": "trino", + "secret": "very-secret", + "scope": "", + "redirect_uri": "http://localhost:8088/api/v1/database/oauth2/", + "authorization_request_uri": "https://trino.auth.server.example/realms/master/protocol/openid-connect/auth", + "token_request_uri": "https://trino.auth.server.example/master/protocol/openid-connect/token", + "request_content_type": "data", + } + + +def test_get_oauth2_token( + mocker: MockerFixture, + oauth2_config: OAuth2ClientConfig, +) -> None: + """ + Test `get_oauth2_token`. + """ + from superset.db_engine_specs.trino import TrinoEngineSpec + + requests = mocker.patch("superset.db_engine_specs.base.requests") + requests.post().json.return_value = { + "access_token": "access-token", + "expires_in": 3600, + "scope": "scope", + "token_type": "Bearer", + "refresh_token": "refresh-token", + } + + assert TrinoEngineSpec.get_oauth2_token(oauth2_config, "code") == { + "access_token": "access-token", + "expires_in": 3600, + "scope": "scope", + "token_type": "Bearer", + "refresh_token": "refresh-token", + } + requests.post.assert_called_with( + "https://trino.auth.server.example/master/protocol/openid-connect/token", + data={ + "code": "code", + "client_id": "trino", + "client_secret": "very-secret", + "redirect_uri": "http://localhost:8088/api/v1/database/oauth2/", + "grant_type": "authorization_code", + }, + timeout=30.0, + ) diff --git a/tests/unit_tests/models/core_test.py b/tests/unit_tests/models/core_test.py index 452cbb6f56997..1dff4784ec9a5 100644 --- a/tests/unit_tests/models/core_test.py +++ b/tests/unit_tests/models/core_test.py @@ -521,6 +521,7 @@ def test_get_oauth2_config(app_context: None) -> None: "token_request_uri": "https://abcd1234.snowflakecomputing.com/oauth/token-request", "scope": "refresh_token session:role:USERADMIN", "redirect_uri": "http://example.com/api/v1/database/oauth2/", + "request_content_type": "json", } From f85175e16deb6539116c14494df3186d97c35576 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Nov 2024 10:00:57 -0700 Subject: [PATCH 042/307] build(deps): bump webpack from 5.80.0 to 5.96.1 in /superset-frontend/cypress-base (#30817) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .../cypress-base/package-lock.json | 738 +++++++++--------- 1 file changed, 362 insertions(+), 376 deletions(-) diff --git a/superset-frontend/cypress-base/package-lock.json b/superset-frontend/cypress-base/package-lock.json index 38e80a183cc9a..a648fa64f541d 100644 --- a/superset-frontend/cypress-base/package-lock.json +++ b/superset-frontend/cypress-base/package-lock.json @@ -2849,13 +2849,13 @@ } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", "dependencies": { - "@jridgewell/set-array": "^1.0.1", + "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { "node": ">=6.0.0" @@ -2870,21 +2870,21 @@ } }, "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/source-map": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.3.tgz", - "integrity": "sha512-b+fsZXeLYi9fEULmfBrhxn4IrPlINf8fiNarzTof004v3lFdntdwa9PF7vFJqm3mg7s+ScJMxXaE3Acp1irZcg==", + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", "peer": true, "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" } }, "node_modules/@jridgewell/sourcemap-codec": { @@ -2893,12 +2893,12 @@ "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.18", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", - "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dependencies": { - "@jridgewell/resolve-uri": "3.1.0", - "@jridgewell/sourcemap-codec": "1.4.14" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, "node_modules/@nodelib/fs.scandir": { @@ -3159,9 +3159,9 @@ "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==" }, "node_modules/@types/eslint": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.37.0.tgz", - "integrity": "sha512-Piet7dG2JBuDIfohBngQ3rCt7MgO9xCO4xIMKxBThCq5PNRB91IjlJ10eJVwfoNtvTErmxLzwBZ7rHZtbOMmFQ==", + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", + "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", "peer": true, "dependencies": { "@types/estree": "*", @@ -3169,9 +3169,9 @@ } }, "node_modules/@types/eslint-scope": { - "version": "3.7.4", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz", - "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==", + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", "peer": true, "dependencies": { "@types/eslint": "*", @@ -3179,9 +3179,9 @@ } }, "node_modules/@types/estree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz", - "integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", "peer": true }, "node_modules/@types/fetch-mock": { @@ -3616,148 +3616,148 @@ } }, "node_modules/@webassemblyjs/ast": { - "version": "1.11.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.5.tgz", - "integrity": "sha512-LHY/GSAZZRpsNQH+/oHqhRQ5FT7eoULcBqgfyTB5nQHogFnK3/7QoN7dLnwSE/JkUAF0SrRuclT7ODqMFtWxxQ==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", + "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==", "peer": true, "dependencies": { - "@webassemblyjs/helper-numbers": "1.11.5", - "@webassemblyjs/helper-wasm-bytecode": "1.11.5" + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" } }, "node_modules/@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.5.tgz", - "integrity": "sha512-1j1zTIC5EZOtCplMBG/IEwLtUojtwFVwdyVMbL/hwWqbzlQoJsWCOavrdnLkemwNoC/EOwtUFch3fuo+cbcXYQ==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", "peer": true }, "node_modules/@webassemblyjs/helper-api-error": { - "version": "1.11.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.5.tgz", - "integrity": "sha512-L65bDPmfpY0+yFrsgz8b6LhXmbbs38OnwDCf6NpnMUYqa+ENfE5Dq9E42ny0qz/PdR0LJyq/T5YijPnU8AXEpA==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", "peer": true }, "node_modules/@webassemblyjs/helper-buffer": { - "version": "1.11.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.5.tgz", - "integrity": "sha512-fDKo1gstwFFSfacIeH5KfwzjykIE6ldh1iH9Y/8YkAZrhmu4TctqYjSh7t0K2VyDSXOZJ1MLhht/k9IvYGcIxg==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz", + "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==", "peer": true }, "node_modules/@webassemblyjs/helper-numbers": { - "version": "1.11.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.5.tgz", - "integrity": "sha512-DhykHXM0ZABqfIGYNv93A5KKDw/+ywBFnuWybZZWcuzWHfbp21wUfRkbtz7dMGwGgT4iXjWuhRMA2Mzod6W4WA==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", + "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", "peer": true, "dependencies": { - "@webassemblyjs/floating-point-hex-parser": "1.11.5", - "@webassemblyjs/helper-api-error": "1.11.5", + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", "@xtuc/long": "4.2.2" } }, "node_modules/@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.5.tgz", - "integrity": "sha512-oC4Qa0bNcqnjAowFn7MPCETQgDYytpsfvz4ujZz63Zu/a/v71HeCAAmZsgZ3YVKec3zSPYytG3/PrRCqbtcAvA==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", "peer": true }, "node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.11.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.5.tgz", - "integrity": "sha512-uEoThA1LN2NA+K3B9wDo3yKlBfVtC6rh0i4/6hvbz071E8gTNZD/pT0MsBf7MeD6KbApMSkaAK0XeKyOZC7CIA==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz", + "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==", "peer": true, "dependencies": { - "@webassemblyjs/ast": "1.11.5", - "@webassemblyjs/helper-buffer": "1.11.5", - "@webassemblyjs/helper-wasm-bytecode": "1.11.5", - "@webassemblyjs/wasm-gen": "1.11.5" + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.12.1" } }, "node_modules/@webassemblyjs/ieee754": { - "version": "1.11.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.5.tgz", - "integrity": "sha512-37aGq6qVL8A8oPbPrSGMBcp38YZFXcHfiROflJn9jxSdSMMM5dS5P/9e2/TpaJuhE+wFrbukN2WI6Hw9MH5acg==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", + "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", "peer": true, "dependencies": { "@xtuc/ieee754": "^1.2.0" } }, "node_modules/@webassemblyjs/leb128": { - "version": "1.11.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.5.tgz", - "integrity": "sha512-ajqrRSXaTJoPW+xmkfYN6l8VIeNnR4vBOTQO9HzR7IygoCcKWkICbKFbVTNMjMgMREqXEr0+2M6zukzM47ZUfQ==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", + "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", "peer": true, "dependencies": { "@xtuc/long": "4.2.2" } }, "node_modules/@webassemblyjs/utf8": { - "version": "1.11.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.5.tgz", - "integrity": "sha512-WiOhulHKTZU5UPlRl53gHR8OxdGsSOxqfpqWeA2FmcwBMaoEdz6b2x2si3IwC9/fSPLfe8pBMRTHVMk5nlwnFQ==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", "peer": true }, "node_modules/@webassemblyjs/wasm-edit": { - "version": "1.11.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.5.tgz", - "integrity": "sha512-C0p9D2fAu3Twwqvygvf42iGCQ4av8MFBLiTb+08SZ4cEdwzWx9QeAHDo1E2k+9s/0w1DM40oflJOpkZ8jW4HCQ==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz", + "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==", "peer": true, "dependencies": { - "@webassemblyjs/ast": "1.11.5", - "@webassemblyjs/helper-buffer": "1.11.5", - "@webassemblyjs/helper-wasm-bytecode": "1.11.5", - "@webassemblyjs/helper-wasm-section": "1.11.5", - "@webassemblyjs/wasm-gen": "1.11.5", - "@webassemblyjs/wasm-opt": "1.11.5", - "@webassemblyjs/wasm-parser": "1.11.5", - "@webassemblyjs/wast-printer": "1.11.5" + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-opt": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1", + "@webassemblyjs/wast-printer": "1.12.1" } }, "node_modules/@webassemblyjs/wasm-gen": { - "version": "1.11.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.5.tgz", - "integrity": "sha512-14vteRlRjxLK9eSyYFvw1K8Vv+iPdZU0Aebk3j6oB8TQiQYuO6hj9s4d7qf6f2HJr2khzvNldAFG13CgdkAIfA==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz", + "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==", "peer": true, "dependencies": { - "@webassemblyjs/ast": "1.11.5", - "@webassemblyjs/helper-wasm-bytecode": "1.11.5", - "@webassemblyjs/ieee754": "1.11.5", - "@webassemblyjs/leb128": "1.11.5", - "@webassemblyjs/utf8": "1.11.5" + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" } }, "node_modules/@webassemblyjs/wasm-opt": { - "version": "1.11.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.5.tgz", - "integrity": "sha512-tcKwlIXstBQgbKy1MlbDMlXaxpucn42eb17H29rawYLxm5+MsEmgPzeCP8B1Cl69hCice8LeKgZpRUAPtqYPgw==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz", + "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==", "peer": true, "dependencies": { - "@webassemblyjs/ast": "1.11.5", - "@webassemblyjs/helper-buffer": "1.11.5", - "@webassemblyjs/wasm-gen": "1.11.5", - "@webassemblyjs/wasm-parser": "1.11.5" + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1" } }, "node_modules/@webassemblyjs/wasm-parser": { - "version": "1.11.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.5.tgz", - "integrity": "sha512-SVXUIwsLQlc8srSD7jejsfTU83g7pIGr2YYNb9oHdtldSxaOhvA5xwvIiWIfcX8PlSakgqMXsLpLfbbJ4cBYew==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz", + "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==", "peer": true, "dependencies": { - "@webassemblyjs/ast": "1.11.5", - "@webassemblyjs/helper-api-error": "1.11.5", - "@webassemblyjs/helper-wasm-bytecode": "1.11.5", - "@webassemblyjs/ieee754": "1.11.5", - "@webassemblyjs/leb128": "1.11.5", - "@webassemblyjs/utf8": "1.11.5" + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" } }, "node_modules/@webassemblyjs/wast-printer": { - "version": "1.11.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.5.tgz", - "integrity": "sha512-f7Pq3wvg3GSPUPzR0F6bmI89Hdb+u9WXrSKc4v+N0aV0q6r42WoF92Jp2jEorBEBRoRNXgjp53nBniDXcqZYPA==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz", + "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==", "peer": true, "dependencies": { - "@webassemblyjs/ast": "1.11.5", + "@webassemblyjs/ast": "1.12.1", "@xtuc/long": "4.2.2" } }, @@ -4346,9 +4346,9 @@ } }, "node_modules/browserslist": { - "version": "4.21.5", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", - "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", + "version": "4.24.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.2.tgz", + "integrity": "sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==", "funding": [ { "type": "opencollective", @@ -4357,13 +4357,17 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ], "dependencies": { - "caniuse-lite": "^1.0.30001449", - "electron-to-chromium": "^1.4.284", - "node-releases": "^2.0.8", - "update-browserslist-db": "^1.0.10" + "caniuse-lite": "^1.0.30001669", + "electron-to-chromium": "^1.5.41", + "node-releases": "^2.0.18", + "update-browserslist-db": "^1.1.1" }, "bin": { "browserslist": "cli.js" @@ -4470,9 +4474,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001481", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001481.tgz", - "integrity": "sha512-KCqHwRnaa1InZBtqXzP98LPg0ajCVujMKjqKDhZEthIpAsJl/YEIa3YvXjGXPVqzZVguccuu7ga9KOE1J9rKPQ==", + "version": "1.0.30001676", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001676.tgz", + "integrity": "sha512-Qz6zwGCiPghQXGJvgQAem79esjitvJ+CxSbSQkW9H/UX5hg8XM88d4lp2W+MEQ81j+Hip58Il+jGVdazk1z9cw==", "funding": [ { "type": "opencollective", @@ -5218,9 +5222,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.371", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.371.tgz", - "integrity": "sha512-jlBzY4tFcJaiUjzhRTCWAqRvTO/fWzjA3Bls0mykzGZ7zvcMP7h05W6UcgzfT9Ca1SW2xyKDOFRyI0pQeRNZGw==" + "version": "1.5.50", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.50.tgz", + "integrity": "sha512-eMVObiUQ2LdgeO1F/ySTXsvqvxb6ZH2zPGaMYsWzRDdOddUa77tdmI0ltg+L16UpbWdhPmuF3wIQYyQq65WfZw==" }, "node_modules/emoji-regex": { "version": "8.0.0", @@ -5244,9 +5248,9 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.13.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.13.0.tgz", - "integrity": "sha512-eyV8f0y1+bzyfh8xAwW/WTSZpLbjhqc4ne9eGSH4Zo2ejdyiNG9pU6mf9DG8a7+Auk6MFTlNOT4Y2y/9k8GKVg==", + "version": "5.17.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", + "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", "peer": true, "dependencies": { "graceful-fs": "^4.2.4", @@ -5288,9 +5292,9 @@ "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==" }, "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "engines": { "node": ">=6" } @@ -8137,9 +8141,9 @@ } }, "node_modules/node-releases": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", - "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==" + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==" }, "node_modules/normalize-url": { "version": "6.1.0", @@ -8479,9 +8483,9 @@ "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==" }, "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" }, "node_modules/picomatch": { "version": "2.3.1", @@ -9240,9 +9244,9 @@ "integrity": "sha512-TcZvGMMy9vodEFSse30lWinkj+JgOBvPn8wRItpQRSayhc+4ssDs335uklkfvQQJgL/WvmHLVj4Ycv2s7QCQMg==" }, "node_modules/serialize-javascript": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", - "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", "peer": true, "dependencies": { "randombytes": "^2.1.0" @@ -9636,13 +9640,13 @@ } }, "node_modules/terser": { - "version": "5.17.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.17.1.tgz", - "integrity": "sha512-hVl35zClmpisy6oaoKALOpS0rDYLxRFLHhRuDlEGTKey9qHjS1w9GMORjuwIMt70Wan4lwsLYyWDVnWgF+KUEw==", + "version": "5.36.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.36.0.tgz", + "integrity": "sha512-IYV9eNMuFAV4THUspIRXkLakHnV6XO7FEdtKjf/mDyrnqUg9LnlOn6/RwRvM9SZjR4GUq8Nk8zj67FzVARr74w==", "peer": true, "dependencies": { - "@jridgewell/source-map": "^0.3.2", - "acorn": "^8.5.0", + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, @@ -9654,16 +9658,16 @@ } }, "node_modules/terser-webpack-plugin": { - "version": "5.3.7", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.7.tgz", - "integrity": "sha512-AfKwIktyP7Cu50xNjXF/6Qb5lBNzYaWpU6YfoX3uZicTx0zTy0stDDCsvjDapKsSDvOeWo5MEq4TmdBy2cNoHw==", + "version": "5.3.10", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", + "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", "peer": true, "dependencies": { - "@jridgewell/trace-mapping": "^0.3.17", + "@jridgewell/trace-mapping": "^0.3.20", "jest-worker": "^27.4.5", "schema-utils": "^3.1.1", "serialize-javascript": "^6.0.1", - "terser": "^5.16.5" + "terser": "^5.26.0" }, "engines": { "node": ">= 10.13.0" @@ -9688,9 +9692,9 @@ } }, "node_modules/terser-webpack-plugin/node_modules/schema-utils": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.2.tgz", - "integrity": "sha512-pvjEHOgWc9OWA/f/DE3ohBWTD6EleVLf7iFUkoSwAxttdBhB9QUebQgxER2kWueOvRJXPHNnyrvvh9eZINB8Eg==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", "peer": true, "dependencies": { "@types/json-schema": "^7.0.8", @@ -9706,9 +9710,9 @@ } }, "node_modules/terser/node_modules/acorn": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", - "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", "peer": true, "bin": { "acorn": "bin/acorn" @@ -10057,9 +10061,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", - "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", + "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", "funding": [ { "type": "opencollective", @@ -10075,8 +10079,8 @@ } ], "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" + "escalade": "^3.2.0", + "picocolors": "^1.1.0" }, "bin": { "update-browserslist-db": "cli.js" @@ -10189,9 +10193,9 @@ } }, "node_modules/watchpack": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", - "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz", + "integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==", "peer": true, "dependencies": { "glob-to-regexp": "^0.4.1", @@ -10251,34 +10255,33 @@ "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" }, "node_modules/webpack": { - "version": "5.80.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.80.0.tgz", - "integrity": "sha512-OIMiq37XK1rWO8mH9ssfFKZsXg4n6klTEDL7S8/HqbAOBBaiy8ABvXvz0dDCXeEF9gqwxSvVk611zFPjS8hJxA==", - "peer": true, - "dependencies": { - "@types/eslint-scope": "^3.7.3", - "@types/estree": "^1.0.0", - "@webassemblyjs/ast": "^1.11.5", - "@webassemblyjs/wasm-edit": "^1.11.5", - "@webassemblyjs/wasm-parser": "^1.11.5", - "acorn": "^8.7.1", - "acorn-import-assertions": "^1.7.6", - "browserslist": "^4.14.5", + "version": "5.96.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.96.1.tgz", + "integrity": "sha512-l2LlBSvVZGhL4ZrPwyr8+37AunkcYj5qh8o6u2/2rzoPc8gxFJkLj1WxNgooi9pnoc06jh0BjuXnamM4qlujZA==", + "peer": true, + "dependencies": { + "@types/eslint-scope": "^3.7.7", + "@types/estree": "^1.0.6", + "@webassemblyjs/ast": "^1.12.1", + "@webassemblyjs/wasm-edit": "^1.12.1", + "@webassemblyjs/wasm-parser": "^1.12.1", + "acorn": "^8.14.0", + "browserslist": "^4.24.0", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.13.0", + "enhanced-resolve": "^5.17.1", "es-module-lexer": "^1.2.1", "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.9", + "graceful-fs": "^4.2.11", "json-parse-even-better-errors": "^2.3.1", "loader-runner": "^4.2.0", "mime-types": "^2.1.27", "neo-async": "^2.6.2", - "schema-utils": "^3.1.2", + "schema-utils": "^3.2.0", "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.3.7", - "watchpack": "^2.4.0", + "terser-webpack-plugin": "^5.3.10", + "watchpack": "^2.4.1", "webpack-sources": "^3.2.3" }, "bin": { @@ -10307,9 +10310,9 @@ } }, "node_modules/webpack/node_modules/acorn": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", - "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", "peer": true, "bin": { "acorn": "bin/acorn" @@ -10318,19 +10321,10 @@ "node": ">=0.4.0" } }, - "node_modules/webpack/node_modules/acorn-import-assertions": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", - "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", - "peer": true, - "peerDependencies": { - "acorn": "^8" - } - }, "node_modules/webpack/node_modules/schema-utils": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.2.tgz", - "integrity": "sha512-pvjEHOgWc9OWA/f/DE3ohBWTD6EleVLf7iFUkoSwAxttdBhB9QUebQgxER2kWueOvRJXPHNnyrvvh9eZINB8Eg==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", "peer": true, "dependencies": { "@types/json-schema": "^7.0.8", @@ -12566,13 +12560,13 @@ "integrity": "sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw==" }, "@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", "requires": { - "@jridgewell/set-array": "^1.0.1", + "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/trace-mapping": "^0.3.24" } }, "@jridgewell/resolve-uri": { @@ -12581,18 +12575,18 @@ "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==" }, "@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==" + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==" }, "@jridgewell/source-map": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.3.tgz", - "integrity": "sha512-b+fsZXeLYi9fEULmfBrhxn4IrPlINf8fiNarzTof004v3lFdntdwa9PF7vFJqm3mg7s+ScJMxXaE3Acp1irZcg==", + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", "peer": true, "requires": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" } }, "@jridgewell/sourcemap-codec": { @@ -12601,12 +12595,12 @@ "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" }, "@jridgewell/trace-mapping": { - "version": "0.3.18", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", - "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "requires": { - "@jridgewell/resolve-uri": "3.1.0", - "@jridgewell/sourcemap-codec": "1.4.14" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, "@nodelib/fs.scandir": { @@ -12841,9 +12835,9 @@ } }, "@types/eslint": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.37.0.tgz", - "integrity": "sha512-Piet7dG2JBuDIfohBngQ3rCt7MgO9xCO4xIMKxBThCq5PNRB91IjlJ10eJVwfoNtvTErmxLzwBZ7rHZtbOMmFQ==", + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", + "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", "peer": true, "requires": { "@types/estree": "*", @@ -12851,9 +12845,9 @@ } }, "@types/eslint-scope": { - "version": "3.7.4", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz", - "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==", + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", "peer": true, "requires": { "@types/eslint": "*", @@ -12861,9 +12855,9 @@ } }, "@types/estree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz", - "integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", "peer": true }, "@types/fetch-mock": { @@ -13255,148 +13249,148 @@ } }, "@webassemblyjs/ast": { - "version": "1.11.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.5.tgz", - "integrity": "sha512-LHY/GSAZZRpsNQH+/oHqhRQ5FT7eoULcBqgfyTB5nQHogFnK3/7QoN7dLnwSE/JkUAF0SrRuclT7ODqMFtWxxQ==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", + "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==", "peer": true, "requires": { - "@webassemblyjs/helper-numbers": "1.11.5", - "@webassemblyjs/helper-wasm-bytecode": "1.11.5" + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" } }, "@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.5.tgz", - "integrity": "sha512-1j1zTIC5EZOtCplMBG/IEwLtUojtwFVwdyVMbL/hwWqbzlQoJsWCOavrdnLkemwNoC/EOwtUFch3fuo+cbcXYQ==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", "peer": true }, "@webassemblyjs/helper-api-error": { - "version": "1.11.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.5.tgz", - "integrity": "sha512-L65bDPmfpY0+yFrsgz8b6LhXmbbs38OnwDCf6NpnMUYqa+ENfE5Dq9E42ny0qz/PdR0LJyq/T5YijPnU8AXEpA==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", "peer": true }, "@webassemblyjs/helper-buffer": { - "version": "1.11.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.5.tgz", - "integrity": "sha512-fDKo1gstwFFSfacIeH5KfwzjykIE6ldh1iH9Y/8YkAZrhmu4TctqYjSh7t0K2VyDSXOZJ1MLhht/k9IvYGcIxg==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz", + "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==", "peer": true }, "@webassemblyjs/helper-numbers": { - "version": "1.11.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.5.tgz", - "integrity": "sha512-DhykHXM0ZABqfIGYNv93A5KKDw/+ywBFnuWybZZWcuzWHfbp21wUfRkbtz7dMGwGgT4iXjWuhRMA2Mzod6W4WA==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", + "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", "peer": true, "requires": { - "@webassemblyjs/floating-point-hex-parser": "1.11.5", - "@webassemblyjs/helper-api-error": "1.11.5", + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", "@xtuc/long": "4.2.2" } }, "@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.5.tgz", - "integrity": "sha512-oC4Qa0bNcqnjAowFn7MPCETQgDYytpsfvz4ujZz63Zu/a/v71HeCAAmZsgZ3YVKec3zSPYytG3/PrRCqbtcAvA==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", "peer": true }, "@webassemblyjs/helper-wasm-section": { - "version": "1.11.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.5.tgz", - "integrity": "sha512-uEoThA1LN2NA+K3B9wDo3yKlBfVtC6rh0i4/6hvbz071E8gTNZD/pT0MsBf7MeD6KbApMSkaAK0XeKyOZC7CIA==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz", + "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==", "peer": true, "requires": { - "@webassemblyjs/ast": "1.11.5", - "@webassemblyjs/helper-buffer": "1.11.5", - "@webassemblyjs/helper-wasm-bytecode": "1.11.5", - "@webassemblyjs/wasm-gen": "1.11.5" + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.12.1" } }, "@webassemblyjs/ieee754": { - "version": "1.11.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.5.tgz", - "integrity": "sha512-37aGq6qVL8A8oPbPrSGMBcp38YZFXcHfiROflJn9jxSdSMMM5dS5P/9e2/TpaJuhE+wFrbukN2WI6Hw9MH5acg==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", + "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", "peer": true, "requires": { "@xtuc/ieee754": "^1.2.0" } }, "@webassemblyjs/leb128": { - "version": "1.11.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.5.tgz", - "integrity": "sha512-ajqrRSXaTJoPW+xmkfYN6l8VIeNnR4vBOTQO9HzR7IygoCcKWkICbKFbVTNMjMgMREqXEr0+2M6zukzM47ZUfQ==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", + "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", "peer": true, "requires": { "@xtuc/long": "4.2.2" } }, "@webassemblyjs/utf8": { - "version": "1.11.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.5.tgz", - "integrity": "sha512-WiOhulHKTZU5UPlRl53gHR8OxdGsSOxqfpqWeA2FmcwBMaoEdz6b2x2si3IwC9/fSPLfe8pBMRTHVMk5nlwnFQ==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", "peer": true }, "@webassemblyjs/wasm-edit": { - "version": "1.11.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.5.tgz", - "integrity": "sha512-C0p9D2fAu3Twwqvygvf42iGCQ4av8MFBLiTb+08SZ4cEdwzWx9QeAHDo1E2k+9s/0w1DM40oflJOpkZ8jW4HCQ==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz", + "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==", "peer": true, "requires": { - "@webassemblyjs/ast": "1.11.5", - "@webassemblyjs/helper-buffer": "1.11.5", - "@webassemblyjs/helper-wasm-bytecode": "1.11.5", - "@webassemblyjs/helper-wasm-section": "1.11.5", - "@webassemblyjs/wasm-gen": "1.11.5", - "@webassemblyjs/wasm-opt": "1.11.5", - "@webassemblyjs/wasm-parser": "1.11.5", - "@webassemblyjs/wast-printer": "1.11.5" + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-opt": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1", + "@webassemblyjs/wast-printer": "1.12.1" } }, "@webassemblyjs/wasm-gen": { - "version": "1.11.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.5.tgz", - "integrity": "sha512-14vteRlRjxLK9eSyYFvw1K8Vv+iPdZU0Aebk3j6oB8TQiQYuO6hj9s4d7qf6f2HJr2khzvNldAFG13CgdkAIfA==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz", + "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==", "peer": true, "requires": { - "@webassemblyjs/ast": "1.11.5", - "@webassemblyjs/helper-wasm-bytecode": "1.11.5", - "@webassemblyjs/ieee754": "1.11.5", - "@webassemblyjs/leb128": "1.11.5", - "@webassemblyjs/utf8": "1.11.5" + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" } }, "@webassemblyjs/wasm-opt": { - "version": "1.11.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.5.tgz", - "integrity": "sha512-tcKwlIXstBQgbKy1MlbDMlXaxpucn42eb17H29rawYLxm5+MsEmgPzeCP8B1Cl69hCice8LeKgZpRUAPtqYPgw==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz", + "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==", "peer": true, "requires": { - "@webassemblyjs/ast": "1.11.5", - "@webassemblyjs/helper-buffer": "1.11.5", - "@webassemblyjs/wasm-gen": "1.11.5", - "@webassemblyjs/wasm-parser": "1.11.5" + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1" } }, "@webassemblyjs/wasm-parser": { - "version": "1.11.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.5.tgz", - "integrity": "sha512-SVXUIwsLQlc8srSD7jejsfTU83g7pIGr2YYNb9oHdtldSxaOhvA5xwvIiWIfcX8PlSakgqMXsLpLfbbJ4cBYew==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz", + "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==", "peer": true, "requires": { - "@webassemblyjs/ast": "1.11.5", - "@webassemblyjs/helper-api-error": "1.11.5", - "@webassemblyjs/helper-wasm-bytecode": "1.11.5", - "@webassemblyjs/ieee754": "1.11.5", - "@webassemblyjs/leb128": "1.11.5", - "@webassemblyjs/utf8": "1.11.5" + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" } }, "@webassemblyjs/wast-printer": { - "version": "1.11.5", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.5.tgz", - "integrity": "sha512-f7Pq3wvg3GSPUPzR0F6bmI89Hdb+u9WXrSKc4v+N0aV0q6r42WoF92Jp2jEorBEBRoRNXgjp53nBniDXcqZYPA==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz", + "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==", "peer": true, "requires": { - "@webassemblyjs/ast": "1.11.5", + "@webassemblyjs/ast": "1.12.1", "@xtuc/long": "4.2.2" } }, @@ -13837,14 +13831,14 @@ } }, "browserslist": { - "version": "4.21.5", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", - "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", + "version": "4.24.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.2.tgz", + "integrity": "sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==", "requires": { - "caniuse-lite": "^1.0.30001449", - "electron-to-chromium": "^1.4.284", - "node-releases": "^2.0.8", - "update-browserslist-db": "^1.0.10" + "caniuse-lite": "^1.0.30001669", + "electron-to-chromium": "^1.5.41", + "node-releases": "^2.0.18", + "update-browserslist-db": "^1.1.1" } }, "buffer-crc32": { @@ -13918,9 +13912,9 @@ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" }, "caniuse-lite": { - "version": "1.0.30001481", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001481.tgz", - "integrity": "sha512-KCqHwRnaa1InZBtqXzP98LPg0ajCVujMKjqKDhZEthIpAsJl/YEIa3YvXjGXPVqzZVguccuu7ga9KOE1J9rKPQ==" + "version": "1.0.30001676", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001676.tgz", + "integrity": "sha512-Qz6zwGCiPghQXGJvgQAem79esjitvJ+CxSbSQkW9H/UX5hg8XM88d4lp2W+MEQ81j+Hip58Il+jGVdazk1z9cw==" }, "caseless": { "version": "0.12.0", @@ -14474,9 +14468,9 @@ } }, "electron-to-chromium": { - "version": "1.4.371", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.371.tgz", - "integrity": "sha512-jlBzY4tFcJaiUjzhRTCWAqRvTO/fWzjA3Bls0mykzGZ7zvcMP7h05W6UcgzfT9Ca1SW2xyKDOFRyI0pQeRNZGw==" + "version": "1.5.50", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.50.tgz", + "integrity": "sha512-eMVObiUQ2LdgeO1F/ySTXsvqvxb6ZH2zPGaMYsWzRDdOddUa77tdmI0ltg+L16UpbWdhPmuF3wIQYyQq65WfZw==" }, "emoji-regex": { "version": "8.0.0", @@ -14500,9 +14494,9 @@ } }, "enhanced-resolve": { - "version": "5.13.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.13.0.tgz", - "integrity": "sha512-eyV8f0y1+bzyfh8xAwW/WTSZpLbjhqc4ne9eGSH4Zo2ejdyiNG9pU6mf9DG8a7+Auk6MFTlNOT4Y2y/9k8GKVg==", + "version": "5.17.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", + "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", "peer": true, "requires": { "graceful-fs": "^4.2.4", @@ -14538,9 +14532,9 @@ "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==" }, "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==" }, "escape-string-regexp": { "version": "1.0.5", @@ -16564,9 +16558,9 @@ } }, "node-releases": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", - "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==" + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==" }, "normalize-url": { "version": "6.1.0", @@ -16821,9 +16815,9 @@ "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==" }, "picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" }, "picomatch": { "version": "2.3.1", @@ -17395,9 +17389,9 @@ "integrity": "sha512-TcZvGMMy9vodEFSse30lWinkj+JgOBvPn8wRItpQRSayhc+4ssDs335uklkfvQQJgL/WvmHLVj4Ycv2s7QCQMg==" }, "serialize-javascript": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", - "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", "peer": true, "requires": { "randombytes": "^2.1.0" @@ -17701,21 +17695,21 @@ } }, "terser": { - "version": "5.17.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.17.1.tgz", - "integrity": "sha512-hVl35zClmpisy6oaoKALOpS0rDYLxRFLHhRuDlEGTKey9qHjS1w9GMORjuwIMt70Wan4lwsLYyWDVnWgF+KUEw==", + "version": "5.36.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.36.0.tgz", + "integrity": "sha512-IYV9eNMuFAV4THUspIRXkLakHnV6XO7FEdtKjf/mDyrnqUg9LnlOn6/RwRvM9SZjR4GUq8Nk8zj67FzVARr74w==", "peer": true, "requires": { - "@jridgewell/source-map": "^0.3.2", - "acorn": "^8.5.0", + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, "dependencies": { "acorn": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", - "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", "peer": true }, "commander": { @@ -17727,22 +17721,22 @@ } }, "terser-webpack-plugin": { - "version": "5.3.7", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.7.tgz", - "integrity": "sha512-AfKwIktyP7Cu50xNjXF/6Qb5lBNzYaWpU6YfoX3uZicTx0zTy0stDDCsvjDapKsSDvOeWo5MEq4TmdBy2cNoHw==", + "version": "5.3.10", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", + "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", "peer": true, "requires": { - "@jridgewell/trace-mapping": "^0.3.17", + "@jridgewell/trace-mapping": "^0.3.20", "jest-worker": "^27.4.5", "schema-utils": "^3.1.1", "serialize-javascript": "^6.0.1", - "terser": "^5.16.5" + "terser": "^5.26.0" }, "dependencies": { "schema-utils": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.2.tgz", - "integrity": "sha512-pvjEHOgWc9OWA/f/DE3ohBWTD6EleVLf7iFUkoSwAxttdBhB9QUebQgxER2kWueOvRJXPHNnyrvvh9eZINB8Eg==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", "peer": true, "requires": { "@types/json-schema": "^7.0.8", @@ -17999,12 +17993,12 @@ "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==" }, "update-browserslist-db": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", - "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", + "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", "requires": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" + "escalade": "^3.2.0", + "picocolors": "^1.1.0" } }, "uri-js": { @@ -18087,9 +18081,9 @@ } }, "watchpack": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", - "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz", + "integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==", "peer": true, "requires": { "glob-to-regexp": "^0.4.1", @@ -18138,54 +18132,46 @@ "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" }, "webpack": { - "version": "5.80.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.80.0.tgz", - "integrity": "sha512-OIMiq37XK1rWO8mH9ssfFKZsXg4n6klTEDL7S8/HqbAOBBaiy8ABvXvz0dDCXeEF9gqwxSvVk611zFPjS8hJxA==", - "peer": true, - "requires": { - "@types/eslint-scope": "^3.7.3", - "@types/estree": "^1.0.0", - "@webassemblyjs/ast": "^1.11.5", - "@webassemblyjs/wasm-edit": "^1.11.5", - "@webassemblyjs/wasm-parser": "^1.11.5", - "acorn": "^8.7.1", - "acorn-import-assertions": "^1.7.6", - "browserslist": "^4.14.5", + "version": "5.96.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.96.1.tgz", + "integrity": "sha512-l2LlBSvVZGhL4ZrPwyr8+37AunkcYj5qh8o6u2/2rzoPc8gxFJkLj1WxNgooi9pnoc06jh0BjuXnamM4qlujZA==", + "peer": true, + "requires": { + "@types/eslint-scope": "^3.7.7", + "@types/estree": "^1.0.6", + "@webassemblyjs/ast": "^1.12.1", + "@webassemblyjs/wasm-edit": "^1.12.1", + "@webassemblyjs/wasm-parser": "^1.12.1", + "acorn": "^8.14.0", + "browserslist": "^4.24.0", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.13.0", + "enhanced-resolve": "^5.17.1", "es-module-lexer": "^1.2.1", "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.9", + "graceful-fs": "^4.2.11", "json-parse-even-better-errors": "^2.3.1", "loader-runner": "^4.2.0", "mime-types": "^2.1.27", "neo-async": "^2.6.2", - "schema-utils": "^3.1.2", + "schema-utils": "^3.2.0", "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.3.7", - "watchpack": "^2.4.0", + "terser-webpack-plugin": "^5.3.10", + "watchpack": "^2.4.1", "webpack-sources": "^3.2.3" }, "dependencies": { "acorn": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", - "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", "peer": true }, - "acorn-import-assertions": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", - "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", - "peer": true, - "requires": {} - }, "schema-utils": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.2.tgz", - "integrity": "sha512-pvjEHOgWc9OWA/f/DE3ohBWTD6EleVLf7iFUkoSwAxttdBhB9QUebQgxER2kWueOvRJXPHNnyrvvh9eZINB8Eg==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", "peer": true, "requires": { "@types/json-schema": "^7.0.8", From b73ee7f2e0296361aa98317d02d6838a1a4fe784 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Nov 2024 10:01:23 -0700 Subject: [PATCH 043/307] build(deps-dev): bump prettier-plugin-packagejson from 2.5.2 to 2.5.3 in /superset-frontend (#30809) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- superset-frontend/package-lock.json | 42 ++++++++++++++--------------- superset-frontend/package.json | 2 +- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/superset-frontend/package-lock.json b/superset-frontend/package-lock.json index eef1b1443c6f4..5dba423ff3b66 100644 --- a/superset-frontend/package-lock.json +++ b/superset-frontend/package-lock.json @@ -270,7 +270,7 @@ "open-cli": "^8.0.0", "po2json": "^0.4.5", "prettier": "3.3.3", - "prettier-plugin-packagejson": "^2.5.2", + "prettier-plugin-packagejson": "^2.5.3", "process": "^0.11.10", "react-resizable": "^3.0.5", "react-test-renderer": "^16.14.0", @@ -44220,13 +44220,13 @@ } }, "node_modules/prettier-plugin-packagejson": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/prettier-plugin-packagejson/-/prettier-plugin-packagejson-2.5.2.tgz", - "integrity": "sha512-w+TmoLv2pIa+siplW1cCj2ujEXQQS6z7wmWLOiLQK/2QVl7Wy6xh/ZUpqQw8tbKMXDodmSW4GONxlA33xpdNOg==", + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/prettier-plugin-packagejson/-/prettier-plugin-packagejson-2.5.3.tgz", + "integrity": "sha512-ATMEEXr+ywls1kgrZEWl4SBPEm0uDdyDAjyNzUC0/Z8WZTD3RqbJcQDR+Dau+wYkW9KHK6zqQIsFyfn+9aduWg==", "dev": true, "dependencies": { "sort-package-json": "2.10.1", - "synckit": "0.9.1" + "synckit": "0.9.2" }, "peerDependencies": { "prettier": ">= 1.16.0" @@ -50847,9 +50847,9 @@ "license": "MIT" }, "node_modules/synckit": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.1.tgz", - "integrity": "sha512-7gr8p9TQP6RAHusBOSLs46F4564ZrjV8xFmw5zCmgmhGUcw2hxsShhJ6CEiHQMgPDwAQ1fWHPM0ypc4RMAig4A==", + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.2.tgz", + "integrity": "sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw==", "dev": true, "dependencies": { "@pkgr/core": "^0.1.0", @@ -50863,9 +50863,9 @@ } }, "node_modules/synckit/node_modules/tslib": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", - "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "dev": true }, "node_modules/tapable": { @@ -89435,13 +89435,13 @@ } }, "prettier-plugin-packagejson": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/prettier-plugin-packagejson/-/prettier-plugin-packagejson-2.5.2.tgz", - "integrity": "sha512-w+TmoLv2pIa+siplW1cCj2ujEXQQS6z7wmWLOiLQK/2QVl7Wy6xh/ZUpqQw8tbKMXDodmSW4GONxlA33xpdNOg==", + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/prettier-plugin-packagejson/-/prettier-plugin-packagejson-2.5.3.tgz", + "integrity": "sha512-ATMEEXr+ywls1kgrZEWl4SBPEm0uDdyDAjyNzUC0/Z8WZTD3RqbJcQDR+Dau+wYkW9KHK6zqQIsFyfn+9aduWg==", "dev": true, "requires": { "sort-package-json": "2.10.1", - "synckit": "0.9.1" + "synckit": "0.9.2" } }, "pretty-bytes": { @@ -93733,9 +93733,9 @@ "dev": true }, "synckit": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.1.tgz", - "integrity": "sha512-7gr8p9TQP6RAHusBOSLs46F4564ZrjV8xFmw5zCmgmhGUcw2hxsShhJ6CEiHQMgPDwAQ1fWHPM0ypc4RMAig4A==", + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.2.tgz", + "integrity": "sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw==", "dev": true, "requires": { "@pkgr/core": "^0.1.0", @@ -93743,9 +93743,9 @@ }, "dependencies": { "tslib": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", - "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "dev": true } } diff --git a/superset-frontend/package.json b/superset-frontend/package.json index 828a25b19d35d..ec7457047b54f 100644 --- a/superset-frontend/package.json +++ b/superset-frontend/package.json @@ -336,7 +336,7 @@ "open-cli": "^8.0.0", "po2json": "^0.4.5", "prettier": "3.3.3", - "prettier-plugin-packagejson": "^2.5.2", + "prettier-plugin-packagejson": "^2.5.3", "process": "^0.11.10", "react-resizable": "^3.0.5", "react-test-renderer": "^16.14.0", From 2a96a9c734d3d61420e2c551dc5003df8fa64384 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Nov 2024 10:11:54 -0700 Subject: [PATCH 044/307] build(deps-dev): bump typescript-eslint from 8.8.0 to 8.12.2 in /superset-websocket (#30781) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- superset-websocket/package-lock.json | 197 +++++++++++++-------------- superset-websocket/package.json | 2 +- 2 files changed, 98 insertions(+), 101 deletions(-) diff --git a/superset-websocket/package-lock.json b/superset-websocket/package-lock.json index 78bcdae9f7402..0f988f555b1d8 100644 --- a/superset-websocket/package-lock.json +++ b/superset-websocket/package-lock.json @@ -40,7 +40,7 @@ "ts-jest": "^29.2.5", "ts-node": "^10.9.2", "typescript": "^5.6.2", - "typescript-eslint": "^8.8.0" + "typescript-eslint": "^8.12.2" }, "engines": { "node": "^16.9.1", @@ -1817,16 +1817,16 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.8.0.tgz", - "integrity": "sha512-wORFWjU30B2WJ/aXBfOm1LX9v9nyt9D3jsSOxC3cCaTQGCW5k4jNpmjFv3U7p/7s4yvdjHzwtv2Sd2dOyhjS0A==", + "version": "8.12.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.12.2.tgz", + "integrity": "sha512-gQxbxM8mcxBwaEmWdtLCIGLfixBMHhQjBqR8sVWNTPpcj45WlYL2IObS/DNMLH1DBP0n8qz+aiiLTGfopPEebw==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.8.0", - "@typescript-eslint/type-utils": "8.8.0", - "@typescript-eslint/utils": "8.8.0", - "@typescript-eslint/visitor-keys": "8.8.0", + "@typescript-eslint/scope-manager": "8.12.2", + "@typescript-eslint/type-utils": "8.12.2", + "@typescript-eslint/utils": "8.12.2", + "@typescript-eslint/visitor-keys": "8.12.2", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -1850,15 +1850,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.8.0.tgz", - "integrity": "sha512-uEFUsgR+tl8GmzmLjRqz+VrDv4eoaMqMXW7ruXfgThaAShO9JTciKpEsB+TvnfFfbg5IpujgMXVV36gOJRLtZg==", + "version": "8.12.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.12.2.tgz", + "integrity": "sha512-MrvlXNfGPLH3Z+r7Tk+Z5moZAc0dzdVjTgUgwsdGweH7lydysQsnSww3nAmsq8blFuRD5VRlAr9YdEFw3e6PBw==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "8.8.0", - "@typescript-eslint/types": "8.8.0", - "@typescript-eslint/typescript-estree": "8.8.0", - "@typescript-eslint/visitor-keys": "8.8.0", + "@typescript-eslint/scope-manager": "8.12.2", + "@typescript-eslint/types": "8.12.2", + "@typescript-eslint/typescript-estree": "8.12.2", + "@typescript-eslint/visitor-keys": "8.12.2", "debug": "^4.3.4" }, "engines": { @@ -1878,13 +1878,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.8.0.tgz", - "integrity": "sha512-EL8eaGC6gx3jDd8GwEFEV091210U97J0jeEHrAYvIYosmEGet4wJ+g0SYmLu+oRiAwbSA5AVrt6DxLHfdd+bUg==", + "version": "8.12.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.12.2.tgz", + "integrity": "sha512-gPLpLtrj9aMHOvxJkSbDBmbRuYdtiEbnvO25bCMza3DhMjTQw0u7Y1M+YR5JPbMsXXnSPuCf5hfq0nEkQDL/JQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "8.8.0", - "@typescript-eslint/visitor-keys": "8.8.0" + "@typescript-eslint/types": "8.12.2", + "@typescript-eslint/visitor-keys": "8.12.2" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1895,13 +1895,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.8.0.tgz", - "integrity": "sha512-IKwJSS7bCqyCeG4NVGxnOP6lLT9Okc3Zj8hLO96bpMkJab+10HIfJbMouLrlpyOr3yrQ1cA413YPFiGd1mW9/Q==", + "version": "8.12.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.12.2.tgz", + "integrity": "sha512-bwuU4TAogPI+1q/IJSKuD4shBLc/d2vGcRT588q+jzayQyjVK2X6v/fbR4InY2U2sgf8MEvVCqEWUzYzgBNcGQ==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "8.8.0", - "@typescript-eslint/utils": "8.8.0", + "@typescript-eslint/typescript-estree": "8.12.2", + "@typescript-eslint/utils": "8.12.2", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -1919,9 +1919,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.8.0.tgz", - "integrity": "sha512-QJwc50hRCgBd/k12sTykOJbESe1RrzmX6COk8Y525C9l7oweZ+1lw9JiU56im7Amm8swlz00DRIlxMYLizr2Vw==", + "version": "8.12.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.12.2.tgz", + "integrity": "sha512-VwDwMF1SZ7wPBUZwmMdnDJ6sIFk4K4s+ALKLP6aIQsISkPv8jhiw65sAK6SuWODN/ix+m+HgbYDkH+zLjrzvOA==", "dev": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1932,13 +1932,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.8.0.tgz", - "integrity": "sha512-ZaMJwc/0ckLz5DaAZ+pNLmHv8AMVGtfWxZe/x2JVEkD5LnmhWiQMMcYT7IY7gkdJuzJ9P14fRy28lUrlDSWYdw==", + "version": "8.12.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.12.2.tgz", + "integrity": "sha512-mME5MDwGe30Pq9zKPvyduyU86PH7aixwqYR2grTglAdB+AN8xXQ1vFGpYaUSJ5o5P/5znsSBeNcs5g5/2aQwow==", "dev": true, "dependencies": { - "@typescript-eslint/types": "8.8.0", - "@typescript-eslint/visitor-keys": "8.8.0", + "@typescript-eslint/types": "8.12.2", + "@typescript-eslint/visitor-keys": "8.12.2", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", @@ -1984,15 +1984,15 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.8.0.tgz", - "integrity": "sha512-QE2MgfOTem00qrlPgyByaCHay9yb1+9BjnMFnSFkUKQfu7adBXDTnCAivURnuPPAG/qiB+kzKkZKmKfaMT0zVg==", + "version": "8.12.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.12.2.tgz", + "integrity": "sha512-UTTuDIX3fkfAz6iSVa5rTuSfWIYZ6ATtEocQ/umkRSyC9O919lbZ8dcH7mysshrCdrAM03skJOEYaBugxN+M6A==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.8.0", - "@typescript-eslint/types": "8.8.0", - "@typescript-eslint/typescript-estree": "8.8.0" + "@typescript-eslint/scope-manager": "8.12.2", + "@typescript-eslint/types": "8.12.2", + "@typescript-eslint/typescript-estree": "8.12.2" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2006,12 +2006,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.8.0.tgz", - "integrity": "sha512-8mq51Lx6Hpmd7HnA2fcHQo3YgfX1qbccxQOgZcb4tvasu//zXRaA1j5ZRFeCw/VRAdFi4mRM9DnZw0Nu0Q2d1g==", + "version": "8.12.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.12.2.tgz", + "integrity": "sha512-PChz8UaKQAVNHghsHcPyx1OMHoFRUEA7rJSK/mDhdq85bk+PLsUHUBqTQTFt18VJZbmxBovM65fezlheQRsSDA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "8.8.0", + "@typescript-eslint/types": "8.12.2", "eslint-visitor-keys": "^3.4.3" }, "engines": { @@ -3071,7 +3071,6 @@ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", "dev": true, - "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -3308,7 +3307,6 @@ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, - "license": "ISC", "dependencies": { "is-glob": "^4.0.1" }, @@ -5182,7 +5180,6 @@ "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "dev": true, - "license": "MIT", "engines": { "node": ">= 8" } @@ -6152,14 +6149,14 @@ } }, "node_modules/typescript-eslint": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.8.0.tgz", - "integrity": "sha512-BjIT/VwJ8+0rVO01ZQ2ZVnjE1svFBiRczcpr1t1Yxt7sT25VSbPfrJtDsQ8uQTy2pilX5nI9gwxhUyLULNentw==", + "version": "8.12.2", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.12.2.tgz", + "integrity": "sha512-UbuVUWSrHVR03q9CWx+JDHeO6B/Hr9p4U5lRH++5tq/EbFq1faYZe50ZSBePptgfIKLEti0aPQ3hFgnPVcd8ZQ==", "dev": true, "dependencies": { - "@typescript-eslint/eslint-plugin": "8.8.0", - "@typescript-eslint/parser": "8.8.0", - "@typescript-eslint/utils": "8.8.0" + "@typescript-eslint/eslint-plugin": "8.12.2", + "@typescript-eslint/parser": "8.12.2", + "@typescript-eslint/utils": "8.12.2" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -7869,16 +7866,16 @@ "dev": true }, "@typescript-eslint/eslint-plugin": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.8.0.tgz", - "integrity": "sha512-wORFWjU30B2WJ/aXBfOm1LX9v9nyt9D3jsSOxC3cCaTQGCW5k4jNpmjFv3U7p/7s4yvdjHzwtv2Sd2dOyhjS0A==", + "version": "8.12.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.12.2.tgz", + "integrity": "sha512-gQxbxM8mcxBwaEmWdtLCIGLfixBMHhQjBqR8sVWNTPpcj45WlYL2IObS/DNMLH1DBP0n8qz+aiiLTGfopPEebw==", "dev": true, "requires": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.8.0", - "@typescript-eslint/type-utils": "8.8.0", - "@typescript-eslint/utils": "8.8.0", - "@typescript-eslint/visitor-keys": "8.8.0", + "@typescript-eslint/scope-manager": "8.12.2", + "@typescript-eslint/type-utils": "8.12.2", + "@typescript-eslint/utils": "8.12.2", + "@typescript-eslint/visitor-keys": "8.12.2", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -7886,54 +7883,54 @@ } }, "@typescript-eslint/parser": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.8.0.tgz", - "integrity": "sha512-uEFUsgR+tl8GmzmLjRqz+VrDv4eoaMqMXW7ruXfgThaAShO9JTciKpEsB+TvnfFfbg5IpujgMXVV36gOJRLtZg==", + "version": "8.12.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.12.2.tgz", + "integrity": "sha512-MrvlXNfGPLH3Z+r7Tk+Z5moZAc0dzdVjTgUgwsdGweH7lydysQsnSww3nAmsq8blFuRD5VRlAr9YdEFw3e6PBw==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "8.8.0", - "@typescript-eslint/types": "8.8.0", - "@typescript-eslint/typescript-estree": "8.8.0", - "@typescript-eslint/visitor-keys": "8.8.0", + "@typescript-eslint/scope-manager": "8.12.2", + "@typescript-eslint/types": "8.12.2", + "@typescript-eslint/typescript-estree": "8.12.2", + "@typescript-eslint/visitor-keys": "8.12.2", "debug": "^4.3.4" } }, "@typescript-eslint/scope-manager": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.8.0.tgz", - "integrity": "sha512-EL8eaGC6gx3jDd8GwEFEV091210U97J0jeEHrAYvIYosmEGet4wJ+g0SYmLu+oRiAwbSA5AVrt6DxLHfdd+bUg==", + "version": "8.12.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.12.2.tgz", + "integrity": "sha512-gPLpLtrj9aMHOvxJkSbDBmbRuYdtiEbnvO25bCMza3DhMjTQw0u7Y1M+YR5JPbMsXXnSPuCf5hfq0nEkQDL/JQ==", "dev": true, "requires": { - "@typescript-eslint/types": "8.8.0", - "@typescript-eslint/visitor-keys": "8.8.0" + "@typescript-eslint/types": "8.12.2", + "@typescript-eslint/visitor-keys": "8.12.2" } }, "@typescript-eslint/type-utils": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.8.0.tgz", - "integrity": "sha512-IKwJSS7bCqyCeG4NVGxnOP6lLT9Okc3Zj8hLO96bpMkJab+10HIfJbMouLrlpyOr3yrQ1cA413YPFiGd1mW9/Q==", + "version": "8.12.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.12.2.tgz", + "integrity": "sha512-bwuU4TAogPI+1q/IJSKuD4shBLc/d2vGcRT588q+jzayQyjVK2X6v/fbR4InY2U2sgf8MEvVCqEWUzYzgBNcGQ==", "dev": true, "requires": { - "@typescript-eslint/typescript-estree": "8.8.0", - "@typescript-eslint/utils": "8.8.0", + "@typescript-eslint/typescript-estree": "8.12.2", + "@typescript-eslint/utils": "8.12.2", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" } }, "@typescript-eslint/types": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.8.0.tgz", - "integrity": "sha512-QJwc50hRCgBd/k12sTykOJbESe1RrzmX6COk8Y525C9l7oweZ+1lw9JiU56im7Amm8swlz00DRIlxMYLizr2Vw==", + "version": "8.12.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.12.2.tgz", + "integrity": "sha512-VwDwMF1SZ7wPBUZwmMdnDJ6sIFk4K4s+ALKLP6aIQsISkPv8jhiw65sAK6SuWODN/ix+m+HgbYDkH+zLjrzvOA==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.8.0.tgz", - "integrity": "sha512-ZaMJwc/0ckLz5DaAZ+pNLmHv8AMVGtfWxZe/x2JVEkD5LnmhWiQMMcYT7IY7gkdJuzJ9P14fRy28lUrlDSWYdw==", + "version": "8.12.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.12.2.tgz", + "integrity": "sha512-mME5MDwGe30Pq9zKPvyduyU86PH7aixwqYR2grTglAdB+AN8xXQ1vFGpYaUSJ5o5P/5znsSBeNcs5g5/2aQwow==", "dev": true, "requires": { - "@typescript-eslint/types": "8.8.0", - "@typescript-eslint/visitor-keys": "8.8.0", + "@typescript-eslint/types": "8.12.2", + "@typescript-eslint/visitor-keys": "8.12.2", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", @@ -7963,24 +7960,24 @@ } }, "@typescript-eslint/utils": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.8.0.tgz", - "integrity": "sha512-QE2MgfOTem00qrlPgyByaCHay9yb1+9BjnMFnSFkUKQfu7adBXDTnCAivURnuPPAG/qiB+kzKkZKmKfaMT0zVg==", + "version": "8.12.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.12.2.tgz", + "integrity": "sha512-UTTuDIX3fkfAz6iSVa5rTuSfWIYZ6ATtEocQ/umkRSyC9O919lbZ8dcH7mysshrCdrAM03skJOEYaBugxN+M6A==", "dev": true, "requires": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.8.0", - "@typescript-eslint/types": "8.8.0", - "@typescript-eslint/typescript-estree": "8.8.0" + "@typescript-eslint/scope-manager": "8.12.2", + "@typescript-eslint/types": "8.12.2", + "@typescript-eslint/typescript-estree": "8.12.2" } }, "@typescript-eslint/visitor-keys": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.8.0.tgz", - "integrity": "sha512-8mq51Lx6Hpmd7HnA2fcHQo3YgfX1qbccxQOgZcb4tvasu//zXRaA1j5ZRFeCw/VRAdFi4mRM9DnZw0Nu0Q2d1g==", + "version": "8.12.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.12.2.tgz", + "integrity": "sha512-PChz8UaKQAVNHghsHcPyx1OMHoFRUEA7rJSK/mDhdq85bk+PLsUHUBqTQTFt18VJZbmxBovM65fezlheQRsSDA==", "dev": true, "requires": { - "@typescript-eslint/types": "8.8.0", + "@typescript-eslint/types": "8.12.2", "eslint-visitor-keys": "^3.4.3" } }, @@ -11039,14 +11036,14 @@ "dev": true }, "typescript-eslint": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.8.0.tgz", - "integrity": "sha512-BjIT/VwJ8+0rVO01ZQ2ZVnjE1svFBiRczcpr1t1Yxt7sT25VSbPfrJtDsQ8uQTy2pilX5nI9gwxhUyLULNentw==", + "version": "8.12.2", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.12.2.tgz", + "integrity": "sha512-UbuVUWSrHVR03q9CWx+JDHeO6B/Hr9p4U5lRH++5tq/EbFq1faYZe50ZSBePptgfIKLEti0aPQ3hFgnPVcd8ZQ==", "dev": true, "requires": { - "@typescript-eslint/eslint-plugin": "8.8.0", - "@typescript-eslint/parser": "8.8.0", - "@typescript-eslint/utils": "8.8.0" + "@typescript-eslint/eslint-plugin": "8.12.2", + "@typescript-eslint/parser": "8.12.2", + "@typescript-eslint/utils": "8.12.2" } }, "undici-types": { diff --git a/superset-websocket/package.json b/superset-websocket/package.json index 47bf01856e82b..9222c8c5b89d7 100644 --- a/superset-websocket/package.json +++ b/superset-websocket/package.json @@ -48,7 +48,7 @@ "ts-jest": "^29.2.5", "ts-node": "^10.9.2", "typescript": "^5.6.2", - "typescript-eslint": "^8.8.0" + "typescript-eslint": "^8.12.2" }, "engines": { "node": "^16.9.1", From 8b815a3aac4837917a476ac5438d5b978953162b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Nov 2024 10:15:00 -0700 Subject: [PATCH 045/307] build(deps-dev): bump eslint-plugin-react from 7.33.2 to 7.37.2 in /superset-frontend (#30803) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- superset-frontend/package-lock.json | 1046 ++++++++++++++++++--------- superset-frontend/package.json | 2 +- 2 files changed, 700 insertions(+), 348 deletions(-) diff --git a/superset-frontend/package-lock.json b/superset-frontend/package-lock.json index 5dba423ff3b66..472a8f2ec3659 100644 --- a/superset-frontend/package-lock.json +++ b/superset-frontend/package-lock.json @@ -240,7 +240,7 @@ "eslint-plugin-lodash": "^7.4.0", "eslint-plugin-no-only-tests": "^3.3.0", "eslint-plugin-prettier": "^5.1.3", - "eslint-plugin-react": "^7.22.0", + "eslint-plugin-react": "^7.37.2", "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-prefer-function-component": "^3.3.0", "eslint-plugin-storybook": "^0.8.0", @@ -17094,14 +17094,16 @@ "license": "MIT" }, "node_modules/array-includes": { - "version": "3.1.7", + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz", + "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", "dev": true, - "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1", + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", "is-string": "^1.0.7" }, "engines": { @@ -17170,6 +17172,26 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/array.prototype.findlast": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", + "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/array.prototype.findlastindex": { "version": "1.2.4", "dev": true, @@ -17223,15 +17245,19 @@ } }, "node_modules/array.prototype.tosorted": { - "version": "1.1.3", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", + "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", "dev": true, - "license": "MIT", "dependencies": { - "call-bind": "^1.0.5", + "call-bind": "^1.0.7", "define-properties": "^1.2.1", - "es-abstract": "^1.22.3", - "es-errors": "^1.1.0", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" } }, "node_modules/arraybuffer.prototype.slice": { @@ -17352,14 +17378,6 @@ "version": "3.5.1", "license": "MIT" }, - "node_modules/asynciterator.prototype": { - "version": "1.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "has-symbols": "^1.0.3" - } - }, "node_modules/asynckit": { "version": "0.4.0", "dev": true, @@ -17394,8 +17412,12 @@ } }, "node_modules/available-typed-arrays": { - "version": "1.0.6", - "license": "MIT", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, "engines": { "node": ">= 0.4" }, @@ -21693,6 +21715,57 @@ "node": ">=18" } }, + "node_modules/data-view-buffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", + "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", + "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz", + "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/datamaps": { "version": "0.5.9", "license": "MIT", @@ -23243,17 +23316,22 @@ } }, "node_modules/es-abstract": { - "version": "1.22.4", + "version": "1.23.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz", + "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==", "dev": true, - "license": "MIT", "dependencies": { "array-buffer-byte-length": "^1.0.1", "arraybuffer.prototype.slice": "^1.0.3", - "available-typed-arrays": "^1.0.6", + "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.7", + "data-view-buffer": "^1.0.1", + "data-view-byte-length": "^1.0.1", + "data-view-byte-offset": "^1.0.0", "es-define-property": "^1.0.0", "es-errors": "^1.3.0", - "es-set-tostringtag": "^2.0.2", + "es-object-atoms": "^1.0.0", + "es-set-tostringtag": "^2.0.3", "es-to-primitive": "^1.2.1", "function.prototype.name": "^1.1.6", "get-intrinsic": "^1.2.4", @@ -23261,15 +23339,16 @@ "globalthis": "^1.0.3", "gopd": "^1.0.1", "has-property-descriptors": "^1.0.2", - "has-proto": "^1.0.1", + "has-proto": "^1.0.3", "has-symbols": "^1.0.3", - "hasown": "^2.0.1", + "hasown": "^2.0.2", "internal-slot": "^1.0.7", "is-array-buffer": "^3.0.4", "is-callable": "^1.2.7", - "is-negative-zero": "^2.0.2", + "is-data-view": "^1.0.1", + "is-negative-zero": "^2.0.3", "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", + "is-shared-array-buffer": "^1.0.3", "is-string": "^1.0.7", "is-typed-array": "^1.1.13", "is-weakref": "^1.0.2", @@ -23277,17 +23356,17 @@ "object-keys": "^1.1.1", "object.assign": "^4.1.5", "regexp.prototype.flags": "^1.5.2", - "safe-array-concat": "^1.1.0", + "safe-array-concat": "^1.1.2", "safe-regex-test": "^1.0.3", - "string.prototype.trim": "^1.2.8", - "string.prototype.trimend": "^1.0.7", - "string.prototype.trimstart": "^1.0.7", - "typed-array-buffer": "^1.0.1", - "typed-array-byte-length": "^1.0.0", - "typed-array-byte-offset": "^1.0.0", - "typed-array-length": "^1.0.4", + "string.prototype.trim": "^1.2.9", + "string.prototype.trimend": "^1.0.8", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.2", + "typed-array-byte-length": "^1.0.1", + "typed-array-byte-offset": "^1.0.2", + "typed-array-length": "^1.0.6", "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.14" + "which-typed-array": "^1.1.15" }, "engines": { "node": ">= 0.4" @@ -23351,25 +23430,25 @@ "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" }, "node_modules/es-iterator-helpers": { - "version": "1.0.17", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.1.0.tgz", + "integrity": "sha512-/SurEfycdyssORP/E+bj4sEu1CWw4EmLDsHynHwSXQ7utgbrMRWW195pTrCjFgFCddf/UkYm3oqKPRq5i8bJbw==", "dev": true, - "license": "MIT", "dependencies": { - "asynciterator.prototype": "^1.0.0", "call-bind": "^1.0.7", "define-properties": "^1.2.1", - "es-abstract": "^1.22.4", + "es-abstract": "^1.23.3", "es-errors": "^1.3.0", - "es-set-tostringtag": "^2.0.2", + "es-set-tostringtag": "^2.0.3", "function-bind": "^1.1.2", "get-intrinsic": "^1.2.4", - "globalthis": "^1.0.3", + "globalthis": "^1.0.4", "has-property-descriptors": "^1.0.2", - "has-proto": "^1.0.1", + "has-proto": "^1.0.3", "has-symbols": "^1.0.3", "internal-slot": "^1.0.7", - "iterator.prototype": "^1.1.2", - "safe-array-concat": "^1.1.0" + "iterator.prototype": "^1.1.3", + "safe-array-concat": "^1.1.2" }, "engines": { "node": ">= 0.4" @@ -23380,14 +23459,27 @@ "devOptional": true, "license": "MIT" }, + "node_modules/es-object-atoms": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", + "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/es-set-tostringtag": { - "version": "2.0.2", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", + "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", "dev": true, - "license": "MIT", "dependencies": { - "get-intrinsic": "^1.2.2", - "has-tostringtag": "^1.0.0", - "hasown": "^2.0.0" + "get-intrinsic": "^1.2.4", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.1" }, "engines": { "node": ">= 0.4" @@ -24561,32 +24653,35 @@ "license": "0BSD" }, "node_modules/eslint-plugin-react": { - "version": "7.33.2", + "version": "7.37.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.2.tgz", + "integrity": "sha512-EsTAnj9fLVr/GZleBLFbj/sSuXeWmp1eXIN60ceYnZveqEaUCyW4X+Vh4WTdUhCkW4xutXYqTXCUSyqD4rB75w==", "dev": true, - "license": "MIT", "dependencies": { - "array-includes": "^3.1.6", - "array.prototype.flatmap": "^1.3.1", - "array.prototype.tosorted": "^1.1.1", + "array-includes": "^3.1.8", + "array.prototype.findlast": "^1.2.5", + "array.prototype.flatmap": "^1.3.2", + "array.prototype.tosorted": "^1.1.4", "doctrine": "^2.1.0", - "es-iterator-helpers": "^1.0.12", + "es-iterator-helpers": "^1.1.0", "estraverse": "^5.3.0", + "hasown": "^2.0.2", "jsx-ast-utils": "^2.4.1 || ^3.0.0", "minimatch": "^3.1.2", - "object.entries": "^1.1.6", - "object.fromentries": "^2.0.6", - "object.hasown": "^1.1.2", - "object.values": "^1.1.6", + "object.entries": "^1.1.8", + "object.fromentries": "^2.0.8", + "object.values": "^1.2.0", "prop-types": "^15.8.1", - "resolve": "^2.0.0-next.4", + "resolve": "^2.0.0-next.5", "semver": "^6.3.1", - "string.prototype.matchall": "^4.0.8" + "string.prototype.matchall": "^4.0.11", + "string.prototype.repeat": "^1.0.0" }, "engines": { "node": ">=4" }, "peerDependencies": { - "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" } }, "node_modules/eslint-plugin-react-hooks": { @@ -27687,11 +27782,13 @@ } }, "node_modules/globalthis": { - "version": "1.0.3", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", "dev": true, - "license": "MIT", "dependencies": { - "define-properties": "^1.1.3" + "define-properties": "^1.2.1", + "gopd": "^1.0.1" }, "engines": { "node": ">= 0.4" @@ -28010,8 +28107,9 @@ } }, "node_modules/has-proto": { - "version": "1.0.1", - "license": "MIT", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", "engines": { "node": ">= 0.4" }, @@ -28113,8 +28211,9 @@ } }, "node_modules/hasown": { - "version": "2.0.1", - "license": "MIT", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "dependencies": { "function-bind": "^1.1.2" }, @@ -29581,8 +29680,9 @@ }, "node_modules/is-async-function": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz", + "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==", "dev": true, - "license": "MIT", "dependencies": { "has-tostringtag": "^1.0.0" }, @@ -29696,6 +29796,21 @@ "node": ">=0.10.0" } }, + "node_modules/is-data-view": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz", + "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==", + "dev": true, + "dependencies": { + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-date-object": { "version": "1.0.5", "license": "MIT", @@ -29766,8 +29881,9 @@ }, "node_modules/is-finalizationregistry": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz", + "integrity": "sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.2" }, @@ -29898,8 +30014,12 @@ } }, "node_modules/is-map": { - "version": "2.0.2", - "license": "MIT", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -29919,9 +30039,10 @@ } }, "node_modules/is-negative-zero": { - "version": "2.0.2", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -30028,17 +30149,25 @@ } }, "node_modules/is-set": { - "version": "2.0.2", - "license": "MIT", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/is-shared-array-buffer": { - "version": "1.0.2", - "license": "MIT", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", + "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", "dependencies": { - "call-bind": "^1.0.2" + "call-bind": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -30137,8 +30266,12 @@ "license": "MIT" }, "node_modules/is-weakmap": { - "version": "2.0.1", - "license": "MIT", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -30155,11 +30288,15 @@ } }, "node_modules/is-weakset": { - "version": "2.0.2", - "license": "MIT", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.3.tgz", + "integrity": "sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==", "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -30493,15 +30630,19 @@ } }, "node_modules/iterator.prototype": { - "version": "1.1.2", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.3.tgz", + "integrity": "sha512-FW5iMbeQ6rBGm/oKgzq2aW4KvAGpxPzYES8N4g4xNXUKpL1mclMvOe+76AcLDTvD+Ze+sOpVhgdAQEKF4L9iGQ==", "dev": true, - "license": "MIT", "dependencies": { "define-properties": "^1.2.1", "get-intrinsic": "^1.2.1", "has-symbols": "^1.0.3", "reflect.getprototypeof": "^1.0.4", "set-function-name": "^2.0.1" + }, + "engines": { + "node": ">= 0.4" } }, "node_modules/jackspeak": { @@ -42205,26 +42346,29 @@ } }, "node_modules/object.entries": { - "version": "1.1.6", + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.8.tgz", + "integrity": "sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==", "dev": true, - "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" }, "engines": { "node": ">= 0.4" } }, "node_modules/object.fromentries": { - "version": "2.0.7", + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", "dev": true, - "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -42261,18 +42405,6 @@ "es-errors": "^1.0.0" } }, - "node_modules/object.hasown": { - "version": "1.1.3", - "dev": true, - "license": "MIT", - "dependencies": { - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/object.pick": { "version": "1.3.0", "dev": true, @@ -42285,13 +42417,14 @@ } }, "node_modules/object.values": { - "version": "1.1.7", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz", + "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==", "dev": true, - "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -43673,6 +43806,14 @@ "node": ">=0.10.0" } }, + "node_modules/possible-typed-array-names": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", + "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/postcss": { "version": "8.4.33", "dev": true, @@ -46975,15 +47116,16 @@ "license": "MIT" }, "node_modules/reflect.getprototypeof": { - "version": "1.0.5", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz", + "integrity": "sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==", "dev": true, - "license": "MIT", "dependencies": { - "call-bind": "^1.0.5", + "call-bind": "^1.0.7", "define-properties": "^1.2.1", - "es-abstract": "^1.22.3", - "es-errors": "^1.0.0", - "get-intrinsic": "^1.2.3", + "es-abstract": "^1.23.1", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", "globalthis": "^1.0.3", "which-builtin-type": "^1.1.3" }, @@ -48802,12 +48944,13 @@ } }, "node_modules/safe-array-concat": { - "version": "1.1.0", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", + "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", "dev": true, - "license": "MIT", "dependencies": { - "call-bind": "^1.0.5", - "get-intrinsic": "^1.2.2", + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4", "has-symbols": "^1.0.3", "isarray": "^2.0.5" }, @@ -48820,8 +48963,9 @@ }, "node_modules/safe-array-concat/node_modules/isarray": { "version": "2.0.5", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true }, "node_modules/safe-buffer": { "version": "5.1.2", @@ -49134,12 +49278,14 @@ } }, "node_modules/set-function-name": { - "version": "2.0.1", - "license": "MIT", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", "dependencies": { - "define-data-property": "^1.0.1", + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", "functions-have-names": "^1.2.3", - "has-property-descriptors": "^1.0.0" + "has-property-descriptors": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -50478,32 +50624,51 @@ } }, "node_modules/string.prototype.matchall": { - "version": "4.0.10", + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz", + "integrity": "sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==", "dev": true, - "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1", + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", "has-symbols": "^1.0.3", - "internal-slot": "^1.0.5", - "regexp.prototype.flags": "^1.5.0", - "set-function-name": "^2.0.0", - "side-channel": "^1.0.4" + "internal-slot": "^1.0.7", + "regexp.prototype.flags": "^1.5.2", + "set-function-name": "^2.0.2", + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/string.prototype.repeat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz", + "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, "node_modules/string.prototype.trim": { - "version": "1.2.8", + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", + "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", "dev": true, - "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.0", + "es-object-atoms": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -50513,26 +50678,31 @@ } }, "node_modules/string.prototype.trimend": { - "version": "1.0.7", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", + "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", "dev": true, - "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/string.prototype.trimstart": { - "version": "1.0.7", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", "dev": true, - "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -51958,11 +52128,12 @@ } }, "node_modules/typed-array-buffer": { - "version": "1.0.1", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", + "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", "dev": true, - "license": "MIT", "dependencies": { - "call-bind": "^1.0.6", + "call-bind": "^1.0.7", "es-errors": "^1.3.0", "is-typed-array": "^1.1.13" }, @@ -51971,14 +52142,16 @@ } }, "node_modules/typed-array-byte-length": { - "version": "1.0.0", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", + "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", "dev": true, - "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", + "call-bind": "^1.0.7", "for-each": "^0.3.3", - "has-proto": "^1.0.1", - "is-typed-array": "^1.1.10" + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" }, "engines": { "node": ">= 0.4" @@ -51988,15 +52161,17 @@ } }, "node_modules/typed-array-byte-offset": { - "version": "1.0.0", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", + "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", "dev": true, - "license": "MIT", "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", "for-each": "^0.3.3", - "has-proto": "^1.0.1", - "is-typed-array": "^1.1.10" + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" }, "engines": { "node": ">= 0.4" @@ -52006,13 +52181,20 @@ } }, "node_modules/typed-array-length": { - "version": "1.0.4", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", + "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", "dev": true, - "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", + "call-bind": "^1.0.7", "for-each": "^0.3.3", - "is-typed-array": "^1.1.9" + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -53782,12 +53964,13 @@ } }, "node_modules/which-builtin-type": { - "version": "1.1.3", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.4.tgz", + "integrity": "sha512-bppkmBSsHFmIMSl8BO9TbsyzsvGjVoppt8xUiGzwiu/bhDCGxnpOKCxgqj6GuyHE0mINMDecBFPlOm2hzY084w==", "dev": true, - "license": "MIT", "dependencies": { - "function.prototype.name": "^1.1.5", - "has-tostringtag": "^1.0.0", + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", "is-async-function": "^2.0.0", "is-date-object": "^1.0.5", "is-finalizationregistry": "^1.0.2", @@ -53796,8 +53979,8 @@ "is-weakref": "^1.0.2", "isarray": "^2.0.5", "which-boxed-primitive": "^1.0.2", - "which-collection": "^1.0.1", - "which-typed-array": "^1.1.9" + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.15" }, "engines": { "node": ">= 0.4" @@ -53808,17 +53991,22 @@ }, "node_modules/which-builtin-type/node_modules/isarray": { "version": "2.0.5", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true }, "node_modules/which-collection": { - "version": "1.0.1", - "license": "MIT", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", "dependencies": { - "is-map": "^2.0.1", - "is-set": "^2.0.1", - "is-weakmap": "^2.0.1", - "is-weakset": "^2.0.1" + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -54165,14 +54353,15 @@ } }, "node_modules/which-typed-array": { - "version": "1.1.14", - "license": "MIT", + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", + "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", "dependencies": { - "available-typed-arrays": "^1.0.6", - "call-bind": "^1.0.5", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", "for-each": "^0.3.3", "gopd": "^1.0.1", - "has-tostringtag": "^1.0.1" + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -72324,13 +72513,16 @@ "dev": true }, "array-includes": { - "version": "3.1.7", + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz", + "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", "dev": true, "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1", + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", "is-string": "^1.0.7" } }, @@ -72369,6 +72561,20 @@ "es-shim-unscopables": "^1.0.0" } }, + "array.prototype.findlast": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", + "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + } + }, "array.prototype.findlastindex": { "version": "1.2.4", "dev": true, @@ -72401,13 +72607,15 @@ } }, "array.prototype.tosorted": { - "version": "1.1.3", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", + "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", "dev": true, "requires": { - "call-bind": "^1.0.5", + "call-bind": "^1.0.7", "define-properties": "^1.2.1", - "es-abstract": "^1.22.3", - "es-errors": "^1.1.0", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", "es-shim-unscopables": "^1.0.2" } }, @@ -72493,13 +72701,6 @@ "async-validator": { "version": "3.5.1" }, - "asynciterator.prototype": { - "version": "1.0.0", - "dev": true, - "requires": { - "has-symbols": "^1.0.3" - } - }, "asynckit": { "version": "0.4.0", "dev": true @@ -72519,7 +72720,12 @@ "dev": true }, "available-typed-arrays": { - "version": "1.0.6" + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "requires": { + "possible-typed-array-names": "^1.0.0" + } }, "avvio": { "version": "8.4.0", @@ -75440,6 +75646,39 @@ } } }, + "data-view-buffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", + "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==", + "dev": true, + "requires": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + } + }, + "data-view-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", + "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + } + }, + "data-view-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz", + "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==", + "dev": true, + "requires": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + } + }, "datamaps": { "version": "0.5.9", "requires": { @@ -76485,16 +76724,22 @@ } }, "es-abstract": { - "version": "1.22.4", + "version": "1.23.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz", + "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==", "dev": true, "requires": { "array-buffer-byte-length": "^1.0.1", "arraybuffer.prototype.slice": "^1.0.3", - "available-typed-arrays": "^1.0.6", + "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.7", + "data-view-buffer": "^1.0.1", + "data-view-byte-length": "^1.0.1", + "data-view-byte-offset": "^1.0.0", "es-define-property": "^1.0.0", "es-errors": "^1.3.0", - "es-set-tostringtag": "^2.0.2", + "es-object-atoms": "^1.0.0", + "es-set-tostringtag": "^2.0.3", "es-to-primitive": "^1.2.1", "function.prototype.name": "^1.1.6", "get-intrinsic": "^1.2.4", @@ -76502,15 +76747,16 @@ "globalthis": "^1.0.3", "gopd": "^1.0.1", "has-property-descriptors": "^1.0.2", - "has-proto": "^1.0.1", + "has-proto": "^1.0.3", "has-symbols": "^1.0.3", - "hasown": "^2.0.1", + "hasown": "^2.0.2", "internal-slot": "^1.0.7", "is-array-buffer": "^3.0.4", "is-callable": "^1.2.7", - "is-negative-zero": "^2.0.2", + "is-data-view": "^1.0.1", + "is-negative-zero": "^2.0.3", "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", + "is-shared-array-buffer": "^1.0.3", "is-string": "^1.0.7", "is-typed-array": "^1.1.13", "is-weakref": "^1.0.2", @@ -76518,17 +76764,17 @@ "object-keys": "^1.1.1", "object.assign": "^4.1.5", "regexp.prototype.flags": "^1.5.2", - "safe-array-concat": "^1.1.0", + "safe-array-concat": "^1.1.2", "safe-regex-test": "^1.0.3", - "string.prototype.trim": "^1.2.8", - "string.prototype.trimend": "^1.0.7", - "string.prototype.trimstart": "^1.0.7", - "typed-array-buffer": "^1.0.1", - "typed-array-byte-length": "^1.0.0", - "typed-array-byte-offset": "^1.0.0", - "typed-array-length": "^1.0.4", + "string.prototype.trim": "^1.2.9", + "string.prototype.trimend": "^1.0.8", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.2", + "typed-array-byte-length": "^1.0.1", + "typed-array-byte-offset": "^1.0.2", + "typed-array-length": "^1.0.6", "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.14" + "which-typed-array": "^1.1.15" }, "dependencies": { "object-inspect": { @@ -76574,37 +76820,49 @@ } }, "es-iterator-helpers": { - "version": "1.0.17", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.1.0.tgz", + "integrity": "sha512-/SurEfycdyssORP/E+bj4sEu1CWw4EmLDsHynHwSXQ7utgbrMRWW195pTrCjFgFCddf/UkYm3oqKPRq5i8bJbw==", "dev": true, "requires": { - "asynciterator.prototype": "^1.0.0", "call-bind": "^1.0.7", "define-properties": "^1.2.1", - "es-abstract": "^1.22.4", + "es-abstract": "^1.23.3", "es-errors": "^1.3.0", - "es-set-tostringtag": "^2.0.2", + "es-set-tostringtag": "^2.0.3", "function-bind": "^1.1.2", "get-intrinsic": "^1.2.4", - "globalthis": "^1.0.3", + "globalthis": "^1.0.4", "has-property-descriptors": "^1.0.2", - "has-proto": "^1.0.1", + "has-proto": "^1.0.3", "has-symbols": "^1.0.3", "internal-slot": "^1.0.7", - "iterator.prototype": "^1.1.2", - "safe-array-concat": "^1.1.0" + "iterator.prototype": "^1.1.3", + "safe-array-concat": "^1.1.2" } }, "es-module-lexer": { "version": "1.5.4", "devOptional": true }, + "es-object-atoms": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", + "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", + "dev": true, + "requires": { + "es-errors": "^1.3.0" + } + }, "es-set-tostringtag": { - "version": "2.0.2", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", + "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", "dev": true, "requires": { - "get-intrinsic": "^1.2.2", - "has-tostringtag": "^1.0.0", - "hasown": "^2.0.0" + "get-intrinsic": "^1.2.4", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.1" } }, "es-shim-unscopables": { @@ -77457,25 +77715,29 @@ } }, "eslint-plugin-react": { - "version": "7.33.2", + "version": "7.37.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.2.tgz", + "integrity": "sha512-EsTAnj9fLVr/GZleBLFbj/sSuXeWmp1eXIN60ceYnZveqEaUCyW4X+Vh4WTdUhCkW4xutXYqTXCUSyqD4rB75w==", "dev": true, "requires": { - "array-includes": "^3.1.6", - "array.prototype.flatmap": "^1.3.1", - "array.prototype.tosorted": "^1.1.1", + "array-includes": "^3.1.8", + "array.prototype.findlast": "^1.2.5", + "array.prototype.flatmap": "^1.3.2", + "array.prototype.tosorted": "^1.1.4", "doctrine": "^2.1.0", - "es-iterator-helpers": "^1.0.12", + "es-iterator-helpers": "^1.1.0", "estraverse": "^5.3.0", + "hasown": "^2.0.2", "jsx-ast-utils": "^2.4.1 || ^3.0.0", "minimatch": "^3.1.2", - "object.entries": "^1.1.6", - "object.fromentries": "^2.0.6", - "object.hasown": "^1.1.2", - "object.values": "^1.1.6", + "object.entries": "^1.1.8", + "object.fromentries": "^2.0.8", + "object.values": "^1.2.0", "prop-types": "^15.8.1", - "resolve": "^2.0.0-next.4", + "resolve": "^2.0.0-next.5", "semver": "^6.3.1", - "string.prototype.matchall": "^4.0.8" + "string.prototype.matchall": "^4.0.11", + "string.prototype.repeat": "^1.0.0" }, "dependencies": { "doctrine": { @@ -79363,10 +79625,13 @@ "version": "11.12.0" }, "globalthis": { - "version": "1.0.3", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", "dev": true, "requires": { - "define-properties": "^1.1.3" + "define-properties": "^1.2.1", + "gopd": "^1.0.1" } }, "globby": { @@ -79566,7 +79831,9 @@ } }, "has-proto": { - "version": "1.0.1" + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==" }, "has-symbols": { "version": "1.0.3" @@ -79626,7 +79893,9 @@ } }, "hasown": { - "version": "2.0.1", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "requires": { "function-bind": "^1.1.2" } @@ -80563,6 +80832,8 @@ }, "is-async-function": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz", + "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==", "dev": true, "requires": { "has-tostringtag": "^1.0.0" @@ -80634,6 +80905,15 @@ } } }, + "is-data-view": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz", + "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==", + "dev": true, + "requires": { + "is-typed-array": "^1.1.13" + } + }, "is-date-object": { "version": "1.0.5", "requires": { @@ -80672,6 +80952,8 @@ }, "is-finalizationregistry": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz", + "integrity": "sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==", "dev": true, "requires": { "call-bind": "^1.0.2" @@ -80746,7 +81028,9 @@ "dev": true }, "is-map": { - "version": "2.0.2" + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==" }, "is-nan": { "version": "1.3.2", @@ -80756,7 +81040,9 @@ } }, "is-negative-zero": { - "version": "2.0.2", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", "dev": true }, "is-number": { @@ -80821,12 +81107,16 @@ } }, "is-set": { - "version": "2.0.2" + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==" }, "is-shared-array-buffer": { - "version": "1.0.2", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", + "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", "requires": { - "call-bind": "^1.0.2" + "call-bind": "^1.0.7" } }, "is-ssh": { @@ -80884,7 +81174,9 @@ "version": "0.2.1" }, "is-weakmap": { - "version": "2.0.1" + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==" }, "is-weakref": { "version": "1.0.2", @@ -80894,10 +81186,12 @@ } }, "is-weakset": { - "version": "2.0.2", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.3.tgz", + "integrity": "sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==", "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4" } }, "is-what": { @@ -81117,7 +81411,9 @@ } }, "iterator.prototype": { - "version": "1.1.2", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.3.tgz", + "integrity": "sha512-FW5iMbeQ6rBGm/oKgzq2aW4KvAGpxPzYES8N4g4xNXUKpL1mclMvOe+76AcLDTvD+Ze+sOpVhgdAQEKF4L9iGQ==", "dev": true, "requires": { "define-properties": "^1.2.1", @@ -88205,21 +88501,26 @@ } }, "object.entries": { - "version": "1.1.6", + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.8.tgz", + "integrity": "sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==", "dev": true, "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" } }, "object.fromentries": { - "version": "2.0.7", + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", "dev": true, "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" } }, "object.getownpropertydescriptors": { @@ -88242,14 +88543,6 @@ "es-errors": "^1.0.0" } }, - "object.hasown": { - "version": "1.1.3", - "dev": true, - "requires": { - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - } - }, "object.pick": { "version": "1.3.0", "dev": true, @@ -88258,12 +88551,14 @@ } }, "object.values": { - "version": "1.1.7", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz", + "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==", "dev": true, "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" } }, "objectorarray": { @@ -89161,6 +89456,11 @@ "version": "0.1.1", "dev": true }, + "possible-typed-array-names": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", + "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==" + }, "postcss": { "version": "8.4.33", "dev": true, @@ -91249,14 +91549,16 @@ "version": "1.0.0-beta9-9-7" }, "reflect.getprototypeof": { - "version": "1.0.5", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz", + "integrity": "sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==", "dev": true, "requires": { - "call-bind": "^1.0.5", + "call-bind": "^1.0.7", "define-properties": "^1.2.1", - "es-abstract": "^1.22.3", - "es-errors": "^1.0.0", - "get-intrinsic": "^1.2.3", + "es-abstract": "^1.23.1", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", "globalthis": "^1.0.3", "which-builtin-type": "^1.1.3" } @@ -92336,17 +92638,21 @@ } }, "safe-array-concat": { - "version": "1.1.0", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", + "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", "dev": true, "requires": { - "call-bind": "^1.0.5", - "get-intrinsic": "^1.2.2", + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4", "has-symbols": "^1.0.3", "isarray": "^2.0.5" }, "dependencies": { "isarray": { "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", "dev": true } } @@ -92593,11 +92899,14 @@ } }, "set-function-name": { - "version": "2.0.1", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", "requires": { - "define-data-property": "^1.0.1", + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", "functions-have-names": "^1.2.3", - "has-property-descriptors": "^1.0.0" + "has-property-descriptors": "^1.0.2" } }, "set-value": { @@ -93515,45 +93824,67 @@ } }, "string.prototype.matchall": { - "version": "4.0.10", + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz", + "integrity": "sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==", "dev": true, "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1", + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", "has-symbols": "^1.0.3", - "internal-slot": "^1.0.5", - "regexp.prototype.flags": "^1.5.0", - "set-function-name": "^2.0.0", - "side-channel": "^1.0.4" + "internal-slot": "^1.0.7", + "regexp.prototype.flags": "^1.5.2", + "set-function-name": "^2.0.2", + "side-channel": "^1.0.6" + } + }, + "string.prototype.repeat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz", + "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" } }, "string.prototype.trim": { - "version": "1.2.8", + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", + "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", "dev": true, "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.0", + "es-object-atoms": "^1.0.0" } }, "string.prototype.trimend": { - "version": "1.0.7", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", + "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", "dev": true, "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" } }, "string.prototype.trimstart": { - "version": "1.0.7", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", "dev": true, "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" } }, "stringify-entities": { @@ -94467,42 +94798,55 @@ } }, "typed-array-buffer": { - "version": "1.0.1", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", + "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", "dev": true, "requires": { - "call-bind": "^1.0.6", + "call-bind": "^1.0.7", "es-errors": "^1.3.0", "is-typed-array": "^1.1.13" } }, "typed-array-byte-length": { - "version": "1.0.0", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", + "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", "dev": true, "requires": { - "call-bind": "^1.0.2", + "call-bind": "^1.0.7", "for-each": "^0.3.3", - "has-proto": "^1.0.1", - "is-typed-array": "^1.1.10" + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" } }, "typed-array-byte-offset": { - "version": "1.0.0", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", + "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", "dev": true, "requires": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", "for-each": "^0.3.3", - "has-proto": "^1.0.1", - "is-typed-array": "^1.1.10" + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" } }, "typed-array-length": { - "version": "1.0.4", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", + "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", "dev": true, "requires": { - "call-bind": "^1.0.2", + "call-bind": "^1.0.7", "for-each": "^0.3.3", - "is-typed-array": "^1.1.9" + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0" } }, "typedarray": { @@ -95632,11 +95976,13 @@ } }, "which-builtin-type": { - "version": "1.1.3", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.4.tgz", + "integrity": "sha512-bppkmBSsHFmIMSl8BO9TbsyzsvGjVoppt8xUiGzwiu/bhDCGxnpOKCxgqj6GuyHE0mINMDecBFPlOm2hzY084w==", "dev": true, "requires": { - "function.prototype.name": "^1.1.5", - "has-tostringtag": "^1.0.0", + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", "is-async-function": "^2.0.0", "is-date-object": "^1.0.5", "is-finalizationregistry": "^1.0.2", @@ -95645,23 +95991,27 @@ "is-weakref": "^1.0.2", "isarray": "^2.0.5", "which-boxed-primitive": "^1.0.2", - "which-collection": "^1.0.1", - "which-typed-array": "^1.1.9" + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.15" }, "dependencies": { "isarray": { "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", "dev": true } } }, "which-collection": { - "version": "1.0.1", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", "requires": { - "is-map": "^2.0.1", - "is-set": "^2.0.1", - "is-weakmap": "^2.0.1", - "is-weakset": "^2.0.1" + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" } }, "which-module": { @@ -95863,13 +96213,15 @@ } }, "which-typed-array": { - "version": "1.1.14", + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", + "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", "requires": { - "available-typed-arrays": "^1.0.6", - "call-bind": "^1.0.5", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", "for-each": "^0.3.3", "gopd": "^1.0.1", - "has-tostringtag": "^1.0.1" + "has-tostringtag": "^1.0.2" } }, "wide-align": { diff --git a/superset-frontend/package.json b/superset-frontend/package.json index ec7457047b54f..bded686f7e8d6 100644 --- a/superset-frontend/package.json +++ b/superset-frontend/package.json @@ -306,7 +306,7 @@ "eslint-plugin-lodash": "^7.4.0", "eslint-plugin-no-only-tests": "^3.3.0", "eslint-plugin-prettier": "^5.1.3", - "eslint-plugin-react": "^7.22.0", + "eslint-plugin-react": "^7.37.2", "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-prefer-function-component": "^3.3.0", "eslint-plugin-storybook": "^0.8.0", From 4b33353165f39fa735107f1013c64c217e3a1603 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Nov 2024 10:15:53 -0700 Subject: [PATCH 046/307] build(deps): bump deck.gl from 9.0.28 to 9.0.34 in /superset-frontend/plugins/legacy-preset-chart-deckgl (#30786) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .../plugins/legacy-preset-chart-deckgl/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/superset-frontend/plugins/legacy-preset-chart-deckgl/package.json b/superset-frontend/plugins/legacy-preset-chart-deckgl/package.json index 08425170fff89..0c7e66b2466a7 100644 --- a/superset-frontend/plugins/legacy-preset-chart-deckgl/package.json +++ b/superset-frontend/plugins/legacy-preset-chart-deckgl/package.json @@ -31,7 +31,7 @@ "d3-array": "^1.2.4", "d3-color": "^1.4.1", "d3-scale": "^3.0.0", - "deck.gl": "9.0.28", + "deck.gl": "9.0.34", "lodash": "^4.17.21", "moment": "^2.30.1", "mousetrap": "^1.6.5", From e01c8792ec06fff5985e200a00f083a751743c0f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Nov 2024 10:16:27 -0700 Subject: [PATCH 047/307] build(deps): bump winston from 3.13.0 to 3.15.0 in /superset-websocket (#30784) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- superset-websocket/package-lock.json | 18 +++++++++--------- superset-websocket/package.json | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/superset-websocket/package-lock.json b/superset-websocket/package-lock.json index 0f988f555b1d8..55e3aaa3d0d89 100644 --- a/superset-websocket/package-lock.json +++ b/superset-websocket/package-lock.json @@ -15,7 +15,7 @@ "jsonwebtoken": "^9.0.2", "lodash": "^4.17.21", "uuid": "^10.0.0", - "winston": "^3.13.0", + "winston": "^3.15.0", "ws": "^8.18.0" }, "devDependencies": { @@ -6309,15 +6309,15 @@ } }, "node_modules/winston": { - "version": "3.13.0", - "resolved": "https://registry.npmjs.org/winston/-/winston-3.13.0.tgz", - "integrity": "sha512-rwidmA1w3SE4j0E5MuIufFhyJPBDG7Nu71RkZor1p2+qHvJSZ9GYDA81AyleQcZbh/+V6HjeBdfnTZJm9rSeQQ==", + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.15.0.tgz", + "integrity": "sha512-RhruH2Cj0bV0WgNL+lOfoUBI4DVfdUNjVnJGVovWZmrcKtrFTTRzgXYK2O9cymSGjrERCtaAeHwMNnUWXlwZow==", "dependencies": { "@colors/colors": "^1.6.0", "@dabh/diagnostics": "^2.0.2", "async": "^3.2.3", "is-stream": "^2.0.0", - "logform": "^2.4.0", + "logform": "^2.6.0", "one-time": "^1.0.0", "readable-stream": "^3.4.0", "safe-stable-stringify": "^2.3.1", @@ -11145,15 +11145,15 @@ } }, "winston": { - "version": "3.13.0", - "resolved": "https://registry.npmjs.org/winston/-/winston-3.13.0.tgz", - "integrity": "sha512-rwidmA1w3SE4j0E5MuIufFhyJPBDG7Nu71RkZor1p2+qHvJSZ9GYDA81AyleQcZbh/+V6HjeBdfnTZJm9rSeQQ==", + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.15.0.tgz", + "integrity": "sha512-RhruH2Cj0bV0WgNL+lOfoUBI4DVfdUNjVnJGVovWZmrcKtrFTTRzgXYK2O9cymSGjrERCtaAeHwMNnUWXlwZow==", "requires": { "@colors/colors": "^1.6.0", "@dabh/diagnostics": "^2.0.2", "async": "^3.2.3", "is-stream": "^2.0.0", - "logform": "^2.4.0", + "logform": "^2.6.0", "one-time": "^1.0.0", "readable-stream": "^3.4.0", "safe-stable-stringify": "^2.3.1", diff --git a/superset-websocket/package.json b/superset-websocket/package.json index 9222c8c5b89d7..3d79edf5edda9 100644 --- a/superset-websocket/package.json +++ b/superset-websocket/package.json @@ -23,7 +23,7 @@ "jsonwebtoken": "^9.0.2", "lodash": "^4.17.21", "uuid": "^10.0.0", - "winston": "^3.13.0", + "winston": "^3.15.0", "ws": "^8.18.0" }, "devDependencies": { From 41464931a48d98573bf9767b66484119f96b8e4f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Nov 2024 10:31:40 -0700 Subject: [PATCH 048/307] build(deps): bump uuid from 10.0.0 to 11.0.2 in /superset-websocket (#30782) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- superset-websocket/package-lock.json | 16 ++++++++-------- superset-websocket/package.json | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/superset-websocket/package-lock.json b/superset-websocket/package-lock.json index 55e3aaa3d0d89..9cea26dae3487 100644 --- a/superset-websocket/package-lock.json +++ b/superset-websocket/package-lock.json @@ -14,7 +14,7 @@ "ioredis": "^4.28.0", "jsonwebtoken": "^9.0.2", "lodash": "^4.17.21", - "uuid": "^10.0.0", + "uuid": "^11.0.2", "winston": "^3.15.0", "ws": "^8.18.0" }, @@ -6237,15 +6237,15 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, "node_modules/uuid": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", - "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==", + "version": "11.0.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.0.2.tgz", + "integrity": "sha512-14FfcOJmqdjbBPdDjFQyk/SdT4NySW4eM0zcG+HqbHP5jzuH56xO3J1DGhgs/cEMCfwYi3HQI1gnTO62iaG+tQ==", "funding": [ "https://github.com/sponsors/broofa", "https://github.com/sponsors/ctavan" ], "bin": { - "uuid": "dist/bin/uuid" + "uuid": "dist/esm/bin/uuid" } }, "node_modules/v8-compile-cache-lib": { @@ -11087,9 +11087,9 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, "uuid": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", - "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==" + "version": "11.0.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.0.2.tgz", + "integrity": "sha512-14FfcOJmqdjbBPdDjFQyk/SdT4NySW4eM0zcG+HqbHP5jzuH56xO3J1DGhgs/cEMCfwYi3HQI1gnTO62iaG+tQ==" }, "v8-compile-cache-lib": { "version": "3.0.1", diff --git a/superset-websocket/package.json b/superset-websocket/package.json index 3d79edf5edda9..f8855e87c941e 100644 --- a/superset-websocket/package.json +++ b/superset-websocket/package.json @@ -22,7 +22,7 @@ "ioredis": "^4.28.0", "jsonwebtoken": "^9.0.2", "lodash": "^4.17.21", - "uuid": "^10.0.0", + "uuid": "^11.0.2", "winston": "^3.15.0", "ws": "^8.18.0" }, From 54cc69a382e98cb05b078cd13ec267d4bed2cfbb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Nov 2024 11:07:01 -0700 Subject: [PATCH 049/307] build(deps-dev): bump eslint from 9.11.0 to 9.14.0 in /superset-websocket (#30835) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- superset-websocket/package-lock.json | 255 ++++++++++++++++----------- superset-websocket/package.json | 2 +- 2 files changed, 154 insertions(+), 103 deletions(-) diff --git a/superset-websocket/package-lock.json b/superset-websocket/package-lock.json index 9cea26dae3487..2312683319fa8 100644 --- a/superset-websocket/package-lock.json +++ b/superset-websocket/package-lock.json @@ -31,7 +31,7 @@ "@types/ws": "^8.5.12", "@typescript-eslint/eslint-plugin": "^8.8.0", "@typescript-eslint/parser": "^8.6.0", - "eslint": "^9.11.0", + "eslint": "^9.14.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-lodash": "^8.0.0", "globals": "^15.9.0", @@ -737,11 +737,10 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.11.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.1.tgz", - "integrity": "sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q==", + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", "dev": true, - "license": "MIT", "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } @@ -761,6 +760,15 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@eslint/core": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.7.0.tgz", + "integrity": "sha512-xp5Jirz5DyPYlPiKat8jaq0EmYvDXKKpzTbxXMpT9eqlRJkRKIz9AGMdlvYjih+im+QlhWrpvVjl8IPC/lHlUw==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, "node_modules/@eslint/eslintrc": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", @@ -819,11 +827,10 @@ } }, "node_modules/@eslint/js": { - "version": "9.11.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.11.0.tgz", - "integrity": "sha512-LPkkenkDqyzTFauZLLAPhIb48fj6drrfMvRGSL9tS3AcZBSVTllemLSNyCvHNNL2t797S/6DJNSIwRwXgMO/eQ==", + "version": "9.14.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.14.0.tgz", + "integrity": "sha512-pFoEtFWCPyDOl+C6Ift+wC7Ro89otjigCf5vcuWqWgqNSQbRrpjSvdeE6ofLz4dHmyxD5f7gIdGT4+p36L6Twg==", "dev": true, - "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } @@ -851,6 +858,41 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", + "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", + "dev": true, + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.3.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "dev": true, + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", @@ -865,11 +907,10 @@ } }, "node_modules/@humanwhocodes/retry": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.0.tgz", - "integrity": "sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==", + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.0.tgz", + "integrity": "sha512-xnRgu9DxZbkWak/te3fcytNyp8MTbuiZIaueg2rgEvBuN55n04nwLYLU9TX/VVlusc9L2ZNXi99nUFNkHXtr5g==", "dev": true, - "license": "Apache-2.0", "engines": { "node": ">=18.18" }, @@ -2023,11 +2064,10 @@ } }, "node_modules/acorn": { - "version": "8.12.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", - "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", "dev": true, - "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -2681,29 +2721,31 @@ } }, "node_modules/eslint": { - "version": "9.11.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.11.0.tgz", - "integrity": "sha512-yVS6XODx+tMFMDFcG4+Hlh+qG7RM6cCJXtQhCKLSsr3XkLvWggHjCqjfh0XsPPnt1c56oaT6PMgW9XWQQjdHXA==", + "version": "9.14.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.14.0.tgz", + "integrity": "sha512-c2FHsVBr87lnUtjP4Yhvk4yEhKrQavGafRA/Se1ouse8PfbfC/Qh9Mxa00yWsZRlqeUB9raXip0aiiUZkgnr9g==", "dev": true, - "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.11.0", + "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.18.0", + "@eslint/core": "^0.7.0", "@eslint/eslintrc": "^3.1.0", - "@eslint/js": "9.11.0", + "@eslint/js": "9.14.0", "@eslint/plugin-kit": "^0.2.0", + "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.3.0", - "@nodelib/fs.walk": "^1.2.8", + "@humanwhocodes/retry": "^0.4.0", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.0.2", - "eslint-visitor-keys": "^4.0.0", - "espree": "^10.1.0", + "eslint-scope": "^8.2.0", + "eslint-visitor-keys": "^4.2.0", + "espree": "^10.3.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", @@ -2713,13 +2755,11 @@ "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", "text-table": "^0.2.0" }, "bin": { @@ -2769,11 +2809,10 @@ } }, "node_modules/eslint-scope": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.0.2.tgz", - "integrity": "sha512-6E4xmrTw5wtxnLA5wYL3WDfhZ/1bUBGOXV0zQvVRDOtrR8D0p6W7fs3JweNYhwRYeGvd/1CKX2se0/2s7Q/nJA==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.2.0.tgz", + "integrity": "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" @@ -2810,11 +2849,10 @@ } }, "node_modules/eslint/node_modules/eslint-visitor-keys": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", - "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", "dev": true, - "license": "Apache-2.0", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -2913,15 +2951,14 @@ } }, "node_modules/espree": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.1.0.tgz", - "integrity": "sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==", + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", + "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { - "acorn": "^8.12.0", + "acorn": "^8.14.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.0.0" + "eslint-visitor-keys": "^4.2.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2931,11 +2968,10 @@ } }, "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", - "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", "dev": true, - "license": "Apache-2.0", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -2974,7 +3010,6 @@ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" }, @@ -3557,15 +3592,6 @@ "node": ">=0.12.0" } }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/is-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", @@ -6975,9 +7001,9 @@ } }, "@eslint-community/regexpp": { - "version": "4.11.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.1.tgz", - "integrity": "sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q==", + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", "dev": true }, "@eslint/config-array": { @@ -6991,6 +7017,12 @@ "minimatch": "^3.1.2" } }, + "@eslint/core": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.7.0.tgz", + "integrity": "sha512-xp5Jirz5DyPYlPiKat8jaq0EmYvDXKKpzTbxXMpT9eqlRJkRKIz9AGMdlvYjih+im+QlhWrpvVjl8IPC/lHlUw==", + "dev": true + }, "@eslint/eslintrc": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", @@ -7032,9 +7064,9 @@ } }, "@eslint/js": { - "version": "9.11.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.11.0.tgz", - "integrity": "sha512-LPkkenkDqyzTFauZLLAPhIb48fj6drrfMvRGSL9tS3AcZBSVTllemLSNyCvHNNL2t797S/6DJNSIwRwXgMO/eQ==", + "version": "9.14.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.14.0.tgz", + "integrity": "sha512-pFoEtFWCPyDOl+C6Ift+wC7Ro89otjigCf5vcuWqWgqNSQbRrpjSvdeE6ofLz4dHmyxD5f7gIdGT4+p36L6Twg==", "dev": true }, "@eslint/object-schema": { @@ -7052,6 +7084,30 @@ "levn": "^0.4.1" } }, + "@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true + }, + "@humanfs/node": { + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", + "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", + "dev": true, + "requires": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.3.0" + }, + "dependencies": { + "@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "dev": true + } + } + }, "@humanwhocodes/module-importer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", @@ -7059,9 +7115,9 @@ "dev": true }, "@humanwhocodes/retry": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.0.tgz", - "integrity": "sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==", + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.0.tgz", + "integrity": "sha512-xnRgu9DxZbkWak/te3fcytNyp8MTbuiZIaueg2rgEvBuN55n04nwLYLU9TX/VVlusc9L2ZNXi99nUFNkHXtr5g==", "dev": true }, "@istanbuljs/load-nyc-config": { @@ -7982,9 +8038,9 @@ } }, "acorn": { - "version": "8.12.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", - "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", "dev": true }, "acorn-jsx": { @@ -8476,28 +8532,31 @@ "dev": true }, "eslint": { - "version": "9.11.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.11.0.tgz", - "integrity": "sha512-yVS6XODx+tMFMDFcG4+Hlh+qG7RM6cCJXtQhCKLSsr3XkLvWggHjCqjfh0XsPPnt1c56oaT6PMgW9XWQQjdHXA==", + "version": "9.14.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.14.0.tgz", + "integrity": "sha512-c2FHsVBr87lnUtjP4Yhvk4yEhKrQavGafRA/Se1ouse8PfbfC/Qh9Mxa00yWsZRlqeUB9raXip0aiiUZkgnr9g==", "dev": true, "requires": { "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.11.0", + "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.18.0", + "@eslint/core": "^0.7.0", "@eslint/eslintrc": "^3.1.0", - "@eslint/js": "9.11.0", + "@eslint/js": "9.14.0", "@eslint/plugin-kit": "^0.2.0", + "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.3.0", - "@nodelib/fs.walk": "^1.2.8", + "@humanwhocodes/retry": "^0.4.0", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.0.2", - "eslint-visitor-keys": "^4.0.0", - "espree": "^10.1.0", + "eslint-scope": "^8.2.0", + "eslint-visitor-keys": "^4.2.0", + "espree": "^10.3.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", @@ -8507,13 +8566,11 @@ "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", "text-table": "^0.2.0" }, "dependencies": { @@ -8524,9 +8581,9 @@ "dev": true }, "eslint-visitor-keys": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", - "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", "dev": true }, "find-up": { @@ -8608,9 +8665,9 @@ } }, "eslint-scope": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.0.2.tgz", - "integrity": "sha512-6E4xmrTw5wtxnLA5wYL3WDfhZ/1bUBGOXV0zQvVRDOtrR8D0p6W7fs3JweNYhwRYeGvd/1CKX2se0/2s7Q/nJA==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.2.0.tgz", + "integrity": "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==", "dev": true, "requires": { "esrecurse": "^4.3.0", @@ -8624,20 +8681,20 @@ "dev": true }, "espree": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.1.0.tgz", - "integrity": "sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==", + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", + "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", "dev": true, "requires": { - "acorn": "^8.12.0", + "acorn": "^8.14.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.0.0" + "eslint-visitor-keys": "^4.2.0" }, "dependencies": { "eslint-visitor-keys": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", - "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", "dev": true } } @@ -9100,12 +9157,6 @@ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, - "is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true - }, "is-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", diff --git a/superset-websocket/package.json b/superset-websocket/package.json index f8855e87c941e..1a78765369c88 100644 --- a/superset-websocket/package.json +++ b/superset-websocket/package.json @@ -39,7 +39,7 @@ "@types/ws": "^8.5.12", "@typescript-eslint/eslint-plugin": "^8.8.0", "@typescript-eslint/parser": "^8.6.0", - "eslint": "^9.11.0", + "eslint": "^9.14.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-lodash": "^8.0.0", "globals": "^15.9.0", From a91daab1f7d03148e93008df414e746554306ef3 Mon Sep 17 00:00:00 2001 From: Ahmed Habeeb Date: Mon, 4 Nov 2024 20:29:32 +0200 Subject: [PATCH 050/307] docs: Update INTHEWILD.md (#30822) --- RESOURCES/INTHEWILD.md | 1 + 1 file changed, 1 insertion(+) diff --git a/RESOURCES/INTHEWILD.md b/RESOURCES/INTHEWILD.md index 6400adc11cfd4..2799b160783f4 100644 --- a/RESOURCES/INTHEWILD.md +++ b/RESOURCES/INTHEWILD.md @@ -84,6 +84,7 @@ Join our growing community! - [Deepomatic](https://deepomatic.com/) [@Zanoellia] - [Dial Once](https://www.dial-once.com/) - [Dremio](https://dremio.com) [@narendrans] +- [EFinance](https://www.efinance.com.eg) [@habeeb556] - [Elestio](https://elest.io/) [@kaiwalyakoparkar] - [ELMO Cloud HR & Payroll](https://elmosoftware.com.au/) - [Endress+Hauser](https://www.endress.com/) [@rumbin] From f0b86f877ffaeca2e1806889c4084c7ae56d0400 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Nov 2024 12:45:43 -0800 Subject: [PATCH 051/307] build(deps-dev): bump webpack from 5.95.0 to 5.96.1 in /docs (#30832) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- docs/package.json | 2 +- docs/yarn.lock | 118 ++++++++++++++++++++++++++++------------------ 2 files changed, 73 insertions(+), 47 deletions(-) diff --git a/docs/package.json b/docs/package.json index 9283ea56006a5..3c6153d204657 100644 --- a/docs/package.json +++ b/docs/package.json @@ -50,7 +50,7 @@ "@docusaurus/tsconfig": "^3.5.2", "@types/react": "^18.3.10", "typescript": "^5.6.2", - "webpack": "^5.95.0" + "webpack": "^5.96.1" }, "browserslist": { "production": [ diff --git a/docs/yarn.lock b/docs/yarn.lock index fa4f80ceaa73a..7864eb956ae4a 100644 --- a/docs/yarn.lock +++ b/docs/yarn.lock @@ -2738,6 +2738,22 @@ dependencies: "@types/ms" "*" +"@types/eslint-scope@^3.7.7": + version "3.7.7" + resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.7.tgz#3108bd5f18b0cdb277c867b3dd449c9ed7079ac5" + integrity sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg== + dependencies: + "@types/eslint" "*" + "@types/estree" "*" + +"@types/eslint@*": + version "9.6.1" + resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-9.6.1.tgz#d5795ad732ce81715f27f75da913004a56751584" + integrity sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag== + dependencies: + "@types/estree" "*" + "@types/json-schema" "*" + "@types/estree-jsx@^1.0.0": version "1.0.5" resolved "https://registry.yarnpkg.com/@types/estree-jsx/-/estree-jsx-1.0.5.tgz#858a88ea20f34fe65111f005a689fa1ebf70dc18" @@ -2745,10 +2761,10 @@ dependencies: "@types/estree" "*" -"@types/estree@*", "@types/estree@^1.0.0", "@types/estree@^1.0.5": - version "1.0.5" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4" - integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw== +"@types/estree@*", "@types/estree@^1.0.0", "@types/estree@^1.0.6": + version "1.0.6" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.6.tgz#628effeeae2064a1b4e79f78e81d87b7e5fc7b50" + integrity sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw== "@types/express-serve-static-core@*", "@types/express-serve-static-core@^4.17.33": version "4.19.0" @@ -2835,7 +2851,7 @@ dependencies: "@types/istanbul-lib-report" "*" -"@types/json-schema@^7.0.4", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": +"@types/json-schema@*", "@types/json-schema@^7.0.4", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": version "7.0.15" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== @@ -3168,11 +3184,6 @@ accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.8: mime-types "~2.1.34" negotiator "0.6.3" -acorn-import-attributes@^1.9.5: - version "1.9.5" - resolved "https://registry.yarnpkg.com/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz#7eb1557b1ba05ef18b5ed0ec67591bfab04688ef" - integrity sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ== - acorn-jsx@^5.0.0: version "5.3.2" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" @@ -3183,10 +3194,10 @@ acorn-walk@^8.0.0: resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.2.tgz#7703af9415f1b6db9315d6895503862e231d34aa" integrity sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A== -acorn@^8.0.0, acorn@^8.0.4, acorn@^8.7.1, acorn@^8.8.2: - version "8.11.3" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.3.tgz#71e0b14e13a4ec160724b38fb7b0f233b1b81d7a" - integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg== +acorn@^8.0.0, acorn@^8.0.4, acorn@^8.14.0, acorn@^8.8.2: + version "8.14.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.14.0.tgz#063e2c70cac5fb4f6467f0b11152e04c682795b0" + integrity sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA== address@^1.0.1, address@^1.1.2: version "1.2.2" @@ -3641,15 +3652,15 @@ braces@^3.0.3, braces@~3.0.2: dependencies: fill-range "^7.1.1" -browserslist@^4.0.0, browserslist@^4.18.1, browserslist@^4.21.10, browserslist@^4.22.2, browserslist@^4.23.0: - version "4.23.0" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.23.0.tgz#8f3acc2bbe73af7213399430890f86c63a5674ab" - integrity sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ== +browserslist@^4.0.0, browserslist@^4.18.1, browserslist@^4.22.2, browserslist@^4.23.0, browserslist@^4.24.0: + version "4.24.2" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.24.2.tgz#f5845bc91069dbd55ee89faf9822e1d885d16580" + integrity sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg== dependencies: - caniuse-lite "^1.0.30001587" - electron-to-chromium "^1.4.668" - node-releases "^2.0.14" - update-browserslist-db "^1.0.13" + caniuse-lite "^1.0.30001669" + electron-to-chromium "^1.5.41" + node-releases "^2.0.18" + update-browserslist-db "^1.1.1" buffer-from@^1.0.0: version "1.1.2" @@ -3744,11 +3755,16 @@ caniuse-api@^3.0.0: lodash.memoize "^4.1.2" lodash.uniq "^4.5.0" -caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001587, caniuse-lite@^1.0.30001599: +caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001599: version "1.0.30001614" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001614.tgz#f894b4209376a0bf923d67d9c361d96b1dfebe39" integrity sha512-jmZQ1VpmlRwHgdP1/uiKzgiAuGOfLEJsYFP4+GBou/QQ4U6IOJCB4NP1c+1p9RGLpwObcT94jA5/uO+F1vBbog== +caniuse-lite@^1.0.30001669: + version "1.0.30001677" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001677.tgz#27c2e2c637e007cfa864a16f7dfe7cde66b38b5f" + integrity sha512-fmfjsOlJUpMWu+mAAtZZZHz7UEwsUxIIvu1TJfO1HqFQvB/B+ii0xr9B5HpbZY/mC4XZ8SvjHJqtAY6pDPQEog== + ccount@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/ccount/-/ccount-2.0.1.tgz#17a3bf82302e0870d6da43a01311a8bc02a3ecf5" @@ -4637,10 +4653,10 @@ ee-first@1.1.1: resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== -electron-to-chromium@^1.4.668: - version "1.4.752" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.752.tgz#99227455547c8254488e3dab7d316c34a2c067b8" - integrity sha512-P3QJreYI/AUTcfBVrC4zy9KvnZWekViThgQMX/VpJ+IsOBbcX5JFpORM4qWapwWQ+agb2nYAOyn/4PMXOk0m2Q== +electron-to-chromium@^1.5.41: + version "1.5.50" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.50.tgz#d9ba818da7b2b5ef1f3dd32bce7046feb7e93234" + integrity sha512-eMVObiUQ2LdgeO1F/ySTXsvqvxb6ZH2zPGaMYsWzRDdOddUa77tdmI0ltg+L16UpbWdhPmuF3wIQYyQq65WfZw== emoji-regex@^8.0.0: version "8.0.0" @@ -4742,11 +4758,16 @@ es-module-lexer@^1.2.1: resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.5.2.tgz#00b423304f2500ac59359cc9b6844951f372d497" integrity sha512-l60ETUTmLqbVbVHv1J4/qj+M8nq7AwMzEcg3kmJDt9dCNrTk+yHcYFf/Kw75pMDwd9mPcIGCG5LcS20SxYRzFA== -escalade@^3.1.1, escalade@^3.1.2: +escalade@^3.1.1: version "3.1.2" resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.2.tgz#54076e9ab29ea5bf3d8f1ed62acffbb88272df27" integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA== +escalade@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" + integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== + escape-goat@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/escape-goat/-/escape-goat-4.0.0.tgz#9424820331b510b0666b98f7873fe11ac4aa8081" @@ -7294,10 +7315,10 @@ node-forge@^1: resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.1.tgz#be8da2af243b2417d5f646a770663a92b7e9ded3" integrity sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA== -node-releases@^2.0.14: - version "2.0.14" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.14.tgz#2ffb053bceb8b2be8495ece1ab6ce600c4461b0b" - integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw== +node-releases@^2.0.18: + version "2.0.18" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.18.tgz#f010e8d35e2fe8d6b2944f03f70213ecedc4ca3f" + integrity sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g== normalize-path@^3.0.0, normalize-path@~3.0.0: version "3.0.0" @@ -7647,6 +7668,11 @@ picocolors@^1.0.0: resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== +picocolors@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" + integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== + picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3, picomatch@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" @@ -10110,13 +10136,13 @@ unraw@^3.0.0: resolved "https://registry.yarnpkg.com/unraw/-/unraw-3.0.0.tgz#73443ed70d2ab09ccbac2b00525602d5991fbbe3" integrity sha512-08/DA66UF65OlpUDIQtbJyrqTR0jTAlJ+jsnkQ4jxR7+K5g5YG1APZKQSMCE1vqqmD+2pv6+IdEjmopFatacvg== -update-browserslist-db@^1.0.13: - version "1.0.14" - resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.14.tgz#46a9367c323f8ade9a9dddb7f3ae7814b3a0b31c" - integrity sha512-JixKH8GR2pWYshIPUg/NujK3JO7JiqEEUiNArE86NQyrgUuZeTlZQN3xuS/yiV5Kb48ev9K6RqNkaJjXsdg7Jw== +update-browserslist-db@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz#80846fba1d79e82547fb661f8d141e0945755fe5" + integrity sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A== dependencies: - escalade "^3.1.2" - picocolors "^1.0.0" + escalade "^3.2.0" + picocolors "^1.1.0" update-notifier@^6.0.2: version "6.0.2" @@ -10336,18 +10362,18 @@ webpack-sources@^3.2.3: resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== -webpack@^5.88.1, webpack@^5.95.0: - version "5.95.0" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.95.0.tgz#8fd8c454fa60dad186fbe36c400a55848307b4c0" - integrity sha512-2t3XstrKULz41MNMBF+cJ97TyHdyQ8HCt//pqErqDvNjU9YQBnZxIHa11VXsi7F3mb5/aO2tuDxdeTPdU7xu9Q== +webpack@^5.88.1, webpack@^5.96.1: + version "5.96.1" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.96.1.tgz#3676d1626d8312b6b10d0c18cc049fba7ac01f0c" + integrity sha512-l2LlBSvVZGhL4ZrPwyr8+37AunkcYj5qh8o6u2/2rzoPc8gxFJkLj1WxNgooi9pnoc06jh0BjuXnamM4qlujZA== dependencies: - "@types/estree" "^1.0.5" + "@types/eslint-scope" "^3.7.7" + "@types/estree" "^1.0.6" "@webassemblyjs/ast" "^1.12.1" "@webassemblyjs/wasm-edit" "^1.12.1" "@webassemblyjs/wasm-parser" "^1.12.1" - acorn "^8.7.1" - acorn-import-attributes "^1.9.5" - browserslist "^4.21.10" + acorn "^8.14.0" + browserslist "^4.24.0" chrome-trace-event "^1.0.2" enhanced-resolve "^5.17.1" es-module-lexer "^1.2.1" From 0b263697ca9369d5ff6cb0134f2935005f52c7f0 Mon Sep 17 00:00:00 2001 From: Evan Rusackas Date: Mon, 4 Nov 2024 17:08:55 -0700 Subject: [PATCH 052/307] chore: Revert "build(deps): bump JustinBeckwith/linkinator-action from 1.10.4 to 1.11.0" (#30838) --- .github/workflows/superset-docs-verify.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/superset-docs-verify.yml b/.github/workflows/superset-docs-verify.yml index 944fda8f9a3b1..70da191621afb 100644 --- a/.github/workflows/superset-docs-verify.yml +++ b/.github/workflows/superset-docs-verify.yml @@ -20,7 +20,9 @@ jobs: continue-on-error: true # This will make the job advisory (non-blocking, no red X) steps: - uses: actions/checkout@v4 - - uses: JustinBeckwith/linkinator-action@v1.11.0 + # Do not bump this linkinator-action version without opening + # an ASF Infra ticket to allow the new verison first! + - uses: JustinBeckwith/linkinator-action@v1.10.4 with: paths: "**/*.md, **/*.mdx" linksToSkip: >- From d1bc986d9323182b35257e29e833ef0caa4dde26 Mon Sep 17 00:00:00 2001 From: Sanjay Nayak Date: Tue, 5 Nov 2024 06:08:40 +0530 Subject: [PATCH 053/307] docs: Update INTHEWILD.md with 2070Health Org (#30824) --- RESOURCES/INTHEWILD.md | 1 + 1 file changed, 1 insertion(+) diff --git a/RESOURCES/INTHEWILD.md b/RESOURCES/INTHEWILD.md index 2799b160783f4..291635af0b3f3 100644 --- a/RESOURCES/INTHEWILD.md +++ b/RESOURCES/INTHEWILD.md @@ -161,6 +161,7 @@ Join our growing community! - [REDCap Cloud](https://www.redcapcloud.com/) - [TrustMedis](https://trustmedis.com/) [@famasya] - [WeSure](https://www.wesure.cn/) +- [2070Health](https://2070health.com/) ### HR / Staffing - [Swile](https://www.swile.co/) [@PaoloTerzi] From 2eadc1f0863c90b31b0363ed004a800fd9145330 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Nov 2024 09:46:58 -0700 Subject: [PATCH 054/307] build(deps): bump @saucelabs/theme-github-codeblock from 0.2.3 to 0.3.0 in /docs (#30799) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- docs/package.json | 2 +- docs/yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/package.json b/docs/package.json index 3c6153d204657..de4e1c0841b1a 100644 --- a/docs/package.json +++ b/docs/package.json @@ -26,7 +26,7 @@ "@emotion/core": "^10.1.1", "@emotion/styled": "^10.0.27", "@mdx-js/react": "^3.0.0", - "@saucelabs/theme-github-codeblock": "^0.2.3", + "@saucelabs/theme-github-codeblock": "^0.3.0", "@superset-ui/style": "^0.14.23", "@svgr/webpack": "^8.1.0", "antd": "^5.21.6", diff --git a/docs/yarn.lock b/docs/yarn.lock index 7864eb956ae4a..2ab0aceda9085 100644 --- a/docs/yarn.lock +++ b/docs/yarn.lock @@ -2127,10 +2127,10 @@ rc-resize-observer "^1.3.1" rc-util "^5.38.0" -"@saucelabs/theme-github-codeblock@^0.2.3": - version "0.2.3" - resolved "https://registry.yarnpkg.com/@saucelabs/theme-github-codeblock/-/theme-github-codeblock-0.2.3.tgz#706a43292f600532271979941b0155db667c2c21" - integrity sha512-GSl3Lr/jOWm4OP3BPX2vXxc8FMSOXj1mJnls6cUqMwlGOfKQ1Ia9pq1O9/ES+5TrZHIzAws/n5FFSn1OkGJw/Q== +"@saucelabs/theme-github-codeblock@^0.3.0": + version "0.3.0" + resolved "https://registry.yarnpkg.com/@saucelabs/theme-github-codeblock/-/theme-github-codeblock-0.3.0.tgz#7936bc6aa97a15f2483ac143df4918c8d2baf5f0" + integrity sha512-+8xWxBfN+I8StJ0QXERMbGf+BHwRXHWV3mFl9uDayXERiZ/rR93d0nAS3s9s/rKjqh/YSm/4dThEkBNBLnGs4Q== "@sideway/address@^4.1.5": version "4.1.5" From fb6ad3240f90ef211588c6c3ec733e0f77e59887 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Nov 2024 09:48:04 -0700 Subject: [PATCH 055/307] build(deps-dev): bump typescript from 5.6.2 to 5.6.3 in /docs (#30795) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- docs/package.json | 2 +- docs/yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/package.json b/docs/package.json index de4e1c0841b1a..30444393fa14c 100644 --- a/docs/package.json +++ b/docs/package.json @@ -49,7 +49,7 @@ "@docusaurus/module-type-aliases": "^3.5.2", "@docusaurus/tsconfig": "^3.5.2", "@types/react": "^18.3.10", - "typescript": "^5.6.2", + "typescript": "^5.6.3", "webpack": "^5.96.1" }, "browserslist": { diff --git a/docs/yarn.lock b/docs/yarn.lock index 2ab0aceda9085..973e5182e01f8 100644 --- a/docs/yarn.lock +++ b/docs/yarn.lock @@ -10010,10 +10010,10 @@ types-ramda@^0.30.0: dependencies: ts-toolbelt "^9.6.0" -typescript@^5.6.2: - version "5.6.2" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.6.2.tgz#d1de67b6bef77c41823f822df8f0b3bcff60a5a0" - integrity sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw== +typescript@^5.6.3: + version "5.6.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.6.3.tgz#5f3449e31c9d94febb17de03cc081dd56d81db5b" + integrity sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw== undici-types@~5.26.4: version "5.26.5" From 5a59dcf06e8659dde15a9063c4455cdcffd638a2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Nov 2024 10:40:47 -0700 Subject: [PATCH 056/307] build(deps-dev): bump @types/react from 18.3.10 to 18.3.12 in /docs (#30793) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- docs/package.json | 2 +- docs/yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/package.json b/docs/package.json index 30444393fa14c..ee38745319c12 100644 --- a/docs/package.json +++ b/docs/package.json @@ -48,7 +48,7 @@ "devDependencies": { "@docusaurus/module-type-aliases": "^3.5.2", "@docusaurus/tsconfig": "^3.5.2", - "@types/react": "^18.3.10", + "@types/react": "^18.3.12", "typescript": "^5.6.3", "webpack": "^5.96.1" }, diff --git a/docs/yarn.lock b/docs/yarn.lock index 973e5182e01f8..6e19bfb75ad6b 100644 --- a/docs/yarn.lock +++ b/docs/yarn.lock @@ -2955,10 +2955,10 @@ "@types/history" "^4.7.11" "@types/react" "*" -"@types/react@*", "@types/react@^18.3.10": - version "18.3.10" - resolved "https://registry.yarnpkg.com/@types/react/-/react-18.3.10.tgz#6edc26dc22ff8c9c226d3c7bf8357b013c842219" - integrity sha512-02sAAlBnP39JgXwkAq3PeU9DVaaGpZyF3MGcC0MKgQVkZor5IiiDAipVaxQHtDJAmO4GIy/rVBy/LzVj76Cyqg== +"@types/react@*", "@types/react@^18.3.12": + version "18.3.12" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.3.12.tgz#99419f182ccd69151813b7ee24b792fe08774f60" + integrity sha512-D2wOSq/d6Agt28q7rSI3jhU7G6aiuzljDGZ2hTZHIkrTLUI+AF3WMeKkEZ9nN2fkBAlcktT6vcZjDFiIhMYEQw== dependencies: "@types/prop-types" "*" csstype "^3.0.2" From 6b9122bb3bc2085efdb0ae53ccc167d5ff455501 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Nov 2024 10:43:44 -0700 Subject: [PATCH 057/307] build(deps): bump @mdx-js/react from 3.0.1 to 3.1.0 in /docs (#30796) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- docs/package.json | 2 +- docs/yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/package.json b/docs/package.json index ee38745319c12..83dc5b97f63ef 100644 --- a/docs/package.json +++ b/docs/package.json @@ -25,7 +25,7 @@ "@docusaurus/preset-classic": "^3.5.2", "@emotion/core": "^10.1.1", "@emotion/styled": "^10.0.27", - "@mdx-js/react": "^3.0.0", + "@mdx-js/react": "^3.1.0", "@saucelabs/theme-github-codeblock": "^0.3.0", "@superset-ui/style": "^0.14.23", "@svgr/webpack": "^8.1.0", diff --git a/docs/yarn.lock b/docs/yarn.lock index 6e19bfb75ad6b..5d3542405f471 100644 --- a/docs/yarn.lock +++ b/docs/yarn.lock @@ -1991,10 +1991,10 @@ unist-util-visit "^5.0.0" vfile "^6.0.0" -"@mdx-js/react@^3.0.0": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@mdx-js/react/-/react-3.0.1.tgz#997a19b3a5b783d936c75ae7c47cfe62f967f746" - integrity sha512-9ZrPIU4MGf6et1m1ov3zKf+q9+deetI51zprKB1D/z3NOb+rUxxtEl3mCjW5wTGh6VhRdwPueh1oRzi6ezkA8A== +"@mdx-js/react@^3.0.0", "@mdx-js/react@^3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@mdx-js/react/-/react-3.1.0.tgz#c4522e335b3897b9a845db1dbdd2f966ae8fb0ed" + integrity sha512-QjHtSaoameoalGnKDT3FoIl4+9RwyTmo9ZJGBdLOks/YOiWHoRDI3PUwEzOE7kEmGcV3AFcp9K6dYu9rEuKLAQ== dependencies: "@types/mdx" "^2.0.0" From 63b97ab76d6e4b1abcacb6cff430a009afcfed08 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Nov 2024 11:41:48 -0700 Subject: [PATCH 058/307] build(deps): bump @docsearch/react from 3.6.2 to 3.6.3 in /docs (#30797) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- docs/package.json | 2 +- docs/yarn.lock | 174 +++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 158 insertions(+), 18 deletions(-) diff --git a/docs/package.json b/docs/package.json index 83dc5b97f63ef..b4e88f203af84 100644 --- a/docs/package.json +++ b/docs/package.json @@ -19,7 +19,7 @@ "dependencies": { "@algolia/client-search": "^4.24.0", "@ant-design/icons": "^5.4.0", - "@docsearch/react": "^3.6.2", + "@docsearch/react": "^3.6.3", "@docusaurus/core": "^3.5.2", "@docusaurus/plugin-client-redirects": "^3.5.2", "@docusaurus/preset-classic": "^3.5.2", diff --git a/docs/yarn.lock b/docs/yarn.lock index 5d3542405f471..c4b06390ff2ec 100644 --- a/docs/yarn.lock +++ b/docs/yarn.lock @@ -17,12 +17,17 @@ dependencies: "@algolia/autocomplete-shared" "1.9.3" -"@algolia/autocomplete-preset-algolia@1.9.3": - version "1.9.3" - resolved "https://registry.yarnpkg.com/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.9.3.tgz#64cca4a4304cfcad2cf730e83067e0c1b2f485da" - integrity sha512-d4qlt6YmrLMYy95n5TB52wtNDr6EgAIPH81dvvvW8UmuWRgxEtY0NJiPwl/h95JtG2vmRM804M0DSwMCNZlzRA== +"@algolia/autocomplete-preset-algolia@1.17.6": + version "1.17.6" + resolved "https://registry.yarnpkg.com/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.17.6.tgz#465b652bff5c262aad4da2488d78629cfa906be6" + integrity sha512-Cvg5JENdSCMuClwhJ1ON1/jSuojaYMiUW2KePm18IkdCzPJj/NXojaOxw58RFtQFpJgfVW8h2E8mEoDtLlMdeA== dependencies: - "@algolia/autocomplete-shared" "1.9.3" + "@algolia/autocomplete-shared" "1.17.6" + +"@algolia/autocomplete-shared@1.17.6": + version "1.17.6" + resolved "https://registry.yarnpkg.com/@algolia/autocomplete-shared/-/autocomplete-shared-1.17.6.tgz#ad951632b6d477d4ba9a68a347e1702d26009d58" + integrity sha512-aq/3V9E00Tw2GC/PqgyPGXtqJUlVc17v4cn1EUhSc+O/4zd04Uwb3UmPm8KDaYQQOrkt1lwvCj2vG2wRE5IKhw== "@algolia/autocomplete-shared@1.9.3": version "1.9.3" @@ -53,6 +58,16 @@ dependencies: "@algolia/cache-common" "4.23.3" +"@algolia/client-abtesting@5.12.0": + version "5.12.0" + resolved "https://registry.yarnpkg.com/@algolia/client-abtesting/-/client-abtesting-5.12.0.tgz#45175422ee85d505ff6a16d1634a739478a6ad0b" + integrity sha512-hx4eVydkm3yrFCFxmcBtSzI/ykt0cZ6sDWch+v3JTgKpD2WtosMJU3Upv1AjQ4B6COSHCOWEX3vfFxW6OoH6aA== + dependencies: + "@algolia/client-common" "5.12.0" + "@algolia/requester-browser-xhr" "5.12.0" + "@algolia/requester-fetch" "5.12.0" + "@algolia/requester-node-http" "5.12.0" + "@algolia/client-account@4.23.3": version "4.23.3" resolved "https://registry.yarnpkg.com/@algolia/client-account/-/client-account-4.23.3.tgz#8751bbf636e6741c95e7c778488dee3ee430ac6f" @@ -72,6 +87,16 @@ "@algolia/requester-common" "4.23.3" "@algolia/transporter" "4.23.3" +"@algolia/client-analytics@5.12.0": + version "5.12.0" + resolved "https://registry.yarnpkg.com/@algolia/client-analytics/-/client-analytics-5.12.0.tgz#e387f4de01f4fb549b7506762003bef335be2927" + integrity sha512-EpTsSv6IW8maCfXCDIptgT7+mQJj7pImEkcNUnxR8yUKAHzTogTXv9yGm2WXOZFVuwstd2i0sImhQ1Vz8RH/hA== + dependencies: + "@algolia/client-common" "5.12.0" + "@algolia/requester-browser-xhr" "5.12.0" + "@algolia/requester-fetch" "5.12.0" + "@algolia/requester-node-http" "5.12.0" + "@algolia/client-common@4.23.3": version "4.23.3" resolved "https://registry.yarnpkg.com/@algolia/client-common/-/client-common-4.23.3.tgz#891116aa0db75055a7ecc107649f7f0965774704" @@ -88,6 +113,21 @@ "@algolia/requester-common" "4.24.0" "@algolia/transporter" "4.24.0" +"@algolia/client-common@5.12.0": + version "5.12.0" + resolved "https://registry.yarnpkg.com/@algolia/client-common/-/client-common-5.12.0.tgz#e33b6fefb333beb56eb58ab7424fcd7ec11ac7d0" + integrity sha512-od3WmO8qxyfNhKc+K3D17tvun3IMs/xMNmxCG9MiElAkYVbPPTRUYMkRneCpmJyQI0hNx2/EA4kZgzVfQjO86Q== + +"@algolia/client-insights@5.12.0": + version "5.12.0" + resolved "https://registry.yarnpkg.com/@algolia/client-insights/-/client-insights-5.12.0.tgz#bb80c4227178b452dd93a649b9991b8140cba52d" + integrity sha512-8alajmsYUd+7vfX5lpRNdxqv3Xx9clIHLUItyQK0Z6gwGMbVEFe6YYhgDtwslMAP0y6b0WeJEIZJMLgT7VYpRw== + dependencies: + "@algolia/client-common" "5.12.0" + "@algolia/requester-browser-xhr" "5.12.0" + "@algolia/requester-fetch" "5.12.0" + "@algolia/requester-node-http" "5.12.0" + "@algolia/client-personalization@4.23.3": version "4.23.3" resolved "https://registry.yarnpkg.com/@algolia/client-personalization/-/client-personalization-4.23.3.tgz#35fa8e5699b0295fbc400a8eb211dc711e5909db" @@ -97,6 +137,26 @@ "@algolia/requester-common" "4.23.3" "@algolia/transporter" "4.23.3" +"@algolia/client-personalization@5.12.0": + version "5.12.0" + resolved "https://registry.yarnpkg.com/@algolia/client-personalization/-/client-personalization-5.12.0.tgz#ad711245403754686efff6a65d6c83877e64ecfa" + integrity sha512-bUV9HtfkTBgpoVhxFrMkmVPG03ZN1Rtn51kiaEtukucdk3ggjR9Qu1YUfRSU2lFgxr9qJc8lTxwfvhjCeJRcqw== + dependencies: + "@algolia/client-common" "5.12.0" + "@algolia/requester-browser-xhr" "5.12.0" + "@algolia/requester-fetch" "5.12.0" + "@algolia/requester-node-http" "5.12.0" + +"@algolia/client-query-suggestions@5.12.0": + version "5.12.0" + resolved "https://registry.yarnpkg.com/@algolia/client-query-suggestions/-/client-query-suggestions-5.12.0.tgz#fc3bbf6d86e8989bb8487dc69ec49743fa75ceb4" + integrity sha512-Q5CszzGWfxbIDs9DJ/QJsL7bP6h+lJMg27KxieEnI9KGCu0Jt5iFA3GkREkgRZxRdzlHbZKkrIzhtHVbSHw/rg== + dependencies: + "@algolia/client-common" "5.12.0" + "@algolia/requester-browser-xhr" "5.12.0" + "@algolia/requester-fetch" "5.12.0" + "@algolia/requester-node-http" "5.12.0" + "@algolia/client-search@4.23.3": version "4.23.3" resolved "https://registry.yarnpkg.com/@algolia/client-search/-/client-search-4.23.3.tgz#a3486e6af13a231ec4ab43a915a1f318787b937f" @@ -106,6 +166,16 @@ "@algolia/requester-common" "4.23.3" "@algolia/transporter" "4.23.3" +"@algolia/client-search@5.12.0": + version "5.12.0" + resolved "https://registry.yarnpkg.com/@algolia/client-search/-/client-search-5.12.0.tgz#cd3eb4854664177d6e992bb2b942e2a12e4cb919" + integrity sha512-R3qzEytgVLHOGNri+bpta6NtTt7YtkvUe/QBcAmMDjW4Jk1P0eBYIPfvnzIPbINRsLxIq9fZs9uAYBgsrts4Zg== + dependencies: + "@algolia/client-common" "5.12.0" + "@algolia/requester-browser-xhr" "5.12.0" + "@algolia/requester-fetch" "5.12.0" + "@algolia/requester-node-http" "5.12.0" + "@algolia/client-search@^4.24.0": version "4.24.0" resolved "https://registry.yarnpkg.com/@algolia/client-search/-/client-search-4.24.0.tgz#75e6c02d33ef3e0f34afd9962c085b856fc4a55f" @@ -120,6 +190,16 @@ resolved "https://registry.yarnpkg.com/@algolia/events/-/events-4.0.1.tgz#fd39e7477e7bc703d7f893b556f676c032af3950" integrity sha512-FQzvOCgoFXAbf5Y6mYozw2aj5KCJoA3m4heImceldzPSMbdyS4atVjJzXKMsfX3wnZTFYwkkt8/z8UesLHlSBQ== +"@algolia/ingestion@1.12.0": + version "1.12.0" + resolved "https://registry.yarnpkg.com/@algolia/ingestion/-/ingestion-1.12.0.tgz#01a297fb2a58019595e5d74e95939da033a18194" + integrity sha512-zpHo6qhR22tL8FsdSI4DvEraPDi/019HmMrCFB/TUX98yzh5ooAU7sNW0qPL1I7+S++VbBmNzJOEU9VI8tEC8A== + dependencies: + "@algolia/client-common" "5.12.0" + "@algolia/requester-browser-xhr" "5.12.0" + "@algolia/requester-fetch" "5.12.0" + "@algolia/requester-node-http" "5.12.0" + "@algolia/logger-common@4.23.3": version "4.23.3" resolved "https://registry.yarnpkg.com/@algolia/logger-common/-/logger-common-4.23.3.tgz#35c6d833cbf41e853a4f36ba37c6e5864920bfe9" @@ -137,6 +217,16 @@ dependencies: "@algolia/logger-common" "4.23.3" +"@algolia/monitoring@1.12.0": + version "1.12.0" + resolved "https://registry.yarnpkg.com/@algolia/monitoring/-/monitoring-1.12.0.tgz#f510bfd9d09352b31ccce293d1fd84cdea59354c" + integrity sha512-i2AJZED/zf4uhxezAJUhMKoL5QoepCBp2ynOYol0N76+TSoohaMADdPnWCqOULF4RzOwrG8wWynAwBlXsAI1RQ== + dependencies: + "@algolia/client-common" "5.12.0" + "@algolia/requester-browser-xhr" "5.12.0" + "@algolia/requester-fetch" "5.12.0" + "@algolia/requester-node-http" "5.12.0" + "@algolia/recommend@4.23.3": version "4.23.3" resolved "https://registry.yarnpkg.com/@algolia/recommend/-/recommend-4.23.3.tgz#53d4f194d22d9c72dc05f3f7514c5878f87c5890" @@ -154,6 +244,16 @@ "@algolia/requester-node-http" "4.23.3" "@algolia/transporter" "4.23.3" +"@algolia/recommend@5.12.0": + version "5.12.0" + resolved "https://registry.yarnpkg.com/@algolia/recommend/-/recommend-5.12.0.tgz#bc9f69c78c08ba9a3579e7fe2a0f4037b494cc55" + integrity sha512-0jmZyKvYnB/Bj5c7WKsKedOUjnr0UtXm0LVFUdQrxXfqOqvWv9n6Vpr65UjdYG4Q49kRQxhlwtal9WJYrYymXg== + dependencies: + "@algolia/client-common" "5.12.0" + "@algolia/requester-browser-xhr" "5.12.0" + "@algolia/requester-fetch" "5.12.0" + "@algolia/requester-node-http" "5.12.0" + "@algolia/requester-browser-xhr@4.23.3": version "4.23.3" resolved "https://registry.yarnpkg.com/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.23.3.tgz#9e47e76f60d540acc8b27b4ebc7a80d1b41938b9" @@ -161,6 +261,13 @@ dependencies: "@algolia/requester-common" "4.23.3" +"@algolia/requester-browser-xhr@5.12.0": + version "5.12.0" + resolved "https://registry.yarnpkg.com/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.12.0.tgz#dba0072d5098a145e4724a723ea1c765b4af0cb6" + integrity sha512-KxwleraFuVoEGCoeW6Y1RAEbgBMS7SavqeyzWdtkJc6mXeCOJXn1iZitb8Tyn2FcpMNUKlSm0adrUTt7G47+Ow== + dependencies: + "@algolia/client-common" "5.12.0" + "@algolia/requester-common@4.23.3": version "4.23.3" resolved "https://registry.yarnpkg.com/@algolia/requester-common/-/requester-common-4.23.3.tgz#7dbae896e41adfaaf1d1fa5f317f83a99afb04b3" @@ -171,6 +278,13 @@ resolved "https://registry.yarnpkg.com/@algolia/requester-common/-/requester-common-4.24.0.tgz#1c60c198031f48fcdb9e34c4057a3ea987b9a436" integrity sha512-k3CXJ2OVnvgE3HMwcojpvY6d9kgKMPRxs/kVohrwF5WMr2fnqojnycZkxPoEg+bXm8fi5BBfFmOqgYztRtHsQA== +"@algolia/requester-fetch@5.12.0": + version "5.12.0" + resolved "https://registry.yarnpkg.com/@algolia/requester-fetch/-/requester-fetch-5.12.0.tgz#4db2772b9b0699fdfadbcd7b87e0608a4acf8363" + integrity sha512-FuDZXUGU1pAg2HCnrt8+q1VGHKChV/LhvjvZlLOT7e56GJie6p+EuLu4/hMKPOVuQQ8XXtrTHKIU3Lw+7O5/bQ== + dependencies: + "@algolia/client-common" "5.12.0" + "@algolia/requester-node-http@4.23.3": version "4.23.3" resolved "https://registry.yarnpkg.com/@algolia/requester-node-http/-/requester-node-http-4.23.3.tgz#c9f94a5cb96a15f48cea338ab6ef16bbd0ff989f" @@ -178,6 +292,13 @@ dependencies: "@algolia/requester-common" "4.23.3" +"@algolia/requester-node-http@5.12.0": + version "5.12.0" + resolved "https://registry.yarnpkg.com/@algolia/requester-node-http/-/requester-node-http-5.12.0.tgz#6c6bb47df33351b819790f26346632196c97a3c7" + integrity sha512-ncDDY7CxZhMs6LIoPl+vHFQceIBhYPY5EfuGF1V7beO0U38xfsCYEyutEFB2kRzf4D9Gqppn3iWX71sNtrKcuw== + dependencies: + "@algolia/client-common" "5.12.0" + "@algolia/transporter@4.23.3": version "4.23.3" resolved "https://registry.yarnpkg.com/@algolia/transporter/-/transporter-4.23.3.tgz#545b045b67db3850ddf0bbecbc6c84ff1f3398b7" @@ -1335,20 +1456,20 @@ resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70" integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw== -"@docsearch/css@3.6.2": - version "3.6.2" - resolved "https://registry.yarnpkg.com/@docsearch/css/-/css-3.6.2.tgz#ccd9c83dbfeaf34efe4e3547ee596714ae7e5891" - integrity sha512-vKNZepO2j7MrYBTZIGXvlUOIR+v9KRf70FApRgovWrj3GTs1EITz/Xb0AOlm1xsQBp16clVZj1SY/qaOJbQtZw== +"@docsearch/css@3.6.3": + version "3.6.3" + resolved "https://registry.yarnpkg.com/@docsearch/css/-/css-3.6.3.tgz#d787cc9d27a7e67305fa47d668656eb2e64c4526" + integrity sha512-3uvbg8E7rhqE1C4oBAK3tGlS2qfhi9zpfZgH/yjDPF73vd9B41urVIKujF4rczcF4E3qs34SedhehiDJ4UdNBA== -"@docsearch/react@^3.5.2", "@docsearch/react@^3.6.2": - version "3.6.2" - resolved "https://registry.yarnpkg.com/@docsearch/react/-/react-3.6.2.tgz#32b16dd7d5614f0d39e6bc018549816b68d171b8" - integrity sha512-rtZce46OOkVflCQH71IdbXSFK+S8iJZlUF56XBW5rIgx/eG5qoomC7Ag3anZson1bBac/JFQn7XOBfved/IMRA== +"@docsearch/react@^3.5.2", "@docsearch/react@^3.6.3": + version "3.6.3" + resolved "https://registry.yarnpkg.com/@docsearch/react/-/react-3.6.3.tgz#326a0811306060bfb481df3cd0db51adaa9f737c" + integrity sha512-2munr4uBuZq1PG+Ge+F+ldIdxb3Wi8OmEIv2tQQb4RvEvvph+xtQkxwHzVIEnt5s+HecwucuXwB+3JhcZboFLg== dependencies: "@algolia/autocomplete-core" "1.9.3" - "@algolia/autocomplete-preset-algolia" "1.9.3" - "@docsearch/css" "3.6.2" - algoliasearch "^4.19.1" + "@algolia/autocomplete-preset-algolia" "1.17.6" + "@docsearch/css" "3.6.3" + algoliasearch "^5.11.0" "@docusaurus/core@3.5.2", "@docusaurus/core@^3.5.2": version "3.5.2" @@ -3258,7 +3379,7 @@ algoliasearch-helper@^3.13.3: dependencies: "@algolia/events" "^4.0.1" -algoliasearch@^4.18.0, algoliasearch@^4.19.1: +algoliasearch@^4.18.0: version "4.23.3" resolved "https://registry.yarnpkg.com/algoliasearch/-/algoliasearch-4.23.3.tgz#e09011d0a3b0651444916a3e6bbcba064ec44b60" integrity sha512-Le/3YgNvjW9zxIQMRhUHuhiUjAlKY/zsdZpfq4dlLqg6mEm0nL6yk+7f2hDOtLpxsgE4jSzDmvHL7nXdBp5feg== @@ -3279,6 +3400,25 @@ algoliasearch@^4.18.0, algoliasearch@^4.19.1: "@algolia/requester-node-http" "4.23.3" "@algolia/transporter" "4.23.3" +algoliasearch@^5.11.0: + version "5.12.0" + resolved "https://registry.yarnpkg.com/algoliasearch/-/algoliasearch-5.12.0.tgz#2e822a7916d691e55058ea7dba277d5110969dd0" + integrity sha512-psGBRYdGgik8I6m28iAB8xpubvjEt7UQU+w5MAJUA2324WHiGoHap5BPkkjB14rMaXeRts6pmOsrVIglGyOVwg== + dependencies: + "@algolia/client-abtesting" "5.12.0" + "@algolia/client-analytics" "5.12.0" + "@algolia/client-common" "5.12.0" + "@algolia/client-insights" "5.12.0" + "@algolia/client-personalization" "5.12.0" + "@algolia/client-query-suggestions" "5.12.0" + "@algolia/client-search" "5.12.0" + "@algolia/ingestion" "1.12.0" + "@algolia/monitoring" "1.12.0" + "@algolia/recommend" "5.12.0" + "@algolia/requester-browser-xhr" "5.12.0" + "@algolia/requester-fetch" "5.12.0" + "@algolia/requester-node-http" "5.12.0" + ansi-align@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-3.0.1.tgz#0cdf12e111ace773a86e9a1fad1225c43cb19a59" From d217a78857f5bbf08e411cc78df5b8383702931a Mon Sep 17 00:00:00 2001 From: Evan Rusackas Date: Tue, 5 Nov 2024 14:27:44 -0700 Subject: [PATCH 059/307] chore(actions): Bump Linkinator in superset-docs-verify.yml (#30846) --- .github/workflows/superset-docs-verify.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/superset-docs-verify.yml b/.github/workflows/superset-docs-verify.yml index 70da191621afb..c33b55c6b91f8 100644 --- a/.github/workflows/superset-docs-verify.yml +++ b/.github/workflows/superset-docs-verify.yml @@ -22,7 +22,7 @@ jobs: - uses: actions/checkout@v4 # Do not bump this linkinator-action version without opening # an ASF Infra ticket to allow the new verison first! - - uses: JustinBeckwith/linkinator-action@v1.10.4 + - uses: JustinBeckwith/linkinator-action@v1.11.0 with: paths: "**/*.md, **/*.mdx" linksToSkip: >- From 3be6cef5970836079c23dbaeccf26b03bba20e3a Mon Sep 17 00:00:00 2001 From: Evan Rusackas Date: Tue, 5 Nov 2024 14:36:38 -0700 Subject: [PATCH 060/307] chore(scripts): purge node_modules folder on `npm prune` (#30255) --- superset-frontend/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/superset-frontend/package.json b/superset-frontend/package.json index bded686f7e8d6..626a4560b93dc 100644 --- a/superset-frontend/package.json +++ b/superset-frontend/package.json @@ -65,7 +65,7 @@ "prettier": "npm run _prettier -- --write", "prettier-check": "npm run _prettier -- --check", "prod": "npm run build", - "prune": "rm -rf ./{packages,plugins}/*/{lib,esm,tsconfig.tsbuildinfo,package-lock.json}", + "prune": "rm -rf ./{packages,plugins}/*/{node_modules,lib,esm,tsconfig.tsbuildinfo,package-lock.json} ./.temp_cache", "storybook": "cross-env NODE_ENV=development BABEL_ENV=development storybook dev -p 6006", "tdd": "cross-env NODE_ENV=test NODE_OPTIONS=\"--max-old-space-size=4096\" jest --watch", "test": "cross-env NODE_ENV=test NODE_OPTIONS=\"--max-old-space-size=4096\" jest --max-workers=50%", From 8c7a3bf85a2b535e03030ad0d195f65a25a75843 Mon Sep 17 00:00:00 2001 From: Antonio Rivero <38889534+Antonio-RiveroMartnez@users.noreply.github.com> Date: Wed, 6 Nov 2024 13:26:11 +0100 Subject: [PATCH 061/307] fix(time_comparison): Allow deleting dates when using custom shift (#30848) --- .../src/constants.ts | 3 + .../src/sections/timeComparison.tsx | 28 ++++++- .../controls/TimeOffsetControl.test.tsx | 80 +++++++++++++++++++ .../components/controls/TimeOffsetControl.tsx | 23 ++++-- 4 files changed, 127 insertions(+), 7 deletions(-) create mode 100644 superset-frontend/src/explore/components/controls/TimeOffsetControl.test.tsx diff --git a/superset-frontend/packages/superset-ui-chart-controls/src/constants.ts b/superset-frontend/packages/superset-ui-chart-controls/src/constants.ts index d31843690b763..6534258c66f56 100644 --- a/superset-frontend/packages/superset-ui-chart-controls/src/constants.ts +++ b/superset-frontend/packages/superset-ui-chart-controls/src/constants.ts @@ -80,3 +80,6 @@ export const DEFAULT_XAXIS_SORT_SERIES_DATA: SortSeriesData = { }; export const DEFAULT_DATE_PATTERN = /\d{4}-\d{2}-\d{2}/g; + +// When moment fails to parse a date +export const INVALID_DATE = 'Invalid date'; diff --git a/superset-frontend/packages/superset-ui-chart-controls/src/sections/timeComparison.tsx b/superset-frontend/packages/superset-ui-chart-controls/src/sections/timeComparison.tsx index 17239de87ff76..901c34abc8508 100644 --- a/superset-frontend/packages/superset-ui-chart-controls/src/sections/timeComparison.tsx +++ b/superset-frontend/packages/superset-ui-chart-controls/src/sections/timeComparison.tsx @@ -18,7 +18,12 @@ */ import { t, ComparisonType } from '@superset-ui/core'; -import { ControlPanelSectionConfig } from '../types'; +import { + ControlPanelSectionConfig, + ControlPanelState, + ControlState, +} from '../types'; +import { INVALID_DATE } from '..'; const fullChoices = [ ['1 day ago', t('1 day ago')], @@ -94,9 +99,28 @@ export const timeComparisonControls: ({ name: 'start_date_offset', config: { type: 'TimeOffsetControl', - label: t('shift start date'), + label: t('Shift start date'), visibility: ({ controls }) => controls?.time_compare.value === 'custom', + mapStateToProps: ( + state: ControlPanelState, + controlState: ControlState, + ) => { + const { form_data } = state; + const { time_compare } = form_data; + const newState = { ...controlState }; + if ( + time_compare === 'custom' && + (controlState.value === '' || controlState.value === INVALID_DATE) + ) { + newState.externalValidationErrors = [ + t('A date is required when using custom date shift'), + ]; + } else { + newState.externalValidationErrors = []; + } + return newState; + }, }, }, ], diff --git a/superset-frontend/src/explore/components/controls/TimeOffsetControl.test.tsx b/superset-frontend/src/explore/components/controls/TimeOffsetControl.test.tsx new file mode 100644 index 0000000000000..6745e34cf332a --- /dev/null +++ b/superset-frontend/src/explore/components/controls/TimeOffsetControl.test.tsx @@ -0,0 +1,80 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import configureStore from 'redux-mock-store'; +import { render, screen } from '@testing-library/react'; +import '@testing-library/jest-dom'; +import { Provider } from 'react-redux'; +import { ThemeProvider, supersetTheme } from '@superset-ui/core'; +import moment from 'moment'; +import { INVALID_DATE } from '@superset-ui/chart-controls'; +import TimeOffsetControls, { + TimeOffsetControlsProps, +} from './TimeOffsetControl'; + +const mockStore = configureStore([]); + +const defaultProps: TimeOffsetControlsProps = { + onChange: jest.fn(), +}; + +describe('TimeOffsetControls', () => { + const setup = (initialState = {}) => { + const store = mockStore({ + explore: { + form_data: { + adhoc_filters: [ + { + operator: 'TEMPORAL_RANGE', + subject: 'date', + comparator: '2023-01-01 : 2023-12-31', + }, + ], + start_date_offset: '2023-01-01', + ...initialState, + }, + }, + }); + + const props = { ...defaultProps }; + + render( + + + + + , + ); + + return { store, props }; + }; + + it('TimeOffsetControl renders DatePicker when startDate is set', () => { + setup(); + const datePickerInput = screen.getByRole('textbox'); + expect(datePickerInput).toBeInTheDocument(); + expect(datePickerInput).toHaveValue('2023-01-01'); + }); + + // Our Time comparison control depends on this string for supporting date deletion on date picker + // That's why this test is linked to the TimeOffsetControl component + it('Moment should return "Invalid date" when parsing an invalid date string', () => { + const invalidDate = moment('not-a-date'); + expect(invalidDate.format()).toBe(INVALID_DATE); + }); +}); diff --git a/superset-frontend/src/explore/components/controls/TimeOffsetControl.tsx b/superset-frontend/src/explore/components/controls/TimeOffsetControl.tsx index e58a87497401e..d2959483adb75 100644 --- a/superset-frontend/src/explore/components/controls/TimeOffsetControl.tsx +++ b/superset-frontend/src/explore/components/controls/TimeOffsetControl.tsx @@ -34,7 +34,10 @@ import { useSelector } from 'react-redux'; import ControlHeader from 'src/explore/components/ControlHeader'; import { RootState } from 'src/views/store'; -import { DEFAULT_DATE_PATTERN } from '@superset-ui/chart-controls'; +import { + DEFAULT_DATE_PATTERN, + INVALID_DATE, +} from '@superset-ui/chart-controls'; export interface TimeOffsetControlsProps { label?: ReactNode; @@ -68,6 +71,7 @@ export default function TimeOffsetControls({ moment.Moment | undefined >(undefined); const [savedStartDate, setSavedStartDate] = useState(null); + const [isDateSelected, setIsDateSelected] = useState(true); const currentTimeRangeFilters = useSelector( state => @@ -86,7 +90,12 @@ export default function TimeOffsetControls({ useEffect(() => { if (savedStartDate !== currentStartDate) { setSavedStartDate(currentStartDate); - onChange(moment(currentStartDate).format(MOMENT_FORMAT)); + if (currentStartDate !== INVALID_DATE) { + onChange(moment(currentStartDate).format(MOMENT_FORMAT)); + setIsDateSelected(true); + } else { + setIsDateSelected(false); + } } }, [currentStartDate]); @@ -165,8 +174,10 @@ export default function TimeOffsetControls({ setFormatedDate(moment(parseDttmToDate(date))); } } else if (savedStartDate) { - setStartDate(savedStartDate); - setFormatedDate(moment(parseDttmToDate(savedStartDate))); + if (savedStartDate !== INVALID_DATE) { + setStartDate(savedStartDate); + setFormatedDate(moment(parseDttmToDate(savedStartDate))); + } } }, [previousCustomFilter, savedStartDate, customStartDateInFilter]); @@ -180,6 +191,7 @@ export default function TimeOffsetControls({ setStartDate(resetDate.toString()); setFormatedDate(resetDate); onChange(moment.utc(resetDate).format(MOMENT_FORMAT)); + setIsDateSelected(true); } } if ( @@ -191,6 +203,7 @@ export default function TimeOffsetControls({ setStartDate(resetDate.toString()); setFormatedDate(resetDate); onChange(moment.utc(resetDate).format(MOMENT_FORMAT)); + setIsDateSelected(true); } }, [formatedFilterDate, formatedDate, customStartDateInFilter]); @@ -218,7 +231,7 @@ export default function TimeOffsetControls({ } disabledDate={disabledDate} defaultValue={moment(formatedDate)} - value={moment(formatedDate)} + value={isDateSelected ? moment(formatedDate) : null} />
) : null; From 710c6f9412edaff5dcde7ce3fa8aa654f2f35f04 Mon Sep 17 00:00:00 2001 From: Kamil Gabryjelski Date: Wed, 6 Nov 2024 15:23:22 +0100 Subject: [PATCH 062/307] chore: Chart context menu permissions cleanup (#30854) --- .../ChartContextMenu/ChartContextMenu.tsx | 21 ++------ .../Chart/ChartContextMenu/usePermissions.ts | 51 +++++++++++++++++++ 2 files changed, 54 insertions(+), 18 deletions(-) create mode 100644 superset-frontend/src/components/Chart/ChartContextMenu/usePermissions.ts diff --git a/superset-frontend/src/components/Chart/ChartContextMenu/ChartContextMenu.tsx b/superset-frontend/src/components/Chart/ChartContextMenu/ChartContextMenu.tsx index 9df0e73bc9e6c..e5a94ba97f61f 100644 --- a/superset-frontend/src/components/Chart/ChartContextMenu/ChartContextMenu.tsx +++ b/superset-frontend/src/components/Chart/ChartContextMenu/ChartContextMenu.tsx @@ -39,7 +39,6 @@ import { useTheme, } from '@superset-ui/core'; import { RootState } from 'src/dashboard/types'; -import { findPermission } from 'src/utils/findPermission'; import { Menu } from 'src/components/Menu'; import { AntdDropdown as Dropdown } from 'src/components/index'; import { updateDataMask } from 'src/dataMask/actions'; @@ -47,6 +46,7 @@ import { DrillDetailMenuItems } from '../DrillDetail'; import { getMenuAdjustedY } from '../utils'; import { MenuItemTooltip } from '../DisabledMenuItemTooltip'; import { DrillByMenuItems } from '../DrillBy/DrillByMenuItems'; +import { usePermissions } from './usePermissions'; export enum ContextMenuItem { CrossFilter, @@ -88,23 +88,8 @@ const ChartContextMenu = ( ) => { const theme = useTheme(); const dispatch = useDispatch(); - const canExplore = useSelector((state: RootState) => - findPermission('can_explore', 'Superset', state.user?.roles), - ); - const canWriteExploreFormData = useSelector((state: RootState) => - findPermission('can_write', 'ExploreFormDataRestApi', state.user?.roles), - ); - const canDatasourceSamples = useSelector((state: RootState) => - findPermission('can_samples', 'Datasource', state.user?.roles), - ); - const canDownload = useSelector((state: RootState) => - findPermission('can_csv', 'Superset', state.user?.roles), - ); - const canDrill = useSelector((state: RootState) => - findPermission('can_drill', 'Dashboard', state.user?.roles), - ); - const canDrillBy = (canExplore || canDrill) && canWriteExploreFormData; - const canDrillToDetail = (canExplore || canDrill) && canDatasourceSamples; + const { canDrillToDetail, canDrillBy, canDownload } = usePermissions(); + const crossFiltersEnabled = useSelector( ({ dashboardInfo }) => dashboardInfo.crossFiltersEnabled, ); diff --git a/superset-frontend/src/components/Chart/ChartContextMenu/usePermissions.ts b/superset-frontend/src/components/Chart/ChartContextMenu/usePermissions.ts new file mode 100644 index 0000000000000..ef45cdf0b4a2f --- /dev/null +++ b/superset-frontend/src/components/Chart/ChartContextMenu/usePermissions.ts @@ -0,0 +1,51 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { useSelector } from 'react-redux'; +import { RootState } from 'src/dashboard/types'; +import { findPermission } from 'src/utils/findPermission'; + +export const usePermissions = () => { + const canExplore = useSelector((state: RootState) => + findPermission('can_explore', 'Superset', state.user?.roles), + ); + const canWriteExploreFormData = useSelector((state: RootState) => + findPermission('can_write', 'ExploreFormDataRestApi', state.user?.roles), + ); + const canDatasourceSamples = useSelector((state: RootState) => + findPermission('can_samples', 'Datasource', state.user?.roles), + ); + const canDownload = useSelector((state: RootState) => + findPermission('can_csv', 'Superset', state.user?.roles), + ); + const canDrill = useSelector((state: RootState) => + findPermission('can_drill', 'Dashboard', state.user?.roles), + ); + const canDrillBy = (canExplore || canDrill) && canWriteExploreFormData; + const canDrillToDetail = (canExplore || canDrill) && canDatasourceSamples; + + return { + canExplore, + canWriteExploreFormData, + canDatasourceSamples, + canDownload, + canDrill, + canDrillBy, + canDrillToDetail, + }; +}; From de8282cea0d36c41ce2b780cc5f13ce9d5d3f0ee Mon Sep 17 00:00:00 2001 From: Geido <60598000+geido@users.noreply.github.com> Date: Wed, 6 Nov 2024 20:47:07 +0200 Subject: [PATCH 063/307] fix(package.json): Pin luxon version to unblock master (#30859) --- superset-frontend/package-lock.json | 17 +++++++++-------- superset-frontend/package.json | 1 + 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/superset-frontend/package-lock.json b/superset-frontend/package-lock.json index 472a8f2ec3659..dfaecc84df430 100644 --- a/superset-frontend/package-lock.json +++ b/superset-frontend/package-lock.json @@ -87,6 +87,7 @@ "json-bigint": "^1.0.0", "json-stringify-pretty-compact": "^2.0.0", "lodash": "^4.17.21", + "luxon": "^3.5.0", "mapbox-gl": "^2.10.0", "markdown-to-jsx": "^7.4.7", "match-sorter": "^6.3.4", @@ -34959,10 +34960,10 @@ } }, "node_modules/luxon": { - "version": "3.4.4", + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.5.0.tgz", + "integrity": "sha512-rh+Zjr6DNfUYR3bPwJEnuwDdqMbxZW7LOQfUN4B54+Cl+0o5zaU9RJ6bcidfDtC1cWCZXQ+nvX8bf6bAji37QQ==", "license": "MIT", - "optional": true, - "peer": true, "engines": { "node": ">=12" } @@ -58103,7 +58104,7 @@ "d3-array": "^1.2.4", "d3-color": "^1.4.1", "d3-scale": "^3.0.0", - "deck.gl": "9.0.28", + "deck.gl": "9.0.34", "lodash": "^4.17.21", "moment": "^2.30.1", "mousetrap": "^1.6.5", @@ -68831,7 +68832,7 @@ "d3-array": "^1.2.4", "d3-color": "^1.4.1", "d3-scale": "^3.0.0", - "deck.gl": "9.0.28", + "deck.gl": "9.0.34", "lodash": "^4.17.21", "moment": "^2.30.1", "mousetrap": "^1.6.5", @@ -84308,9 +84309,9 @@ } }, "luxon": { - "version": "3.4.4", - "optional": true, - "peer": true + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.5.0.tgz", + "integrity": "sha512-rh+Zjr6DNfUYR3bPwJEnuwDdqMbxZW7LOQfUN4B54+Cl+0o5zaU9RJ6bcidfDtC1cWCZXQ+nvX8bf6bAji37QQ==" }, "lz-string": { "version": "1.5.0" diff --git a/superset-frontend/package.json b/superset-frontend/package.json index 626a4560b93dc..434f95032512a 100644 --- a/superset-frontend/package.json +++ b/superset-frontend/package.json @@ -153,6 +153,7 @@ "json-bigint": "^1.0.0", "json-stringify-pretty-compact": "^2.0.0", "lodash": "^4.17.21", + "luxon": "^3.5.0", "mapbox-gl": "^2.10.0", "markdown-to-jsx": "^7.4.7", "match-sorter": "^6.3.4", From 5b2f005e80e4dbc862e9a6f7bb310fff84673274 Mon Sep 17 00:00:00 2001 From: alexandrusoare <37236580+alexandrusoare@users.noreply.github.com> Date: Thu, 7 Nov 2024 13:08:32 +0200 Subject: [PATCH 064/307] chore(FilterBar): Filter bar accessibility (#30812) --- superset-frontend/src/components/Select/Select.tsx | 3 ++- .../FilterBar/FilterControls/FilterControl.tsx | 7 +++++-- .../controls/DateFilterControl/DateFilterLabel.tsx | 7 +++++++ .../controls/DateFilterControl/components/DateLabel.tsx | 9 +++++++-- .../src/filters/components/Range/RangeFilterPlugin.tsx | 5 ++++- .../src/filters/components/Select/SelectFilterPlugin.tsx | 1 + .../src/filters/components/Time/TimeFilterPlugin.tsx | 2 +- .../components/TimeColumn/TimeColumnFilterPlugin.tsx | 1 + .../components/TimeGrain/TimeGrainFilterPlugin.tsx | 1 + 9 files changed, 29 insertions(+), 7 deletions(-) diff --git a/superset-frontend/src/components/Select/Select.tsx b/superset-frontend/src/components/Select/Select.tsx index bebb788879794..91f9515448dc2 100644 --- a/superset-frontend/src/components/Select/Select.tsx +++ b/superset-frontend/src/components/Select/Select.tsx @@ -608,8 +608,9 @@ const Select = forwardRef( {header} )} ( - + {name} {isRequired && } @@ -315,7 +318,7 @@ const FilterControl = ({
diff --git a/superset-frontend/src/explore/components/controls/DateFilterControl/DateFilterLabel.tsx b/superset-frontend/src/explore/components/controls/DateFilterControl/DateFilterLabel.tsx index ebdd716b91496..2003f5212fe69 100644 --- a/superset-frontend/src/explore/components/controls/DateFilterControl/DateFilterLabel.tsx +++ b/superset-frontend/src/explore/components/controls/DateFilterControl/DateFilterLabel.tsx @@ -152,6 +152,7 @@ const getTooltipTitle = ( export default function DateFilterLabel(props: DateFilterControlProps) { const { + name, onChange, onOpenPopover = noOp, onClosePopover = noOp, @@ -384,6 +385,9 @@ export default function DateFilterLabel(props: DateFilterControlProps) { getPopupContainer={trigger => trigger.parentElement as HTMLElement} > trigger.parentElement as HTMLElement} > ) => { const theme = useTheme(); return ( - - + + {typeof props.label === 'string' ? t(props.label) : props.label} {t('Chosen non-numeric column')} ) : ( - + + +); + +export const InteractiveInputNumber = (args: InputNumberProps) => ( + + + +); + +export const InteractiveTextArea = (args: TextAreaProps) => ( + +