Compare commits

...

71 Commits

Author SHA1 Message Date
Michael S. Molina
c35842e9f1 chore: Adds 4.0.0 RC2 data to CHANGELOG.md 2024-04-01 16:18:03 -03:00
Michael S. Molina
6a21f6da3d chore: Adds the 4.0 release notes (#27441)
Co-authored-by: John Bodley <4567245+john-bodley@users.noreply.github.com>
Co-authored-by: Sam Firke <sfirke@users.noreply.github.com>
(cherry picked from commit ca47717eb0)
2024-04-01 16:14:10 -03:00
John Bodley
0d5be95826 chore(docs): Cleanup UPDATING.md (#27768)
(cherry picked from commit 8ae4662f17)
2024-04-01 16:06:30 -03:00
Michael S. Molina
b7fa3edcf4 fix: Select onChange is fired when the same item is selected in single mode (#27706)
(cherry picked from commit d69a1870a0)
2024-04-01 16:06:30 -03:00
Michael S. Molina
b8e556d6f2 fix: Removes filter plugins from viz gallery (#27763) 2024-04-01 16:06:09 -03:00
Elizabeth Thompson
bb5c0b4086 fix: reduce alert error to warning (#27744)
(cherry picked from commit 70da454bbc)
2024-03-28 09:27:44 -03:00
JUST.in DO IT
2fa1b35c16 perf(explore): virtualized datasource field sections (#27625)
(cherry picked from commit 38eecfc5d4)
2024-03-28 09:27:44 -03:00
JUST.in DO IT
a024b4ac1b fix(explore): drag and drop indicator UX (#27558)
(cherry picked from commit 7369754192)
2024-03-28 09:27:43 -03:00
John Bodley
5c567895cc fix: Provide more inclusive error handling for saved queries (#27644)
(cherry picked from commit 3ae74d1f2d)
2024-03-26 16:37:40 -03:00
John Bodley
51ad63426c fix: Leverage actual database for rendering Jinjarized SQL (#27646) 2024-03-26 16:37:22 -03:00
Jack
34b06f94ab fix(AlertReports): disabling value when not null option is active (#27550)
(cherry picked from commit ed9e542781)
2024-03-26 15:37:36 -03:00
JUST.in DO IT
32aa25ae17 fix(sqllab): unable to remove table (#27636)
(cherry picked from commit fa3fea9dd8)
2024-03-26 15:37:36 -03:00
Ross Mabbett
29553939a2 fix(Chart Annotation modal): Table and Superset annotation options will paginate, exceeding previous max limit 100 (#27022)
(cherry picked from commit ce210eebde)
2024-03-26 15:37:36 -03:00
Jack
d8517213bf fix(AlertReports): defaulting grace period to undefined (#27552)
(cherry picked from commit 4fce940a9c)
2024-03-26 15:37:36 -03:00
Jack
3bfa8a9cbc fix(AlertReports): clearing custom_width when disabled (#27551)
(cherry picked from commit 0f6e4041c7)
2024-03-26 15:36:06 -03:00
John Bodley
7c14968e6d fix(sql_parse): Ensure table extraction handles Jinja templating (#27470) 2024-03-22 09:29:07 -03:00
Kamil Gabryjelski
4ff331a66c fix: Persist query params appended to permalink (#27601)
(cherry picked from commit 5083ca0e81)
2024-03-22 09:28:27 -03:00
Ross Mabbett
a2fb13b522 fix(Dashboard): Add editMode conditional for translate3d fix on charts to allow intended Fullscreen (#27613)
(cherry picked from commit 842b0939f6)
2024-03-22 09:28:27 -03:00
Sam Firke
fe95adac98 fix(utils): fix off-by-one error in how rolling window's min_periods truncates dataframe (#27388)
(cherry picked from commit d4d8625ab8)
2024-03-22 09:28:27 -03:00
Pat Nadolny
90afb34df5 fix: Volatile datasource ordering in dashboard export (#19595)
Co-authored-by: Michael S. Molina <70410625+michael-s-molina@users.noreply.github.com>
(cherry picked from commit bfe55b9ded)
2024-03-22 09:28:27 -03:00
Beto Dealmeida
336f6bd021 fix: sqlglot SQL Server (#27577)
(cherry picked from commit 72a41c1642)
2024-03-22 09:28:26 -03:00
Beto Dealmeida
4a59f23be3 fix: bump sqlglot to support materialized CTEs (#27576) 2024-03-21 16:21:28 -03:00
hlcianfagna
652e6cfa3f fix(db_engine_specs): Update convert_dttm to work correctly with CrateDB (#27567)
(cherry picked from commit fcceaf081c)
2024-03-21 16:19:15 -03:00
Michael S. Molina
634d72b19d fix: Skips Hive tests that are blocking PRs (#27605)
(cherry picked from commit 718cd64657)
2024-03-21 16:19:15 -03:00
Beto Dealmeida
4b750c0caf fix: guest queries (#27566)
(cherry picked from commit 36290ce72f)
2024-03-21 16:19:14 -03:00
JUST.in DO IT
f52647ff48 perf(sqllab): reduce bootstrap data delay by queries (#27488)
(cherry picked from commit f4bdcb5743)
2024-03-19 09:57:28 -03:00
Beto Dealmeida
35562198f8 fix: pass valid SQL to SM (#27464)
(cherry picked from commit 376bfd05bd)
2024-03-19 09:57:28 -03:00
Beto Dealmeida
94f677850c feat: improve _extract_tables_from_sql (#26748) 2024-03-19 09:57:09 -03:00
JUST.in DO IT
d4314a92d8 fix(explore): Allow only saved metrics and columns (#27539) 2024-03-19 09:54:00 -03:00
Jack
297849a8b5 fix(alerts/reports): implementing custom_width as an Antd number input (#27260)
(cherry picked from commit ad9024b040)
2024-03-19 09:28:13 -03:00
Ville Brofeldt
1016fd92f6 fix(postprocessing): resample with holes (#27487)
(cherry picked from commit 7f19d296b1)
2024-03-19 09:28:13 -03:00
Beto Dealmeida
017e0fc733 fix: check if guest user modified query (#27484)
(cherry picked from commit 735b895dd5)
2024-03-14 09:32:56 -03:00
Evan Rusackas
0ee452e9f9 fix(webpack): remove double-dotted file extensions in webpack config (#27471)
(cherry picked from commit 47ae9d4cc3)
2024-03-14 09:32:56 -03:00
Geido
131c254fe7 fix: SSH Tunnel configuration settings (#27186)
(cherry picked from commit 89e89de341)
2024-03-14 09:32:56 -03:00
Mark Skelton
759863553d fix(dashboard): Only fetch CSS templates for dashboard header menu when in edit mode (#27411)
Co-authored-by: Michael S. Molina <michael.s.molina@gmail.com>
(cherry picked from commit fde93dcf08)
2024-03-14 09:32:56 -03:00
Jack
15557f493d fix(deps): resolving canvg and html2canvas module not found (#27315)
(cherry picked from commit 5915851ba3)
2024-03-14 09:32:55 -03:00
JUST.in DO IT
5b6e5e475e fix: missing shared color in mixed timeseries (#27403)
(cherry picked from commit 9ced2552db)
2024-03-07 15:51:07 -03:00
JUST.in DO IT
2060e545e6 fix: typescript errors in 4.0 (#27402)
(cherry picked from commit ce0b70cc86)
2024-03-07 15:17:06 -03:00
Michael S. Molina
0baa2af200 fix: Re-enable CI checks on release branches (#27390)
(cherry picked from commit a54a24e3b5)
2024-03-07 15:17:06 -03:00
JUST.in DO IT
db6df71fad fix(sqllab): Close already removed tab (#27391)
(cherry picked from commit 5107cc0fd9)
2024-03-07 15:17:06 -03:00
Vitor Avila
4f3a7f3931 fix(API): Updating assets via the API should preserve ownership configuration (#27364)
(cherry picked from commit 66bf70172f)
2024-03-07 15:17:06 -03:00
Daniel Vaz Gaspar
94aeef5f82 fix: improve explore REST api validations (#27395)
(cherry picked from commit a3d2e0bf44)
2024-03-07 15:17:06 -03:00
Jack
19efb146b2 fix(Alerts & Reports): Fixing bug that resets cron value to default when empty (#27262)
(cherry picked from commit 32179f1a85)
2024-03-04 11:35:24 -05:00
Michael S. Molina
25b7eb0ec9 fix: Results section in Explore shows an infinite spinner (#27366)
(cherry picked from commit 231e659b56)
2024-03-04 11:16:40 -05:00
nigzak
ecebd70ba0 chore: numexpr to fix CVE-2023-39631⁠ (2.8.4 => 2.9.0) (#27187)
Co-authored-by: Stefan Arnold <stefan.st.arnold@mercedes-benz.com>
(cherry picked from commit f453d5d7e7)
2024-03-04 11:16:40 -05:00
Michael S. Molina
e9ebc386f2 fix: Missing SQL Lab permission (#27361)
(cherry picked from commit 8a46694ce9)
2024-03-04 11:16:40 -05:00
Michael S. Molina
85efe2525c fix: Heatmap numeric sorting (#27360)
(cherry picked from commit fe2f5a7be9)
2024-03-04 11:16:40 -05:00
JUST.in DO IT
f0632405c2 fix(sqllab): Missing empty query result state (#27313)
(cherry picked from commit ae8ec9c2b4)
2024-03-04 11:16:40 -05:00
Ross Mabbett
f5750dda8c fix(dashboard): table chart drag preview overflowing container (#27308)
(cherry picked from commit ad3995daf6)
2024-03-04 11:16:40 -05:00
Joe Li
c0fa4f43e1 chore: bump cryptography minimum to 42.0.4 (#27281)
(cherry picked from commit 371f2ab851)
2024-03-04 11:16:40 -05:00
JUST.in DO IT
e881675f58 fix(sqllab): invalid dump sql shown after closing tab (#27295)
(cherry picked from commit 8d245704ef)
2024-03-04 11:16:40 -05:00
goto-loop
8103f22fa3 fix(plugin-chart-echarts): calculate Gauge Chart intervals correctly when min value is set (#27285)
(cherry picked from commit d65f64d1ce)
2024-03-04 11:16:40 -05:00
Michael S. Molina
74842fe6e8 fix: Incorrect data type on import page (#27307)
(cherry picked from commit fa04eec2d5)
2024-03-04 11:16:40 -05:00
Michael S. Molina
5cba9bcb0e fix: Data zoom with horizontal orientation (#27291)
(cherry picked from commit 7854b622a3)
2024-03-04 11:16:40 -05:00
Michael S. Molina
824367564a fix: Navigating to an invalid page index in lists (#27273) 2024-03-04 11:16:25 -05:00
Michael S. Molina
6b82e27561 fix: Inoperable dashboard filter slider when range is <= 1 (#27271)
Co-authored-by: Justin Francos <jfrancos@manifold.ai>
(cherry picked from commit ce9e4b4b77)
2024-03-04 11:13:39 -05:00
James O'Claire
2e80b688bb fix(import-datasources): Use "admin" user as default for importing datasources (#27154)
(cherry picked from commit 6447cd0e92)
2024-03-04 11:13:39 -05:00
Michael S. Molina
b9ec312350 fix: Sorting charts/dashboards makes the applied filters ineffective (#27258)
(cherry picked from commit 8b4dce71d6)
2024-03-04 11:13:38 -05:00
Evan Rusackas
524dbd570d fix(trino): bumping trino to fix hudi schema fetching (#27213)
(cherry picked from commit 11760d3fbf)
2024-03-04 11:13:38 -05:00
Jack
8fd47c62c1 fix(reports): fixing unit test (#27236)
(cherry picked from commit 6278315072)
2024-03-04 11:13:38 -05:00
John Bodley
7de3e0fcda fix(sqlglot): Address regressions introduced in #26476 (#27217)
(cherry picked from commit 2c564817f1)
2024-03-04 11:13:38 -05:00
Michael S. Molina
7115b2cce6 chore: Removes Chromatic workflow and dependencies (#27232)
(cherry picked from commit 6d8870125f)
2024-03-04 11:13:38 -05:00
Daniel Vaz Gaspar
3650228f88 fix: bump FAB to 4.4.1 (perf issue) (#27233)
(cherry picked from commit 62cf0365e9)
2024-03-04 11:13:38 -05:00
Daniel Vaz Gaspar
ffa0c73776 fix: setting important lower bounds versions on requirements (#27167)
(cherry picked from commit c78ea20bef)
2024-02-23 10:49:07 -05:00
Beto Dealmeida
c29873cc81 fix: no limit in SELECT * for TOP dbs (#27215)
(cherry picked from commit c54fbe6e96)
2024-02-23 10:49:07 -05:00
Evan Rusackas
ef2ca408cc fix(releasing): fixes npm script for release validation (#27214)
(cherry picked from commit 2a47edc3a7)
2024-02-23 10:49:07 -05:00
Bill Belanger
d47fd44b49 fix: Translations related to the date range filter (#26074)
(cherry picked from commit cc2f6f1ed9)
2024-02-23 10:49:06 -05:00
JUST.in DO IT
3440a301ba fix(dashboard): drag and drop indicator UX (#26699)
(cherry picked from commit ac8c283df0)
2024-02-23 10:49:05 -05:00
Michael S. Molina
a523d9aac6 fix: Failed to execute importScripts on worker-css (#27191)
(cherry picked from commit 983a1646c4)
2024-02-23 10:49:05 -05:00
JUST.in DO IT
d69be3286a fix(sqllab): typeahead search is broken in db selector (#27181)
(cherry picked from commit 8fbaf84f66)
2024-02-23 10:49:05 -05:00
Michael S. Molina
beb9ec77a5 chore: Adds 4.0.0 RC1 data to CHANGELOG.md and UPDATING.md 2024-02-20 11:42:05 -05:00
257 changed files with 373936 additions and 371708 deletions

View File

@@ -4,7 +4,8 @@ on:
paths:
- "superset/migrations/**"
branches:
- 'master'
- "master"
- "[0-9].[0-9]"
pull_request:
paths:
- "superset/migrations/**"

View File

@@ -1,72 +0,0 @@
# .github/workflows/chromatic.yml
# see https://www.chromatic.com/docs/github-actions
#
# 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.
#
# Workflow name
name: 'Chromatic Storybook Master'
# Event for the workflow
# Only run if changes were made in superset-frontend folder of repo on merge to Master
on:
# This will trigger when a branch merges to master when the PR has changes in the frontend folder updating the chromatic baseline
push:
branches:
- master
paths:
- "superset-frontend/**"
# List of jobs
jobs:
config:
runs-on: "ubuntu-latest"
outputs:
has-secrets: ${{ steps.check.outputs.has-secrets }}
steps:
- name: "Check for secrets"
id: check
shell: bash
run: |
if [ -n "${{ (secrets.CHROMATIC_PROJECT_TOKEN != '') || '' }}" ]; then
echo "has-secrets=1" >> "$GITHUB_OUTPUT"
fi
chromatic-deployment:
needs: config
if: needs.config.outputs.has-secrets
# Operating System
runs-on: ubuntu-latest
# Job steps
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # 👈 Required to retrieve git history
- name: Install dependencies
run: npm ci
working-directory: superset-frontend
# 👇 Build and publish Storybook to Chromatic
- name: Build and publish Storybook to Chromatic
id: chromatic-master
uses: chromaui/action@v10
# Required options for the Chromatic GitHub Action
with:
# 👇 Location of package.json from root of mono-repo
workingDir: superset-frontend
# 👇 Chromatic projectToken, refer to the manage page to obtain it.
projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
exitZeroOnChanges: true # 👈 Option to prevent the workflow from failing
autoAcceptChanges: true # 👈 Option to accept all changes when merging to master

View File

@@ -2,16 +2,16 @@ name: "CodeQL"
on:
push:
branches: [ "master" ]
branches: ["master", "[0-9].[0-9]"]
paths:
- 'superset/**'
- "superset/**"
pull_request:
# The branches below must be a subset of the branches above
branches: [ "master" ]
branches: ["master"]
paths:
- 'superset/**'
- "superset/**"
schedule:
- cron: '0 4 * * *'
- cron: "0 4 * * *"
# cancel previous workflow jobs for PRs
concurrency:
@@ -30,7 +30,7 @@ jobs:
strategy:
fail-fast: false
matrix:
language: [ 'python', 'javascript' ]
language: ["python", "javascript"]
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
steps:

View File

@@ -3,9 +3,11 @@ name: Docker
on:
push:
branches:
- 'master'
- "master"
- "[0-9].[0-9]"
pull_request:
types: [synchronize, opened, reopened, ready_for_review]
branches:
- "master"
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}

View File

@@ -3,7 +3,8 @@ name: Embedded SDK Release
on:
push:
branches:
- 'master'
- "master"
- "[0-9].[0-9]"
jobs:
config:
@@ -31,7 +32,7 @@ jobs:
- uses: actions/setup-node@v4
with:
node-version: "16"
registry-url: 'https://registry.npmjs.org'
registry-url: "https://registry.npmjs.org"
- run: npm ci
- run: npm run ci:release
env:

View File

@@ -4,6 +4,7 @@ on:
push:
branches:
- "master"
- "[0-9].[0-9]"
jobs:
config:
@@ -33,8 +34,8 @@ jobs:
- name: Setup Java
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '11'
distribution: "temurin"
java-version: "11"
- name: Generate fossa report
env:
FOSSA_API_KEY: ${{ secrets.FOSSA_API_KEY }}

View File

@@ -3,7 +3,8 @@ name: pre-commit checks
on:
push:
branches:
- 'master'
- "master"
- "[0-9].[0-9]"
pull_request:
types: [synchronize, opened, reopened, ready_for_review]

View File

@@ -3,7 +3,8 @@ name: Prefer TypeScript
on:
push:
branches:
- 'master'
- "master"
- "[0-9].[0-9]"
paths:
- "superset-frontend/src/**"
pull_request:

View File

@@ -3,7 +3,8 @@ name: release-workflow
on:
push:
branches:
- 'master'
- "master"
- "[0-9].[0-9]"
jobs:
config:

View File

@@ -3,7 +3,8 @@ name: Superset CLI tests
on:
push:
branches:
- 'master'
- "master"
- "[0-9].[0-9]"
pull_request:
types: [synchronize, opened, reopened, ready_for_review]
@@ -55,8 +56,8 @@ jobs:
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: 'pip'
cache-dependency-path: 'requirements/testing.txt'
cache: "pip"
cache-dependency-path: "requirements/testing.txt"
- name: Install dependencies
if: steps.check.outcome == 'failure'
uses: ./.github/actions/cached-dependencies

View File

@@ -6,6 +6,7 @@ on:
- "docs/**"
branches:
- "master"
- "[0-9].[0-9]"
jobs:
config:
@@ -38,7 +39,7 @@ jobs:
- name: Set up Node.js 16
uses: actions/setup-node@v4
with:
node-version: '16'
node-version: "16"
- name: yarn install
run: |
yarn install --check-cache

View File

@@ -3,7 +3,8 @@ name: E2E
on:
push:
branches:
- 'master'
- "master"
- "[0-9].[0-9]"
pull_request:
types: [synchronize, opened, reopened, ready_for_review]

View File

@@ -4,6 +4,7 @@ on:
push:
branches:
- "master"
- "[0-9].[0-9]"
paths:
- "superset-frontend/**"
pull_request:

View File

@@ -4,6 +4,7 @@ on:
push:
branches:
- "master"
- "[0-9].[0-9]"
paths:
- "helm/**"

View File

@@ -4,7 +4,8 @@ name: Python-Integration
on:
push:
branches:
- 'master'
- "master"
- "[0-9].[0-9]"
pull_request:
types: [synchronize, opened, reopened, ready_for_review]
@@ -54,8 +55,8 @@ jobs:
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: 'pip'
cache-dependency-path: 'requirements/testing.txt'
cache: "pip"
cache-dependency-path: "requirements/testing.txt"
- name: Install dependencies
if: steps.check.outcome == 'failure'
uses: ./.github/actions/cached-dependencies
@@ -120,8 +121,8 @@ jobs:
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: 'pip'
cache-dependency-path: 'requirements/testing.txt'
cache: "pip"
cache-dependency-path: "requirements/testing.txt"
- name: Install dependencies
if: steps.check.outcome == 'failure'
uses: ./.github/actions/cached-dependencies
@@ -180,8 +181,8 @@ jobs:
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: 'pip'
cache-dependency-path: 'requirements/testing.txt'
cache: "pip"
cache-dependency-path: "requirements/testing.txt"
- name: Install dependencies
if: steps.check.outcome == 'failure'
uses: ./.github/actions/cached-dependencies

View File

@@ -4,7 +4,8 @@ name: Python Misc
on:
push:
branches:
- 'master'
- "master"
- "[0-9].[0-9]"
paths:
- "superset/**"
pull_request:

View File

@@ -4,7 +4,8 @@ name: Python Presto/Hive
on:
push:
branches:
- 'master'
- "master"
- "[0-9].[0-9]"
paths:
- "superset/**"
pull_request:
@@ -70,8 +71,8 @@ jobs:
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: 'pip'
cache-dependency-path: 'requirements/testing.txt'
cache: "pip"
cache-dependency-path: "requirements/testing.txt"
- name: Install dependencies
if: steps.check.outcome == 'failure'
uses: ./.github/actions/cached-dependencies
@@ -147,8 +148,8 @@ jobs:
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: 'pip'
cache-dependency-path: 'requirements/testing.txt'
cache: "pip"
cache-dependency-path: "requirements/testing.txt"
- name: Install dependencies
if: steps.check.outcome == 'failure'
uses: ./.github/actions/cached-dependencies

View File

@@ -4,7 +4,8 @@ name: Python-Unit
on:
push:
branches:
- 'master'
- "master"
- "[0-9].[0-9]"
paths:
- "superset/**"
pull_request:
@@ -43,9 +44,9 @@ jobs:
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: 'pip'
cache-dependency-path: 'requirements/testing.txt'
# TODO: separated requirements.txt file just for unit tests
cache: "pip"
cache-dependency-path: "requirements/testing.txt"
# TODO: separated requirements.txt file just for unit tests
- name: Install dependencies
if: steps.check.outcome == 'failure'
uses: ./.github/actions/cached-dependencies

View File

@@ -3,7 +3,8 @@ name: Translations
on:
push:
branches:
- 'master'
- "master"
- "[0-9].[0-9]"
pull_request:
types: [synchronize, opened, reopened, ready_for_review]
@@ -24,7 +25,7 @@ jobs:
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '16'
node-version: "16"
- name: Install dependencies
uses: ./.github/actions/cached-dependencies
with:

View File

@@ -2,7 +2,8 @@ name: WebSocket server
on:
push:
branches:
- 'master'
- "master"
- "[0-9].[0-9]"
paths:
- "superset-websocket/**"
pull_request:

View File

@@ -4,6 +4,7 @@ on:
push:
branches:
- master
- "[0-9].[0-9]"
jobs:
config:
@@ -31,7 +32,7 @@ jobs:
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '16'
node-version: "16"
- name: Install Dependencies
run: npm install
@@ -39,7 +40,7 @@ jobs:
- name: Run Script
env:
SPREADSHEET_ID: '1oABNnzxJYzwUrHjr_c9wfYEq9dFL1ScVof9LlaAdxvo'
SPREADSHEET_ID: "1oABNnzxJYzwUrHjr_c9wfYEq9dFL1ScVof9LlaAdxvo"
SERVICE_ACCOUNT_KEY: ${{ secrets.GSHEET_KEY }}
run: npm run lint-stats
continue-on-error: true

View File

@@ -37,3 +37,4 @@ under the License.
- [3.0.3](./CHANGELOG/3.0.3.md)
- [3.0.4](./CHANGELOG/3.0.4.md)
- [3.1.0](./CHANGELOG/3.1.0.md)
- [4.0.0](./CHANGELOG/4.0.0.md)

472
CHANGELOG/4.0.0.md Normal file
View File

@@ -0,0 +1,472 @@
<!--
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.
-->
## Change Log
### 4.0 (Mon Apr 1 10:04:00 2024 -0500)
**Database Migrations**
- [#27119](https://github.com/apache/superset/pull/27119) refactor: Updates some database columns to MediumText (@michael-s-molina)
- [#27029](https://github.com/apache/superset/pull/27029) chore: Add granular permissions for actions in Dashboard (@geido)
- [#26654](https://github.com/apache/superset/pull/26654) chore: add unique constraint to tagged_objects (@mistercrunch)
- [#26377](https://github.com/apache/superset/pull/26377) refactor: Removes the deprecated redirect endpoint (@michael-s-molina)
- [#26328](https://github.com/apache/superset/pull/26328) refactor: Removes the Filter Box code (@michael-s-molina)
- [#26350](https://github.com/apache/superset/pull/26350) refactor: Migrates legacy Sunburst charts to ECharts and removes legacy code (@michael-s-molina)
- [#26369](https://github.com/apache/superset/pull/26369) refactor: Removes the filters set feature (@michael-s-molina)
- [#26416](https://github.com/apache/superset/pull/26416) fix: improve performance on reports log queries (@dpgaspar)
- [#26290](https://github.com/apache/superset/pull/26290) feat(echarts-funnel): Implement % calculation type (@kgabryje)
- [#26288](https://github.com/apache/superset/pull/26288) chore: Ensure Mixins are ordered according to the MRO (@john-bodley)
**Features**
- [#27159](https://github.com/apache/superset/pull/27159) feat: bump FAB to 4.4.0 (@dpgaspar)
- [#26202](https://github.com/apache/superset/pull/26202) feat(Alerts and Reports): Modal redesign (@rtexelm)
- [#26907](https://github.com/apache/superset/pull/26907) feat(storybook): Co-habitating/Upgrading Storybooks to v7 (dependency madness ensues) (@rusackas)
- [#27092](https://github.com/apache/superset/pull/27092) feat(plugins): Tooltips on BigNumber with Time Comparison chart (@Antonio-RiveroMartnez)
- [#27052](https://github.com/apache/superset/pull/27052) feat(plugins): Adding colors to BigNumber with Time Comparison chart (@Antonio-RiveroMartnez)
- [#27054](https://github.com/apache/superset/pull/27054) feat(plugins): Update custom controls for BigNumber with Time Comparison chart (@Antonio-RiveroMartnez)
- [#27055](https://github.com/apache/superset/pull/27055) feat(docker): allow for docker release builds to be multi-platform (@mistercrunch)
- [#26923](https://github.com/apache/superset/pull/26923) feat: docker image tags documentation + tweaks (@mistercrunch)
- [#26945](https://github.com/apache/superset/pull/26945) feat(ci): kill duplicate CI jobs on PRs (@mistercrunch)
- [#26639](https://github.com/apache/superset/pull/26639) feat(components): Add static class name with button style (@mskelton)
- [#26908](https://github.com/apache/superset/pull/26908) feat: Period over Period Big Number comparison chart (@eschutho)
- [#26912](https://github.com/apache/superset/pull/26912) feat(ci): unleash dependabot on our github actions (@mistercrunch)
- [#26300](https://github.com/apache/superset/pull/26300) feat(maps): Consolidating all country maps (and TS) into the Jupyter notebook workflow. (@rusackas)
- [#26877](https://github.com/apache/superset/pull/26877) feat(ci): add a check to make sure there's no hold label on the PR (@mistercrunch)
- [#26880](https://github.com/apache/superset/pull/26880) feat: configuring an extensible PR auto-labeler (@mistercrunch)
- [#25323](https://github.com/apache/superset/pull/25323) feat(i18n): add ukranian translations (@GlugovGrGlib)
- [#26443](https://github.com/apache/superset/pull/26443) feat: add chart id and dataset id to global logs (@eschutho)
- [#26754](https://github.com/apache/superset/pull/26754) feat: Stop editor scrolling to top (@puridach-w)
- [#26745](https://github.com/apache/superset/pull/26745) feat: auto-label PRs that contain db migrations (@mistercrunch)
- [#26418](https://github.com/apache/superset/pull/26418) feat: global logs context (@eschutho)
- [#26604](https://github.com/apache/superset/pull/26604) feat(celery): upgrade celery and its dependencies packages (@Musa10)
- [#26407](https://github.com/apache/superset/pull/26407) feat: Add ValuePercent option to LABEL TYPE for Pie and Funnel charts (@kainchow)
- [#26278](https://github.com/apache/superset/pull/26278) feat(releasing): adding SHA512 and RSA signature validation script to verify releases (@rusackas)
- [#26011](https://github.com/apache/superset/pull/26011) feat(telemetry): Adding Scarf based telemetry to Superset (@rusackas)
- [#26196](https://github.com/apache/superset/pull/26196) feat(docker): Add ARM builds (@alekseyolg)
- [#26161](https://github.com/apache/superset/pull/26161) feat: Create db_engine_spec ibmi.py (@wAVeckx)
**Fixes**
- [#27706](https://github.com/apache/superset/pull/27706) fix: Select onChange is fired when the same item is selected in single mode (@michael-s-molina)
- [#27763](https://github.com/apache/superset/pull/27763) fix: Removes filter plugins from viz gallery (@michael-s-molina)
- [#27744](https://github.com/apache/superset/pull/27744) fix: reduce alert error to warning (@eschutho)
- [#27558](https://github.com/apache/superset/pull/27558) fix(explore): drag and drop indicator UX (@justinpark)
- [#27644](https://github.com/apache/superset/pull/27644) fix: Provide more inclusive error handling for saved queries (@john-bodley)
- [#27646](https://github.com/apache/superset/pull/27646) fix: Leverage actual database for rendering Jinjarized SQL (@john-bodley)
- [#27550](https://github.com/apache/superset/pull/27550) fix(AlertReports): disabling value when not null option is active (@fisjac)
- [#27636](https://github.com/apache/superset/pull/27636) fix(sqllab): unable to remove table (@justinpark)
- [#27022](https://github.com/apache/superset/pull/27022) fix(Chart Annotation modal): Table and Superset annotation options will paginate, exceeding previous max limit 100 (@rtexelm)
- [#27552](https://github.com/apache/superset/pull/27552) fix(AlertReports): defaulting grace period to undefined (@fisjac)
- [#27551](https://github.com/apache/superset/pull/27551) fix(AlertReports): clearing custom_width when disabled (@fisjac)
- [#27470](https://github.com/apache/superset/pull/27470) fix(sql_parse): Ensure table extraction handles Jinja templating (@john-bodley)
- [#27601](https://github.com/apache/superset/pull/27601) fix: Persist query params appended to permalink (@kgabryje)
- [#27613](https://github.com/apache/superset/pull/27613) fix(Dashboard): Add editMode conditional for translate3d fix on charts to allow intended Fullscreen (@rtexelm)
- [#27388](https://github.com/apache/superset/pull/27388) fix(utils): fix off-by-one error in how rolling window's min_periods truncates dataframe (@sfirke)
- [#19595](https://github.com/apache/superset/pull/19595) fix: Volatile datasource ordering in dashboard export (@pnadolny13)
- [#27577](https://github.com/apache/superset/pull/27577) fix: sqlglot SQL Server (@betodealmeida)
- [#27576](https://github.com/apache/superset/pull/27576) fix: bump sqlglot to support materialized CTEs (@betodealmeida)
- [#27567](https://github.com/apache/superset/pull/27567) fix(db_engine_specs): Update convert_dttm to work correctly with CrateDB (@hlcianfagna)
- [#27605](https://github.com/apache/superset/pull/27605) fix: Skips Hive tests that are blocking PRs (@michael-s-molina)
- [#27566](https://github.com/apache/superset/pull/27566) fix: guest queries (@betodealmeida)
- [#27464](https://github.com/apache/superset/pull/27464) fix: pass valid SQL to SM (@betodealmeida)
- [#26748](https://github.com/apache/superset/pull/26748) fix: `improve _extract_tables_from_sql` (@betodealmeida)
- [#27539](https://github.com/apache/superset/pull/27539) fix(explore): Allow only saved metrics and columns (@justinpark)
- [#27260](https://github.com/apache/superset/pull/27260) fix(alerts/reports): implementing custom_width as an Antd number input (@fisjac)
- [#27487](https://github.com/apache/superset/pull/27487) fix(postprocessing): resample with holes (@villebro)
- [#27484](https://github.com/apache/superset/pull/27484) fix: check if guest user modified query (@betodealmeida)
- [#27471](https://github.com/apache/superset/pull/27471) fix(webpack): remove double-dotted file extensions in webpack config (@rusackas)
- [#27186](https://github.com/apache/superset/pull/27186) fix: SSH Tunnel configuration settings (@geido)
- [#27411](https://github.com/apache/superset/pull/27411) fix(dashboard): Only fetch CSS templates for dashboard header menu when in edit mode (@mskelton)
- [#27315](https://github.com/apache/superset/pull/27315) fix(deps): resolving canvg and html2canvas module not found (@fisjac)
- [#27403](https://github.com/apache/superset/pull/27403) fix: missing shared color in mixed timeseries (@justinpark)
- [#27402](https://github.com/apache/superset/pull/27402) fix: typescript errors in 4.0 (@justinpark)
- [#27390](https://github.com/apache/superset/pull/27390) fix: Re-enable CI checks on release branches (@michael-s-molina)
- [#27391](https://github.com/apache/superset/pull/27391) fix(sqllab): Close already removed tab (@justinpark)
- [#27364](https://github.com/apache/superset/pull/27364) fix(API): Updating assets via the API should preserve ownership configuration (@Vitor-Avila)
- [#27395](https://github.com/apache/superset/pull/27395) fix: improve explore REST api validations (@dpgaspar)
- [#27262](https://github.com/apache/superset/pull/27262) fix(Alerts & Reports): Fixing bug that resets cron value to default when empty (@fisjac)
- [#27366](https://github.com/apache/superset/pull/27366) fix: Results section in Explore shows an infinite spinner (@michael-s-molina)
- [#27187](https://github.com/apache/superset/pull/27187) fix: numexpr to fix CVE-2023-39631 (2.8.4 => 2.9.0) (@nigzak)
- [#27361](https://github.com/apache/superset/pull/27361) fix: Missing SQL Lab permission (@michael-s-molina)
- [#27360](https://github.com/apache/superset/pull/27360) fix: Heatmap numeric sorting (@michael-s-molina)
- [#27313](https://github.com/apache/superset/pull/27313) fix(sqllab): Missing empty query result state (@justinpark)
- [#27308](https://github.com/apache/superset/pull/27308) fix(dashboard): table chart drag preview overflowing container (@rtexelm)
- [#27295](https://github.com/apache/superset/pull/27295) fix(sqllab): invalid dump sql shown after closing tab (@justinpark)
- [#27285](https://github.com/apache/superset/pull/27285) fix(plugin-chart-echarts): calculate Gauge Chart intervals correctly when min value is set (@goto-loop)
- [#27307](https://github.com/apache/superset/pull/27307) fix: Incorrect data type on import page (@michael-s-molina)
- [#27291](https://github.com/apache/superset/pull/27291) fix: Data zoom with horizontal orientation (@michael-s-molina)
- [#27273](https://github.com/apache/superset/pull/27273) fix: Navigating to an invalid page index in lists (@michael-s-molina)
- [#27271](https://github.com/apache/superset/pull/27271) fix: Inoperable dashboard filter slider when range is <= 1 (@michael-s-molina)
- [#27154](https://github.com/apache/superset/pull/27154) fix(import-datasources): Use "admin" user as default for importing datasources (@ddxv)
- [#27258](https://github.com/apache/superset/pull/27258) fix: Sorting charts/dashboards makes the applied filters ineffective (@michael-s-molina)
- [#27213](https://github.com/apache/superset/pull/27213) fix(trino): bumping trino to fix hudi schema fetching (@rusackas)
- [#27236](https://github.com/apache/superset/pull/27236) fix(reports): fixing unit test (@fisjac)
- [#27217](https://github.com/apache/superset/pull/27217) fix(sqlglot): Address regressions introduced in #26476 (@john-bodley)
- [#27233](https://github.com/apache/superset/pull/27233) fix: bump FAB to 4.4.1 (perf issue) (@dpgaspar)
- [#27167](https://github.com/apache/superset/pull/27167) fix: setting important lower bounds versions on requirements (@dpgaspar)
- [#27215](https://github.com/apache/superset/pull/27215) fix: no limit in SELECT * for TOP dbs (@betodealmeida)
- [#27214](https://github.com/apache/superset/pull/27214) fix(releasing): fixes npm script for release validation (@rusackas)
- [#26074](https://github.com/apache/superset/pull/26074) fix: Translations related to the date range filter (@Ralkion)
- [#26699](https://github.com/apache/superset/pull/26699) fix(dashboard): drag and drop indicator UX (@justinpark)
- [#27191](https://github.com/apache/superset/pull/27191) fix: Failed to execute importScripts on worker-css (@michael-s-molina)
- [#27181](https://github.com/apache/superset/pull/27181) fix(sqllab): typeahead search is broken in db selector (@justinpark)
- [#27164](https://github.com/apache/superset/pull/27164) fix: unlock and bump werkzeug (@dpgaspar)
- [#27161](https://github.com/apache/superset/pull/27161) fix(ci): mypy pre-commit issues (@dpgaspar)
- [#27138](https://github.com/apache/superset/pull/27138) fix(plugins): Apply dashboard filters to comparison query in BigNumber with Time Comparison chart (@Antonio-RiveroMartnez)
- [#27135](https://github.com/apache/superset/pull/27135) fix: Duplicated toast messages (@michael-s-molina)
- [#27132](https://github.com/apache/superset/pull/27132) fix: Plain error message when visiting a dashboard via permalink without permissions (@michael-s-molina)
- [#27130](https://github.com/apache/superset/pull/27130) fix: ID param for DELETE ssh_tunnel endpoint (@geido)
- [#22840](https://github.com/apache/superset/pull/22840) fix(pivot-table-v2): Added forgotten translation pivot table v2 (@Always-prog)
- [#27128](https://github.com/apache/superset/pull/27128) fix: RLS modal overflow (@michael-s-molina)
- [#27112](https://github.com/apache/superset/pull/27112) fix: gevent upgrade to 23.9.1 (@dpgaspar)
- [#27117](https://github.com/apache/superset/pull/27117) fix: removes old deprecated sqllab endpoints (@dpgaspar)
- [#27124](https://github.com/apache/superset/pull/27124) fix: bump grpcio, urllib3 and paramiko (@dpgaspar)
- [#27116](https://github.com/apache/superset/pull/27116) fix(docker): \*-dev tags target right stage from Dockerfile (@lodu)
- [#26791](https://github.com/apache/superset/pull/26791) fix(sqllab): flaky json explore modal due to over-rendering (@justinpark)
- [#27113](https://github.com/apache/superset/pull/27113) fix: upgrade cryptography to major 42 (@dpgaspar)
- [#27106](https://github.com/apache/superset/pull/27106) fix: Timeseries Y-axis format with contribution mode (@michael-s-molina)
- [#27098](https://github.com/apache/superset/pull/27098) fix: try to fix cypress with magic (@mistercrunch)
- [#27094](https://github.com/apache/superset/pull/27094) fix(helm): typo on ssl_cert_reqs variable (@pcop00)
- [#27091](https://github.com/apache/superset/pull/27091) fix(deps): un-bumping dom-to-pdf ro resolve missing file warnings (@rusackas)
- [#27087](https://github.com/apache/superset/pull/27087) fix(ci): Docker master builds fail while checking version (@mistercrunch)
- [#27085](https://github.com/apache/superset/pull/27085) fix(ci): new PR comments cancel ongoing ephemeral builds (@dpgaspar)
- [#26663](https://github.com/apache/superset/pull/26663) fix(helm): Include option to use Redis with SSL (@shakeelansari63)
- [#27060](https://github.com/apache/superset/pull/27060) fix(ephemeral): last try fixing this GH action (@mistercrunch)
- [#27058](https://github.com/apache/superset/pull/27058) fix(ephemeral): point to the full tag name (@mistercrunch)
- [#27057](https://github.com/apache/superset/pull/27057) fix(ephemeral): fix tagging command for ECR (@mistercrunch)
- [#27056](https://github.com/apache/superset/pull/27056) fix(ephemeral): fix ephemeral builds in PR (@mistercrunch)
- [#27048](https://github.com/apache/superset/pull/27048) fix(actions): correcting malformed labeler configs (@rusackas)
- [#19744](https://github.com/apache/superset/pull/19744) fix(webpack-dev-server): parse env args (@jdbranham)
- [#27042](https://github.com/apache/superset/pull/27042) fix(ci): fix action script v7 breaking changes v3 (@dpgaspar)
- [#27040](https://github.com/apache/superset/pull/27040) fix(ci): fix action script v7 breaking changes v2 (@dpgaspar)
- [#27014](https://github.com/apache/superset/pull/27014) fix(maps): france_regions.geojson generated with the notebook, from natural earth data (@qleroy)
- [#26966](https://github.com/apache/superset/pull/26966) fix(actions): make tech debt uploader not block CI and skip w/o creds (@rusackas)
- [#27001](https://github.com/apache/superset/pull/27001) fix(cypress): resolving random dri3 error on cypress runner (@rusackas)
- [#27013](https://github.com/apache/superset/pull/27013) fix(plugins): Fix dashboard filter in Period Over Period KPI plugin (@Antonio-RiveroMartnez)
- [#27005](https://github.com/apache/superset/pull/27005) fix(helm): Fix inconsistency for the chart appVersion and default image tag (@dnskr)
- [#26995](https://github.com/apache/superset/pull/26995) fix(maps): Move Overseas department and regions closer to France mainland (@qleroy)
- [#26987](https://github.com/apache/superset/pull/26987) fix(ci): typo in my bash script (@mistercrunch)
- [#26985](https://github.com/apache/superset/pull/26985) fix(plugin): Period Over Period KPI Plugin Feature flag value (@Antonio-RiveroMartnez)
- [#26969](https://github.com/apache/superset/pull/26969) fix(ci): support action/script v5 breaking change v2 (@dpgaspar)
- [#26968](https://github.com/apache/superset/pull/26968) fix(ci): support action/script v5 breaking change (@dpgaspar)
- [#26963](https://github.com/apache/superset/pull/26963) fix(plugin-chart-table): Revert "fix(chart table in dashboard): improve screen reading of table (#26453)" (@kgabryje)
- [#26949](https://github.com/apache/superset/pull/26949) fix(actions): specify branch on monorepo lockfile pusher (@rusackas)
- [#26921](https://github.com/apache/superset/pull/26921) fix(ci): remove deprecated set-output on github workflows (@dpgaspar)
- [#26920](https://github.com/apache/superset/pull/26920) fix(ci): lint issue on update-monorepo-lockfiles.yml (@dpgaspar)
- [#26919](https://github.com/apache/superset/pull/26919) fix(ci): ephemeral env build and up dependency (@dpgaspar)
- [#26852](https://github.com/apache/superset/pull/26852) fix(ci): ephemeral env build (@dpgaspar)
- [#26917](https://github.com/apache/superset/pull/26917) fix: remove ephemeral docker build from required workflow (@dpgaspar)
- [#26787](https://github.com/apache/superset/pull/26787) fix(docker): improve docker tags to be cleared and avoid conflicts (@mistercrunch)
- [#26904](https://github.com/apache/superset/pull/26904) fix(dependabot): lockfile updater won't fail when there's nothing to push (@rusackas)
- [#26888](https://github.com/apache/superset/pull/26888) fix(dependencies): adding auth for dependabot lockfile action (@rusackas)
- [#26901](https://github.com/apache/superset/pull/26901) fix(svg): reformatting svgs to allow license without breaking images (@rusackas)
- [#26453](https://github.com/apache/superset/pull/26453) fix(chart table in dashboard): improve screen reading of table (@ncar285)
- [#26801](https://github.com/apache/superset/pull/26801) fix: docker should always run, even in forks (@mistercrunch)
- [#26752](https://github.com/apache/superset/pull/26752) fix: add user to latest-release-tag workflow (@eschutho)
- [#26772](https://github.com/apache/superset/pull/26772) fix(docker): credentials issues around superset-cache in forks (@mistercrunch)
- [#25510](https://github.com/apache/superset/pull/25510) fix: change the validation logic for python_date_format (@mapledan)
- [#26710](https://github.com/apache/superset/pull/26710) fix(dependencies): stopping (and preventing) full lodash library import... now using only method level imports. (@rusackas)
- [#26473](https://github.com/apache/superset/pull/26473) fix: docker ephemeral environment, push only on testenv comment (@dpgaspar)
- [#26682](https://github.com/apache/superset/pull/26682) fix: Revert "build(deps): bump @mdx-js/react from 1.6.22 to 3.0.0 in /docs" (@rusackas)
- [#26679](https://github.com/apache/superset/pull/26679) fix: Revert "buld(deps): bump swagger-ui-react from 4.1.3 to 5.11.0 in docs (#26552) (@michael-s-molina)
- [#26648](https://github.com/apache/superset/pull/26648) fix: Removes unused cache cleanup (@michael-s-molina)
- [#26649](https://github.com/apache/superset/pull/26649) fix: remove possible unnecessary file 1 (@dpgaspar)
- [#26351](https://github.com/apache/superset/pull/26351) fix: stringify scarf pixel value (@eschutho)
- [#26205](https://github.com/apache/superset/pull/26205) fix(docker): Remove race condition when building image (@alekseyolg)
**Others**
- [#27441](https://github.com/apache/superset/pull/27441) chore: Adds the 4.0 release notes (@michael-s-molina)
- [#27768](https://github.com/apache/superset/pull/27768) chore(docs): Cleanup UPDATING.md (@john-bodley)
- [#27625](https://github.com/apache/superset/pull/27625) perf(explore): virtualized datasource field sections (@justinpark)
- [#27488](https://github.com/apache/superset/pull/27488) perf(sqllab): reduce bootstrap data delay by queries (@justinpark)
- [#27281](https://github.com/apache/superset/pull/27281) chore: bump cryptography minimum to 42.0.4 (@sadpandajoe)
- [#27232](https://github.com/apache/superset/pull/27232) chore: Removes Chromatic workflow and dependencies (@michael-s-molina)
- [#27169](https://github.com/apache/superset/pull/27169) chore: Updates CHANGELOG.md with 3.0.4 data (@michael-s-molina)
- [#27166](https://github.com/apache/superset/pull/27166) docs: add Dropit Shopping to users list (@IlyaDropit)
- [#27143](https://github.com/apache/superset/pull/27143) refactor: Migrate ErrorBoundary to typescript (@EnxDev)
- [#27136](https://github.com/apache/superset/pull/27136) chore(tests): Remove unnecessary explicit Flask-SQLAlchemy session expunges (@john-bodley)
- [#27134](https://github.com/apache/superset/pull/27134) docs: add Geotab to users list (@JZ6)
- [#26693](https://github.com/apache/superset/pull/26693) chore(hail mary): Update package-lock.json via npm-audit-fix (@rusackas)
- [#27129](https://github.com/apache/superset/pull/27129) chore: lower cryptography min version to 41.0.2 (@sadpandajoe)
- [#27120](https://github.com/apache/superset/pull/27120) docs(miscellaneous): Export Datasoruces: export datasources exports to ZIP (@ddxv)
- [#27078](https://github.com/apache/superset/pull/27078) chore(internet_port): added new ports and removed unnecessary string class (@anirudh-hegde)
- [#27118](https://github.com/apache/superset/pull/27118) chore: bump firebolt-sqlalchemy to support service account auth (@Vitor-Avila)
- [#27090](https://github.com/apache/superset/pull/27090) chore(plugins): Update dropdown control for BigNumber with Time Comparison range (@Antonio-RiveroMartnez)
- [#26909](https://github.com/apache/superset/pull/26909) refactor: Ensure Flask framework leverages the Flask-SQLAlchemy session (Phase II) (@john-bodley)
- [#27030](https://github.com/apache/superset/pull/27030) chore: Migrate AlteredSliceTag to typescript (@EnxDev)
- [#26773](https://github.com/apache/superset/pull/26773) chore(translations): updating pot -> po -> json files (babel 2.9.1) (@rusackas)
- [#27071](https://github.com/apache/superset/pull/27071) chore(docs): adding meta db to Feature Flags page (@rusackas)
- [#27072](https://github.com/apache/superset/pull/27072) docs(installation): document multi-platform support in Docker builds (@mistercrunch)
- [#27053](https://github.com/apache/superset/pull/27053) chore: prevent prophet from logging non-errors as errors (@betodealmeida)
- [#27038](https://github.com/apache/superset/pull/27038) chore(docs): bump version number in docs example (@sfirke)
- [#26973](https://github.com/apache/superset/pull/26973) build(deps-dev): bump @types/jest from 26.0.24 to 29.5.12 in /superset-frontend/plugins/plugin-chart-handlebars (@dependabot[bot])
- [#26260](https://github.com/apache/superset/pull/26260) chore(dashboard): migrate enzyme to RTL (@justinpark)
- [#26989](https://github.com/apache/superset/pull/26989) chore: Remove database ID dependency for SSH Tunnel creation (@geido)
- [#26981](https://github.com/apache/superset/pull/26981) build(deps): bump react-js-cron from 1.2.0 to 2.1.2 in /superset-frontend (@dependabot[bot])
- [#26893](https://github.com/apache/superset/pull/26893) build(deps-dev): bump copy-webpack-plugin from 9.1.0 to 12.0.2 in /superset-frontend (@dependabot[bot])
- [#26171](https://github.com/apache/superset/pull/26171) chore(sqllab): migrate to typescript (@justinpark)
- [#27021](https://github.com/apache/superset/pull/27021) chore(plugins): Description, Category and Tags for BigNumber with Period Time Comparison plugin (@Antonio-RiveroMartnez)
- [#27020](https://github.com/apache/superset/pull/27020) docs: add a note about database drivers in Docker builds (@mistercrunch)
- [#26979](https://github.com/apache/superset/pull/26979) build(deps): bump @types/seedrandom from 2.4.30 to 3.0.8 in /superset-frontend (@dependabot[bot])
- [#27000](https://github.com/apache/superset/pull/27000) chore(github): adding code owners for translation and country map wor… (@rusackas)
- [#26998](https://github.com/apache/superset/pull/26998) docs: add notes to RELEASING about how to deploy docker images (@mistercrunch)
- [#26996](https://github.com/apache/superset/pull/26996) build(deps): bump react-intersection-observer from 9.4.1 to 9.6.0 in /superset-frontend (@dependabot[bot])
- [#26986](https://github.com/apache/superset/pull/26986) docs(presto): add Presto SSL connection details (@rusackas)
- [#26526](https://github.com/apache/superset/pull/26526) build(deps): bump @vx/legend from 0.0.198 to 0.0.199 in /superset-frontend/plugins/legacy-plugin-chart-histogram (@dependabot[bot])
- [#26903](https://github.com/apache/superset/pull/26903) chore(dependencies): bump encodable to 0.7.8 (@rusackas)
- [#26977](https://github.com/apache/superset/pull/26977) build(deps-dev): bump webpack from 5.90.0 to 5.90.1 in /docs (@dependabot[bot])
- [#26974](https://github.com/apache/superset/pull/26974) build(deps-dev): bump @types/node from 20.11.14 to 20.11.16 in /superset-websocket (@dependabot[bot])
- [#26971](https://github.com/apache/superset/pull/26971) build(deps): bump actions/checkout from 2 to 4 (@dependabot[bot])
- [#26972](https://github.com/apache/superset/pull/26972) build(deps): bump actions/cache from 1 to 4 (@dependabot[bot])
- [#26970](https://github.com/apache/superset/pull/26970) build(deps): bump actions/setup-python from 4 to 5 (@dependabot[bot])
- [#26950](https://github.com/apache/superset/pull/26950) chore(actions): getting fancier with labels (@rusackas)
- [#26952](https://github.com/apache/superset/pull/26952) build(deps): bump actions/setup-java from 1 to 4 (@dependabot[bot])
- [#26958](https://github.com/apache/superset/pull/26958) build(deps-dev): bump mock-socket from 9.0.3 to 9.3.1 in /superset-frontend (@dependabot[bot])
- [#26953](https://github.com/apache/superset/pull/26953) build(deps): bump actions/github-script from 3 to 7 (@dependabot[bot])
- [#26927](https://github.com/apache/superset/pull/26927) build(deps): bump actions/setup-node from 2 to 4 (@dependabot[bot])
- [#26954](https://github.com/apache/superset/pull/26954) build(deps): bump aws-actions/configure-aws-credentials from 1 to 4 (@dependabot[bot])
- [#26955](https://github.com/apache/superset/pull/26955) build(deps): bump aws-actions/amazon-ecr-login from 1 to 2 (@dependabot[bot])
- [#26956](https://github.com/apache/superset/pull/26956) build(deps): bump github/codeql-action from 2 to 3 (@dependabot[bot])
- [#26938](https://github.com/apache/superset/pull/26938) build(deps): bump moment from 2.29.4 to 2.30.1 in /superset-frontend (@dependabot[bot])
- [#26943](https://github.com/apache/superset/pull/26943) chore(dependencies): Push lockfile for monorepo updates on rebuild/rebase (@rusackas)
- [#26875](https://github.com/apache/superset/pull/26875) chore: make TS enums strictly PascalCase (@villebro)
- [#26942](https://github.com/apache/superset/pull/26942) chore(ci): run pre-commit across the repo (@mistercrunch)
- [#26935](https://github.com/apache/superset/pull/26935) build(deps): bump interweave from 13.0.0 to 13.1.0 in /superset-frontend (@dependabot[bot])
- [#26941](https://github.com/apache/superset/pull/26941) build(deps): bump emotion-rgba from 0.0.9 to 0.0.12 in /superset-frontend (@dependabot[bot])
- [#26939](https://github.com/apache/superset/pull/26939) build(deps-dev): bump @babel/core from 7.22.8 to 7.23.9 in /superset-frontend (@dependabot[bot])
- [#26940](https://github.com/apache/superset/pull/26940) build(deps): bump shortid from 2.2.14 to 2.2.16 in /superset-frontend (@dependabot[bot])
- [#26924](https://github.com/apache/superset/pull/26924) build(deps-dev): bump @types/node from 20.11.10 to 20.11.14 in /superset-websocket (@dependabot[bot])
- [#26928](https://github.com/apache/superset/pull/26928) build(deps): bump chromaui/action from 1 to 10 (@dependabot[bot])
- [#26929](https://github.com/apache/superset/pull/26929) build(deps): bump azure/setup-helm from 1 to 3 (@dependabot[bot])
- [#26930](https://github.com/apache/superset/pull/26930) build(deps): bump actions/upload-artifact from 3 to 4 (@dependabot[bot])
- [#26931](https://github.com/apache/superset/pull/26931) build(deps): bump actions/dependency-review-action from 2 to 4 (@dependabot[bot])
- [#26918](https://github.com/apache/superset/pull/26918) chore(ci): notify PMCs of changes on required workflows (@dpgaspar)
- [#26372](https://github.com/apache/superset/pull/26372) refactor: Removes the deprecated GENERIC_CHART_AXES feature flag (@michael-s-molina)
- [#26881](https://github.com/apache/superset/pull/26881) build(deps-dev): update @babel/types requirement from ^7.13.12 to ^7.23.9 in /superset-frontend/plugins/plugin-chart-pivot-table (@dependabot[bot])
- [#26727](https://github.com/apache/superset/pull/26727) build(deps): bump @ant-design/icons from 5.0.1 to 5.2.6 in /superset-frontend (@dependabot[bot])
- [#26894](https://github.com/apache/superset/pull/26894) build(deps): bump @vx/scale from 0.0.197 to 0.0.199 in /superset-frontend (@dependabot[bot])
- [#26840](https://github.com/apache/superset/pull/26840) build(deps): bump d3-selection from 1.4.2 to 3.0.0 in /superset-frontend (@dependabot[bot])
- [#26861](https://github.com/apache/superset/pull/26861) build(deps): bump @visx/axis from 3.5.0 to 3.8.0 in /superset-frontend (@dependabot[bot])
- [#26272](https://github.com/apache/superset/pull/26272) chore(explore): migrate enzyme to RTL (@justinpark)
- [#26899](https://github.com/apache/superset/pull/26899) build(deps): bump @types/rison from 0.0.6 to 0.0.9 in /superset-frontend (@dependabot[bot])
- [#26831](https://github.com/apache/superset/pull/26831) build(deps): bump @types/rison from 0.0.6 to 0.0.9 in /superset-frontend/packages/superset-ui-core (@dependabot[bot])
- [#26869](https://github.com/apache/superset/pull/26869) build(deps): bump dom-to-image-more from 2.16.0 to 3.2.0 in /superset-frontend (@dependabot[bot])
- [#26902](https://github.com/apache/superset/pull/26902) chore(docs): remove misplaced k8s installation instructions (@sfirke)
- [#26897](https://github.com/apache/superset/pull/26897) build(deps-dev): bump webpack-bundle-analyzer from 4.9.0 to 4.10.1 in /superset-frontend (@dependabot[bot])
- [#26900](https://github.com/apache/superset/pull/26900) chore(ci): make action/labeler work on fork PRs (@mistercrunch)
- [#26879](https://github.com/apache/superset/pull/26879) chore(dependabot): ignore css-minimizer-webpack-plugin (@mistercrunch)
- [#26860](https://github.com/apache/superset/pull/26860) build(deps): bump rehype-sanitize from 5.0.1 to 6.0.0 in /superset-frontend (@dependabot[bot])
- [#26872](https://github.com/apache/superset/pull/26872) chore(dependabot): auto-update lockfiles for monorepo package bumps (@rusackas)
- [#26859](https://github.com/apache/superset/pull/26859) build(deps): bump @types/enzyme from 3.10.10 to 3.10.18 in /superset-frontend (@dependabot[bot])
- [#26874](https://github.com/apache/superset/pull/26874) chore(license): adding a missing license blurb to a translation file (@rusackas)
- [#26870](https://github.com/apache/superset/pull/26870) build(deps): bump yargs and @types/yargs in /superset-frontend (@dependabot[bot])
- [#26841](https://github.com/apache/superset/pull/26841) chore(dependencies): bump less from 3.12.2 to 4.2.0 in /superset-frontend (@dependabot[bot])
- [#26868](https://github.com/apache/superset/pull/26868) chore(actions): run docs actions on Node 16 to conform with the project (@rusackas)
- [#26857](https://github.com/apache/superset/pull/26857) chore(actions): generate FOSSA report on master, and ALWAYS check for… (@rusackas)
- [#26826](https://github.com/apache/superset/pull/26826) build(deps-dev): bump @types/uuid from 9.0.7 to 9.0.8 in /superset-websocket (@dependabot[bot])
- [#26867](https://github.com/apache/superset/pull/26867) build(deps): bump @testing-library/react-hooks from 5.0.3 to 5.1.3 in /superset-frontend (@dependabot[bot])
- [#26866](https://github.com/apache/superset/pull/26866) build(deps): bump mousetrap and @types/mousetrap in /superset-frontend (@dependabot[bot])
- [#26865](https://github.com/apache/superset/pull/26865) build(deps): bump react-redux from 7.2.8 to 7.2.9 in /superset-frontend (@dependabot[bot])
- [#26855](https://github.com/apache/superset/pull/26855) chore(dependabot): lowering bump cadence from weekly to monthly (@rusackas)
- [#26854](https://github.com/apache/superset/pull/26854) chore(CI): get docs building on ALL branches. (@rusackas)
- [#26825](https://github.com/apache/superset/pull/26825) build(deps-dev): bump @types/node from 20.11.5 to 20.11.10 in /superset-websocket (@dependabot[bot])
- [#26820](https://github.com/apache/superset/pull/26820) chore(lint/a11y): fixing and locking down jsx-a11y/anchor-is-valid (@rusackas)
- [#26819](https://github.com/apache/superset/pull/26819) chore(dependencies): bumps match-sorter (@rusackas)
- [#26798](https://github.com/apache/superset/pull/26798) chore: Add permission to view and drill on Dashboard context (@geido)
- [#26827](https://github.com/apache/superset/pull/26827) build(deps): bump use-immer from 0.8.1 to 0.9.0 in /superset-frontend (@dependabot[bot])
- [#24272](https://github.com/apache/superset/pull/24272) chore(deps): bump typescript to 4.8.4 (@jansule)
- [#26832](https://github.com/apache/superset/pull/26832) build(deps): bump @types/react-table from 7.0.29 to 7.7.19 in /superset-frontend (@dependabot[bot])
- [#26834](https://github.com/apache/superset/pull/26834) build(deps-dev): bump @docusaurus/module-type-aliases from 3.1.0 to 3.1.1 in /docs (@dependabot[bot])
- [#26839](https://github.com/apache/superset/pull/26839) build(deps-dev): bump webpack from 5.89.0 to 5.90.0 in /docs (@dependabot[bot])
- [#23873](https://github.com/apache/superset/pull/23873) chore: Slovenian translation update (@dkrat7)
- [#26702](https://github.com/apache/superset/pull/26702) chore: fix GitHub 'Unchanged files with check annotations' reports in PR (@mistercrunch)
- [#26726](https://github.com/apache/superset/pull/26726) build(deps): bump prism-react-renderer from 1.2.1 to 2.3.1 in /docs (@dependabot[bot])
- [#26813](https://github.com/apache/superset/pull/26813) chore(ci): change code owners for .github (@dpgaspar)
- [#26794](https://github.com/apache/superset/pull/26794) chore(dependencies): bumping jinja2 (@rusackas)
- [#26816](https://github.com/apache/superset/pull/26816) chore: add google-auth for new example dashboard (@betodealmeida)
- [#26815](https://github.com/apache/superset/pull/26815) chore: Reformat changelogs (@geido)
- [#26793](https://github.com/apache/superset/pull/26793) chore(dependencies): bumping fonttools (@rusackas)
- [#26442](https://github.com/apache/superset/pull/26442) chore: Technical Debt Metrics (@rusackas)
- [#26800](https://github.com/apache/superset/pull/26800) chore: Splits the CHANGELOG into multiple files (@michael-s-molina)
- [#26621](https://github.com/apache/superset/pull/26621) build(deps): update jquery requirement from ^3.4.1 to ^3.7.1 in /superset-frontend/packages/superset-ui-demo (@dependabot[bot])
- [#26789](https://github.com/apache/superset/pull/26789) chore(RESOURCES): fix markdown for table formatting (@qleroy)
- [#26759](https://github.com/apache/superset/pull/26759) chore: Add Embed Modal extension override and tests (@geido)
- [#26656](https://github.com/apache/superset/pull/26656) build(deps-dev): bump css-minimizer-webpack-plugin from 3.4.1 to 6.0.0 in /superset-frontend (@dependabot[bot])
- [#26704](https://github.com/apache/superset/pull/26704) chore: improve/decouple eslint and tsc 'npm run' commands (@mistercrunch)
- [#26728](https://github.com/apache/superset/pull/26728) build(deps): bump @visx/grid from 3.0.1 to 3.5.0 in /superset-frontend (@dependabot[bot])
- [#26729](https://github.com/apache/superset/pull/26729) build(deps): update classnames requirement from ^2.3.2 to ^2.5.1 in /superset-frontend/plugins/plugin-chart-table (@dependabot[bot])
- [#26766](https://github.com/apache/superset/pull/26766) chore: prevent CI double runs on push + pull_request (@mistercrunch)
- [#26528](https://github.com/apache/superset/pull/26528) build(deps-dev): bump jest from 26.6.3 to 29.7.0 in /superset-frontend/plugins/plugin-chart-handlebars (@dependabot[bot])
- [#26513](https://github.com/apache/superset/pull/26513) build(deps): bump d3-color from 1.4.1 to 3.1.0 in /superset-frontend/plugins/legacy-plugin-chart-world-map (@dependabot[bot])
- [#26596](https://github.com/apache/superset/pull/26596) build(deps): update @types/math-expression-evaluator requirement from ^1.2.1 to ^1.3.3 in /superset-frontend/packages/superset-ui-core (@dependabot[bot])
- [#26595](https://github.com/apache/superset/pull/26595) build(deps-dev): update @types/lodash requirement from ^4.14.149 to ^4.14.202 in /superset-frontend/plugins/plugin-chart-handlebars (@dependabot[bot])
- [#26698](https://github.com/apache/superset/pull/26698) build: Parallelize the CI image builds (continued) (@mistercrunch)
- [#26499](https://github.com/apache/superset/pull/26499) build(deps): update d3-cloud requirement from ^1.2.5 to ^1.2.7 in /superset-frontend/plugins/plugin-chart-word-cloud (@dependabot[bot])
- [#26481](https://github.com/apache/superset/pull/26481) build(deps-dev): bump @types/jest from 26.0.24 to 29.5.11 in /superset-frontend/plugins/plugin-chart-pivot-table (@dependabot[bot])
- [#26546](https://github.com/apache/superset/pull/26546) build(deps-dev): bump @docusaurus/module-type-aliases from 2.4.1 to 3.1.0 in /docs (@dependabot[bot])
- [#26105](https://github.com/apache/superset/pull/26105) docs(storybook): fix typo in TimeFormatStories.tsx (@HurSungYun)
- [#26594](https://github.com/apache/superset/pull/26594) build(deps): update whatwg-fetch requirement from ^3.0.0 to ^3.6.20 in /superset-frontend/packages/superset-ui-core (@dependabot[bot])
- [#26753](https://github.com/apache/superset/pull/26753) chore: do not mark helm releases as github latest (@eschutho)
- [#26718](https://github.com/apache/superset/pull/26718) build(deps): bump @svgr/webpack from 5.5.0 to 8.1.0 in /docs (@dependabot[bot])
- [#26714](https://github.com/apache/superset/pull/26714) build(deps): bump @visx/axis from 3.0.1 to 3.5.0 in /superset-frontend (@dependabot[bot])
- [#26760](https://github.com/apache/superset/pull/26760) docs: update fixed CVEs for version 3.0.3 (@dpgaspar)
- [#26483](https://github.com/apache/superset/pull/26483) build(deps): update @types/d3-cloud requirement from ^1.2.1 to ^1.2.9 in /superset-frontend/plugins/plugin-chart-word-cloud (@dependabot[bot])
- [#26616](https://github.com/apache/superset/pull/26616) build(deps): bump fuse.js from 6.4.6 to 7.0.0 in /superset-frontend (@dependabot[bot])
- [#26717](https://github.com/apache/superset/pull/26717) build(deps-dev): bump webpack from 5.76.0 to 5.89.0 in /docs (@dependabot[bot])
- [#26570](https://github.com/apache/superset/pull/26570) build(deps-dev): bump prettier-plugin-packagejson from 2.2.15 to 2.4.9 in /superset-frontend (@dependabot[bot])
- [#26556](https://github.com/apache/superset/pull/26556) build(deps-dev): bump @babel/register from 7.22.5 to 7.23.7 in /superset-frontend (@dependabot[bot])
- [#26522](https://github.com/apache/superset/pull/26522) build(deps): update react-table requirement from ^7.6.3 to ^7.8.0 in /superset-frontend/plugins/plugin-chart-table (@dependabot[bot])
- [#26613](https://github.com/apache/superset/pull/26613) build(deps): bump react-github-btn from 1.2.1 to 1.4.0 in /docs (@dependabot[bot])
- [#26572](https://github.com/apache/superset/pull/26572) build(deps-dev): bump eslint-plugin-react-hooks from 4.2.0 to 4.6.0 in /superset-frontend (@dependabot[bot])
- [#26576](https://github.com/apache/superset/pull/26576) build(deps): bump @emotion/babel-preset-css-prop from 11.2.0 to 11.11.0 in /superset-frontend (@dependabot[bot])
- [#26724](https://github.com/apache/superset/pull/26724) build(deps): bump @saucelabs/theme-github-codeblock from 0.1.1 to 0.2.3 in /docs (@dependabot[bot])
- [#26720](https://github.com/apache/superset/pull/26720) build(deps): bump @docsearch/react from 3.3.3 to 3.5.2 in /docs (@dependabot[bot])
- [#26708](https://github.com/apache/superset/pull/26708) chore(dependencies): loosen constraints on dependency checker (@rusackas)
- [#25665](https://github.com/apache/superset/pull/25665) build(deps): bump @babel/traverse from 7.22.8 to 7.23.2 in /superset-frontend (@dependabot[bot])
- [#26694](https://github.com/apache/superset/pull/26694) chore(dependencies): removes unsued d3-color and d3-array (@rusackas)
- [#26692](https://github.com/apache/superset/pull/26692) chore(dependencies): removes unused minimist (@rusackas)
- [#26690](https://github.com/apache/superset/pull/26690) chore(dependencies): remove unused global-box (@rusackas)
- [#26689](https://github.com/apache/superset/pull/26689) chore(dependencies): remove unused lodash-es (@rusackas)
- [#26688](https://github.com/apache/superset/pull/26688) chore(dependencies): remove unused react-datetime (@rusackas)
- [#26687](https://github.com/apache/superset/pull/26687) chore(dependencies): remove unused ansi-regex (@rusackas)
- [#26686](https://github.com/apache/superset/pull/26686) chore(dependencies): removes unused @visx/tooltip (@rusackas)
- [#26685](https://github.com/apache/superset/pull/26685) chore(dependencies): remove unused @babel/runtime-corejs3 (@rusackas)
- [#26684](https://github.com/apache/superset/pull/26684) chore(dependencies): removes unused bootstrap-slider (@rusackas)
- [#26691](https://github.com/apache/superset/pull/26691) chore(dependencies): npm audit fix for superset-ui-demo (@rusackas)
- [#26703](https://github.com/apache/superset/pull/26703) chore: silence SECRET_KEY warning when running tests (@mistercrunch)
- [#26733](https://github.com/apache/superset/pull/26733) build(deps-dev): bump @types/node from 20.11.1 to 20.11.5 in /superset-websocket (@dependabot[bot])
- [#26329](https://github.com/apache/superset/pull/26329) refactor: Removes the deprecated DASHBOARD_NATIVE_FILTERS feature flag (@michael-s-molina)
- [#26347](https://github.com/apache/superset/pull/26347) refactor: Removes the deprecated VERSIONED_EXPORT feature flag (@michael-s-molina)
- [#26677](https://github.com/apache/superset/pull/26677) chore: Updates the Release Process link in the issue template (@michael-s-molina)
- [#26375](https://github.com/apache/superset/pull/26375) chore: Updates the bug report template (@michael-s-molina)
- [#26462](https://github.com/apache/superset/pull/26462) refactor: Removes the Profile feature (@michael-s-molina)
- [#26665](https://github.com/apache/superset/pull/26665) build(deps): bump the npm_and_yarn group group in /superset-frontend with 2 updates (@dependabot[bot])
- [#26661](https://github.com/apache/superset/pull/26661) chore: Updates CHANGELOG.md and UPDATING.md with 3.1.0 data (@michael-s-molina)
- [#26330](https://github.com/apache/superset/pull/26330) refactor: Removes the deprecated DASHBOARD_FILTERS_EXPERIMENTAL feature flag (@michael-s-molina)
- [#26547](https://github.com/apache/superset/pull/26547) build(deps): bump @mdx-js/react from 1.6.22 to 3.0.0 in /docs (@dependabot[bot])
- [#26552](https://github.com/apache/superset/pull/26552) build(deps): bump swagger-ui-react from 4.1.3 to 5.11.0 in /docs (@dependabot[bot])
- [#26555](https://github.com/apache/superset/pull/26555) build(deps-dev): bump @tsconfig/docusaurus from 1.0.7 to 2.0.2 in /docs (@dependabot[bot])
- [#26344](https://github.com/apache/superset/pull/26344) refactor: Removes the deprecated ENABLE_EXPLORE_JSON_CSRF_PROTECTION feature flag (@michael-s-molina)
- [#26345](https://github.com/apache/superset/pull/26345) refactor: Removes the deprecated ENABLE_TEMPLATE_REMOVE_FILTERS feature flag (@michael-s-molina)
- [#25800](https://github.com/apache/superset/pull/25800) docs: update embedded readme with user params context (@jbat)
- [#12175](https://github.com/apache/superset/pull/12175) build(deps): bump node-notifier from 8.0.0 to 8.0.1 in /superset-frontend (@dependabot[bot])
- [#26549](https://github.com/apache/superset/pull/26549) build(deps): bump clsx from 1.1.1 to 2.1.0 in /docs (@dependabot[bot])
- [#26560](https://github.com/apache/superset/pull/26560) build(deps-dev): bump typescript from 4.4.4 to 5.3.3 in /docs (@dependabot[bot])
- [#26650](https://github.com/apache/superset/pull/26650) chore: Updates CHANGELOG.md and UPDATING.md with 3.0.3 data (@michael-s-molina)
- [#26346](https://github.com/apache/superset/pull/26346) refactor: Removes the deprecated REMOVE_SLICE_LEVEL_LABEL_COLORS feature flag (@michael-s-molina)
- [#26200](https://github.com/apache/superset/pull/26200) refactor: Ensure Flask framework leverages the Flask-SQLAlchemy session (Phase I) (@john-bodley)
- [#26633](https://github.com/apache/superset/pull/26633) chore: Deprecates the DASHBOARD_CROSS_FILTERS feature flag (@michael-s-molina)
- [#26635](https://github.com/apache/superset/pull/26635) chore: Deprecates the ENABLE_JAVASCRIPT_CONTROLS feature flag (@michael-s-molina)
- [#26636](https://github.com/apache/superset/pull/26636) chore: Sets DASHBOARD_VIRTUALIZATION feature flag to True by default (@michael-s-molina)
- [#26540](https://github.com/apache/superset/pull/26540) chore(API): Include changed_by.id in Get Charts and Get Datasets API responses (@Vitor-Avila)
- [#26637](https://github.com/apache/superset/pull/26637) chore: Sets the DRILL_BY feature flag to True by default (@michael-s-molina)
- [#26186](https://github.com/apache/superset/pull/26186) refactor: Ensure Celery leverages the Flask-SQLAlchemy session (@john-bodley)
- [#26500](https://github.com/apache/superset/pull/26500) build(deps): update datamaps requirement from ^0.5.8 to ^0.5.9 in /superset-frontend/plugins/legacy-plugin-chart-world-map (@dependabot[bot])
- [#25663](https://github.com/apache/superset/pull/25663) build(deps-dev): bump @babel/traverse from 7.16.10 to 7.23.2 in /superset-embedded-sdk (@dependabot[bot])
- [#25664](https://github.com/apache/superset/pull/25664) build(deps): bump @babel/traverse from 7.21.4 to 7.23.2 in /superset-frontend/cypress-base (@dependabot[bot])
- [#25662](https://github.com/apache/superset/pull/25662) build(deps): bump @babel/traverse from 7.16.3 to 7.23.2 in /docs (@dependabot[bot])
- [#26606](https://github.com/apache/superset/pull/26606) docs: fix links (@fenilgmehta)
- [#26348](https://github.com/apache/superset/pull/26348) refactor: Removes the deprecated CLIENT_CACHE feature flag (@michael-s-molina)
- [#26349](https://github.com/apache/superset/pull/26349) refactor: Removes the deprecated DASHBOARD_CACHE feature flag (@michael-s-molina)
- [#26450](https://github.com/apache/superset/pull/26450) chore: Deprecates the KV_STORE feature flag (@michael-s-molina)
- [#26343](https://github.com/apache/superset/pull/26343) refactor: Removes the deprecated ENABLE_EXPLORE_DRAG_AND_DROP feature flag (@michael-s-molina)
- [#26331](https://github.com/apache/superset/pull/26331) refactor: Removes the deprecated DISABLE_DATASET_SOURCE_EDIT feature flag (@michael-s-molina)
- [#26589](https://github.com/apache/superset/pull/26589) build(deps): update lodash requirement from ^4.17.11 to ^4.17.21 in /superset-frontend/plugins/legacy-preset-chart-nvd3 (@dependabot[bot])
- [#26506](https://github.com/apache/superset/pull/26506) build(deps): update urijs requirement from ^1.19.8 to ^1.19.11 in /superset-frontend/plugins/legacy-preset-chart-nvd3 (@dependabot[bot])
- [#26520](https://github.com/apache/superset/pull/26520) build(deps-dev): bump style-loader from 3.3.3 to 3.3.4 in /superset-frontend (@dependabot[bot])
- [#26538](https://github.com/apache/superset/pull/26538) build(deps-dev): bump @types/urijs from 1.19.19 to 1.19.25 in /superset-frontend (@dependabot[bot])
- [#26530](https://github.com/apache/superset/pull/26530) build(deps): update lodash requirement from ^4.17.15 to ^4.17.21 in /superset-frontend/packages/superset-ui-chart-controls (@dependabot[bot])
- [#26539](https://github.com/apache/superset/pull/26539) build(deps): update xss requirement from ^1.0.10 to ^1.0.14 in /superset-frontend/plugins/plugin-chart-table (@dependabot[bot])
- [#26545](https://github.com/apache/superset/pull/26545) build(deps): bump moment-timezone from 0.5.37 to 0.5.44 in /superset-frontend (@dependabot[bot])
- [#26562](https://github.com/apache/superset/pull/26562) build(deps): bump less from 4.1.3 to 4.2.0 in /docs (@dependabot[bot])
- [#26612](https://github.com/apache/superset/pull/26612) build(deps): bump @docusaurus/preset-classic from 2.4.1 to 2.4.3 in /docs (@dependabot[bot])
- [#26619](https://github.com/apache/superset/pull/26619) build(deps-dev): bump @types/node from 20.11.0 to 20.11.1 in /superset-websocket (@dependabot[bot])
- [#26503](https://github.com/apache/superset/pull/26503) build(deps): update prop-types requirement from ^15.6.2 to ^15.8.1 in /superset-frontend/plugins/legacy-plugin-chart-sunburst (@dependabot[bot])
- [#26509](https://github.com/apache/superset/pull/26509) build(deps): update prop-types requirement from ^15.6.2 to ^15.8.1 in /superset-frontend/plugins/legacy-plugin-chart-rose (@dependabot[bot])
- [#26515](https://github.com/apache/superset/pull/26515) build(deps): update prop-types requirement from ^15.6.2 to ^15.8.1 in /superset-frontend/plugins/legacy-plugin-chart-country-map (@dependabot[bot])
- [#26524](https://github.com/apache/superset/pull/26524) build(deps): update prop-types requirement from ^15.6.2 to ^15.8.1 in /superset-frontend/plugins/legacy-plugin-chart-partition (@dependabot[bot])
- [#26525](https://github.com/apache/superset/pull/26525) build(deps): update prop-types requirement from ^15.6.2 to ^15.8.1 in /superset-frontend/plugins/legacy-plugin-chart-chord (@dependabot[bot])
- [#26535](https://github.com/apache/superset/pull/26535) build(deps): update prop-types requirement from ^15.6.2 to ^15.8.1 in /superset-frontend/plugins/legacy-plugin-chart-histogram (@dependabot[bot])
- [#26536](https://github.com/apache/superset/pull/26536) build(deps): update prop-types requirement from ^15.6.2 to ^15.8.1 in /superset-frontend/plugins/legacy-plugin-chart-calendar (@dependabot[bot])
- [#26541](https://github.com/apache/superset/pull/26541) build(deps): update lodash requirement from ^4.17.15 to ^4.17.21 in /superset-frontend/plugins/plugin-chart-echarts (@dependabot[bot])
- [#26569](https://github.com/apache/superset/pull/26569) build(deps): update prop-types requirement from ^15.6.2 to ^15.8.1 in /superset-frontend/plugins/legacy-plugin-chart-map-box (@dependabot[bot])
- [#26574](https://github.com/apache/superset/pull/26574) build(deps): update prop-types requirement from ^15.7.2 to ^15.8.1 in /superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates (@dependabot[bot])
- [#26580](https://github.com/apache/superset/pull/26580) build(deps): update prop-types requirement from ^15.6.2 to ^15.8.1 in /superset-frontend/plugins/legacy-plugin-chart-horizon (@dependabot[bot])
- [#26587](https://github.com/apache/superset/pull/26587) build(deps): update prop-types requirement from ^15.7.2 to ^15.8.1 in /superset-frontend/packages/superset-ui-chart-controls (@dependabot[bot])
- [#26477](https://github.com/apache/superset/pull/26477) build(deps): update prop-types requirement from ^15.6.2 to ^15.8.1 in /superset-frontend/plugins/legacy-plugin-chart-sankey (@dependabot[bot])
- [#26480](https://github.com/apache/superset/pull/26480) build(deps): update prop-types requirement from ^15.6.2 to ^15.8.1 in /superset-frontend/plugins/legacy-preset-chart-nvd3 (@dependabot[bot])
- [#26484](https://github.com/apache/superset/pull/26484) build(deps): update prop-types requirement from ^15.6.2 to ^15.8.1 in /superset-frontend/plugins/legacy-plugin-chart-world-map (@dependabot[bot])
- [#26486](https://github.com/apache/superset/pull/26486) build(deps): update prop-types requirement from ^15.6.2 to ^15.8.1 in /superset-frontend/plugins/legacy-plugin-chart-event-flow (@dependabot[bot])
- [#26488](https://github.com/apache/superset/pull/26488) build(deps): update prop-types requirement from ^15.6.2 to ^15.8.1 in /superset-frontend/plugins/legacy-plugin-chart-heatmap (@dependabot[bot])
- [#26492](https://github.com/apache/superset/pull/26492) build(deps): update prop-types requirement from ^15.6.2 to ^15.8.1 in /superset-frontend/plugins/legacy-plugin-chart-sankey-loop (@dependabot[bot])
- [#26558](https://github.com/apache/superset/pull/26558) build(deps): bump @docusaurus/plugin-client-redirects from 2.4.1 to 2.4.3 in /docs (@dependabot[bot])
- [#26554](https://github.com/apache/superset/pull/26554) build(deps): bump @algolia/client-search from 4.13.0 to 4.22.1 in /docs (@dependabot[bot])
- [#26559](https://github.com/apache/superset/pull/26559) build(deps): bump react-draggable from 4.4.3 to 4.4.6 in /superset-frontend (@dependabot[bot])
- [#26568](https://github.com/apache/superset/pull/26568) build(deps): bump react-resizable from 3.0.4 to 3.0.5 in /superset-frontend (@dependabot[bot])
- [#26591](https://github.com/apache/superset/pull/26591) build(deps): update lodash requirement from ^4.17.11 to ^4.17.21 in /superset-frontend/packages/generator-superset (@dependabot[bot])
- [#26592](https://github.com/apache/superset/pull/26592) build(deps): update prop-types requirement from ^15.6.2 to ^15.8.1 in /superset-frontend/plugins/legacy-plugin-chart-paired-t-test (@dependabot[bot])
- [#26600](https://github.com/apache/superset/pull/26600) build(deps-dev): update yeoman-assert requirement from ^3.1.0 to ^3.1.1 in /superset-frontend/packages/generator-superset (@dependabot[bot])
- [#26601](https://github.com/apache/superset/pull/26601) build(deps): update fast-safe-stringify requirement from ^2.0.6 to ^2.1.1 in /superset-frontend/plugins/legacy-preset-chart-nvd3 (@dependabot[bot])
- [#26444](https://github.com/apache/superset/pull/26444) chore(deps): adding dependabot for plugins/packages and upping PR limits. (@rusackas)
- [#26468](https://github.com/apache/superset/pull/26468) docs: Update installing-superset-from-scratch.mdx (@nytai)
- [#26455](https://github.com/apache/superset/pull/26455) build(deps-dev): bump @types/node from 20.10.8 to 20.11.0 in /superset-websocket (@dependabot[bot])
- [#26447](https://github.com/apache/superset/pull/26447) build(deps-dev): bump @types/node from 20.10.7 to 20.10.8 in /superset-websocket (@dependabot[bot])
- [#26441](https://github.com/apache/superset/pull/26441) build(deps): bump follow-redirects from 1.15.2 to 1.15.4 in /superset-frontend (@dependabot[bot])
- [#26440](https://github.com/apache/superset/pull/26440) build(deps-dev): bump follow-redirects from 1.15.3 to 1.15.4 in /superset-embedded-sdk (@dependabot[bot])
- [#26438](https://github.com/apache/superset/pull/26438) build(deps): bump follow-redirects from 1.14.8 to 1.15.4 in /docs (@dependabot[bot])
- [#26428](https://github.com/apache/superset/pull/26428) chore(docs): remove incorrect answer from FAQ (@sfirke)
- [#26425](https://github.com/apache/superset/pull/26425) build(deps-dev): bump @types/node from 20.10.6 to 20.10.7 in /superset-websocket (@dependabot[bot])
- [#24605](https://github.com/apache/superset/pull/24605) chore: Reenable SQLite tests which leverage foreign key constraints et al. (@john-bodley)
- [#26386](https://github.com/apache/superset/pull/26386) build(deps-dev): bump @types/node from 20.10.5 to 20.10.6 in /superset-websocket (@dependabot[bot])
- [#26381](https://github.com/apache/superset/pull/26381) docs: fix spelling and grammar (@fenilgmehta)
- [#26363](https://github.com/apache/superset/pull/26363) build(deps): bump ws from 8.15.0 to 8.16.0 in /superset-websocket (@dependabot[bot])
- [#26371](https://github.com/apache/superset/pull/26371) docs: fix config webdriver snippet in install on K8s (@dbaltor)
- [#26368](https://github.com/apache/superset/pull/26368) chore(docs): point to correct StackOverflow page (@sfirke)
- [#26308](https://github.com/apache/superset/pull/26308) docs: update CVEs fixed on 3.0.2 and 2.1.3 (@dpgaspar)
- [#26305](https://github.com/apache/superset/pull/26305) build(deps-dev): bump @types/node from 20.10.4 to 20.10.5 in /superset-websocket (@dependabot[bot])
- [#26301](https://github.com/apache/superset/pull/26301) chore(sqlalchemy): import from correct path (@villebro)
- [#26294](https://github.com/apache/superset/pull/26294) build(deps-dev): bump eslint from 8.55.0 to 8.56.0 in /superset-websocket (@dependabot[bot])
- [#26293](https://github.com/apache/superset/pull/26293) chore(cleanup): removing redundant rendering logic in telemetry pixel (@rusackas)
- [#26285](https://github.com/apache/superset/pull/26285) chore(docs): fix typo "loader balancer" -> "load balancer" (@sfirke)
- [#26280](https://github.com/apache/superset/pull/26280) chore(in the wild): Making it even easer to add a name (and cleanup) (@rusackas)
- [#26253](https://github.com/apache/superset/pull/26253) chore(docs): add troubleshooting guide to alerts & reports (@sfirke)
- [#26259](https://github.com/apache/superset/pull/26259) chore(async queries): sending statsd event for async events API call (@zephyring)
- [#25628](https://github.com/apache/superset/pull/25628) chore: adding 'no-experimental-fetch' node option by default (@rusackas)
- [#26220](https://github.com/apache/superset/pull/26220) chore(tests): Add tests to the column denormalization flow (@Vitor-Avila)
- [#26078](https://github.com/apache/superset/pull/26078) chore: add class component tasklist file (@eschutho)
- [#26234](https://github.com/apache/superset/pull/26234) build(deps): bump ws from 8.14.2 to 8.15.0 in /superset-websocket (@dependabot[bot])
- [#26233](https://github.com/apache/superset/pull/26233) build(deps-dev): bump ts-node from 10.9.1 to 10.9.2 in /superset-websocket (@dependabot[bot])
- [#26204](https://github.com/apache/superset/pull/26204) build(deps-dev): bump @types/node from 20.10.3 to 20.10.4 in /superset-websocket (@dependabot[bot])
- [#26174](https://github.com/apache/superset/pull/26174) build(deps-dev): bump eslint from 8.54.0 to 8.55.0 in /superset-websocket (@dependabot[bot])
- [#26150](https://github.com/apache/superset/pull/26150) docs: update CHANGELOG for 2.1.2 (@dpgaspar)
- [#26166](https://github.com/apache/superset/pull/26166) build(deps-dev): bump eslint-config-prettier from 9.0.0 to 9.1.0 in /superset-websocket (@dependabot[bot])
- [#26167](https://github.com/apache/superset/pull/26167) build(deps-dev): bump @types/node from 20.10.1 to 20.10.3 in /superset-websocket (@dependabot[bot])
- [#26129](https://github.com/apache/superset/pull/26129) docs: add quickstart (@artofcomputing)
- [#26143](https://github.com/apache/superset/pull/26143) build(deps-dev): bump @types/node from 20.10.0 to 20.10.1 in /superset-websocket (@dependabot[bot])
- [#26149](https://github.com/apache/superset/pull/26149) docs: update CVEs fixed on 3.0.0 (@dpgaspar)
- [#26038](https://github.com/apache/superset/pull/26038) docs(drivers): refresh guide on adding a db driver in docker (@sfirke)
- [#26124](https://github.com/apache/superset/pull/26124) docs: add Increff to INTHEWILD (@ishansinghania)
- [#26112](https://github.com/apache/superset/pull/26112) docs: add Onebeat to users list (@GuyAttia)
- [#26119](https://github.com/apache/superset/pull/26119) docs: Update Trino Kerberos configuration (@john-bodley)
- [#26100](https://github.com/apache/superset/pull/26100) build(deps-dev): bump @types/node from 20.9.4 to 20.10.0 in /superset-websocket (@dependabot[bot])
- [#26099](https://github.com/apache/superset/pull/26099) build(deps-dev): bump @types/cookie from 0.5.4 to 0.6.0 in /superset-websocket (@dependabot[bot])
- [#26104](https://github.com/apache/superset/pull/26104) docs: update CVEs fixed on 2.1.2 (@dpgaspar)

View File

@@ -0,0 +1,151 @@
<!--
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.
-->
# Release Notes for Superset 4.0.0
4.0.0 brings a plethora of exciting changes to Superset. We have introduced several breaking changes to improve the overall architecture and scalability of our codebase. These changes may require some code updates, but they are designed to enhance performance and maintainability in the long run. We have also upgraded various dependencies to their latest versions and deprecated certain features that are no longer aligned with our long-term roadmap. We encourage all developers to carefully review the `CHANGELOG.md` and `UPDATING.md` files and update their code accordingly. While our main focus was on code cleanup, this release also contains exciting new features and marks a significant milestone for the project.
Here are some of the highlights of this release.
### Alerts and Reports modal redesign
The Alerts and Reports modal has been [redesigned](https://github.com/apache/superset/discussions/25729) to improve the user experience and make it more intuitive. The new design has the following goals:
- Declutter the interface by providing a cleaner, more organized layout
- Create a linear setup process with the necessary options in a step-by-step manner to make alert/report setup more intuitive
- Prepare the interface for additional features that will be introduced in future releases, like the ability to pre-filter a dashboard being sent.
<div>
<img src="media/alert-modal-1.png" alt="Image" width="33%">
<img src="media/alert-modal-2.png" alt="Image" width="33%">
<img src="media/alert-modal-3.png" alt="Image" width="33%">
</div>
### Tags
Tags are available using the `TAGGING_SYSTEM` feature flag. They address many of the [requests made by the community](https://github.com/apache/superset/discussions/19194) and aim to make it easier to organize and curate charts, dashboards, and saved queries, allowing for effortless data discovery and collaboration within an organization. Users can create flexible and customizable tags for each piece of content, enabling different ways of organizing assets. Programmatic access to tag-related operations are supported via the RESTful API.
<div>
<img src="media/tags-1.png" alt="Image" width="100%">
<img src="media/tags-2.png" alt="Image" width="100%">
</div>
### New CHANGELOG format
We changed the structure of the `CHANGELOG.md` file in [#26800](https://github.com/apache/superset/pull/26800) to better organize the contents of each release and also to deal with GitHub size limitations when displaying the file. Now every release will have its own file at `CHANGELOG/<version>.md`. The main `CHANGELOG.md` file is now an index with links to all releases.
### Improved drag and drop experience when editing a dashboard
When a component was being dragged towards the edge of the tab container or the row/column containers, multiple drop indicators were often displayed. This created confusion about the exact insertion point of the element. To fix this, we built in [#26699](https://github.com/apache/superset/pull/26699) and [#26313](https://github.com/apache/superset/pull/26313) a distinct, non-conflicting area for the drop zone, which is highlighted during the dragging process to clearly indicate where the element will be placed. We also improved the forbidden drop zones to prevent users from dropping elements in invalid locations.
<div>
<img src="media/dashboard-dnd-1.png" alt="Image" width="100%">
<img src="media/dashboard-dnd-2.png" alt="Image" width="100%">
</div>
### Improved drag and drop experience when editing a chart
Now, during dragging, all droppable zones are highlighted, with distinct colors indicating available and unavailable drop locations. This enhancement clarifies potential drop points and helps avoid inadvertent placements in invalid areas. The update also aligns the drag-over feedback with the dashboard's drag-and-drop modifications, ensuring a uniform and enhanced user experience.
![Drag and drop](media/explore-dnd.png)
### Dropping support for 3.0.X versions
In accordance with our [release process](https://github.com/apache/superset/wiki/Release-Process), we are dropping support for the 3.0.X versions. As a result, we will no longer be providing bug fixes for these versions. We strongly recommend that all users upgrade to the latest version to take advantage of the newest features and bug fixes. Moving forward, the supported versions will be 3.1.X and 4.0.X. Bug fixes will continue to be backported to 3.1.X until the next minor release. For more information, please refer to our [release schedule](https://github.com/apache/superset/wiki/Release-Process#schedule).
### Feature flag changes
Following our 4.0 proposals, the following feature flags were removed, i.e., the feature was permanently enabled or removed.
- `VERSIONED_EXPORT`
- `DASHBOARD_FILTERS_EXPERIMENTAL`
- `ENABLE_EXPLORE_JSON_CSRF_PROTECTION`
- `ENABLE_TEMPLATE_REMOVE_FILTERS`
- `REMOVE_SLICE_LEVEL_LABEL_COLORS`
- `CLIENT_CACHE`
- `DASHBOARD_CACHE`
- `DASHBOARD_NATIVE_FILTERS_SET`
- `ENABLE_EXPLORE_DRAG_AND_DROP`
- `DISABLE_DATASET_SOURCE_EDIT`
- `DASHBOARD_NATIVE_FILTERS`
- `GENERIC_CHART_AXES`
The following feature flags were deprecated:
- `DASHBOARD_CROSS_FILTERS`
- `ENABLE_JAVASCRIPT_CONTROLS`
- `KV_STORE`
The following feature flags were enabled by default:
- `DASHBOARD_VIRTUALIZATION`
- `DRILL_BY`
### Removed features
As part of the 4.0 approved initiatives, the following features were removed from Superset:
- Filter Box: [#26328](https://github.com/apache/superset/pull/26328) removed the Filter Box code and its associated dependencies `react-select` and `array-move`. It also removed the `DeprecatedSelect` and `AsyncSelect` components that were exclusively used by filter boxes. Existing filter boxes will be automatically migrated to native dashboard filters.
- Filter Sets: [#26369](https://github.com/apache/superset/pull/26369) removed the Filters Set feature including the deprecated `DASHBOARD_NATIVE_FILTERS_SET` feature flag and all related API endpoints. The feature is permanently removed as it was not being actively maintained, it was not widely used, and it was full of bugs. We also considered that if we were to provide a similar feature, it would be better to re-implement it from scratch given the amount of technical debt that the implementation had.
- Profile: [#26462](https://github.com/apache/superset/pull/26462) removed the Profile feature given that it was not actively maintained nor widely used.
- Redirect API: [#26377](https://github.com/apache/superset/pull/26377) removed the deprecated Redirect API that supported short URLs (`/r`) and the `url` metadata table used to store them that was used before the permalink feature. Users lost the ability to generate R links ~1.5 years ago which seems sufficient time to remove the API.
### Business logic improvements
As part of [[SIP-99] Proposal for correctly handling business logic](https://github.com/apache/superset/issues/25048) (specifically [SIP-99A](https://github.com/apache/superset/issues/25107) and [SIP-99B](https://github.com/apache/superset/issues/25108)), this release contains many improvements to the handling of business logic in Superset, specifically related to SQLAlchemy sessions and transactions. The goal of these efforts is to simplify the code, improve code quality, ensure a consistent "unit of work" approach, and provide clear guidance and examples of accepted code standards. These changes aim to improve developer experience by making the code simpler, improving testing, and ensuring a more streamlined and reliable system. We still have a long way to go to fully implement the SIP-99 proposal, but we are making progress and we are excited about the improvements that have been made so far.
### All country maps are now managed via Jupyter Notebook
In this release we made updates to the Jupyter Notebook to ensure reliable execution by removing deprecated methods, adding new countries, including missing maps, and fixing filename inconsistencies. This will make it easier to add more countries, dynamically add them to the country map plugin, and update map regions periodically. You can check [#26300](https://github.com/apache/superset/pull/26300) for more details.
### Sunburst chart migrated to ECharts
The ECharts version of the Sunburst chart was introduced by [#22833](https://github.com/apache/superset/pull/22833) as part of our efforts to complete [SIP-50](https://github.com/apache/superset/issues/10418). In 4.0, legacy Sunburst charts are [automatically migrated](https://github.com/apache/superset/pull/26350) to ECharts and the legacy version was removed.
![Sunburst](media/sunburst.png)
### Some cool stats
- ~15K lines of code were removed by PRs related to 4.0 proposals
- We reduced the number of NPM packages vulnerabilities by 72%
- 3.1: 90 vulnerabilities (42 moderate, 34 high, 14 critical)
- 4.0: 25 vulnerabilities (16 moderate, 8 high, 1 critical)
- 40+ dependency changes (upgrades, additions, and removals)
### How to upgrade
As with any Superset version upgrade, the process is simple in the broadest strokes, as outlined in the documentation. However, as with any upgrade, we expect to see numerous speed bumps along that path depending on your configuration, your infrastructure, your databases in use, and other customizations/configurations. To make a safe leap to this version, we'd suggest the following steps:
- Back up your databases
- Carefully read `CHANGELOG.md` for all the incremental changes in this version (and any prior versions between your current installation and 4.0.0).
- Similarly, review `UPDATING.md` to keep an eye out for all changes that have been explicitly marked as breaking changes.
- Adjust your feature flags and configurations to meet your feature requirements and preferences.
- Execute the migrations
- If you have third-party apps interacting with Superset, check for relevant dependency updates or API endpoint changes that may affect compatibility.
Your mileage may vary depending on:
- How you install and deploy Superset (e.g. docker vs. pip vs. helm)
- How youve configured Superset
- What integrations, databases, etc. you're using
Reach out in `#deploying-superset` on Slack in case you find any problems, and if you find a reproducible bug, please file a new issue on GitHub.

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 611 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 441 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 626 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 374 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 267 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 294 KiB

View File

@@ -39,7 +39,7 @@ PYTHON=$(get_python_command)
PIP=$(get_pip_command)
# Get the release directory's path. If you unzip an Apache release and just run the npm script to validate the release, this will be a file name like `apache-superset-x.x.xrcx-source.tar.gz`
RELEASE_DIR_NAME="../../$(basename "$(dirname "$(pwd)")").tar.gz"
RELEASE_ZIP_PATH="../../$(basename "$(dirname "$(pwd)")")-source.tar.gz"
# Install dependencies from requirements.txt if the file exists
if [ -f "path/to/requirements.txt" ]; then
@@ -47,8 +47,5 @@ if [ -f "path/to/requirements.txt" ]; then
$PYTHON -m $PIP install -r path/to/requirements.txt
fi
# echo $PYTHON
# echo $RELEASE_DIR_NAME
# Run the Python script with the parent directory name as an argument
$PYTHON ../RELEASING/verify_release.py "$RELEASE_DIR_NAME"
$PYTHON ../RELEASING/verify_release.py "$RELEASE_ZIP_PATH"

View File

@@ -22,7 +22,7 @@ under the License.
This file documents any backwards-incompatible changes in Superset and
assists people when migrating to a new version.
## Next
## 4.0.0
- [27119](https://github.com/apache/superset/pull/27119): Updates various database columns to use the `MediumText` type, potentially requiring a table lock on MySQL dbs or taking some time to complete on large deployments.
@@ -30,7 +30,7 @@ assists people when migrating to a new version.
### Breaking Changes
- [27130](https://github.com/apache/superset/pull/27130): Fixes the DELETE `/database/{id}/ssh_tunnel/`` endpoint to now correctly accept a database ID as a parameter, rather than an SSH tunnel ID.
- [27130](https://github.com/apache/superset/pull/27130): Fixes the DELETE `/database/{id}/ssh_tunnel/` endpoint to now correctly accept a database ID as a parameter, rather than an SSH tunnel ID.
- [27117](https://github.com/apache/superset/pull/27117): Removes the following deprecated endpoints: `/superset/sqllab`, `/superset/sqllab/history`, `/sqllab/my_queries` use `/sqllab`, `/sqllab/history`, `/savedqueryview/list/?_flt_0_user={get_user_id()}` instead.
- [26347](https://github.com/apache/superset/issues/26347): Removes the deprecated `VERSIONED_EXPORT` feature flag. The previous value of the feature flag was `True` and now the feature is permanently enabled.
- [26328](https://github.com/apache/superset/issues/26328): Removes the deprecated Filter Box code and it's associated dependencies `react-select` and `array-move`. It also removes the `DeprecatedSelect` and `AsyncSelect` components that were exclusively used by filter boxes. Existing filter boxes will be automatically migrated to native filters.
@@ -53,7 +53,7 @@ assists people when migrating to a new version.
### Potential Downtime
- [26416](https://github.com/apache/superset/pull/26416): adds 2 database indexes to report_execution_log and 1 to report_recipient to improve performance, this may cause downtime on large deployments.
- [26416](https://github.com/apache/superset/pull/26416): Adds two database indexes to the `report_execution_log` table and one database index to the `report_recipient` to improve performance. Scheduled downtime may be required for large deployments.
## 3.1.0

View File

@@ -17,3 +17,6 @@
# under the License.
#
-e file:.
urllib3>=1.26.18
werkzeug>=3.0.1
numexpr>=2.9.0

View File

@@ -1,4 +1,4 @@
# SHA1:a9dde048f1ee1f00586264d726d0e89f16e56183
# SHA1:85649679306ea016e401f37adfbad832028d2e5f
#
# This file is autogenerated by pip-compile-multi
# To update, run:
@@ -78,7 +78,7 @@ cron-descriptor==1.2.24
# via apache-superset
croniter==1.0.15
# via apache-superset
cryptography==42.0.2
cryptography==42.0.4
# via
# apache-superset
# paramiko
@@ -104,7 +104,7 @@ flask==2.2.5
# flask-session
# flask-sqlalchemy
# flask-wtf
flask-appbuilder==4.4.0
flask-appbuilder==4.4.1
# via apache-superset
flask-babel==1.0.0
# via flask-appbuilder
@@ -143,7 +143,9 @@ geopy==2.2.0
google-auth==2.27.0
# via shillelagh
greenlet==3.0.3
# via shillelagh
# via
# shillelagh
# sqlalchemy
gunicorn==21.2.0
# via apache-superset
hashids==1.3.1
@@ -208,8 +210,10 @@ nh3==0.2.11
# via apache-superset
numba==0.57.1
# via pandas
numexpr==2.8.4
# via pandas
numexpr==2.9.0
# via
# -r requirements/base.in
# pandas
numpy==1.23.5
# via
# apache-superset
@@ -232,7 +236,9 @@ packaging==23.1
pandas[performance]==2.0.3
# via apache-superset
paramiko==3.4.0
# via sshtunnel
# via
# apache-superset
# sshtunnel
parsedatetime==2.6
# via apache-superset
pgsanity==0.2.9
@@ -336,7 +342,7 @@ sqlalchemy-utils==0.38.3
# via
# apache-superset
# flask-appbuilder
sqlglot==20.8.0
sqlglot==23.0.2
# via apache-superset
sqlparse==0.4.4
# via apache-superset
@@ -358,6 +364,7 @@ url-normalize==1.4.3
# via requests-cache
urllib3==1.26.18
# via
# -r requirements/base.in
# requests
# requests-cache
# selenium
@@ -370,6 +377,7 @@ wcwidth==0.2.5
# via prompt-toolkit
werkzeug==3.0.1
# via
# -r requirements/base.in
# flask
# flask-appbuilder
# flask-jwt-extended

View File

@@ -82,10 +82,6 @@ ptyprocess==0.7.0
# via pexpect
pure-eval==0.2.2
# via stack-data
pure-sasl==0.6.2
# via
# pyhive
# thrift-sasl
pydruid==0.6.5
# via apache-superset
pyhive[hive_pure_sasl]==0.7.0
@@ -109,12 +105,7 @@ tableschema==1.20.2
tabulator==1.53.5
# via tableschema
thrift==0.16.0
# via
# apache-superset
# pyhive
# thrift-sasl
thrift-sasl==0.4.3
# via pyhive
# via apache-superset
tomlkit==0.11.8
# via pylint
traitlets==5.9.0

View File

@@ -15,6 +15,5 @@
# limitations under the License.
#
-r base.in
-e .[postgres]
gevent
-e .[postgres,gevent]
greenlet>=2.0.2

View File

@@ -1,4 +1,4 @@
# SHA1:439e3ee196ce81f342c935117ba5e0eeee8c385b
# SHA1:f00a57c70a52607d638c19f64f426f887382927e
#
# This file is autogenerated by pip-compile-multi
# To update, run:
@@ -11,7 +11,7 @@
# -r requirements/base.in
# -r requirements/docker.in
gevent==23.9.1
# via -r requirements/docker.in
# via apache-superset
psycopg2-binary==2.9.6
# via apache-superset
zope-event==4.5.0

View File

@@ -20,6 +20,7 @@
docker
flask-testing
freezegun
grpcio>=1.55.3
openapi-spec-validator
parameterized
pyfakefs

View File

@@ -1,4 +1,4 @@
# SHA1:95300275481abb1413eb98a5c79fb7cf96814cdd
# SHA1:a37a1037f359c1101162ef43288178fbf00c487d
#
# This file is autogenerated by pip-compile-multi
# To update, run:
@@ -62,6 +62,7 @@ googleapis-common-protos==1.59.0
# grpcio-status
grpcio==1.60.1
# via
# -r requirements/testing.in
# google-api-core
# google-cloud-bigquery
# grpcio-status
@@ -132,7 +133,7 @@ tqdm==4.65.0
# via
# cmdstanpy
# prophet
trino==0.324.0
trino==0.328.0
# via apache-superset
tzlocal==4.3
# via trino

View File

@@ -80,11 +80,10 @@ setup(
"colorama",
"croniter>=0.3.28",
"cron-descriptor",
# snowflake-connector-python as of 3.7.0 doesn't support >=42.* therefore lowering the min to 41.0.2
"cryptography>=41.0.2, <43.0.0",
"cryptography>=42.0.4, <43.0.0",
"deprecation>=2.1.0, <2.2.0",
"flask>=2.2.5, <3.0.0",
"flask-appbuilder>=4.4.0, <5.0.0",
"flask-appbuilder>=4.4.1, <5.0.0",
"flask-caching>=2.1.0, <3",
"flask-compress>=1.13, <2.0",
"flask-talisman>=1.0.0, <2.0",
@@ -108,6 +107,7 @@ setup(
"packaging",
"pandas[performance]>=2.0.3, <2.1",
"parsedatetime",
"paramiko>=3.4.0",
"pgsanity",
"polyline>=2.0.0, <3.0",
"pyparsing>=3.0.6, <4",
@@ -126,7 +126,7 @@ setup(
"slack_sdk>=3.19.0, <4",
"sqlalchemy>=1.4, <2",
"sqlalchemy-utils>=0.38.3, <0.39",
"sqlglot>=20,<21",
"sqlglot>=23.0.2,<24",
"sqlparse>=0.4.4, <0.5",
"tabulate>=0.8.9, <0.9",
"typing-extensions>=4, <5",
@@ -189,7 +189,7 @@ setup(
"playwright": ["playwright>=1.37.0, <2"],
"postgres": ["psycopg2-binary==2.9.6"],
"presto": ["pyhive[presto]>=0.6.5"],
"trino": ["trino>=0.324.0"],
"trino": ["trino>=0.328.0"],
"prophet": ["prophet>=1.1.5, <2"],
"redshift": ["sqlalchemy-redshift>=0.8.1, <0.9"],
"rockset": ["rockset-sqlalchemy>=0.0.1, <1"],

View File

@@ -173,6 +173,13 @@ describe('Charts list', () => {
orderAlphabetical();
cy.getBySel('styled-card').first().contains('% Rural');
});
it('should preserve other filters when sorting', () => {
cy.getBySel('styled-card').should('have.length', 25);
setFilter('Type', 'Big Number');
setFilter('Sort', 'Least recently modified');
cy.getBySel('styled-card').should('have.length', 3);
});
});
describe('common actions', () => {

View File

@@ -117,6 +117,13 @@ describe('Dashboards list', () => {
orderAlphabetical();
cy.getBySel('styled-card').first().contains('Supported Charts Dashboard');
});
it('should preserve other filters when sorting', () => {
cy.getBySel('styled-card').should('have.length', 5);
setFilter('Status', 'Published');
setFilter('Sort', 'Least recently modified');
cy.getBySel('styled-card').should('have.length', 3);
});
});
describe('common actions', () => {

View File

@@ -210,7 +210,7 @@ describe('Time range filter', () => {
.click()
.then(() => {
cy.get('.ant-radio-group').children().its('length').should('eq', 5);
cy.get('.ant-radio-checked + span').contains('last year');
cy.get('.ant-radio-checked + span').contains('Last year');
cy.get('[data-test=cancel-button]').click();
});
});

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "superset",
"version": "0.0.0-dev",
"version": "4.0.0",
"description": "Superset is a data exploration platform designed to be visual, intuitive, and interactive.",
"keywords": [
"big",
@@ -43,7 +43,6 @@
"build-instrumented": "cross-env NODE_ENV=production BABEL_ENV=instrumented webpack --mode=production --color",
"build-storybook": "storybook build",
"check-translation": "prettier --check ../superset/translations/**/LC_MESSAGES/*.json",
"chromatic": "npx chromatic --skip 'dependabot/**' --only-changed",
"clean-translation": "prettier --write ../superset/translations/**/LC_MESSAGES/*.json",
"core:cover": "cross-env NODE_ENV=test jest --coverage --coverageThreshold='{\"global\":{\"statements\":100,\"branches\":100,\"functions\":100,\"lines\":100}}' --collectCoverageFrom='[\"packages/**/src/**/*.{js,ts}\", \"!packages/superset-ui-demo/**/*\"]' packages",
"cover": "cross-env NODE_ENV=test jest --coverage",
@@ -57,7 +56,6 @@
"plugins:build": "node ./scripts/build.js",
"plugins:build-assets": "node ./scripts/copyAssets.js",
"plugins:build-storybook": "cd packages/superset-ui-demo && npm run build-storybook",
"plugins:chromatic": "cd packages/superset-ui-demo && npm run chromatic",
"plugins:create-conventional-version": "npm run prune && lerna version --conventional-commits --create-release github --no-private --yes",
"plugins:create-minor-version": "npm run prune && lerna version minor --no-private --yes",
"plugins:create-patch-version": "npm run prune && lerna version patch --no-private --yes",
@@ -268,6 +266,7 @@
"@types/react-table": "^7.7.19",
"@types/react-transition-group": "^4.4.10",
"@types/react-ultimate-pagination": "^1.2.0",
"@types/react-virtualized-auto-sizer": "^1.0.4",
"@types/react-window": "^1.8.5",
"@types/redux-localstorage": "^1.0.8",
"@types/redux-mock-store": "^1.0.2",
@@ -283,7 +282,6 @@
"babel-plugin-dynamic-import-node": "^2.3.3",
"babel-plugin-jsx-remove-data-test-id": "^2.1.3",
"babel-plugin-lodash": "^3.3.4",
"chromatic": "^6.7.4",
"copy-webpack-plugin": "^12.0.2",
"cross-env": "^5.2.1",
"css-loader": "^6.8.1",

View File

@@ -115,11 +115,11 @@ export default function makeApi<
jsonPayload: undefined as JsonObject | undefined,
};
if (requestType === 'search') {
requestConfig.searchParams = payload as URLSearchParams;
requestConfig.searchParams = payload as unknown as URLSearchParams;
} else if (requestType === 'rison') {
requestConfig.endpoint = `${endpoint}?q=${rison.encode(payload)}`;
} else if (requestType === 'form') {
requestConfig.postPayload = payload as FormData;
requestConfig.postPayload = payload as unknown as FormData;
} else {
requestConfig.jsonPayload = payload as JsonObject;
}

View File

@@ -44,15 +44,15 @@ interface MenuObjectChildProps {
disable?: boolean;
}
export interface SwitchProps {
isEditMode: boolean;
dbFetched: any;
disableSSHTunnelingForEngine?: boolean;
useSSHTunneling: boolean;
setUseSSHTunneling: React.Dispatch<React.SetStateAction<boolean>>;
setDB: React.Dispatch<any>;
isSSHTunneling: boolean;
}
// loose typing to avoid any circular dependencies
// refer to SSHTunnelSwitch component for strict typing
type SwitchProps = {
db: object;
changeMethods: {
onParametersChange: (event: any) => void;
};
clearValidationErrors: () => void;
};
type ConfigDetailsProps = {
embeddedId: string;

View File

@@ -62,7 +62,6 @@
"@babel/preset-typescript": "^7.23.3",
"@storybook/react-webpack5": "^7.6.13",
"babel-loader": "^8.1.0",
"chromatic": "^5.4.0",
"fork-ts-checker-webpack-plugin": "^5.0.7",
"ts-loader": "^7.0.4",
"typescript": "^4.5.4"

View File

@@ -90,9 +90,6 @@ export default function createQueryStory({
</div>
);
};
story.parameters = {
chromatic: { disable: true },
};
story.args = {
host: 'localhost:8088',
mode: keys[0],

View File

@@ -40,7 +40,7 @@ export default {
],
};
export const configureCORS = ({
export const ConfigureCORS = ({
host,
selectEndpoint,
customEndpoint,
@@ -84,18 +84,14 @@ export const configureCORS = ({
</div>
);
};
configureCORS.parameters = {
chromatic: { disable: true },
};
configureCORS.args = {
ConfigureCORS.args = {
host: 'localhost:8088',
selectEndpoint: '/api/v1/chart/data',
customEndpoint: '',
methodOption: 'POST', // TODO disable when custonEndpoint and selectEndpoint are empty
postPayloadContents: JSON.stringify({ form_data: bigNumberFormData }),
};
configureCORS.argTypes = {
ConfigureCORS.argTypes = {
host: {
control: 'text',
description: 'Set Superset App host for CORS request',
@@ -122,4 +118,4 @@ configureCORS.argTypes = {
description: 'Set POST payload contents',
},
};
configureCORS.storyName = 'Verify CORS';
ConfigureCORS.storyName = 'Verify CORS';

View File

@@ -177,15 +177,12 @@ function Heatmap(element, props) {
}
}
function ordScale(k, rangeBands, sortMethod) {
function ordScale(k, rangeBands, sortMethod, formatter) {
let domain = {};
const actualKeys = {}; // hack to preserve type of keys when number
records.forEach(d => {
domain[d[k]] = (domain[d[k]] || 0) + d.v;
actualKeys[d[k]] = d[k];
});
// Not using object.keys() as it converts to strings
const keys = Object.keys(actualKeys).map(s => actualKeys[s]);
const keys = Object.keys(domain).map(k => formatter(k));
if (sortMethod === 'alpha_asc') {
domain = keys.sort(cmp);
} else if (sortMethod === 'alpha_desc') {
@@ -252,10 +249,10 @@ function Heatmap(element, props) {
const fp = getNumberFormatter(NumberFormats.PERCENT_2_POINT);
const xScale = ordScale('x', null, sortXAxis);
const yScale = ordScale('y', null, sortYAxis);
const xRbScale = ordScale('x', [0, hmWidth], sortXAxis);
const yRbScale = ordScale('y', [hmHeight, 0], sortYAxis);
const xScale = ordScale('x', null, sortXAxis, xAxisFormatter);
const yScale = ordScale('y', null, sortYAxis, yAxisFormatter);
const xRbScale = ordScale('x', [0, hmWidth], sortXAxis, xAxisFormatter);
const yRbScale = ordScale('y', [hmHeight, 0], sortYAxis, yAxisFormatter);
const X = 0;
const Y = 1;
const heatmapDim = [xRbScale.domain().length, yRbScale.domain().length];

View File

@@ -57,11 +57,15 @@ export default function transformProps(chartProps) {
const xAxisFormatter =
coltypes[0] === GenericDataType.Temporal
? getTimeFormatter(timeFormat)
: String;
: coltypes[0] === GenericDataType.Numeric
? Number
: String;
const yAxisFormatter =
coltypes[1] === GenericDataType.Temporal
? getTimeFormatter(timeFormat)
: String;
: coltypes[1] === GenericDataType.Numeric
? Number
: String;
return {
width,
height,

View File

@@ -48,11 +48,12 @@ import { getDefaultTooltip } from '../utils/tooltip';
import { Refs } from '../types';
import { getColtypesMapping } from '../utils/series';
const setIntervalBoundsAndColors = (
export const getIntervalBoundsAndColors = (
intervals: string,
intervalColorIndices: string,
colorFn: CategoricalColorScale,
normalizer: number,
min: number,
max: number,
): Array<[number, string]> => {
let intervalBoundsNonNormalized;
let intervalColorIndicesArray;
@@ -65,7 +66,7 @@ const setIntervalBoundsAndColors = (
}
const intervalBounds = intervalBoundsNonNormalized.map(
bound => bound / normalizer,
bound => (bound - min) / (max - min),
);
const intervalColors = intervalColorIndicesArray.map(
ind => colorFn.colors[(ind - 1) % colorFn.colors.length],
@@ -221,12 +222,12 @@ export default function transformProps(
const axisLabelLength = Math.max(
...axisLabels.map(label => numberFormatter(label).length).concat([1]),
);
const normalizer = max;
const intervalBoundsAndColors = setIntervalBoundsAndColors(
const intervalBoundsAndColors = getIntervalBoundsAndColors(
intervals,
intervalColorIndices,
colorFn,
normalizer,
min,
max,
);
const splitLineDistance =
axisLineWidth + splitLineLength + OFFSETS.ticksFromLine;

View File

@@ -410,8 +410,9 @@ export default function transformProps(
rawSeriesB.forEach(entry => {
const entryName = String(entry.name || '');
const seriesName = `${inverted[entryName] || entryName} (1)`;
const colorScaleKey = getOriginalSeries(seriesName, array);
const seriesEntry = inverted[entryName] || entryName;
const seriesName = `${seriesEntry} (1)`;
const colorScaleKey = getOriginalSeries(seriesEntry, array);
const seriesFormatter = getFormatter(
customFormattersSecondary,

View File

@@ -575,7 +575,6 @@ export default function transformProps(
right: TIMESERIES_CONSTANTS.toolboxRight,
feature: {
dataZoom: {
yAxisIndex: false,
title: {
zoom: t('zoom area'),
back: t('restore zoom'),
@@ -590,6 +589,7 @@ export default function transformProps(
start: TIMESERIES_CONSTANTS.dataZoomStart,
end: TIMESERIES_CONSTANTS.dataZoomEnd,
bottom: TIMESERIES_CONSTANTS.zoomBottom,
yAxisIndex: isHorizontal ? 0 : undefined,
},
]
: [],

View File

@@ -570,9 +570,10 @@ export function getPadding(
yAxisTitlePosition && yAxisTitlePosition === 'Top'
? TIMESERIES_CONSTANTS.gridOffsetTop + (Number(yAxisTitleMargin) || 0)
: TIMESERIES_CONSTANTS.gridOffsetTop + yAxisOffset,
bottom: zoomable
? TIMESERIES_CONSTANTS.gridOffsetBottomZoomable + xAxisOffset
: TIMESERIES_CONSTANTS.gridOffsetBottom + xAxisOffset,
bottom:
zoomable && !isHorizontal
? TIMESERIES_CONSTANTS.gridOffsetBottomZoomable + xAxisOffset
: TIMESERIES_CONSTANTS.gridOffsetBottom + xAxisOffset,
left:
yAxisTitlePosition === 'Left'
? TIMESERIES_CONSTANTS.gridOffsetLeft +

View File

@@ -16,8 +16,15 @@
* specific language governing permissions and limitations
* under the License.
*/
import { ChartProps, SqlaFormData, supersetTheme } from '@superset-ui/core';
import transformProps from '../../src/Gauge/transformProps';
import {
CategoricalColorNamespace,
ChartProps,
SqlaFormData,
supersetTheme,
} from '@superset-ui/core';
import transformProps, {
getIntervalBoundsAndColors,
} from '../../src/Gauge/transformProps';
import { EchartsGaugeChartProps } from '../../src/Gauge/types';
describe('Echarts Gauge transformProps', () => {
@@ -256,8 +263,9 @@ describe('Echarts Gauge transformProps', () => {
const formData: SqlaFormData = {
...baseFormData,
groupby: ['year', 'platform'],
intervals: '50,100',
intervals: '60,100',
intervalColorIndices: '1,2',
minVal: 20,
};
const queriesData = [
{
@@ -342,3 +350,43 @@ describe('Echarts Gauge transformProps', () => {
);
});
});
describe('getIntervalBoundsAndColors', () => {
it('should generate correct interval bounds and colors', () => {
const colorFn = CategoricalColorNamespace.getScale(
'supersetColors' as string,
);
expect(getIntervalBoundsAndColors('', '', colorFn, 0, 10)).toEqual([]);
expect(getIntervalBoundsAndColors('4, 10', '1, 2', colorFn, 0, 10)).toEqual(
[
[0.4, '#1f77b4'],
[1, '#ff7f0e'],
],
);
expect(
getIntervalBoundsAndColors('4, 8, 10', '9, 8, 7', colorFn, 0, 10),
).toEqual([
[0.4, '#bcbd22'],
[0.8, '#7f7f7f'],
[1, '#e377c2'],
]);
expect(getIntervalBoundsAndColors('4, 10', '1, 2', colorFn, 2, 10)).toEqual(
[
[0.25, '#1f77b4'],
[1, '#ff7f0e'],
],
);
expect(
getIntervalBoundsAndColors('-4, 0', '1, 2', colorFn, -10, 0),
).toEqual([
[0.6, '#1f77b4'],
[1, '#ff7f0e'],
]);
expect(
getIntervalBoundsAndColors('-4, -2', '1, 2', colorFn, -10, -2),
).toEqual([
[0.75, '#1f77b4'],
[1, '#ff7f0e'],
]);
});
});

View File

@@ -743,15 +743,18 @@ export function removeQueryEditor(queryEditor) {
return sync
.then(() => dispatch({ type: REMOVE_QUERY_EDITOR, queryEditor }))
.catch(() =>
dispatch(
addDangerToast(
t(
'An error occurred while removing tab. Please contact your administrator.',
.catch(({ status }) => {
if (status !== 404) {
return dispatch(
addDangerToast(
t(
'An error occurred while removing tab. Please contact your administrator.',
),
),
),
),
);
);
}
return dispatch({ type: REMOVE_QUERY_EDITOR, queryEditor });
});
};
}
@@ -1127,9 +1130,11 @@ export function removeTables(tables) {
const sync = isFeatureEnabled(FeatureFlag.SqllabBackendPersistence)
? Promise.all(
tablesToRemove.map(table =>
SupersetClient.delete({
endpoint: encodeURI(`/tableschemaview/${table.id}`),
}),
table.initialized
? SupersetClient.delete({
endpoint: encodeURI(`/tableschemaview/${table.id}`),
})
: Promise.resolve(),
),
)
: Promise.resolve();

View File

@@ -883,7 +883,7 @@ describe('async actions', () => {
it('updates the table schema state in the backend', () => {
expect.assertions(2);
const table = { id: 1 };
const table = { id: 1, initialized: true };
const store = mockStore({});
const expectedActions = [
{
@@ -900,7 +900,10 @@ describe('async actions', () => {
it('deletes multiple tables and updates the table schema state in the backend', () => {
expect.assertions(2);
const tables = [{ id: 1 }, { id: 2 }];
const tables = [
{ id: 1, initialized: true },
{ id: 2, initialized: true },
];
const store = mockStore({});
const expectedActions = [
{
@@ -913,6 +916,23 @@ describe('async actions', () => {
expect(fetchMock.calls(updateTableSchemaEndpoint)).toHaveLength(2);
});
});
it('only updates the initialized table schema state in the backend', () => {
expect.assertions(2);
const tables = [{ id: 1 }, { id: 2, initialized: true }];
const store = mockStore({});
const expectedActions = [
{
type: actions.REMOVE_TABLES,
tables,
},
];
return store.dispatch(actions.removeTables(tables)).then(() => {
expect(store.getActions()).toEqual(expectedActions);
expect(fetchMock.calls(updateTableSchemaEndpoint)).toHaveLength(1);
});
});
});
describe('migrateQueryEditorFromLocalStorage', () => {

View File

@@ -17,7 +17,10 @@
* under the License.
*/
import React from 'react';
import { render, screen } from 'spec/helpers/testing-library';
import fetchMock from 'fetch-mock';
import * as uiCore from '@superset-ui/core';
import { FeatureFlag, QueryState } from '@superset-ui/core';
import { render, screen, waitFor } from 'spec/helpers/testing-library';
import QueryHistory from 'src/SqlLab/components/QueryHistory';
import { initialState } from 'src/SqlLab/fixtures';
@@ -27,18 +30,72 @@ const mockedProps = {
latestQueryId: 'yhMUZCGb',
};
const fakeApiResult = {
count: 4,
ids: [692],
result: [
{
changed_on: '2024-03-12T20:01:02.497775',
client_id: 'b0ZDzRYzn',
database: {
database_name: 'examples',
id: 1,
},
end_time: '1710273662496.047852',
error_message: null,
executed_sql: 'SELECT * from "FCC 2018 Survey"\nLIMIT 1001',
id: 692,
limit: 1000,
limiting_factor: 'DROPDOWN',
progress: 100,
results_key: null,
rows: 443,
schema: 'main',
select_as_cta: false,
sql: 'SELECT * from "FCC 2018 Survey" ',
sql_editor_id: '22',
start_time: '1710273662445.992920',
status: QueryState.Success,
tab_name: 'Untitled Query 16',
tmp_table_name: null,
tracking_url: null,
user: {
first_name: 'admin',
id: 1,
last_name: 'user',
},
},
],
};
const setup = (overrides = {}) => (
<QueryHistory {...mockedProps} {...overrides} />
);
describe('QueryHistory', () => {
it('Renders an empty state for query history', () => {
render(setup(), { useRedux: true, initialState });
test('Renders an empty state for query history', () => {
render(setup(), { useRedux: true, initialState });
const emptyStateText = screen.getByText(
/run a query to display query history/i,
const emptyStateText = screen.getByText(
/run a query to display query history/i,
);
expect(emptyStateText).toBeVisible();
});
test('fetches the query history when the persistence mode is enabled', async () => {
const isFeatureEnabledMock = jest
.spyOn(uiCore, 'isFeatureEnabled')
.mockImplementation(
featureFlag => featureFlag === FeatureFlag.SqllabBackendPersistence,
);
expect(emptyStateText).toBeVisible();
});
const editorQueryApiRoute = `glob:*/api/v1/query/?q=*`;
fetchMock.get(editorQueryApiRoute, fakeApiResult);
render(setup(), { useRedux: true, initialState });
await waitFor(() =>
expect(fetchMock.calls(editorQueryApiRoute).length).toBe(1),
);
const queryResultText = screen.getByText(fakeApiResult.result[0].rows);
expect(queryResultText).toBeInTheDocument();
isFeatureEnabledMock.mockClear();
});

View File

@@ -16,12 +16,23 @@
* specific language governing permissions and limitations
* under the License.
*/
import React, { useMemo } from 'react';
import React, { useEffect, useMemo, useState } from 'react';
import { shallowEqual, useSelector } from 'react-redux';
import { useInView } from 'react-intersection-observer';
import { omit } from 'lodash';
import { EmptyStateMedium } from 'src/components/EmptyState';
import { t, styled } from '@superset-ui/core';
import {
t,
styled,
css,
FeatureFlag,
isFeatureEnabled,
} from '@superset-ui/core';
import QueryTable from 'src/SqlLab/components/QueryTable';
import { SqlLabRootState } from 'src/SqlLab/types';
import { useEditorQueriesQuery } from 'src/hooks/apiResources/queries';
import { Skeleton } from 'src/components';
import useEffectEvent from 'src/hooks/useEffectEvent';
interface QueryHistoryProps {
queryEditorId: string | number;
@@ -40,39 +51,92 @@ const StyledEmptyStateWrapper = styled.div`
}
`;
const getEditorQueries = (
queries: SqlLabRootState['sqlLab']['queries'],
queryEditorId: string | number,
) =>
Object.values(queries).filter(
({ sqlEditorId }) => String(sqlEditorId) === String(queryEditorId),
);
const QueryHistory = ({
queryEditorId,
displayLimit,
latestQueryId,
}: QueryHistoryProps) => {
const [ref, hasReachedBottom] = useInView({ threshold: 0 });
const [pageIndex, setPageIndex] = useState(0);
const queries = useSelector(
({ sqlLab: { queries } }: SqlLabRootState) => queries,
shallowEqual,
);
const { data, isLoading, isFetching } = useEditorQueriesQuery(
{ editorId: `${queryEditorId}`, pageIndex },
{
skip: !isFeatureEnabled(FeatureFlag.SqllabBackendPersistence),
},
);
const editorQueries = useMemo(
() =>
Object.values(queries).filter(
({ sqlEditorId }) => String(sqlEditorId) === String(queryEditorId),
),
[queries, queryEditorId],
data
? getEditorQueries(
omit(
queries,
data.result.map(({ id }) => id),
),
queryEditorId,
)
.concat(data.result)
.reverse()
: getEditorQueries(queries, queryEditorId),
[queries, data, queryEditorId],
);
const loadNext = useEffectEvent(() => {
setPageIndex(pageIndex + 1);
});
const loadedDataCount = data?.result.length || 0;
const totalCount = data?.count || 0;
useEffect(() => {
if (hasReachedBottom && loadedDataCount < totalCount) {
loadNext();
}
}, [hasReachedBottom, loadNext, loadedDataCount, totalCount]);
if (!editorQueries.length && isLoading) {
return <Skeleton active />;
}
return editorQueries.length > 0 ? (
<QueryTable
columns={[
'state',
'started',
'duration',
'progress',
'rows',
'sql',
'results',
'actions',
]}
queries={editorQueries}
displayLimit={displayLimit}
latestQueryId={latestQueryId}
/>
<>
<QueryTable
columns={[
'state',
'started',
'duration',
'progress',
'rows',
'sql',
'results',
'actions',
]}
queries={editorQueries}
displayLimit={displayLimit}
latestQueryId={latestQueryId}
/>
{data && loadedDataCount < totalCount && (
<div
ref={ref}
css={css`
position: relative;
top: -150px;
`}
/>
)}
{isFetching && <Skeleton active />}
</>
) : (
<StyledEmptyStateWrapper>
<EmptyStateMedium

View File

@@ -29,7 +29,7 @@ import { LOCALSTORAGE_MAX_QUERY_AGE_MS } from '../../constants';
const EXTRA_HEIGHT_RESULTS = 8; // we need extra height in RESULTS tab. because the height from props was calculated based on PREVIEW tab.
type Props = {
latestQueryId: string;
latestQueryId?: string;
height: number;
displayLimit: number;
defaultQueryLimit: number;

View File

@@ -123,6 +123,19 @@ test('should render offline when the state is offline', async () => {
expect(getByText(STATUS_OPTIONS.offline)).toBeVisible();
});
test('should render empty result state when latestQuery is empty', () => {
const { getAllByRole } = render(
<SouthPane {...mockedProps} latestQueryId={undefined} />,
{
useRedux: true,
initialState: mockState,
},
);
const resultPanel = getAllByRole('tabpanel')[0];
expect(resultPanel).toHaveTextContent('Run a query to display results');
});
test('should render tabs for table preview queries', () => {
const { getAllByRole } = render(<SouthPane {...mockedProps} />, {
useRedux: true,

View File

@@ -144,14 +144,12 @@ const SouthPane = ({
animated={false}
>
<Tabs.TabPane tab={t('Results')} key="Results">
{latestQueryId && (
<Results
height={innerTabContentHeight}
latestQueryId={latestQueryId}
displayLimit={displayLimit}
defaultQueryLimit={defaultQueryLimit}
/>
)}
<Results
height={innerTabContentHeight}
latestQueryId={latestQueryId}
displayLimit={displayLimit}
defaultQueryLimit={defaultQueryLimit}
/>
</Tabs.TabPane>
<Tabs.TabPane tab={t('Query history')} key="History">
<QueryHistory

View File

@@ -17,6 +17,7 @@
* under the License.
*/
import React from 'react';
import * as uiCore from '@superset-ui/core';
import { act } from 'react-dom/test-utils';
import { fireEvent, render, waitFor } from 'spec/helpers/testing-library';
import fetchMock from 'fetch-mock';
@@ -31,7 +32,7 @@ import {
import SqlEditorLeftBar from 'src/SqlLab/components/SqlEditorLeftBar';
import ResultSet from 'src/SqlLab/components/ResultSet';
import { api } from 'src/hooks/apiResources/queryApi';
import { getExtensionsRegistry } from '@superset-ui/core';
import { getExtensionsRegistry, FeatureFlag } from '@superset-ui/core';
import setupExtensions from 'src/setup/setupExtensions';
import type { Action, Middleware, Store } from 'redux';
import SqlEditor, { Props } from '.';
@@ -63,6 +64,7 @@ fetchMock.get('glob:*/api/v1/database/*/function_names/', {
});
fetchMock.get('glob:*/api/v1/database/*', { result: [] });
fetchMock.get('glob:*/api/v1/database/*/tables/*', { options: [] });
fetchMock.get('glob:*/tabstateview/*', defaultQueryEditor);
fetchMock.post('glob:*/sqllab/execute/*', { result: [] });
let store: Store;
@@ -291,4 +293,43 @@ describe('SqlEditor', () => {
await findByText('sqleditor.extension.form extension component'),
).toBeInTheDocument();
});
describe('with SqllabBackendPersistence enabled', () => {
let isFeatureEnabledMock: jest.MockInstance<
boolean,
[feature: FeatureFlag]
>;
beforeEach(() => {
isFeatureEnabledMock = jest
.spyOn(uiCore, 'isFeatureEnabled')
.mockImplementation(
featureFlag =>
featureFlag === uiCore.FeatureFlag.SqllabBackendPersistence,
);
});
afterEach(() => {
isFeatureEnabledMock.mockClear();
});
it('should render loading state when its Editor is not loaded', async () => {
const switchTabApi = `glob:*/tabstateview/${defaultQueryEditor.id}/activate`;
fetchMock.post(switchTabApi, {});
const { getByTestId } = setup(
{
...mockedProps,
queryEditor: {
...mockedProps.queryEditor,
loaded: false,
},
},
store,
);
const indicator = getByTestId('sqlEditor-loading');
expect(indicator).toBeInTheDocument();
await waitFor(() =>
expect(fetchMock.calls('glob:*/tabstateview/*').length).toBe(1),
);
expect(fetchMock.calls(switchTabApi).length).toBe(1);
});
});
});

View File

@@ -54,7 +54,7 @@ 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 } from 'src/components';
import { AntdDropdown, AntdSwitch, Skeleton } from 'src/components';
import { Input } from 'src/components/Input';
import { Menu } from 'src/components/Menu';
import Icons from 'src/components/Icons';
@@ -77,6 +77,7 @@ import {
setActiveSouthPaneTab,
updateSavedQuery,
formatQuery,
switchQueryEditor,
} from 'src/SqlLab/actions/sqlLab';
import {
STATE_TYPE_MAP,
@@ -494,6 +495,16 @@ const SqlEditor: React.FC<Props> = ({
}
});
const shouldLoadQueryEditor =
isFeatureEnabled(FeatureFlag.SqllabBackendPersistence) &&
!queryEditor.loaded;
const loadQueryEditor = useEffectEvent(() => {
if (shouldLoadQueryEditor) {
dispatch(switchQueryEditor(queryEditor, displayLimit));
}
});
useEffect(() => {
// We need to measure the height of the sql editor post render to figure the height of
// the south pane so it gets rendered properly
@@ -503,6 +514,7 @@ const SqlEditor: React.FC<Props> = ({
WINDOW_RESIZE_THROTTLE_MS,
);
if (isActive) {
loadQueryEditor();
window.addEventListener('resize', handleWindowResizeWithThrottle);
window.addEventListener('beforeunload', onBeforeUnload);
}
@@ -512,7 +524,7 @@ const SqlEditor: React.FC<Props> = ({
window.removeEventListener('beforeunload', onBeforeUnload);
};
// TODO: Remove useEffectEvent deps once https://github.com/facebook/react/pull/25881 is released
}, [onBeforeUnload, isActive]);
}, [onBeforeUnload, loadQueryEditor, isActive]);
useEffect(() => {
if (!database || isEmpty(database)) {
@@ -847,7 +859,17 @@ const SqlEditor: React.FC<Props> = ({
)}
</ResizableSidebar>
</CSSTransition>
{showEmptyState ? (
{shouldLoadQueryEditor ? (
<div
data-test="sqlEditor-loading"
css={css`
flex: 1;
padding: ${theme.gridUnit * 4}px;
`}
>
<Skeleton active />
</div>
) : showEmptyState ? (
<EmptyStateBig
image="vector.svg"
title={t('Select a database to write a query')}

View File

@@ -25,7 +25,6 @@ const apiData = {
common: DEFAULT_COMMON_BOOTSTRAP_DATA,
tab_state_ids: [],
databases: [],
queries: {},
user: {
userId: 1,
username: 'some name',
@@ -220,18 +219,20 @@ describe('getInitialState', () => {
}),
);
const latestQuery = {
...runningQuery,
id: 'latestPersisted',
startDttm: Number(startDttmInStr),
endDttm: Number(endDttmInStr),
};
const initializedQueries = getInitialState({
...apiData,
queries: {
backendPersisted: {
...runningQuery,
id: 'backendPersisted',
startDttm: startDttmInStr,
endDttm: endDttmInStr,
},
...apiDataWithTabState,
active_tab: {
...apiDataWithTabState.active_tab,
latest_query: latestQuery,
},
}).sqlLab.queries;
expect(initializedQueries.backendPersisted).toEqual(
expect(initializedQueries.latestPersisted).toEqual(
expect.objectContaining({
startDttm: Number(startDttmInStr),
endDttm: Number(endDttmInStr),

View File

@@ -57,7 +57,7 @@ export default function getInitialState({
version: LatestQueryEditorVersion,
loaded: true,
name: t('Untitled query'),
sql: 'SELECT *\nFROM\nWHERE',
sql: '',
latestQueryId: null,
autorun: false,
dbId: common.conf.SQLLAB_DEFAULT_DBID,
@@ -136,7 +136,12 @@ export default function getInitialState({
});
}
const queries = { ...queries_ };
const queries = {
...queries_,
...(activeTab?.latest_query && {
[activeTab.latest_query.id]: activeTab.latest_query,
}),
};
/**
* If the `SQLLAB_BACKEND_PERSISTENCE` feature flag is off, or if the user

View File

@@ -152,7 +152,10 @@ export default function sqlLabReducer(state = {}, action) {
newState = {
...newState,
tabHistory,
tabHistory:
tabHistory.length === 0 && newState.queryEditors.length > 0
? newState.queryEditors.slice(-1).map(qe => qe.id)
: tabHistory,
tables,
queries,
unsavedQueryEditor: {

View File

@@ -75,6 +75,25 @@ describe('sqlLabReducer', () => {
initialState.queryEditors.length,
);
});
it('should select the latest query editor when tabHistory is empty', () => {
const currentQE = newState.queryEditors[0];
newState = {
...initialState,
tabHistory: [initialState.queryEditors[0]],
};
const action = {
type: actions.REMOVE_QUERY_EDITOR,
queryEditor: currentQE,
};
newState = sqlLabReducer(newState, action);
expect(newState.queryEditors).toHaveLength(
initialState.queryEditors.length - 1,
);
expect(newState.queryEditors.map(qe => qe.id)).not.toContainEqual(
currentQE.id,
);
expect(newState.tabHistory).toEqual([initialState.queryEditors[2].id]);
});
it('should remove a query editor including unsaved changes', () => {
expect(newState.queryEditors).toHaveLength(
initialState.queryEditors.length + 1,

View File

@@ -17,7 +17,7 @@
* under the License.
*/
import { QueryFormData } from '@superset-ui/core';
import { ControlPanelConfig } from 'packages/superset-ui-chart-controls/src/types';
import { ControlPanelConfig } from '@superset-ui/chart-controls';
import { DiffType, RowType } from './index';
export const defaultProps: Record<string, Partial<QueryFormData>> = {

View File

@@ -179,7 +179,7 @@ class AlteredSliceTag extends React.Component<
return '[]';
}
return value
.map(v => {
.map((v: FilterItemType) => {
const filterVal =
v.comparator && v.comparator.constructor === Array
? `[${v.comparator.join(', ')}]`
@@ -198,14 +198,14 @@ class AlteredSliceTag extends React.Component<
return value.map(v => safeStringify(v)).join(', ');
}
if (controlsMap[key]?.type === 'MetricsControl' && Array.isArray(value)) {
const formattedValue = value.map(v => v?.label ?? v);
const formattedValue = value.map((v: FilterItemType) => v?.label ?? v);
return formattedValue.length ? formattedValue.join(', ') : '[]';
}
if (typeof value === 'boolean') {
return value ? 'true' : 'false';
}
if (Array.isArray(value)) {
const formattedValue = value.map(v => v?.label ?? v);
const formattedValue = value.map((v: FilterItemType) => v?.label ?? v);
return formattedValue.length ? formattedValue.join(', ') : '[]';
}
if (typeof value === 'string' || typeof value === 'number') {

View File

@@ -24,11 +24,15 @@ import {
TextMode as OrigTextMode,
} from 'brace';
import AceEditor, { IAceEditorProps } from 'react-ace';
import { config } from 'ace-builds';
import { acequire } from 'ace-builds/src-noconflict/ace';
import AsyncEsmComponent, {
PlaceholderProps,
} from 'src/components/AsyncEsmComponent';
import useEffectEvent from 'src/hooks/useEffectEvent';
import cssWorkerUrl from 'ace-builds/src-noconflict/worker-css';
config.setModuleUrl('ace/mode/css_worker', cssWorkerUrl);
export interface AceCompleterKeywordData {
name: string;

View File

@@ -229,6 +229,32 @@ test('Should database select display options', async () => {
expect(await screen.findByText('test-mysql')).toBeInTheDocument();
});
test('Should fetch the search keyword when total count exceeds initial options', async () => {
fetchMock.get(
databaseApiRoute,
{
...fakeDatabaseApiResult,
count: fakeDatabaseApiResult.result.length + 1,
},
{ overwriteRoutes: true },
);
const props = createProps();
render(<DatabaseSelector {...props} />, { useRedux: true, store });
const select = screen.getByRole('combobox', {
name: 'Select database or type to search databases',
});
await waitFor(() =>
expect(fetchMock.calls(databaseApiRoute)).toHaveLength(1),
);
expect(select).toBeInTheDocument();
userEvent.type(select, 'keywordtest');
await waitFor(() =>
expect(fetchMock.calls(databaseApiRoute)).toHaveLength(2),
);
expect(fetchMock.calls(databaseApiRoute)[1][0]).toContain('keywordtest');
});
test('should show empty state if there are no options', async () => {
fetchMock.reset();
fetchMock.get(databaseApiRoute, { result: [] });

View File

@@ -167,7 +167,7 @@ export default function DatabaseSelector({
});
const endpoint = `/api/v1/database/?q=${queryParams}`;
return SupersetClient.get({ endpoint }).then(({ json }) => {
const { result } = json;
const { result, count } = json;
if (getDbList) {
getDbList(result);
}
@@ -189,7 +189,7 @@ export default function DatabaseSelector({
return {
data: options,
totalCount: options.length,
totalCount: count ?? options.length,
};
});
},

View File

@@ -21,7 +21,7 @@ import { styled, t } from '@superset-ui/core';
import { Select } from 'src/components';
import { FormLabel } from 'src/components/Form';
import { SELECT_WIDTH } from './utils';
import { CardSortSelectOption, FetchDataConfig, SortColumn } from './types';
import { CardSortSelectOption, SortColumn } from './types';
const SortContainer = styled.div`
display: inline-flex;
@@ -32,22 +32,22 @@ const SortContainer = styled.div`
`;
interface CardViewSelectSortProps {
onChange: (conf: FetchDataConfig) => any;
onChange: (value: SortColumn[]) => void;
options: Array<CardSortSelectOption>;
initialSort?: SortColumn[];
pageIndex: number;
pageSize: number;
}
export const CardSortSelect = ({
initialSort,
onChange,
options,
pageIndex,
pageSize,
}: CardViewSelectSortProps) => {
const defaultSort =
(initialSort && options.find(({ id }) => id === initialSort[0].id)) ||
(initialSort &&
options.find(
({ id, desc }) =>
id === initialSort[0].id && desc === initialSort[0].desc,
)) ||
options[0];
const [value, setValue] = useState({
@@ -72,7 +72,7 @@ export const CardSortSelect = ({
desc: originalOption.desc,
},
];
onChange({ pageIndex, pageSize, sortBy, filters: [] });
onChange(sortBy);
}
};
@@ -82,7 +82,7 @@ export const CardSortSelect = ({
ariaLabel={t('Sort')}
header={<FormLabel>{t('Sort')}</FormLabel>}
labelInValue
onChange={(value: CardSortSelectOption) => handleOnChange(value)}
onChange={handleOnChange}
options={formattedOptions}
showSearch
value={value}

View File

@@ -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 React from 'react';
import { render, waitFor } from 'spec/helpers/testing-library';
import ListView from './ListView';
const mockedProps = {
title: 'Data Table',
columns: [
{
accessor: 'id',
Header: 'ID',
sortable: true,
},
{
accessor: 'age',
Header: 'Age',
},
{
accessor: 'name',
Header: 'Name',
},
{
accessor: 'time',
Header: 'Time',
},
],
data: [
{ id: 1, name: 'data 1', age: 10, time: '2020-11-18T07:53:45.354Z' },
{ id: 2, name: 'data 2', age: 1, time: '2020-11-18T07:53:45.354Z' },
],
count: 2,
pageSize: 1,
loading: false,
refreshData: jest.fn(),
addSuccessToast: jest.fn(),
addDangerToast: jest.fn(),
};
test('redirects to first page when page index is invalid', async () => {
const fetchData = jest.fn();
window.history.pushState({}, '', '/?pageIndex=9');
render(<ListView {...mockedProps} fetchData={fetchData} />, {
useRouter: true,
useQueryParams: true,
});
await waitFor(() => {
expect(window.location.search).toEqual('?pageIndex=0');
expect(fetchData).toBeCalledTimes(2);
expect(fetchData).toHaveBeenCalledWith(
expect.objectContaining({ pageIndex: 9 }),
);
expect(fetchData).toHaveBeenCalledWith(
expect.objectContaining({ pageIndex: 0 }),
);
});
fetchData.mockClear();
});

View File

@@ -271,10 +271,11 @@ function ListView<T extends object = any>({
pageCount = 1,
gotoPage,
applyFilterValue,
setSortBy,
selectedFlatRows,
toggleAllRowsSelected,
setViewMode,
state: { pageIndex, pageSize, internalFilters, viewMode },
state: { pageIndex, pageSize, internalFilters, sortBy, viewMode },
query,
} = useListViewState({
bulkSelectColumnConfig,
@@ -321,6 +322,12 @@ function ListView<T extends object = any>({
if (!bulkSelectEnabled) toggleAllRowsSelected(false);
}, [bulkSelectEnabled, toggleAllRowsSelected]);
useEffect(() => {
if (!loading && pageIndex > pageCount - 1 && pageCount > 0) {
gotoPage(0);
}
}, [gotoPage, loading, pageCount, pageIndex]);
return (
<ListViewStyles>
{allowBulkTagActions && (
@@ -350,11 +357,9 @@ function ListView<T extends object = any>({
)}
{viewMode === 'card' && cardSortSelectOptions && (
<CardSortSelect
initialSort={initialSort}
onChange={fetchData}
initialSort={sortBy}
onChange={(value: SortColumn[]) => setSortBy(value)}
options={cardSortSelectOptions}
pageIndex={pageIndex}
pageSize={pageSize}
/>
)}
</div>
@@ -464,7 +469,7 @@ function ListView<T extends object = any>({
<div className="pagination-container">
<Pagination
totalPages={pageCount || 0}
currentPage={pageCount ? pageIndex + 1 : 0}
currentPage={pageCount && pageIndex < pageCount ? pageIndex + 1 : 0}
onChange={(p: number) => gotoPage(p - 1)}
hideFirstAndLastPageLinks
/>

View File

@@ -23,8 +23,6 @@ export interface SortColumn {
desc?: boolean;
}
export type SortColumns = SortColumn[];
export interface SelectOption {
label: string;
value: any;
@@ -84,7 +82,7 @@ export interface FilterValue {
export interface FetchDataConfig {
pageIndex: number;
pageSize: number;
sortBy: SortColumns;
sortBy: SortColumn[];
filters: FilterValue[];
}

View File

@@ -220,7 +220,7 @@ export function useListViewState({
query.sortColumn && query.sortOrder
? [{ id: query.sortColumn, desc: query.sortOrder === 'desc' }]
: initialSort,
[query.sortColumn, query.sortOrder],
[initialSort, query.sortColumn, query.sortOrder],
);
const initialState = {
@@ -256,6 +256,7 @@ export function useListViewState({
pageCount,
gotoPage,
setAllFilters,
setSortBy,
selectedFlatRows,
toggleAllRowsSelected,
state: { pageIndex, pageSize, sortBy, filters },
@@ -373,6 +374,7 @@ export function useListViewState({
rows,
selectedFlatRows,
setAllFilters,
setSortBy,
state: { pageIndex, pageSize, sortBy, filters, internalFilters, viewMode },
toggleAllRowsSelected,
applyFilterValue,

View File

@@ -939,6 +939,18 @@ test('pasting an existing option does not duplicate it in multiple mode', async
expect(await findAllSelectOptions()).toHaveLength(4);
});
test('does not fire onChange if the same value is selected in single mode', async () => {
const onChange = jest.fn();
render(<AsyncSelect {...defaultProps} onChange={onChange} />);
const optionText = 'Emma';
await open();
expect(onChange).toHaveBeenCalledTimes(0);
userEvent.click(await findSelectOption(optionText));
expect(onChange).toHaveBeenCalledTimes(1);
userEvent.click(await findSelectOption(optionText));
expect(onChange).toHaveBeenCalledTimes(1);
});
/*
TODO: Add tests that require scroll interaction. Needs further investigation.
- Fetches more data when scrolling and more data is available

View File

@@ -50,10 +50,12 @@ import {
mapOptions,
getOption,
isObject,
isEqual as utilsIsEqual,
} from './utils';
import {
AsyncSelectProps,
AsyncSelectRef,
RawValue,
SelectOptionsPagePromise,
SelectOptionsType,
SelectOptionsTypePage,
@@ -220,7 +222,16 @@ const AsyncSelect = forwardRef(
const handleOnSelect: SelectProps['onSelect'] = (selectedItem, option) => {
if (isSingleMode) {
// on select is fired in single value mode if the same value is selected
const valueChanged = !utilsIsEqual(
selectedItem,
selectValue as RawValue | AntdLabeledValue,
'value',
);
setSelectValue(selectedItem);
if (valueChanged) {
fireOnChange();
}
} else {
setSelectValue(previousState => {
const array = ensureIsArray(previousState);
@@ -234,8 +245,8 @@ const AsyncSelect = forwardRef(
}
return previousState;
});
fireOnChange();
}
fireOnChange();
onSelect?.(selectedItem, option);
};

View File

@@ -1053,6 +1053,18 @@ test('pasting an existing option does not duplicate it in multiple mode', async
expect(await findAllSelectOptions()).toHaveLength(4);
});
test('does not fire onChange if the same value is selected in single mode', async () => {
const onChange = jest.fn();
render(<Select {...defaultProps} onChange={onChange} />);
const optionText = 'Emma';
await open();
expect(onChange).toHaveBeenCalledTimes(0);
userEvent.click(await findSelectOption(optionText));
expect(onChange).toHaveBeenCalledTimes(1);
userEvent.click(await findSelectOption(optionText));
expect(onChange).toHaveBeenCalledTimes(1);
});
/*
TODO: Add tests that require scroll interaction. Needs further investigation.
- Fetches more data when scrolling and more data is available

View File

@@ -53,6 +53,7 @@ import {
hasCustomLabels,
getOption,
isObject,
isEqual as utilsIsEqual,
} from './utils';
import { RawValue, SelectOptionsType, SelectProps } from './types';
import {
@@ -227,7 +228,16 @@ const Select = forwardRef(
const handleOnSelect: SelectProps['onSelect'] = (selectedItem, option) => {
if (isSingleMode) {
// on select is fired in single value mode if the same value is selected
const valueChanged = !utilsIsEqual(
selectedItem,
selectValue as RawValue | AntdLabeledValue,
'value',
);
setSelectValue(selectedItem);
if (valueChanged) {
fireOnChange();
}
} else {
setSelectValue(previousState => {
const array = ensureIsArray(previousState);
@@ -259,8 +269,8 @@ const Select = forwardRef(
}
return previousState;
});
fireOnChange();
}
fireOnChange();
onSelect?.(selectedItem, option);
};

View File

@@ -49,22 +49,24 @@ export function getValue(
return isLabeledValue(option) ? option.value : option;
}
export function isEqual(a: V | LabeledValue, b: V | LabeledValue, key: string) {
const actualA = isObject(a) && key in a ? a[key] : a;
const actualB = isObject(b) && key in b ? b[key] : b;
// When comparing the values we use the equality
// operator to automatically convert different types
// eslint-disable-next-line eqeqeq
return actualA == actualB;
}
export function getOption(
value: V,
options?: V | LabeledValue | (V | LabeledValue)[],
checkLabel = false,
): V | LabeledValue {
const optionsArray = ensureIsArray(options);
// When comparing the values we use the equality
// operator to automatically convert different types
return optionsArray.find(
x =>
// eslint-disable-next-line eqeqeq
x == value ||
(isObject(x) &&
// eslint-disable-next-line eqeqeq
(('value' in x && x.value == value) ||
(checkLabel && 'label' in x && x.label === value))),
isEqual(x, value, 'value') || (checkLabel && isEqual(x, value, 'label')),
);
}

View File

@@ -47,6 +47,7 @@ const TelemetryPixel = ({
const pixelPath = `https://apachesuperset.gateway.scarf.sh/pixel/${PIXEL_ID}/${version}/${sha}/${build}`;
return process.env.SCARF_ANALYTICS === 'false' ? null : (
<img
// @ts-ignore
referrerPolicy="no-referrer-when-downgrade"
src={pixelPath}
width={0}

View File

@@ -189,3 +189,11 @@ export const DEFAULT_COMMON_BOOTSTRAP_DATA: CommonBootstrapData = {
export const DEFAULT_BOOTSTRAP_DATA: BootstrapData = {
common: DEFAULT_COMMON_BOOTSTRAP_DATA,
};
export enum FilterPlugins {
Select = 'filter_select',
Range = 'filter_range',
Time = 'filter_time',
TimeColumn = 'filter_timecolumn',
TimeGrain = 'filter_timegrain',
}

View File

@@ -21,6 +21,7 @@ import { render, screen, waitFor } from 'spec/helpers/testing-library';
import { CssEditor as AceCssEditor } from 'src/components/AsyncAceEditor';
import { IAceEditorProps } from 'react-ace';
import userEvent from '@testing-library/user-event';
import fetchMock from 'fetch-mock';
import CssEditor from '.';
jest.mock('src/components/AsyncAceEditor', () => ({
@@ -33,46 +34,59 @@ jest.mock('src/components/AsyncAceEditor', () => ({
}));
const templates = [
{ label: 'Template A', css: 'background-color: red;' },
{ label: 'Template B', css: 'background-color: blue;' },
{ label: 'Template C', css: 'background-color: yellow;' },
{ template_name: 'Template A', css: 'background-color: red;' },
{ template_name: 'Template B', css: 'background-color: blue;' },
{ template_name: 'Template C', css: 'background-color: yellow;' },
];
fetchMock.get('glob:*/csstemplateasyncmodelview/api/read', {
result: templates,
});
AceCssEditor.preload = () => new Promise(() => {});
test('renders with default props', () => {
render(<CssEditor triggerNode={<>Click</>} />);
const defaultProps = {
triggerNode: <>Click</>,
addDangerToast: jest.fn(),
};
test('renders with default props', async () => {
await waitFor(() => render(<CssEditor {...defaultProps} />));
expect(screen.getByRole('button', { name: 'Click' })).toBeInTheDocument();
});
test('renders with initial CSS', () => {
test('renders with initial CSS', async () => {
const initialCss = 'margin: 10px;';
render(<CssEditor triggerNode={<>Click</>} initialCss={initialCss} />);
await waitFor(() =>
render(<CssEditor {...defaultProps} initialCss={initialCss} />),
);
userEvent.click(screen.getByRole('button', { name: 'Click' }));
expect(screen.getByText(initialCss)).toBeInTheDocument();
});
test('renders with templates', async () => {
render(<CssEditor triggerNode={<>Click</>} templates={templates} />);
await waitFor(() => render(<CssEditor {...defaultProps} />));
userEvent.click(screen.getByRole('button', { name: 'Click' }));
userEvent.hover(screen.getByText('Load a CSS template'));
await waitFor(() => {
templates.forEach(template =>
expect(screen.getByText(template.label)).toBeInTheDocument(),
expect(screen.getByText(template.template_name)).toBeInTheDocument(),
);
});
});
test('triggers onChange when using the editor', () => {
test('triggers onChange when using the editor', async () => {
const onChange = jest.fn();
const initialCss = 'margin: 10px;';
const additionalCss = 'color: red;';
render(
<CssEditor
triggerNode={<>Click</>}
initialCss={initialCss}
onChange={onChange}
/>,
await waitFor(() =>
render(
<CssEditor
{...defaultProps}
initialCss={initialCss}
onChange={onChange}
/>,
),
);
userEvent.click(screen.getByRole('button', { name: 'Click' }));
expect(onChange).not.toHaveBeenCalled();
@@ -82,12 +96,8 @@ test('triggers onChange when using the editor', () => {
test('triggers onChange when selecting a template', async () => {
const onChange = jest.fn();
render(
<CssEditor
triggerNode={<>Click</>}
templates={templates}
onChange={onChange}
/>,
await waitFor(() =>
render(<CssEditor {...defaultProps} onChange={onChange} />),
);
userEvent.click(screen.getByRole('button', { name: 'Click' }));
userEvent.click(screen.getByText('Load a CSS template'));

View File

@@ -21,7 +21,7 @@ import PropTypes from 'prop-types';
import { AntdDropdown } from 'src/components';
import { Menu } from 'src/components/Menu';
import Button from 'src/components/Button';
import { t, styled } from '@superset-ui/core';
import { t, styled, SupersetClient } from '@superset-ui/core';
import ModalTrigger from 'src/components/ModalTrigger';
import { CssEditor as AceCssEditor } from 'src/components/AsyncAceEditor';
@@ -47,7 +47,7 @@ const propTypes = {
initialCss: PropTypes.string,
triggerNode: PropTypes.node.isRequired,
onChange: PropTypes.func,
templates: PropTypes.array,
addDangerToast: PropTypes.func.isRequired,
};
const defaultProps = {
@@ -60,6 +60,7 @@ class CssEditor extends React.PureComponent {
super(props);
this.state = {
css: props.initialCss,
templates: [],
};
this.changeCss = this.changeCss.bind(this);
this.changeCssTemplate = this.changeCssTemplate.bind(this);
@@ -67,6 +68,22 @@ class CssEditor extends React.PureComponent {
componentDidMount() {
AceCssEditor.preload();
SupersetClient.get({ endpoint: '/csstemplateasyncmodelview/api/read' })
.then(({ json }) => {
const templates = json.result.map(row => ({
value: row.template_name,
css: row.css,
label: row.template_name,
}));
this.setState({ templates });
})
.catch(() => {
this.props.addDangerToast(
t('An error occurred while fetching available CSS templates'),
);
});
}
changeCss(css) {
@@ -80,10 +97,10 @@ class CssEditor extends React.PureComponent {
}
renderTemplateSelector() {
if (this.props.templates) {
if (this.state.templates) {
const menu = (
<Menu onClick={this.changeCssTemplate}>
{this.props.templates.map(template => (
{this.state.templates.map(template => (
<Menu.Item key={template.css}>{template.label}</Menu.Item>
))}
</Menu>

View File

@@ -44,7 +44,7 @@ import BuilderComponentPane from 'src/dashboard/components/BuilderComponentPane'
import DashboardHeader from 'src/dashboard/containers/DashboardHeader';
import Icons from 'src/components/Icons';
import IconButton from 'src/dashboard/components/IconButton';
import DragDroppable from 'src/dashboard/components/dnd/DragDroppable';
import { Droppable } from 'src/dashboard/components/dnd/DragDroppable';
import DashboardComponent from 'src/dashboard/containers/DashboardComponent';
import WithPopoverMenu from 'src/dashboard/components/menu/WithPopoverMenu';
import getDirectPathToTabIndex from 'src/dashboard/util/getDirectPathToTabIndex';
@@ -81,6 +81,7 @@ import {
MAIN_HEADER_HEIGHT,
OPEN_FILTER_BAR_MAX_WIDTH,
OPEN_FILTER_BAR_WIDTH,
EMPTY_CONTAINER_Z_INDEX,
} from 'src/dashboard/constants';
import { getRootLevelTabsComponent, shouldFocusTabs } from './utils';
import DashboardContainer from './DashboardContainer';
@@ -107,12 +108,27 @@ const StickyPanel = styled.div<{ width: number }>`
// @z-index-above-dashboard-popovers (99) + 1 = 100
const StyledHeader = styled.div`
grid-column: 2;
grid-row: 1;
position: sticky;
top: 0;
z-index: 100;
max-width: 100vw;
${({ theme }) => css`
grid-column: 2;
grid-row: 1;
position: sticky;
top: 0;
z-index: 100;
max-width: 100vw;
.empty-droptarget:before {
position: absolute;
content: '';
display: none;
width: calc(100% - ${theme.gridUnit * 2}px);
height: calc(100% - ${theme.gridUnit * 2}px);
left: ${theme.gridUnit}px;
top: ${theme.gridUnit}px;
border: 1px dashed transparent;
border-radius: ${theme.gridUnit}px;
opacity: 0.5;
}
`}
`;
const StyledContent = styled.div<{
@@ -211,13 +227,9 @@ const DashboardContentWrapper = styled.div`
/* provide hit area in case row contents is edge to edge */
.dashboard-component-tabs-content {
.dragdroppable-row {
> .dragdroppable-row {
padding-top: ${theme.gridUnit * 4}px;
}
& > div:not(:last-child):not(.empty-droptarget) {
margin-bottom: ${theme.gridUnit * 4}px;
}
}
.dashboard-component-chart-holder {
@@ -250,25 +262,21 @@ const DashboardContentWrapper = styled.div`
}
& > .empty-droptarget {
z-index: ${EMPTY_CONTAINER_Z_INDEX};
position: absolute;
width: 100%;
}
& > .empty-droptarget:first-child:not(.empty-droptarget--full) {
height: ${theme.gridUnit * 4}px;
top: -2px;
z-index: 10;
top: 0;
}
& > .empty-droptarget:last-child {
height: ${theme.gridUnit * 3}px;
bottom: 0;
height: ${theme.gridUnit * 4}px;
bottom: ${-theme.gridUnit * 4}px;
}
}
.empty-droptarget:first-child .drop-indicator--bottom {
top: ${theme.gridUnit * 6}px;
}
`}
`;
@@ -616,8 +624,9 @@ const DashboardBuilder: FC<DashboardBuilderProps> = () => {
)}
<StyledHeader ref={headerRef}>
{/* @ts-ignore */}
<DragDroppable
<Droppable
data-test="top-level-tabs"
className={cx(!topLevelTabs && editMode && 'empty-droptarget')}
component={dashboardRoot}
parentComponent={null}
depth={DASHBOARD_ROOT_DEPTH}
@@ -630,7 +639,7 @@ const DashboardBuilder: FC<DashboardBuilderProps> = () => {
style={draggableStyle}
>
{renderDraggableContent}
</DragDroppable>
</Droppable>
</StyledHeader>
<StyledContent fullSizeChartId={fullSizeChartId}>
<Global

View File

@@ -17,11 +17,19 @@
* under the License.
*/
import React from 'react';
import { fireEvent, render } from 'spec/helpers/testing-library';
import { fireEvent, render, waitFor } from 'spec/helpers/testing-library';
import { OptionControlLabel } from 'src/explore/components/controls/OptionControls';
import DashboardWrapper from './DashboardWrapper';
beforeAll(() => {
jest.useFakeTimers();
});
afterAll(() => {
jest.useRealTimers();
});
test('should render children', () => {
const { getByTestId } = render(
<DashboardWrapper>
@@ -32,7 +40,7 @@ test('should render children', () => {
expect(getByTestId('mock-children')).toBeInTheDocument();
});
test('should update the style on dragging state', () => {
test('should update the style on dragging state', async () => {
const defaultProps = {
label: <span>Test label</span>,
tooltipTitle: 'This is a tooltip title',
@@ -69,7 +77,13 @@ test('should update the style on dragging state', () => {
container.getElementsByClassName('dragdroppable--dragging'),
).toHaveLength(0);
fireEvent.dragStart(getByText('Label 1'));
await waitFor(() => jest.runAllTimers());
expect(
container.getElementsByClassName('dragdroppable--dragging'),
).toHaveLength(1);
fireEvent.dragEnd(getByText('Label 1'));
// immediately discards dragging state after dragEnd
expect(
container.getElementsByClassName('dragdroppable--dragging'),
).toHaveLength(0);
});

View File

@@ -17,11 +17,12 @@
* under the License.
*/
import React, { useEffect } from 'react';
import { css, styled } from '@superset-ui/core';
import { FAST_DEBOUNCE, css, styled } from '@superset-ui/core';
import { RootState } from 'src/dashboard/types';
import { useSelector } from 'react-redux';
import { useDragDropManager } from 'react-dnd';
import classNames from 'classnames';
import { debounce } from 'lodash';
const StyledDiv = styled.div`
${({ theme }) => css`
@@ -32,10 +33,20 @@ const StyledDiv = styled.div`
flex: 1;
/* Special cases */
&.dragdroppable--dragging
.dashboard-component-tabs-content
> .empty-droptarget.empty-droptarget--full {
height: 100%;
&.dragdroppable--dragging {
&
.dashboard-component-tabs-content
> .empty-droptarget.empty-droptarget--full {
height: 100%;
}
& .empty-droptarget:before {
display: block;
border-color: ${theme.colors.primary.light1};
background-color: ${theme.colors.primary.light3};
}
& .grid-row:after {
border-style: hidden;
}
}
/* A row within a column has inset hover menu */
@@ -106,12 +117,22 @@ const DashboardWrapper: React.FC<Props> = ({ children }) => {
useEffect(() => {
const monitor = dragDropManager.getMonitor();
const debouncedSetIsDragged = debounce(setIsDragged, FAST_DEBOUNCE);
const unsub = monitor.subscribeToStateChange(() => {
setIsDragged(monitor.isDragging());
const isDragging = monitor.isDragging();
if (isDragging) {
// set a debounced function to prevent HTML5 drag source
// from interfering with the drop zone highlighting
debouncedSetIsDragged(true);
} else {
debouncedSetIsDragged.cancel();
setIsDragged(false);
}
});
return () => {
unsub();
debouncedSetIsDragged.cancel();
};
}, [dragDropManager]);

View File

@@ -23,7 +23,7 @@ import { addAlpha, css, styled, t } from '@superset-ui/core';
import { EmptyStateBig } from 'src/components/EmptyState';
import { componentShape } from '../util/propShapes';
import DashboardComponent from '../containers/DashboardComponent';
import DragDroppable from './dnd/DragDroppable';
import { Droppable } from './dnd/DragDroppable';
import { GRID_GUTTER_SIZE, GRID_COLUMN_COUNT } from '../util/constants';
import { TAB_TYPE } from '../util/componentTypes';
@@ -41,15 +41,8 @@ const propTypes = {
const defaultProps = {};
const renderDraggableContentBottom = dropProps =>
dropProps.dropIndicatorProps && (
<div className="drop-indicator drop-indicator--bottom" />
);
const renderDraggableContentTop = dropProps =>
dropProps.dropIndicatorProps && (
<div className="drop-indicator drop-indicator--top" />
);
const renderDraggableContent = dropProps =>
dropProps.dropIndicatorProps && <div {...dropProps.dropIndicatorProps} />;
const DashboardEmptyStateContainer = styled.div`
position: absolute;
@@ -60,28 +53,42 @@ const DashboardEmptyStateContainer = styled.div`
`;
const GridContent = styled.div`
${({ theme }) => css`
${({ theme, editMode }) => css`
display: flex;
flex-direction: column;
/* gutters between rows */
& > div:not(:last-child):not(.empty-droptarget) {
margin-bottom: ${theme.gridUnit * 4}px;
${!editMode && `margin-bottom: ${theme.gridUnit * 4}px`};
}
& > .empty-droptarget {
.empty-droptarget {
width: 100%;
height: 100%;
height: ${theme.gridUnit * 4}px;
display: flex;
align-items: center;
justify-content: center;
border-radius: ${theme.gridUnit}px;
overflow: hidden;
&:before {
content: '';
display: block;
width: calc(100% - ${theme.gridUnit * 2}px);
height: calc(100% - ${theme.gridUnit * 2}px);
border: 1px dashed transparent;
border-radius: ${theme.gridUnit}px;
opacity: 0.5;
}
}
& > .empty-droptarget:first-child {
height: ${theme.gridUnit * 12}px;
margin-top: ${theme.gridUnit * -6}px;
height: ${theme.gridUnit * 4}px;
margin-top: ${theme.gridUnit * -4}px;
}
& > .empty-droptarget:last-child {
height: ${theme.gridUnit * 12}px;
margin-top: ${theme.gridUnit * -6}px;
height: ${theme.gridUnit * 24}px;
}
& > .empty-droptarget.empty-droptarget--full:only-child {
@@ -265,10 +272,14 @@ class DashboardGrid extends React.PureComponent {
</DashboardEmptyStateContainer>
)}
<div className="dashboard-grid" ref={this.setGridRef}>
<GridContent className="grid-content" data-test="grid-content">
<GridContent
className="grid-content"
data-test="grid-content"
editMode={editMode}
>
{/* make the area above components droppable */}
{editMode && (
<DragDroppable
<Droppable
component={gridComponent}
depth={depth}
parentComponent={null}
@@ -281,41 +292,43 @@ class DashboardGrid extends React.PureComponent {
gridComponent?.children?.length === 0,
})}
editMode
dropToChild={gridComponent?.children?.length === 0}
>
{renderDraggableContentTop}
</DragDroppable>
{renderDraggableContent}
</Droppable>
)}
{gridComponent?.children?.map((id, index) => (
<DashboardComponent
key={id}
id={id}
parentId={gridComponent.id}
depth={depth + 1}
index={index}
availableColumnCount={GRID_COLUMN_COUNT}
columnWidth={columnWidth}
isComponentVisible={isComponentVisible}
onResizeStart={this.handleResizeStart}
onResize={this.handleResize}
onResizeStop={this.handleResizeStop}
onChangeTab={this.handleChangeTab}
/>
<React.Fragment key={id}>
<DashboardComponent
id={id}
parentId={gridComponent.id}
depth={depth + 1}
index={index}
availableColumnCount={GRID_COLUMN_COUNT}
columnWidth={columnWidth}
isComponentVisible={isComponentVisible}
onResizeStart={this.handleResizeStart}
onResize={this.handleResize}
onResizeStop={this.handleResizeStop}
onChangeTab={this.handleChangeTab}
/>
{/* make the area below components droppable */}
{editMode && (
<Droppable
component={gridComponent}
depth={depth}
parentComponent={null}
index={index + 1}
orientation="column"
onDrop={handleComponentDrop}
className="empty-droptarget"
editMode
>
{renderDraggableContent}
</Droppable>
)}
</React.Fragment>
))}
{/* make the area below components droppable */}
{editMode && gridComponent?.children?.length > 0 && (
<DragDroppable
component={gridComponent}
depth={depth}
parentComponent={null}
index={gridComponent.children.length}
orientation="column"
onDrop={handleComponentDrop}
className="empty-droptarget"
editMode
>
{renderDraggableContentBottom}
</DragDroppable>
)}
{isResizing &&
Array(GRID_COLUMN_COUNT)
.fill(null)

View File

@@ -19,7 +19,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import { isEmpty } from 'lodash';
import { SupersetClient, t } from '@superset-ui/core';
import { t } from '@superset-ui/core';
import { Menu } from 'src/components/Menu';
import { URL_PARAMS } from 'src/constants';
import ShareMenuItems from 'src/dashboard/components/menu/ShareMenuItems';
@@ -99,7 +99,6 @@ class HeaderActionsDropdown extends React.PureComponent {
super(props);
this.state = {
css: props.customCss,
cssTemplates: [],
showReportSubMenu: null,
};
@@ -109,23 +108,6 @@ class HeaderActionsDropdown extends React.PureComponent {
this.setShowReportSubMenu = this.setShowReportSubMenu.bind(this);
}
UNSAFE_componentWillMount() {
SupersetClient.get({ endpoint: '/csstemplateasyncmodelview/api/read' })
.then(({ json }) => {
const cssTemplates = json.result.map(row => ({
value: row.template_name,
css: row.css,
label: row.template_name,
}));
this.setState({ cssTemplates });
})
.catch(() => {
this.props.addDangerToast(
t('An error occurred while fetching available CSS templates'),
);
});
}
UNSAFE_componentWillReceiveProps(nextProps) {
if (this.props.customCss !== nextProps.customCss) {
this.setState({ css: nextProps.customCss }, () => {
@@ -257,8 +239,8 @@ class HeaderActionsDropdown extends React.PureComponent {
<CssEditor
triggerNode={<span>{t('Edit CSS')}</span>}
initialCss={this.state.css}
templates={this.state.cssTemplates}
onChange={this.changeCss}
addDangerToast={addDangerToast}
/>
</Menu.Item>
)}

View File

@@ -25,12 +25,7 @@ import { css, styled } from '@superset-ui/core';
import { componentShape } from '../../util/propShapes';
import { dragConfig, dropConfig } from './dragDroppableConfig';
import {
DROP_TOP,
DROP_RIGHT,
DROP_BOTTOM,
DROP_LEFT,
} from '../../util/getDropPosition';
import { DROP_FORBIDDEN } from '../../util/getDropPosition';
const propTypes = {
children: PropTypes.func,
@@ -39,6 +34,7 @@ const propTypes = {
parentComponent: componentShape,
depth: PropTypes.number.isRequired,
disableDragDrop: PropTypes.bool,
dropToChild: PropTypes.bool,
orientation: PropTypes.oneOf(['row', 'column']),
index: PropTypes.number.isRequired,
style: PropTypes.object,
@@ -61,6 +57,7 @@ const defaultProps = {
style: null,
parentComponent: null,
disableDragDrop: false,
dropToChild: false,
children() {},
onDrop() {},
onHover() {},
@@ -77,6 +74,14 @@ const defaultProps = {
const DragDroppableStyles = styled.div`
${({ theme }) => css`
position: relative;
/*
Next line is a workaround for a bug in react-dnd where the drag
preview expands outside of the bounds of the drag source card, see:
https://github.com/react-dnd/react-dnd/issues/832#issuecomment-442071628
*/
&.dragdroppable--edit-mode {
transform: translate3d(0, 0, 0);
}
&.dragdroppable--dragging {
opacity: 0.2;
@@ -90,49 +95,18 @@ const DragDroppableStyles = styled.div`
z-index: 10;
}
&.empty-droptarget--full > .drop-indicator--top {
height: 100%;
opacity: 0.3;
}
& {
.drop-indicator {
display: block;
background-color: ${theme.colors.primary.base};
position: absolute;
z-index: 10;
}
.drop-indicator--top {
top: ${-theme.gridUnit - 2}px;
left: 0;
height: ${theme.gridUnit}px;
opacity: 0.3;
width: 100%;
min-width: ${theme.gridUnit * 4}px;
}
.drop-indicator--bottom {
bottom: ${-theme.gridUnit - 2}px;
left: 0;
height: ${theme.gridUnit}px;
width: 100%;
min-width: ${theme.gridUnit * 4}px;
}
.drop-indicator--right {
top: 0;
left: calc(100% - ${theme.gridUnit}px);
height: 100%;
width: ${theme.gridUnit}px;
min-height: ${theme.gridUnit * 4}px;
}
.drop-indicator--left {
top: 0;
left: 0;
height: 100%;
width: ${theme.gridUnit}px;
min-height: ${theme.gridUnit * 4}px;
&.drop-indicator--forbidden {
background-color: ${theme.colors.error.light1};
}
}
}
`};
@@ -189,10 +163,7 @@ export class UnwrappedDragDroppable extends React.PureComponent {
? {
className: cx(
'drop-indicator',
dropIndicator === DROP_TOP && 'drop-indicator--top',
dropIndicator === DROP_BOTTOM && 'drop-indicator--bottom',
dropIndicator === DROP_LEFT && 'drop-indicator--left',
dropIndicator === DROP_RIGHT && 'drop-indicator--right',
dropIndicator === DROP_FORBIDDEN && 'drop-indicator--forbidden',
),
}
: null;
@@ -211,6 +182,7 @@ export class UnwrappedDragDroppable extends React.PureComponent {
data-test="dragdroppable-object"
className={cx(
'dragdroppable',
editMode && 'dragdroppable--edit-mode',
orientation === 'row' && 'dragdroppable-row',
orientation === 'column' && 'dragdroppable-column',
isDragging && 'dragdroppable--dragging',
@@ -226,6 +198,9 @@ export class UnwrappedDragDroppable extends React.PureComponent {
UnwrappedDragDroppable.propTypes = propTypes;
UnwrappedDragDroppable.defaultProps = defaultProps;
export const Draggable = DragSource(...dragConfig)(UnwrappedDragDroppable);
export const Droppable = DropTarget(...dropConfig)(UnwrappedDragDroppable);
// note that the composition order here determines using
// component.method() vs decoratedComponentInstance.method() in the drag/drop config
export default DragSource(...dragConfig)(

View File

@@ -18,10 +18,7 @@
*/
import getDropPosition, {
clearDropCache,
DROP_TOP,
DROP_RIGHT,
DROP_BOTTOM,
DROP_LEFT,
DROP_FORBIDDEN,
} from '../../util/getDropPosition';
export default function handleDrop(props, monitor, Component) {
@@ -31,7 +28,7 @@ export default function handleDrop(props, monitor, Component) {
Component.setState(() => ({ dropIndicator: null }));
const dropPosition = getDropPosition(monitor, Component);
if (!dropPosition) {
if (!dropPosition || dropPosition === DROP_FORBIDDEN) {
return undefined;
}
@@ -40,19 +37,11 @@ export default function handleDrop(props, monitor, Component) {
component,
index: componentIndex,
onDrop,
orientation,
dropToChild,
} = Component.props;
const draggingItem = monitor.getItem();
const dropAsChildOrSibling =
(orientation === 'row' &&
(dropPosition === DROP_TOP || dropPosition === DROP_BOTTOM)) ||
(orientation === 'column' &&
(dropPosition === DROP_LEFT || dropPosition === DROP_RIGHT))
? 'sibling'
: 'child';
const dropResult = {
source: {
id: draggingItem.parentId,
@@ -67,12 +56,18 @@ export default function handleDrop(props, monitor, Component) {
};
// simplest case, append as child
if (dropAsChildOrSibling === 'child') {
if (dropToChild) {
dropResult.destination = {
id: component.id,
type: component.type,
index: component.children.length,
};
} else if (!parentComponent) {
dropResult.destination = {
id: component.id,
type: component.type,
index: componentIndex,
};
} else {
// if the item is in the same list with a smaller index, you must account for the
// "missing" index upon movement within the list
@@ -81,10 +76,9 @@ export default function handleDrop(props, monitor, Component) {
const sameParentLowerIndex =
sameParent && draggingItem.index < componentIndex;
let nextIndex = sameParentLowerIndex ? componentIndex - 1 : componentIndex;
if (dropPosition === DROP_BOTTOM || dropPosition === DROP_RIGHT) {
nextIndex += 1;
}
const nextIndex = sameParentLowerIndex
? componentIndex - 1
: componentIndex;
dropResult.destination = {
id: parentComponent.id,

View File

@@ -25,7 +25,7 @@ import { LayoutItem, RootState } from 'src/dashboard/types';
import AnchorLink from 'src/dashboard/components/AnchorLink';
import Chart from 'src/dashboard/containers/Chart';
import DeleteComponentButton from 'src/dashboard/components/DeleteComponentButton';
import DragDroppable from 'src/dashboard/components/dnd/DragDroppable';
import { Draggable } from 'src/dashboard/components/dnd/DragDroppable';
import HoverMenu from 'src/dashboard/components/menu/HoverMenu';
import ResizableContainer from 'src/dashboard/components/resizable/ResizableContainer';
import getChartAndLabelComponentIdFromPath from 'src/dashboard/util/getChartAndLabelComponentIdFromPath';
@@ -243,7 +243,7 @@ const ChartHolder: React.FC<ChartHolderProps> = ({
}, []);
return (
<DragDroppable
<Draggable
component={component}
parentComponent={parentComponent}
orientation={parentComponent.type === ROW_TYPE ? 'column' : 'row'}
@@ -253,7 +253,7 @@ const ChartHolder: React.FC<ChartHolderProps> = ({
disableDragDrop={false}
editMode={editMode}
>
{({ dropIndicatorProps, dragSourceRef }) => (
{({ dragSourceRef }) => (
<ResizableContainer
id={component.id}
adjustableWidth={parentComponent.type === ROW_TYPE}
@@ -324,10 +324,9 @@ const ChartHolder: React.FC<ChartHolderProps> = ({
</HoverMenu>
)}
</div>
{dropIndicatorProps && <div {...dropIndicatorProps} />}
</ResizableContainer>
)}
</DragDroppable>
</Draggable>
);
};

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