mirror of
https://github.com/apache/superset.git
synced 2026-06-10 18:19:28 +00:00
Compare commits
1 Commits
fix/smtp-s
...
url-param-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
376b5c9491 |
28
.github/dependabot.yml
vendored
28
.github/dependabot.yml
vendored
@@ -14,6 +14,12 @@ updates:
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
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: "@rjsf/*"
|
||||
# remark-gfm v4+ requires react-markdown v9+, which needs React 18
|
||||
@@ -36,6 +42,14 @@ updates:
|
||||
# and confirm the issue https://github.com/apache/superset/issues/39600 is fixed
|
||||
- dependency-name: "react-checkbox-tree"
|
||||
update-types: ["version-update:semver-major"]
|
||||
groups:
|
||||
storybook:
|
||||
applies-to: version-updates
|
||||
patterns:
|
||||
- "@storybook*"
|
||||
- "storybook"
|
||||
update-types:
|
||||
- "patch"
|
||||
directory: "/superset-frontend/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
@@ -76,7 +90,21 @@ updates:
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/docs/"
|
||||
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"
|
||||
groups:
|
||||
storybook:
|
||||
applies-to: version-updates
|
||||
patterns:
|
||||
- "@storybook*"
|
||||
- "storybook"
|
||||
update-types:
|
||||
- "patch"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
open-pull-requests-limit: 10
|
||||
|
||||
3
.github/workflows/bump-python-package.yml
vendored
3
.github/workflows/bump-python-package.yml
vendored
@@ -30,8 +30,9 @@ jobs:
|
||||
pull-requests: write
|
||||
checks: write
|
||||
steps:
|
||||
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: true
|
||||
ref: master
|
||||
|
||||
2
.github/workflows/check-python-deps.yml
vendored
2
.github/workflows/check-python-deps.yml
vendored
@@ -22,7 +22,7 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
|
||||
@@ -25,7 +25,7 @@ jobs:
|
||||
pull-requests: write
|
||||
steps:
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Check and notify
|
||||
|
||||
20
.github/workflows/claude.yml
vendored
20
.github/workflows/claude.yml
vendored
@@ -75,14 +75,14 @@ jobs:
|
||||
issues: write
|
||||
id-token: write
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
with:
|
||||
persist-credentials: false
|
||||
fetch-depth: 1
|
||||
- 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"
|
||||
- name: Run Claude PR Action
|
||||
uses: anthropics/claude-code-action@5fb899572b81d2bb648d4d187173a2f423a9677c # beta
|
||||
with:
|
||||
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
|
||||
timeout_minutes: "60"
|
||||
|
||||
8
.github/workflows/codeql-analysis.yml
vendored
8
.github/workflows/codeql-analysis.yml
vendored
@@ -26,7 +26,7 @@ jobs:
|
||||
frontend: ${{ steps.check.outputs.frontend }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Check for file changes
|
||||
@@ -57,13 +57,13 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@87557b9c84dde89fdd9b10e88954ac2f4248e463 # v4
|
||||
uses: github/codeql-action/init@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
@@ -74,6 +74,6 @@ jobs:
|
||||
# queries: security-extended,security-and-quality
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@87557b9c84dde89fdd9b10e88954ac2f4248e463 # v4
|
||||
uses: github/codeql-action/analyze@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4
|
||||
with:
|
||||
category: "/language:${{matrix.language}}"
|
||||
|
||||
4
.github/workflows/dependency-review.yml
vendored
4
.github/workflows/dependency-review.yml
vendored
@@ -27,7 +27,7 @@ jobs:
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: "Checkout Repository"
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: "Dependency Review"
|
||||
@@ -51,7 +51,7 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: "Checkout Repository"
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
|
||||
8
.github/workflows/docker.yml
vendored
8
.github/workflows/docker.yml
vendored
@@ -18,6 +18,7 @@ concurrency:
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
|
||||
changes:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 10
|
||||
@@ -30,7 +31,7 @@ jobs:
|
||||
docker: ${{ steps.check.outputs.docker }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Check for file changes
|
||||
@@ -70,8 +71,9 @@ jobs:
|
||||
IMAGE_TAG: apache/superset:GHA-${{ matrix.build_preset }}-${{ github.run_id }}
|
||||
|
||||
steps:
|
||||
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
@@ -145,7 +147,7 @@ jobs:
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Setup Docker Environment
|
||||
|
||||
6
.github/workflows/embedded-sdk-release.yml
vendored
6
.github/workflows/embedded-sdk-release.yml
vendored
@@ -33,13 +33,13 @@ jobs:
|
||||
run:
|
||||
working-directory: superset-embedded-sdk
|
||||
steps:
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
|
||||
with:
|
||||
node-version-file: "./superset-embedded-sdk/.nvmrc"
|
||||
registry-url: "https://registry.npmjs.org"
|
||||
node-version-file: './superset-embedded-sdk/.nvmrc'
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
- run: npm ci
|
||||
- run: npm run ci:release
|
||||
env:
|
||||
|
||||
6
.github/workflows/embedded-sdk-test.yml
vendored
6
.github/workflows/embedded-sdk-test.yml
vendored
@@ -21,13 +21,13 @@ jobs:
|
||||
run:
|
||||
working-directory: superset-embedded-sdk
|
||||
steps:
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
|
||||
with:
|
||||
node-version-file: "./superset-embedded-sdk/.nvmrc"
|
||||
registry-url: "https://registry.npmjs.org"
|
||||
node-version-file: './superset-embedded-sdk/.nvmrc'
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
- run: npm ci
|
||||
- run: npm test
|
||||
- run: npm run build
|
||||
|
||||
2
.github/workflows/generate-FOSSA-report.yml
vendored
2
.github/workflows/generate-FOSSA-report.yml
vendored
@@ -32,7 +32,7 @@ jobs:
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
|
||||
@@ -18,6 +18,7 @@ concurrency:
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
|
||||
validate-all-ghas:
|
||||
runs-on: ubuntu-24.04
|
||||
permissions:
|
||||
@@ -27,14 +28,14 @@ jobs:
|
||||
security-events: write
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
||||
with:
|
||||
node-version: "20"
|
||||
node-version: '20'
|
||||
|
||||
- name: Install Dependencies
|
||||
run: npm install -g @action-validator/core @action-validator/cli --save-dev
|
||||
|
||||
3
.github/workflows/issue_creation.yml
vendored
3
.github/workflows/issue_creation.yml
vendored
@@ -15,8 +15,9 @@ jobs:
|
||||
pull-requests: write
|
||||
issues: write
|
||||
steps:
|
||||
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
|
||||
46
.github/workflows/latest-release-tag.yml
vendored
46
.github/workflows/latest-release-tag.yml
vendored
@@ -11,29 +11,29 @@ jobs:
|
||||
contents: write
|
||||
|
||||
steps:
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
with:
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
|
||||
- name: Check for latest tag
|
||||
id: latest-tag
|
||||
env:
|
||||
RELEASE_TAG_NAME: ${{ github.event.release.tag_name }}
|
||||
run: |
|
||||
source ./scripts/tag_latest_release.sh "$RELEASE_TAG_NAME" --dry-run
|
||||
- name: Check for latest tag
|
||||
id: latest-tag
|
||||
env:
|
||||
RELEASE_TAG_NAME: ${{ github.event.release.tag_name }}
|
||||
run: |
|
||||
source ./scripts/tag_latest_release.sh "$RELEASE_TAG_NAME" --dry-run
|
||||
|
||||
- name: Configure Git
|
||||
run: |
|
||||
git config user.name "$GITHUB_ACTOR"
|
||||
git config user.email "$GITHUB_ACTOR@users.noreply.github.com"
|
||||
- name: Configure Git
|
||||
run: |
|
||||
git config user.name "$GITHUB_ACTOR"
|
||||
git config user.email "$GITHUB_ACTOR@users.noreply.github.com"
|
||||
|
||||
- name: Run latest-tag
|
||||
uses: ./.github/actions/latest-tag
|
||||
if: steps.latest-tag.outputs.SKIP_TAG != 'true'
|
||||
with:
|
||||
description: Superset latest release
|
||||
tag-name: latest
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
- name: Run latest-tag
|
||||
uses: ./.github/actions/latest-tag
|
||||
if: steps.latest-tag.outputs.SKIP_TAG != 'true'
|
||||
with:
|
||||
description: Superset latest release
|
||||
tag-name: latest
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
|
||||
6
.github/workflows/license-check.yml
vendored
6
.github/workflows/license-check.yml
vendored
@@ -18,14 +18,14 @@ jobs:
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5
|
||||
with:
|
||||
distribution: "temurin"
|
||||
java-version: "11"
|
||||
distribution: 'temurin'
|
||||
java-version: '11'
|
||||
- name: Run license check
|
||||
run: ./scripts/check_license.sh
|
||||
|
||||
5
.github/workflows/pr-lint.yml
vendored
5
.github/workflows/pr-lint.yml
vendored
@@ -21,7 +21,7 @@ jobs:
|
||||
pull-requests: write
|
||||
steps:
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
@@ -31,5 +31,6 @@ jobs:
|
||||
on-failed-regex-fail-action: true
|
||||
on-failed-regex-request-changes: 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 }}"
|
||||
|
||||
10
.github/workflows/pre-commit.yml
vendored
10
.github/workflows/pre-commit.yml
vendored
@@ -28,7 +28,7 @@ jobs:
|
||||
python-version: ${{ github.event_name == 'pull_request' && fromJSON('["current"]') || fromJSON('["current", "previous", "next"]') }}
|
||||
steps:
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
@@ -48,9 +48,9 @@ jobs:
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
|
||||
with:
|
||||
node-version: "20"
|
||||
cache: "npm"
|
||||
cache-dependency-path: "superset-frontend/package-lock.json"
|
||||
node-version: '20'
|
||||
cache: 'npm'
|
||||
cache-dependency-path: 'superset-frontend/package-lock.json'
|
||||
|
||||
- name: Install Frontend Dependencies
|
||||
run: |
|
||||
@@ -74,7 +74,7 @@ jobs:
|
||||
id: changed_files
|
||||
uses: ./.github/actions/file-changes-action
|
||||
with:
|
||||
output: " "
|
||||
output: ' '
|
||||
|
||||
- name: pre-commit
|
||||
env:
|
||||
|
||||
4
.github/workflows/release.yml
vendored
4
.github/workflows/release.yml
vendored
@@ -33,7 +33,7 @@ jobs:
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
# pulls all commits (needed for lerna / semantic release to correctly version)
|
||||
@@ -52,7 +52,7 @@ jobs:
|
||||
if: env.HAS_TAGS
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
|
||||
with:
|
||||
node-version-file: "./superset-frontend/.nvmrc"
|
||||
node-version-file: './superset-frontend/.nvmrc'
|
||||
|
||||
- name: Cache npm
|
||||
if: env.HAS_TAGS
|
||||
|
||||
6
.github/workflows/showtime-trigger.yml
vendored
6
.github/workflows/showtime-trigger.yml
vendored
@@ -10,11 +10,11 @@ on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
pr_number:
|
||||
description: "PR number to sync"
|
||||
description: 'PR number to sync'
|
||||
required: true
|
||||
type: number
|
||||
sha:
|
||||
description: "Specific SHA to deploy (optional, defaults to latest)"
|
||||
description: 'Specific SHA to deploy (optional, defaults to latest)'
|
||||
required: false
|
||||
type: string
|
||||
|
||||
@@ -152,7 +152,7 @@ jobs:
|
||||
|
||||
- name: Checkout PR code (only if build needed)
|
||||
if: steps.auth.outputs.authorized == 'true' && steps.check.outputs.build_needed == 'true'
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
ref: ${{ steps.check.outputs.target_sha }}
|
||||
persist-credentials: false
|
||||
|
||||
2
.github/workflows/superset-app-cli.yml
vendored
2
.github/workflows/superset-app-cli.yml
vendored
@@ -41,7 +41,7 @@ jobs:
|
||||
- 16379:6379
|
||||
steps:
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
|
||||
8
.github/workflows/superset-docs-deploy.yml
vendored
8
.github/workflows/superset-docs-deploy.yml
vendored
@@ -60,7 +60,7 @@ jobs:
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: "Checkout ${{ github.event.workflow_run.head_sha || github.sha }}"
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
ref: ${{ github.event.workflow_run.head_sha || github.sha }}
|
||||
persist-credentials: false
|
||||
@@ -68,13 +68,13 @@ jobs:
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
|
||||
with:
|
||||
node-version-file: "./docs/.nvmrc"
|
||||
node-version-file: './docs/.nvmrc'
|
||||
- name: Setup Python
|
||||
uses: ./.github/actions/setup-backend/
|
||||
- uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5
|
||||
with:
|
||||
distribution: "zulu"
|
||||
java-version: "21"
|
||||
distribution: 'zulu'
|
||||
java-version: '21'
|
||||
- name: Install Graphviz
|
||||
run: sudo apt-get install -y graphviz
|
||||
- name: Compute Entity Relationship diagram (ERD)
|
||||
|
||||
14
.github/workflows/superset-docs-verify.yml
vendored
14
.github/workflows/superset-docs-verify.yml
vendored
@@ -28,12 +28,12 @@ jobs:
|
||||
name: Link Checking
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
# Do not bump this linkinator-action version without opening
|
||||
# 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)
|
||||
with:
|
||||
paths: "**/*.md, **/*.mdx"
|
||||
@@ -73,14 +73,14 @@ jobs:
|
||||
working-directory: docs
|
||||
steps:
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
|
||||
with:
|
||||
node-version-file: "./docs/.nvmrc"
|
||||
node-version-file: './docs/.nvmrc'
|
||||
- name: yarn install
|
||||
run: |
|
||||
yarn install --check-cache
|
||||
@@ -112,7 +112,7 @@ jobs:
|
||||
working-directory: docs
|
||||
steps:
|
||||
- name: "Checkout PR head: ${{ github.event.workflow_run.head_sha }}"
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
ref: ${{ github.event.workflow_run.head_sha }}
|
||||
persist-credentials: false
|
||||
@@ -120,7 +120,7 @@ jobs:
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
|
||||
with:
|
||||
node-version-file: "./docs/.nvmrc"
|
||||
node-version-file: './docs/.nvmrc'
|
||||
- name: yarn install
|
||||
run: |
|
||||
yarn install --check-cache
|
||||
@@ -131,7 +131,7 @@ jobs:
|
||||
run_id: ${{ github.event.workflow_run.id }}
|
||||
name: database-diagnostics
|
||||
path: docs/src/data/
|
||||
if_no_artifact_found: "warning"
|
||||
if_no_artifact_found: 'warning'
|
||||
- name: Use fresh diagnostics
|
||||
run: |
|
||||
if [ -f "src/data/databases-diagnostics.json" ]; then
|
||||
|
||||
38
.github/workflows/superset-e2e.yml
vendored
38
.github/workflows/superset-e2e.yml
vendored
@@ -10,17 +10,17 @@ on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
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
|
||||
default: "false"
|
||||
default: 'false'
|
||||
ref:
|
||||
description: "The branch or tag to checkout"
|
||||
description: 'The branch or tag to checkout'
|
||||
required: false
|
||||
default: ""
|
||||
default: ''
|
||||
pr_id:
|
||||
description: "The pull request ID to checkout"
|
||||
description: 'The pull request ID to checkout'
|
||||
required: false
|
||||
default: ""
|
||||
default: ''
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
|
||||
@@ -38,7 +38,7 @@ jobs:
|
||||
frontend: ${{ steps.check.outputs.frontend }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Check for file changes
|
||||
@@ -97,21 +97,21 @@ jobs:
|
||||
# Conditional checkout based on context
|
||||
- name: Checkout for push or pull_request event
|
||||
if: github.event_name == 'push' || github.event_name == 'pull_request'
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}
|
||||
- name: Checkout using ref (workflow_dispatch)
|
||||
if: github.event_name == 'workflow_dispatch' && github.event.inputs.ref != ''
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
ref: ${{ github.event.inputs.ref }}
|
||||
submodules: recursive
|
||||
- name: Checkout using PR ID (workflow_dispatch)
|
||||
if: github.event_name == 'workflow_dispatch' && github.event.inputs.pr_id != ''
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
ref: refs/pull/${{ github.event.inputs.pr_id }}/merge
|
||||
@@ -130,9 +130,9 @@ jobs:
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
|
||||
with:
|
||||
node-version-file: "./superset-frontend/.nvmrc"
|
||||
cache: "npm"
|
||||
cache-dependency-path: "superset-frontend/package-lock.json"
|
||||
node-version-file: './superset-frontend/.nvmrc'
|
||||
cache: 'npm'
|
||||
cache-dependency-path: 'superset-frontend/package-lock.json'
|
||||
- name: Install npm dependencies
|
||||
uses: ./.github/actions/cached-dependencies
|
||||
with:
|
||||
@@ -207,21 +207,21 @@ jobs:
|
||||
# Conditional checkout based on context (same as Cypress workflow)
|
||||
- name: Checkout for push or pull_request event
|
||||
if: github.event_name == 'push' || github.event_name == 'pull_request'
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}
|
||||
- name: Checkout using ref (workflow_dispatch)
|
||||
if: github.event_name == 'workflow_dispatch' && github.event.inputs.ref != ''
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
ref: ${{ github.event.inputs.ref }}
|
||||
submodules: recursive
|
||||
- name: Checkout using PR ID (workflow_dispatch)
|
||||
if: github.event_name == 'workflow_dispatch' && github.event.inputs.pr_id != ''
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
ref: refs/pull/${{ github.event.inputs.pr_id }}/merge
|
||||
@@ -240,9 +240,9 @@ jobs:
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
|
||||
with:
|
||||
node-version-file: "./superset-frontend/.nvmrc"
|
||||
cache: "npm"
|
||||
cache-dependency-path: "superset-frontend/package-lock.json"
|
||||
node-version-file: './superset-frontend/.nvmrc'
|
||||
cache: 'npm'
|
||||
cache-dependency-path: 'superset-frontend/package-lock.json'
|
||||
- name: Install npm dependencies
|
||||
uses: ./.github/actions/cached-dependencies
|
||||
with:
|
||||
|
||||
@@ -31,7 +31,7 @@ jobs:
|
||||
working-directory: superset-extensions-cli
|
||||
steps:
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
|
||||
4
.github/workflows/superset-frontend.yml
vendored
4
.github/workflows/superset-frontend.yml
vendored
@@ -27,7 +27,7 @@ jobs:
|
||||
should-run: ${{ steps.check.outputs.frontend }}
|
||||
steps:
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
fetch-depth: 0
|
||||
@@ -110,7 +110,7 @@ jobs:
|
||||
id-token: write
|
||||
steps:
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
fetch-depth: 0
|
||||
|
||||
4
.github/workflows/superset-helm-lint.yml
vendored
4
.github/workflows/superset-helm-lint.yml
vendored
@@ -19,7 +19,7 @@ jobs:
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
@@ -33,7 +33,7 @@ jobs:
|
||||
- name: Setup Python
|
||||
uses: ./.github/actions/setup-backend/
|
||||
with:
|
||||
install-superset: "false"
|
||||
install-superset: 'false'
|
||||
|
||||
- name: Set up chart-testing
|
||||
uses: ./.github/actions/chart-testing-action
|
||||
|
||||
2
.github/workflows/superset-helm-release.yml
vendored
2
.github/workflows/superset-helm-release.yml
vendored
@@ -29,7 +29,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
ref: ${{ inputs.ref || github.ref_name }}
|
||||
persist-credentials: true
|
||||
|
||||
22
.github/workflows/superset-playwright.yml
vendored
22
.github/workflows/superset-playwright.yml
vendored
@@ -10,13 +10,13 @@ on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
ref:
|
||||
description: "The branch or tag to checkout"
|
||||
description: 'The branch or tag to checkout'
|
||||
required: false
|
||||
default: ""
|
||||
default: ''
|
||||
pr_id:
|
||||
description: "The pull request ID to checkout"
|
||||
description: 'The pull request ID to checkout'
|
||||
required: false
|
||||
default: ""
|
||||
default: ''
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
|
||||
@@ -34,7 +34,7 @@ jobs:
|
||||
frontend: ${{ steps.check.outputs.frontend }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Check for file changes
|
||||
@@ -83,21 +83,21 @@ jobs:
|
||||
# Conditional checkout based on context (same as Cypress workflow)
|
||||
- name: Checkout for push or pull_request event
|
||||
if: github.event_name == 'push' || github.event_name == 'pull_request'
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}
|
||||
- name: Checkout using ref (workflow_dispatch)
|
||||
if: github.event_name == 'workflow_dispatch' && github.event.inputs.ref != ''
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
ref: ${{ github.event.inputs.ref }}
|
||||
submodules: recursive
|
||||
- name: Checkout using PR ID (workflow_dispatch)
|
||||
if: github.event_name == 'workflow_dispatch' && github.event.inputs.pr_id != ''
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
ref: refs/pull/${{ github.event.inputs.pr_id }}/merge
|
||||
@@ -116,9 +116,9 @@ jobs:
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
|
||||
with:
|
||||
node-version-file: "./superset-frontend/.nvmrc"
|
||||
cache: "npm"
|
||||
cache-dependency-path: "superset-frontend/package-lock.json"
|
||||
node-version-file: './superset-frontend/.nvmrc'
|
||||
cache: 'npm'
|
||||
cache-dependency-path: 'superset-frontend/package-lock.json'
|
||||
- name: Install npm dependencies
|
||||
uses: ./.github/actions/cached-dependencies
|
||||
with:
|
||||
|
||||
@@ -24,7 +24,7 @@ jobs:
|
||||
python: ${{ steps.check.outputs.python }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Check for file changes
|
||||
@@ -67,7 +67,7 @@ jobs:
|
||||
- 16379:6379
|
||||
steps:
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
@@ -152,7 +152,7 @@ jobs:
|
||||
- 16379:6379
|
||||
steps:
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
@@ -202,7 +202,7 @@ jobs:
|
||||
- 16379:6379
|
||||
steps:
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
|
||||
@@ -25,7 +25,7 @@ jobs:
|
||||
python: ${{ steps.check.outputs.python }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Check for file changes
|
||||
@@ -72,7 +72,7 @@ jobs:
|
||||
- 16379:6379
|
||||
steps:
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
@@ -127,7 +127,7 @@ jobs:
|
||||
- 16379:6379
|
||||
steps:
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
|
||||
@@ -25,7 +25,7 @@ jobs:
|
||||
python: ${{ steps.check.outputs.python }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Check for file changes
|
||||
@@ -50,7 +50,7 @@ jobs:
|
||||
PYTHONPATH: ${{ github.workspace }}
|
||||
steps:
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
|
||||
10
.github/workflows/superset-translations.yml
vendored
10
.github/workflows/superset-translations.yml
vendored
@@ -25,7 +25,7 @@ jobs:
|
||||
pull-requests: read
|
||||
steps:
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
@@ -40,9 +40,9 @@ jobs:
|
||||
if: steps.check.outputs.frontend
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
|
||||
with:
|
||||
node-version-file: "./superset-frontend/.nvmrc"
|
||||
cache: "npm"
|
||||
cache-dependency-path: "superset-frontend/package-lock.json"
|
||||
node-version-file: './superset-frontend/.nvmrc'
|
||||
cache: 'npm'
|
||||
cache-dependency-path: 'superset-frontend/package-lock.json'
|
||||
- name: Install dependencies
|
||||
if: steps.check.outputs.frontend
|
||||
uses: ./.github/actions/cached-dependencies
|
||||
@@ -61,7 +61,7 @@ jobs:
|
||||
pull-requests: read
|
||||
steps:
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
|
||||
2
.github/workflows/superset-websocket.yml
vendored
2
.github/workflows/superset-websocket.yml
vendored
@@ -25,7 +25,7 @@ jobs:
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Install dependencies
|
||||
|
||||
4
.github/workflows/supersetbot.yml
vendored
4
.github/workflows/supersetbot.yml
vendored
@@ -9,7 +9,7 @@ on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
comment_body:
|
||||
description: "Comment Body"
|
||||
description: 'Comment Body'
|
||||
required: true
|
||||
type: string
|
||||
|
||||
@@ -38,7 +38,7 @@ jobs:
|
||||
});
|
||||
|
||||
- name: "Checkout ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
|
||||
15
.github/workflows/tag-release.yml
vendored
15
.github/workflows/tag-release.yml
vendored
@@ -16,11 +16,11 @@ on:
|
||||
force-latest:
|
||||
required: true
|
||||
type: choice
|
||||
default: "false"
|
||||
default: 'false'
|
||||
description: Whether to force a latest tag on the release
|
||||
options:
|
||||
- "true"
|
||||
- "false"
|
||||
- 'true'
|
||||
- 'false'
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
@@ -49,12 +49,12 @@ jobs:
|
||||
contents: write
|
||||
strategy:
|
||||
matrix:
|
||||
build_preset:
|
||||
["dev", "lean", "py310", "websocket", "dockerize", "py311", "py312"]
|
||||
build_preset: ["dev", "lean", "py310", "websocket", "dockerize", "py311", "py312"]
|
||||
fail-fast: false
|
||||
steps:
|
||||
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
fetch-depth: 0
|
||||
@@ -119,8 +119,9 @@ jobs:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
steps:
|
||||
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
fetch-depth: 0
|
||||
|
||||
4
.github/workflows/tech-debt.yml
vendored
4
.github/workflows/tech-debt.yml
vendored
@@ -32,14 +32,14 @@ jobs:
|
||||
name: Generate Reports
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
|
||||
with:
|
||||
node-version-file: "./superset-frontend/.nvmrc"
|
||||
node-version-file: './superset-frontend/.nvmrc'
|
||||
|
||||
- name: Install Dependencies
|
||||
run: npm ci
|
||||
|
||||
@@ -55,13 +55,6 @@ WORKDIR /app/superset-frontend
|
||||
RUN mkdir -p /app/superset/static/assets \
|
||||
/app/superset/translations
|
||||
|
||||
# Harden `npm ci` against transient npm-registry network blips (e.g. ECONNRESET),
|
||||
# which otherwise fail the entire multi-platform image build with no retry.
|
||||
ENV npm_config_fetch_retries=5 \
|
||||
npm_config_fetch_retry_mintimeout=20000 \
|
||||
npm_config_fetch_retry_maxtimeout=120000 \
|
||||
npm_config_fetch_timeout=600000
|
||||
|
||||
# Mount package files and install dependencies if not in dev mode
|
||||
# NOTE: we mount packages and plugins as they are referenced in package.json as workspaces
|
||||
# ideally we'd COPY only their package.json. Here npm ci will be cached as long
|
||||
|
||||
38
UPDATING.md
38
UPDATING.md
@@ -44,44 +44,6 @@ The embedded dashboard page now validates the origin of incoming `postMessage` e
|
||||
|
||||
Enforcement only applies when the Allowed Domains list is non-empty. If the list is empty (the default), any origin is accepted, so there is no behavior change for embeds that did not configure Allowed Domains.
|
||||
|
||||
### Default guest/async JWT secrets are rejected at startup
|
||||
|
||||
Superset already refuses to start in production (non-debug, non-testing) when `SECRET_KEY` is left at its built-in default, and when `GUEST_TOKEN_JWT_SECRET` is left at its default while `EMBEDDED_SUPERSET` is enabled. This behavior is extended to `GLOBAL_ASYNC_QUERIES_JWT_SECRET`: if the `GLOBAL_ASYNC_QUERIES` feature flag is enabled and the secret is still the publicly known default (`test-secret-change-me`), Superset logs a clear error and refuses to start.
|
||||
|
||||
As with the existing `SECRET_KEY` check, this only fails in production. In debug mode, testing mode, or under the test runner, a warning is logged instead of exiting, so local development is unaffected.
|
||||
|
||||
To resolve the error, set a strong random value in `superset_config.py`:
|
||||
|
||||
```python
|
||||
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.
|
||||
|
||||
### 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.
|
||||
|
||||
### SMTP server certificate validation enabled by default
|
||||
|
||||
`SMTP_SSL_SERVER_AUTH` now defaults to `True` (previously `False`). With this default, STARTTLS/SSL connections to the configured SMTP server validate the server's TLS certificate against the system trusted CA store. This makes outbound email (alerts and reports) verify the mail server's identity out of the box.
|
||||
|
||||
If your SMTP server presents a self-signed certificate, or a certificate that is not trusted by the system CA store, email delivery may now fail with a certificate verification error. To restore the previous behavior of skipping certificate validation, set the following in `superset_config.py`:
|
||||
|
||||
```python
|
||||
SMTP_SSL_SERVER_AUTH = False
|
||||
```
|
||||
|
||||
The recommended fix is to add the SMTP server's certificate (or its issuing CA) to the system trust store rather than disabling validation.
|
||||
|
||||
### 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.
|
||||
|
||||
@@ -101,7 +101,7 @@
|
||||
"@types/js-yaml": "^4.0.9",
|
||||
"@types/react": "^19.1.8",
|
||||
"@typescript-eslint/eslint-plugin": "^8.59.3",
|
||||
"@typescript-eslint/parser": "^8.60.1",
|
||||
"@typescript-eslint/parser": "^8.60.0",
|
||||
"eslint": "^9.39.2",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
"eslint-plugin-prettier": "^5.5.6",
|
||||
@@ -109,7 +109,7 @@
|
||||
"globals": "^17.6.0",
|
||||
"prettier": "^3.8.3",
|
||||
"typescript": "~6.0.3",
|
||||
"typescript-eslint": "^8.60.1",
|
||||
"typescript-eslint": "^8.60.0",
|
||||
"webpack": "^5.107.2"
|
||||
},
|
||||
"browserslist": {
|
||||
|
||||
156
docs/yarn.lock
156
docs/yarn.lock
@@ -4812,110 +4812,110 @@
|
||||
dependencies:
|
||||
"@types/yargs-parser" "*"
|
||||
|
||||
"@typescript-eslint/eslint-plugin@8.60.1", "@typescript-eslint/eslint-plugin@^8.59.3":
|
||||
version "8.60.1"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.60.1.tgz#c1060bb8fa4be80624d3f3dec8dd9caca373af76"
|
||||
integrity sha512-JQ4S5GB0tfjO8BuJ4fcX+HodkzJjYBV+7OJ+wLygaX7OGQ7FudyHL4NSCA6ob+w3Yn+5MkKIozOwQhXeM7opVg==
|
||||
"@typescript-eslint/eslint-plugin@8.60.0", "@typescript-eslint/eslint-plugin@^8.59.3":
|
||||
version "8.60.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.60.0.tgz#8fc1e0a950c43270eaf0212dc060f7edaa42f9cf"
|
||||
integrity sha512-QYb/sa74/s7OKMbACMjrYnGspj9Hs5YI5aaffSL65UfeBUzVzBJfVo3oWSpbzPurvm7yaCCo2Lk7lVj610HqKw==
|
||||
dependencies:
|
||||
"@eslint-community/regexpp" "^4.12.2"
|
||||
"@typescript-eslint/scope-manager" "8.60.1"
|
||||
"@typescript-eslint/type-utils" "8.60.1"
|
||||
"@typescript-eslint/utils" "8.60.1"
|
||||
"@typescript-eslint/visitor-keys" "8.60.1"
|
||||
"@typescript-eslint/scope-manager" "8.60.0"
|
||||
"@typescript-eslint/type-utils" "8.60.0"
|
||||
"@typescript-eslint/utils" "8.60.0"
|
||||
"@typescript-eslint/visitor-keys" "8.60.0"
|
||||
ignore "^7.0.5"
|
||||
natural-compare "^1.4.0"
|
||||
ts-api-utils "^2.5.0"
|
||||
|
||||
"@typescript-eslint/parser@8.60.1", "@typescript-eslint/parser@^8.60.1":
|
||||
version "8.60.1"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.60.1.tgz#a9d7f30850384d34b41f4687dd8944823c09e289"
|
||||
integrity sha512-A0M6ua6H252bVjPvvtSgl2QA4+ET9S5Mtkb2GDyTxIhH/C4qDItT7RQNO5PhMC6NXGYXOR9dIalcDDgBKT7oFA==
|
||||
"@typescript-eslint/parser@8.60.0", "@typescript-eslint/parser@^8.60.0":
|
||||
version "8.60.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.60.0.tgz#38d611b8e658cb10850d4975e8a175a222fbcd6a"
|
||||
integrity sha512-fcqpj/MyK4sxDPcbe7STNPbpQL4RLZOPWuaTmwZYuc+hJKzRf58yRxfhqGpc6PIq9ZyfSBpfHgmUHmHs0KwHwg==
|
||||
dependencies:
|
||||
"@typescript-eslint/scope-manager" "8.60.1"
|
||||
"@typescript-eslint/types" "8.60.1"
|
||||
"@typescript-eslint/typescript-estree" "8.60.1"
|
||||
"@typescript-eslint/visitor-keys" "8.60.1"
|
||||
"@typescript-eslint/scope-manager" "8.60.0"
|
||||
"@typescript-eslint/types" "8.60.0"
|
||||
"@typescript-eslint/typescript-estree" "8.60.0"
|
||||
"@typescript-eslint/visitor-keys" "8.60.0"
|
||||
debug "^4.4.3"
|
||||
|
||||
"@typescript-eslint/project-service@8.60.1":
|
||||
version "8.60.1"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/project-service/-/project-service-8.60.1.tgz#eb29712f58d72c222fc727162e92f2ab4670971b"
|
||||
integrity sha512-eXkTH2bxmXlqD1RnOPmLZ9ZM9D3VwSx04JOwBnP9RQ+yUA5a2Mu7SfW8uaV2Aon53NJzZlZYuX7tn91Izf+xaw==
|
||||
"@typescript-eslint/project-service@8.60.0":
|
||||
version "8.60.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/project-service/-/project-service-8.60.0.tgz#b82ab12e64d005d0c7163d1240c432381f1bde0f"
|
||||
integrity sha512-aZu74NNKJeUWqCjDddzdiKaS82dgYgV/vmf+Ui3ZdZejmgfXR/q+pRumgobnQ2cCJTgGTWp4ypiwsuofFubavg==
|
||||
dependencies:
|
||||
"@typescript-eslint/tsconfig-utils" "^8.60.1"
|
||||
"@typescript-eslint/types" "^8.60.1"
|
||||
"@typescript-eslint/tsconfig-utils" "^8.60.0"
|
||||
"@typescript-eslint/types" "^8.60.0"
|
||||
debug "^4.4.3"
|
||||
|
||||
"@typescript-eslint/scope-manager@8.60.1":
|
||||
version "8.60.1"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.60.1.tgz#2f875962eaad0a0789cc3c36aea9b4ddeb2dd9c8"
|
||||
integrity sha512-gvI5OQoptnxQnchOirukCuQ55svJSTuD/4k5+pC267xyBtYry748R9/c3tYUzb/iE6RZfllRz2lVulLCHkTm4w==
|
||||
"@typescript-eslint/scope-manager@8.60.0":
|
||||
version "8.60.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.60.0.tgz#7617a4617c043fe235dcf066f9a40f106cfd2fd5"
|
||||
integrity sha512-pFzqhllJMs+jghLQWzV00ds39xLzuyqPSev5pd8f4Ir0rtKR3ZLUB4/4dhjOFighWb9larvtfJvqL+4yKDI3Xw==
|
||||
dependencies:
|
||||
"@typescript-eslint/types" "8.60.1"
|
||||
"@typescript-eslint/visitor-keys" "8.60.1"
|
||||
"@typescript-eslint/types" "8.60.0"
|
||||
"@typescript-eslint/visitor-keys" "8.60.0"
|
||||
|
||||
"@typescript-eslint/tsconfig-utils@8.60.1":
|
||||
"@typescript-eslint/tsconfig-utils@8.60.0":
|
||||
version "8.60.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.60.0.tgz#3af78c48956227a407dea9626b8db8ca53f130d2"
|
||||
integrity sha512-BZPR3RGYlAXnly6ymAxfkVn5rCbZzQNou0rxv3GfWZ8cTQp+hhVd73khbGLAd8k1TlAPLISH337M+tAgAnaJDQ==
|
||||
|
||||
"@typescript-eslint/tsconfig-utils@^8.60.0":
|
||||
version "8.60.1"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.60.1.tgz#bee8b942a13679a878101c9c74577d732062ed93"
|
||||
integrity sha512-nh8w4qAteiKuZu3pSSzG/yGKpw0OlkrKnzFmbVRenKaD4qc+7i1GrmZaLVkr8rk4uipiPGMOW4YsM6WmKZ5CvA==
|
||||
|
||||
"@typescript-eslint/tsconfig-utils@^8.60.1":
|
||||
version "8.61.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.61.0.tgz#05d6e3ff20001674ebcd22d03dac29ee448043ba"
|
||||
integrity sha512-O5Amvdv9ztMpxpf+vmFULGG78IE6Qwdr3bCGvqwG4nwc9H2qXkOYJJnRbRHyMkQTjv1d03olqwwwzHLMqpFePQ==
|
||||
|
||||
"@typescript-eslint/type-utils@8.60.1":
|
||||
version "8.60.1"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.60.1.tgz#1ae45f0f2a701354beea4a58c2161e40a5e3c379"
|
||||
integrity sha512-sdwTrpjosW7ANQYJ39ZBF1ZyEMEGVB2UsikrserVM/30a/F1dTLnu9bGxEdosugyu5caigjLrR2qiD11asjI1A==
|
||||
"@typescript-eslint/type-utils@8.60.0":
|
||||
version "8.60.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.60.0.tgz#6971a61bc4f3a1b2df45dcc14e26a43a88a4cb6a"
|
||||
integrity sha512-SX46wEUtitCpq7AN38HkUU/+zvUpdKf7ephtWAFgckH8O7PQIyL5gvrhQgBLuEYgLfuKWOVvWVskMbuFHAz5xg==
|
||||
dependencies:
|
||||
"@typescript-eslint/types" "8.60.1"
|
||||
"@typescript-eslint/typescript-estree" "8.60.1"
|
||||
"@typescript-eslint/utils" "8.60.1"
|
||||
"@typescript-eslint/types" "8.60.0"
|
||||
"@typescript-eslint/typescript-estree" "8.60.0"
|
||||
"@typescript-eslint/utils" "8.60.0"
|
||||
debug "^4.4.3"
|
||||
ts-api-utils "^2.5.0"
|
||||
|
||||
"@typescript-eslint/types@8.60.1":
|
||||
"@typescript-eslint/types@8.60.0":
|
||||
version "8.60.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.60.0.tgz#e77ad768e933263b1960b2fe79de75fe1cc6e7db"
|
||||
integrity sha512-AsE7x2XaAK+CVbeih0Fvbn+r1qHxtpLDJ3XUuFcIinT318T90yHMJC+Zgv+jUuDjQQd06HKwxnDu6sz1IcTilA==
|
||||
|
||||
"@typescript-eslint/types@^8.60.0":
|
||||
version "8.60.1"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.60.1.tgz#ccdc482ba9e17f9723a10ce240b5e67dad3046c4"
|
||||
integrity sha512-4h0tY8ppCkdCzcrl2YM5M3my0xsE1Tf8om3owEu5oPWmXwkKRmk0j0LGDzYBGUcAlesEbxBhazqu/K4cu3Ug7w==
|
||||
|
||||
"@typescript-eslint/types@^8.60.1":
|
||||
version "8.61.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.61.0.tgz#0ddb46e012a4288292950bdd253db42f278ce64d"
|
||||
integrity sha512-9QTQpZ5Iin4CdIodfbDQFSeiSJKidgYJYug1P9CC2xWgUTvlmixViqDZNciMjwLBZyJnG4tGmPl97rVAFb1AJg==
|
||||
|
||||
"@typescript-eslint/typescript-estree@8.60.1":
|
||||
version "8.60.1"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.60.1.tgz#016630b119228bf483ddc652703a6a038f3fdd74"
|
||||
integrity sha512-alpRkfG8hlVE5kdJW2GkfgDgXxold3e8e4l6EnmhRmRLbekgAPCCGDVD++sABy9FcgPFroq+uFcCSM1vR57Cew==
|
||||
"@typescript-eslint/typescript-estree@8.60.0":
|
||||
version "8.60.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.60.0.tgz#c102196a44414481190041c99eea1d854e66001b"
|
||||
integrity sha512-3AcZNBGMClm6CXDyo8kYvVGT/sx29sS0oBsIb9oZI2gunA4Vm2M3YHzRLPvsUBBsl+yB5FPtltq7gGH0iTlp9g==
|
||||
dependencies:
|
||||
"@typescript-eslint/project-service" "8.60.1"
|
||||
"@typescript-eslint/tsconfig-utils" "8.60.1"
|
||||
"@typescript-eslint/types" "8.60.1"
|
||||
"@typescript-eslint/visitor-keys" "8.60.1"
|
||||
"@typescript-eslint/project-service" "8.60.0"
|
||||
"@typescript-eslint/tsconfig-utils" "8.60.0"
|
||||
"@typescript-eslint/types" "8.60.0"
|
||||
"@typescript-eslint/visitor-keys" "8.60.0"
|
||||
debug "^4.4.3"
|
||||
minimatch "^10.2.2"
|
||||
semver "^7.7.3"
|
||||
tinyglobby "^0.2.15"
|
||||
ts-api-utils "^2.5.0"
|
||||
|
||||
"@typescript-eslint/utils@8.60.1":
|
||||
version "8.60.1"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.60.1.tgz#31cf566095602d9fe8ad91837d2eb520b8de762b"
|
||||
integrity sha512-h2MPBLoNtjc3qZWfY3Tl51yPorQ2McHn8pJfcMNTcIvrrZrr90Ykffit0yjrPFWQcRcUxzH20+6OcVdW4yHtUg==
|
||||
"@typescript-eslint/utils@8.60.0":
|
||||
version "8.60.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.60.0.tgz#6110cddaef87606ae4ca6f8bf81bb5949fc8e098"
|
||||
integrity sha512-HtXuPfrHTyBDkameWpl+vJb1Uevu2tznAyahM1Oc4AENidCLTPiZDWIo4GfcxNdC/RcfGcadzzkqbRG87dUrQA==
|
||||
dependencies:
|
||||
"@eslint-community/eslint-utils" "^4.9.1"
|
||||
"@typescript-eslint/scope-manager" "8.60.1"
|
||||
"@typescript-eslint/types" "8.60.1"
|
||||
"@typescript-eslint/typescript-estree" "8.60.1"
|
||||
"@typescript-eslint/scope-manager" "8.60.0"
|
||||
"@typescript-eslint/types" "8.60.0"
|
||||
"@typescript-eslint/typescript-estree" "8.60.0"
|
||||
|
||||
"@typescript-eslint/visitor-keys@8.60.1":
|
||||
version "8.60.1"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.60.1.tgz#165d1d8901137b944efaf18f00ab5ecb57f06995"
|
||||
integrity sha512-EbGRQg4FhrmwLodl+t3JNAnXHWVr9Vp+Zl1QBZVPY4ByfkzIT8cX3K6QWODHtkIZqqJVEWvhHSx3v5PDHsaQag==
|
||||
"@typescript-eslint/visitor-keys@8.60.0":
|
||||
version "8.60.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.60.0.tgz#f2c41eedd3d7b03b808369fb2e3fb40a93783ec2"
|
||||
integrity sha512-9WI52t8ZGLVGrPMBet25yAftqY/n95+zmoUUtJBBQTKDSKUu7OsPTroT2op7U9JatkoRccL0YkWDNMFfC4Sjxg==
|
||||
dependencies:
|
||||
"@typescript-eslint/types" "8.60.1"
|
||||
"@typescript-eslint/types" "8.60.0"
|
||||
eslint-visitor-keys "^5.0.0"
|
||||
|
||||
"@ungap/structured-clone@^1.0.0":
|
||||
@@ -13490,9 +13490,9 @@ shebang-regex@^3.0.0:
|
||||
integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
|
||||
|
||||
shell-quote@^1.8.3:
|
||||
version "1.8.4"
|
||||
resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.8.4.tgz#2edd9a4dcefc96649e2e2cb12f637b1f1d92a190"
|
||||
integrity sha512-VsC6n6vz1ihYYyZZwX7YZSF5l5x36ca17OC+a69h94YqB7X6XLwf+5MOgynYir2SLFUbl8gIYvBo8K8RoNQ6bQ==
|
||||
version "1.8.3"
|
||||
resolved "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz"
|
||||
integrity sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==
|
||||
|
||||
shelljs@0.8.5:
|
||||
version "0.8.5"
|
||||
@@ -14389,15 +14389,15 @@ types-ramda@^0.30.1:
|
||||
dependencies:
|
||||
ts-toolbelt "^9.6.0"
|
||||
|
||||
typescript-eslint@^8.60.1:
|
||||
version "8.60.1"
|
||||
resolved "https://registry.yarnpkg.com/typescript-eslint/-/typescript-eslint-8.60.1.tgz#13db05c6eabb89669deec44545b788a0e9aee640"
|
||||
integrity sha512-6m5hkkRAp8lKvhVpcprAIn5KkehQEh+47oHH2VGnExEh7dhNxXlg6GPAOIu6TxbVQxhebrJDvjl3020ooiWCMA==
|
||||
typescript-eslint@^8.60.0:
|
||||
version "8.60.0"
|
||||
resolved "https://registry.yarnpkg.com/typescript-eslint/-/typescript-eslint-8.60.0.tgz#6686fecb1f4f367c0bf0075828e93b7ecacbc62b"
|
||||
integrity sha512-9f65qWLZdAW9m1JaxBDUHcqRUfL8bkxxXL7XxEfI+F09q56PkBvIfCjLF3yInsDM/BBmwkqmCQdCZe/RYlIWEw==
|
||||
dependencies:
|
||||
"@typescript-eslint/eslint-plugin" "8.60.1"
|
||||
"@typescript-eslint/parser" "8.60.1"
|
||||
"@typescript-eslint/typescript-estree" "8.60.1"
|
||||
"@typescript-eslint/utils" "8.60.1"
|
||||
"@typescript-eslint/eslint-plugin" "8.60.0"
|
||||
"@typescript-eslint/parser" "8.60.0"
|
||||
"@typescript-eslint/typescript-estree" "8.60.0"
|
||||
"@typescript-eslint/utils" "8.60.0"
|
||||
|
||||
typescript@~6.0.3:
|
||||
version "6.0.3"
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
# limitations under the License.
|
||||
#
|
||||
apiVersion: v2
|
||||
appVersion: "6.1.0"
|
||||
appVersion: "5.0.0"
|
||||
description: Apache Superset is a modern, enterprise-ready business intelligence web application
|
||||
name: superset
|
||||
icon: https://artifacthub.io/image/68c1d717-0e97-491f-b046-754e46f46922@2x
|
||||
@@ -29,7 +29,7 @@ maintainers:
|
||||
- name: craig-rueda
|
||||
email: craig@craigrueda.com
|
||||
url: https://github.com/craig-rueda
|
||||
version: 0.16.0 # 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:
|
||||
- name: postgresql
|
||||
version: 16.7.27
|
||||
|
||||
@@ -23,7 +23,7 @@ NOTE: This file is generated by helm-docs: https://github.com/norwoodj/helm-docs
|
||||
|
||||
# superset
|
||||
|
||||

|
||||

|
||||
|
||||
Apache Superset is a modern, enterprise-ready business intelligence web application
|
||||
|
||||
|
||||
@@ -89,7 +89,7 @@ dependencies = [
|
||||
"python-dateutil",
|
||||
"python-dotenv", # optional dependencies for Flask but required for Superset, see https://flask.palletsprojects.com/en/stable/installation/#optional-dependencies
|
||||
"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.0, <7.0.0",
|
||||
"PyJWT>=2.4.0, <3.0",
|
||||
"redis>=5.0.0, <6.0",
|
||||
@@ -447,7 +447,6 @@ requirement_txt_file = "requirements/base.txt"
|
||||
authorized_licenses = [
|
||||
"academic free license (afl)",
|
||||
"any-osi",
|
||||
"apache-2.0",
|
||||
"apache license 2.0",
|
||||
"apache software",
|
||||
"apache software, bsd",
|
||||
|
||||
@@ -30,7 +30,7 @@ cryptography>=46.0.7,<47.0.0
|
||||
# Security: Snyk - XSS vulnerability in Mako templates
|
||||
mako>=1.3.11,<2.0.0
|
||||
# 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
|
||||
pyopenssl>=26.0.0,<27.0.0
|
||||
# Security: CVE-2026-25645 (MEDIUM) - Insecure Temporary File
|
||||
|
||||
@@ -294,7 +294,7 @@ prison==0.2.1
|
||||
# via flask-appbuilder
|
||||
prompt-toolkit==3.0.51
|
||||
# via click-repl
|
||||
pyarrow==24.0.0
|
||||
pyarrow==20.0.0
|
||||
# via
|
||||
# -r requirements/base.in
|
||||
# apache-superset (pyproject.toml)
|
||||
|
||||
@@ -715,7 +715,7 @@ psycopg2-binary==2.9.12
|
||||
# via apache-superset
|
||||
py-key-value-aio==0.4.4
|
||||
# via fastmcp
|
||||
pyarrow==24.0.0
|
||||
pyarrow==20.0.0
|
||||
# via
|
||||
# -c requirements/base-constraint.txt
|
||||
# apache-superset
|
||||
|
||||
@@ -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 \
|
||||
&& 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 \
|
||||
-i superset/translations/messages.pot \
|
||||
-d superset/translations \
|
||||
--ignore-obsolete \
|
||||
--no-fuzzy-matching
|
||||
--ignore-obsolete
|
||||
|
||||
# Chop off last blankline from po/pot files, see https://github.com/python-babel/babel/issues/799
|
||||
for file in $( find superset/translations/** );
|
||||
|
||||
@@ -20,21 +20,20 @@ Check that source-code changes don't cause translation regressions.
|
||||
|
||||
What counts as a regression
|
||||
---------------------------
|
||||
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
|
||||
translated count, because a count drop happens identically for a benign
|
||||
*deletion* and a real *rename*, so it cannot distinguish the two — whereas a
|
||||
``#, fuzzy`` marker unambiguously flags a stranded translation.
|
||||
A regression is an *existing translation that a source change invalidated* —
|
||||
i.e. a string was renamed/reworded so its committed translation no longer
|
||||
applies. ``babel_update.sh`` (``pybabel update --ignore-obsolete``) surfaces
|
||||
exactly these as **newly fuzzy** entries: the old translation is fuzzy-matched
|
||||
onto the new ``msgid`` and flagged ``#, fuzzy``.
|
||||
|
||||
Note ``babel_update.sh`` runs ``pybabel update`` with ``--no-fuzzy-matching``,
|
||||
so *adding* (or renaming) a source string does **not** auto-generate a fuzzy
|
||||
guess against an unrelated existing translation — new strings land as cleanly
|
||||
untranslated (empty ``msgstr``). This deliberately avoids the prior behaviour
|
||||
where *every* PR that merely added a translatable string tripped this check on
|
||||
spurious fuzzies. As a result the check now guards against ``#, fuzzy`` entries
|
||||
that arrive another way — e.g. a committed ``.po`` edit — rather than ones the
|
||||
update step synthesises. *Deleting* a string is still not a regression: with
|
||||
``--ignore-obsolete`` it is simply dropped and no fuzzy is created.
|
||||
Crucially, *deleting* a translatable string is **not** a regression. With
|
||||
``--ignore-obsolete`` a removed string is dropped from the catalogs entirely;
|
||||
no fuzzy entry is created. So a PR that intentionally removes a string (e.g. a
|
||||
security fix that stops rendering a value) legitimately lowers the translated
|
||||
count without introducing any fuzzies, and must not be flagged. We therefore
|
||||
key the check on the **increase in fuzzy entries**, not on a drop in the
|
||||
translated count (a drop happens identically for a benign deletion and a real
|
||||
rename, so it cannot distinguish the two).
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
@@ -22,7 +22,6 @@ import {
|
||||
getGuestTokenRefreshTiming,
|
||||
MIN_REFRESH_WAIT_MS,
|
||||
DEFAULT_TOKEN_EXP_MS,
|
||||
DEFAULT_TOKEN_REFRESH_RETRY_MS,
|
||||
} from "./guestTokenRefresh";
|
||||
|
||||
describe("guest token refresh", () => {
|
||||
@@ -94,11 +93,4 @@ describe("guest token refresh", () => {
|
||||
expect(timing).toBeGreaterThan(MIN_REFRESH_WAIT_MS);
|
||||
expect(timing).toBe(DEFAULT_TOKEN_EXP_MS - REFRESH_TIMING_BUFFER_MS);
|
||||
});
|
||||
|
||||
it("exposes a positive retry delay for failed token refreshes", () => {
|
||||
// The refresh loop reschedules itself after this delay when a fetch
|
||||
// fails or times out, so it must be a sane positive value.
|
||||
expect(DEFAULT_TOKEN_REFRESH_RETRY_MS).toBe(10000);
|
||||
expect(DEFAULT_TOKEN_REFRESH_RETRY_MS).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -21,7 +21,6 @@ import { jwtDecode } from "jwt-decode";
|
||||
export const REFRESH_TIMING_BUFFER_MS = 5000 // refresh guest token early to avoid failed superset requests
|
||||
export const MIN_REFRESH_WAIT_MS = 10000 // avoid blasting requests as fast as the cpu can handle
|
||||
export const DEFAULT_TOKEN_EXP_MS = 300000 // (5 min) used only when parsing guest token exp fails
|
||||
export const DEFAULT_TOKEN_REFRESH_RETRY_MS = 10000 // wait before retrying a failed/timed-out token refresh
|
||||
|
||||
// when do we refresh the guest token?
|
||||
export function getGuestTokenRefreshTiming(currentGuestToken: string) {
|
||||
|
||||
@@ -24,11 +24,7 @@ import {
|
||||
|
||||
// We can swap this out for the actual switchboard package once it gets published
|
||||
import { Switchboard } from '@superset-ui/switchboard';
|
||||
import {
|
||||
getGuestTokenRefreshTiming,
|
||||
DEFAULT_TOKEN_REFRESH_RETRY_MS,
|
||||
} from './guestTokenRefresh';
|
||||
import { withTimeout } from './withTimeout';
|
||||
import { getGuestTokenRefreshTiming } from './guestTokenRefresh';
|
||||
|
||||
/**
|
||||
* The function to fetch a guest token from your Host App's backend server.
|
||||
@@ -53,9 +49,6 @@ export type UiConfigType = {
|
||||
showRowLimitWarning?: boolean;
|
||||
};
|
||||
|
||||
/** Default per-call timeout (ms) applied to the host `fetchGuestToken` callback. */
|
||||
const DEFAULT_GUEST_TOKEN_FETCH_TIMEOUT_MS = 30_000;
|
||||
|
||||
export type EmbedDashboardParams = {
|
||||
/** The id provided by the embed configuration UI in Superset */
|
||||
id: string;
|
||||
@@ -80,10 +73,6 @@ export type EmbedDashboardParams = {
|
||||
/** Callback to resolve permalink URLs. If provided, this will be called when generating permalinks
|
||||
* to allow the host app to customize the URL. If not provided, Superset's default URL is used. */
|
||||
resolvePermalinkUrl?: ResolvePermalinkUrlFn;
|
||||
/** Timeout, in milliseconds, applied to each `fetchGuestToken` call so a host
|
||||
* callback that never resolves cannot hang the embed/refresh cycle. Defaults
|
||||
* to 30000ms. Set to 0 to disable the timeout. */
|
||||
guestTokenFetchTimeoutMs?: number;
|
||||
};
|
||||
|
||||
export type Size = {
|
||||
@@ -138,7 +127,6 @@ export async function embedDashboard({
|
||||
iframeAllowExtras = [],
|
||||
referrerPolicy,
|
||||
resolvePermalinkUrl,
|
||||
guestTokenFetchTimeoutMs = DEFAULT_GUEST_TOKEN_FETCH_TIMEOUT_MS,
|
||||
}: EmbedDashboardParams): Promise<EmbeddedDashboard> {
|
||||
function log(...info: unknown[]) {
|
||||
if (debug) {
|
||||
@@ -146,16 +134,6 @@ export async function embedDashboard({
|
||||
}
|
||||
}
|
||||
|
||||
// Wrap the host-provided fetchGuestToken so a callback that never settles
|
||||
// cannot hang the initial embed or a later refresh cycle.
|
||||
function fetchGuestTokenWithTimeout(): Promise<string> {
|
||||
return withTimeout(
|
||||
fetchGuestToken(),
|
||||
guestTokenFetchTimeoutMs,
|
||||
'fetchGuestToken',
|
||||
);
|
||||
}
|
||||
|
||||
log('embedding');
|
||||
|
||||
if (supersetDomain.endsWith('/')) {
|
||||
@@ -269,57 +247,21 @@ export async function embedDashboard({
|
||||
});
|
||||
}
|
||||
|
||||
let guestToken: string;
|
||||
let ourPort: Switchboard;
|
||||
try {
|
||||
[guestToken, ourPort] = await Promise.all([
|
||||
fetchGuestTokenWithTimeout(),
|
||||
mountIframe(),
|
||||
]);
|
||||
} catch (err) {
|
||||
// If the initial token fetch (or timeout) rejects after the iframe has
|
||||
// already been mounted, tear down the partially initialized iframe so the
|
||||
// host isn't left with an orphaned embedded dashboard before rethrowing.
|
||||
//@ts-ignore
|
||||
mountPoint.replaceChildren();
|
||||
throw err;
|
||||
}
|
||||
const [guestToken, ourPort]: [string, Switchboard] = await Promise.all([
|
||||
fetchGuestToken(),
|
||||
mountIframe(),
|
||||
]);
|
||||
|
||||
ourPort.emit('guestToken', { guestToken });
|
||||
log('sent guest token');
|
||||
|
||||
// Track the pending refresh timer so it can be cancelled on unmount, and
|
||||
// stop the cycle once unmounted so it cannot leak across mount/unmount cycles.
|
||||
let refreshTimer: ReturnType<typeof setTimeout> | undefined;
|
||||
let unmounted = false;
|
||||
|
||||
async function refreshGuestToken() {
|
||||
if (unmounted) return;
|
||||
try {
|
||||
const newGuestToken = await fetchGuestTokenWithTimeout();
|
||||
if (unmounted) return;
|
||||
ourPort.emit('guestToken', { guestToken: newGuestToken });
|
||||
refreshTimer = setTimeout(
|
||||
refreshGuestToken,
|
||||
getGuestTokenRefreshTiming(newGuestToken),
|
||||
);
|
||||
} catch (err) {
|
||||
// A transient fetch failure or timeout must not permanently stop the
|
||||
// refresh cycle. Log it and retry so the session can recover once the
|
||||
// host callback succeeds again.
|
||||
log('failed to refresh guest token, will retry:', err);
|
||||
if (unmounted) return;
|
||||
refreshTimer = setTimeout(
|
||||
refreshGuestToken,
|
||||
DEFAULT_TOKEN_REFRESH_RETRY_MS,
|
||||
);
|
||||
}
|
||||
const newGuestToken = await fetchGuestToken();
|
||||
ourPort.emit('guestToken', { guestToken: newGuestToken });
|
||||
setTimeout(refreshGuestToken, getGuestTokenRefreshTiming(newGuestToken));
|
||||
}
|
||||
|
||||
refreshTimer = setTimeout(
|
||||
refreshGuestToken,
|
||||
getGuestTokenRefreshTiming(guestToken),
|
||||
);
|
||||
setTimeout(refreshGuestToken, getGuestTokenRefreshTiming(guestToken));
|
||||
|
||||
// Register the resolvePermalinkUrl method for the iframe to call
|
||||
// Returns null if no callback provided or on error, allowing iframe to use default URL
|
||||
@@ -341,11 +283,6 @@ export async function embedDashboard({
|
||||
|
||||
function unmount() {
|
||||
log('unmounting');
|
||||
unmounted = true;
|
||||
if (refreshTimer !== undefined) {
|
||||
clearTimeout(refreshTimer);
|
||||
refreshTimer = undefined;
|
||||
}
|
||||
//@ts-ignore
|
||||
mountPoint.replaceChildren();
|
||||
}
|
||||
|
||||
@@ -1,39 +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 { withTimeout } from "./withTimeout";
|
||||
|
||||
test("resolves with the value when the promise settles in time", async () => {
|
||||
await expect(withTimeout(Promise.resolve("ok"), 1000, "fetch")).resolves.toBe(
|
||||
"ok"
|
||||
);
|
||||
});
|
||||
|
||||
test("rejects when the promise does not settle within the timeout", async () => {
|
||||
const never = new Promise<string>(() => {});
|
||||
await expect(withTimeout(never, 10, "fetch")).rejects.toThrow(
|
||||
/fetch did not resolve within 10ms/
|
||||
);
|
||||
});
|
||||
|
||||
test("passes the promise through unchanged when the timeout is disabled", async () => {
|
||||
await expect(withTimeout(Promise.resolve("ok"), 0, "fetch")).resolves.toBe(
|
||||
"ok"
|
||||
);
|
||||
});
|
||||
@@ -1,43 +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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Rejects if `promise` does not settle within `ms` milliseconds. A non-positive
|
||||
* `ms` disables the timeout and returns the promise unchanged. The timer is
|
||||
* always cleared so it cannot keep the event loop alive.
|
||||
*/
|
||||
export function withTimeout<T>(
|
||||
promise: Promise<T>,
|
||||
ms: number,
|
||||
label: string,
|
||||
): Promise<T> {
|
||||
if (!ms || ms <= 0) {
|
||||
return promise;
|
||||
}
|
||||
let timer: ReturnType<typeof setTimeout>;
|
||||
const timeout = new Promise<never>((_resolve, reject) => {
|
||||
timer = setTimeout(
|
||||
() => reject(new Error(`${label} did not resolve within ${ms}ms`)),
|
||||
ms,
|
||||
);
|
||||
});
|
||||
return Promise.race([promise, timeout]).finally(() =>
|
||||
clearTimeout(timer),
|
||||
) as Promise<T>;
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
import { dirname, join } from 'path';
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
@@ -16,16 +17,8 @@
|
||||
* specific language governing permissions and limitations
|
||||
* 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
|
||||
import customConfig from '../webpack.config.js';
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
const customConfig = require('../webpack.config.js');
|
||||
|
||||
// Filter out plugins that shouldn't be included in Storybook's static build
|
||||
// ReactRefreshWebpackPlugin adds Fast Refresh code that requires a dev server runtime,
|
||||
@@ -83,7 +76,7 @@ const disableDevModeInRules = rules =>
|
||||
};
|
||||
});
|
||||
|
||||
export default {
|
||||
module.exports = {
|
||||
stories: [
|
||||
'../src/**/*.stories.tsx',
|
||||
'../packages/superset-ui-core/src/**/*.stories.tsx',
|
||||
@@ -91,8 +84,11 @@ export default {
|
||||
],
|
||||
|
||||
addons: [
|
||||
"@storybook/addon-links",
|
||||
"@storybook/addon-docs"
|
||||
getAbsolutePath('@storybook/addon-essentials'),
|
||||
getAbsolutePath('@storybook/addon-links'),
|
||||
'@mihkeleidast/storybook-addon-source',
|
||||
getAbsolutePath('@storybook/addon-controls'),
|
||||
getAbsolutePath('@storybook/addon-mdx-gfm'),
|
||||
],
|
||||
|
||||
staticDirs: ['../src/assets/images'],
|
||||
@@ -109,13 +105,11 @@ export default {
|
||||
alias: {
|
||||
...config.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
|
||||
'@storybook-shared': path.join(__dirname, 'shared'),
|
||||
'@storybook-shared': join(__dirname, 'shared'),
|
||||
},
|
||||
fallback: {
|
||||
tty: false,
|
||||
vm: require.resolve('vm-browserify')
|
||||
}
|
||||
},
|
||||
plugins: [...config.plugins, ...filteredPlugins],
|
||||
}),
|
||||
@@ -125,11 +119,15 @@ export default {
|
||||
},
|
||||
|
||||
framework: {
|
||||
name: getAbsolutePath("@storybook/react-webpack5"),
|
||||
name: getAbsolutePath('@storybook/react-webpack5'),
|
||||
options: {},
|
||||
}
|
||||
},
|
||||
|
||||
docs: {
|
||||
autodocs: false,
|
||||
},
|
||||
};
|
||||
|
||||
function getAbsolutePath(value) {
|
||||
return path.dirname(require.resolve(path.join(value, 'package.json')));
|
||||
return dirname(require.resolve(join(value, 'package.json')));
|
||||
}
|
||||
@@ -16,6 +16,7 @@
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { withJsx } from '@mihkeleidast/storybook-addon-source';
|
||||
import { themeObject, css, exampleThemes } from '@apache-superset/core/theme';
|
||||
import { combineReducers, createStore, applyMiddleware, compose } from 'redux';
|
||||
import thunk from 'redux-thunk';
|
||||
@@ -113,12 +114,9 @@ const providerDecorator = Story => (
|
||||
</Provider>
|
||||
);
|
||||
|
||||
export const decorators = [themeDecorator, providerDecorator];
|
||||
export const decorators = [withJsx, themeDecorator, providerDecorator];
|
||||
|
||||
export const parameters = {
|
||||
docs: {
|
||||
codePanel: true,
|
||||
},
|
||||
paddings: {
|
||||
values: [
|
||||
{ name: 'None', value: '0px' },
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
import { useState, ReactNode, SyntheticEvent } from 'react';
|
||||
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 ResizablePanel, { Size } from './ResizablePanel';
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ module.exports = {
|
||||
],
|
||||
coverageReporters: ['lcov', 'json-summary', 'html', 'text'],
|
||||
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/*.)',
|
||||
'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',
|
||||
transform: {
|
||||
|
||||
9091
superset-frontend/package-lock.json
generated
9091
superset-frontend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -164,8 +164,8 @@
|
||||
"@visx/scale": "^3.5.0",
|
||||
"@visx/tooltip": "^3.0.0",
|
||||
"@visx/xychart": "^3.5.1",
|
||||
"ag-grid-community": "35.3.1",
|
||||
"ag-grid-react": "35.3.1",
|
||||
"ag-grid-community": "35.3.0",
|
||||
"ag-grid-react": "35.3.0",
|
||||
"antd": "^5.26.0",
|
||||
"chrono-node": "^2.9.1",
|
||||
"classnames": "^2.2.5",
|
||||
@@ -263,12 +263,20 @@
|
||||
"@emotion/jest": "^11.14.2",
|
||||
"@formatjs/intl-durationformat": "^0.10.3",
|
||||
"@istanbuljs/nyc-config-typescript": "^1.0.1",
|
||||
"@mihkeleidast/storybook-addon-source": "^1.0.1",
|
||||
"@playwright/test": "^1.60.0",
|
||||
"@pmmmwh/react-refresh-webpack-plugin": "^0.6.2",
|
||||
"@storybook/addon-docs": "10.4.1",
|
||||
"@storybook/addon-links": "10.4.1",
|
||||
"@storybook/react-webpack5": "10.4.1",
|
||||
"@storybook/test-runner": "0.24.4",
|
||||
"@storybook/addon-actions": "^8.6.18",
|
||||
"@storybook/addon-controls": "^8.6.18",
|
||||
"@storybook/addon-essentials": "^8.6.18",
|
||||
"@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",
|
||||
"@swc/core": "^1.15.40",
|
||||
"@swc/plugin-emotion": "^14.12.0",
|
||||
@@ -289,6 +297,7 @@
|
||||
"@types/react-dom": "^18.2.0",
|
||||
"@types/react-loadable": "^5.5.11",
|
||||
"@types/react-redux": "^7.1.10",
|
||||
"@types/react-resizable": "^4.0.0",
|
||||
"@types/react-router-dom": "^5.3.3",
|
||||
"@types/react-transition-group": "^4.4.12",
|
||||
"@types/react-window": "^1.8.8",
|
||||
@@ -297,7 +306,7 @@
|
||||
"@types/rison": "0.1.0",
|
||||
"@types/tinycolor2": "^1.4.3",
|
||||
"@types/unzipper": "^0.10.11",
|
||||
"@typescript-eslint/eslint-plugin": "^8.60.1",
|
||||
"@typescript-eslint/eslint-plugin": "^8.60.0",
|
||||
"@typescript-eslint/parser": "^8.59.4",
|
||||
"babel-jest": "^30.4.1",
|
||||
"babel-loader": "^10.1.1",
|
||||
@@ -306,7 +315,7 @@
|
||||
"babel-plugin-lodash": "^3.3.4",
|
||||
"baseline-browser-mapping": "^2.10.33",
|
||||
"cheerio": "1.2.0",
|
||||
"concurrently": "^10.0.3",
|
||||
"concurrently": "^10.0.0",
|
||||
"copy-webpack-plugin": "^14.0.0",
|
||||
"cross-env": "^10.1.0",
|
||||
"css-loader": "^7.1.4",
|
||||
@@ -314,7 +323,7 @@
|
||||
"eslint": "^8.56.0",
|
||||
"eslint-config-prettier": "^7.2.0",
|
||||
"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-i18n-strings": "file:eslint-rules/eslint-plugin-i18n-strings",
|
||||
"eslint-plugin-icons": "file:eslint-rules/eslint-plugin-icons",
|
||||
@@ -325,7 +334,7 @@
|
||||
"eslint-plugin-prettier": "^5.5.6",
|
||||
"eslint-plugin-react-prefer-function-component": "^5.0.0",
|
||||
"eslint-plugin-react-you-might-not-need-an-effect": "^0.10.4",
|
||||
"eslint-plugin-storybook": "10.4.1",
|
||||
"eslint-plugin-storybook": "^0.8.0",
|
||||
"eslint-plugin-testing-library": "^7.16.2",
|
||||
"eslint-plugin-theme-colors": "file:eslint-rules/eslint-plugin-theme-colors",
|
||||
"fetch-mock": "^12.6.0",
|
||||
@@ -344,7 +353,7 @@
|
||||
"lightningcss": "^1.32.0",
|
||||
"mini-css-extract-plugin": "^2.10.2",
|
||||
"open-cli": "^9.0.0",
|
||||
"oxlint": "^1.68.0",
|
||||
"oxlint": "^1.67.0",
|
||||
"po2json": "^0.4.5",
|
||||
"prettier": "3.8.3",
|
||||
"prettier-plugin-packagejson": "^3.0.2",
|
||||
@@ -355,7 +364,7 @@
|
||||
"source-map": "^0.7.6",
|
||||
"source-map-support": "^0.5.21",
|
||||
"speed-measure-webpack-plugin": "^1.6.0",
|
||||
"storybook": "10.4.1",
|
||||
"storybook": "8.6.18",
|
||||
"style-loader": "^4.0.0",
|
||||
"swc-loader": "^0.2.7",
|
||||
"terser-webpack-plugin": "^5.6.1",
|
||||
|
||||
@@ -508,12 +508,6 @@ export interface ThemeContextType {
|
||||
clearLocalOverrides: () => void;
|
||||
getCurrentCrudThemeId: () => string | null;
|
||||
hasDevOverride: () => boolean;
|
||||
/**
|
||||
* True when an explicit theme config override is active (e.g. supplied via
|
||||
* the Embedded SDK). Such an override takes precedence over a
|
||||
* dashboard-level theme.
|
||||
*/
|
||||
hasThemeConfigOverride: boolean;
|
||||
canSetMode: () => boolean;
|
||||
canSetTheme: () => boolean;
|
||||
canDetectOSPreference: () => boolean;
|
||||
|
||||
@@ -118,6 +118,7 @@ const matrixifyControls: Record<string, SharedControlConfig<any>> = {};
|
||||
description: t(`Select dimension and values`),
|
||||
default: { dimension: '', values: [] },
|
||||
validators: [], // No validation - rely on visibility
|
||||
renderTrigger: true,
|
||||
tabOverride: 'matrixify',
|
||||
shouldMapStateToProps: (prevState, state) => {
|
||||
// Recalculate when any relevant form_data field changes
|
||||
|
||||
@@ -31,8 +31,8 @@
|
||||
"@types/json-bigint": "^1.0.4",
|
||||
"@visx/responsive": "^3.12.0",
|
||||
"ace-builds": "^1.44.0",
|
||||
"ag-grid-community": "35.3.1",
|
||||
"ag-grid-react": "35.3.1",
|
||||
"ag-grid-community": "35.3.0",
|
||||
"ag-grid-react": "35.3.0",
|
||||
"brace": "^0.11.1",
|
||||
"classnames": "^2.5.1",
|
||||
"core-js": "^3.49.0",
|
||||
|
||||
@@ -17,20 +17,8 @@
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
forwardRef,
|
||||
useEffect,
|
||||
useImperativeHandle,
|
||||
useLayoutEffect,
|
||||
useRef,
|
||||
} from 'react';
|
||||
import type {
|
||||
ComponentType,
|
||||
WeakValidationMap,
|
||||
ForwardRefExoticComponent,
|
||||
PropsWithoutRef,
|
||||
RefAttributes,
|
||||
} from 'react';
|
||||
// eslint-disable-next-line no-restricted-syntax -- whole React import is required for `reactify.test.tsx` Jest test passing.
|
||||
import { Component, ComponentClass, WeakValidationMap } from 'react';
|
||||
|
||||
// TODO: Note that id and className can collide between Props and ReactifyProps
|
||||
// leading to (likely) unexpected behaviors. We should either require Props to not
|
||||
@@ -61,103 +49,66 @@ export interface RenderFuncType<Props> {
|
||||
propTypes?: WeakValidationMap<Props & ReactifyProps>;
|
||||
}
|
||||
|
||||
export interface ReactifiedComponentRef {
|
||||
container?: HTMLDivElement;
|
||||
}
|
||||
|
||||
export type ReactifiedComponent<Props> = ForwardRefExoticComponent<
|
||||
PropsWithoutRef<Props & ReactifyProps> & RefAttributes<ReactifiedComponentRef>
|
||||
>;
|
||||
|
||||
// Return the widest public type that covers "use it as a React component" so
|
||||
// TypeScript JSX callers and `ComponentType<...>`-typed variables still compile;
|
||||
// callers with explicit `ComponentClass<...>` annotations must widen to
|
||||
// `ComponentType`. Those wanting the forwardRef surface can narrow to
|
||||
// `ReactifiedComponent<Props>` explicitly.
|
||||
export default function reactify<Props extends object>(
|
||||
renderFn: RenderFuncType<Props>,
|
||||
callbacks?: LifeCycleCallbacks,
|
||||
): ComponentType<Props & ReactifyProps> {
|
||||
const ReactifiedComponent = forwardRef<
|
||||
ReactifiedComponentRef,
|
||||
Props & ReactifyProps
|
||||
>(function ReactifiedComponent(props, ref) {
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
// Keep the latest props available to the unmount callback — legacy
|
||||
// consumers read values off `this.props` (e.g. ReactNVD3 uses id).
|
||||
// Update the ref in a layout effect rather than during render so the
|
||||
// assignment only happens for committed renders (safe under Concurrent
|
||||
// Mode) and is in place before the passive unmount effect reads it.
|
||||
const propsRef = useRef(props);
|
||||
useLayoutEffect(() => {
|
||||
propsRef.current = props;
|
||||
});
|
||||
): ComponentClass<Props & ReactifyProps> {
|
||||
class ReactifiedComponent extends Component<Props & ReactifyProps> {
|
||||
container?: HTMLDivElement;
|
||||
|
||||
// Expose container via ref for external access
|
||||
useImperativeHandle(
|
||||
ref,
|
||||
() => ({
|
||||
get container() {
|
||||
return containerRef.current ?? undefined;
|
||||
},
|
||||
}),
|
||||
[],
|
||||
);
|
||||
constructor(props: Props & ReactifyProps) {
|
||||
super(props);
|
||||
this.setContainerRef = this.setContainerRef.bind(this);
|
||||
}
|
||||
|
||||
// Execute renderFn on mount and every update (mimics componentDidMount + componentDidUpdate)
|
||||
useEffect(() => {
|
||||
if (containerRef.current) {
|
||||
// `forwardRef` widens the props parameter to `PropsWithoutRef<...>`,
|
||||
// which TypeScript can't narrow back to `Props & ReactifyProps` when
|
||||
// `Props` is a generic `object`. The values are identical at runtime,
|
||||
// so assert the original prop shape for `renderFn`.
|
||||
renderFn(
|
||||
containerRef.current,
|
||||
props as Readonly<Props & ReactifyProps>,
|
||||
);
|
||||
componentDidMount() {
|
||||
this.execute();
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
this.execute();
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.container = undefined;
|
||||
if (callbacks?.componentWillUnmount) {
|
||||
callbacks.componentWillUnmount.bind(this)();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Cleanup on unmount
|
||||
useEffect(
|
||||
() => () => {
|
||||
if (callbacks?.componentWillUnmount) {
|
||||
// Preserve legacy behavior where `this` was a component instance
|
||||
// exposing `props`. The class version cleared `this.container`
|
||||
// before invoking componentWillUnmount, so mirror that here to
|
||||
// prevent callbacks from touching a DOM node that's being torn
|
||||
// down.
|
||||
callbacks.componentWillUnmount.call({
|
||||
container: undefined,
|
||||
props: propsRef.current,
|
||||
});
|
||||
}
|
||||
},
|
||||
[],
|
||||
);
|
||||
setContainerRef(ref: HTMLDivElement) {
|
||||
this.container = ref;
|
||||
}
|
||||
|
||||
const { id, className } = props;
|
||||
execute() {
|
||||
if (this.container) {
|
||||
renderFn(this.container, this.props);
|
||||
}
|
||||
}
|
||||
|
||||
return <div ref={containerRef} id={id} className={className} />;
|
||||
});
|
||||
render() {
|
||||
const { id, className } = this.props;
|
||||
|
||||
if (renderFn.displayName) {
|
||||
ReactifiedComponent.displayName = renderFn.displayName;
|
||||
return <div ref={this.setContainerRef} id={id} className={className} />;
|
||||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- forwardRef static field types don't line up with renderFn's validator types
|
||||
const result = ReactifiedComponent as any;
|
||||
const ReactifiedClass: ComponentClass<Props & ReactifyProps> =
|
||||
ReactifiedComponent;
|
||||
|
||||
if (renderFn.displayName) {
|
||||
ReactifiedClass.displayName = renderFn.displayName;
|
||||
}
|
||||
// eslint-disable-next-line react/forbid-foreign-prop-types
|
||||
if (renderFn.propTypes) {
|
||||
result.propTypes = {
|
||||
...result.propTypes,
|
||||
ReactifiedClass.propTypes = {
|
||||
...ReactifiedClass.propTypes,
|
||||
...renderFn.propTypes,
|
||||
};
|
||||
}
|
||||
|
||||
if (renderFn.defaultProps) {
|
||||
result.defaultProps = renderFn.defaultProps;
|
||||
ReactifiedClass.defaultProps = renderFn.defaultProps;
|
||||
}
|
||||
|
||||
return result as unknown as ComponentType<Props & ReactifyProps>;
|
||||
return ReactifiedComponent;
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
* under the License.
|
||||
*/
|
||||
import { useState } from 'react';
|
||||
import type { Meta, StoryObj } from '@storybook/react-webpack5';
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
import { AutoComplete } from '.';
|
||||
import type { AutoCompleteProps } from './types';
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import type { Meta, StoryObj } from '@storybook/react-webpack5';
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
import { Breadcrumb } from '.';
|
||||
import type { BreadcrumbProps } from './types';
|
||||
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { action } from 'storybook/actions';
|
||||
import { Meta, StoryFn } from '@storybook/react-webpack5';
|
||||
import { action } from '@storybook/addon-actions';
|
||||
import { Meta, StoryFn } from '@storybook/react';
|
||||
import { CachedLabel } from '.';
|
||||
import type { CacheLabelProps } from './types';
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { useArgs } from 'storybook/preview-api';
|
||||
import { useArgs } from '@storybook/preview-api';
|
||||
import { useState } from 'react';
|
||||
import { Checkbox } from '.';
|
||||
import type { CheckboxProps, CheckboxChangeEvent } from './types';
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { Meta, StoryFn } from '@storybook/react-webpack5';
|
||||
import { Meta, StoryFn } from '@storybook/react';
|
||||
import { Row, Col } from '@superset-ui/core/components';
|
||||
import { EmptyState, imageMap } from '.';
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import type { Meta, StoryObj } from '@storybook/react-webpack5';
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
import { FaveStar } from '.';
|
||||
|
||||
export default {
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { Meta, StoryObj } from '@storybook/react-webpack5';
|
||||
import { Meta, StoryObj } from '@storybook/react';
|
||||
import Slider from '@superset-ui/core/components/Slider/index';
|
||||
import { useState } from 'react';
|
||||
import { Row, Col } from '.';
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { Meta, StoryObj } from '@storybook/react-webpack5';
|
||||
import { Meta, StoryObj } from '@storybook/react';
|
||||
import { IconButton } from '.';
|
||||
|
||||
export default {
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import type { StoryObj } from '@storybook/react-webpack5';
|
||||
import type { StoryObj } from '@storybook/react';
|
||||
import { Input, InputNumber } from '.';
|
||||
import type { InputProps, InputNumberProps, TextAreaProps } from './types';
|
||||
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { action } from 'storybook/actions';
|
||||
import { Meta, StoryFn } from '@storybook/react-webpack5';
|
||||
import { action } from '@storybook/addon-actions';
|
||||
import { Meta, StoryFn } from '@storybook/react';
|
||||
import type { LabelType } from './types';
|
||||
import { Label, DatasetTypeLabel, PublishedLabel } from '.';
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { Meta, StoryObj } from '@storybook/react-webpack5';
|
||||
import { Meta, StoryObj } from '@storybook/react';
|
||||
import { Icons } from '@superset-ui/core/components/Icons';
|
||||
import { Menu } from '../Menu';
|
||||
import type { LayoutProps, SiderProps } from './types';
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import type { Meta, StoryObj } from '@storybook/react-webpack5';
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
import { ListViewCard } from '.';
|
||||
|
||||
export default {
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import type { StoryObj } from '@storybook/react-webpack5';
|
||||
import type { StoryObj } from '@storybook/react';
|
||||
import { css } from '@apache-superset/core/theme';
|
||||
import { Icons } from '@superset-ui/core/components/Icons';
|
||||
import { Space } from '../Space';
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { Meta, StoryFn } from '@storybook/react-webpack5';
|
||||
import { Meta, StoryFn } from '@storybook/react';
|
||||
import { SafeMarkdown } from './SafeMarkdown';
|
||||
|
||||
export default {
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import type { Meta, StoryObj } from '@storybook/react-webpack5';
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
import { Space } from '../Space';
|
||||
import { Skeleton, type SkeletonProps } from '.';
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { useArgs } from 'storybook/preview-api';
|
||||
import { useArgs } from '@storybook/preview-api';
|
||||
import { Switch, type SwitchProps } from '.';
|
||||
|
||||
export default {
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
*/
|
||||
import { useState, DragEvent } from 'react';
|
||||
|
||||
import type { Meta, StoryFn } from '@storybook/react-webpack5';
|
||||
import { action } from 'storybook/actions';
|
||||
import type { Meta, StoryFn } from '@storybook/react';
|
||||
import { action } from '@storybook/addon-actions';
|
||||
import {
|
||||
ColumnsType,
|
||||
ETableAction,
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { StoryFn, Meta } from '@storybook/react-webpack5';
|
||||
import { StoryFn, Meta } from '@storybook/react';
|
||||
import ActionCell from './index';
|
||||
import { exampleMenuOptions, exampleRow } from './fixtures';
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { action } from 'storybook/actions';
|
||||
import { action } from '@storybook/addon-actions';
|
||||
import { ActionMenuItem } from './index';
|
||||
|
||||
export const exampleMenuOptions: ActionMenuItem[] = [
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { StoryFn, Meta } from '@storybook/react-webpack5';
|
||||
import { StoryFn, Meta } from '@storybook/react';
|
||||
import BooleanCell from '.';
|
||||
|
||||
export default {
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { StoryFn, Meta } from '@storybook/react-webpack5';
|
||||
import { action } from 'storybook/actions';
|
||||
import { StoryFn, Meta } from '@storybook/react';
|
||||
import { action } from '@storybook/addon-actions';
|
||||
import { ButtonCell } from './index';
|
||||
|
||||
export default {
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { StoryFn, Meta } from '@storybook/react-webpack5';
|
||||
import { StoryFn, Meta } from '@storybook/react';
|
||||
import NullCell from '.';
|
||||
|
||||
export default {
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { StoryFn, Meta } from '@storybook/react-webpack5';
|
||||
import { StoryFn, Meta } from '@storybook/react';
|
||||
import { CurrencyCode, NumericCell, LocaleCode, Style } from './index';
|
||||
|
||||
export default {
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { StoryFn, Meta } from '@storybook/react-webpack5';
|
||||
import { StoryFn, Meta } from '@storybook/react';
|
||||
import { TimeFormats } from '@superset-ui/core';
|
||||
import TimeCell from '.';
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
* under the License.
|
||||
*/
|
||||
import { useMemo, useState, useCallback } from 'react';
|
||||
import { Meta, StoryFn } from '@storybook/react-webpack5';
|
||||
import { Meta, StoryFn } from '@storybook/react';
|
||||
import {
|
||||
useTable,
|
||||
useSortBy,
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { useArgs } from 'storybook/preview-api';
|
||||
import { useArgs } from '@storybook/preview-api';
|
||||
import TimezoneSelector, { TimezoneSelectorProps } from './index';
|
||||
|
||||
export default {
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { StoryObj } from '@storybook/react-webpack5';
|
||||
import { StoryObj } from '@storybook/react';
|
||||
import { Icons } from '@superset-ui/core/components/Icons';
|
||||
import Tree, { TreeProps, type TreeDataNode } from './index';
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { Meta, StoryObj } from '@storybook/react-webpack5';
|
||||
import { Meta, StoryObj } from '@storybook/react';
|
||||
import { TreeSelect, type TreeSelectProps } from '.';
|
||||
|
||||
export default {
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import type { Meta, StoryObj } from '@storybook/react-webpack5';
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
import { Typography } from '.';
|
||||
|
||||
export default {
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import type { StoryObj } from '@storybook/react-webpack5';
|
||||
import type { StoryObj } from '@storybook/react';
|
||||
import { Icons } from '../Icons';
|
||||
import { Button } from '../Button';
|
||||
import { Upload } from '.';
|
||||
|
||||
@@ -19,9 +19,9 @@
|
||||
|
||||
import '@testing-library/jest-dom';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { PureComponent } from 'react';
|
||||
import { reactify } from '@superset-ui/core';
|
||||
import { render, screen, waitFor } from '@testing-library/react';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { RenderFuncType } from '../../../src/chart/components/reactify';
|
||||
|
||||
describe('reactify(renderFn)', () => {
|
||||
@@ -52,41 +52,48 @@ describe('reactify(renderFn)', () => {
|
||||
componentWillUnmount: willUnmountCb,
|
||||
});
|
||||
|
||||
function TestComponent() {
|
||||
const [content, setContent] = useState('abc');
|
||||
class TestComponent extends PureComponent<{}, { content: string }> {
|
||||
constructor(props = {}) {
|
||||
super(props);
|
||||
this.state = { content: 'abc' };
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const timer = setTimeout(() => {
|
||||
setContent('def');
|
||||
componentDidMount() {
|
||||
setTimeout(() => {
|
||||
this.setState({ content: 'def' });
|
||||
}, 10);
|
||||
return () => clearTimeout(timer);
|
||||
}, []);
|
||||
}
|
||||
|
||||
return <TheChart id="test" content={content} />;
|
||||
render() {
|
||||
const { content } = this.state;
|
||||
|
||||
return <TheChart id="test" content={content} />;
|
||||
}
|
||||
}
|
||||
|
||||
function AnotherTestComponent() {
|
||||
return <TheChartWithWillUnmountHook id="another_test" />;
|
||||
class AnotherTestComponent extends PureComponent<{}, {}> {
|
||||
render() {
|
||||
return <TheChartWithWillUnmountHook id="another_test" />;
|
||||
}
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
(renderFn as jest.Mock).mockClear();
|
||||
willUnmountCb.mockClear();
|
||||
});
|
||||
test('returns a React component class', () =>
|
||||
new Promise(done => {
|
||||
render(<TestComponent />);
|
||||
|
||||
test('returns a React component and re-renders on prop changes', async () => {
|
||||
render(<TestComponent />);
|
||||
|
||||
expect(renderFn).toHaveBeenCalledTimes(1);
|
||||
expect(screen.getByText('abc')).toBeInTheDocument();
|
||||
expect(screen.getByText('abc').parentNode).toHaveAttribute('id', 'test');
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('def')).toBeInTheDocument();
|
||||
});
|
||||
expect(screen.getByText('def').parentNode).toHaveAttribute('id', 'test');
|
||||
expect(renderFn).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
expect(renderFn).toHaveBeenCalledTimes(1);
|
||||
expect(screen.getByText('abc')).toBeInTheDocument();
|
||||
expect(screen.getByText('abc').parentNode).toHaveAttribute('id', 'test');
|
||||
setTimeout(() => {
|
||||
expect(renderFn).toHaveBeenCalledTimes(2);
|
||||
expect(screen.getByText('def')).toBeInTheDocument();
|
||||
expect(screen.getByText('def').parentNode).toHaveAttribute(
|
||||
'id',
|
||||
'test',
|
||||
);
|
||||
done(undefined);
|
||||
}, 20);
|
||||
}));
|
||||
describe('displayName', () => {
|
||||
test('has displayName if renderFn.displayName is defined', () => {
|
||||
expect(TheChart.displayName).toEqual('BoldText');
|
||||
@@ -119,16 +126,20 @@ describe('reactify(renderFn)', () => {
|
||||
expect(AnotherChart.defaultProps).toBeUndefined();
|
||||
});
|
||||
});
|
||||
test('calls renderFn when container is set', () => {
|
||||
test('does not try to render if not mounted', () => {
|
||||
const anotherRenderFn = jest.fn();
|
||||
const AnotherChart = reactify(anotherRenderFn);
|
||||
const { unmount } = render(<AnotherChart id="test" />);
|
||||
expect(anotherRenderFn).toHaveBeenCalled();
|
||||
unmount();
|
||||
});
|
||||
test('calls willUnmount hook when it is provided', () => {
|
||||
const { unmount } = render(<AnotherTestComponent />);
|
||||
unmount();
|
||||
expect(willUnmountCb).toHaveBeenCalledTimes(1);
|
||||
const AnotherChart = reactify(anotherRenderFn); // enables valid new AnotherChart() call
|
||||
// @ts-expect-error
|
||||
new AnotherChart({ id: 'test' }).execute();
|
||||
expect(anotherRenderFn).not.toHaveBeenCalled();
|
||||
});
|
||||
test('calls willUnmount hook when it is provided', () =>
|
||||
new Promise(done => {
|
||||
const { unmount } = render(<AnotherTestComponent />);
|
||||
setTimeout(() => {
|
||||
unmount();
|
||||
expect(willUnmountCb).toHaveBeenCalledTimes(1);
|
||||
done(undefined);
|
||||
}, 20);
|
||||
}));
|
||||
});
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
"dependencies": {
|
||||
"d3": "^3.5.17",
|
||||
"prop-types": "^15.8.1",
|
||||
"react": "^19.2.7"
|
||||
"react": "^19.2.6"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@superset-ui/chart-controls": "*",
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
"@math.gl/web-mercator": "^4.1.0",
|
||||
"mapbox-gl": "^3.24.0",
|
||||
"maplibre-gl": "^5.24.0",
|
||||
"react-map-gl": "^8.1.1",
|
||||
"react-map-gl": "^8.1.0",
|
||||
"supercluster": "^8.0.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
||||
@@ -25,7 +25,6 @@ import { FeatureFlag, isFeatureEnabled } from '@superset-ui/core';
|
||||
import { styled } from '@apache-superset/core/theme';
|
||||
import { Logger } from 'src/logger/LogUtils';
|
||||
import { EmptyState, Tooltip } from '@superset-ui/core/components';
|
||||
import { ErrorBoundary } from 'src/components/ErrorBoundary';
|
||||
import { detectOS } from 'src/utils/common';
|
||||
import * as Actions from 'src/SqlLab/actions/sqlLab';
|
||||
import { Icons } from '@superset-ui/core/components/Icons';
|
||||
@@ -177,16 +176,14 @@ class TabbedSqlEditors extends PureComponent<TabbedSqlEditorsProps> {
|
||||
key: qe.id,
|
||||
label: <SqlEditorTabHeader queryEditor={qe} />,
|
||||
children: (
|
||||
<ErrorBoundary>
|
||||
<SqlEditor
|
||||
queryEditor={qe}
|
||||
defaultQueryLimit={this.props.defaultQueryLimit}
|
||||
maxRow={this.props.maxRow}
|
||||
displayLimit={this.props.displayLimit}
|
||||
saveQueryWarning={this.props.saveQueryWarning}
|
||||
scheduleQueryWarning={this.props.scheduleQueryWarning}
|
||||
/>
|
||||
</ErrorBoundary>
|
||||
<SqlEditor
|
||||
queryEditor={qe}
|
||||
defaultQueryLimit={this.props.defaultQueryLimit}
|
||||
maxRow={this.props.maxRow}
|
||||
displayLimit={this.props.displayLimit}
|
||||
saveQueryWarning={this.props.saveQueryWarning}
|
||||
scheduleQueryWarning={this.props.scheduleQueryWarning}
|
||||
/>
|
||||
),
|
||||
}));
|
||||
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
/**
|
||||
* 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 fetchMock from 'fetch-mock';
|
||||
import { JsonObject, QueryFormData, VizType } from '@superset-ui/core';
|
||||
import { getChartDataRequest } from 'src/components/Chart/chartAction';
|
||||
|
||||
/**
|
||||
* Integration (mocked-network) port of the deprecated Cypress spec
|
||||
* `cypress/e2e/dashboard/_skip.url_params.test.ts` (sc-107448).
|
||||
*
|
||||
* The original test loaded a dashboard with query-string params, intercepted
|
||||
* `/api/v1/chart/data`, and asserted each query in the request body carried
|
||||
* `url_params`. That assertion is request-construction logic — the form_data
|
||||
* → query-context pipeline — which is exercised here without a backend.
|
||||
*
|
||||
* Intentional narrowing: the URL-string → `form_data.url_params` hop (handled
|
||||
* in `src/dashboard/actions/hydrate.ts` via `extractUrlParams`) is not covered
|
||||
* here. This file verifies the chart-data side of the contract only; the
|
||||
* dashboard hydration side is covered by its own unit tests.
|
||||
*/
|
||||
const CHART_DATA_GLOB = 'glob:*/api/v1/chart/data*';
|
||||
const CHART_DATA_ROUTE = 'urlParamsForwarding-chartData';
|
||||
const URL_PARAMS = { param1: '123', param2: 'abc' };
|
||||
|
||||
type ChartDataRequestBody = {
|
||||
queries: JsonObject[];
|
||||
form_data: JsonObject;
|
||||
};
|
||||
|
||||
const buildFormData = (
|
||||
overrides: Partial<QueryFormData> = {},
|
||||
): QueryFormData => ({
|
||||
datasource: '1__table',
|
||||
granularity_sqla: 'ds',
|
||||
viz_type: VizType.Table,
|
||||
url_params: URL_PARAMS,
|
||||
...overrides,
|
||||
});
|
||||
|
||||
const lastChartDataBody = (): ChartDataRequestBody => {
|
||||
const calls = fetchMock.callHistory.calls(CHART_DATA_ROUTE);
|
||||
expect(calls.length).toBeGreaterThan(0);
|
||||
return JSON.parse(
|
||||
calls[calls.length - 1].options.body as string,
|
||||
) as ChartDataRequestBody;
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
fetchMock.post(
|
||||
CHART_DATA_GLOB,
|
||||
{ result: [{ data: [] }] },
|
||||
{
|
||||
name: CHART_DATA_ROUTE,
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
// Remove only this file's route so global routes registered in
|
||||
// setupSupersetClient (e.g. CSRF) survive into the next test.
|
||||
afterEach(() => {
|
||||
fetchMock.clearHistory();
|
||||
fetchMock.removeRoutes({ names: [CHART_DATA_ROUTE] });
|
||||
});
|
||||
|
||||
test('forwards url_params from form_data onto each query in the chart-data request body', async () => {
|
||||
await getChartDataRequest({ formData: buildFormData() });
|
||||
|
||||
const body = lastChartDataBody();
|
||||
expect(Array.isArray(body.queries)).toBe(true);
|
||||
expect(body.queries.length).toBeGreaterThan(0);
|
||||
body.queries.forEach(query => {
|
||||
expect(query.url_params).toEqual(URL_PARAMS);
|
||||
});
|
||||
});
|
||||
|
||||
test('preserves url_params on form_data echoed back in the chart-data request body', async () => {
|
||||
await getChartDataRequest({ formData: buildFormData() });
|
||||
|
||||
const body = lastChartDataBody();
|
||||
expect(body.form_data.url_params).toEqual(URL_PARAMS);
|
||||
});
|
||||
|
||||
// buildQueryObject defaults missing url_params to `{}` (see
|
||||
// packages/superset-ui-core/src/query/buildQueryObject.ts), so the chart-data
|
||||
// request body carries an empty object — not `undefined`. This test documents
|
||||
// that contract; a future change that flips the default should update both.
|
||||
test('emits an empty url_params object on each query when form_data has none', async () => {
|
||||
await getChartDataRequest({
|
||||
formData: buildFormData({ url_params: undefined }),
|
||||
});
|
||||
|
||||
const body = lastChartDataBody();
|
||||
expect(body.queries.length).toBeGreaterThan(0);
|
||||
body.queries.forEach(query => {
|
||||
expect(query.url_params).toEqual({});
|
||||
});
|
||||
});
|
||||
@@ -25,8 +25,6 @@ import {
|
||||
isThemeConfigDark,
|
||||
} from '@apache-superset/core/theme';
|
||||
import getBootstrapData from 'src/utils/getBootstrapData';
|
||||
import { ThemeContext } from 'src/theme/ThemeProvider';
|
||||
import type { ThemeContextType } from '@apache-superset/core/theme';
|
||||
import CrudThemeProvider from './CrudThemeProvider';
|
||||
|
||||
jest.mock('@apache-superset/core/theme', () => ({
|
||||
@@ -309,59 +307,6 @@ test('ignores non-array fontUrls in theme config without throwing', () => {
|
||||
expect(fontStyle).toBeNull();
|
||||
});
|
||||
|
||||
test('skips the dashboard theme when an SDK theme config override is active', () => {
|
||||
const themeConfig = {
|
||||
token: {
|
||||
colorPrimary: '#ff0000',
|
||||
fontUrls: ['https://fonts.example.com/dashboard.css'],
|
||||
},
|
||||
};
|
||||
render(
|
||||
<ThemeContext.Provider
|
||||
value={{ hasThemeConfigOverride: true } as unknown as ThemeContextType}
|
||||
>
|
||||
<CrudThemeProvider
|
||||
theme={{
|
||||
id: 1,
|
||||
theme_name: 'Custom Theme',
|
||||
json_data: JSON.stringify(themeConfig),
|
||||
}}
|
||||
>
|
||||
<div>Dashboard Content</div>
|
||||
</CrudThemeProvider>
|
||||
</ThemeContext.Provider>,
|
||||
);
|
||||
|
||||
// The SDK override wins: the dashboard theme provider must not wrap children.
|
||||
expect(screen.getByText('Dashboard Content')).toBeInTheDocument();
|
||||
expect(
|
||||
screen.queryByTestId('dashboard-theme-provider'),
|
||||
).not.toBeInTheDocument();
|
||||
// The override fully owns theming, so dashboard fonts must not be injected.
|
||||
expect(document.querySelector('style[data-superset-fonts]')).toBeNull();
|
||||
});
|
||||
|
||||
test('applies the dashboard theme when no SDK theme config override is active', () => {
|
||||
const themeConfig = { token: { colorPrimary: '#ff0000' } };
|
||||
render(
|
||||
<ThemeContext.Provider
|
||||
value={{ hasThemeConfigOverride: false } as unknown as ThemeContextType}
|
||||
>
|
||||
<CrudThemeProvider
|
||||
theme={{
|
||||
id: 1,
|
||||
theme_name: 'Custom Theme',
|
||||
json_data: JSON.stringify(themeConfig),
|
||||
}}
|
||||
>
|
||||
<div>Dashboard Content</div>
|
||||
</CrudThemeProvider>
|
||||
</ThemeContext.Provider>,
|
||||
);
|
||||
|
||||
expect(screen.getByTestId('dashboard-theme-provider')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('does not inject font style element when no fontUrls in config', () => {
|
||||
const themeConfig = { token: { colorPrimary: '#ff0000' } };
|
||||
render(
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { ReactNode, useContext, useEffect, useMemo } from 'react';
|
||||
import { ReactNode, useEffect, useMemo } from 'react';
|
||||
import { logging } from '@apache-superset/core/utils';
|
||||
import {
|
||||
Theme,
|
||||
@@ -24,7 +24,6 @@ import {
|
||||
isThemeConfigDark,
|
||||
} from '@apache-superset/core/theme';
|
||||
import getBootstrapData from 'src/utils/getBootstrapData';
|
||||
import { ThemeContext } from 'src/theme/ThemeProvider';
|
||||
import type { Dashboard } from 'src/types/Dashboard';
|
||||
|
||||
interface CrudThemeProviderProps {
|
||||
@@ -42,18 +41,8 @@ export default function CrudThemeProvider({
|
||||
children,
|
||||
theme,
|
||||
}: CrudThemeProviderProps) {
|
||||
// An explicit theme config override (e.g. supplied via the Embedded SDK)
|
||||
// applies on the global theme controller and must win over the
|
||||
// dashboard-level theme. When such an override is active, skip the
|
||||
// dashboard theme so the override is not shadowed by this nested provider.
|
||||
const themeContext = useContext(ThemeContext);
|
||||
const hasThemeConfigOverride = themeContext?.hasThemeConfigOverride ?? false;
|
||||
|
||||
const { dashboardTheme, fontUrls } = useMemo(() => {
|
||||
// When an SDK override is active it fully owns theming, so skip parsing the
|
||||
// dashboard theme entirely. This also prevents the font-injection effect
|
||||
// below from loading dashboard fonts the override does not use.
|
||||
if (hasThemeConfigOverride || !theme?.json_data) {
|
||||
if (!theme?.json_data) {
|
||||
return { dashboardTheme: null, fontUrls: undefined };
|
||||
}
|
||||
try {
|
||||
@@ -75,7 +64,7 @@ export default function CrudThemeProvider({
|
||||
logging.warn('Failed to load dashboard theme:', error);
|
||||
return { dashboardTheme: null, fontUrls: undefined };
|
||||
}
|
||||
}, [theme?.json_data, hasThemeConfigOverride]);
|
||||
}, [theme?.json_data]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!dashboardTheme || !fontUrls?.length) return undefined;
|
||||
@@ -94,7 +83,7 @@ export default function CrudThemeProvider({
|
||||
};
|
||||
}, [dashboardTheme, fontUrls]);
|
||||
|
||||
if (!dashboardTheme || hasThemeConfigOverride) {
|
||||
if (!dashboardTheme) {
|
||||
return <>{children}</>;
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user