Compare commits

..

2 Commits

Author SHA1 Message Date
Evan
1d814383c2 fix(swagger): avoid route collision, respect global Swagger flag, normalize app root
Address review feedback:
- Gate the APPLICATION_ROOT-aware Swagger/OpenAPI registration on
  FAB_API_SWAGGER_UI so the global Swagger disable still takes precedence.
- Suppress FAB's default OpenAPI/Swagger views (FAB_ADD_OPENAPI_VIEWS) when
  the prefix-aware variant is active, so the two don't register duplicate URL
  rules for /api/<version>/_openapi and /swagger/<version>.
- Normalize APPLICATION_ROOT (treat '/' as empty, strip trailing slash) so the
  Swagger UI spec URL is not built as a protocol-relative '//api/...' URL.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 10:50:17 -07:00
Claude Code
b53a6e0b11 fix(swagger): support URL prefix via APPLICATION_ROOT in OpenAPI and Swagger UI
Adopts #34407 by @rsbhatti. Serves the OpenAPI spec and an APPLICATION_ROOT-aware
Swagger UI for Superset deployments behind a URL prefix (reverse proxy), gated by
a new FAB_API_SWAGGER_UI_SUPERSET_APP_ROOT flag (default False).

Adoption cleanups over the original:
- keep the existing FAB_API_SWAGGER_UI flag (the original removed it)
- drop an unrelated AUTH_ROLE_PUBLIC change that the original accidentally included
- add ASF license headers and type hints to the new openapi module
- fix the SupsersetSwaggerView -> SupersetSwaggerView class-name typo
- add a unit test for the schema-name resolver

Closes #34407
Fixes #33304

Co-authored-by: rsbhatti <rajvindrasinghbhatti12@gmail.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 09:46:50 -07:00
772 changed files with 23662 additions and 107188 deletions

View File

@@ -41,8 +41,8 @@ body:
label: Superset version label: Superset version
options: options:
- master / latest-dev - master / latest-dev
- "6.1.0"
- "6.0.0" - "6.0.0"
- "5.0.0"
validations: validations:
required: true required: true
- type: dropdown - type: dropdown

View File

@@ -42,7 +42,7 @@ runs:
fi fi
echo "python-version=$RESOLVED_VERSION" >> "$GITHUB_OUTPUT" echo "python-version=$RESOLVED_VERSION" >> "$GITHUB_OUTPUT"
- name: Set up Python ${{ steps.set-python-version.outputs.python-version }} - name: Set up Python ${{ steps.set-python-version.outputs.python-version }}
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6 uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with: with:
python-version: ${{ steps.set-python-version.outputs.python-version }} python-version: ${{ steps.set-python-version.outputs.python-version }}
cache: ${{ inputs.cache }} cache: ${{ inputs.cache }}

View File

@@ -3,6 +3,10 @@ enable-beta-ecosystems: true
updates: updates:
- package-ecosystem: "github-actions" - package-ecosystem: "github-actions"
directory: "/" directory: "/"
ignore:
# Ignore temporarily as release schedule is too mentally taxing for dep-handling maintainers
# Additionally, very few PRs are reviewed by this action.
- dependency-name: anthropics/claude-code-action
schedule: schedule:
interval: "daily" interval: "daily"
cooldown: cooldown:
@@ -10,6 +14,12 @@ updates:
- package-ecosystem: "npm" - package-ecosystem: "npm"
ignore: ignore:
# TODO: remove below entries until React >= 18.0.0
- dependency-name: "storybook"
update-types: ["version-update:semver-major", "version-update:semver-minor"]
- dependency-name: "@storybook*"
update-types: ["version-update:semver-major", "version-update:semver-minor"]
- dependency-name: "eslint-plugin-storybook"
- dependency-name: "react-error-boundary" - dependency-name: "react-error-boundary"
- dependency-name: "@rjsf/*" - dependency-name: "@rjsf/*"
# remark-gfm v4+ requires react-markdown v9+, which needs React 18 # remark-gfm v4+ requires react-markdown v9+, which needs React 18
@@ -32,6 +42,14 @@ updates:
# and confirm the issue https://github.com/apache/superset/issues/39600 is fixed # and confirm the issue https://github.com/apache/superset/issues/39600 is fixed
- dependency-name: "react-checkbox-tree" - dependency-name: "react-checkbox-tree"
update-types: ["version-update:semver-major"] update-types: ["version-update:semver-major"]
groups:
storybook:
applies-to: version-updates
patterns:
- "@storybook*"
- "storybook"
update-types:
- "patch"
directory: "/superset-frontend/" directory: "/superset-frontend/"
schedule: schedule:
interval: "daily" interval: "daily"
@@ -72,7 +90,21 @@ updates:
- package-ecosystem: "npm" - package-ecosystem: "npm"
directory: "/docs/" directory: "/docs/"
ignore: ignore:
# TODO: remove below entries until React >= 18.0.0 in superset-frontend
- dependency-name: "storybook"
update-types: ["version-update:semver-major", "version-update:semver-minor"]
- dependency-name: "@storybook*"
update-types: ["version-update:semver-major", "version-update:semver-minor"]
- dependency-name: "eslint-plugin-storybook"
- dependency-name: "react-error-boundary" - dependency-name: "react-error-boundary"
groups:
storybook:
applies-to: version-updates
patterns:
- "@storybook*"
- "storybook"
update-types:
- "patch"
schedule: schedule:
interval: "daily" interval: "daily"
open-pull-requests-limit: 10 open-pull-requests-limit: 10

View File

@@ -114,7 +114,7 @@ testdata() {
say "::group::Load test data" say "::group::Load test data"
# must specify PYTHONPATH to make `tests.superset_test_config` importable # must specify PYTHONPATH to make `tests.superset_test_config` importable
export PYTHONPATH="$GITHUB_WORKSPACE" export PYTHONPATH="$GITHUB_WORKSPACE"
uv pip install --system -e . pip install -e .
superset db upgrade superset db upgrade
superset load_test_users superset load_test_users
superset load_examples --load-test-data superset load_examples --load-test-data
@@ -127,7 +127,7 @@ playwright_testdata() {
say "::group::Load all examples for Playwright tests" say "::group::Load all examples for Playwright tests"
# must specify PYTHONPATH to make `tests.superset_test_config` importable # must specify PYTHONPATH to make `tests.superset_test_config` importable
export PYTHONPATH="$GITHUB_WORKSPACE" export PYTHONPATH="$GITHUB_WORKSPACE"
uv pip install --system -e . pip install -e .
superset db upgrade superset db upgrade
superset load_test_users superset load_test_users
superset load_examples superset load_examples

View File

@@ -30,8 +30,9 @@ jobs:
pull-requests: write pull-requests: write
checks: write checks: write
steps: steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with: with:
persist-credentials: true persist-credentials: true
ref: master ref: master
@@ -40,7 +41,7 @@ jobs:
uses: ./.github/actions/setup-supersetbot/ uses: ./.github/actions/setup-supersetbot/
- name: Set up Python ${{ inputs.python-version }} - name: Set up Python ${{ inputs.python-version }}
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6
with: with:
python-version: "3.10" python-version: "3.10"

View File

@@ -22,7 +22,7 @@ jobs:
runs-on: ubuntu-22.04 runs-on: ubuntu-22.04
steps: steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with: with:
persist-credentials: false persist-credentials: false
submodules: recursive submodules: recursive

View File

@@ -25,7 +25,7 @@ jobs:
pull-requests: write pull-requests: write
steps: steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with: with:
persist-credentials: false persist-credentials: false
- name: Check and notify - name: Check and notify

88
.github/workflows/claude.yml vendored Normal file
View File

@@ -0,0 +1,88 @@
name: Claude PR Assistant
on:
issue_comment:
types: [created]
pull_request_review_comment:
types: [created]
permissions:
contents: read
jobs:
check-permissions:
if: |
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude'))
runs-on: ubuntu-latest
outputs:
allowed: ${{ steps.check.outputs.allowed }}
steps:
- name: Check if user is allowed
id: check
env:
COMMENTER: ${{ github.event.comment.user.login }}
run: |
# List of allowed users
ALLOWED_USERS="mistercrunch,rusackas"
echo "Checking permissions for user: $COMMENTER"
# Check if user is in allowed list
if [[ ",$ALLOWED_USERS," == *",$COMMENTER,"* ]]; then
echo "allowed=true" >> $GITHUB_OUTPUT
echo "✅ User $COMMENTER is allowed to use Claude"
else
echo "allowed=false" >> $GITHUB_OUTPUT
echo "❌ User $COMMENTER is not allowed to use Claude"
fi
deny-access:
needs: check-permissions
if: needs.check-permissions.outputs.allowed == 'false'
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
steps:
- name: Comment access denied
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
COMMENTER_LOGIN: ${{ github.event.comment.user.login || github.event.review.user.login || github.event.issue.user.login }}
with:
script: |
const commenter = process.env.COMMENTER_LOGIN;
const message = `👋 Hi @${commenter}!
Thanks for trying to use Claude Code, but currently only certain team members have access to this feature.
If you believe you should have access, please contact a project maintainer.`;
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: message
});
claude-code-action:
needs: check-permissions
if: needs.check-permissions.outputs.allowed == 'true'
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
issues: write
id-token: write
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
persist-credentials: false
fetch-depth: 1
- name: Run Claude PR Action
uses: anthropics/claude-code-action@5fb899572b81d2bb648d4d187173a2f423a9677c # beta
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
timeout_minutes: "60"

View File

@@ -26,7 +26,7 @@ jobs:
frontend: ${{ steps.check.outputs.frontend }} frontend: ${{ steps.check.outputs.frontend }}
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with: with:
persist-credentials: false persist-credentials: false
- name: Check for file changes - name: Check for file changes
@@ -47,7 +47,6 @@ jobs:
permissions: permissions:
actions: read actions: read
contents: read contents: read
pull-requests: read
security-events: write security-events: write
strategy: strategy:
@@ -58,13 +57,13 @@ jobs:
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with: with:
persist-credentials: false persist-credentials: false
# Initializes the CodeQL tools for scanning. # Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL - name: Initialize CodeQL
uses: github/codeql-action/init@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4 uses: github/codeql-action/init@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4
with: with:
languages: ${{ matrix.language }} languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file. # If you wish to specify custom queries, you can do so here or in a config file.
@@ -75,6 +74,6 @@ jobs:
# queries: security-extended,security-and-quality # queries: security-extended,security-and-quality
- name: Perform CodeQL Analysis - name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4 uses: github/codeql-action/analyze@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4
with: with:
category: "/language:${{matrix.language}}" category: "/language:${{matrix.language}}"

View File

@@ -27,7 +27,7 @@ jobs:
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
steps: steps:
- name: "Checkout Repository" - name: "Checkout Repository"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with: with:
persist-credentials: false persist-credentials: false
- name: "Dependency Review" - name: "Dependency Review"
@@ -43,7 +43,7 @@ jobs:
# the latest version. It's MIT: https://github.com/nbubna/store/blob/master/LICENSE-MIT # the latest version. It's MIT: https://github.com/nbubna/store/blob/master/LICENSE-MIT
# pkg:npm/node-forge@1.3.1 # pkg:npm/node-forge@1.3.1
# selecting BSD-3-Clause licensing terms for node-forge to ensure compatibility with Apache # selecting BSD-3-Clause licensing terms for node-forge to ensure compatibility with Apache
allow-dependencies-licenses: pkg:npm/rgbcolor, pkg:npm/jszip@3.10.1 allow-dependencies-licenses: pkg:npm/store2@2.14.2, pkg:npm/node-forge@1.3.1, pkg:npm/rgbcolor, pkg:npm/jszip@3.10.1
python-dependency-liccheck: python-dependency-liccheck:
# NOTE: Configuration for liccheck lives in our pyproject.yml. # NOTE: Configuration for liccheck lives in our pyproject.yml.
@@ -51,7 +51,7 @@ jobs:
runs-on: ubuntu-22.04 runs-on: ubuntu-22.04
steps: steps:
- name: "Checkout Repository" - name: "Checkout Repository"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with: with:
persist-credentials: false persist-credentials: false

View File

@@ -18,6 +18,7 @@ concurrency:
cancel-in-progress: true cancel-in-progress: true
jobs: jobs:
changes: changes:
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
timeout-minutes: 10 timeout-minutes: 10
@@ -30,7 +31,7 @@ jobs:
docker: ${{ steps.check.outputs.docker }} docker: ${{ steps.check.outputs.docker }}
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with: with:
persist-credentials: false persist-credentials: false
- name: Check for file changes - name: Check for file changes
@@ -70,29 +71,12 @@ jobs:
IMAGE_TAG: apache/superset:GHA-${{ matrix.build_preset }}-${{ github.run_id }} IMAGE_TAG: apache/superset:GHA-${{ matrix.build_preset }}-${{ github.run_id }}
steps: steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with: with:
persist-credentials: false persist-credentials: false
- name: Free up disk space
shell: bash
run: |
# Reclaim large preinstalled toolchains we don't use. The image
# build, and especially the docker-compose sanity check (which
# rebuilds from scratch whenever the registry cache image
# apache/superset-cache is unavailable), can otherwise exhaust the
# runner's root disk and fail with "no space left on device".
echo "Disk before cleanup:"; df -h /
sudo rm -rf \
/usr/share/dotnet \
/usr/local/lib/android \
/opt/ghc \
/usr/local/.ghcup \
/opt/hostedtoolcache/CodeQL \
/usr/local/share/boost || true
echo "Disk after cleanup:"; df -h /
- name: Setup Docker Environment - name: Setup Docker Environment
uses: ./.github/actions/setup-docker uses: ./.github/actions/setup-docker
with: with:
@@ -119,27 +103,13 @@ jobs:
PUSH_OR_LOAD="--load" PUSH_OR_LOAD="--load"
fi fi
# Retry to absorb transient Docker Hub registry errors (base-image supersetbot docker \
# pull timeouts, 504/401 on push, ECONNRESET) that otherwise fail $PUSH_OR_LOAD \
# the whole job. buildx reuses the buildkit layer cache from the --preset "$BUILD_PRESET" \
# failed attempt, so a retry mostly re-does just the failed push. --context "$EVENT" \
for attempt in 1 2 3; do --context-ref "$RELEASE" $FORCE_LATEST \
if supersetbot docker \ --extra-flags "--build-arg INCLUDE_CHROMIUM=false --tag $IMAGE_TAG" \
$PUSH_OR_LOAD \ $PLATFORM_ARG
--preset "$BUILD_PRESET" \
--context "$EVENT" \
--context-ref "$RELEASE" $FORCE_LATEST \
--extra-flags "--build-arg INCLUDE_CHROMIUM=false --tag $IMAGE_TAG" \
$PLATFORM_ARG; then
break
fi
if [ "$attempt" -eq 3 ]; then
echo "::error::supersetbot docker build failed after 3 attempts"
exit 1
fi
echo "::warning::Build attempt ${attempt} failed; retrying in 30s..."
sleep 30
done
# in the context of push (using multi-platform build), we need to pull the image locally # in the context of push (using multi-platform build), we need to pull the image locally
- name: Docker pull - name: Docker pull
@@ -177,24 +147,9 @@ jobs:
timeout-minutes: 30 timeout-minutes: 30
steps: steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with: with:
persist-credentials: false persist-credentials: false
- name: Free up disk space
shell: bash
run: |
# The sanity check rebuilds the image from scratch whenever the
# registry cache image apache/superset-cache is unavailable, which
# can exhaust the runner's root disk ("no space left on device").
echo "Disk before cleanup:"; df -h /
sudo rm -rf \
/usr/share/dotnet \
/usr/local/lib/android \
/opt/ghc \
/usr/local/.ghcup \
/opt/hostedtoolcache/CodeQL \
/usr/local/share/boost || true
echo "Disk after cleanup:"; df -h /
- name: Setup Docker Environment - name: Setup Docker Environment
uses: ./.github/actions/setup-docker uses: ./.github/actions/setup-docker
with: with:

View File

@@ -10,29 +10,37 @@ permissions:
contents: read contents: read
jobs: jobs:
build: config:
# Publishing uses npm trusted publishing (OIDC), so there is no NPM_TOKEN to runs-on: ubuntu-24.04
# gate on. Restrict to the canonical repo: forks cannot mint a valid OIDC outputs:
# token for this package and must not publish. has-secrets: ${{ steps.check.outputs.has-secrets }}
if: github.repository == 'apache/superset' steps:
- name: "Check for secrets"
id: check
shell: bash
run: |
if [ -n "${NPM_TOKEN}" ]; then
echo "has-secrets=1" >> "$GITHUB_OUTPUT"
fi
env:
NPM_TOKEN: ${{ (secrets.NPM_TOKEN != '') || '' }}
build:
needs: config
if: needs.config.outputs.has-secrets
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
permissions:
contents: read
id-token: write # required for npm trusted publishing (OIDC)
defaults: defaults:
run: run:
working-directory: superset-embedded-sdk working-directory: superset-embedded-sdk
steps: steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with: with:
persist-credentials: false persist-credentials: false
# Note: registry-url is intentionally omitted. When set, actions/setup-node
# writes an .npmrc with `_authToken=${NODE_AUTH_TOKEN}` and a placeholder
# token, which makes npm attempt token auth and skip the OIDC
# trusted-publishing exchange. With no .npmrc auth line, npm authenticates
# via OIDC against the default registry (registry.npmjs.org).
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with: with:
node-version-file: "./superset-embedded-sdk/.nvmrc" node-version-file: './superset-embedded-sdk/.nvmrc'
registry-url: 'https://registry.npmjs.org'
- run: npm ci - run: npm ci
- run: npm run ci:release - run: npm run ci:release
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

View File

@@ -21,13 +21,13 @@ jobs:
run: run:
working-directory: superset-embedded-sdk working-directory: superset-embedded-sdk
steps: steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with: with:
persist-credentials: false persist-credentials: false
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with: with:
node-version-file: "./superset-embedded-sdk/.nvmrc" node-version-file: './superset-embedded-sdk/.nvmrc'
registry-url: "https://registry.npmjs.org" registry-url: 'https://registry.npmjs.org'
- run: npm ci - run: npm ci
- run: npm test - run: npm test
- run: npm run build - run: npm run build

View File

@@ -32,12 +32,12 @@ jobs:
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
steps: steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with: with:
persist-credentials: false persist-credentials: false
submodules: recursive submodules: recursive
- name: Setup Java - name: Setup Java
uses: actions/setup-java@ad2b38190b15e4d6bdf0c97fb4fca8412226d287 # v5.3.0 uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5
with: with:
distribution: "temurin" distribution: "temurin"
java-version: "11" java-version: "11"

View File

@@ -18,6 +18,7 @@ concurrency:
cancel-in-progress: true cancel-in-progress: true
jobs: jobs:
validate-all-ghas: validate-all-ghas:
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
permissions: permissions:
@@ -27,14 +28,14 @@ jobs:
security-events: write security-events: write
steps: steps:
- name: Checkout Repository - name: Checkout Repository
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with: with:
persist-credentials: false persist-credentials: false
- name: Set up Node.js - name: Set up Node.js
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with: with:
node-version: "20" node-version: '20'
- name: Install Dependencies - name: Install Dependencies
run: npm install -g @action-validator/core @action-validator/cli --save-dev run: npm install -g @action-validator/core @action-validator/cli --save-dev

View File

@@ -15,8 +15,9 @@ jobs:
pull-requests: write pull-requests: write
issues: write issues: write
steps: steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with: with:
persist-credentials: false persist-credentials: false

View File

@@ -11,29 +11,29 @@ jobs:
contents: write contents: write
steps: steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with: with:
persist-credentials: false persist-credentials: false
submodules: recursive submodules: recursive
- name: Check for latest tag - name: Check for latest tag
id: latest-tag id: latest-tag
env: env:
RELEASE_TAG_NAME: ${{ github.event.release.tag_name }} RELEASE_TAG_NAME: ${{ github.event.release.tag_name }}
run: | run: |
source ./scripts/tag_latest_release.sh "$RELEASE_TAG_NAME" --dry-run source ./scripts/tag_latest_release.sh "$RELEASE_TAG_NAME" --dry-run
- name: Configure Git - name: Configure Git
run: | run: |
git config user.name "$GITHUB_ACTOR" git config user.name "$GITHUB_ACTOR"
git config user.email "$GITHUB_ACTOR@users.noreply.github.com" git config user.email "$GITHUB_ACTOR@users.noreply.github.com"
- name: Run latest-tag - name: Run latest-tag
uses: ./.github/actions/latest-tag uses: ./.github/actions/latest-tag
if: steps.latest-tag.outputs.SKIP_TAG != 'true' if: steps.latest-tag.outputs.SKIP_TAG != 'true'
with: with:
description: Superset latest release description: Superset latest release
tag-name: latest tag-name: latest
env: env:
GITHUB_TOKEN: ${{ github.token }} GITHUB_TOKEN: ${{ github.token }}

View File

@@ -18,14 +18,14 @@ jobs:
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
steps: steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with: with:
persist-credentials: false persist-credentials: false
submodules: recursive submodules: recursive
- name: Setup Java - name: Setup Java
uses: actions/setup-java@ad2b38190b15e4d6bdf0c97fb4fca8412226d287 # v5.3.0 uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5
with: with:
distribution: "temurin" distribution: 'temurin'
java-version: "11" java-version: '11'
- name: Run license check - name: Run license check
run: ./scripts/check_license.sh run: ./scripts/check_license.sh

View File

@@ -21,7 +21,7 @@ jobs:
pull-requests: write pull-requests: write
steps: steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with: with:
persist-credentials: false persist-credentials: false
submodules: recursive submodules: recursive
@@ -31,5 +31,6 @@ jobs:
on-failed-regex-fail-action: true on-failed-regex-fail-action: true
on-failed-regex-request-changes: false on-failed-regex-request-changes: false
on-failed-regex-create-review: false on-failed-regex-create-review: false
on-failed-regex-comment: "Please format your PR title to match: `%regex%`!" on-failed-regex-comment:
"Please format your PR title to match: `%regex%`!"
repo-token: "${{ github.token }}" repo-token: "${{ github.token }}"

View File

@@ -28,7 +28,7 @@ jobs:
python-version: ${{ github.event_name == 'pull_request' && fromJSON('["current"]') || fromJSON('["current", "previous", "next"]') }} python-version: ${{ github.event_name == 'pull_request' && fromJSON('["current"]') || fromJSON('["current", "previous", "next"]') }}
steps: steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with: with:
persist-credentials: false persist-credentials: false
submodules: recursive submodules: recursive
@@ -48,9 +48,9 @@ jobs:
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with: with:
node-version-file: "superset-frontend/.nvmrc" node-version: '20'
cache: "npm" cache: 'npm'
cache-dependency-path: "superset-frontend/package-lock.json" cache-dependency-path: 'superset-frontend/package-lock.json'
- name: Install Frontend Dependencies - name: Install Frontend Dependencies
run: | run: |
@@ -74,7 +74,7 @@ jobs:
id: changed_files id: changed_files
uses: ./.github/actions/file-changes-action uses: ./.github/actions/file-changes-action
with: with:
output: " " output: ' '
- name: pre-commit - name: pre-commit
env: env:

View File

@@ -33,7 +33,7 @@ jobs:
permissions: permissions:
contents: write contents: write
steps: steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with: with:
persist-credentials: false persist-credentials: false
# pulls all commits (needed for lerna / semantic release to correctly version) # pulls all commits (needed for lerna / semantic release to correctly version)
@@ -52,7 +52,7 @@ jobs:
if: env.HAS_TAGS if: env.HAS_TAGS
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with: with:
node-version-file: "./superset-frontend/.nvmrc" node-version-file: './superset-frontend/.nvmrc'
- name: Cache npm - name: Cache npm
if: env.HAS_TAGS if: env.HAS_TAGS

View File

@@ -10,11 +10,11 @@ on:
workflow_dispatch: workflow_dispatch:
inputs: inputs:
pr_number: pr_number:
description: "PR number to sync" description: 'PR number to sync'
required: true required: true
type: number type: number
sha: sha:
description: "Specific SHA to deploy (optional, defaults to latest)" description: 'Specific SHA to deploy (optional, defaults to latest)'
required: false required: false
type: string type: string
@@ -152,7 +152,7 @@ jobs:
- name: Checkout PR code (only if build needed) - name: Checkout PR code (only if build needed)
if: steps.auth.outputs.authorized == 'true' && steps.check.outputs.build_needed == 'true' if: steps.auth.outputs.authorized == 'true' && steps.check.outputs.build_needed == 'true'
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with: with:
ref: ${{ steps.check.outputs.target_sha }} ref: ${{ steps.check.outputs.target_sha }}
persist-credentials: false persist-credentials: false

View File

@@ -41,7 +41,7 @@ jobs:
- 16379:6379 - 16379:6379
steps: steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with: with:
persist-credentials: false persist-credentials: false
submodules: recursive submodules: recursive
@@ -61,7 +61,7 @@ jobs:
- name: superset init - name: superset init
if: steps.check.outputs.python if: steps.check.outputs.python
run: | run: |
uv pip install --system -e . pip install -e .
superset db upgrade superset db upgrade
superset load_test_users superset load_test_users
- name: superset load_examples - name: superset load_examples

View File

@@ -60,7 +60,7 @@ jobs:
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
steps: steps:
- name: "Checkout ${{ github.event.workflow_run.head_sha || github.sha }}" - name: "Checkout ${{ github.event.workflow_run.head_sha || github.sha }}"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with: with:
ref: ${{ github.event.workflow_run.head_sha || github.sha }} ref: ${{ github.event.workflow_run.head_sha || github.sha }}
persist-credentials: false persist-credentials: false
@@ -68,13 +68,13 @@ jobs:
- name: Set up Node.js - name: Set up Node.js
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with: with:
node-version-file: "./docs/.nvmrc" node-version-file: './docs/.nvmrc'
- name: Setup Python - name: Setup Python
uses: ./.github/actions/setup-backend/ uses: ./.github/actions/setup-backend/
- uses: actions/setup-java@ad2b38190b15e4d6bdf0c97fb4fca8412226d287 # v5.3.0 - uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5
with: with:
distribution: "zulu" distribution: 'zulu'
java-version: "21" java-version: '21'
- name: Install Graphviz - name: Install Graphviz
run: sudo apt-get install -y graphviz run: sudo apt-get install -y graphviz
- name: Compute Entity Relationship diagram (ERD) - name: Compute Entity Relationship diagram (ERD)

View File

@@ -28,12 +28,12 @@ jobs:
name: Link Checking name: Link Checking
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with: with:
persist-credentials: false persist-credentials: false
# Do not bump this linkinator-action version without opening # Do not bump this linkinator-action version without opening
# an ASF Infra ticket to allow the new version first! # an ASF Infra ticket to allow the new version first!
- uses: JustinBeckwith/linkinator-action@af984b9f30f63e796ae2ea5be5e07cb587f1bbd9 # v2.3 - uses: JustinBeckwith/linkinator-action@af984b9f30f63e796ae2ea5be5e07cb587f1bbd9 # v2.3
continue-on-error: true # This will make the job advisory (non-blocking, no red X) continue-on-error: true # This will make the job advisory (non-blocking, no red X)
with: with:
paths: "**/*.md, **/*.mdx" paths: "**/*.md, **/*.mdx"
@@ -73,14 +73,14 @@ jobs:
working-directory: docs working-directory: docs
steps: steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with: with:
persist-credentials: false persist-credentials: false
submodules: recursive submodules: recursive
- name: Set up Node.js - name: Set up Node.js
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with: with:
node-version-file: "./docs/.nvmrc" node-version-file: './docs/.nvmrc'
- name: yarn install - name: yarn install
run: | run: |
yarn install --check-cache yarn install --check-cache
@@ -112,7 +112,7 @@ jobs:
working-directory: docs working-directory: docs
steps: steps:
- name: "Checkout PR head: ${{ github.event.workflow_run.head_sha }}" - name: "Checkout PR head: ${{ github.event.workflow_run.head_sha }}"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with: with:
ref: ${{ github.event.workflow_run.head_sha }} ref: ${{ github.event.workflow_run.head_sha }}
persist-credentials: false persist-credentials: false
@@ -120,7 +120,7 @@ jobs:
- name: Set up Node.js - name: Set up Node.js
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with: with:
node-version-file: "./docs/.nvmrc" node-version-file: './docs/.nvmrc'
- name: yarn install - name: yarn install
run: | run: |
yarn install --check-cache yarn install --check-cache
@@ -131,7 +131,7 @@ jobs:
run_id: ${{ github.event.workflow_run.id }} run_id: ${{ github.event.workflow_run.id }}
name: database-diagnostics name: database-diagnostics
path: docs/src/data/ path: docs/src/data/
if_no_artifact_found: "warning" if_no_artifact_found: 'warning'
- name: Use fresh diagnostics - name: Use fresh diagnostics
run: | run: |
if [ -f "src/data/databases-diagnostics.json" ]; then if [ -f "src/data/databases-diagnostics.json" ]; then

View File

@@ -10,17 +10,17 @@ on:
workflow_dispatch: workflow_dispatch:
inputs: inputs:
use_dashboard: use_dashboard:
description: "Use Cypress Dashboard (true/false) [paid service - trigger manually when needed]. You MUST provide a branch and/or PR number below for this to work." description: 'Use Cypress Dashboard (true/false) [paid service - trigger manually when needed]. You MUST provide a branch and/or PR number below for this to work.'
required: false required: false
default: "false" default: 'false'
ref: ref:
description: "The branch or tag to checkout" description: 'The branch or tag to checkout'
required: false required: false
default: "" default: ''
pr_id: pr_id:
description: "The pull request ID to checkout" description: 'The pull request ID to checkout'
required: false required: false
default: "" default: ''
concurrency: concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }} group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
@@ -38,7 +38,7 @@ jobs:
frontend: ${{ steps.check.outputs.frontend }} frontend: ${{ steps.check.outputs.frontend }}
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with: with:
persist-credentials: false persist-credentials: false
- name: Check for file changes - name: Check for file changes
@@ -49,7 +49,7 @@ jobs:
cypress-matrix: cypress-matrix:
needs: changes needs: changes
if: (needs.changes.outputs.python == 'true' || needs.changes.outputs.frontend == 'true') && github.event.pull_request.draft == false if: needs.changes.outputs.python == 'true' || needs.changes.outputs.frontend == 'true'
# Somehow one test flakes on 24.04 for unknown reasons, this is the only GHA left on 22.04 # Somehow one test flakes on 24.04 for unknown reasons, this is the only GHA left on 22.04
runs-on: ubuntu-22.04 runs-on: ubuntu-22.04
timeout-minutes: 30 timeout-minutes: 30
@@ -97,21 +97,21 @@ jobs:
# Conditional checkout based on context # Conditional checkout based on context
- name: Checkout for push or pull_request event - name: Checkout for push or pull_request event
if: github.event_name == 'push' || github.event_name == 'pull_request' if: github.event_name == 'push' || github.event_name == 'pull_request'
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with: with:
persist-credentials: false persist-credentials: false
submodules: recursive submodules: recursive
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }} ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}
- name: Checkout using ref (workflow_dispatch) - name: Checkout using ref (workflow_dispatch)
if: github.event_name == 'workflow_dispatch' && github.event.inputs.ref != '' if: github.event_name == 'workflow_dispatch' && github.event.inputs.ref != ''
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with: with:
persist-credentials: false persist-credentials: false
ref: ${{ github.event.inputs.ref }} ref: ${{ github.event.inputs.ref }}
submodules: recursive submodules: recursive
- name: Checkout using PR ID (workflow_dispatch) - name: Checkout using PR ID (workflow_dispatch)
if: github.event_name == 'workflow_dispatch' && github.event.inputs.pr_id != '' if: github.event_name == 'workflow_dispatch' && github.event.inputs.pr_id != ''
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with: with:
persist-credentials: false persist-credentials: false
ref: refs/pull/${{ github.event.inputs.pr_id }}/merge ref: refs/pull/${{ github.event.inputs.pr_id }}/merge
@@ -130,9 +130,9 @@ jobs:
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with: with:
node-version-file: "./superset-frontend/.nvmrc" node-version-file: './superset-frontend/.nvmrc'
cache: "npm" cache: 'npm'
cache-dependency-path: "superset-frontend/package-lock.json" cache-dependency-path: 'superset-frontend/package-lock.json'
- name: Install npm dependencies - name: Install npm dependencies
uses: ./.github/actions/cached-dependencies uses: ./.github/actions/cached-dependencies
with: with:
@@ -207,21 +207,21 @@ jobs:
# Conditional checkout based on context (same as Cypress workflow) # Conditional checkout based on context (same as Cypress workflow)
- name: Checkout for push or pull_request event - name: Checkout for push or pull_request event
if: github.event_name == 'push' || github.event_name == 'pull_request' if: github.event_name == 'push' || github.event_name == 'pull_request'
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with: with:
persist-credentials: false persist-credentials: false
submodules: recursive submodules: recursive
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }} ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}
- name: Checkout using ref (workflow_dispatch) - name: Checkout using ref (workflow_dispatch)
if: github.event_name == 'workflow_dispatch' && github.event.inputs.ref != '' if: github.event_name == 'workflow_dispatch' && github.event.inputs.ref != ''
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with: with:
persist-credentials: false persist-credentials: false
ref: ${{ github.event.inputs.ref }} ref: ${{ github.event.inputs.ref }}
submodules: recursive submodules: recursive
- name: Checkout using PR ID (workflow_dispatch) - name: Checkout using PR ID (workflow_dispatch)
if: github.event_name == 'workflow_dispatch' && github.event.inputs.pr_id != '' if: github.event_name == 'workflow_dispatch' && github.event.inputs.pr_id != ''
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with: with:
persist-credentials: false persist-credentials: false
ref: refs/pull/${{ github.event.inputs.pr_id }}/merge ref: refs/pull/${{ github.event.inputs.pr_id }}/merge
@@ -240,9 +240,9 @@ jobs:
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with: with:
node-version-file: "./superset-frontend/.nvmrc" node-version-file: './superset-frontend/.nvmrc'
cache: "npm" cache: 'npm'
cache-dependency-path: "superset-frontend/package-lock.json" cache-dependency-path: 'superset-frontend/package-lock.json'
- name: Install npm dependencies - name: Install npm dependencies
uses: ./.github/actions/cached-dependencies uses: ./.github/actions/cached-dependencies
with: with:

View File

@@ -31,7 +31,7 @@ jobs:
working-directory: superset-extensions-cli working-directory: superset-extensions-cli
steps: steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with: with:
persist-credentials: false persist-credentials: false
submodules: recursive submodules: recursive
@@ -56,7 +56,7 @@ jobs:
- name: Upload coverage reports to Codecov - name: Upload coverage reports to Codecov
if: steps.check.outputs.superset-extensions-cli if: steps.check.outputs.superset-extensions-cli
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0 uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # v6.0.1
with: with:
file: ./coverage.xml file: ./coverage.xml
flags: superset-extensions-cli flags: superset-extensions-cli

View File

@@ -27,7 +27,7 @@ jobs:
should-run: ${{ steps.check.outputs.frontend }} should-run: ${{ steps.check.outputs.frontend }}
steps: steps:
- name: Checkout Code - name: Checkout Code
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with: with:
persist-credentials: false persist-credentials: false
fetch-depth: 0 fetch-depth: 0
@@ -110,7 +110,7 @@ jobs:
id-token: write id-token: write
steps: steps:
- name: Checkout Code - name: Checkout Code
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with: with:
persist-credentials: false persist-credentials: false
fetch-depth: 0 fetch-depth: 0
@@ -134,7 +134,7 @@ jobs:
run: npx nyc merge coverage/ merged-output/coverage-summary.json run: npx nyc merge coverage/ merged-output/coverage-summary.json
- name: Upload Code Coverage - name: Upload Code Coverage
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0 uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # v6.0.1
with: with:
flags: javascript flags: javascript
use_oidc: true use_oidc: true

View File

@@ -19,7 +19,7 @@ jobs:
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
steps: steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with: with:
persist-credentials: false persist-credentials: false
submodules: recursive submodules: recursive
@@ -33,7 +33,7 @@ jobs:
- name: Setup Python - name: Setup Python
uses: ./.github/actions/setup-backend/ uses: ./.github/actions/setup-backend/
with: with:
install-superset: "false" install-superset: 'false'
- name: Set up chart-testing - name: Set up chart-testing
uses: ./.github/actions/chart-testing-action uses: ./.github/actions/chart-testing-action

View File

@@ -29,7 +29,7 @@ jobs:
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with: with:
ref: ${{ inputs.ref || github.ref_name }} ref: ${{ inputs.ref || github.ref_name }}
persist-credentials: true persist-credentials: true

View File

@@ -10,13 +10,13 @@ on:
workflow_dispatch: workflow_dispatch:
inputs: inputs:
ref: ref:
description: "The branch or tag to checkout" description: 'The branch or tag to checkout'
required: false required: false
default: "" default: ''
pr_id: pr_id:
description: "The pull request ID to checkout" description: 'The pull request ID to checkout'
required: false required: false
default: "" default: ''
concurrency: concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }} group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
@@ -34,7 +34,7 @@ jobs:
frontend: ${{ steps.check.outputs.frontend }} frontend: ${{ steps.check.outputs.frontend }}
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with: with:
persist-credentials: false persist-credentials: false
- name: Check for file changes - name: Check for file changes
@@ -83,21 +83,21 @@ jobs:
# Conditional checkout based on context (same as Cypress workflow) # Conditional checkout based on context (same as Cypress workflow)
- name: Checkout for push or pull_request event - name: Checkout for push or pull_request event
if: github.event_name == 'push' || github.event_name == 'pull_request' if: github.event_name == 'push' || github.event_name == 'pull_request'
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with: with:
persist-credentials: false persist-credentials: false
submodules: recursive submodules: recursive
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }} ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}
- name: Checkout using ref (workflow_dispatch) - name: Checkout using ref (workflow_dispatch)
if: github.event_name == 'workflow_dispatch' && github.event.inputs.ref != '' if: github.event_name == 'workflow_dispatch' && github.event.inputs.ref != ''
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with: with:
persist-credentials: false persist-credentials: false
ref: ${{ github.event.inputs.ref }} ref: ${{ github.event.inputs.ref }}
submodules: recursive submodules: recursive
- name: Checkout using PR ID (workflow_dispatch) - name: Checkout using PR ID (workflow_dispatch)
if: github.event_name == 'workflow_dispatch' && github.event.inputs.pr_id != '' if: github.event_name == 'workflow_dispatch' && github.event.inputs.pr_id != ''
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with: with:
persist-credentials: false persist-credentials: false
ref: refs/pull/${{ github.event.inputs.pr_id }}/merge ref: refs/pull/${{ github.event.inputs.pr_id }}/merge
@@ -116,9 +116,9 @@ jobs:
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with: with:
node-version-file: "./superset-frontend/.nvmrc" node-version-file: './superset-frontend/.nvmrc'
cache: "npm" cache: 'npm'
cache-dependency-path: "superset-frontend/package-lock.json" cache-dependency-path: 'superset-frontend/package-lock.json'
- name: Install npm dependencies - name: Install npm dependencies
uses: ./.github/actions/cached-dependencies uses: ./.github/actions/cached-dependencies
with: with:

View File

@@ -1,11 +1,6 @@
# Python integration tests # Python integration tests
name: Python-Integration name: Python-Integration
# Least-privilege default for GITHUB_TOKEN. Jobs that need more (e.g. OIDC for
# codecov uploads) opt in via their own job-level `permissions:` block.
permissions:
contents: read
on: on:
push: push:
branches: branches:
@@ -29,7 +24,7 @@ jobs:
python: ${{ steps.check.outputs.python }} python: ${{ steps.check.outputs.python }}
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with: with:
persist-credentials: false persist-credentials: false
- name: Check for file changes - name: Check for file changes
@@ -72,7 +67,7 @@ jobs:
- 16379:6379 - 16379:6379
steps: steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with: with:
persist-credentials: false persist-credentials: false
submodules: recursive submodules: recursive
@@ -90,7 +85,7 @@ jobs:
run: | run: |
./scripts/python_tests.sh ./scripts/python_tests.sh
- name: Upload code coverage - name: Upload code coverage
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0 uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # v6.0.1
with: with:
flags: python,mysql flags: python,mysql
verbose: true verbose: true
@@ -157,7 +152,7 @@ jobs:
- 16379:6379 - 16379:6379
steps: steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with: with:
persist-credentials: false persist-credentials: false
submodules: recursive submodules: recursive
@@ -178,7 +173,7 @@ jobs:
run: | run: |
./scripts/python_tests.sh ./scripts/python_tests.sh
- name: Upload code coverage - name: Upload code coverage
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0 uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # v6.0.1
with: with:
flags: python,postgres flags: python,postgres
verbose: true verbose: true
@@ -207,7 +202,7 @@ jobs:
- 16379:6379 - 16379:6379
steps: steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with: with:
persist-credentials: false persist-credentials: false
submodules: recursive submodules: recursive
@@ -227,7 +222,7 @@ jobs:
run: | run: |
./scripts/python_tests.sh ./scripts/python_tests.sh
- name: Upload code coverage - name: Upload code coverage
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0 uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # v6.0.1
with: with:
flags: python,sqlite flags: python,sqlite
verbose: true verbose: true

View File

@@ -25,7 +25,7 @@ jobs:
python: ${{ steps.check.outputs.python }} python: ${{ steps.check.outputs.python }}
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with: with:
persist-credentials: false persist-credentials: false
- name: Check for file changes - name: Check for file changes
@@ -72,7 +72,7 @@ jobs:
- 16379:6379 - 16379:6379
steps: steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with: with:
persist-credentials: false persist-credentials: false
submodules: recursive submodules: recursive
@@ -90,7 +90,7 @@ jobs:
run: | run: |
./scripts/python_tests.sh -m 'chart_data_flow or sql_json_flow' ./scripts/python_tests.sh -m 'chart_data_flow or sql_json_flow'
- name: Upload code coverage - name: Upload code coverage
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0 uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # v6.0.1
with: with:
flags: python,presto flags: python,presto
verbose: true verbose: true
@@ -127,7 +127,7 @@ jobs:
- 16379:6379 - 16379:6379
steps: steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with: with:
persist-credentials: false persist-credentials: false
submodules: recursive submodules: recursive
@@ -149,10 +149,10 @@ jobs:
run: celery-worker run: celery-worker
- name: Python unit tests (PostgreSQL) - name: Python unit tests (PostgreSQL)
run: | run: |
uv pip install --system -e .[hive] pip install -e .[hive]
./scripts/python_tests.sh -m 'chart_data_flow or sql_json_flow' ./scripts/python_tests.sh -m 'chart_data_flow or sql_json_flow'
- name: Upload code coverage - name: Upload code coverage
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0 uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # v6.0.1
with: with:
flags: python,hive flags: python,hive
verbose: true verbose: true

View File

@@ -1,11 +1,6 @@
# Python unit tests # Python unit tests
name: Python-Unit name: Python-Unit
# Least-privilege default for GITHUB_TOKEN. Jobs that need more (e.g. OIDC for
# codecov uploads) opt in via their own job-level `permissions:` block.
permissions:
contents: read
on: on:
push: push:
branches: branches:
@@ -30,7 +25,7 @@ jobs:
python: ${{ steps.check.outputs.python }} python: ${{ steps.check.outputs.python }}
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with: with:
persist-credentials: false persist-credentials: false
- name: Check for file changes - name: Check for file changes
@@ -55,7 +50,7 @@ jobs:
PYTHONPATH: ${{ github.workspace }} PYTHONPATH: ${{ github.workspace }}
steps: steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with: with:
persist-credentials: false persist-credentials: false
submodules: recursive submodules: recursive
@@ -77,7 +72,7 @@ jobs:
pytest --durations-min=0.5 --cov=superset/sql/ ./tests/unit_tests/sql/ --cache-clear --cov-fail-under=100 pytest --durations-min=0.5 --cov=superset/sql/ ./tests/unit_tests/sql/ --cache-clear --cov-fail-under=100
pytest --durations-min=0.5 --cov=superset/semantic_layers/ ./tests/unit_tests/semantic_layers/ --cache-clear --cov-fail-under=100 pytest --durations-min=0.5 --cov=superset/semantic_layers/ ./tests/unit_tests/semantic_layers/ --cache-clear --cov-fail-under=100
- name: Upload code coverage - name: Upload code coverage
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0 uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # v6.0.1
with: with:
flags: python,unit flags: python,unit
verbose: true verbose: true

View File

@@ -25,7 +25,7 @@ jobs:
pull-requests: read pull-requests: read
steps: steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with: with:
persist-credentials: false persist-credentials: false
submodules: recursive submodules: recursive
@@ -40,9 +40,9 @@ jobs:
if: steps.check.outputs.frontend if: steps.check.outputs.frontend
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with: with:
node-version-file: "./superset-frontend/.nvmrc" node-version-file: './superset-frontend/.nvmrc'
cache: "npm" cache: 'npm'
cache-dependency-path: "superset-frontend/package-lock.json" cache-dependency-path: 'superset-frontend/package-lock.json'
- name: Install dependencies - name: Install dependencies
if: steps.check.outputs.frontend if: steps.check.outputs.frontend
uses: ./.github/actions/cached-dependencies uses: ./.github/actions/cached-dependencies
@@ -61,7 +61,7 @@ jobs:
pull-requests: read pull-requests: read
steps: steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with: with:
persist-credentials: false persist-credentials: false
submodules: recursive submodules: recursive

View File

@@ -25,7 +25,7 @@ jobs:
timeout-minutes: 20 timeout-minutes: 20
steps: steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with: with:
persist-credentials: false persist-credentials: false
- name: Install dependencies - name: Install dependencies

View File

@@ -9,7 +9,7 @@ on:
workflow_dispatch: workflow_dispatch:
inputs: inputs:
comment_body: comment_body:
description: "Comment Body" description: 'Comment Body'
required: true required: true
type: string type: string
@@ -38,7 +38,7 @@ jobs:
}); });
- name: "Checkout ( ${{ github.sha }} )" - name: "Checkout ( ${{ github.sha }} )"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with: with:
persist-credentials: false persist-credentials: false

View File

@@ -1,60 +0,0 @@
name: Sync requirements for Python dependency PRs
on:
pull_request:
types: [opened, synchronize]
permissions:
contents: write
pull-requests: read
jobs:
sync-python-dep-requirements:
# This action is limited for (1) PRs authored by Dependabot and (2) upstream repo due to write back to remote
if: github.repository == 'apache/superset' && github.event.pull_request.user.login == 'dependabot[bot]' && github.event.pull_request.head.repo.fork == false
runs-on: ubuntu-26.04
steps:
- name: Fetch Dependabot metadata
id: dependabot-metadata
shell: bash
env:
BRANCH_NAME: ${{ github.head_ref }}
run: |
# Get current branch name, extract the package ecosystem and return as GHA step output
packageEcosystem=$(echo "$BRANCH_NAME" | cut -d'/' -f2)
echo "package-ecosystem=$packageEcosystem" >> $GITHUB_OUTPUT
# zizmor: ignore[artipacked] - required persisted credentials to push synced requirement changes back to remote
- name: Checkout source code
if: ${{ steps.dependabot-metadata.outputs.package-ecosystem == 'pip' }}
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
ref: ${{ github.event.pull_request.head.sha }}
persist-credentials: true
# Authenticate the Docker daemon so the python:slim pull in
# uv-pip-compile.sh uses our (much higher) authenticated rate limit
# instead of the shared-runner anonymous one.
- name: Login to Docker Hub
if: ${{ steps.dependabot-metadata.outputs.package-ecosystem == 'pip' }}
continue-on-error: true
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
with:
username: ${{ secrets.DOCKERHUB_USER }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Sync requirements in containerized environment
if: ${{ steps.dependabot-metadata.outputs.package-ecosystem == 'pip' }}
run: ./scripts/uv-pip-compile.sh
- name: Push changes to remote PRs
if: ${{ steps.dependabot-metadata.outputs.package-ecosystem == 'pip' }}
run: |
git config user.name 'github-actions[bot]'
git config user.email '41898282+github-actions[bot]@users.noreply.github.com'
git add requirements
git diff --cached --quiet && exit 0
git commit --signoff --message "build(deps): sync pinned requirements for Dependabot pip PRs"
git push origin "HEAD:refs/heads/${GITHUB_EVENT_PULL_REQUEST_HEAD_REF}"
env:
GITHUB_EVENT_PULL_REQUEST_HEAD_REF: ${{ github.event.pull_request.head.ref }}

View File

@@ -16,11 +16,11 @@ on:
force-latest: force-latest:
required: true required: true
type: choice type: choice
default: "false" default: 'false'
description: Whether to force a latest tag on the release description: Whether to force a latest tag on the release
options: options:
- "true" - 'true'
- "false" - 'false'
permissions: permissions:
contents: read contents: read
@@ -49,12 +49,12 @@ jobs:
contents: write contents: write
strategy: strategy:
matrix: matrix:
build_preset: build_preset: ["dev", "lean", "py310", "websocket", "dockerize", "py311", "py312"]
["dev", "lean", "py310", "websocket", "dockerize", "py311", "py312"]
fail-fast: false fail-fast: false
steps: steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with: with:
persist-credentials: false persist-credentials: false
fetch-depth: 0 fetch-depth: 0
@@ -119,8 +119,9 @@ jobs:
contents: read contents: read
pull-requests: write pull-requests: write
steps: steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with: with:
persist-credentials: false persist-credentials: false
fetch-depth: 0 fetch-depth: 0

View File

@@ -32,14 +32,14 @@ jobs:
name: Generate Reports name: Generate Reports
steps: steps:
- name: Checkout Repository - name: Checkout Repository
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with: with:
persist-credentials: false persist-credentials: false
- name: Set up Node.js - name: Set up Node.js
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with: with:
node-version-file: "./superset-frontend/.nvmrc" node-version-file: './superset-frontend/.nvmrc'
- name: Install Dependencies - name: Install Dependencies
run: npm ci run: npm ci

View File

@@ -50,4 +50,3 @@ under the License.
- [4.1.4](./CHANGELOG/4.1.4.md) - [4.1.4](./CHANGELOG/4.1.4.md)
- [5.0.0](./CHANGELOG/5.0.0.md) - [5.0.0](./CHANGELOG/5.0.0.md)
- [6.0.0](./CHANGELOG/6.0.0.md) - [6.0.0](./CHANGELOG/6.0.0.md)
- [6.1.0](./CHANGELOG/6.1.0.md)

File diff suppressed because it is too large Load Diff

View File

@@ -29,7 +29,7 @@ ARG BUILD_TRANSLATIONS="false"
###################################################################### ######################################################################
# superset-node-ci used as a base for building frontend assets and CI # superset-node-ci used as a base for building frontend assets and CI
###################################################################### ######################################################################
FROM --platform=${BUILDPLATFORM} node:24-trixie-slim AS superset-node-ci FROM --platform=${BUILDPLATFORM} node:22-trixie-slim AS superset-node-ci
ARG BUILD_TRANSLATIONS ARG BUILD_TRANSLATIONS
ENV BUILD_TRANSLATIONS=${BUILD_TRANSLATIONS} ENV BUILD_TRANSLATIONS=${BUILD_TRANSLATIONS}
ARG DEV_MODE="false" # Skip frontend build in dev mode ARG DEV_MODE="false" # Skip frontend build in dev mode

View File

@@ -23,14 +23,11 @@ PYTHON=`command -v python3.11 || command -v python3.10`
install: superset pre-commit install: superset pre-commit
superset: superset:
# Bootstrap uv (the project's installer) into the active environment
pip install uv
# Install external dependencies # Install external dependencies
uv pip install -r requirements/development.txt pip install -r requirements/development.txt
# Install Superset in editable (development) mode # Install Superset in editable (development) mode
uv pip install -e . pip install -e .
# Create an admin user in your metadata database # Create an admin user in your metadata database
superset fab create-admin \ superset fab create-admin \
@@ -55,14 +52,11 @@ superset:
update: update-py update-js update: update-py update-js
update-py: update-py:
# Bootstrap uv (the project's installer) into the active environment
pip install uv
# Install external dependencies # Install external dependencies
uv pip install -r requirements/development.txt pip install -r requirements/development.txt
# Install Superset in editable (development) mode # Install Superset in editable (development) mode
uv pip install -e . pip install -e .
# Initialize the database # Initialize the database
superset db upgrade superset db upgrade
@@ -85,8 +79,7 @@ activate:
pre-commit: pre-commit:
# setup pre commit dependencies # setup pre commit dependencies
pip install uv pip3 install -r requirements/development.txt
uv pip install -r requirements/development.txt
pre-commit install pre-commit install
format: py-format js-format format: py-format js-format

View File

@@ -83,9 +83,6 @@ categories:
- name: Clark.de - name: Clark.de
url: https://clark.de/ url: https://clark.de/
- name: Cover Genius
url: https://covergenius.com/
- name: EnquiryLabs - name: EnquiryLabs
url: https://www.enquirylabs.co.uk url: https://www.enquirylabs.co.uk
@@ -95,10 +92,6 @@ categories:
- name: KarrotPay - name: KarrotPay
url: https://www.daangnpay.com/ url: https://www.daangnpay.com/
- name: NICE Actimize
url: https://www.niceactimize.com/
contributors: ["@stevensuting"]
- name: Remita - name: Remita
url: https://remita.net url: https://remita.net
contributors: ["@mujibishola"] contributors: ["@mujibishola"]
@@ -119,6 +112,9 @@ categories:
url: https://xendit.co/ url: https://xendit.co/
contributors: ["@LieAlbertTriAdrian"] contributors: ["@LieAlbertTriAdrian"]
- name: Cover Genius
url: https://covergenius.com/
Gaming: Gaming:
- name: Popoko VM Games Studio - name: Popoko VM Games Studio
url: https://popoko.live url: https://popoko.live
@@ -300,6 +296,7 @@ categories:
logo: hifadih.png logo: hifadih.png
contributors: ["@saintLaurent00"] contributors: ["@saintLaurent00"]
# Logo approved by @anmol-hpe on behalf of HPE
- name: HPE - name: HPE
url: https://www.hpe.com/in/en/home.html url: https://www.hpe.com/in/en/home.html
logo: hpe.png logo: hpe.png
@@ -399,10 +396,6 @@ categories:
url: https://www.techaudit.info url: https://www.techaudit.info
contributors: ["@ETselikov"] contributors: ["@ETselikov"]
- name: Tech Solution
url: https://www.tech-solution.com.ar/
contributors: ["@danteGiuliano", "@LeandroVallejos", "@McJaben", "@xJeree", "@zeo-return-null"]
- name: Tenable - name: Tenable
url: https://www.tenable.com url: https://www.tenable.com
contributors: ["@dflionis"] contributors: ["@dflionis"]
@@ -432,10 +425,6 @@ categories:
logo: userguiding.svg logo: userguiding.svg
contributors: ["@tzercin"] contributors: ["@tzercin"]
- name: Value Ad
url: https://bestpair.info/
contributors: ["@stevensuting"]
- name: Virtuoso QA - name: Virtuoso QA
url: https://www.virtuosoqa.com url: https://www.virtuosoqa.com
@@ -520,6 +509,10 @@ categories:
url: https://www.sunbird.org/ url: https://www.sunbird.org/
contributors: ["@eksteporg"] contributors: ["@eksteporg"]
- name: The GRAPH Network
url: https://thegraphnetwork.org/
contributors: ["@fccoelho"]
- name: Udemy - name: Udemy
url: https://www.udemy.com/ url: https://www.udemy.com/
contributors: ["@sungjuly"] contributors: ["@sungjuly"]
@@ -528,24 +521,7 @@ categories:
url: https://www.vipkid.com.cn/ url: https://www.vipkid.com.cn/
contributors: ["@illpanda"] contributors: ["@illpanda"]
Social Organization: - name: WikiMedia Foundation
- name: Living Goods
url: https://www.livinggoods.org
contributors: ["@chelule"]
- name: One Acre Fund
url: https://oneacrefund.org/
contributors: ["@stevensuting"]
- name: Quest Alliance
url: https://www.questalliance.net/
contributors: ["@stevensuting"]
- name: The GRAPH Network
url: https://thegraphnetwork.org/
contributors: ["@fccoelho"]
- name: Wikimedia Foundation
url: https://wikimediafoundation.org url: https://wikimediafoundation.org
contributors: ["@vg"] contributors: ["@vg"]
@@ -558,10 +534,6 @@ categories:
url: https://www.douroeci.com/ url: https://www.douroeci.com/
contributors: ["@nunohelibeires"] contributors: ["@nunohelibeires"]
- name: Rogow
url: https://rogow.com.br/
contributors: ["@nilmonto"]
- name: Safaricom - name: Safaricom
url: https://www.safaricom.co.ke/ url: https://www.safaricom.co.ke/
contributors: ["@mmutiso"] contributors: ["@mmutiso"]
@@ -574,10 +546,11 @@ categories:
url: https://wattbewerb.de/ url: https://wattbewerb.de/
contributors: ["@wattbewerb"] contributors: ["@wattbewerb"]
Healthcare: - name: Rogow
- name: 2070Health url: https://rogow.com.br/
url: https://2070health.com/ contributors: ["@nilmonto"]
Healthcare:
- name: Amino - name: Amino
url: https://amino.com url: https://amino.com
contributors: ["@shkr"] contributors: ["@shkr"]
@@ -590,6 +563,10 @@ categories:
url: https://www.getcare.io/ url: https://www.getcare.io/
contributors: ["@alandao2021"] contributors: ["@alandao2021"]
- name: Living Goods
url: https://www.livinggoods.org
contributors: ["@chelule"]
- name: Maieutical Labs - name: Maieutical Labs
url: https://maieuticallabs.it url: https://maieuticallabs.it
contributors: ["@xrmx"] contributors: ["@xrmx"]
@@ -608,10 +585,10 @@ categories:
- name: WeSure - name: WeSure
url: https://www.wesure.cn/ url: https://www.wesure.cn/
HR / Staffing: - name: 2070Health
- name: bluquist url: https://2070health.com/
url: https://bluquist.com/
HR / Staffing:
- name: Swile - name: Swile
url: https://www.swile.co/ url: https://www.swile.co/
contributors: ["@PaoloTerzi"] contributors: ["@PaoloTerzi"]
@@ -619,18 +596,21 @@ categories:
- name: Symmetrics - name: Symmetrics
url: https://www.symmetrics.fyi url: https://www.symmetrics.fyi
- name: bluquist
url: https://bluquist.com/
Government: Government:
- name: City of Ann Arbor, MI - name: City of Ann Arbor, MI
url: https://www.a2gov.org/ url: https://www.a2gov.org/
contributors: ["@sfirke"] contributors: ["@sfirke"]
- name: NRLM - Sarathi, India
url: https://pib.gov.in/PressReleasePage.aspx?PRID=1999586
- name: RIS3 Strategy of CZ, MIT CR - name: RIS3 Strategy of CZ, MIT CR
url: https://www.ris3.cz/ url: https://www.ris3.cz/
contributors: ["@RIS3CZ"] contributors: ["@RIS3CZ"]
- name: NRLM - Sarathi, India
url: https://pib.gov.in/PressReleasePage.aspx?PRID=1999586
Mobile Software: Mobile Software:
- name: VLMedia - name: VLMedia
url: https://www.vlmedia.com.tr url: https://www.vlmedia.com.tr

View File

@@ -24,67 +24,6 @@ assists people when migrating to a new version.
## Next ## Next
### Pivot table First/Last aggregations follow data order
The pivot table chart's `First` and `Last` aggregations now return the first and last value in data (query result) order, instead of effectively returning the minimum and maximum. Existing pivot tables that use these aggregations for totals/subtotals may show different values after upgrading. For deterministic results, ensure the underlying query has a stable sort order.
### `thumbnail_url` removed from dashboard list API response
The `thumbnail_url` field has been removed from `GET /api/v1/dashboard/` list responses. External consumers relying on this field must now construct the thumbnail URL client-side using `id` and `changed_on_utc`:
```
/api/v1/dashboard/{id}/thumbnail/{changed_on_utc}/
```
The thumbnail endpoint redirects to the current digest URL regardless of whether the supplied digest is exact. If the image is not yet cached, that digest URL may return `202` and trigger async generation. Using `changed_on_utc` as the digest is sufficient for cache-busting purposes.
### Webhook alerts/reports block private/internal hosts by default
Webhook alert/report dispatch (`WebhookNotification.send`) now validates the target URL's host against the same private/internal-IP block applied to dataset import URLs. If the resolved host is in a loopback, link-local, private (RFC-1918), shared-CGNAT, or multicast range, the webhook is rejected with `NotificationParamException`.
Deployments that intentionally point webhooks at internal targets (chatops bridges, internal automation servers, on-premises Mattermost/Rocket.Chat, etc.) can opt out by setting `ALERT_REPORTS_WEBHOOK_ALLOW_INTERNAL_HOSTS = True` in `superset_config.py`. This mirrors the existing `DATASET_IMPORT_ALLOW_INTERNAL_DATA_URLS` opt-out for dataset imports.
### Impala cancel_query blocks private/internal hosts by default
The Impala engine spec's `cancel_query` issues an HTTP request from the Superset backend to the host configured on the Impala database connection. That host is now validated before the request: if it resolves to a private/internal IP range, the cancel call is refused and a warning is logged. Operators whose Impala cluster runs on an internal network can opt out by setting `IMPALA_CANCEL_QUERY_ALLOW_INTERNAL_HOSTS = True` in `superset_config.py`. This mirrors the dataset-import and webhook opt-out flags.
### Map chart renderer and OpenStreetMap migration behavior
The MapLibre migration for deck.gl charts preserves saved non-Mapbox styles on
the MapLibre-compatible path. Saved styles such as OpenStreetMap, `tile://`
tile templates, generic HTTPS style URLs, and charts without a saved style are
not reclassified as Mapbox during migration and do not require
`MAPBOX_API_KEY` only because of the migration.
Saved true Mapbox styles whose value starts with `mapbox://` remain
Mapbox-backed. If a Superset deployment does not configure `MAPBOX_API_KEY`,
those saved Mapbox charts keep the existing missing-key message instead of
silently falling back to MapLibre or another provider. In Explore, deck.gl and
point-cluster renderer controls preserve saved Mapbox state, but the Mapbox
choice is not available as a new working renderer without a configured key.
The MapLibre style choices include `Streets (OSM)`, backed by
`https://tile.openstreetmap.org/{z}/{x}/{y}.png`. This OpenStreetMap tile
service requires visible `© OpenStreetMap contributors` attribution and should
be used through normal browser map tile requests and caching; it is not intended
for bulk prefetch or offline tile downloads.
### Password complexity policy enabled by default
Superset now ships a default password-complexity policy, enforced (via Flask-AppBuilder) across self-registration, the user create/edit/reset forms, and the User REST API. The policy requires a minimum password length of 8 characters and rejects a built-in blocklist of common/guessable passwords.
This is enabled by default (`FAB_PASSWORD_COMPLEXITY_ENABLED = True`), so new or reset passwords that are too short or appear in the blocklist will be rejected where they were previously accepted. Existing stored passwords are unaffected until they are next changed.
Operators can tune or disable the policy via config:
- `AUTH_PASSWORD_MIN_LENGTH` — minimum length (default `8`).
- `AUTH_PASSWORD_COMMON_BLOCKLIST` — extra passwords to reject, in addition to the built-in list.
- `FAB_PASSWORD_COMPLEXITY_VALIDATOR` — replace with your own callable for custom rules.
- `FAB_PASSWORD_COMPLEXITY_ENABLED = False` — disable enforcement entirely.
### Data uploads bounded by UPLOAD_MAX_FILE_SIZE_BYTES
Single data-file uploads (CSV, Excel, columnar) are now bounded by the `UPLOAD_MAX_FILE_SIZE_BYTES` config option, which defaults to `100 * 1024 * 1024` (100 MB). Files larger than this are rejected with a `413` before their contents are buffered into memory. Set `UPLOAD_MAX_FILE_SIZE_BYTES = None` to disable the check and restore unbounded uploads.
### Duration formatter precision ### Duration formatter precision
The `DURATION` number formatter now uses `Intl.DurationFormat` for locale-aware output. By default, sub-second fields are omitted, so values that previously displayed fractional seconds with `pretty-ms`, such as `10500` milliseconds rendering as `10.5s`, now render as `10s`. The `DURATION` number formatter now uses `Intl.DurationFormat` for locale-aware output. By default, sub-second fields are omitted, so values that previously displayed fractional seconds with `pretty-ms`, such as `10500` milliseconds rendering as `10.5s`, now render as `10s`.
@@ -119,36 +58,6 @@ GLOBAL_ASYNC_QUERIES_JWT_SECRET = "<output of: openssl rand -base64 42>"
The check is only active when the relevant feature is enabled, so deployments that do not use global async queries (or embedding) are not affected. The check is only active when the relevant feature is enabled, so deployments that do not use global async queries (or embedding) are not affected.
### Guest token revocation (opt-in)
Embedded guest tokens can be coarsely revoked at runtime via a new opt-in mechanism. A new config flag `GUEST_TOKEN_REVOCATION_ENABLED` (default `False`) gates the feature. When enabled, every minted guest token carries a revocation version, and tokens whose version is below the current expected version (stored in the metadata database) are rejected at validation time.
Bump the expected version with the new CLI command to invalidate all outstanding guest tokens:
```bash
superset revoke-guest-tokens
```
This change is backward compatible. The feature is off by default, and even when enabled nothing is revoked until an admin explicitly bumps the version: the expected version starts at `0`, and tokens minted before this change (which carry no version claim) are treated as version `0`. No database migration is required.
### Sessions are terminated when an account is disabled
Disabling a user account (setting `active` to `False`, via the admin UI, REST API, or CLI) now terminates that user's outstanding sessions on their next request, instead of relying on a passive check. This works for both client-side cookie sessions and server-side session stores via a per-user invalidation epoch (`user_attribute.sessions_invalidated_at`, added by a migration). The mechanism is inert for users that were never disabled (NULL epoch), so there is no behavior change for active users. Re-enabling an account and logging in again starts a fresh, valid session. The migration backfills the epoch for accounts that are already disabled at upgrade time, so re-enabling such an account does not revive a session that predates this feature.
### Opt-in SSH tunnel server host key verification
SSH tunnels can now optionally pin the expected SSH server host key as a defense-in-depth measure against man-in-the-middle attacks. paramiko's transport performs no known-hosts checking by default, so previously the SSH server's identity was not verified. This feature is opt-in and off by default; existing tunnels are unaffected.
- A new nullable `server_host_key` column on the `ssh_tunnels` table stores the expected host key in authorized-key form (e.g. `ssh-ed25519 AAAA...`). It is a public key and is stored in plaintext. It can be set via the SSH tunnel POST/PUT payloads (`ssh_tunnel.server_host_key`).
- When a tunnel has `server_host_key` set, Superset connects to the SSH server, reads the host key it presents, and rejects the tunnel if it does not match.
- A new config flag `SSH_TUNNEL_STRICT_HOST_KEY_CHECKING` (default `False`) controls fail-closed behavior. When `True`, every tunnel must declare a `server_host_key`; a tunnel without one is rejected.
Runbook to adopt:
1. Capture the SSH server's host key, e.g. `ssh-keyscan -t ed25519 ssh.example.com` (verify it out-of-band).
2. Set that value on the tunnel's `server_host_key` (via the database/SSH tunnel API or UI payload).
3. Optionally set `SSH_TUNNEL_STRICT_HOST_KEY_CHECKING = True` in `superset_config.py` to require host-key verification on all tunnels.
### Dataset import validates catalog against the target connection ### Dataset import validates catalog against the target connection
Importing a dataset now validates the `catalog` field against the target database connection. When the connection has multi-catalog disabled (`allow_multi_catalog` off) and the dataset's catalog is not the connection's default catalog, the import fails instead of silently persisting the non-default catalog. This matches the validation already enforced on the dataset update path and prevents imported datasets from querying an unintended database. Importing a dataset now validates the `catalog` field against the target database connection. When the connection has multi-catalog disabled (`allow_multi_catalog` off) and the dataset's catalog is not the connection's default catalog, the import fails instead of silently persisting the non-default catalog. This matches the validation already enforced on the dataset update path and prevents imported datasets from querying an unintended database.
@@ -168,36 +77,6 @@ Both default to empty (no behavior change). They apply to both the `LOCAL_EXTENS
The Dynamic Group By chart customization now orders its display values according to the "Sort display control values" toggle: ascending (AZ), descending (ZA), or the dataset's source order when the toggle is unset. Previously the dropdown always sorted alphabetically. Existing dashboards where the toggle was never set will show options in source order instead of AZ; open the customization and enable the toggle to restore alphabetical ordering. The Dynamic Group By chart customization now orders its display values according to the "Sort display control values" toggle: ascending (AZ), descending (ZA), or the dataset's source order when the toggle is unset. Previously the dropdown always sorted alphabetically. Existing dashboards where the toggle was never set will show options in source order instead of AZ; open the customization and enable the toggle to restore alphabetical ordering.
### Selectable encryption engine for app-encrypted fields (AES-GCM)
App-encrypted fields (database passwords, SSH tunnel credentials, OAuth tokens, etc.) can now use authenticated **AES-GCM** encryption instead of the historical unauthenticated **AES-CBC**. A new config selects the engine for the default adapter:
```python
# "aes" (AES-CBC, historical default) | "aes-gcm" (authenticated, recommended for new installs)
SQLALCHEMY_ENCRYPTED_FIELD_ENGINE = "aes"
```
**No action required / no behavior change:** the default remains `"aes"`, so existing installs are unaffected.
**Opting in on an existing install:** flipping the engine on a populated database without re-encrypting first will make stored secrets undecryptable, because the two ciphertext formats are not compatible. A migrator is provided. Recommended runbook:
1. Take a metadata-DB backup.
2. Re-encrypt existing secrets into the new engine (the `SECRET_KEY` is unchanged):
```bash
superset re-encrypt-secrets --engine aes-gcm
```
3. Set `SQLALCHEMY_ENCRYPTED_FIELD_ENGINE = "aes-gcm"` in your config.
4. Restart Superset.
5. Re-run the migrator once more after the restart:
```bash
superset re-encrypt-secrets --engine aes-gcm
```
A live instance keeps writing *new* secrets as AES-CBC during the window between step 2 and the restart in step 4; this second pass sweeps those up (it is idempotent, so already-migrated values are skipped).
Schedule the cutover in a quiet window. Runtime reads use only the single configured engine, so in a multi-worker deployment there is an unavoidable brief decrypt-outage between the migration commit and the last worker restarting with the new config — each migrator run is transactional, but the fleet-wide cutover is not zero-downtime.
The migration is transactional (all-or-nothing) and idempotent — it can be safely re-run or resumed. Note that AES-GCM, unlike AES-CBC, does not support querying directly over encrypted columns; audit any code that filters on an encrypted column before switching. See the SIP at `docs/sip/authenticated-encryption-at-rest.md` for details.
### Granular Export Controls ### Granular Export Controls
A new feature flag `GRANULAR_EXPORT_CONTROLS` introduces three fine-grained permissions that replace the legacy `can_csv` permission: A new feature flag `GRANULAR_EXPORT_CONTROLS` introduces three fine-grained permissions that replace the legacy `can_csv` permission:
@@ -227,9 +106,6 @@ Added a new combined datasource list endpoint at `GET /api/v1/datasource/` to se
- The endpoint is available to users with at least one of `can_read` on `Dataset` or `SemanticView`. - The endpoint is available to users with at least one of `can_read` on `Dataset` or `SemanticView`.
- Semantic views are included only when the `SEMANTIC_LAYERS` feature flag is enabled. - Semantic views are included only when the `SEMANTIC_LAYERS` feature flag is enabled.
- The endpoint enforces strict `order_column` validation and returns `400` for invalid sort columns. - The endpoint enforces strict `order_column` validation and returns `400` for invalid sort columns.
## 6.1.0
### ClickHouse minimum driver version bump ### ClickHouse minimum driver version bump
The minimum required version of `clickhouse-connect` has been raised to `>=0.13.0`. If you are using the ClickHouse connector, please upgrade your `clickhouse-connect` package. The `_mutate_label` workaround that appended hash suffixes to column aliases has also been removed, as it is no longer needed with modern versions of the driver. The minimum required version of `clickhouse-connect` has been raised to `>=0.13.0`. If you are using the ClickHouse connector, please upgrade your `clickhouse-connect` package. The `_mutate_label` workaround that appended hash suffixes to column aliases has also been removed, as it is no longer needed with modern versions of the driver.

View File

@@ -72,23 +72,20 @@ services:
- -c - -c
- | - |
url="http://host.docker.internal:9000/static/assets/manifest.json" url="http://host.docker.internal:9000/static/assets/manifest.json"
max_attempts=300 # ~10 minutes at 2s intervals; first build can be slow max_attempts=150 # ~5 minutes at 2s intervals
echo "Waiting for webpack dev server at $$url..." echo "Waiting for webpack dev server at $url..."
attempt=0 attempt=0
until curl -sf --max-time 5 -H "Host: localhost" -o /dev/null "$$url"; do until curl -sf --max-time 5 -o /dev/null "$url"; do
attempt=$$((attempt + 1)) attempt=$((attempt + 1))
if [ "$$attempt" -ge "$$max_attempts" ]; then if [ "$attempt" -ge "$max_attempts" ]; then
echo "ERROR: webpack dev server did not serve $$url after $$max_attempts attempts." >&2 echo "ERROR: webpack dev server did not serve $url after $max_attempts attempts (~5 minutes)." >&2
echo "Is the dev server running? With BUILD_SUPERSET_FRONTEND_IN_DOCKER=false you must start it on the host (e.g. 'npm run dev' in superset-frontend)." >&2 echo "Is the dev server running? With BUILD_SUPERSET_FRONTEND_IN_DOCKER=false you must start it on the host (e.g. 'npm run dev' in superset-frontend)." >&2
exit 1 exit 1
fi fi
if [ $$((attempt % 15)) -eq 0 ]; then
echo "Still waiting for webpack dev server... ($$attempt/$$max_attempts)"
fi
sleep 2 sleep 2
done done
echo "Webpack dev server is ready; starting nginx." echo "Webpack dev server is ready; starting nginx."
exec /docker-entrypoint.sh nginx -g 'daemon off;' exec nginx -g 'daemon off;'
redis: redis:
image: redis:7 image: redis:7

View File

@@ -71,29 +71,27 @@ case "${1}" in
worker) worker)
echo "Starting Celery worker..." echo "Starting Celery worker..."
# setting up only 2 workers by default to contain memory usage in dev environments # setting up only 2 workers by default to contain memory usage in dev environments
celery --app=superset.tasks.celery_app:app worker -O fair -l INFO --concurrency=${CELERYD_CONCURRENCY:-2} ${WORKER_LOG_FILE:+--logfile=$WORKER_LOG_FILE} celery --app=superset.tasks.celery_app:app worker -O fair -l INFO --concurrency=${CELERYD_CONCURRENCY:-2}
;; ;;
beat) beat)
echo "Starting Celery beat..." echo "Starting Celery beat..."
rm -f /tmp/celerybeat.pid rm -f /tmp/celerybeat.pid
celery --app=superset.tasks.celery_app:app beat --pidfile /tmp/celerybeat.pid -l INFO -s "${SUPERSET_HOME}"/celerybeat-schedule ${BEAT_LOG_FILE:+--logfile=$BEAT_LOG_FILE} celery --app=superset.tasks.celery_app:app beat --pidfile /tmp/celerybeat.pid -l INFO -s "${SUPERSET_HOME}"/celerybeat-schedule
;; ;;
app) app)
echo "Starting web app (using development server)..." echo "Starting web app (using development server)..."
# Default to Flask debug mode in this dev compose entrypoint so the Talisman # Environment-based debugger control for security
# dev CSP (which permits 'unsafe-eval' required by React Refresh / HMR) is # Only enable Werkzeug interactive debugger when explicitly requested
# served. Operators can still set FLASK_DEBUG=false in docker/.env-local # Modern Werkzeug (3.0+) includes PIN protection, but defense-in-depth approach
# to exercise the production-like CSP and error handling. # Override FLASK_DEBUG so the effective state matches SUPERSET_DEBUG_ENABLED even
: "${FLASK_DEBUG:=1}" # when FLASK_DEBUG=true is inherited from docker/.env or .flaskenv
export FLASK_DEBUG
# Werkzeug's interactive debugger (/console) is a separate, security-sensitive
# feature and must be opted into explicitly via SUPERSET_DEBUG_ENABLED=true.
if [[ "${SUPERSET_DEBUG_ENABLED:-}" == "true" ]]; then if [[ "${SUPERSET_DEBUG_ENABLED:-}" == "true" ]]; then
export FLASK_DEBUG=1
DEBUGGER_FLAG="--debugger" DEBUGGER_FLAG="--debugger"
echo " ⚠️ Werkzeug debugger enabled (requires PIN for /console access)" echo " ⚠️ Werkzeug debugger enabled (requires PIN for /console access)"
else else
export FLASK_DEBUG=0
DEBUGGER_FLAG="--no-debugger" DEBUGGER_FLAG="--no-debugger"
echo " 🔒 Werkzeug debugger disabled (set SUPERSET_DEBUG_ENABLED=true to enable)" echo " 🔒 Werkzeug debugger disabled (set SUPERSET_DEBUG_ENABLED=true to enable)"
fi fi

View File

@@ -19,7 +19,7 @@
# #
HYPHEN_SYMBOL='-' HYPHEN_SYMBOL='-'
exec gunicorn \ gunicorn \
--bind "${SUPERSET_BIND_ADDRESS:-0.0.0.0}:${SUPERSET_PORT:-8088}" \ --bind "${SUPERSET_BIND_ADDRESS:-0.0.0.0}:${SUPERSET_PORT:-8088}" \
--access-logfile "${ACCESS_LOG_FILE:-$HYPHEN_SYMBOL}" \ --access-logfile "${ACCESS_LOG_FILE:-$HYPHEN_SYMBOL}" \
--error-logfile "${ERROR_LOG_FILE:-$HYPHEN_SYMBOL}" \ --error-logfile "${ERROR_LOG_FILE:-$HYPHEN_SYMBOL}" \

View File

@@ -1 +1 @@
v24.16.0 v22.22.0

View File

@@ -455,51 +455,6 @@ def FLASK_APP_MUTATOR(app: Flask) -> None:
app.before_request_funcs.setdefault(None, []).append(make_session_permanent) app.before_request_funcs.setdefault(None, []).append(make_session_permanent)
``` ```
## Customizing the landing page (index view)
The page served at `/` is rendered by an index view. By default Superset registers
`SupersetIndexView`, which redirects to `/superset/welcome/` and also adds the
`/lang/<locale>` locale handler. You can replace it with your own view, for example
to send users straight to a specific dashboard or to a chart list.
Set `FAB_INDEX_VIEW` to the **importable dotted path** of your view class. Flask-AppBuilder
resolves this during app initialization and uses it in place of the default:
```python
# my_overrides.py — must be importable on the PYTHONPATH
from flask import redirect
from superset.initialization import SupersetIndexView
from superset.superset_typing import FlaskResponse
from flask_appbuilder import expose
class MyIndexView(SupersetIndexView):
@expose("/")
def index(self) -> FlaskResponse:
return redirect("/chart/list/")
```
```python
# superset_config.py
FAB_INDEX_VIEW = "my_overrides.MyIndexView"
```
A few things that commonly trip people up:
- **Subclass `SupersetIndexView`, not Flask-AppBuilder's bare `IndexView`.** Subclassing
keeps Superset's `/lang/<locale>` locale handling; replacing it with a bare `IndexView`
silently drops that behavior.
- **The class must be importable as a real module.** `FAB_INDEX_VIEW` is resolved by
importing the dotted path, which is independent of how `superset_config.py` itself is
loaded. Superset only copies **uppercase** names out of `superset_config.py` into its
runtime config, so a `FAB_INDEX_VIEW = "superset_config.MyIndexView"` reference only works
if `superset_config` is itself importable by that name on the `PYTHONPATH`. If you load
config via `SUPERSET_CONFIG_PATH` (an arbitrary file path), put the view in a separate
importable module instead and reference that module.
- **Don't set `appbuilder.indexview` from `FLASK_APP_MUTATOR`.** The mutator runs after
routes are already registered, so the assignment has no effect on the `/` route. Use
`FAB_INDEX_VIEW` instead.
## Feature Flags ## Feature Flags
To support a diverse set of users, Superset has some features that are not enabled by default. For To support a diverse set of users, Superset has some features that are not enabled by default. For

View File

@@ -22,24 +22,31 @@ level dependencies.
**Debian and Ubuntu** **Debian and Ubuntu**
The following command will ensure that the required dependencies are installed (tested on Ubuntu 20.04, 22.04, and 24.04): Ubuntu **24.04** uses python 3.12 per default, which currently is not supported by Superset. You need to add a second python installation of 3.11 and install the required additional dependencies.
```bash ```bash
sudo apt-get install build-essential libssl-dev libffi-dev python3-dev python3-pip python3-venv libsasl2-dev libldap2-dev libpq-dev default-libmysqlclient-dev pkg-config sudo add-apt-repository ppa:deadsnakes/ppa
sudo apt update
sudo apt install python3.11 python3.11-dev python3.11-venv build-essential libssl-dev libffi-dev libsasl2-dev libldap2-dev default-libmysqlclient-dev
``` ```
Refer to the In Ubuntu **20.04 and 22.04** the following command will ensure that the required dependencies are installed:
[pyproject.toml](https://github.com/apache/superset/blob/master/pyproject.toml) file for the list of
Python versions officially supported by Superset, and install a matching `python3` interpreter for ```bash
your distribution. The `libpq-dev` package is only needed if you intend to connect to (or use) a sudo apt-get install build-essential libssl-dev libffi-dev python3-dev python3-pip libsasl2-dev libldap2-dev default-libmysqlclient-dev
PostgreSQL database; you can omit it otherwise. ```
In Ubuntu **before 20.04** the following command will ensure that the required dependencies are installed:
```bash
sudo apt-get install build-essential libssl-dev libffi-dev python-dev python-pip libsasl2-dev libldap2-dev default-libmysqlclient-dev
```
**Fedora and RHEL-derivative Linux distributions** **Fedora and RHEL-derivative Linux distributions**
Install the following packages using the `yum` package manager: Install the following packages using the `yum` package manager:
```bash ```bash
sudo yum install gcc gcc-c++ libffi-devel python3-devel python3-pip python3-wheel openssl-devel cyrus-sasl-devel openldap-devel sudo yum install gcc gcc-c++ libffi-devel python-devel python-pip python-wheel openssl-devel cyrus-sasl-devel openldap-devel
``` ```
In more recent versions of CentOS and Fedora, you may need to install a slightly different set of packages using `dnf`: In more recent versions of CentOS and Fedora, you may need to install a slightly different set of packages using `dnf`:

View File

@@ -28,19 +28,14 @@
# Skip builds when no docs changes (exit 0 = skip, non-zero = build). # Skip builds when no docs changes (exit 0 = skip, non-zero = build).
# Checks for changes in docs/ and README.md (which gets pulled into docs). # Checks for changes in docs/ and README.md (which gets pulled into docs).
# #
# $CACHED_COMMIT_REF is the last *deployed* commit; it is set on incremental # $CACHED_COMMIT_REF is the last *deployed* commit. On a PR's first build it
# builds (notably the master production deploy) and empty on a context's # is empty, so the original `git diff` errored and Netlify fell back to
# first build (every deploy preview). The production path diffs against it # building -- which is why every PR built a docs preview once even with no
# and skips correctly. # docs changes. When it is empty we instead diff the whole branch against its
# # merge-base with master, so non-docs PRs are skipped from the very first
# Deploy previews need different handling: Netlify checks out a *merge* # build. Subsequent builds (and the master production build) keep the cheaper
# commit, so $COMMIT_REF (the PR head SHA) is frequently not resolvable in # incremental $CACHED_COMMIT_REF diff. Any failure exits non-zero -> build.
# the clone, and on a shallow clone `git merge-base` can fail too -- so the ignore = 'if [ -n "$CACHED_COMMIT_REF" ]; then git diff --quiet "$CACHED_COMMIT_REF" "$COMMIT_REF" -- . ../README.md; else git fetch origin master --depth=100 >/dev/null 2>&1; git diff --quiet "$(git merge-base origin/master "$COMMIT_REF" 2>/dev/null || echo origin/master)" "$COMMIT_REF" -- . ../README.md; fi'
# previous logic fell through to a build on every PR, even non-docs ones.
# Instead, always diff the checked-out HEAD against its merge-base with
# master, deepening the shallow clone until that merge-base resolves. If it
# genuinely can't be determined, exit non-zero to build (fail safe).
ignore = 'if [ -n "$CACHED_COMMIT_REF" ]; then git diff --quiet "$CACHED_COMMIT_REF" HEAD -- . ../README.md; else git fetch --no-tags origin master >/dev/null 2>&1 || true; i=0; while [ "$i" -lt 10 ] && ! git merge-base origin/master HEAD >/dev/null 2>&1; do git fetch --deepen=200 origin master >/dev/null 2>&1 || break; i=$((i+1)); done; BASE="$(git merge-base origin/master HEAD 2>/dev/null || true)"; if [ -z "$BASE" ]; then exit 1; fi; git diff --quiet "$BASE" HEAD -- . ../README.md; fi'
[build.environment] [build.environment]
# Node version matching docs/.nvmrc # Node version matching docs/.nvmrc

View File

@@ -70,10 +70,10 @@
"@storybook/preview-api": "^8.6.18", "@storybook/preview-api": "^8.6.18",
"@storybook/theming": "^8.6.15", "@storybook/theming": "^8.6.15",
"@superset-ui/core": "^0.20.4", "@superset-ui/core": "^0.20.4",
"@swc/core": "^1.15.41", "@swc/core": "^1.15.40",
"antd": "^6.4.4", "antd": "^6.4.3",
"baseline-browser-mapping": "^2.10.37", "baseline-browser-mapping": "^2.10.33",
"caniuse-lite": "^1.0.30001799", "caniuse-lite": "^1.0.30001793",
"docusaurus-plugin-openapi-docs": "^5.0.2", "docusaurus-plugin-openapi-docs": "^5.0.2",
"docusaurus-theme-openapi-docs": "^5.0.2", "docusaurus-theme-openapi-docs": "^5.0.2",
"js-yaml": "^4.2.0", "js-yaml": "^4.2.0",
@@ -101,15 +101,15 @@
"@types/js-yaml": "^4.0.9", "@types/js-yaml": "^4.0.9",
"@types/react": "^19.1.8", "@types/react": "^19.1.8",
"@typescript-eslint/eslint-plugin": "^8.59.3", "@typescript-eslint/eslint-plugin": "^8.59.3",
"@typescript-eslint/parser": "^8.61.0", "@typescript-eslint/parser": "^8.60.0",
"eslint": "^9.39.2", "eslint": "^9.39.2",
"eslint-config-prettier": "^10.1.8", "eslint-config-prettier": "^10.1.8",
"eslint-plugin-prettier": "^5.5.6", "eslint-plugin-prettier": "^5.5.6",
"eslint-plugin-react": "^7.37.5", "eslint-plugin-react": "^7.37.5",
"globals": "^17.6.0", "globals": "^17.6.0",
"prettier": "^3.8.4", "prettier": "^3.8.3",
"typescript": "~6.0.3", "typescript": "~6.0.3",
"typescript-eslint": "^8.61.1", "typescript-eslint": "^8.60.0",
"webpack": "^5.107.2" "webpack": "^5.107.2"
}, },
"browserslist": { "browserslist": {

View File

@@ -1,136 +0,0 @@
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
# SIP: Authenticated encryption (AES-GCM) for app-encrypted fields
## [DRAFT — proposal for discussion]
This document is a draft proposal accompanying the code in this PR. It is
intended to seed the formal SIP discussion. The code here ships the
backward-compatible engine selection **and** the re-encryption migrator
(Phases 12 below); both are opt-in and change nothing for existing installs by
default. Flipping the default for fresh installs (Phase 3) remains future work.
## Motivation
Superset app-encrypts a number of sensitive fields before persisting them to
the metadata database, including:
- database connection passwords and `encrypted_extra` (`superset/models/core.py`),
- SSH tunnel credentials — password, private key, private-key password
(`superset/databases/ssh_tunnel/models.py`),
- OAuth2 tokens and other secrets stored via `EncryptedType`.
These fields are encrypted with `sqlalchemy_utils.EncryptedType`, which
**defaults to `AesEngine` (AES-CBC)**. AES-CBC provides confidentiality but is
**unauthenticated**: it has no integrity tag. An attacker with write access to
the ciphertext (e.g. direct metadata-DB access, a backup, or a compromised
replica) can perform **bit-flipping / chosen-ciphertext manipulation** to
silently alter the decrypted plaintext of a secret without detection.
`AesGcmEngine` (AES-GCM) is authenticated encryption: tampering causes
decryption to fail loudly rather than yielding attacker-influenced plaintext.
Using authenticated encryption for secrets at rest is an ASVS L1 expectation
(11.3.2 / cryptography best practice).
`config.py` already documents that operators *can* switch to GCM by writing a
custom `AbstractEncryptedFieldAdapter`, but:
1. it is opt-in, undocumented as a security recommendation, and easy to miss;
2. there is **no migration path** — flipping the engine on a populated database
makes every existing secret undecryptable, because GCM ciphertext is not
format-compatible with CBC.
## Proposed change
A three-part change, delivered incrementally so existing deployments are never
broken:
### Phase 1 — engine selection (this PR)
- Add a `SQLALCHEMY_ENCRYPTED_FIELD_ENGINE` config (`"aes"` | `"aes-gcm"`),
**defaulting to `"aes"`** (no behavior change for existing installs).
- Teach the default `SQLAlchemyUtilsAdapter` to honor it (an explicit `engine`
kwarg still wins, so the migrator can pin an engine).
- This lets **new** deployments choose AES-GCM from day one with a one-line
config, instead of writing a custom adapter.
### Phase 2 — CBC→GCM re-encryption migrator (this PR)
The existing `SecretsMigrator` (previously only used for `SECRET_KEY` rotation)
gains an **engine migration** mode that:
1. discovers every `EncryptedType` column (via `discover_encrypted_fields()`),
2. decrypts each value with the **source** engine (AES-CBC) under the current
`SECRET_KEY`,
3. re-encrypts with the **target** engine (AES-GCM),
4. runs transactionally per the existing all-or-nothing semantics, and is
idempotent per column (already-migrated values are skipped), so a run can be
safely repeated or resumed.
Exposed via a new `--engine` option on the existing CLI command:
`superset re-encrypt-secrets --engine aes-gcm`, runnable by operators with a DB
backup in hand. The `SECRET_KEY` is unchanged; an engine change and a key
rotation can also be combined (pass `--previous_secret_key` as well).
### Phase 3 — flip the default for new installs
Once the migrator and docs are in place, change the default to `"aes-gcm"` for
**fresh** installs only (e.g. keyed off an empty metadata DB / documented in
`UPDATING.md`), keeping existing installs on `"aes"` until they run Phase 2.
## New or changed public interfaces
- New config: `SQLALCHEMY_ENCRYPTED_FIELD_ENGINE: Literal["aes", "aes-gcm"]`.
- New (Phase 2) CLI: `superset re-encrypt-secrets --engine <name>`.
- No schema changes; ciphertext format changes per migrated column.
## Migration plan and compatibility
- **Backward compatible by default.** Phase 1 changes nothing unless the
operator opts in.
- Switching an existing deployment to `"aes-gcm"` **without** running the Phase
2 migrator will make existing secrets undecryptable — this is called out in
the config comment and must be in `UPDATING.md`.
- Recommended operator runbook: take a metadata-DB backup → run
`re-encrypt-secrets --engine aes-gcm` → set
`SQLALCHEMY_ENCRYPTED_FIELD_ENGINE = "aes-gcm"` → restart → re-run
`re-encrypt-secrets --engine aes-gcm` once more to sweep up any secrets a live
instance wrote as AES-CBC during the cutover window. The canonical, more
detailed version of this runbook lives in `UPDATING.md`; this is a summary.
- `AesEngine` allows queryability over encrypted fields; AES-GCM does not.
Any code that filters/queries on an encrypted column directly must be audited
before Phase 3 (none is expected, but it must be verified).
## Rejected alternatives
- **Flip the default immediately.** Rejected: bricks every existing
deployment's secrets with no migration path.
- **Document-only (custom adapter).** Status quo; high friction and no
migration tooling — most operators will never do it.
## Open questions
- GCM→CBC rollback (for operators who need queryability) already works via the
same command (`re-encrypt-secrets --engine aes`), since the migrator is
engine-symmetric. Should rollback be documented as a supported path or
discouraged?
- The migrator already supports a concurrent `SECRET_KEY` rotation + engine
change in a single pass (pass `--previous_secret_key` alongside `--engine`).
Is that combination worth calling out in the operator docs, or kept advanced?

View File

@@ -7235,10 +7235,10 @@
"pypi_packages": [ "pypi_packages": [
"oracledb" "oracledb"
], ],
"connection_string": "oracle+oracledb://{username}:{password}@{hostname}:{port}", "connection_string": "oracle://{username}:{password}@{hostname}:{port}",
"default_port": 1521, "default_port": 1521,
"notes": "Previously used cx_Oracle, now uses oracledb.", "notes": "Previously used cx_Oracle, now uses oracledb.",
"docs_url": "https://python-oracledb.readthedocs.io/en/latest/user_guide/installation.html", "docs_url": "https://cx-oracle.readthedocs.io/en/latest/user_guide/installation.html",
"category": "Other Databases" "category": "Other Databases"
}, },
"engine": "oracle", "engine": "oracle",

View File

@@ -1808,10 +1808,6 @@ If you enable DML in the meta database users will be able to run DML queries on
Second, you might want to change the value of `SUPERSET_META_DB_LIMIT`. The default value is 1000, and defines how many are read from each database before any aggregations and joins are executed. You can also set this value `None` if you only have small tables. Second, you might want to change the value of `SUPERSET_META_DB_LIMIT`. The default value is 1000, and defines how many are read from each database before any aggregations and joins are executed. You can also set this value `None` if you only have small tables.
:::warning
`SUPERSET_META_DB_LIMIT` is applied to **each** underlying table *before* the in-memory join runs, not to the final result. If any table involved in a join has more rows than the limit, the meta database will read only the first `SUPERSET_META_DB_LIMIT` rows of that table, which means matching rows can be silently dropped and the join can return **incomplete or even empty** results with no error. If you join tables larger than the limit, raise `SUPERSET_META_DB_LIMIT` to comfortably exceed your largest joined table, or set it to `None` when working only with small tables, to get correct results.
:::
Additionally, you might want to restrict the databases to with the meta database has access to. This can be done in the database configuration, under "Advanced" -> "Other" -> "ENGINE PARAMETERS" and adding: Additionally, you might want to restrict the databases to with the meta database has access to. This can be done in the database configuration, under "Advanced" -> "Other" -> "ENGINE PARAMETERS" and adding:
```json ```json

File diff suppressed because it is too large Load Diff

View File

@@ -15,7 +15,7 @@
# limitations under the License. # limitations under the License.
# #
apiVersion: v2 apiVersion: v2
appVersion: "6.1.0" appVersion: "5.0.0"
description: Apache Superset is a modern, enterprise-ready business intelligence web application description: Apache Superset is a modern, enterprise-ready business intelligence web application
name: superset name: superset
icon: https://artifacthub.io/image/68c1d717-0e97-491f-b046-754e46f46922@2x icon: https://artifacthub.io/image/68c1d717-0e97-491f-b046-754e46f46922@2x
@@ -29,7 +29,7 @@ maintainers:
- name: craig-rueda - name: craig-rueda
email: craig@craigrueda.com email: craig@craigrueda.com
url: https://github.com/craig-rueda url: https://github.com/craig-rueda
version: 0.17.2 # See [README](https://github.com/apache/superset/blob/master/helm/superset/README.md#versioning) for version details. version: 0.15.5 # See [README](https://github.com/apache/superset/blob/master/helm/superset/README.md#versioning) for version details.
dependencies: dependencies:
- name: postgresql - name: postgresql
version: 16.7.27 version: 16.7.27

View File

@@ -23,7 +23,7 @@ NOTE: This file is generated by helm-docs: https://github.com/norwoodj/helm-docs
# superset # superset
![Version: 0.17.2](https://img.shields.io/badge/Version-0.17.2-informational?style=flat-square) ![Version: 0.15.5](https://img.shields.io/badge/Version-0.15.5-informational?style=flat-square)
Apache Superset is a modern, enterprise-ready business intelligence web application Apache Superset is a modern, enterprise-ready business intelligence web application
@@ -111,6 +111,9 @@ On helm this can be set on `extraSecretEnv.SUPERSET_SECRET_KEY` or `configOverri
| init.resources | object | `{}` | | | init.resources | object | `{}` | |
| init.tolerations | list | `[]` | | | init.tolerations | list | `[]` | |
| init.topologySpreadConstraints | list | `[]` | TopologySpreadConstrains to be added to init job | | init.topologySpreadConstraints | list | `[]` | TopologySpreadConstrains to be added to init job |
| initImage.pullPolicy | string | `"IfNotPresent"` | |
| initImage.repository | string | `"apache/superset"` | |
| initImage.tag | string | `"dockerize"` | |
| nameOverride | string | `nil` | Provide a name to override the name of the chart | | nameOverride | string | `nil` | Provide a name to override the name of the chart |
| nodeSelector | object | `{}` | | | nodeSelector | object | `{}` | |
| postgresql | object | see `values.yaml` | Configuration values for the postgresql dependency. ref: https://github.com/bitnami/charts/tree/main/bitnami/postgresql | | postgresql | object | see `values.yaml` | Configuration values for the postgresql dependency. ref: https://github.com/bitnami/charts/tree/main/bitnami/postgresql |
@@ -216,7 +219,6 @@ On helm this can be set on `extraSecretEnv.SUPERSET_SECRET_KEY` or `configOverri
| supersetNode.extraContainers | list | `[]` | Launch additional containers into supersetNode pod | | supersetNode.extraContainers | list | `[]` | Launch additional containers into supersetNode pod |
| supersetNode.forceReload | bool | `false` | If true, forces deployment to reload on each upgrade | | supersetNode.forceReload | bool | `false` | If true, forces deployment to reload on each upgrade |
| supersetNode.initContainers | list | a container waiting for postgres | Init containers | | supersetNode.initContainers | list | a container waiting for postgres | Init containers |
| supersetNode.lifecycle | object | `{}` | Container lifecycle hooks, e.g. a preStop sleep so the Service/Ingress stops routing to the pod before gunicorn receives SIGTERM |
| supersetNode.livenessProbe.failureThreshold | int | `3` | | | supersetNode.livenessProbe.failureThreshold | int | `3` | |
| supersetNode.livenessProbe.httpGet.path | string | `"/health"` | | | supersetNode.livenessProbe.httpGet.path | string | `"/health"` | |
| supersetNode.livenessProbe.httpGet.port | string | `"http"` | | | supersetNode.livenessProbe.httpGet.port | string | `"http"` | |
@@ -249,7 +251,6 @@ On helm this can be set on `extraSecretEnv.SUPERSET_SECRET_KEY` or `configOverri
| supersetNode.startupProbe.successThreshold | int | `1` | | | supersetNode.startupProbe.successThreshold | int | `1` | |
| supersetNode.startupProbe.timeoutSeconds | int | `1` | | | supersetNode.startupProbe.timeoutSeconds | int | `1` | |
| supersetNode.strategy | object | `{}` | | | supersetNode.strategy | object | `{}` | |
| supersetNode.terminationGracePeriodSeconds | string | `nil` | Pod termination grace period (seconds). Set greater than GUNICORN_TIMEOUT so in-flight requests can drain before SIGKILL |
| supersetNode.topologySpreadConstraints | list | `[]` | TopologySpreadConstrains to be added to supersetNode deployments | | supersetNode.topologySpreadConstraints | list | `[]` | TopologySpreadConstrains to be added to supersetNode deployments |
| supersetWebsockets.affinity | object | `{}` | Affinity to be added to supersetWebsockets deployment | | supersetWebsockets.affinity | object | `{}` | Affinity to be added to supersetWebsockets deployment |
| supersetWebsockets.command | list | `[]` | | | supersetWebsockets.command | list | `[]` | |
@@ -313,7 +314,6 @@ On helm this can be set on `extraSecretEnv.SUPERSET_SECRET_KEY` or `configOverri
| supersetWorker.extraContainers | list | `[]` | Launch additional containers into supersetWorker pod | | supersetWorker.extraContainers | list | `[]` | Launch additional containers into supersetWorker pod |
| supersetWorker.forceReload | bool | `false` | If true, forces deployment to reload on each upgrade | | supersetWorker.forceReload | bool | `false` | If true, forces deployment to reload on each upgrade |
| supersetWorker.initContainers | list | a container waiting for postgres and redis | Init container | | supersetWorker.initContainers | list | a container waiting for postgres and redis | Init container |
| supersetWorker.lifecycle | object | `{}` | Container lifecycle hooks for the worker pod |
| supersetWorker.livenessProbe.exec.command | list | a `celery inspect ping` command | Liveness probe command | | supersetWorker.livenessProbe.exec.command | list | a `celery inspect ping` command | Liveness probe command |
| supersetWorker.livenessProbe.failureThreshold | int | `3` | | | supersetWorker.livenessProbe.failureThreshold | int | `3` | |
| supersetWorker.livenessProbe.initialDelaySeconds | int | `120` | | | supersetWorker.livenessProbe.initialDelaySeconds | int | `120` | |
@@ -334,7 +334,6 @@ On helm this can be set on `extraSecretEnv.SUPERSET_SECRET_KEY` or `configOverri
| supersetWorker.resources | object | `{}` | Resource settings for the supersetWorker pods - these settings overwrite might existing values from the global resources object defined above. | | supersetWorker.resources | object | `{}` | Resource settings for the supersetWorker pods - these settings overwrite might existing values from the global resources object defined above. |
| supersetWorker.startupProbe | object | `{}` | No startup/readiness probes by default since we don't really care about its startup time (it doesn't serve traffic) | | supersetWorker.startupProbe | object | `{}` | No startup/readiness probes by default since we don't really care about its startup time (it doesn't serve traffic) |
| supersetWorker.strategy | object | `{}` | | | supersetWorker.strategy | object | `{}` | |
| supersetWorker.terminationGracePeriodSeconds | string | `nil` | Pod termination grace period (seconds) for the worker pod so in-flight tasks can drain before SIGKILL |
| supersetWorker.topologySpreadConstraints | list | `[]` | TopologySpreadConstrains to be added to supersetWorker deployments | | supersetWorker.topologySpreadConstraints | list | `[]` | TopologySpreadConstrains to be added to supersetWorker deployments |
| tolerations | list | `[]` | | | tolerations | list | `[]` | |
| topologySpreadConstraints | list | `[]` | TopologySpreadConstrains to be added to all deployments | | topologySpreadConstraints | list | `[]` | TopologySpreadConstrains to be added to all deployments |

View File

@@ -126,7 +126,7 @@ spec:
{{- toYaml .Values.resources | nindent 12 }} {{- toYaml .Values.resources | nindent 12 }}
{{- end }} {{- end }}
{{- if .Values.supersetCeleryBeat.extraContainers }} {{- if .Values.supersetCeleryBeat.extraContainers }}
{{- tpl (toYaml .Values.supersetCeleryBeat.extraContainers) . | nindent 8 }} {{- toYaml .Values.supersetCeleryBeat.extraContainers | nindent 8 }}
{{- end }} {{- end }}
{{- with .Values.nodeSelector }} {{- with .Values.nodeSelector }}
nodeSelector: {{- toYaml . | nindent 8 }} nodeSelector: {{- toYaml . | nindent 8 }}

View File

@@ -121,7 +121,7 @@ spec:
{{- toYaml .Values.resources | nindent 12 }} {{- toYaml .Values.resources | nindent 12 }}
{{- end }} {{- end }}
{{- if .Values.supersetCeleryFlower.extraContainers }} {{- if .Values.supersetCeleryFlower.extraContainers }}
{{- tpl (toYaml .Values.supersetCeleryFlower.extraContainers) . | nindent 8 }} {{- toYaml .Values.supersetCeleryFlower.extraContainers | nindent 8 }}
{{- end }} {{- end }}
{{- with .Values.nodeSelector }} {{- with .Values.nodeSelector }}
nodeSelector: {{- toYaml . | nindent 8 }} nodeSelector: {{- toYaml . | nindent 8 }}

View File

@@ -134,9 +134,6 @@ spec:
{{- if .Values.supersetWorker.livenessProbe }} {{- if .Values.supersetWorker.livenessProbe }}
livenessProbe: {{- .Values.supersetWorker.livenessProbe | toYaml | nindent 12 }} livenessProbe: {{- .Values.supersetWorker.livenessProbe | toYaml | nindent 12 }}
{{- end }} {{- end }}
{{- if .Values.supersetWorker.lifecycle }}
lifecycle: {{- .Values.supersetWorker.lifecycle | toYaml | nindent 12 }}
{{- end }}
resources: resources:
{{- if .Values.supersetWorker.resources }} {{- if .Values.supersetWorker.resources }}
{{- toYaml .Values.supersetWorker.resources | nindent 12 }} {{- toYaml .Values.supersetWorker.resources | nindent 12 }}
@@ -144,7 +141,7 @@ spec:
{{- toYaml .Values.resources | nindent 12 }} {{- toYaml .Values.resources | nindent 12 }}
{{- end }} {{- end }}
{{- if .Values.supersetWorker.extraContainers }} {{- if .Values.supersetWorker.extraContainers }}
{{- tpl (toYaml .Values.supersetWorker.extraContainers) . | nindent 8 }} {{- toYaml .Values.supersetWorker.extraContainers | nindent 8 }}
{{- end }} {{- end }}
{{- with .Values.nodeSelector }} {{- with .Values.nodeSelector }}
nodeSelector: {{- toYaml . | nindent 8 }} nodeSelector: {{- toYaml . | nindent 8 }}
@@ -173,9 +170,6 @@ spec:
{{- with .Values.tolerations }} {{- with .Values.tolerations }}
tolerations: {{- toYaml . | nindent 8 }} tolerations: {{- toYaml . | nindent 8 }}
{{- end }} {{- end }}
{{- if .Values.supersetWorker.terminationGracePeriodSeconds }}
terminationGracePeriodSeconds: {{ .Values.supersetWorker.terminationGracePeriodSeconds }}
{{- end }}
{{- if .Values.imagePullSecrets }} {{- if .Values.imagePullSecrets }}
imagePullSecrets: {{- toYaml .Values.imagePullSecrets | nindent 8 }} imagePullSecrets: {{- toYaml .Values.imagePullSecrets | nindent 8 }}
{{- end }} {{- end }}

View File

@@ -120,7 +120,7 @@ spec:
livenessProbe: {{- .Values.supersetWebsockets.livenessProbe | toYaml | nindent 12 }} livenessProbe: {{- .Values.supersetWebsockets.livenessProbe | toYaml | nindent 12 }}
{{- end }} {{- end }}
{{- if .Values.supersetWebsockets.extraContainers }} {{- if .Values.supersetWebsockets.extraContainers }}
{{- tpl (toYaml .Values.supersetWebsockets.extraContainers) . | nindent 8 }} {{- toYaml .Values.supersetWebsockets.extraContainers | nindent 8 }}
{{- end }} {{- end }}
{{- with .Values.nodeSelector }} {{- with .Values.nodeSelector }}
nodeSelector: {{- toYaml . | nindent 8 }} nodeSelector: {{- toYaml . | nindent 8 }}

View File

@@ -144,9 +144,6 @@ spec:
{{- if .Values.supersetNode.livenessProbe }} {{- if .Values.supersetNode.livenessProbe }}
livenessProbe: {{- .Values.supersetNode.livenessProbe | toYaml | nindent 12 }} livenessProbe: {{- .Values.supersetNode.livenessProbe | toYaml | nindent 12 }}
{{- end }} {{- end }}
{{- if .Values.supersetNode.lifecycle }}
lifecycle: {{- .Values.supersetNode.lifecycle | toYaml | nindent 12 }}
{{- end }}
resources: resources:
{{- if .Values.supersetNode.resources }} {{- if .Values.supersetNode.resources }}
{{- toYaml .Values.supersetNode.resources | nindent 12 }} {{- toYaml .Values.supersetNode.resources | nindent 12 }}
@@ -154,7 +151,7 @@ spec:
{{- toYaml .Values.resources | nindent 12 }} {{- toYaml .Values.resources | nindent 12 }}
{{- end }} {{- end }}
{{- if .Values.supersetNode.extraContainers }} {{- if .Values.supersetNode.extraContainers }}
{{- tpl (toYaml .Values.supersetNode.extraContainers) . | nindent 8 }} {{- toYaml .Values.supersetNode.extraContainers | nindent 8 }}
{{- end }} {{- end }}
{{- with .Values.nodeSelector }} {{- with .Values.nodeSelector }}
nodeSelector: {{- toYaml . | nindent 8 }} nodeSelector: {{- toYaml . | nindent 8 }}
@@ -183,9 +180,6 @@ spec:
{{- with .Values.tolerations }} {{- with .Values.tolerations }}
tolerations: {{- toYaml . | nindent 8 }} tolerations: {{- toYaml . | nindent 8 }}
{{- end }} {{- end }}
{{- if .Values.supersetNode.terminationGracePeriodSeconds }}
terminationGracePeriodSeconds: {{ .Values.supersetNode.terminationGracePeriodSeconds }}
{{- end }}
{{- if .Values.imagePullSecrets }} {{- if .Values.imagePullSecrets }}
imagePullSecrets: {{- toYaml .Values.imagePullSecrets | nindent 8 }} imagePullSecrets: {{- toYaml .Values.imagePullSecrets | nindent 8 }}
{{- end }} {{- end }}

View File

@@ -62,9 +62,6 @@ spec:
{{- if .Values.init.initContainers }} {{- if .Values.init.initContainers }}
initContainers: {{- tpl (toYaml .Values.init.initContainers) . | nindent 6 }} initContainers: {{- tpl (toYaml .Values.init.initContainers) . | nindent 6 }}
{{- end }} {{- end }}
{{- with .Values.hostAliases }}
hostAliases: {{- toYaml . | nindent 6 }}
{{- end }}
containers: containers:
- name: {{ template "superset.name" . }}-init-db - name: {{ template "superset.name" . }}-init-db
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
@@ -104,7 +101,7 @@ spec:
command: {{ tpl (toJson .Values.init.command) . }} command: {{ tpl (toJson .Values.init.command) . }}
resources: {{- toYaml .Values.init.resources | nindent 10 }} resources: {{- toYaml .Values.init.resources | nindent 10 }}
{{- if .Values.init.extraContainers }} {{- if .Values.init.extraContainers }}
{{- tpl (toYaml .Values.init.extraContainers) . | nindent 6 }} {{- toYaml .Values.init.extraContainers | nindent 6 }}
{{- end }} {{- end }}
{{- with .Values.nodeSelector }} {{- with .Values.nodeSelector }}
nodeSelector: {{- toYaml . | nindent 8 }} nodeSelector: {{- toYaml . | nindent 8 }}

View File

@@ -194,6 +194,11 @@ image:
imagePullSecrets: [] imagePullSecrets: []
initImage:
repository: apache/superset
tag: dockerize
pullPolicy: IfNotPresent
service: service:
type: ClusterIP type: ClusterIP
port: 8088 port: 8088
@@ -269,7 +274,7 @@ supersetNode:
command: command:
- "/bin/sh" - "/bin/sh"
- "-c" - "-c"
- ". {{ .Values.configMountPath }}/superset_bootstrap.sh; exec /usr/bin/run-server.sh" - ". {{ .Values.configMountPath }}/superset_bootstrap.sh; /usr/bin/run-server.sh"
connections: connections:
# -- Change in case of bringing your own redis and then also set redis.enabled:false # -- Change in case of bringing your own redis and then also set redis.enabled:false
redis_host: "{{ .Release.Name }}-redis-headless" redis_host: "{{ .Release.Name }}-redis-headless"
@@ -298,29 +303,15 @@ supersetNode:
# @default -- a container waiting for postgres # @default -- a container waiting for postgres
initContainers: initContainers:
- name: wait-for-postgres - name: wait-for-postgres
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" image: "{{ .Values.initImage.repository }}:{{ .Values.initImage.tag }}"
imagePullPolicy: "{{ .Values.image.pullPolicy }}" imagePullPolicy: "{{ .Values.initImage.pullPolicy }}"
envFrom: envFrom:
- secretRef: - secretRef:
name: "{{ tpl .Values.envFromSecret . }}" name: "{{ tpl .Values.envFromSecret . }}"
command: command:
- /bin/bash - /bin/sh
- -c - -c
- | - dockerize -wait "tcp://$DB_HOST:$DB_PORT" -timeout 120s
# opening a /dev/tcp fd performs a TCP connect without sending any
# payload (avoids postgres "incomplete startup packet" log noise);
# no external `dockerize`, `nc`, or busybox needed. SECONDS-based
# deadline mirrors the prior `dockerize -timeout 120s` behaviour.
SECONDS=0
until (exec 3<>/dev/tcp/"$DB_HOST"/"$DB_PORT") 2>/dev/null; do
if [ "$SECONDS" -ge 120 ]; then
echo "timeout waiting for postgres at $DB_HOST:$DB_PORT after 120s" >&2
exit 1
fi
echo "waiting for postgres at $DB_HOST:$DB_PORT (elapsed ${SECONDS}s)"
sleep 2
done
echo "postgres at $DB_HOST:$DB_PORT is up"
resources: resources:
limits: limits:
memory: "256Mi" memory: "256Mi"
@@ -369,12 +360,6 @@ supersetNode:
failureThreshold: 3 failureThreshold: 3
periodSeconds: 15 periodSeconds: 15
successThreshold: 1 successThreshold: 1
# -- Container lifecycle hooks, e.g. a preStop sleep so the Service/Ingress
# stops routing to the pod before gunicorn receives SIGTERM
lifecycle: {}
# -- Pod termination grace period (seconds). Set greater than GUNICORN_TIMEOUT so
# in-flight requests can drain before SIGKILL
terminationGracePeriodSeconds: ~
# -- Resource settings for the supersetNode pods - these settings overwrite might existing values from the global resources object defined above. # -- Resource settings for the supersetNode pods - these settings overwrite might existing values from the global resources object defined above.
resources: {} resources: {}
# limits: # limits:
@@ -415,38 +400,22 @@ supersetWorker:
command: command:
- "/bin/sh" - "/bin/sh"
- "-c" - "-c"
- ". {{ .Values.configMountPath }}/superset_bootstrap.sh; exec celery --app=superset.tasks.celery_app:app worker" - ". {{ .Values.configMountPath }}/superset_bootstrap.sh; celery --app=superset.tasks.celery_app:app worker"
# -- If true, forces deployment to reload on each upgrade # -- If true, forces deployment to reload on each upgrade
forceReload: false forceReload: false
# -- Init container # -- Init container
# @default -- a container waiting for postgres and redis # @default -- a container waiting for postgres and redis
initContainers: initContainers:
- name: wait-for-postgres-redis - name: wait-for-postgres-redis
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" image: "{{ .Values.initImage.repository }}:{{ .Values.initImage.tag }}"
imagePullPolicy: "{{ .Values.image.pullPolicy }}" imagePullPolicy: "{{ .Values.initImage.pullPolicy }}"
envFrom: envFrom:
- secretRef: - secretRef:
name: "{{ tpl .Values.envFromSecret . }}" name: "{{ tpl .Values.envFromSecret . }}"
command: command:
- /bin/bash - /bin/sh
- -c - -c
- | - dockerize -wait "tcp://$DB_HOST:$DB_PORT" -wait "tcp://$REDIS_HOST:$REDIS_PORT" -timeout 120s
# See supersetNode.initContainers for the rationale.
SECONDS=0
wait_for() {
local host=$1 port=$2 name=$3
until (exec 3<>/dev/tcp/"$host"/"$port") 2>/dev/null; do
if [ "$SECONDS" -ge 120 ]; then
echo "timeout waiting for $name at $host:$port after 120s" >&2
exit 1
fi
echo "waiting for $name at $host:$port (elapsed ${SECONDS}s)"
sleep 2
done
echo "$name at $host:$port is up"
}
wait_for "$DB_HOST" "$DB_PORT" postgres
wait_for "$REDIS_HOST" "$REDIS_PORT" redis
resources: resources:
limits: limits:
memory: "256Mi" memory: "256Mi"
@@ -495,10 +464,6 @@ supersetWorker:
failureThreshold: 3 failureThreshold: 3
periodSeconds: 60 periodSeconds: 60
successThreshold: 1 successThreshold: 1
# -- Container lifecycle hooks for the worker pod
lifecycle: {}
# -- Pod termination grace period (seconds) for the worker pod so in-flight tasks can drain before SIGKILL
terminationGracePeriodSeconds: ~
# -- No startup/readiness probes by default since we don't really care about its startup time (it doesn't serve traffic) # -- No startup/readiness probes by default since we don't really care about its startup time (it doesn't serve traffic)
startupProbe: {} startupProbe: {}
# -- No startup/readiness probes by default since we don't really care about its startup time (it doesn't serve traffic) # -- No startup/readiness probes by default since we don't really care about its startup time (it doesn't serve traffic)
@@ -523,38 +488,22 @@ supersetCeleryBeat:
command: command:
- "/bin/sh" - "/bin/sh"
- "-c" - "-c"
- ". {{ .Values.configMountPath }}/superset_bootstrap.sh; exec celery --app=superset.tasks.celery_app:app beat --pidfile /tmp/celerybeat.pid --schedule /tmp/celerybeat-schedule" - ". {{ .Values.configMountPath }}/superset_bootstrap.sh; celery --app=superset.tasks.celery_app:app beat --pidfile /tmp/celerybeat.pid --schedule /tmp/celerybeat-schedule"
# -- If true, forces deployment to reload on each upgrade # -- If true, forces deployment to reload on each upgrade
forceReload: false forceReload: false
# -- List of init containers # -- List of init containers
# @default -- a container waiting for postgres # @default -- a container waiting for postgres
initContainers: initContainers:
- name: wait-for-postgres-redis - name: wait-for-postgres-redis
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" image: "{{ .Values.initImage.repository }}:{{ .Values.initImage.tag }}"
imagePullPolicy: "{{ .Values.image.pullPolicy }}" imagePullPolicy: "{{ .Values.initImage.pullPolicy }}"
envFrom: envFrom:
- secretRef: - secretRef:
name: "{{ tpl .Values.envFromSecret . }}" name: "{{ tpl .Values.envFromSecret . }}"
command: command:
- /bin/bash - /bin/sh
- -c - -c
- | - dockerize -wait "tcp://$DB_HOST:$DB_PORT" -wait "tcp://$REDIS_HOST:$REDIS_PORT" -timeout 120s
# See supersetNode.initContainers for the rationale.
SECONDS=0
wait_for() {
local host=$1 port=$2 name=$3
until (exec 3<>/dev/tcp/"$host"/"$port") 2>/dev/null; do
if [ "$SECONDS" -ge 120 ]; then
echo "timeout waiting for $name at $host:$port after 120s" >&2
exit 1
fi
echo "waiting for $name at $host:$port (elapsed ${SECONDS}s)"
sleep 2
done
echo "$name at $host:$port is up"
}
wait_for "$DB_HOST" "$DB_PORT" postgres
wait_for "$REDIS_HOST" "$REDIS_PORT" redis
resources: resources:
limits: limits:
memory: "256Mi" memory: "256Mi"
@@ -645,31 +594,15 @@ supersetCeleryFlower:
# @default -- a container waiting for postgres and redis # @default -- a container waiting for postgres and redis
initContainers: initContainers:
- name: wait-for-postgres-redis - name: wait-for-postgres-redis
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" image: "{{ .Values.initImage.repository }}:{{ .Values.initImage.tag }}"
imagePullPolicy: "{{ .Values.image.pullPolicy }}" imagePullPolicy: "{{ .Values.initImage.pullPolicy }}"
envFrom: envFrom:
- secretRef: - secretRef:
name: "{{ tpl .Values.envFromSecret . }}" name: "{{ tpl .Values.envFromSecret . }}"
command: command:
- /bin/bash - /bin/sh
- -c - -c
- | - dockerize -wait "tcp://$DB_HOST:$DB_PORT" -wait "tcp://$REDIS_HOST:$REDIS_PORT" -timeout 120s
# See supersetNode.initContainers for the rationale.
SECONDS=0
wait_for() {
local host=$1 port=$2 name=$3
until (exec 3<>/dev/tcp/"$host"/"$port") 2>/dev/null; do
if [ "$SECONDS" -ge 120 ]; then
echo "timeout waiting for $name at $host:$port after 120s" >&2
exit 1
fi
echo "waiting for $name at $host:$port (elapsed ${SECONDS}s)"
sleep 2
done
echo "$name at $host:$port is up"
}
wait_for "$DB_HOST" "$DB_PORT" postgres
wait_for "$REDIS_HOST" "$REDIS_PORT" redis
resources: resources:
limits: limits:
memory: "256Mi" memory: "256Mi"
@@ -831,26 +764,15 @@ init:
# @default -- a container waiting for postgres # @default -- a container waiting for postgres
initContainers: initContainers:
- name: wait-for-postgres - name: wait-for-postgres
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" image: "{{ .Values.initImage.repository }}:{{ .Values.initImage.tag }}"
imagePullPolicy: "{{ .Values.image.pullPolicy }}" imagePullPolicy: "{{ .Values.initImage.pullPolicy }}"
envFrom: envFrom:
- secretRef: - secretRef:
name: "{{ tpl .Values.envFromSecret . }}" name: "{{ tpl .Values.envFromSecret . }}"
command: command:
- /bin/bash - /bin/sh
- -c - -c
- | - dockerize -wait "tcp://$DB_HOST:$DB_PORT" -timeout 120s
# See supersetNode.initContainers for the rationale.
SECONDS=0
until (exec 3<>/dev/tcp/"$DB_HOST"/"$DB_PORT") 2>/dev/null; do
if [ "$SECONDS" -ge 120 ]; then
echo "timeout waiting for postgres at $DB_HOST:$DB_PORT after 120s" >&2
exit 1
fi
echo "waiting for postgres at $DB_HOST:$DB_PORT (elapsed ${SECONDS}s)"
sleep 2
done
echo "postgres at $DB_HOST:$DB_PORT is up"
resources: resources:
limits: limits:
memory: "256Mi" memory: "256Mi"

View File

@@ -38,20 +38,14 @@ dependencies = [
# no bounds for apache-superset-core until we have a stable version # no bounds for apache-superset-core until we have a stable version
"apache-superset-core", "apache-superset-core",
"backoff>=1.8.0", "backoff>=1.8.0",
# cachetools is used directly by ``superset.db_engine_specs.aws_iam`` (TTLCache).
# It used to be installed transitively via ``google-auth`` (<2.53), but
# ``google-auth`` 2.53+ dropped it, so Superset must declare it
# explicitly to keep fresh ``pip install apache-superset`` working
# without the ``base.txt`` lock file (#40962).
"cachetools>=6.2.1, <7",
"celery>=5.3.6, <6.0.0", "celery>=5.3.6, <6.0.0",
"click>=8.4.0", "click>=8.4.0",
"click-option-group", "click-option-group",
"colorama", "colorama",
"flask-cors>=6.0.5, <7.0", "flask-cors>=6.0.0, <7.0",
"croniter>=6.2.2", "croniter>=0.3.28",
"cron-descriptor", "cron-descriptor",
"cryptography>=48.0.0, <49.0.0", "cryptography>=42.0.4, <47.0.0",
"deprecation>=2.1.0, <2.2.0", "deprecation>=2.1.0, <2.2.0",
"flask>=2.2.5, <4.0.0", "flask>=2.2.5, <4.0.0",
"flask-appbuilder>=5.2.1, <6.0.0", "flask-appbuilder>=5.2.1, <6.0.0",
@@ -59,26 +53,24 @@ dependencies = [
"flask-compress>=1.13, <2.0", "flask-compress>=1.13, <2.0",
"flask-talisman>=1.0.0, <2.0", "flask-talisman>=1.0.0, <2.0",
"flask-login>=0.6.0, < 1.0", "flask-login>=0.6.0, < 1.0",
"flask-migrate>=4.1.0, <5.0", "flask-migrate>=3.1.0, <5.0",
"flask-session>=0.4.0, <1.0", "flask-session>=0.4.0, <1.0",
"flask-wtf>=1.3.0, <2.0", "flask-wtf>=1.1.0, <2.0",
"geopy", "geopy",
"greenlet<=3.5.1, >=3.5.1", "greenlet>=3.0.3, <=3.5.0",
"gunicorn>=25.3.0, <26; sys_platform != 'win32'", "gunicorn>=25.3.0, <26; sys_platform != 'win32'",
"hashids>=1.3.1, <2", "hashids>=1.3.1, <2",
# holidays>=0.45 required for security fix # holidays>=0.45 required for security fix
"holidays>=0.45, <1", "holidays>=0.45, <1",
"humanize", "humanize",
"isodate", "isodate",
"jsonpath-ng>=1.8.0, <2", "jsonpath-ng>=1.6.1, <2",
"Mako>=1.2.2", "Mako>=1.2.2",
"markdown>=3.10.2", "markdown>=3.10.2",
# marshmallow 4 compatibility: see superset/marshmallow_compatibility.py for a # marshmallow>=4 has issues: https://github.com/apache/superset/issues/33162
# Flask-AppBuilder workaround. Tracking issue: "marshmallow>=3.0, <4",
# https://github.com/apache/superset/issues/33162
"marshmallow>=3.0, <5",
"marshmallow-union>=0.1", "marshmallow-union>=0.1",
"msgpack>=1.2.0, <1.3", "msgpack>=1.0.0, <1.2",
"nh3>=0.3.5, <0.4", "nh3>=0.3.5, <0.4",
"numpy>1.23.5, <2.3", "numpy>1.23.5, <2.3",
"packaging", "packaging",
@@ -88,7 +80,7 @@ dependencies = [
"bottleneck", # recommended performance dependency for pandas, see https://pandas.pydata.org/docs/getting_started/install.html#performance-dependencies-recommended "bottleneck", # recommended performance dependency for pandas, see https://pandas.pydata.org/docs/getting_started/install.html#performance-dependencies-recommended
# -------------------------- # --------------------------
"parsedatetime", "parsedatetime",
"paramiko>=3.4.0, <4.0", # 4.0 removed DSSKey, still referenced by sshtunnel "paramiko>=3.4.0",
"pgsanity", "pgsanity",
"Pillow>=11.0.0, <13", "Pillow>=11.0.0, <13",
"polyline>=2.0.0, <3.0", "polyline>=2.0.0, <3.0",
@@ -97,15 +89,15 @@ dependencies = [
"python-dateutil", "python-dateutil",
"python-dotenv", # optional dependencies for Flask but required for Superset, see https://flask.palletsprojects.com/en/stable/installation/#optional-dependencies "python-dotenv", # optional dependencies for Flask but required for Superset, see https://flask.palletsprojects.com/en/stable/installation/#optional-dependencies
"pygeohash", "pygeohash",
"pyarrow>=24.0.0, <25", # before upgrading pyarrow, check that all db dependencies support this, see e.g. https://github.com/apache/superset/pull/34693 "pyarrow>=16.1.0, <21", # before upgrading pyarrow, check that all db dependencies support this, see e.g. https://github.com/apache/superset/pull/34693
"pyyaml>=6.0.3, <7.0.0", "pyyaml>=6.0.0, <7.0.0",
"PyJWT>=2.4.0, <3.0", "PyJWT>=2.4.0, <3.0",
"redis>=5.0.0, <6.0", "redis>=5.0.0, <6.0",
"rison>=2.0.0, <3.0", "rison>=2.0.0, <3.0",
"selenium>=4.44.0, <5.0", "selenium>=4.14.0, <5.0",
"shillelagh[gsheetsapi]>=1.4.4, <2.0", "shillelagh[gsheetsapi]>=1.4.4, <2.0",
"sshtunnel>=0.4.0, <0.5", "sshtunnel>=0.4.0, <0.5",
"simplejson>=4.1.1", "simplejson>=3.15.0",
"slack_sdk>=3.19.0, <4", "slack_sdk>=3.19.0, <4",
"sqlalchemy>=1.4, <2", "sqlalchemy>=1.4, <2",
"sqlalchemy-utils>=0.38.0, <0.43", # expanding lowerbound to work with pydoris "sqlalchemy-utils>=0.38.0, <0.43", # expanding lowerbound to work with pydoris
@@ -115,7 +107,7 @@ dependencies = [
"typing-extensions>=4, <5", "typing-extensions>=4, <5",
"waitress; sys_platform == 'win32'", "waitress; sys_platform == 'win32'",
"watchdog>=6.0.0", "watchdog>=6.0.0",
"wtforms>=3.2.2, <4", "wtforms>=2.3.3, <4",
"wtforms-json", "wtforms-json",
"xlsxwriter>=3.2.9, <3.3", "xlsxwriter>=3.2.9, <3.3",
] ]
@@ -126,10 +118,10 @@ athena = ["pyathena[pandas]>=2, <4"]
aurora-data-api = ["preset-sqlalchemy-aurora-data-api>=0.2.8,<0.3"] aurora-data-api = ["preset-sqlalchemy-aurora-data-api>=0.2.8,<0.3"]
bigquery = [ bigquery = [
"pandas-gbq>=0.19.1", "pandas-gbq>=0.19.1",
"sqlalchemy-bigquery>=1.17.0", "sqlalchemy-bigquery>=1.15.0",
"google-cloud-bigquery>=3.10.0", "google-cloud-bigquery>=3.10.0",
] ]
clickhouse = ["clickhouse-connect>=1.1.1, <2.0"] clickhouse = ["clickhouse-connect>=0.13.0, <2.0"]
cockroachdb = ["cockroachdb>=0.3.5, <0.4"] cockroachdb = ["cockroachdb>=0.3.5, <0.4"]
crate = ["sqlalchemy-cratedb>=0.41.0, <1"] crate = ["sqlalchemy-cratedb>=0.41.0, <1"]
d1 = [ d1 = [
@@ -149,49 +141,49 @@ drill = ["sqlalchemy-drill>=1.1.10, <2"]
druid = ["pydruid>=0.6.5,<0.7"] druid = ["pydruid>=0.6.5,<0.7"]
duckdb = ["duckdb>=1.5.2,<2", "duckdb-engine>=0.17.0"] duckdb = ["duckdb>=1.5.2,<2", "duckdb-engine>=0.17.0"]
dynamodb = ["pydynamodb>=0.4.2"] dynamodb = ["pydynamodb>=0.4.2"]
solr = ["sqlalchemy-solr >= 0.2.4.3"] solr = ["sqlalchemy-solr >= 0.2.0"]
elasticsearch = ["elasticsearch-dbapi>=0.2.13, <0.3.0"] elasticsearch = ["elasticsearch-dbapi>=0.2.13, <0.3.0"]
exasol = ["sqlalchemy-exasol>=2.4.0, <8.0"] exasol = ["sqlalchemy-exasol >= 2.4.0, < 8.0"]
excel = ["xlrd>=2.0.2, <2.1"] excel = ["xlrd>=1.2.0, <1.3"]
fastmcp = [ fastmcp = [
"fastmcp>=3.2.4,<4.0", "fastmcp>=3.2.4,<4.0",
# tiktoken backs the response-size-guard token estimator. Without # tiktoken backs the response-size-guard token estimator. Without
# it, the middleware falls back to a coarser character-based # it, the middleware falls back to a coarser character-based
# heuristic that under-counts JSON-heavy MCP responses. # heuristic that under-counts JSON-heavy MCP responses.
"tiktoken>=0.13.0,<1.0", "tiktoken>=0.7.0,<1.0",
] ]
firebird = ["sqlalchemy-firebird>=0.7.0, <2.2"] firebird = ["sqlalchemy-firebird>=0.7.0, <2.2"]
firebolt = ["firebolt-sqlalchemy>=1.0.0, <2"] firebolt = ["firebolt-sqlalchemy>=1.0.0, <2"]
gevent = ["gevent>=26.4.0"] gevent = ["gevent>=26.4.0"]
gsheets = ["shillelagh[gsheetsapi]>=1.4.4, <2"] gsheets = ["shillelagh[gsheetsapi]>=1.4.4, <2"]
hana = ["hdbcli==2.28.21", "sqlalchemy_hana==0.4.0"] hana = ["hdbcli==2.28.20", "sqlalchemy_hana==0.4.0"]
hive = [ hive = [
"pyhive[hive]>=0.6.5;python_version<'3.11'", "pyhive[hive]>=0.6.5;python_version<'3.11'",
"pyhive[hive_pure_sasl]>=0.7.0", "pyhive[hive_pure_sasl]>=0.7.0",
"tableschema", "tableschema",
"thrift>=0.23.0, <1.0.0", "thrift>=0.14.1, <1.0.0",
"thrift_sasl>=0.4.3, < 1.0.0", "thrift_sasl>=0.4.3, < 1.0.0",
] ]
impala = ["impyla>0.16.2, <0.23"] impala = ["impyla>0.16.2, <0.23"]
kusto = ["sqlalchemy-kusto>=3.1.2, <4"] kusto = ["sqlalchemy-kusto>=3.1.2, <4"]
kylin = ["kylinpy>=2.8.1, <2.9"] kylin = ["kylinpy>=2.8.1, <2.9"]
mssql = ["pymssql>=2.3.13, <3"] mssql = ["pymssql>=2.2.8, <3"]
# motherduck is an alias for duckdb - MotherDuck works via the duckdb driver # motherduck is an alias for duckdb - MotherDuck works via the duckdb driver
motherduck = ["apache-superset[duckdb]"] motherduck = ["apache-superset[duckdb]"]
mysql = ["mysqlclient>=2.1.0, <3"] mysql = ["mysqlclient>=2.1.0, <3"]
ocient = [ ocient = [
"sqlalchemy-ocient>=1.0.0", "sqlalchemy-ocient>=1.0.0",
"pyocient>=1.0.15, <4", "pyocient>=1.0.15, <2",
"shapely", "shapely",
"geojson", "geojson",
] ]
oracle = ["oracledb>=2.0.0, <5"] oracle = ["cx-Oracle>8.0.0, <8.4"]
parseable = ["sqlalchemy-parseable>=0.1.3,<0.2.0"] parseable = ["sqlalchemy-parseable>=0.1.3,<0.2.0"]
pinot = ["pinotdb>=5.0.0, <10.0.0"] pinot = ["pinotdb>=5.0.0, <10.0.0"]
playwright = ["playwright>=1.60.0, <2"] playwright = ["playwright>=1.60.0, <2"]
postgres = ["psycopg2-binary==2.9.12"] postgres = ["psycopg2-binary==2.9.12"]
presto = ["pyhive[presto]>=0.6.5"] presto = ["pyhive[presto]>=0.6.5"]
trino = ["trino>=0.337.0"] trino = ["trino>=0.328.0"]
prophet = ["prophet>=1.1.6, <2"] prophet = ["prophet>=1.1.6, <2"]
redshift = ["sqlalchemy-redshift>=0.8.1, <0.9"] redshift = ["sqlalchemy-redshift>=0.8.1, <0.9"]
risingwave = ["sqlalchemy-risingwave"] risingwave = ["sqlalchemy-risingwave"]
@@ -203,7 +195,7 @@ spark = [
"pyhive[hive]>=0.6.5;python_version<'3.11'", "pyhive[hive]>=0.6.5;python_version<'3.11'",
"pyhive[hive_pure_sasl]>=0.7", "pyhive[hive_pure_sasl]>=0.7",
"tableschema", "tableschema",
"thrift>=0.23.0, <1", "thrift>=0.14.1, <1",
] ]
tdengine = [ tdengine = [
"taospy>=2.7.21", "taospy>=2.7.21",
@@ -213,10 +205,10 @@ teradata = ["teradatasql>=16.20.0.23"]
thumbnails = [] # deprecated, will be removed in 7.0 thumbnails = [] # deprecated, will be removed in 7.0
vertica = ["sqlalchemy-vertica-python>= 0.6.3, < 0.7"] vertica = ["sqlalchemy-vertica-python>= 0.6.3, < 0.7"]
netezza = ["nzalchemy>=11.0.2"] netezza = ["nzalchemy>=11.0.2"]
starrocks = ["starrocks>=1.3.3, <2"] starrocks = ["starrocks>=1.0.0"]
doris = ["pydoris>=1.0.0, <2.0.0"] doris = ["pydoris>=1.0.0, <2.0.0"]
oceanbase = ["oceanbase_py>=0.0.1.2"] oceanbase = ["oceanbase_py>=0.0.1.2"]
ydb = ["ydb-sqlalchemy>=0.1.22", "ydb-sqlglot-plugin>=0.2.5"] ydb = ["ydb-sqlalchemy>=0.1.2", "ydb-sqlglot-plugin>=0.2.5"]
development = [ development = [
# no bounds for apache-superset-extensions-cli until a stable version # no bounds for apache-superset-extensions-cli until a stable version
"apache-superset-extensions-cli", "apache-superset-extensions-cli",
@@ -224,13 +216,13 @@ development = [
"docker", "docker",
"flask-testing", "flask-testing",
"freezegun", "freezegun",
"grpcio>=1.81.1", "grpcio>=1.55.3",
"openapi-spec-validator", "openapi-spec-validator",
"parameterized", "parameterized",
"pip", "pip",
"polib", # used by scripts/translations/ and their unit tests "polib", # used by scripts/translations/ and their unit tests
"pre-commit", "pre-commit",
"progress>=1.6.1,<2", "progress>=1.5,<2",
"psutil", "psutil",
"pyfakefs", "pyfakefs",
"pyinstrument>=5.1.2,<6", "pyinstrument>=5.1.2,<6",
@@ -375,6 +367,7 @@ select = [
ignore = [ ignore = [
"S101", "S101",
"PT004", # Fixtures that don't return values - underscore prefix conflicts with pytest usage
"PT006", "PT006",
"T201", "T201",
"N999", "N999",
@@ -454,7 +447,6 @@ requirement_txt_file = "requirements/base.txt"
authorized_licenses = [ authorized_licenses = [
"academic free license (afl)", "academic free license (afl)",
"any-osi", "any-osi",
"apache-2.0",
"apache license 2.0", "apache license 2.0",
"apache software", "apache software",
"apache software, bsd", "apache software, bsd",

View File

@@ -18,30 +18,5 @@
testpaths = testpaths =
tests tests
python_files = *_test.py test_*.py *_tests.py *viz/utils.py python_files = *_test.py test_*.py *_tests.py *viz/utils.py
# `-p no:warnings` temporarily disabled in favor of more finely tuned `filterwarnings`. addopts = -p no:warnings
#addopts = -p no:warnings
asyncio_mode = auto asyncio_mode = auto
# `ignore` is effectively equivalent to `-p no:warnings`.
# Always print RemovedIn20Warning when SQLALCHEMY_WARN_20=1.
# Additionally, raise errors for refactored RemovedIn20Warning cases to prevent regression.
filterwarnings =
ignore
always::sqlalchemy.exc.RemovedIn20Warning
error:Passing a string to Connection.execute\(\) is deprecated:sqlalchemy.exc.RemovedIn20Warning
# error:"Query" object is being merged into a Session:sqlalchemy.exc.RemovedIn20Warning
# error:"SavedQuery" object is being merged into a Session:sqlalchemy.exc.RemovedIn20Warning
# error:"SqlaTable" object is being merged into a Session:sqlalchemy.exc.RemovedIn20Warning
# error:"SqlMetric" object is being merged into a Session:sqlalchemy.exc.RemovedIn20Warning
# error:"TableColumn" object is being merged into a Session:sqlalchemy.exc.RemovedIn20Warning
# error:"TaggedObject" object is being merged into a Session:sqlalchemy.exc.RemovedIn20Warning
# error:The ``as_declarative\(\)`` function is now available:sqlalchemy.exc.RemovedIn20Warning
# error:The autoload parameter is deprecated:sqlalchemy.exc.RemovedIn20Warning
# error:The connection.execute\(\) method:sqlalchemy.exc.RemovedIn20Warning
# error:The current statement is being autocommitted using implicit autocommit:sqlalchemy.exc.RemovedIn20Warning
# error:The `database` package is deprecated:sqlalchemy.exc.RemovedIn20Warning
# error:The ``declarative_base\(\)`` function is now available:sqlalchemy.exc.RemovedIn20Warning
# error:The Engine.execute\(\) method is considered legacy:sqlalchemy.exc.RemovedIn20Warning
error:The legacy calling style of select\(\) is deprecated:sqlalchemy.exc.RemovedIn20Warning
# error:The "whens" argument to case:sqlalchemy.exc.RemovedIn20Warning
# error:"User" object is being merged into a Session:sqlalchemy.exc.RemovedIn20Warning

View File

@@ -26,11 +26,11 @@ filelock>=3.20.3,<4.0.0
brotli>=1.2.0,<2.0.0 brotli>=1.2.0,<2.0.0
numexpr>=2.9.0 numexpr>=2.9.0
# Security: CVE-2026-34073 (MEDIUM) - Improper Certificate Validation # Security: CVE-2026-34073 (MEDIUM) - Improper Certificate Validation
cryptography>=48.0.0,<49.0.0 cryptography>=46.0.7,<47.0.0
# Security: Snyk - XSS vulnerability in Mako templates # Security: Snyk - XSS vulnerability in Mako templates
mako>=1.3.11,<2.0.0 mako>=1.3.11,<2.0.0
# Security: CVE-2024-52338 (CRITICAL) - Deserialization of untrusted data in IPC/Parquet readers # Security: CVE-2024-52338 (CRITICAL) - Deserialization of untrusted data in IPC/Parquet readers
pyarrow>=24.0.0,<25.0.0 pyarrow>=20.0.0,<21.0.0
# Security: CVE-2026-27459 - pyopenssl certificate validation # Security: CVE-2026-27459 - pyopenssl certificate validation
pyopenssl>=26.0.0,<27.0.0 pyopenssl>=26.0.0,<27.0.0
# Security: CVE-2026-25645 (MEDIUM) - Insecure Temporary File # Security: CVE-2026-25645 (MEDIUM) - Insecure Temporary File
@@ -44,10 +44,11 @@ async_timeout>=4.0.0,<5.0.0
# a bit of attention to bump. # a bit of attention to bump.
apispec>=6.0.0,<6.7.0 apispec>=6.0.0,<6.7.0
# 1.4.1 introduced a memory regression that exhausts memory in the test suite # 1.4.1 appears to use much more memory, where the python test suite runs out of memory
# (https://github.com/marshmallow-code/marshmallow-sqlalchemy/issues/665). 1.4.2 # causing CI to fail. 1.4.0 is the last version that works.
# claimed a fix but did not address the root cause; only 1.5.0 actually fixes it. # https://marshmallow-sqlalchemy.readthedocs.io/en/latest/changelog.html#id3
marshmallow-sqlalchemy>=1.5.0 # Opened this issue https://github.com/marshmallow-code/marshmallow-sqlalchemy/issues/665
marshmallow-sqlalchemy>=1.3.0,<1.4.1
# needed for python 3.12 support # needed for python 3.12 support
openapi-schema-validator>=0.6.3 openapi-schema-validator>=0.6.3
@@ -57,9 +58,3 @@ openapi-schema-validator>=0.6.3
# Known affected packages: Preset's 'clients' package # Known affected packages: Preset's 'clients' package
# See docs/docs/contributing/pkg-resources-migration.md for details # See docs/docs/contributing/pkg-resources-migration.md for details
setuptools<81 setuptools<81
# google-auth 2.53+ dropped its transitive dependency on cachetools, which is
# imported directly by superset.db_engine_specs.aws_iam. We declare cachetools
# explicitly in pyproject.toml and pin google-auth to the post-drop range so
# the install path is internally consistent (#40962).
google-auth>=2.53.0,<3.0.0

View File

@@ -45,12 +45,12 @@ cachelib==0.13.0
# flask-caching # flask-caching
# flask-session # flask-session
cachetools==6.2.1 cachetools==6.2.1
# via apache-superset (pyproject.toml) # via google-auth
cattrs==25.1.1 cattrs==25.1.1
# via requests-cache # via requests-cache
celery==5.5.2 celery==5.5.2
# via apache-superset (pyproject.toml) # via apache-superset (pyproject.toml)
certifi==2026.5.20 certifi==2025.6.15
# via # via
# requests # requests
# selenium # selenium
@@ -84,13 +84,12 @@ colorama==0.4.6
# flask-appbuilder # flask-appbuilder
cron-descriptor==1.4.5 cron-descriptor==1.4.5
# via apache-superset (pyproject.toml) # via apache-superset (pyproject.toml)
croniter==6.2.2 croniter==6.0.0
# via apache-superset (pyproject.toml) # via apache-superset (pyproject.toml)
cryptography==48.0.1 cryptography==46.0.7
# via # via
# -r requirements/base.in # -r requirements/base.in
# apache-superset (pyproject.toml) # apache-superset (pyproject.toml)
# google-auth
# paramiko # paramiko
# pyopenssl # pyopenssl
defusedxml==0.7.1 defusedxml==0.7.1
@@ -132,7 +131,7 @@ flask-caching==2.3.1
# via apache-superset (pyproject.toml) # via apache-superset (pyproject.toml)
flask-compress==1.17 flask-compress==1.17
# via apache-superset (pyproject.toml) # via apache-superset (pyproject.toml)
flask-cors==6.0.5 flask-cors==6.0.2
# via apache-superset (pyproject.toml) # via apache-superset (pyproject.toml)
flask-jwt-extended==4.7.1 flask-jwt-extended==4.7.1
# via flask-appbuilder # via flask-appbuilder
@@ -142,7 +141,7 @@ flask-login==0.6.3
# via # via
# apache-superset (pyproject.toml) # apache-superset (pyproject.toml)
# flask-appbuilder # flask-appbuilder
flask-migrate==4.1.0 flask-migrate==3.1.0
# via apache-superset (pyproject.toml) # via apache-superset (pyproject.toml)
flask-session==0.8.0 flask-session==0.8.0
# via apache-superset (pyproject.toml) # via apache-superset (pyproject.toml)
@@ -152,7 +151,7 @@ flask-sqlalchemy==2.5.1
# flask-migrate # flask-migrate
flask-talisman==1.1.0 flask-talisman==1.1.0
# via apache-superset (pyproject.toml) # via apache-superset (pyproject.toml)
flask-wtf==1.3.0 flask-wtf==1.2.2
# via # via
# apache-superset (pyproject.toml) # apache-superset (pyproject.toml)
# flask-appbuilder # flask-appbuilder
@@ -160,11 +159,9 @@ geographiclib==2.0
# via geopy # via geopy
geopy==2.4.1 geopy==2.4.1
# via apache-superset (pyproject.toml) # via apache-superset (pyproject.toml)
google-auth==2.53.0 google-auth==2.43.0
# via # via shillelagh
# -r requirements/base.in greenlet==3.5.0
# shillelagh
greenlet==3.5.1
# via # via
# apache-superset (pyproject.toml) # apache-superset (pyproject.toml)
# shillelagh # shillelagh
@@ -197,7 +194,7 @@ jinja2==3.1.6
# via # via
# flask # flask
# flask-babel # flask-babel
jsonpath-ng==1.8.0 jsonpath-ng==1.7.0
# via apache-superset (pyproject.toml) # via apache-superset (pyproject.toml)
jsonschema==4.23.0 jsonschema==4.23.0
# via # via
@@ -226,13 +223,13 @@ markupsafe==3.0.2
# mako # mako
# werkzeug # werkzeug
# wtforms # wtforms
marshmallow==4.3.0 marshmallow==3.26.2
# via # via
# apache-superset (pyproject.toml) # apache-superset (pyproject.toml)
# flask-appbuilder # flask-appbuilder
# marshmallow-sqlalchemy # marshmallow-sqlalchemy
# marshmallow-union # marshmallow-union
marshmallow-sqlalchemy==1.5.0 marshmallow-sqlalchemy==1.4.0
# via # via
# -r requirements/base.in # -r requirements/base.in
# flask-appbuilder # flask-appbuilder
@@ -240,7 +237,7 @@ marshmallow-union==0.1.15
# via apache-superset (pyproject.toml) # via apache-superset (pyproject.toml)
mdurl==0.1.2 mdurl==0.1.2
# via markdown-it-py # via markdown-it-py
msgpack==1.2.1 msgpack==1.0.8
# via apache-superset (pyproject.toml) # via apache-superset (pyproject.toml)
msgspec==0.19.0 msgspec==0.19.0
# via flask-session # via flask-session
@@ -273,6 +270,7 @@ packaging==25.0
# deprecation # deprecation
# gunicorn # gunicorn
# limits # limits
# marshmallow
# shillelagh # shillelagh
pandas==2.1.4 pandas==2.1.4
# via apache-superset (pyproject.toml) # via apache-superset (pyproject.toml)
@@ -288,19 +286,23 @@ pillow==12.2.0
# via apache-superset (pyproject.toml) # via apache-superset (pyproject.toml)
platformdirs==4.3.8 platformdirs==4.3.8
# via requests-cache # via requests-cache
ply==3.11
# via jsonpath-ng
polyline==2.0.2 polyline==2.0.2
# via apache-superset (pyproject.toml) # via apache-superset (pyproject.toml)
prison==0.2.1 prison==0.2.1
# via flask-appbuilder # via flask-appbuilder
prompt-toolkit==3.0.51 prompt-toolkit==3.0.51
# via click-repl # via click-repl
pyarrow==24.0.0 pyarrow==20.0.0
# via # via
# -r requirements/base.in # -r requirements/base.in
# apache-superset (pyproject.toml) # apache-superset (pyproject.toml)
# apache-superset-core # apache-superset-core
pyasn1==0.6.3 pyasn1==0.6.3
# via pyasn1-modules # via
# pyasn1-modules
# rsa
pyasn1-modules==0.4.2 pyasn1-modules==0.4.2
# via google-auth # via google-auth
pycparser==2.22 pycparser==2.22
@@ -323,7 +325,7 @@ pyjwt==2.12.0
# redis # redis
pynacl==1.6.2 pynacl==1.6.2
# via paramiko # via paramiko
pyopenssl==26.2.0 pyopenssl==26.0.0
# via # via
# -r requirements/base.in # -r requirements/base.in
# shillelagh # shillelagh
@@ -344,11 +346,12 @@ python-dotenv==1.2.2
# via apache-superset (pyproject.toml) # via apache-superset (pyproject.toml)
pytz==2025.2 pytz==2025.2
# via # via
# croniter
# flask-babel # flask-babel
# pandas # pandas
pyxlsb==1.0.10 pyxlsb==1.0.10
# via pandas # via pandas
pyyaml==6.0.3 pyyaml==6.0.2
# via # via
# apache-superset (pyproject.toml) # apache-superset (pyproject.toml)
# apispec # apispec
@@ -375,13 +378,15 @@ rpds-py==0.25.0
# via # via
# jsonschema # jsonschema
# referencing # referencing
selenium==4.44.0 rsa==4.9.1
# via google-auth
selenium==4.32.0
# via apache-superset (pyproject.toml) # via apache-superset (pyproject.toml)
setuptools==80.9.0 setuptools==80.9.0
# via -r requirements/base.in # via -r requirements/base.in
shillelagh==1.4.4 shillelagh==1.4.4
# via apache-superset (pyproject.toml) # via apache-superset (pyproject.toml)
simplejson==4.1.1 simplejson==3.20.1
# via apache-superset (pyproject.toml) # via apache-superset (pyproject.toml)
six==1.17.0 six==1.17.0
# via # via
@@ -418,7 +423,7 @@ sshtunnel==0.4.0
# via apache-superset (pyproject.toml) # via apache-superset (pyproject.toml)
tabulate==0.10.0 tabulate==0.10.0
# via apache-superset (pyproject.toml) # via apache-superset (pyproject.toml)
trio==0.33.0 trio==0.30.0
# via # via
# selenium # selenium
# trio-websocket # trio-websocket
@@ -475,7 +480,7 @@ wrapt==1.17.2
# via deprecated # via deprecated
wsproto==1.2.0 wsproto==1.2.0
# via trio-websocket # via trio-websocket
wtforms==3.2.2 wtforms==3.2.1
# via # via
# apache-superset (pyproject.toml) # apache-superset (pyproject.toml)
# flask-appbuilder # flask-appbuilder

View File

@@ -100,7 +100,7 @@ cachelib==0.13.0
cachetools==6.2.1 cachetools==6.2.1
# via # via
# -c requirements/base-constraint.txt # -c requirements/base-constraint.txt
# apache-superset # google-auth
# py-key-value-aio # py-key-value-aio
caio==0.9.25 caio==0.9.25
# via aiofile # via aiofile
@@ -112,7 +112,7 @@ celery==5.5.2
# via # via
# -c requirements/base-constraint.txt # -c requirements/base-constraint.txt
# apache-superset # apache-superset
certifi==2026.5.20 certifi==2025.6.15
# via # via
# -c requirements/base-constraint.txt # -c requirements/base-constraint.txt
# httpcore # httpcore
@@ -174,16 +174,15 @@ cron-descriptor==1.4.5
# via # via
# -c requirements/base-constraint.txt # -c requirements/base-constraint.txt
# apache-superset # apache-superset
croniter==6.2.2 croniter==6.0.0
# via # via
# -c requirements/base-constraint.txt # -c requirements/base-constraint.txt
# apache-superset # apache-superset
cryptography==48.0.1 cryptography==46.0.7
# via # via
# -c requirements/base-constraint.txt # -c requirements/base-constraint.txt
# apache-superset # apache-superset
# authlib # authlib
# google-auth
# paramiko # paramiko
# pyjwt # pyjwt
# pyopenssl # pyopenssl
@@ -277,7 +276,7 @@ flask-compress==1.17
# via # via
# -c requirements/base-constraint.txt # -c requirements/base-constraint.txt
# apache-superset # apache-superset
flask-cors==6.0.5 flask-cors==6.0.2
# via # via
# -c requirements/base-constraint.txt # -c requirements/base-constraint.txt
# apache-superset # apache-superset
@@ -294,7 +293,7 @@ flask-login==0.6.3
# -c requirements/base-constraint.txt # -c requirements/base-constraint.txt
# apache-superset # apache-superset
# flask-appbuilder # flask-appbuilder
flask-migrate==4.1.0 flask-migrate==3.1.0
# via # via
# -c requirements/base-constraint.txt # -c requirements/base-constraint.txt
# apache-superset # apache-superset
@@ -313,7 +312,7 @@ flask-talisman==1.1.0
# apache-superset # apache-superset
flask-testing==0.8.1 flask-testing==0.8.1
# via apache-superset # via apache-superset
flask-wtf==1.3.0 flask-wtf==1.2.2
# via # via
# -c requirements/base-constraint.txt # -c requirements/base-constraint.txt
# apache-superset # apache-superset
@@ -341,7 +340,7 @@ google-api-core==2.23.0
# google-cloud-core # google-cloud-core
# pandas-gbq # pandas-gbq
# sqlalchemy-bigquery # sqlalchemy-bigquery
google-auth==2.53.0 google-auth==2.43.0
# via # via
# -c requirements/base-constraint.txt # -c requirements/base-constraint.txt
# google-api-core # google-api-core
@@ -374,7 +373,7 @@ googleapis-common-protos==1.66.0
# via # via
# google-api-core # google-api-core
# grpcio-status # grpcio-status
greenlet==3.5.1 greenlet==3.5.0
# via # via
# -c requirements/base-constraint.txt # -c requirements/base-constraint.txt
# apache-superset # apache-superset
@@ -383,7 +382,7 @@ greenlet==3.5.1
# sqlalchemy # sqlalchemy
griffelib==2.0.2 griffelib==2.0.2
# via fastmcp # via fastmcp
grpcio==1.81.1 grpcio==1.71.0
# via # via
# apache-superset # apache-superset
# google-api-core # google-api-core
@@ -472,7 +471,7 @@ jmespath==1.1.0
# via # via
# boto3 # boto3
# botocore # botocore
jsonpath-ng==1.8.0 jsonpath-ng==1.7.0
# via # via
# -c requirements/base-constraint.txt # -c requirements/base-constraint.txt
# apache-superset # apache-superset
@@ -508,8 +507,6 @@ limits==5.1.0
# via # via
# -c requirements/base-constraint.txt # -c requirements/base-constraint.txt
# flask-limiter # flask-limiter
lz4==4.4.5
# via trino
mako==1.3.12 mako==1.3.12
# via # via
# -c requirements/base-constraint.txt # -c requirements/base-constraint.txt
@@ -530,14 +527,14 @@ markupsafe==3.0.2
# mako # mako
# werkzeug # werkzeug
# wtforms # wtforms
marshmallow==4.3.0 marshmallow==3.26.2
# via # via
# -c requirements/base-constraint.txt # -c requirements/base-constraint.txt
# apache-superset # apache-superset
# flask-appbuilder # flask-appbuilder
# marshmallow-sqlalchemy # marshmallow-sqlalchemy
# marshmallow-union # marshmallow-union
marshmallow-sqlalchemy==1.5.0 marshmallow-sqlalchemy==1.4.0
# via # via
# -c requirements/base-constraint.txt # -c requirements/base-constraint.txt
# flask-appbuilder # flask-appbuilder
@@ -559,7 +556,7 @@ more-itertools==10.8.0
# via # via
# jaraco-classes # jaraco-classes
# jaraco-functools # jaraco-functools
msgpack==1.2.1 msgpack==1.0.8
# via # via
# -c requirements/base-constraint.txt # -c requirements/base-constraint.txt
# apache-superset # apache-superset
@@ -611,8 +608,6 @@ ordered-set==4.1.0
# via # via
# -c requirements/base-constraint.txt # -c requirements/base-constraint.txt
# flask-limiter # flask-limiter
orjson==3.11.9
# via trino
outcome==1.3.0.post0 outcome==1.3.0.post0
# via # via
# -c requirements/base-constraint.txt # -c requirements/base-constraint.txt
@@ -631,6 +626,7 @@ packaging==25.0
# google-cloud-bigquery # google-cloud-bigquery
# gunicorn # gunicorn
# limits # limits
# marshmallow
# matplotlib # matplotlib
# pytest # pytest
# shillelagh # shillelagh
@@ -678,6 +674,10 @@ platformdirs==4.3.8
# virtualenv # virtualenv
pluggy==1.5.0 pluggy==1.5.0
# via pytest # via pytest
ply==3.11
# via
# -c requirements/base-constraint.txt
# jsonpath-ng
polib==1.2.0 polib==1.2.0
# via apache-superset # via apache-superset
polyline==2.0.2 polyline==2.0.2
@@ -690,7 +690,7 @@ prison==0.2.1
# via # via
# -c requirements/base-constraint.txt # -c requirements/base-constraint.txt
# flask-appbuilder # flask-appbuilder
progress==1.6.1 progress==1.6
# via apache-superset # via apache-superset
prompt-toolkit==3.0.51 prompt-toolkit==3.0.51
# via # via
@@ -715,7 +715,7 @@ psycopg2-binary==2.9.12
# via apache-superset # via apache-superset
py-key-value-aio==0.4.4 py-key-value-aio==0.4.4
# via fastmcp # via fastmcp
pyarrow==24.0.0 pyarrow==20.0.0
# via # via
# -c requirements/base-constraint.txt # -c requirements/base-constraint.txt
# apache-superset # apache-superset
@@ -727,6 +727,7 @@ pyasn1==0.6.3
# -c requirements/base-constraint.txt # -c requirements/base-constraint.txt
# pyasn1-modules # pyasn1-modules
# python-ldap # python-ldap
# rsa
pyasn1-modules==0.4.2 pyasn1-modules==0.4.2
# via # via
# -c requirements/base-constraint.txt # -c requirements/base-constraint.txt
@@ -783,7 +784,7 @@ pynacl==1.6.2
# via # via
# -c requirements/base-constraint.txt # -c requirements/base-constraint.txt
# paramiko # paramiko
pyopenssl==26.2.0 pyopenssl==26.0.0
# via # via
# -c requirements/base-constraint.txt # -c requirements/base-constraint.txt
# shillelagh # shillelagh
@@ -844,6 +845,7 @@ python-multipart==0.0.29
pytz==2025.2 pytz==2025.2
# via # via
# -c requirements/base-constraint.txt # -c requirements/base-constraint.txt
# croniter
# flask-babel # flask-babel
# pandas # pandas
# trino # trino
@@ -851,7 +853,7 @@ pyxlsb==1.0.10
# via # via
# -c requirements/base-constraint.txt # -c requirements/base-constraint.txt
# pandas # pandas
pyyaml==6.0.3 pyyaml==6.0.2
# via # via
# -c requirements/base-constraint.txt # -c requirements/base-constraint.txt
# apache-superset # apache-superset
@@ -913,13 +915,17 @@ rpds-py==0.25.0
# -c requirements/base-constraint.txt # -c requirements/base-constraint.txt
# jsonschema # jsonschema
# referencing # referencing
rsa==4.9.1
# via
# -c requirements/base-constraint.txt
# google-auth
ruff==0.9.7 ruff==0.9.7
# via apache-superset # via apache-superset
s3transfer==0.16.0 s3transfer==0.16.0
# via boto3 # via boto3
secretstorage==3.5.0 secretstorage==3.5.0
# via keyring # via keyring
selenium==4.44.0 selenium==4.32.0
# via # via
# -c requirements/base-constraint.txt # -c requirements/base-constraint.txt
# apache-superset # apache-superset
@@ -937,7 +943,7 @@ shillelagh==1.4.4
# via # via
# -c requirements/base-constraint.txt # -c requirements/base-constraint.txt
# apache-superset # apache-superset
simplejson==4.1.1 simplejson==3.20.1
# via # via
# -c requirements/base-constraint.txt # -c requirements/base-constraint.txt
# apache-superset # apache-superset
@@ -974,7 +980,7 @@ sqlalchemy==1.4.54
# shillelagh # shillelagh
# sqlalchemy-bigquery # sqlalchemy-bigquery
# sqlalchemy-utils # sqlalchemy-utils
sqlalchemy-bigquery==1.17.0 sqlalchemy-bigquery==1.15.0
# via apache-superset # via apache-superset
sqlalchemy-utils==0.42.0 sqlalchemy-utils==0.42.0
# via # via
@@ -1005,7 +1011,7 @@ tabulate==0.10.0
# via # via
# -c requirements/base-constraint.txt # -c requirements/base-constraint.txt
# apache-superset # apache-superset
tiktoken==0.13.0 tiktoken==0.12.0
# via apache-superset # via apache-superset
tomli-w==1.2.0 tomli-w==1.2.0
# via apache-superset-extensions-cli # via apache-superset-extensions-cli
@@ -1015,9 +1021,9 @@ tqdm==4.67.1
# via # via
# cmdstanpy # cmdstanpy
# prophet # prophet
trino==0.337.0 trino==0.330.0
# via apache-superset # via apache-superset
trio==0.33.0 trio==0.30.0
# via # via
# -c requirements/base-constraint.txt # -c requirements/base-constraint.txt
# selenium # selenium
@@ -1035,7 +1041,6 @@ typing-extensions==4.15.0
# apache-superset-core # apache-superset-core
# cattrs # cattrs
# exceptiongroup # exceptiongroup
# grpcio
# limits # limits
# mcp # mcp
# opentelemetry-api # opentelemetry-api
@@ -1120,7 +1125,7 @@ wsproto==1.2.0
# via # via
# -c requirements/base-constraint.txt # -c requirements/base-constraint.txt
# trio-websocket # trio-websocket
wtforms==3.2.2 wtforms==3.2.1
# via # via
# -c requirements/base-constraint.txt # -c requirements/base-constraint.txt
# apache-superset # apache-superset
@@ -1150,4 +1155,3 @@ zstandard==0.23.0
# via # via
# -c requirements/base-constraint.txt # -c requirements/base-constraint.txt
# flask-compress # flask-compress
# trino

View File

@@ -30,7 +30,7 @@ from flask import current_app
from flask_appbuilder import Model from flask_appbuilder import Model
from flask_migrate import downgrade, upgrade from flask_migrate import downgrade, upgrade
from progress.bar import ChargingBar from progress.bar import ChargingBar
from sqlalchemy import create_engine, inspect, text from sqlalchemy import create_engine, inspect
from sqlalchemy.ext.automap import automap_base from sqlalchemy.ext.automap import automap_base
from superset import db from superset import db
@@ -154,7 +154,7 @@ def main( # noqa: C901
print(f"Migration goes from {down_revision} to {revision}") print(f"Migration goes from {down_revision} to {revision}")
current_revision = db.engine.execute( current_revision = db.engine.execute(
text("SELECT version_num FROM alembic_version") "SELECT version_num FROM alembic_version"
).scalar() ).scalar()
print(f"Current version of the DB is {current_revision}") print(f"Current version of the DB is {current_revision}")

View File

@@ -55,21 +55,10 @@ msgcat --sort-by-msgid --no-wrap --no-location superset/translations/messages.po
cat $LICENSE_TMP superset/translations/messages.pot > messages.pot.tmp \ cat $LICENSE_TMP superset/translations/messages.pot > messages.pot.tmp \
&& mv messages.pot.tmp superset/translations/messages.pot && mv messages.pot.tmp superset/translations/messages.pot
# --no-fuzzy-matching: when a *new* source string is added, Babel's fuzzy
# matcher otherwise guesses a "close" existing translation and marks it
# `#, fuzzy` in every language catalog. Those guesses are (a) usually wrong
# (e.g. a new "valuename" string mapped onto an unrelated "table name"
# translation) and (b) counted by check_translation_regression.py as a
# regression, so every PR that merely adds a translatable string failed the
# babel-extract check. Disabling fuzzy matching means new strings land as
# cleanly untranslated (empty msgstr) instead — accurate, and no spurious
# regression. Renames likewise drop the stale translation rather than
# stranding a wrong guess; the string is re-translated by the community.
pybabel update \ pybabel update \
-i superset/translations/messages.pot \ -i superset/translations/messages.pot \
-d superset/translations \ -d superset/translations \
--ignore-obsolete \ --ignore-obsolete
--no-fuzzy-matching
# Chop off last blankline from po/pot files, see https://github.com/python-babel/babel/issues/799 # Chop off last blankline from po/pot files, see https://github.com/python-babel/babel/issues/799
for file in $( find superset/translations/** ); for file in $( find superset/translations/** );

View File

@@ -106,7 +106,6 @@ LANGUAGE_NAMES: dict[str, str] = {
"ru": "Russian", "ru": "Russian",
"sk": "Slovak", "sk": "Slovak",
"sl": "Slovenian", "sl": "Slovenian",
"sr": "Serbian",
"tr": "Turkish", "tr": "Turkish",
"uk": "Ukrainian", "uk": "Ukrainian",
"zh": "Chinese (Simplified)", "zh": "Chinese (Simplified)",

View File

@@ -20,21 +20,20 @@ Check that source-code changes don't cause translation regressions.
What counts as a regression What counts as a regression
--------------------------- ---------------------------
A regression is an *existing translation that a source change invalidated*. A regression is an *existing translation that a source change invalidated*
The check keys on the **increase in fuzzy entries** rather than a drop in the i.e. a string was renamed/reworded so its committed translation no longer
translated count, because a count drop happens identically for a benign applies. ``babel_update.sh`` (``pybabel update --ignore-obsolete``) surfaces
*deletion* and a real *rename*, so it cannot distinguish the two — whereas a exactly these as **newly fuzzy** entries: the old translation is fuzzy-matched
``#, fuzzy`` marker unambiguously flags a stranded translation. onto the new ``msgid`` and flagged ``#, fuzzy``.
Note ``babel_update.sh`` runs ``pybabel update`` with ``--no-fuzzy-matching``, Crucially, *deleting* a translatable string is **not** a regression. With
so *adding* (or renaming) a source string does **not** auto-generate a fuzzy ``--ignore-obsolete`` a removed string is dropped from the catalogs entirely;
guess against an unrelated existing translation — new strings land as cleanly no fuzzy entry is created. So a PR that intentionally removes a string (e.g. a
untranslated (empty ``msgstr``). This deliberately avoids the prior behaviour security fix that stops rendering a value) legitimately lowers the translated
where *every* PR that merely added a translatable string tripped this check on count without introducing any fuzzies, and must not be flagged. We therefore
spurious fuzzies. As a result the check now guards against ``#, fuzzy`` entries key the check on the **increase in fuzzy entries**, not on a drop in the
that arrive another way — e.g. a committed ``.po`` edit — rather than ones the translated count (a drop happens identically for a benign deletion and a real
update step synthesises. *Deleting* a string is still not a regression: with rename, so it cannot distinguish the two).
``--ignore-obsolete`` it is simply dropped and no fuzzy is created.
Usage Usage
----- -----

View File

@@ -1 +1 @@
v24.16.0 v22.22.0

View File

@@ -27,6 +27,19 @@
"webpack-cli": "^5.1.4" "webpack-cli": "^5.1.4"
} }
}, },
"node_modules/@ampproject/remapping": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz",
"integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==",
"dev": true,
"dependencies": {
"@jridgewell/gen-mapping": "^0.3.5",
"@jridgewell/trace-mapping": "^0.3.24"
},
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@babel/cli": { "node_modules/@babel/cli": {
"version": "7.25.6", "version": "7.25.6",
"resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.25.6.tgz", "resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.25.6.tgz",
@@ -58,12 +71,12 @@
} }
}, },
"node_modules/@babel/code-frame": { "node_modules/@babel/code-frame": {
"version": "7.29.7", "version": "7.29.0",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz",
"integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@babel/helper-validator-identifier": "^7.29.7", "@babel/helper-validator-identifier": "^7.28.5",
"js-tokens": "^4.0.0", "js-tokens": "^4.0.0",
"picocolors": "^1.1.1" "picocolors": "^1.1.1"
}, },
@@ -72,30 +85,32 @@
} }
}, },
"node_modules/@babel/compat-data": { "node_modules/@babel/compat-data": {
"version": "7.29.7", "version": "7.25.4",
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.4.tgz",
"integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", "integrity": "sha512-+LGRog6RAsCJrrrg/IO6LGmpphNe5DiK30dGjCoxxeGv49B10/3XYGxPsAwrDlMFcFEvdAUavDT8r9k/hSyQqQ==",
"dev": true, "dev": true,
"license": "MIT",
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
} }
}, },
"node_modules/@babel/core": { "node_modules/@babel/core": {
"version": "7.29.6", "version": "7.25.2",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.6.tgz", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.2.tgz",
"integrity": "sha512-QdxmAo/ikZqqRGA8s43ww8lcql6naWRvEz0FFrl6MIlc7Gi6TroXnSdWa5U/kq6fzcpqpHesicQxFZIieZbyIA==", "integrity": "sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"@babel/code-frame": "^7.29.0", "@ampproject/remapping": "^2.2.0",
"@babel/generator": "^7.29.6", "@babel/code-frame": "^7.24.7",
"@babel/helper-compilation-targets": "^7.28.6", "@babel/generator": "^7.25.0",
"@babel/helper-module-transforms": "^7.28.6", "@babel/helper-compilation-targets": "^7.25.2",
"@babel/helpers": "^7.29.2", "@babel/helper-module-transforms": "^7.25.2",
"@babel/parser": "^7.29.3", "@babel/helpers": "^7.25.0",
"@babel/template": "^7.28.6", "@babel/parser": "^7.25.0",
"@babel/traverse": "^7.29.0", "@babel/template": "^7.25.0",
"@babel/types": "^7.29.0", "@babel/traverse": "^7.25.2",
"@jridgewell/remapping": "^2.3.5", "@babel/types": "^7.25.2",
"convert-source-map": "^2.0.0", "convert-source-map": "^2.0.0",
"debug": "^4.1.0", "debug": "^4.1.0",
"gensync": "^1.0.0-beta.2", "gensync": "^1.0.0-beta.2",
@@ -111,13 +126,13 @@
} }
}, },
"node_modules/@babel/generator": { "node_modules/@babel/generator": {
"version": "7.29.7", "version": "7.29.1",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz",
"integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==", "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@babel/parser": "^7.29.7", "@babel/parser": "^7.29.0",
"@babel/types": "^7.29.7", "@babel/types": "^7.29.0",
"@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/gen-mapping": "^0.3.12",
"@jridgewell/trace-mapping": "^0.3.28", "@jridgewell/trace-mapping": "^0.3.28",
"jsesc": "^3.0.2" "jsesc": "^3.0.2"
@@ -154,14 +169,15 @@
} }
}, },
"node_modules/@babel/helper-compilation-targets": { "node_modules/@babel/helper-compilation-targets": {
"version": "7.29.7", "version": "7.25.2",
"resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.2.tgz",
"integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", "integrity": "sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"@babel/compat-data": "^7.29.7", "@babel/compat-data": "^7.25.2",
"@babel/helper-validator-option": "^7.29.7", "@babel/helper-validator-option": "^7.24.8",
"browserslist": "^4.24.0", "browserslist": "^4.23.1",
"lru-cache": "^5.1.1", "lru-cache": "^5.1.1",
"semver": "^6.3.1" "semver": "^6.3.1"
}, },
@@ -366,28 +382,29 @@
} }
}, },
"node_modules/@babel/helper-string-parser": { "node_modules/@babel/helper-string-parser": {
"version": "7.29.7", "version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
"integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==",
"dev": true, "dev": true,
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
} }
}, },
"node_modules/@babel/helper-validator-identifier": { "node_modules/@babel/helper-validator-identifier": {
"version": "7.29.7", "version": "7.28.5",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz",
"integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==",
"dev": true, "dev": true,
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
} }
}, },
"node_modules/@babel/helper-validator-option": { "node_modules/@babel/helper-validator-option": {
"version": "7.29.7", "version": "7.24.8",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz",
"integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", "integrity": "sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==",
"dev": true, "dev": true,
"license": "MIT",
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
} }
@@ -408,25 +425,26 @@
} }
}, },
"node_modules/@babel/helpers": { "node_modules/@babel/helpers": {
"version": "7.29.7", "version": "7.25.6",
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.6.tgz",
"integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", "integrity": "sha512-Xg0tn4HcfTijTwfDwYlvVCl43V6h4KyVVX2aEm4qdO/PC6L2YvzLHFdmxhoeSA3eslcE6+ZVXHgWwopXYLNq4Q==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"@babel/template": "^7.29.7", "@babel/template": "^7.25.0",
"@babel/types": "^7.29.7" "@babel/types": "^7.25.6"
}, },
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
} }
}, },
"node_modules/@babel/parser": { "node_modules/@babel/parser": {
"version": "7.29.7", "version": "7.29.3",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.3.tgz",
"integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", "integrity": "sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@babel/types": "^7.29.7" "@babel/types": "^7.29.0"
}, },
"bin": { "bin": {
"parser": "bin/babel-parser.js" "parser": "bin/babel-parser.js"
@@ -1825,14 +1843,14 @@
} }
}, },
"node_modules/@babel/template": { "node_modules/@babel/template": {
"version": "7.29.7", "version": "7.28.6",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz",
"integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@babel/code-frame": "^7.29.7", "@babel/code-frame": "^7.28.6",
"@babel/parser": "^7.29.7", "@babel/parser": "^7.28.6",
"@babel/types": "^7.29.7" "@babel/types": "^7.28.6"
}, },
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
@@ -1857,13 +1875,13 @@
} }
}, },
"node_modules/@babel/types": { "node_modules/@babel/types": {
"version": "7.29.7", "version": "7.29.0",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz",
"integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@babel/helper-string-parser": "^7.29.7", "@babel/helper-string-parser": "^7.27.1",
"@babel/helper-validator-identifier": "^7.29.7" "@babel/helper-validator-identifier": "^7.28.5"
}, },
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
@@ -2631,16 +2649,6 @@
"@jridgewell/trace-mapping": "^0.3.24" "@jridgewell/trace-mapping": "^0.3.24"
} }
}, },
"node_modules/@jridgewell/remapping": {
"version": "2.3.5",
"resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz",
"integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
"dev": true,
"dependencies": {
"@jridgewell/gen-mapping": "^0.3.5",
"@jridgewell/trace-mapping": "^0.3.24"
}
},
"node_modules/@jridgewell/resolve-uri": { "node_modules/@jridgewell/resolve-uri": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz",
@@ -7975,6 +7983,16 @@
} }
}, },
"dependencies": { "dependencies": {
"@ampproject/remapping": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz",
"integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==",
"dev": true,
"requires": {
"@jridgewell/gen-mapping": "^0.3.5",
"@jridgewell/trace-mapping": "^0.3.24"
}
},
"@babel/cli": { "@babel/cli": {
"version": "7.25.6", "version": "7.25.6",
"resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.25.6.tgz", "resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.25.6.tgz",
@@ -7993,38 +8011,38 @@
} }
}, },
"@babel/code-frame": { "@babel/code-frame": {
"version": "7.29.7", "version": "7.29.0",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz",
"integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==",
"dev": true, "dev": true,
"requires": { "requires": {
"@babel/helper-validator-identifier": "^7.29.7", "@babel/helper-validator-identifier": "^7.28.5",
"js-tokens": "^4.0.0", "js-tokens": "^4.0.0",
"picocolors": "^1.1.1" "picocolors": "^1.1.1"
} }
}, },
"@babel/compat-data": { "@babel/compat-data": {
"version": "7.29.7", "version": "7.25.4",
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.4.tgz",
"integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", "integrity": "sha512-+LGRog6RAsCJrrrg/IO6LGmpphNe5DiK30dGjCoxxeGv49B10/3XYGxPsAwrDlMFcFEvdAUavDT8r9k/hSyQqQ==",
"dev": true "dev": true
}, },
"@babel/core": { "@babel/core": {
"version": "7.29.6", "version": "7.25.2",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.6.tgz", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.2.tgz",
"integrity": "sha512-QdxmAo/ikZqqRGA8s43ww8lcql6naWRvEz0FFrl6MIlc7Gi6TroXnSdWa5U/kq6fzcpqpHesicQxFZIieZbyIA==", "integrity": "sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==",
"dev": true, "dev": true,
"requires": { "requires": {
"@babel/code-frame": "^7.29.0", "@ampproject/remapping": "^2.2.0",
"@babel/generator": "^7.29.6", "@babel/code-frame": "^7.24.7",
"@babel/helper-compilation-targets": "^7.28.6", "@babel/generator": "^7.25.0",
"@babel/helper-module-transforms": "^7.28.6", "@babel/helper-compilation-targets": "^7.25.2",
"@babel/helpers": "^7.29.2", "@babel/helper-module-transforms": "^7.25.2",
"@babel/parser": "^7.29.3", "@babel/helpers": "^7.25.0",
"@babel/template": "^7.28.6", "@babel/parser": "^7.25.0",
"@babel/traverse": "^7.29.0", "@babel/template": "^7.25.0",
"@babel/types": "^7.29.0", "@babel/traverse": "^7.25.2",
"@jridgewell/remapping": "^2.3.5", "@babel/types": "^7.25.2",
"convert-source-map": "^2.0.0", "convert-source-map": "^2.0.0",
"debug": "^4.1.0", "debug": "^4.1.0",
"gensync": "^1.0.0-beta.2", "gensync": "^1.0.0-beta.2",
@@ -8033,13 +8051,13 @@
} }
}, },
"@babel/generator": { "@babel/generator": {
"version": "7.29.7", "version": "7.29.1",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz",
"integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==", "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==",
"dev": true, "dev": true,
"requires": { "requires": {
"@babel/parser": "^7.29.7", "@babel/parser": "^7.29.0",
"@babel/types": "^7.29.7", "@babel/types": "^7.29.0",
"@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/gen-mapping": "^0.3.12",
"@jridgewell/trace-mapping": "^0.3.28", "@jridgewell/trace-mapping": "^0.3.28",
"jsesc": "^3.0.2" "jsesc": "^3.0.2"
@@ -8065,14 +8083,14 @@
} }
}, },
"@babel/helper-compilation-targets": { "@babel/helper-compilation-targets": {
"version": "7.29.7", "version": "7.25.2",
"resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.2.tgz",
"integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", "integrity": "sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw==",
"dev": true, "dev": true,
"requires": { "requires": {
"@babel/compat-data": "^7.29.7", "@babel/compat-data": "^7.25.2",
"@babel/helper-validator-option": "^7.29.7", "@babel/helper-validator-option": "^7.24.8",
"browserslist": "^4.24.0", "browserslist": "^4.23.1",
"lru-cache": "^5.1.1", "lru-cache": "^5.1.1",
"semver": "^6.3.1" "semver": "^6.3.1"
} }
@@ -8211,21 +8229,21 @@
} }
}, },
"@babel/helper-string-parser": { "@babel/helper-string-parser": {
"version": "7.29.7", "version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
"integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==",
"dev": true "dev": true
}, },
"@babel/helper-validator-identifier": { "@babel/helper-validator-identifier": {
"version": "7.29.7", "version": "7.28.5",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz",
"integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==",
"dev": true "dev": true
}, },
"@babel/helper-validator-option": { "@babel/helper-validator-option": {
"version": "7.29.7", "version": "7.24.8",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz",
"integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", "integrity": "sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==",
"dev": true "dev": true
}, },
"@babel/helper-wrap-function": { "@babel/helper-wrap-function": {
@@ -8240,22 +8258,22 @@
} }
}, },
"@babel/helpers": { "@babel/helpers": {
"version": "7.29.7", "version": "7.25.6",
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.6.tgz",
"integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", "integrity": "sha512-Xg0tn4HcfTijTwfDwYlvVCl43V6h4KyVVX2aEm4qdO/PC6L2YvzLHFdmxhoeSA3eslcE6+ZVXHgWwopXYLNq4Q==",
"dev": true, "dev": true,
"requires": { "requires": {
"@babel/template": "^7.29.7", "@babel/template": "^7.25.0",
"@babel/types": "^7.29.7" "@babel/types": "^7.25.6"
} }
}, },
"@babel/parser": { "@babel/parser": {
"version": "7.29.7", "version": "7.29.3",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.3.tgz",
"integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", "integrity": "sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA==",
"dev": true, "dev": true,
"requires": { "requires": {
"@babel/types": "^7.29.7" "@babel/types": "^7.29.0"
} }
}, },
"@babel/plugin-bugfix-firefox-class-in-computed-class-key": { "@babel/plugin-bugfix-firefox-class-in-computed-class-key": {
@@ -9139,14 +9157,14 @@
} }
}, },
"@babel/template": { "@babel/template": {
"version": "7.29.7", "version": "7.28.6",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz",
"integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==",
"dev": true, "dev": true,
"requires": { "requires": {
"@babel/code-frame": "^7.29.7", "@babel/code-frame": "^7.28.6",
"@babel/parser": "^7.29.7", "@babel/parser": "^7.28.6",
"@babel/types": "^7.29.7" "@babel/types": "^7.28.6"
} }
}, },
"@babel/traverse": { "@babel/traverse": {
@@ -9165,13 +9183,13 @@
} }
}, },
"@babel/types": { "@babel/types": {
"version": "7.29.7", "version": "7.29.0",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz",
"integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==",
"dev": true, "dev": true,
"requires": { "requires": {
"@babel/helper-string-parser": "^7.29.7", "@babel/helper-string-parser": "^7.27.1",
"@babel/helper-validator-identifier": "^7.29.7" "@babel/helper-validator-identifier": "^7.28.5"
} }
}, },
"@bcoe/v8-coverage": { "@bcoe/v8-coverage": {
@@ -9753,16 +9771,6 @@
"@jridgewell/trace-mapping": "^0.3.24" "@jridgewell/trace-mapping": "^0.3.24"
} }
}, },
"@jridgewell/remapping": {
"version": "2.3.5",
"resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz",
"integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
"dev": true,
"requires": {
"@jridgewell/gen-mapping": "^0.3.5",
"@jridgewell/trace-mapping": "^0.3.24"
}
},
"@jridgewell/resolve-uri": { "@jridgewell/resolve-uri": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz",

View File

@@ -1,6 +1,6 @@
{ {
"name": "@superset-ui/embedded-sdk", "name": "@superset-ui/embedded-sdk",
"version": "0.4.0", "version": "0.3.0",
"description": "SDK for embedding resources from Superset into your own application", "description": "SDK for embedding resources from Superset into your own application",
"access": "public", "access": "public",
"keywords": [ "keywords": [

View File

@@ -47,11 +47,7 @@ function logError(...args) {
execSync('npm publish --access public', { stdio: 'pipe' }); execSync('npm publish --access public', { stdio: 'pipe' });
log(`published ${version} to npm`); log(`published ${version} to npm`);
} catch (err) { } catch (err) {
// npm writes failure details to stderr (auth/permission/registry console.error(String(err.stdout));
// errors in particular), so surface both streams to avoid masking
// the real cause in CI logs.
if (err.stdout) console.error(String(err.stdout));
if (err.stderr) console.error(String(err.stderr));
logError('Encountered an error, details should be above'); logError('Encountered an error, details should be above');
process.exitCode = 1; process.exitCode = 1;
} }

View File

@@ -0,0 +1,34 @@
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
**/*{.,-}min.js
**/*.sh
coverage/**
dist/*
src/assets/images/*
node_modules/*
node_modules*/*
vendor/*
docs/*
src/dashboard/deprecated/*
src/temp/*
**/node_modules
*.d.ts
coverage/
esm/
lib/
tmp/
storybook-static/

View File

@@ -0,0 +1,523 @@
/**
* 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.
*/
// Register TypeScript require hook so ESLint can load .ts plugin files
require('tsx/cjs');
const packageConfig = require('./package.json');
const importCoreModules = [];
Object.entries(packageConfig.dependencies).forEach(([pkg]) => {
if (/@superset-ui/.test(pkg)) {
importCoreModules.push(pkg);
}
});
// ignore files in production mode
let ignorePatterns = [];
if (process.env.NODE_ENV === 'production') {
ignorePatterns = [
'*.test.{js,ts,jsx,tsx}',
'plugins/**/test/**/*',
'packages/**/test/**/*',
'packages/generator-superset/**/*',
];
}
const restrictedImportsRules = {
'no-design-icons': {
name: '@ant-design/icons',
message:
'Avoid importing icons directly from @ant-design/icons. Use the src/components/Icons component instead.',
},
'no-moment': {
name: 'moment',
message:
'Please use the dayjs library instead of moment.js. See https://day.js.org',
},
'no-lodash-memoize': {
name: 'lodash/memoize',
message: 'Lodash Memoize is unsafe! Please use memoize-one instead',
},
'no-testing-library-react': {
name: '@superset-ui/core/spec',
message: 'Please use spec/helpers/testing-library instead',
},
'no-testing-library-react-dom-utils': {
name: '@testing-library/react-dom-utils',
message: 'Please use spec/helpers/testing-library instead',
},
'no-antd': {
name: 'antd',
message: 'Please import Ant components from the index of src/components',
},
'no-superset-theme': {
name: '@superset-ui/core',
importNames: ['supersetTheme'],
message:
'Please use the theme directly from the ThemeProvider rather than importing supersetTheme.',
},
'no-query-string': {
name: 'query-string',
message: 'Please use the URLSearchParams API instead of query-string.',
},
'no-jest-mock-console': {
name: 'jest-mock-console',
message: 'Please use native Jest spies, i.e. jest.spyOn(console, "warn")',
},
};
module.exports = {
extends: [
'eslint:recommended',
'plugin:import/recommended',
'plugin:react-prefer-function-component/recommended',
'plugin:storybook/recommended',
'prettier',
],
parser: '@babel/eslint-parser',
parserOptions: {
ecmaVersion: 2020,
sourceType: 'module',
ecmaFeatures: {
jsx: true,
},
requireConfigFile: false,
babelOptions: {
presets: ['@babel/preset-react', '@babel/preset-env'],
},
},
env: {
browser: true,
node: true,
es2020: true,
},
settings: {
'import/resolver': {
node: {
extensions: ['.js', '.jsx', '.ts', '.tsx', '.json'],
moduleDirectory: ['node_modules', '.'],
},
typescript: {
alwaysTryTypes: true,
project: [
'./tsconfig.json',
'./packages/superset-ui-core/tsconfig.json',
'./packages/superset-ui-chart-controls/',
'./plugins/*/tsconfig.json',
],
},
},
'import/core-modules': importCoreModules,
react: {
version: 'detect',
},
},
plugins: [
'import',
'lodash',
'theme-colors',
'icons',
'i18n-strings',
'react-prefer-function-component',
'react-you-might-not-need-an-effect',
'prettier',
],
rules: {
// === Essential Superset customizations ===
// Prettier integration
'prettier/prettier': 'error',
// Custom Superset rules
'theme-colors/no-literal-colors': 'error',
'icons/no-fa-icons-usage': 'error',
'i18n-strings/no-template-vars': 'error',
// Core ESLint overrides for Superset
'no-console': 'warn',
'no-unused-vars': 'off', // TypeScript handles this
camelcase: [
'error',
{
allow: ['^UNSAFE_', '__REDUX_DEVTOOLS_EXTENSION_COMPOSE__'],
properties: 'never',
},
],
'prefer-destructuring': ['error', { object: true, array: false }],
'no-prototype-builtins': 0,
curly: 'off',
// Import plugin overrides
'import/extensions': [
'error',
'ignorePackages',
{
js: 'never',
jsx: 'never',
ts: 'never',
tsx: 'never',
},
],
'import/no-cycle': 0,
'import/prefer-default-export': 0,
'import/no-named-as-default-member': 0,
'import/no-extraneous-dependencies': [
'error',
{
devDependencies: [
'test/**',
'tests/**',
'spec/**',
'**/__tests__/**',
'**/__mocks__/**',
'*.test.{js,jsx,ts,tsx}',
'*.spec.{js,jsx,ts,tsx}',
'**/*.test.{js,jsx,ts,tsx}',
'**/*.spec.{js,jsx,ts,tsx}',
'**/jest.config.js',
'**/jest.setup.js',
'**/webpack.config.js',
'**/webpack.config.*.js',
'**/.eslintrc*.js',
],
optionalDependencies: false,
},
],
// React plugin overrides
'react-prefer-function-component/react-prefer-function-component': 1,
// React effect best practices
'react-you-might-not-need-an-effect/no-empty-effect': 'error',
'react-you-might-not-need-an-effect/no-pass-live-state-to-parent': 'error',
'react-you-might-not-need-an-effect/no-initialize-state': 'error',
// Lodash
'lodash/import-scope': [2, 'member'],
// React effect best practices
'react-you-might-not-need-an-effect/no-reset-all-state-on-prop-change':
'error',
'react-you-might-not-need-an-effect/no-chain-state-updates': 'error',
'react-you-might-not-need-an-effect/no-event-handler': 'error',
'react-you-might-not-need-an-effect/no-derived-state': 'error',
// Storybook
'storybook/prefer-pascal-case': 'error',
// File progress
'file-progress/activate': 1,
// React effect rules
'react-you-might-not-need-an-effect/no-adjust-state-on-prop-change':
'error',
'react-you-might-not-need-an-effect/no-pass-data-to-parent': 'error',
// Restricted imports
'no-restricted-imports': [
'error',
{
paths: Object.values(restrictedImportsRules).filter(Boolean),
patterns: ['antd/*'],
},
],
// Temporarily disabled for migration
'no-unsafe-optional-chaining': 0,
'no-import-assign': 0,
'import/no-relative-packages': 0,
'no-promise-executor-return': 0,
'import/no-import-module-exports': 0,
// Restrict certain syntax patterns
'no-restricted-syntax': [
'error',
{
selector:
"ImportDeclaration[source.value='react'] :matches(ImportDefaultSpecifier, ImportNamespaceSpecifier)",
message:
'Default React import is not required due to automatic JSX runtime in React 16.4',
},
{
selector: 'ImportNamespaceSpecifier[parent.source.value!=/^(\\.|src)/]',
message: 'Wildcard imports are not allowed',
},
],
},
overrides: [
// Ban JavaScript files in src/ - all new code must be TypeScript
{
files: ['src/**/*.js', 'src/**/*.jsx'],
rules: {
'no-restricted-syntax': [
'error',
{
selector: 'Program',
message:
'JavaScript files are not allowed in src/. Please use TypeScript (.ts/.tsx) instead.',
},
],
},
},
// Ban JavaScript files in plugins/ - all plugin source code must be TypeScript
{
files: ['plugins/**/src/**/*.js', 'plugins/**/src/**/*.jsx'],
rules: {
'no-restricted-syntax': [
'error',
{
selector: 'Program',
message:
'JavaScript files are not allowed in plugins/. Please use TypeScript (.ts/.tsx) instead.',
},
],
},
},
// Ban JavaScript files in packages/ - with exceptions for config files and generators
{
files: ['packages/**/src/**/*.js', 'packages/**/src/**/*.jsx'],
excludedFiles: [
'packages/generator-superset/**/*', // Yeoman generator templates run via Node
'packages/**/__mocks__/**/*', // Test mocks
],
rules: {
'no-restricted-syntax': [
'error',
{
selector: 'Program',
message:
'JavaScript files are not allowed in packages/. Please use TypeScript (.ts/.tsx) instead.',
},
],
},
},
{
files: ['*.ts', '*.tsx'],
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaFeatures: {
jsx: true,
},
tsconfigRootDir: __dirname,
project: ['./tsconfig.json'],
},
extends: ['plugin:@typescript-eslint/recommended', 'prettier'],
plugins: ['@typescript-eslint/eslint-plugin'],
rules: {
// TypeScript-specific rule overrides
'@typescript-eslint/ban-ts-ignore': 0,
'@typescript-eslint/ban-ts-comment': 0,
'@typescript-eslint/ban-types': 0,
'@typescript-eslint/naming-convention': [
'error',
{
selector: 'enum',
format: ['PascalCase'],
},
{
selector: 'enumMember',
format: ['PascalCase'],
},
],
'@typescript-eslint/no-empty-function': 0,
'@typescript-eslint/no-explicit-any': 0,
'@typescript-eslint/no-use-before-define': 'error',
'@typescript-eslint/no-non-null-assertion': 0,
'@typescript-eslint/explicit-function-return-type': 0,
'@typescript-eslint/explicit-module-boundary-types': 0,
'@typescript-eslint/no-unused-vars': 'warn',
'@typescript-eslint/prefer-optional-chain': 'error',
// Disable base rules that conflict with TS versions
'no-unused-vars': 'off',
'no-use-before-define': 'off',
'no-shadow': 'off',
// Import overrides for TypeScript
'import/extensions': [
'error',
'ignorePackages',
{
js: 'never',
jsx: 'never',
ts: 'never',
tsx: 'never',
},
],
},
settings: {
'import/resolver': {
typescript: {},
},
},
},
{
files: ['packages/**'],
rules: {
'import/no-extraneous-dependencies': [
'error',
{ devDependencies: true },
],
'no-restricted-imports': [
'error',
{
paths: [
restrictedImportsRules['no-moment'],
restrictedImportsRules['no-lodash-memoize'],
restrictedImportsRules['no-superset-theme'],
],
patterns: [],
},
],
},
},
{
files: ['plugins/**'],
rules: {
'no-restricted-imports': [
'error',
{
paths: [
restrictedImportsRules['no-moment'],
restrictedImportsRules['no-lodash-memoize'],
],
patterns: [],
},
],
},
},
{
files: ['src/components/**', 'src/theme/**'],
rules: {
'no-restricted-imports': [
'error',
{
paths: Object.values(restrictedImportsRules).filter(
r => r.name !== 'antd',
),
patterns: [],
},
],
},
},
{
files: [
'*.test.ts',
'*.test.tsx',
'*.test.js',
'*.test.jsx',
'*.stories.tsx',
'*.stories.jsx',
'fixtures.*',
'**/test/**/*',
'**/tests/**/*',
'spec/**/*',
'**/fixtures/**/*',
'**/__mocks__/**/*',
'**/spec/**/*',
],
excludedFiles: 'cypress-base/cypress/**/*',
plugins: ['jest-dom', 'no-only-tests', 'testing-library'],
extends: ['plugin:jest-dom/recommended', 'plugin:testing-library/react'],
rules: {
'import/no-extraneous-dependencies': [
'error',
{ devDependencies: true },
],
'prefer-promise-reject-errors': 0,
'max-classes-per-file': 0,
// Temporary for migration
'testing-library/await-async-queries': 0,
'testing-library/await-async-utils': 0,
'testing-library/no-await-sync-events': 0,
'testing-library/no-render-in-lifecycle': 0,
'testing-library/no-unnecessary-act': 0,
'testing-library/no-wait-for-multiple-assertions': 0,
'testing-library/prefer-screen-queries': 0,
'testing-library/await-async-events': 0,
'testing-library/no-node-access': 0,
'testing-library/no-wait-for-side-effects': 0,
'testing-library/prefer-presence-queries': 0,
'testing-library/render-result-naming-convention': 0,
'testing-library/no-container': 0,
'testing-library/prefer-find-by': 0,
'testing-library/no-manual-cleanup': 0,
'no-restricted-syntax': [
'error',
{
selector:
"ImportDeclaration[source.value='react'] :matches(ImportDefaultSpecifier, ImportNamespaceSpecifier)",
message:
'Default React import is not required due to automatic JSX runtime in React 16.4',
},
],
'no-restricted-imports': 0,
},
},
{
files: [
'*.test.ts',
'*.test.tsx',
'*.test.js',
'*.test.jsx',
'*.stories.tsx',
'*.stories.jsx',
'fixtures.*',
'**/test/**/*',
'**/tests/**/*',
'spec/**/*',
'**/fixtures/**/*',
'**/__mocks__/**/*',
'**/spec/**/*',
'cypress-base/cypress/**/*',
'Stories.tsx',
'packages/superset-ui-core/src/theme/index.tsx',
],
rules: {
'theme-colors/no-literal-colors': 0,
'icons/no-fa-icons-usage': 0,
'i18n-strings/no-template-vars': 0,
'no-restricted-imports': 0,
},
},
{
files: [
'packages/**/*.stories.*',
'packages/**/*.overview.*',
'packages/**/fixtures.*',
],
rules: {
'import/no-extraneous-dependencies': 'off',
},
},
{
files: ['playwright/**/*.ts', 'playwright/**/*.js'],
rules: {
'import/no-extraneous-dependencies': [
'error',
{ devDependencies: true },
],
},
},
],
ignorePatterns,
};

View File

@@ -0,0 +1,124 @@
/**
* 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.
*/
// Register TypeScript require hook so ESLint can load .ts plugin files
require('tsx/cjs');
/**
* MINIMAL ESLint config - ONLY for rules OXC doesn't support
* This config is designed to be run alongside OXC linter
*
* Only covers:
* - Custom Superset plugins (theme-colors, icons, i18n)
* - Prettier formatting
* - File progress indicator
*/
module.exports = {
root: true,
// Don't report on eslint-disable comments for rules we don't have
reportUnusedDisableDirectives: false,
// Simple parser - no TypeScript needed since OXC handles that
parser: '@babel/eslint-parser',
parserOptions: {
ecmaVersion: 2020,
sourceType: 'module',
ecmaFeatures: {
jsx: true,
},
requireConfigFile: false,
babelOptions: {
presets: ['@babel/preset-react', '@babel/preset-env'],
},
},
env: {
browser: true,
node: true,
es2020: true,
},
plugins: [
// ONLY custom Superset plugins that OXC doesn't support
'theme-colors',
'icons',
'i18n-strings',
'file-progress',
'prettier',
],
rules: {
// === ONLY rules that OXC cannot handle ===
// Prettier integration (formatting)
'prettier/prettier': 'error',
// Custom Superset plugins
'theme-colors/no-literal-colors': 'error',
'icons/no-fa-icons-usage': 'error',
'i18n-strings/no-template-vars': 'error',
'file-progress/activate': 1,
// Explicitly turn off all other rules to avoid conflicts
// when the config gets merged with other configs
'import/no-unresolved': 'off',
'import/extensions': 'off',
'@typescript-eslint/naming-convention': 'off',
},
overrides: [
{
// Disable custom rules in test/story files
files: [
'**/*.test.*',
'**/*.spec.*',
'**/*.stories.*',
'**/test/**',
'**/tests/**',
'**/spec/**',
'**/__tests__/**',
'**/__mocks__/**',
'cypress-base/**',
'packages/superset-ui-core/src/theme/index.tsx',
],
rules: {
'theme-colors/no-literal-colors': 0,
'icons/no-fa-icons-usage': 0,
'i18n-strings/no-template-vars': 0,
'file-progress/activate': 0,
},
},
],
// Only check src/ files where theme/icon rules matter
ignorePatterns: [
'node_modules',
'dist',
'build',
'.next',
'coverage',
'*.min.js',
'vendor',
// Skip packages/plugins since they have different theming rules
'packages/**',
'plugins/**',
// Skip generated/external files
'*.generated.*',
'*.config.js',
'webpack.*',
// Temporary analysis files
'*.js', // Skip all standalone JS files in root
'*.json',
],
};

View File

@@ -1 +1 @@
v24.16.0 v22.22.0

View File

@@ -1,3 +1,4 @@
import { dirname, join } from 'path';
/** /**
* Licensed to the Apache Software Foundation (ASF) under one * Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file * or more contributor license agreements. See the NOTICE file
@@ -16,16 +17,8 @@
* specific language governing permissions and limitations * specific language governing permissions and limitations
* under the License. * under the License.
*/ */
// This file has been automatically migrated to valid ESM format by Storybook.
import path from 'node:path';
import { createRequire } from 'node:module';
import { fileURLToPath } from 'node:url';
// Superset's webpack.config.js // Superset's webpack.config.js
import customConfig from '../webpack.config.js'; const customConfig = require('../webpack.config.js');
const require = createRequire(import.meta.url);
const __dirname = path.dirname(fileURLToPath(import.meta.url));
// Filter out plugins that shouldn't be included in Storybook's static build // Filter out plugins that shouldn't be included in Storybook's static build
// ReactRefreshWebpackPlugin adds Fast Refresh code that requires a dev server runtime, // ReactRefreshWebpackPlugin adds Fast Refresh code that requires a dev server runtime,
@@ -83,7 +76,7 @@ const disableDevModeInRules = rules =>
}; };
}); });
export default { module.exports = {
stories: [ stories: [
'../src/**/*.stories.tsx', '../src/**/*.stories.tsx',
'../packages/superset-ui-core/src/**/*.stories.tsx', '../packages/superset-ui-core/src/**/*.stories.tsx',
@@ -91,8 +84,11 @@ export default {
], ],
addons: [ addons: [
"@storybook/addon-links", getAbsolutePath('@storybook/addon-essentials'),
"@storybook/addon-docs" getAbsolutePath('@storybook/addon-links'),
'@mihkeleidast/storybook-addon-source',
getAbsolutePath('@storybook/addon-controls'),
getAbsolutePath('@storybook/addon-mdx-gfm'),
], ],
staticDirs: ['../src/assets/images'], staticDirs: ['../src/assets/images'],
@@ -109,13 +105,11 @@ export default {
alias: { alias: {
...config.resolve?.alias, ...config.resolve?.alias,
...customConfig.resolve?.alias, ...customConfig.resolve?.alias,
// Fix for Storybook 8.6.x with React 17 - resolve ESM module paths
'react-dom/test-utils': require.resolve('react-dom/test-utils'),
// Shared storybook utilities // Shared storybook utilities
'@storybook-shared': path.join(__dirname, 'shared'), '@storybook-shared': join(__dirname, 'shared'),
}, },
fallback: {
tty: false,
vm: require.resolve('vm-browserify')
}
}, },
plugins: [...config.plugins, ...filteredPlugins], plugins: [...config.plugins, ...filteredPlugins],
}), }),
@@ -125,11 +119,15 @@ export default {
}, },
framework: { framework: {
name: getAbsolutePath("@storybook/react-webpack5"), name: getAbsolutePath('@storybook/react-webpack5'),
options: {}, options: {},
} },
docs: {
autodocs: false,
},
}; };
function getAbsolutePath(value) { function getAbsolutePath(value) {
return path.dirname(require.resolve(path.join(value, 'package.json'))); return dirname(require.resolve(join(value, 'package.json')));
} }

View File

@@ -16,6 +16,7 @@
* specific language governing permissions and limitations * specific language governing permissions and limitations
* under the License. * under the License.
*/ */
import { withJsx } from '@mihkeleidast/storybook-addon-source';
import { themeObject, css, exampleThemes } from '@apache-superset/core/theme'; import { themeObject, css, exampleThemes } from '@apache-superset/core/theme';
import { combineReducers, createStore, applyMiddleware, compose } from 'redux'; import { combineReducers, createStore, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk'; import thunk from 'redux-thunk';
@@ -113,12 +114,9 @@ const providerDecorator = Story => (
</Provider> </Provider>
); );
export const decorators = [themeDecorator, providerDecorator]; export const decorators = [withJsx, themeDecorator, providerDecorator];
export const parameters = { export const parameters = {
docs: {
codePanel: true,
},
paddings: { paddings: {
values: [ values: [
{ name: 'None', value: '0px' }, { name: 'None', value: '0px' },

View File

@@ -19,7 +19,7 @@
import { useState, ReactNode, SyntheticEvent } from 'react'; import { useState, ReactNode, SyntheticEvent } from 'react';
import { styled } from '@apache-superset/core/theme'; import { styled } from '@apache-superset/core/theme';
import type { Decorator } from '@storybook/react-webpack5'; import type { Decorator } from '@storybook/react';
import { ResizeCallbackData } from 'react-resizable'; import { ResizeCallbackData } from 'react-resizable';
import ResizablePanel, { Size } from './ResizablePanel'; import ResizablePanel, { Size } from './ResizablePanel';

View File

@@ -48,7 +48,6 @@ module.exports = {
'@babel/plugin-syntax-dynamic-import', '@babel/plugin-syntax-dynamic-import',
'@babel/plugin-transform-export-namespace-from', '@babel/plugin-transform-export-namespace-from',
['@babel/plugin-transform-class-properties', { loose: true }], ['@babel/plugin-transform-class-properties', { loose: true }],
'@babel/plugin-transform-class-static-block',
['@babel/plugin-transform-optional-chaining', { loose: true }], ['@babel/plugin-transform-optional-chaining', { loose: true }],
['@babel/plugin-transform-private-methods', { loose: true }], ['@babel/plugin-transform-private-methods', { loose: true }],
['@babel/plugin-transform-nullish-coalescing-operator', { loose: true }], ['@babel/plugin-transform-nullish-coalescing-operator', { loose: true }],
@@ -107,13 +106,7 @@ module.exports = {
[ [
'babel-plugin-jsx-remove-data-test-id', 'babel-plugin-jsx-remove-data-test-id',
{ {
// The plugin matches attribute names exactly (no prefix match), attributes: 'data-test',
// so each data-test* attribute must be listed explicitly.
attributes: [
'data-test',
'data-test-drag-source-id',
'data-test-drop-target-id',
],
}, },
], ],
], ],

View File

@@ -2058,24 +2058,6 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
"license": "Python-2.0"
},
"node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
"integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
"license": "MIT",
"dependencies": {
"argparse": "^2.0.1"
},
"bin": {
"js-yaml": "bin/js-yaml.js"
}
},
"node_modules/@istanbuljs/schema": { "node_modules/@istanbuljs/schema": {
"version": "0.1.2", "version": "0.1.2",
"resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.2.tgz", "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.2.tgz",
@@ -2952,8 +2934,6 @@
"version": "1.0.10", "version": "1.0.10",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
"integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
"dev": true,
"peer": true,
"dependencies": { "dependencies": {
"sprintf-js": "~1.0.2" "sprintf-js": "~1.0.2"
} }
@@ -4373,8 +4353,6 @@
"version": "4.0.1", "version": "4.0.1",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
"dev": true,
"peer": true,
"bin": { "bin": {
"esparse": "bin/esparse.js", "esparse": "bin/esparse.js",
"esvalidate": "bin/esvalidate.js" "esvalidate": "bin/esvalidate.js"
@@ -4708,15 +4686,16 @@
} }
}, },
"node_modules/form-data": { "node_modules/form-data": {
"version": "4.0.6", "version": "4.0.5",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.6.tgz", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz",
"integrity": "sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==", "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==",
"license": "MIT",
"dependencies": { "dependencies": {
"asynckit": "^0.4.0", "asynckit": "^0.4.0",
"combined-stream": "^1.0.8", "combined-stream": "^1.0.8",
"es-set-tostringtag": "^2.1.0", "es-set-tostringtag": "^2.1.0",
"hasown": "^2.0.4", "hasown": "^2.0.2",
"mime-types": "^2.1.35" "mime-types": "^2.1.12"
}, },
"engines": { "engines": {
"node": ">= 6" "node": ">= 6"
@@ -5028,9 +5007,10 @@
} }
}, },
"node_modules/hasown": { "node_modules/hasown": {
"version": "2.0.4", "version": "2.0.2",
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
"integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
"license": "MIT",
"dependencies": { "dependencies": {
"function-bind": "^1.1.2" "function-bind": "^1.1.2"
}, },
@@ -5614,9 +5594,7 @@
"version": "3.14.2", "version": "3.14.2",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz",
"integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==",
"dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"argparse": "^1.0.7", "argparse": "^1.0.7",
"esprima": "^4.0.0" "esprima": "^4.0.0"
@@ -7778,9 +7756,7 @@
"node_modules/sprintf-js": { "node_modules/sprintf-js": {
"version": "1.0.3", "version": "1.0.3",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
"dev": true,
"peer": true
}, },
"node_modules/sshpk": { "node_modules/sshpk": {
"version": "1.18.0", "version": "1.18.0",
@@ -10228,20 +10204,6 @@
"get-package-type": "^0.1.0", "get-package-type": "^0.1.0",
"js-yaml": "^3.13.1", "js-yaml": "^3.13.1",
"resolve-from": "^5.0.0" "resolve-from": "^5.0.0"
},
"dependencies": {
"argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
},
"js-yaml": {
"version": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
"integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
"requires": {
"argparse": "^2.0.1"
}
}
} }
}, },
"@istanbuljs/schema": { "@istanbuljs/schema": {
@@ -11044,8 +11006,6 @@
"version": "1.0.10", "version": "1.0.10",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
"integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
"dev": true,
"peer": true,
"requires": { "requires": {
"sprintf-js": "~1.0.2" "sprintf-js": "~1.0.2"
} }
@@ -12091,9 +12051,7 @@
"esprima": { "esprima": {
"version": "4.0.1", "version": "4.0.1",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
"dev": true,
"peer": true
}, },
"esquery": { "esquery": {
"version": "1.4.0", "version": "1.4.0",
@@ -12342,15 +12300,15 @@
"integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==" "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw=="
}, },
"form-data": { "form-data": {
"version": "4.0.6", "version": "4.0.5",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.6.tgz", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz",
"integrity": "sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==", "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==",
"requires": { "requires": {
"asynckit": "^0.4.0", "asynckit": "^0.4.0",
"combined-stream": "^1.0.8", "combined-stream": "^1.0.8",
"es-set-tostringtag": "^2.1.0", "es-set-tostringtag": "^2.1.0",
"hasown": "^2.0.4", "hasown": "^2.0.2",
"mime-types": "^2.1.35" "mime-types": "^2.1.12"
} }
}, },
"fromentries": { "fromentries": {
@@ -12571,9 +12529,9 @@
} }
}, },
"hasown": { "hasown": {
"version": "2.0.4", "version": "2.0.2",
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
"integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
"requires": { "requires": {
"function-bind": "^1.1.2" "function-bind": "^1.1.2"
} }
@@ -12995,8 +12953,6 @@
"version": "3.14.2", "version": "3.14.2",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz",
"integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==",
"dev": true,
"peer": true,
"requires": { "requires": {
"argparse": "^1.0.7", "argparse": "^1.0.7",
"esprima": "^4.0.0" "esprima": "^4.0.0"
@@ -14507,9 +14463,7 @@
"sprintf-js": { "sprintf-js": {
"version": "1.0.3", "version": "1.0.3",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
"dev": true,
"peer": true
}, },
"sshpk": { "sshpk": {
"version": "1.18.0", "version": "1.18.0",

View File

@@ -65,86 +65,6 @@ const plugin: { rules: Record<string, Rule.RuleModule> } = {
}; };
}, },
}, },
'no-eager-t-in-config': {
meta: {
type: 'problem',
fixable: 'code',
docs: {
description:
'Disallow eager t()/tn() calls for `label` and `description` in config objects evaluated at module load (e.g., controlPanel files). The translation is captured at module-evaluation time, before i18n has loaded, and never updates when the user switches language. Wrap the call in an arrow function so it is evaluated at render time.',
},
schema: [
{
type: 'object',
properties: {
properties: {
type: 'array',
items: { type: 'string' },
},
},
additionalProperties: false,
},
],
messages: {
eager:
'Eager `{{property}}: {{fn}}(...)` is evaluated at module load, before i18n is initialized. Wrap in an arrow function: `{{property}}: () => {{fn}}(...)`.',
},
},
create(context: Rule.RuleContext): Rule.RuleListener {
const watchedProps: string[] = context.options[0]?.properties ?? [
'label',
'description',
];
const TRANSLATE_FNS = new Set(['t', 'tn']);
function handler(node: Node): void {
const prop = node as Node & {
key: { type: string; name?: string; value?: string };
value: Node & {
type: string;
callee?: { type: string; name?: string };
};
shorthand?: boolean;
computed?: boolean;
};
if (prop.shorthand || prop.computed) return;
const keyName =
prop.key.type === 'Identifier'
? prop.key.name
: prop.key.type === 'Literal'
? prop.key.value
: undefined;
if (typeof keyName !== 'string' || !watchedProps.includes(keyName)) {
return;
}
const callee = prop.value;
if (
callee.type !== 'CallExpression' ||
callee.callee?.type !== 'Identifier' ||
!callee.callee.name ||
!TRANSLATE_FNS.has(callee.callee.name)
) {
return;
}
context.report({
node: prop.value,
messageId: 'eager',
data: { property: keyName, fn: callee.callee.name },
fix(fixer) {
const source = context.getSourceCode().getText(prop.value);
return fixer.replaceText(prop.value, `() => ${source}`);
},
});
}
return {
Property: handler,
};
},
},
'sentence-case-buttons': { 'sentence-case-buttons': {
meta: { meta: {
type: 'suggestion', type: 'suggestion',

View File

@@ -1,86 +0,0 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import type { Rule } from 'eslint';
const { RuleTester } = require('eslint');
const plugin: { rules: Record<string, Rule.RuleModule> } = require('.');
const ruleTester = new RuleTester({
parserOptions: { ecmaVersion: 2020, sourceType: 'module' },
});
const rule: Rule.RuleModule = plugin.rules['no-eager-t-in-config'];
ruleTester.run('no-eager-t-in-config', rule, {
valid: [
// Lazy form — the recommended pattern
"const c = { label: () => t('Foo') };",
"const c = { description: () => t('Foo') };",
"const c = { label: () => tn('one', 'many', n) };",
// Static strings — no translation, no issue
"const c = { label: 'Foo' };",
// Other property names — unaffected
"const c = { name: t('Foo') };",
"const c = { title: t('Foo') };",
// Computed keys are too dynamic to lint usefully
"const c = { [labelKey]: t('Foo') };",
// Shorthand: `{ label }` — no value to inspect
'const label = t("Foo"); const c = { label };',
// t() called inside a function body — already lazy
"const c = { label: state => t('Foo') };",
// Non-t() call expressions are fine
"const c = { label: someOtherFn('Foo') };",
],
invalid: [
{
code: "const c = { label: t('Foo') };",
output: "const c = { label: () => t('Foo') };",
errors: [{ messageId: 'eager' }],
},
{
code: "const c = { description: t('Foo bar') };",
output: "const c = { description: () => t('Foo bar') };",
errors: [{ messageId: 'eager' }],
},
{
code: "const c = { label: tn('one', 'many', 2) };",
output: "const c = { label: () => tn('one', 'many', 2) };",
errors: [{ messageId: 'eager' }],
},
// String-literal keys are equivalent to identifier keys
{
code: "const c = { 'label': t('Foo') };",
output: "const c = { 'label': () => t('Foo') };",
errors: [{ messageId: 'eager' }],
},
// Custom watched-property list via rule option
{
code: "const c = { headerTitle: t('Foo') };",
output: "const c = { headerTitle: () => t('Foo') };",
options: [{ properties: ['headerTitle'] }],
errors: [{ messageId: 'eager' }],
},
// Nested config — fires per occurrence
{
code: "const c = { foo: { label: t('A'), description: t('B') } };",
output:
"const c = { foo: { label: () => t('A'), description: () => t('B') } };",
errors: [{ messageId: 'eager' }, { messageId: 'eager' }],
},
],
});

View File

@@ -31,13 +31,12 @@ const plugin: { rules: Record<string, Rule.RuleModule> } = require('.');
// Tests // Tests
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
const ruleTester = new RuleTester({ languageOptions: { ecmaVersion: 6 } }); const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } });
const rule: Rule.RuleModule = plugin.rules['no-template-vars']; const rule: Rule.RuleModule = plugin.rules['no-template-vars'];
const errors: Array<{ message: string }> = [ const errors: Array<{ type: string }> = [
{ {
message: type: 'CallExpression',
"Don't use variables in translation string templates. Flask-babel is a static translation service, so it can't handle strings that include variables",
}, },
]; ];

View File

@@ -31,10 +31,7 @@ const plugin: { rules: Record<string, Rule.RuleModule> } = require('.');
// Tests // Tests
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
const ruleTester = new RuleTester({ const ruleTester = new RuleTester({
languageOptions: { parserOptions: { ecmaVersion: 6, ecmaFeatures: { jsx: true } },
ecmaVersion: 6,
parserOptions: { ecmaFeatures: { jsx: true } },
},
}); });
const rule: Rule.RuleModule = plugin.rules['no-fa-icons-usage']; const rule: Rule.RuleModule = plugin.rules['no-fa-icons-usage'];

View File

@@ -1,137 +0,0 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/**
* MINIMAL ESLint flat config - ONLY for rules OXC doesn't support.
*
* This config is run alongside the OXC (oxlint) linter, which handles the
* bulk of linting. ESLint here only covers the custom Superset plugins and
* Prettier formatting that oxlint cannot express. It is consumed by
* `scripts/oxlint-metrics-uploader.js` (`npm run lint-stats`).
*
* Migrated from the legacy `.eslintrc.minimal.js` (eslintrc) format to flat
* config for ESLint v9+/v10, where eslintrc is no longer supported.
*
* Only covers:
* - Custom Superset plugins (theme-colors, icons, i18n-strings)
* - Prettier formatting
*/
// Register the TypeScript require hook so ESLint can load the .ts plugin files
// from eslint-rules/*.
require('tsx/cjs');
const tsParser = require('@typescript-eslint/parser');
const prettierPlugin = require('eslint-plugin-prettier');
const themeColorsPlugin = require('eslint-plugin-theme-colors');
const iconsPlugin = require('eslint-plugin-icons');
const i18nStringsPlugin = require('eslint-plugin-i18n-strings');
module.exports = [
// Files this config applies to. Flat config has no `--ext`; globs live here.
// Only check src/ files where the theme/icon/i18n rules matter.
{
ignores: [
'node_modules/**',
'dist/**',
'build/**',
'.next/**',
'coverage/**',
'**/*.min.js',
'vendor/**',
// Skip packages/plugins since they have different theming rules
'packages/**',
'plugins/**',
// Skip generated/external/config files
'**/*.generated.*',
'**/*.config.js',
'**/webpack.*',
'*.json',
],
},
{
files: ['**/*.{js,jsx,ts,tsx}'],
languageOptions: {
ecmaVersion: 2020,
sourceType: 'module',
// The @typescript-eslint parser handles both TS/TSX and plain JS/JSX and
// is compatible with ESLint v10's scope manager. (The legacy
// @babel/eslint-parser does not support ESLint v10.) The custom rules
// here are pure AST visitors and do not require type information, so no
// `project` is configured — this keeps parsing fast.
parser: tsParser,
parserOptions: {
ecmaFeatures: {
jsx: true,
},
},
},
// Don't report on eslint-disable comments for rules we don't have.
linterOptions: {
reportUnusedDisableDirectives: false,
},
plugins: {
prettier: prettierPlugin,
'theme-colors': themeColorsPlugin,
icons: iconsPlugin,
'i18n-strings': i18nStringsPlugin,
},
rules: {
// Prettier integration (formatting)
'prettier/prettier': 'error',
// Custom Superset plugins
'theme-colors/no-literal-colors': 'error',
'icons/no-fa-icons-usage': 'error',
'i18n-strings/no-template-vars': 'error',
// Enabled only for controlPanel files via the override below.
'i18n-strings/no-eager-t-in-config': 'off',
},
},
{
// Eager t()/tn() in `label`/`description` config props is captured at
// module-load time, before i18n initializes — labels stay in the fallback
// language even after the user switches. Surfaced as a warning (with
// autofix to `() => t(...)`) wherever this is a real foot-gun:
// controlPanel files. Promote to `'error'` once the codebase is clean.
files: ['**/controlPanel.{ts,tsx,js,jsx}'],
rules: {
'i18n-strings/no-eager-t-in-config': 'warn',
},
},
{
// Disable custom rules in test/story files
files: [
'**/*.test.*',
'**/*.spec.*',
'**/*.stories.*',
'**/test/**',
'**/tests/**',
'**/spec/**',
'**/__tests__/**',
'**/__mocks__/**',
'cypress-base/**',
],
rules: {
'theme-colors/no-literal-colors': 'off',
'icons/no-fa-icons-usage': 'off',
'i18n-strings/no-template-vars': 'off',
},
},
];

View File

@@ -69,7 +69,7 @@ module.exports = {
], ],
coverageReporters: ['lcov', 'json-summary', 'html', 'text'], coverageReporters: ['lcov', 'json-summary', 'html', 'text'],
transformIgnorePatterns: [ transformIgnorePatterns: [
'node_modules/(?!@formatjs/.*|d3-(array|interpolate|color|time|scale|time-format|format)|internmap|@mapbox/tiny-sdf|remark-gfm|(?!@ngrx|(?!deck.gl)|d3-scale)|markdown-table|micromark-*.|decode-named-character-reference|character-entities|mdast-util-*.|unist-util-*.|ccount|escape-string-regexp|nanoid|uuid|@rjsf/*.|echarts|zrender|fetch-mock|pretty-ms|parse-ms|ol|@babel/runtime|@emotion|cheerio|cheerio/lib|parse5|dom-serializer|entities|htmlparser2|rehype-sanitize|hast-util-sanitize|unified|unist-.*|hast-.*|rehype-.*|remark-.*|mdast-.*|micromark-.*|parse-entities|property-information|space-separated-tokens|comma-separated-tokens|bail|devlop|zwitch|longest-streak|geostyler|geostyler-.*|(?!geostyler)lodash|react-error-boundary|react-json-tree|react-base16-styling|lodash-es|rbush|quickselect|react-diff-viewer-continued|storybook/*.|json-stringify-pretty-compact)', 'node_modules/(?!@formatjs/.*|d3-(array|interpolate|color|time|scale|time-format|format)|internmap|@mapbox/tiny-sdf|remark-gfm|(?!@ngrx|(?!deck.gl)|d3-scale)|markdown-table|micromark-*.|decode-named-character-reference|character-entities|mdast-util-*.|unist-util-*.|ccount|escape-string-regexp|nanoid|uuid|@rjsf/*.|echarts|zrender|fetch-mock|pretty-ms|parse-ms|ol|@babel/runtime|@emotion|cheerio|cheerio/lib|parse5|dom-serializer|entities|htmlparser2|rehype-sanitize|hast-util-sanitize|unified|unist-.*|hast-.*|rehype-.*|remark-.*|mdast-.*|micromark-.*|parse-entities|property-information|space-separated-tokens|comma-separated-tokens|bail|devlop|zwitch|longest-streak|geostyler|geostyler-.*|(?!geostyler)lodash|react-error-boundary|react-json-tree|react-base16-styling|lodash-es|rbush|quickselect|react-diff-viewer-continued)',
], ],
preset: 'ts-jest', preset: 'ts-jest',
transform: { transform: {

View File

@@ -287,15 +287,13 @@
"ignorePatterns": [ "ignorePatterns": [
"packages/generator-superset/**/*", "packages/generator-superset/**/*",
"cypress-base/**", "cypress-base/**",
"**/node_modules/**", "node_modules/**",
"build/**", "build/**",
"**/dist/**", "dist/**",
"**/lib/**", "lib/**",
"**/esm/**", "esm/**",
"**/*.min.js", "*.min.js",
"**/*.d.ts",
"coverage/**", "coverage/**",
"storybook-static/**",
".git/**", ".git/**",
"**/*.config.js", "**/*.config.js",
"**/*.config.ts" "**/*.config.ts"

File diff suppressed because it is too large Load Diff

View File

@@ -119,7 +119,7 @@
"@great-expectations/jsonforms-antd-renderers": "^2.2.10", "@great-expectations/jsonforms-antd-renderers": "^2.2.10",
"@jsonforms/core": "^3.7.0", "@jsonforms/core": "^3.7.0",
"@jsonforms/react": "^3.7.0", "@jsonforms/react": "^3.7.0",
"@jsonforms/vanilla-renderers": "^3.8.0", "@jsonforms/vanilla-renderers": "^3.7.0",
"@luma.gl/constants": "~9.2.5", "@luma.gl/constants": "~9.2.5",
"@luma.gl/core": "~9.2.5", "@luma.gl/core": "~9.2.5",
"@luma.gl/engine": "~9.2.5", "@luma.gl/engine": "~9.2.5",
@@ -158,57 +158,58 @@
"@types/d3-selection": "^3.0.11", "@types/d3-selection": "^3.0.11",
"@types/d3-time-format": "^4.0.3", "@types/d3-time-format": "^4.0.3",
"@types/react-google-recaptcha": "^2.1.9", "@types/react-google-recaptcha": "^2.1.9",
"@visx/axis": "^4.0.0", "@visx/axis": "^3.8.0",
"@visx/grid": "^4.0.0", "@visx/grid": "^3.5.0",
"@visx/responsive": "^4.0.0", "@visx/responsive": "^3.0.0",
"@visx/scale": "^4.0.0", "@visx/scale": "^3.5.0",
"@visx/tooltip": "^4.0.0", "@visx/tooltip": "^3.0.0",
"@visx/xychart": "^4.0.0", "@visx/xychart": "^3.5.1",
"ag-grid-community": "35.3.1", "ag-grid-community": "35.3.0",
"ag-grid-react": "35.3.1", "ag-grid-react": "35.3.0",
"antd": "^5.26.0", "antd": "^5.26.0",
"chrono-node": "^2.9.1", "chrono-node": "^2.9.1",
"classnames": "^2.2.5", "classnames": "^2.2.5",
"content-disposition": "^2.0.1", "content-disposition": "^2.0.1",
"d3-color": "^3.1.0",
"d3-scale": "^4.0.2", "d3-scale": "^4.0.2",
"dayjs": "^1.11.21", "dayjs": "^1.11.21",
"dom-to-image-more": "^3.10.0", "dom-to-image-more": "^3.7.2",
"dom-to-pdf": "^0.3.2", "dom-to-pdf": "^0.3.2",
"echarts": "^5.6.0", "echarts": "^5.6.0",
"fast-glob": "^3.3.2", "fast-glob": "^3.3.2",
"fs-extra": "^11.3.5", "fs-extra": "^11.3.5",
"fuse.js": "^7.4.2", "fuse.js": "^7.3.0",
"geolib": "^3.3.14", "geolib": "^3.3.14",
"geostyler": "^18.6.0", "geostyler": "^18.6.0",
"geostyler-data": "^1.1.0", "geostyler-data": "^1.1.0",
"geostyler-openlayers-parser": "^5.7.0", "geostyler-openlayers-parser": "^5.7.0",
"geostyler-style": "11.0.2", "geostyler-style": "11.0.2",
"geostyler-wfs-parser": "^3.0.1", "geostyler-wfs-parser": "^3.0.1",
"google-auth-library": "^10.7.0", "google-auth-library": "^10.6.2",
"immer": "^11.1.8", "immer": "^11.1.8",
"interweave": "^13.1.1", "interweave": "^13.1.1",
"jquery": "^4.0.0", "jquery": "^4.0.0",
"js-levenshtein": "^1.1.6", "js-levenshtein": "^1.1.6",
"json-bigint": "^1.0.0", "json-bigint": "^1.0.0",
"json-stringify-pretty-compact": "^4.0.0", "json-stringify-pretty-compact": "^2.0.0",
"lodash": "^4.18.1", "lodash": "^4.18.1",
"mapbox-gl": "^3.24.1", "mapbox-gl": "^3.24.0",
"markdown-to-jsx": "^9.8.2", "markdown-to-jsx": "^9.8.1",
"match-sorter": "^8.3.0", "match-sorter": "^8.3.0",
"memoize-one": "^6.0.0", "memoize-one": "^5.2.1",
"mousetrap": "^1.6.5", "mousetrap": "^1.6.5",
"mustache": "^4.2.0", "mustache": "^4.2.0",
"nanoid": "^5.1.11", "nanoid": "^5.1.11",
"ol": "^10.9.0", "ol": "^10.9.0",
"query-string": "9.4.0", "query-string": "9.4.0",
"re-resizable": "^6.11.2", "re-resizable": "^6.11.2",
"react": "^18.3.0", "react": "^18.2.0",
"react-arborist": "^3.10.5", "react-arborist": "^3.8.0",
"react-checkbox-tree": "^1.8.0", "react-checkbox-tree": "^1.8.0",
"react-diff-viewer-continued": "^4.2.2", "react-diff-viewer-continued": "^4.2.2",
"react-dnd": "^11.1.3", "react-dnd": "^11.1.3",
"react-dnd-html5-backend": "^11.1.3", "react-dnd-html5-backend": "^11.1.3",
"react-dom": "^18.3.0", "react-dom": "^18.2.0",
"react-google-recaptcha": "^3.1.0", "react-google-recaptcha": "^3.1.0",
"react-intersection-observer": "^10.0.3", "react-intersection-observer": "^10.0.3",
"react-json-tree": "^0.20.0", "react-json-tree": "^0.20.0",
@@ -230,9 +231,9 @@
"redux-undo": "^1.0.0-beta9-9-7", "redux-undo": "^1.0.0-beta9-9-7",
"rison": "^0.1.1", "rison": "^0.1.1",
"scroll-into-view-if-needed": "^3.1.0", "scroll-into-view-if-needed": "^3.1.0",
"simple-zstd": "^2.1.0", "simple-zstd": "^1.4.2",
"stream-browserify": "^3.0.0", "stream-browserify": "^3.0.0",
"tinycolor2": "^1.6.0", "tinycolor2": "^1.4.2",
"urijs": "^1.19.8", "urijs": "^1.19.8",
"use-event-callback": "^0.1.0", "use-event-callback": "^0.1.0",
"use-immer": "^0.11.0", "use-immer": "^0.11.0",
@@ -260,17 +261,25 @@
"@babel/types": "^7.29.7", "@babel/types": "^7.29.7",
"@emotion/babel-plugin": "^11.13.5", "@emotion/babel-plugin": "^11.13.5",
"@emotion/jest": "^11.14.2", "@emotion/jest": "^11.14.2",
"@formatjs/intl-durationformat": "^0.10.15", "@formatjs/intl-durationformat": "^0.10.3",
"@istanbuljs/nyc-config-typescript": "^1.0.1", "@istanbuljs/nyc-config-typescript": "^1.0.1",
"@playwright/test": "^1.61.0", "@mihkeleidast/storybook-addon-source": "^1.0.1",
"@playwright/test": "^1.60.0",
"@pmmmwh/react-refresh-webpack-plugin": "^0.6.2", "@pmmmwh/react-refresh-webpack-plugin": "^0.6.2",
"@storybook/addon-docs": "10.4.5", "@storybook/addon-actions": "^8.6.18",
"@storybook/addon-links": "10.4.4", "@storybook/addon-controls": "^8.6.18",
"@storybook/react-webpack5": "10.4.4", "@storybook/addon-essentials": "^8.6.18",
"@storybook/test-runner": "0.24.4", "@storybook/addon-links": "^8.6.18",
"@storybook/addon-mdx-gfm": "^8.6.18",
"@storybook/components": "^8.6.18",
"@storybook/preview-api": "^8.6.18",
"@storybook/react": "^8.6.18",
"@storybook/react-webpack5": "^8.6.18",
"@storybook/test": "^8.6.18",
"@storybook/test-runner": "^0.17.0",
"@svgr/webpack": "^8.1.0", "@svgr/webpack": "^8.1.0",
"@swc/core": "^1.15.41", "@swc/core": "^1.15.40",
"@swc/plugin-emotion": "^14.13.0", "@swc/plugin-emotion": "^14.12.0",
"@swc/plugin-transform-imports": "^12.5.0", "@swc/plugin-transform-imports": "^12.5.0",
"@testing-library/dom": "^9.3.4", "@testing-library/dom": "^9.3.4",
"@testing-library/jest-dom": "^6.9.1", "@testing-library/jest-dom": "^6.9.1",
@@ -279,15 +288,16 @@
"@types/content-disposition": "^0.5.9", "@types/content-disposition": "^0.5.9",
"@types/dom-to-image": "^2.6.7", "@types/dom-to-image": "^2.6.7",
"@types/jest": "^30.0.0", "@types/jest": "^30.0.0",
"@types/jquery": "^4.0.1", "@types/jquery": "^4.0.0",
"@types/js-levenshtein": "^1.1.3", "@types/js-levenshtein": "^1.1.3",
"@types/json-bigint": "^1.0.4", "@types/json-bigint": "^1.0.4",
"@types/mousetrap": "^1.6.15", "@types/mousetrap": "^1.6.15",
"@types/node": "^25.9.3", "@types/node": "^25.9.1",
"@types/react": "^18.3.0", "@types/react": "^18.2.0",
"@types/react-dom": "^18.3.0", "@types/react-dom": "^18.2.0",
"@types/react-loadable": "^5.5.11", "@types/react-loadable": "^5.5.11",
"@types/react-redux": "^7.1.10", "@types/react-redux": "^7.1.10",
"@types/react-resizable": "^4.0.0",
"@types/react-router-dom": "^5.3.3", "@types/react-router-dom": "^5.3.3",
"@types/react-transition-group": "^4.4.12", "@types/react-transition-group": "^4.4.12",
"@types/react-window": "^1.8.8", "@types/react-window": "^1.8.8",
@@ -296,35 +306,35 @@
"@types/rison": "0.1.0", "@types/rison": "0.1.0",
"@types/tinycolor2": "^1.4.3", "@types/tinycolor2": "^1.4.3",
"@types/unzipper": "^0.10.11", "@types/unzipper": "^0.10.11",
"@typescript-eslint/eslint-plugin": "^8.61.1", "@typescript-eslint/eslint-plugin": "^8.60.0",
"@typescript-eslint/parser": "^8.61.0", "@typescript-eslint/parser": "^8.59.4",
"babel-jest": "^30.4.1", "babel-jest": "^30.4.1",
"babel-loader": "^10.1.1", "babel-loader": "^10.1.1",
"babel-plugin-dynamic-import-node": "^2.3.3", "babel-plugin-dynamic-import-node": "^2.3.3",
"babel-plugin-jsx-remove-data-test-id": "^3.0.0", "babel-plugin-jsx-remove-data-test-id": "^3.0.0",
"babel-plugin-lodash": "^3.3.4", "babel-plugin-lodash": "^3.3.4",
"baseline-browser-mapping": "^2.10.37", "baseline-browser-mapping": "^2.10.33",
"cheerio": "1.2.0", "cheerio": "1.2.0",
"concurrently": "^10.0.3", "concurrently": "^10.0.0",
"copy-webpack-plugin": "^14.0.0", "copy-webpack-plugin": "^14.0.0",
"cross-env": "^10.1.0", "cross-env": "^10.1.0",
"css-loader": "^7.1.4", "css-loader": "^7.1.4",
"css-minimizer-webpack-plugin": "^8.0.0", "css-minimizer-webpack-plugin": "^8.0.0",
"eslint": "^10.5.0", "eslint": "^8.56.0",
"eslint-config-prettier": "^10.1.8", "eslint-config-prettier": "^7.2.0",
"eslint-import-resolver-alias": "^1.1.2", "eslint-import-resolver-alias": "^1.1.2",
"eslint-import-resolver-typescript": "^4.4.5", "eslint-import-resolver-typescript": "^4.4.4",
"eslint-plugin-cypress": "^3.6.0", "eslint-plugin-cypress": "^3.6.0",
"eslint-plugin-i18n-strings": "file:eslint-rules/eslint-plugin-i18n-strings", "eslint-plugin-i18n-strings": "file:eslint-rules/eslint-plugin-i18n-strings",
"eslint-plugin-icons": "file:eslint-rules/eslint-plugin-icons", "eslint-plugin-icons": "file:eslint-rules/eslint-plugin-icons",
"eslint-plugin-import": "^2.32.0", "eslint-plugin-import": "^2.32.0",
"eslint-plugin-jest-dom": "^5.5.0", "eslint-plugin-jest-dom": "^5.5.0",
"eslint-plugin-lodash": "^8.0.0", "eslint-plugin-lodash": "^7.4.0",
"eslint-plugin-no-only-tests": "^3.4.0", "eslint-plugin-no-only-tests": "^3.4.0",
"eslint-plugin-prettier": "^5.5.6", "eslint-plugin-prettier": "^5.5.6",
"eslint-plugin-react-prefer-function-component": "^5.0.0", "eslint-plugin-react-prefer-function-component": "^5.0.0",
"eslint-plugin-react-you-might-not-need-an-effect": "^1.0.1", "eslint-plugin-react-you-might-not-need-an-effect": "^0.10.4",
"eslint-plugin-storybook": "10.4.5", "eslint-plugin-storybook": "^0.8.0",
"eslint-plugin-testing-library": "^7.16.2", "eslint-plugin-testing-library": "^7.16.2",
"eslint-plugin-theme-colors": "file:eslint-rules/eslint-plugin-theme-colors", "eslint-plugin-theme-colors": "file:eslint-rules/eslint-plugin-theme-colors",
"fetch-mock": "^12.6.0", "fetch-mock": "^12.6.0",
@@ -343,19 +353,18 @@
"lightningcss": "^1.32.0", "lightningcss": "^1.32.0",
"mini-css-extract-plugin": "^2.10.2", "mini-css-extract-plugin": "^2.10.2",
"open-cli": "^9.0.0", "open-cli": "^9.0.0",
"oxlint": "^1.70.0", "oxlint": "^1.67.0",
"po2json": "^0.4.5", "po2json": "^0.4.5",
"prettier": "3.8.4", "prettier": "3.8.3",
"prettier-plugin-packagejson": "^3.0.2", "prettier-plugin-packagejson": "^3.0.2",
"process": "^0.11.10", "process": "^0.11.10",
"react-dnd-test-backend": "^16.0.1",
"react-refresh": "^0.18.0", "react-refresh": "^0.18.0",
"react-resizable": "^4.0.1", "react-resizable": "^4.0.1",
"redux-mock-store": "^1.5.4", "redux-mock-store": "^1.5.4",
"source-map": "^0.7.6", "source-map": "^0.7.6",
"source-map-support": "^0.5.21", "source-map-support": "^0.5.21",
"speed-measure-webpack-plugin": "^1.6.0", "speed-measure-webpack-plugin": "^1.6.0",
"storybook": "10.4.6", "storybook": "8.6.18",
"style-loader": "^4.0.0", "style-loader": "^4.0.0",
"swc-loader": "^0.2.7", "swc-loader": "^0.2.7",
"terser-webpack-plugin": "^5.6.1", "terser-webpack-plugin": "^5.6.1",
@@ -368,9 +377,9 @@
"wait-on": "^9.0.10", "wait-on": "^9.0.10",
"webpack": "^5.107.2", "webpack": "^5.107.2",
"webpack-bundle-analyzer": "^5.3.0", "webpack-bundle-analyzer": "^5.3.0",
"webpack-cli": "^7.0.3", "webpack-cli": "^6.0.1",
"webpack-dev-server": "^5.2.5", "webpack-dev-server": "^5.2.4",
"webpack-manifest-plugin": "^6.0.1", "webpack-manifest-plugin": "^5.0.1",
"webpack-sources": "^3.5.0", "webpack-sources": "^3.5.0",
"webpack-visualizer-plugin2": "^2.0.0" "webpack-visualizer-plugin2": "^2.0.0"
}, },
@@ -382,8 +391,8 @@
"regenerator-runtime": "^0.14.1" "regenerator-runtime": "^0.14.1"
}, },
"engines": { "engines": {
"node": "^24.16.0", "node": "^22.22.0",
"npm": "^11.13.0" "npm": "^10.8.1"
}, },
"overrides": { "overrides": {
"uuid": "$uuid", "uuid": "$uuid",
@@ -414,16 +423,7 @@
"@jest/types": "^30.4.0", "@jest/types": "^30.4.0",
"jest-util": "^30.4.0", "jest-util": "^30.4.0",
"jest-circus": "^30.4.0", "jest-circus": "^30.4.0",
"jest-environment-node": "^30.4.0", "jest-environment-node": "^30.4.0"
"@babel/eslint-parser": {
"eslint": "$eslint"
},
"eslint-plugin-import": {
"eslint": "$eslint"
},
"eslint-plugin-jest-dom": {
"eslint": "$eslint"
}
}, },
"readme": "ERROR: No README data found!", "readme": "ERROR: No README data found!",
"scarfSettings": { "scarfSettings": {

View File

@@ -37,7 +37,7 @@
"cross-env": "^10.1.0", "cross-env": "^10.1.0",
"fs-extra": "^11.3.5", "fs-extra": "^11.3.5",
"jest": "^30.4.2", "jest": "^30.4.2",
"yeoman-test": "^11.6.0" "yeoman-test": "^11.5.2"
}, },
"engines": { "engines": {
"npm": ">= 4.0.0", "npm": ">= 4.0.0",

View File

@@ -97,8 +97,8 @@
"@fontsource/ibm-plex-mono": "^5.2.7", "@fontsource/ibm-plex-mono": "^5.2.7",
"@fontsource/inter": "^5.2.6", "@fontsource/inter": "^5.2.6",
"nanoid": "^5.0.9", "nanoid": "^5.0.9",
"react": "^18.3.0", "react": "^18.2.0",
"react-dom": "^18.3.0", "react-dom": "^18.2.0",
"react-loadable": "^5.5.0", "react-loadable": "^5.5.0",
"tinycolor2": "*", "tinycolor2": "*",
"lodash": "^4.18.1", "lodash": "^4.18.1",

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