mirror of
https://github.com/apache/superset.git
synced 2026-07-25 08:02:28 +00:00
Compare commits
76 Commits
fix/export
...
hughhhh/ha
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
670a95215c | ||
|
|
719649fe1a | ||
|
|
de7dfc1585 | ||
|
|
a1212ec089 | ||
|
|
2bbada837b | ||
|
|
de29e984ff | ||
|
|
c7a6c6fc9c | ||
|
|
00cb3037e7 | ||
|
|
6c58afe6ac | ||
|
|
f751716867 | ||
|
|
bafe5ad9ba | ||
|
|
a1d4cda0cb | ||
|
|
2d3cbc162e | ||
|
|
e4005f02c6 | ||
|
|
8296fe8ce4 | ||
|
|
4b659da5c4 | ||
|
|
b4529c2654 | ||
|
|
034823e99b | ||
|
|
abd6dc8e44 | ||
|
|
b3757870cc | ||
|
|
158e321992 | ||
|
|
590357731b | ||
|
|
64053271e8 | ||
|
|
940e2c34a2 | ||
|
|
d65a816b39 | ||
|
|
48faca5b8d | ||
|
|
9178faf9b1 | ||
|
|
15bc73facf | ||
|
|
e0d0eb6d02 | ||
|
|
1f81b700c1 | ||
|
|
3a3f087869 | ||
|
|
f03a66db9c | ||
|
|
515dfef955 | ||
|
|
5a17ae1224 | ||
|
|
c1e660fac8 | ||
|
|
19ca088de6 | ||
|
|
57dc3c0208 | ||
|
|
ceffbe80f9 | ||
|
|
eed41b6435 | ||
|
|
277c814c5a | ||
|
|
7e63b29741 | ||
|
|
b5ae7cbd0d | ||
|
|
e044d7783a | ||
|
|
9e8b9ac8cf | ||
|
|
19588826c8 | ||
|
|
8b415502cf | ||
|
|
09148d0af6 | ||
|
|
3e40bebba8 | ||
|
|
36dbff091f | ||
|
|
9e9b7c4bbd | ||
|
|
42a2aede78 | ||
|
|
c4d50472a9 | ||
|
|
cd045886d0 | ||
|
|
751f5eb663 | ||
|
|
4e098b6f38 | ||
|
|
5ee4a81906 | ||
|
|
caf017bd0b | ||
|
|
a83171bce6 | ||
|
|
6c13ab6657 | ||
|
|
b9ede492b7 | ||
|
|
fb29db6119 | ||
|
|
0a66e4ea2d | ||
|
|
3e0f9e60c0 | ||
|
|
ff1cf5f24e | ||
|
|
023b60c8f0 | ||
|
|
2ada286ee9 | ||
|
|
42e5640f60 | ||
|
|
74703906df | ||
|
|
3c23394675 | ||
|
|
b6ce28ff72 | ||
|
|
79eff6b6f1 | ||
|
|
a58012fc0f | ||
|
|
dab5f30842 | ||
|
|
8299e7f87c | ||
|
|
f6acf68dfa | ||
|
|
cce77b42f6 |
3
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
3
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
@@ -50,9 +50,8 @@ body:
|
||||
attributes:
|
||||
label: Python version
|
||||
options:
|
||||
- "3.9"
|
||||
- "3.10"
|
||||
- "3.11"
|
||||
- "3.12"
|
||||
- Not applicable
|
||||
- I don't know
|
||||
validations:
|
||||
|
||||
21
.github/dependabot.yml
vendored
21
.github/dependabot.yml
vendored
@@ -65,6 +65,11 @@ updates:
|
||||
lumagl:
|
||||
patterns:
|
||||
- "@luma.gl/*"
|
||||
storybook:
|
||||
patterns:
|
||||
- "@storybook/*"
|
||||
- "storybook"
|
||||
- "eslint-plugin-storybook"
|
||||
open-pull-requests-limit: 30
|
||||
versioning-strategy: increase
|
||||
cooldown:
|
||||
@@ -99,6 +104,22 @@ updates:
|
||||
directory: "/docs/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
groups:
|
||||
storybook:
|
||||
patterns:
|
||||
- "@storybook/*"
|
||||
- "storybook"
|
||||
docusaurus:
|
||||
patterns:
|
||||
- "@docusaurus/*"
|
||||
docusaurus-openapi:
|
||||
patterns:
|
||||
- "docusaurus-plugin-openapi-docs"
|
||||
- "docusaurus-theme-openapi-docs"
|
||||
typescript-eslint:
|
||||
patterns:
|
||||
- "@typescript-eslint/*"
|
||||
- "typescript-eslint"
|
||||
open-pull-requests-limit: 10
|
||||
versioning-strategy: increase
|
||||
cooldown:
|
||||
|
||||
4
.github/workflows/bump-python-package.yml
vendored
4
.github/workflows/bump-python-package.yml
vendored
@@ -23,7 +23,7 @@ on:
|
||||
|
||||
jobs:
|
||||
bump-python-package:
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
permissions:
|
||||
actions: write
|
||||
contents: write
|
||||
@@ -42,7 +42,7 @@ jobs:
|
||||
- name: Set up Python ${{ inputs.python-version }}
|
||||
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
|
||||
with:
|
||||
python-version: "3.10"
|
||||
python-version: "3.11"
|
||||
|
||||
- name: Install uv
|
||||
run: pip install uv
|
||||
|
||||
2
.github/workflows/check-python-deps.yml
vendored
2
.github/workflows/check-python-deps.yml
vendored
@@ -19,7 +19,7 @@ concurrency:
|
||||
|
||||
jobs:
|
||||
check-python-deps:
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-26.04
|
||||
steps:
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
|
||||
@@ -19,7 +19,7 @@ concurrency:
|
||||
jobs:
|
||||
check_db_migration_conflict:
|
||||
name: Check DB migration conflict
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
|
||||
4
.github/workflows/codeql-analysis.yml
vendored
4
.github/workflows/codeql-analysis.yml
vendored
@@ -16,7 +16,7 @@ concurrency:
|
||||
|
||||
jobs:
|
||||
changes:
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
timeout-minutes: 10
|
||||
permissions:
|
||||
contents: read
|
||||
@@ -42,7 +42,7 @@ jobs:
|
||||
# analysis runners don't spin up. push/schedule runs always proceed:
|
||||
# the change-detector returns "all changed" for non-PR events.
|
||||
if: needs.changes.outputs.python == 'true' || needs.changes.outputs.frontend == 'true'
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
timeout-minutes: 30
|
||||
permissions:
|
||||
actions: read
|
||||
|
||||
4
.github/workflows/dependency-review.yml
vendored
4
.github/workflows/dependency-review.yml
vendored
@@ -24,7 +24,7 @@ permissions:
|
||||
jobs:
|
||||
dependency-review:
|
||||
if: github.event_name == 'pull_request'
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
steps:
|
||||
- name: "Checkout Repository"
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
@@ -48,7 +48,7 @@ jobs:
|
||||
python-dependency-liccheck:
|
||||
# NOTE: Configuration for liccheck lives in our pyproject.yml.
|
||||
# You cannot use a liccheck.ini file in this workflow.
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-26.04
|
||||
steps:
|
||||
- name: "Checkout Repository"
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
|
||||
19
.github/workflows/docker.yml
vendored
19
.github/workflows/docker.yml
vendored
@@ -19,7 +19,7 @@ concurrency:
|
||||
|
||||
jobs:
|
||||
changes:
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
timeout-minutes: 10
|
||||
permissions:
|
||||
contents: read
|
||||
@@ -40,14 +40,14 @@ jobs:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
setup_matrix:
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
timeout-minutes: 5
|
||||
outputs:
|
||||
matrix_config: ${{ steps.set_matrix.outputs.matrix_config }}
|
||||
steps:
|
||||
- id: set_matrix
|
||||
run: |
|
||||
MATRIX_CONFIG=$(if [ "${{ github.event_name }}" == "pull_request" ]; then echo '["dev", "lean"]'; else echo '["dev", "lean", "py310", "websocket", "dockerize", "py311", "py312"]'; fi)
|
||||
MATRIX_CONFIG=$(if [ "${{ github.event_name }}" == "pull_request" ]; then echo '["dev", "lean"]'; else echo '["dev", "lean", "websocket", "dockerize", "py311", "py312"]'; fi)
|
||||
echo "matrix_config=${MATRIX_CONFIG}" >> $GITHUB_OUTPUT
|
||||
echo $GITHUB_OUTPUT
|
||||
|
||||
@@ -58,7 +58,7 @@ jobs:
|
||||
needs.changes.outputs.python == 'true' ||
|
||||
needs.changes.outputs.frontend == 'true' ||
|
||||
needs.changes.outputs.docker == 'true'
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
timeout-minutes: 60
|
||||
strategy:
|
||||
matrix:
|
||||
@@ -123,13 +123,20 @@ jobs:
|
||||
# pull timeouts, 504/401 on push, ECONNRESET) that otherwise fail
|
||||
# the whole job. buildx reuses the buildkit layer cache from the
|
||||
# failed attempt, so a retry mostly re-does just the failed push.
|
||||
#
|
||||
# supersetbot's "dev"/"lean" presets pin their own --build-arg
|
||||
# PY_VER, which lands ahead of --extra-flags on the assembled
|
||||
# buildx command line; docker/buildx keeps the last value for a
|
||||
# repeated --build-arg key, so appending PY_VER here overrides
|
||||
# supersetbot's pin and keeps the build on the Dockerfile's own
|
||||
# supported Python version.
|
||||
for attempt in 1 2 3; do
|
||||
if supersetbot docker \
|
||||
$PUSH_OR_LOAD \
|
||||
--preset "$BUILD_PRESET" \
|
||||
--context "$EVENT" \
|
||||
--context-ref "$RELEASE" $FORCE_LATEST \
|
||||
--extra-flags "--build-arg INCLUDE_CHROMIUM=false --tag $IMAGE_TAG" \
|
||||
--extra-flags "--build-arg PY_VER=3.11.14-slim-trixie --build-arg INCLUDE_CHROMIUM=false --tag $IMAGE_TAG" \
|
||||
$PLATFORM_ARG; then
|
||||
break
|
||||
fi
|
||||
@@ -173,7 +180,7 @@ jobs:
|
||||
# goal is to check that building the latest image works, not required for all PR pushes
|
||||
needs: changes
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/master' && needs.changes.outputs.docker == 'true'
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
|
||||
4
.github/workflows/embedded-sdk-release.yml
vendored
4
.github/workflows/embedded-sdk-release.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
||||
# gate on. Restrict to the canonical repo: forks cannot mint a valid OIDC
|
||||
# token for this package and must not publish.
|
||||
if: github.repository == 'apache/superset'
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write # required for npm trusted publishing (OIDC)
|
||||
@@ -31,7 +31,7 @@ jobs:
|
||||
# token, which makes npm attempt token auth and skip the OIDC
|
||||
# trusted-publishing exchange. With no .npmrc auth line, npm authenticates
|
||||
# via OIDC against the default registry (registry.npmjs.org).
|
||||
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
||||
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||
with:
|
||||
node-version-file: "./superset-embedded-sdk/.nvmrc"
|
||||
- run: npm ci
|
||||
|
||||
4
.github/workflows/embedded-sdk-test.yml
vendored
4
.github/workflows/embedded-sdk-test.yml
vendored
@@ -16,7 +16,7 @@ concurrency:
|
||||
|
||||
jobs:
|
||||
embedded-sdk-test:
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
defaults:
|
||||
run:
|
||||
working-directory: superset-embedded-sdk
|
||||
@@ -24,7 +24,7 @@ jobs:
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
||||
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||
with:
|
||||
node-version-file: "./superset-embedded-sdk/.nvmrc"
|
||||
registry-url: "https://registry.npmjs.org"
|
||||
|
||||
6
.github/workflows/generate-FOSSA-report.yml
vendored
6
.github/workflows/generate-FOSSA-report.yml
vendored
@@ -11,7 +11,7 @@ permissions:
|
||||
|
||||
jobs:
|
||||
config:
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
outputs:
|
||||
has-secrets: ${{ steps.check.outputs.has-secrets }}
|
||||
steps:
|
||||
@@ -29,7 +29,7 @@ jobs:
|
||||
needs: config
|
||||
if: needs.config.outputs.has-secrets
|
||||
name: Generate Report
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
steps:
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
@@ -37,7 +37,7 @@ jobs:
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@0f481fcb613427c0f801b606911222b5b6f3083a # v5.5.0
|
||||
uses: actions/setup-java@03ad4de0992f5dab5e18fcb136590ce7c4a0ac95 # v5.6.0
|
||||
with:
|
||||
distribution: "temurin"
|
||||
java-version: "11"
|
||||
|
||||
@@ -19,7 +19,7 @@ concurrency:
|
||||
|
||||
jobs:
|
||||
validate-all-ghas:
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
permissions:
|
||||
contents: read
|
||||
# Required for the zizmor action to upload its SARIF results to
|
||||
@@ -32,7 +32,7 @@ jobs:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
||||
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||
with:
|
||||
node-version: "20"
|
||||
|
||||
|
||||
115
.github/workflows/hold-label-ci-gate.yml
vendored
Normal file
115
.github/workflows/hold-label-ci-gate.yml
vendored
Normal file
@@ -0,0 +1,115 @@
|
||||
# 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.
|
||||
name: Hold Label CI Gate
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [labeled, unlabeled]
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
cancel-on-hold:
|
||||
name: Cancel CI runs when hold label applied
|
||||
if: github.event.action == 'labeled' && startsWith(github.event.label.name, 'hold')
|
||||
runs-on: ubuntu-26.04
|
||||
permissions:
|
||||
actions: write
|
||||
pull-requests: read
|
||||
steps:
|
||||
- name: Cancel in-progress workflow runs
|
||||
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
script: |
|
||||
const { owner, repo } = context.repo;
|
||||
const sha = context.payload.pull_request.head.sha;
|
||||
|
||||
const { data: { workflow_runs: runs } } =
|
||||
await github.rest.actions.listWorkflowRunsForRepo({
|
||||
owner,
|
||||
repo,
|
||||
head_sha: sha,
|
||||
per_page: 100,
|
||||
});
|
||||
|
||||
const active = runs.filter(r =>
|
||||
['in_progress', 'queued', 'waiting', 'requested', 'pending'].includes(r.status)
|
||||
);
|
||||
|
||||
core.info(`Found ${active.length} active run(s) to cancel for SHA ${sha}`);
|
||||
|
||||
for (const run of active) {
|
||||
try {
|
||||
await github.rest.actions.cancelWorkflowRun({
|
||||
owner,
|
||||
repo,
|
||||
run_id: run.id,
|
||||
});
|
||||
core.info(`Cancelled run ${run.id} (${run.name})`);
|
||||
} catch (err) {
|
||||
core.warning(`Could not cancel run ${run.id}: ${err.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
rerun-on-unhold:
|
||||
name: Re-run CI when hold label removed
|
||||
if: github.event.action == 'unlabeled' && startsWith(github.event.label.name, 'hold')
|
||||
runs-on: ubuntu-24.04
|
||||
permissions:
|
||||
actions: write
|
||||
pull-requests: read
|
||||
steps:
|
||||
- name: Re-trigger cancelled workflow runs
|
||||
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
script: |
|
||||
const { owner, repo } = context.repo;
|
||||
const sha = context.payload.pull_request.head.sha;
|
||||
|
||||
// Check that no other hold* labels remain on the PR
|
||||
const labels = context.payload.pull_request.labels.map(l => l.name);
|
||||
const stillHeld = labels.some(l => l.startsWith('hold'));
|
||||
if (stillHeld) {
|
||||
core.info('PR still has a hold label — skipping re-run.');
|
||||
return;
|
||||
}
|
||||
|
||||
const { data: { workflow_runs: runs } } =
|
||||
await github.rest.actions.listWorkflowRunsForRepo({
|
||||
owner,
|
||||
repo,
|
||||
head_sha: sha,
|
||||
per_page: 100,
|
||||
});
|
||||
|
||||
const cancelled = runs.filter(r => r.conclusion === 'cancelled');
|
||||
core.info(`Found ${cancelled.length} cancelled run(s) to re-trigger for SHA ${sha}`);
|
||||
|
||||
for (const run of cancelled) {
|
||||
try {
|
||||
await github.rest.actions.reRunWorkflow({
|
||||
owner,
|
||||
repo,
|
||||
run_id: run.id,
|
||||
});
|
||||
core.info(`Re-triggered run ${run.id} (${run.name})`);
|
||||
} catch (err) {
|
||||
core.warning(`Could not re-run ${run.id}: ${err.message}`);
|
||||
}
|
||||
}
|
||||
2
.github/workflows/issue_creation.yml
vendored
2
.github/workflows/issue_creation.yml
vendored
@@ -9,7 +9,7 @@ on:
|
||||
|
||||
jobs:
|
||||
superbot-orglabel:
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
|
||||
2
.github/workflows/labeler.yml
vendored
2
.github/workflows/labeler.yml
vendored
@@ -12,7 +12,7 @@ jobs:
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
steps:
|
||||
- uses: actions/labeler@b8dd2d9be0f68b860e7dae5dae7d772984eacd6d # v6.2.0
|
||||
with:
|
||||
|
||||
2
.github/workflows/latest-release-tag.yml
vendored
2
.github/workflows/latest-release-tag.yml
vendored
@@ -6,7 +6,7 @@ on:
|
||||
jobs:
|
||||
latest-release:
|
||||
name: Add/update tag to new release
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
|
||||
4
.github/workflows/license-check.yml
vendored
4
.github/workflows/license-check.yml
vendored
@@ -15,7 +15,7 @@ concurrency:
|
||||
jobs:
|
||||
license_check:
|
||||
name: License Check
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
steps:
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
@@ -23,7 +23,7 @@ jobs:
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@0f481fcb613427c0f801b606911222b5b6f3083a # v5.5.0
|
||||
uses: actions/setup-java@03ad4de0992f5dab5e18fcb136590ce7c4a0ac95 # v5.6.0
|
||||
with:
|
||||
distribution: "temurin"
|
||||
java-version: "11"
|
||||
|
||||
2
.github/workflows/no-hold-label.yml
vendored
2
.github/workflows/no-hold-label.yml
vendored
@@ -17,7 +17,7 @@ concurrency:
|
||||
|
||||
jobs:
|
||||
check-hold-label:
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
steps:
|
||||
- name: Check for 'hold' label
|
||||
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
|
||||
|
||||
2
.github/workflows/pr-lint.yml
vendored
2
.github/workflows/pr-lint.yml
vendored
@@ -21,7 +21,7 @@ concurrency:
|
||||
|
||||
jobs:
|
||||
lint-check:
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
|
||||
4
.github/workflows/pre-commit.yml
vendored
4
.github/workflows/pre-commit.yml
vendored
@@ -23,7 +23,7 @@ concurrency:
|
||||
|
||||
jobs:
|
||||
pre-commit:
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
timeout-minutes: 20
|
||||
strategy:
|
||||
matrix:
|
||||
@@ -53,7 +53,7 @@ jobs:
|
||||
run: go install github.com/norwoodj/helm-docs/cmd/helm-docs@v1.14.2
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
||||
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||
with:
|
||||
node-version-file: "superset-frontend/.nvmrc"
|
||||
cache: "npm"
|
||||
|
||||
6
.github/workflows/release.yml
vendored
6
.github/workflows/release.yml
vendored
@@ -11,7 +11,7 @@ permissions:
|
||||
|
||||
jobs:
|
||||
config:
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
outputs:
|
||||
has-secrets: ${{ steps.check.outputs.has-secrets }}
|
||||
steps:
|
||||
@@ -29,7 +29,7 @@ jobs:
|
||||
needs: config
|
||||
if: needs.config.outputs.has-secrets
|
||||
name: Bump version and publish package(s)
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
@@ -50,7 +50,7 @@ jobs:
|
||||
|
||||
- name: Install Node.js
|
||||
if: env.HAS_TAGS
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
||||
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||
with:
|
||||
node-version-file: "./superset-frontend/.nvmrc"
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ concurrency:
|
||||
|
||||
jobs:
|
||||
config:
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
outputs:
|
||||
has-secrets: ${{ steps.check.outputs.has-secrets }}
|
||||
latest-release: ${{ steps.latest.outputs.tag }}
|
||||
@@ -93,12 +93,12 @@ jobs:
|
||||
needs: config
|
||||
if: needs.config.outputs.has-secrets == '1'
|
||||
name: docker-rebuild
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
strategy:
|
||||
# Mirror the same matrix the release publisher uses so every variant
|
||||
# operators consume from Docker Hub gets the refreshed base.
|
||||
matrix:
|
||||
build_preset: ["dev", "lean", "py310", "websocket", "dockerize", "py311", "py312"]
|
||||
build_preset: ["dev", "lean", "websocket", "dockerize", "py311", "py312"]
|
||||
fail-fast: false
|
||||
steps:
|
||||
- name: "Checkout release tag: ${{ needs.config.outputs.latest-release }}"
|
||||
@@ -117,7 +117,7 @@ jobs:
|
||||
build: "true"
|
||||
|
||||
- name: Use Node.js 20
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
||||
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||
with:
|
||||
node-version: 20
|
||||
|
||||
@@ -155,7 +155,7 @@ jobs:
|
||||
notify-on-failure:
|
||||
needs: [config, docker-rebuild]
|
||||
if: failure() && needs.config.outputs.has-secrets == '1'
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
permissions:
|
||||
contents: read
|
||||
issues: write
|
||||
|
||||
2
.github/workflows/superset-app-cli.yml
vendored
2
.github/workflows/superset-app-cli.yml
vendored
@@ -19,7 +19,7 @@ concurrency:
|
||||
|
||||
jobs:
|
||||
test-load-examples:
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
env:
|
||||
PYTHONPATH: ${{ github.workspace }}
|
||||
SUPERSET_CONFIG: tests.integration_tests.superset_test_config
|
||||
|
||||
8
.github/workflows/superset-docs-deploy.yml
vendored
8
.github/workflows/superset-docs-deploy.yml
vendored
@@ -33,7 +33,7 @@ permissions:
|
||||
|
||||
jobs:
|
||||
config:
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
outputs:
|
||||
has-secrets: ${{ steps.check.outputs.has-secrets }}
|
||||
steps:
|
||||
@@ -57,7 +57,7 @@ jobs:
|
||||
(github.event_name != 'workflow_run' ||
|
||||
github.event.workflow_run.head_repository.full_name == github.repository)
|
||||
name: Build & Deploy
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
steps:
|
||||
- name: "Checkout ${{ github.event.workflow_run.head_sha || github.sha }}"
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
@@ -66,12 +66,12 @@ jobs:
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
||||
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||
with:
|
||||
node-version-file: "./docs/.nvmrc"
|
||||
- name: Setup Python
|
||||
uses: ./.github/actions/setup-backend/
|
||||
- uses: actions/setup-java@0f481fcb613427c0f801b606911222b5b6f3083a # v5.5.0
|
||||
- uses: actions/setup-java@03ad4de0992f5dab5e18fcb136590ce7c4a0ac95 # v5.6.0
|
||||
with:
|
||||
distribution: "zulu"
|
||||
java-version: "21"
|
||||
|
||||
8
.github/workflows/superset-docs-verify.yml
vendored
8
.github/workflows/superset-docs-verify.yml
vendored
@@ -67,7 +67,7 @@ jobs:
|
||||
# Build docs when PR changes docs/** (uses committed databases.json)
|
||||
if: github.event_name == 'pull_request'
|
||||
name: Build (PR trigger)
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
defaults:
|
||||
run:
|
||||
working-directory: docs
|
||||
@@ -78,7 +78,7 @@ jobs:
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
||||
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||
with:
|
||||
node-version-file: "./docs/.nvmrc"
|
||||
- name: yarn install
|
||||
@@ -106,7 +106,7 @@ jobs:
|
||||
github.event.workflow_run.conclusion == 'success' &&
|
||||
github.event.workflow_run.head_repository.full_name == github.repository
|
||||
name: Build (after integration tests)
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
defaults:
|
||||
run:
|
||||
working-directory: docs
|
||||
@@ -118,7 +118,7 @@ jobs:
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
||||
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||
with:
|
||||
node-version-file: "./docs/.nvmrc"
|
||||
- name: yarn install
|
||||
|
||||
15
.github/workflows/superset-e2e.yml
vendored
15
.github/workflows/superset-e2e.yml
vendored
@@ -28,7 +28,7 @@ concurrency:
|
||||
|
||||
jobs:
|
||||
changes:
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
timeout-minutes: 10
|
||||
permissions:
|
||||
contents: read
|
||||
@@ -50,8 +50,7 @@ jobs:
|
||||
cypress-matrix:
|
||||
needs: changes
|
||||
if: (needs.changes.outputs.python == 'true' || needs.changes.outputs.frontend == 'true') && github.event.pull_request.draft == false
|
||||
# Somehow one test flakes on 24.04 for unknown reasons, this is the only GHA left on 22.04
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-26.04
|
||||
timeout-minutes: 30
|
||||
permissions:
|
||||
contents: read
|
||||
@@ -128,7 +127,7 @@ jobs:
|
||||
with:
|
||||
run: testdata
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
||||
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||
with:
|
||||
node-version-file: "./superset-frontend/.nvmrc"
|
||||
cache: "npm"
|
||||
@@ -173,7 +172,7 @@ jobs:
|
||||
playwright-tests:
|
||||
needs: changes
|
||||
if: needs.changes.outputs.python == 'true' || needs.changes.outputs.frontend == 'true'
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-26.04
|
||||
timeout-minutes: 30
|
||||
permissions:
|
||||
contents: read
|
||||
@@ -238,7 +237,7 @@ jobs:
|
||||
with:
|
||||
run: playwright_testdata
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
||||
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||
with:
|
||||
node-version-file: "./superset-frontend/.nvmrc"
|
||||
cache: "npm"
|
||||
@@ -301,7 +300,7 @@ jobs:
|
||||
cypress-matrix-required:
|
||||
needs: [changes, cypress-matrix]
|
||||
if: always()
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
timeout-minutes: 5
|
||||
permissions: {}
|
||||
steps:
|
||||
@@ -323,7 +322,7 @@ jobs:
|
||||
playwright-tests-required:
|
||||
needs: [changes, playwright-tests]
|
||||
if: always()
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
timeout-minutes: 5
|
||||
permissions: {}
|
||||
steps:
|
||||
|
||||
@@ -19,7 +19,7 @@ concurrency:
|
||||
|
||||
jobs:
|
||||
test-superset-extensions-cli-package:
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
timeout-minutes: 30
|
||||
strategy:
|
||||
matrix:
|
||||
|
||||
14
.github/workflows/superset-frontend.yml
vendored
14
.github/workflows/superset-frontend.yml
vendored
@@ -21,7 +21,7 @@ permissions:
|
||||
|
||||
jobs:
|
||||
frontend-build:
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
timeout-minutes: 30
|
||||
outputs:
|
||||
should-run: ${{ steps.check.outputs.frontend }}
|
||||
@@ -51,7 +51,7 @@ jobs:
|
||||
git show -s --format=raw HEAD
|
||||
docker buildx build \
|
||||
-t $TAG \
|
||||
--cache-from=type=registry,ref=apache/superset-cache:3.10-slim-trixie \
|
||||
--cache-from=type=registry,ref=apache/superset-cache:3.11-slim-trixie \
|
||||
--target superset-node-ci \
|
||||
.
|
||||
|
||||
@@ -74,7 +74,7 @@ jobs:
|
||||
matrix:
|
||||
shard: [1, 2, 3, 4, 5, 6, 7, 8]
|
||||
fail-fast: false
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
- name: Download Docker Image Artifact
|
||||
@@ -104,7 +104,7 @@ jobs:
|
||||
report-coverage:
|
||||
needs: [sharded-jest-tests]
|
||||
if: needs.frontend-build.outputs.should-run == 'true'
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
timeout-minutes: 15
|
||||
permissions:
|
||||
id-token: write
|
||||
@@ -146,7 +146,7 @@ jobs:
|
||||
lint-frontend:
|
||||
needs: frontend-build
|
||||
if: needs.frontend-build.outputs.should-run == 'true'
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
- name: Download Docker Image Artifact
|
||||
@@ -171,7 +171,7 @@ jobs:
|
||||
validate-frontend:
|
||||
needs: frontend-build
|
||||
if: needs.frontend-build.outputs.should-run == 'true'
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
- name: Download Docker Image Artifact
|
||||
@@ -191,7 +191,7 @@ jobs:
|
||||
test-storybook:
|
||||
needs: frontend-build
|
||||
if: needs.frontend-build.outputs.should-run == 'true'
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
timeout-minutes: 25
|
||||
steps:
|
||||
- name: Download Docker Image Artifact
|
||||
|
||||
@@ -19,7 +19,7 @@ concurrency:
|
||||
|
||||
jobs:
|
||||
lint-test:
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
steps:
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
@@ -31,7 +31,7 @@ jobs:
|
||||
- name: Set up Helm
|
||||
uses: azure/setup-helm@9bc31f4ebc9c6b171d7bfbaa5d006ae7abdb4310 # v5.0.1
|
||||
with:
|
||||
version: v3.16.4
|
||||
version: v3.21.3
|
||||
|
||||
- name: Setup Python
|
||||
uses: ./.github/actions/setup-backend/
|
||||
@@ -59,3 +59,9 @@ jobs:
|
||||
CT_LINT_CONF: lintconf.yaml
|
||||
CT_SINCE: HEAD
|
||||
CT_CHART_REPOS: bitnami=https://charts.bitnami.com/bitnami
|
||||
|
||||
- name: Set up helm-unittest
|
||||
run: helm plugin install https://github.com/helm-unittest/helm-unittest --version v1.1.1
|
||||
|
||||
- name: Run helm-unittest
|
||||
run: helm unittest helm/superset
|
||||
2
.github/workflows/superset-helm-release.yml
vendored
2
.github/workflows/superset-helm-release.yml
vendored
@@ -20,7 +20,7 @@ on:
|
||||
|
||||
jobs:
|
||||
release:
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
|
||||
6
.github/workflows/superset-playwright.yml
vendored
6
.github/workflows/superset-playwright.yml
vendored
@@ -24,7 +24,7 @@ concurrency:
|
||||
|
||||
jobs:
|
||||
changes:
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
timeout-minutes: 10
|
||||
permissions:
|
||||
contents: read
|
||||
@@ -48,7 +48,7 @@ jobs:
|
||||
playwright-tests-experimental:
|
||||
needs: changes
|
||||
if: needs.changes.outputs.python == 'true' || needs.changes.outputs.frontend == 'true'
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-26.04
|
||||
timeout-minutes: 30
|
||||
continue-on-error: true
|
||||
permissions:
|
||||
@@ -114,7 +114,7 @@ jobs:
|
||||
with:
|
||||
run: playwright_testdata
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
||||
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||
with:
|
||||
node-version-file: "./superset-frontend/.nvmrc"
|
||||
cache: "npm"
|
||||
|
||||
@@ -20,7 +20,7 @@ concurrency:
|
||||
|
||||
jobs:
|
||||
changes:
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
timeout-minutes: 10
|
||||
permissions:
|
||||
contents: read
|
||||
@@ -41,7 +41,7 @@ jobs:
|
||||
test-mysql:
|
||||
needs: changes
|
||||
if: needs.changes.outputs.python == 'true'
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
timeout-minutes: 45
|
||||
permissions:
|
||||
id-token: write
|
||||
@@ -127,7 +127,7 @@ jobs:
|
||||
test-postgres:
|
||||
needs: changes
|
||||
if: needs.changes.outputs.python == 'true'
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
timeout-minutes: 45
|
||||
permissions:
|
||||
id-token: write
|
||||
@@ -188,7 +188,7 @@ jobs:
|
||||
test-sqlite:
|
||||
needs: changes
|
||||
if: needs.changes.outputs.python == 'true'
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
timeout-minutes: 45
|
||||
permissions:
|
||||
id-token: write
|
||||
@@ -243,7 +243,7 @@ jobs:
|
||||
test-postgres-required:
|
||||
needs: [changes, test-postgres]
|
||||
if: always()
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- name: Check test-postgres result
|
||||
|
||||
@@ -16,7 +16,7 @@ concurrency:
|
||||
|
||||
jobs:
|
||||
changes:
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
timeout-minutes: 10
|
||||
permissions:
|
||||
contents: read
|
||||
@@ -37,7 +37,7 @@ jobs:
|
||||
test-postgres-presto:
|
||||
needs: changes
|
||||
if: needs.changes.outputs.python == 'true'
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
timeout-minutes: 45
|
||||
permissions:
|
||||
id-token: write
|
||||
@@ -100,7 +100,7 @@ jobs:
|
||||
test-postgres-hive:
|
||||
needs: changes
|
||||
if: needs.changes.outputs.python == 'true'
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
timeout-minutes: 45
|
||||
permissions:
|
||||
id-token: write
|
||||
|
||||
@@ -21,7 +21,7 @@ concurrency:
|
||||
|
||||
jobs:
|
||||
changes:
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
timeout-minutes: 10
|
||||
permissions:
|
||||
contents: read
|
||||
@@ -42,7 +42,7 @@ jobs:
|
||||
unit-tests:
|
||||
needs: changes
|
||||
if: needs.changes.outputs.python == 'true'
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
timeout-minutes: 30
|
||||
permissions:
|
||||
id-token: write
|
||||
@@ -99,7 +99,7 @@ jobs:
|
||||
unit-tests-required:
|
||||
needs: [changes, unit-tests]
|
||||
if: always()
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- name: Check unit-tests result
|
||||
|
||||
@@ -20,7 +20,7 @@ permissions:
|
||||
|
||||
jobs:
|
||||
post-comment:
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
# Only act when the Translations workflow failed (which means a regression
|
||||
# was detected — the workflow exits 1 on regression).
|
||||
if: github.event.workflow_run.conclusion == 'failure'
|
||||
|
||||
6
.github/workflows/superset-translations.yml
vendored
6
.github/workflows/superset-translations.yml
vendored
@@ -19,7 +19,7 @@ concurrency:
|
||||
|
||||
jobs:
|
||||
frontend-check-translations:
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: read
|
||||
@@ -38,7 +38,7 @@ jobs:
|
||||
|
||||
- name: Setup Node.js
|
||||
if: steps.check.outputs.frontend
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
||||
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||
with:
|
||||
node-version-file: "./superset-frontend/.nvmrc"
|
||||
cache: "npm"
|
||||
@@ -55,7 +55,7 @@ jobs:
|
||||
npm run build-translation
|
||||
|
||||
babel-extract:
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: read
|
||||
|
||||
4
.github/workflows/superset-websocket.yml
vendored
4
.github/workflows/superset-websocket.yml
vendored
@@ -21,7 +21,7 @@ concurrency:
|
||||
|
||||
jobs:
|
||||
app-checks:
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
@@ -29,7 +29,7 @@ jobs:
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
||||
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||
with:
|
||||
node-version-file: './superset-websocket/.nvmrc'
|
||||
- name: Install dependencies
|
||||
|
||||
2
.github/workflows/supersetbot.yml
vendored
2
.github/workflows/supersetbot.yml
vendored
@@ -15,7 +15,7 @@ on:
|
||||
|
||||
jobs:
|
||||
supersetbot:
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
if: >
|
||||
github.event_name == 'workflow_dispatch' ||
|
||||
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '@supersetbot'))
|
||||
|
||||
12
.github/workflows/tag-release.yml
vendored
12
.github/workflows/tag-release.yml
vendored
@@ -32,7 +32,7 @@ concurrency:
|
||||
|
||||
jobs:
|
||||
config:
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
outputs:
|
||||
has-secrets: ${{ steps.check.outputs.has-secrets }}
|
||||
steps:
|
||||
@@ -50,13 +50,13 @@ jobs:
|
||||
needs: config
|
||||
if: needs.config.outputs.has-secrets
|
||||
name: docker-release
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
permissions:
|
||||
contents: write
|
||||
strategy:
|
||||
matrix:
|
||||
build_preset:
|
||||
["dev", "lean", "py310", "websocket", "dockerize", "py311", "py312"]
|
||||
["dev", "lean", "websocket", "dockerize", "py311", "py312"]
|
||||
fail-fast: false
|
||||
steps:
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
@@ -75,7 +75,7 @@ jobs:
|
||||
|
||||
- name: Use Node.js 20
|
||||
# zizmor: ignore[cache-poisoning] - node only runs the supersetbot CLI; no dependency cache is enabled
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
||||
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||
with:
|
||||
node-version: 20
|
||||
package-manager-cache: false
|
||||
@@ -120,7 +120,7 @@ jobs:
|
||||
update-prs-with-release-info:
|
||||
needs: config
|
||||
if: needs.config.outputs.has-secrets
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
@@ -133,7 +133,7 @@ jobs:
|
||||
|
||||
- name: Use Node.js 20
|
||||
# zizmor: ignore[cache-poisoning] - node only runs the supersetbot CLI; no dependency cache is enabled
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
||||
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||
with:
|
||||
node-version: 20
|
||||
package-manager-cache: false
|
||||
|
||||
6
.github/workflows/tech-debt.yml
vendored
6
.github/workflows/tech-debt.yml
vendored
@@ -11,7 +11,7 @@ permissions:
|
||||
|
||||
jobs:
|
||||
config:
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
outputs:
|
||||
has-secrets: ${{ steps.check.outputs.has-secrets }}
|
||||
steps:
|
||||
@@ -28,7 +28,7 @@ jobs:
|
||||
process-and-upload:
|
||||
needs: config
|
||||
if: needs.config.outputs.has-secrets
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
name: Generate Reports
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
@@ -37,7 +37,7 @@ jobs:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
||||
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||
with:
|
||||
node-version-file: "./superset-frontend/.nvmrc"
|
||||
|
||||
|
||||
2
.github/workflows/welcome-new-users.yml
vendored
2
.github/workflows/welcome-new-users.yml
vendored
@@ -7,7 +7,7 @@ on:
|
||||
|
||||
jobs:
|
||||
welcome:
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
if: github.event.pull_request.author_association == 'FIRST_TIME_CONTRIBUTOR'
|
||||
permissions:
|
||||
pull-requests: write
|
||||
|
||||
6
Makefile
6
Makefile
@@ -15,8 +15,8 @@
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
# Python version installed; we need 3.10-3.11
|
||||
PYTHON=`command -v python3.11 || command -v python3.10`
|
||||
# Python version installed; we need 3.11-3.12
|
||||
PYTHON=`command -v python3.11 || command -v python3.12`
|
||||
|
||||
.PHONY: install superset venv pre-commit up down logs ps nuke ports open
|
||||
|
||||
@@ -76,7 +76,7 @@ update-js:
|
||||
|
||||
venv:
|
||||
# Create a virtual environment and activate it (recommended)
|
||||
if ! [ -x "${PYTHON}" ]; then echo "You need Python 3.10 or 3.11 installed"; exit 1; fi
|
||||
if ! [ -x "${PYTHON}" ]; then echo "You need Python 3.11 or 3.12 installed"; exit 1; fi
|
||||
test -d venv || ${PYTHON} -m venv venv # setup a python3 virtualenv
|
||||
. venv/bin/activate
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
FROM python:3.10-slim-trixie
|
||||
FROM python:3.11-slim-trixie
|
||||
|
||||
RUN useradd --user-group --create-home --no-log-init --shell /bin/bash superset
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
FROM python:3.10-slim-trixie
|
||||
FROM python:3.11-slim-trixie
|
||||
|
||||
RUN useradd --user-group --create-home --no-log-init --shell /bin/bash superset
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
FROM python:3.10-slim-trixie
|
||||
FROM python:3.11-slim-trixie
|
||||
ARG VERSION
|
||||
|
||||
RUN git clone --depth 1 --branch ${VERSION} https://github.com/apache/superset.git /superset
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
FROM python:3.10-slim-trixie
|
||||
FROM python:3.11-slim-trixie
|
||||
|
||||
RUN apt-get update -y
|
||||
RUN apt-get install -y \
|
||||
|
||||
68
UPDATING.md
68
UPDATING.md
@@ -24,6 +24,55 @@ assists people when migrating to a new version.
|
||||
|
||||
## Next
|
||||
|
||||
### Dashboard "Export Data to Excel" requires a Celery worker and S3 bucket
|
||||
|
||||
A new dashboard action exports every chart's data to a single multi-sheet
|
||||
`.xlsx` asynchronously. It is disabled by default and turns on only when
|
||||
`EXCEL_EXPORT_S3_BUCKET` is set (the endpoint returns `501` otherwise). It also
|
||||
requires a running Celery worker and a configured SMTP transport, since the task
|
||||
emails the requesting user a pre-signed download link. New config keys:
|
||||
`EXCEL_EXPORT_S3_BUCKET`, `EXCEL_EXPORT_S3_KEY_PREFIX`,
|
||||
`EXCEL_EXPORT_LINK_TTL_SECONDS`, `EXCEL_EXPORT_S3_CLIENT_KWARGS`,
|
||||
`EXCEL_EXPORT_TABLE_VIZ_TYPES`, and `EXCEL_EXPORT_REBUILD_VIZ_TYPES`.
|
||||
|
||||
The feature depends on `boto3`, which is **not** installed by default; install it
|
||||
with `pip install apache-superset[excel-export]`.
|
||||
|
||||
Charts store their `query_context` only once they have been (re-)saved in
|
||||
Explore, so older charts may have none. For a conservative allowlist of viz types
|
||||
(`EXCEL_EXPORT_REBUILD_VIZ_TYPES`, default `table`, `big_number_total`,
|
||||
`big_number`, `pie`) the export rebuilds a query context from the chart's saved
|
||||
form data so those charts still export. The rebuild is a generic single-query
|
||||
mapping and does **not** reproduce plugin post-processing (pivot, rolling,
|
||||
forecast) or multi-query charts, so any chart of another type without a saved
|
||||
query context is skipped and listed in the email for the user to re-save.
|
||||
|
||||
A second mode, **Export Images to Excel**, embeds non-table charts as rendered
|
||||
images (which viz types stay tabular is controlled by
|
||||
`EXCEL_EXPORT_TABLE_VIZ_TYPES`). It renders through the headless webdriver, so the
|
||||
menu option only appears when the webdriver screenshot feature flags
|
||||
(`ENABLE_DASHBOARD_SCREENSHOT_ENDPOINTS`,
|
||||
`ENABLE_DASHBOARD_DOWNLOAD_WEBDRIVER_SCREENSHOT`) are enabled.
|
||||
|
||||
Deployments that override `CELERY_CONFIG` must add
|
||||
`"superset.tasks.export_dashboard_excel"` to their `imports` tuple, or the task
|
||||
will not register and exports will silently never run.
|
||||
|
||||
### SQL_QUERY_MUTATOR now honors MUTATE_AFTER_SPLIT in SQL Lab
|
||||
|
||||
SQL Lab now applies `SQL_QUERY_MUTATOR` according to `MUTATE_AFTER_SPLIT`, matching the documented semantics and the chart/query path. This only affects deployments that define `SQL_QUERY_MUTATOR` in `superset_config.py`:
|
||||
|
||||
- With `MUTATE_AFTER_SPLIT = True`, the mutator previously never ran in SQL Lab; it now runs on each individual statement (including on engines like BigQuery and Kusto that execute multiple statements as one block, where each statement is mutated before the statements are joined).
|
||||
- With `MUTATE_AFTER_SPLIT = False` (the default), multi-statement SQL Lab queries previously applied the mutator to each statement separately; the mutator now runs once on the whole un-split query, as documented. Single-statement queries are unaffected.
|
||||
- With `MUTATE_AFTER_SPLIT = False` on engines that execute statements individually, the mutator's output is re-parsed to split it into statements. A mutator that emits SQL Superset's parser cannot parse will now fail with a clear parse error before execution, and one that strips a query down to nothing raises an invalid-SQL error instead of executing an empty query.
|
||||
|
||||
### Python 3.10 support removed
|
||||
|
||||
Python 3.10 is no longer supported. Superset now requires **Python 3.11 or higher**.
|
||||
Update your environment (virtualenv, Docker base image, CI configuration, etc.) to
|
||||
Python 3.11+ before upgrading. The `apache/superset-cache:3.10-slim-trixie` and
|
||||
`py310` Docker image variants are no longer published.
|
||||
|
||||
### Owners, dashboard roles, and RLS roles replaced by Subjects
|
||||
|
||||
Superset now uses subject-based access assignments for dashboards, charts, datasets,
|
||||
@@ -216,6 +265,12 @@ The `thumbnail_url` field has been removed from `GET /api/v1/dashboard/` list re
|
||||
|
||||
The thumbnail endpoint redirects to the current digest URL regardless of whether the supplied digest is exact. If the image is not yet cached, that digest URL may return `202` and trigger async generation. Using `changed_on_utc` as the digest is sufficient for cache-busting purposes.
|
||||
|
||||
### Dashboard import can overwrite related charts, datasets, and databases
|
||||
|
||||
Re-importing an existing dashboard previously overwrote only the dashboard itself; its related charts, datasets, and databases were never updated (the importer hardcoded `overwrite=False` for them). They can now be overwritten as part of the import.
|
||||
|
||||
A new `overwrite_all` form field controls this, and defaults to `false` everywhere, so existing behavior is preserved: passing `overwrite=true` alone still overwrites only the dashboard, exactly as before. To also overwrite the related charts, datasets, and databases on the `/api/v1/dashboard/import/` endpoint, pass `overwrite_all=true` explicitly. The import modal in the UI exposes this as an "also overwrite all assets" checkbox, and the CLI `superset import-dashboards` and the `ImportDashboardsCommand` likewise default `overwrite_all` to `false`.
|
||||
|
||||
### Tagging fix for `create_all`-bootstrapped schemas
|
||||
|
||||
Only affects deployments whose metadata schema was created with SQLAlchemy's `create_all` (rather than `superset db upgrade`) on a foreign-key-enforcing backend — PostgreSQL, or MySQL with `FOREIGN_KEY_CHECKS=1`. Such schemas carry three invalid foreign keys on `tagged_object.object_id` that break tagging (`TAGGING_SYSTEM = True`) with a `ForeignKeyViolation`. Schemas built via `superset db upgrade` are unaffected.
|
||||
@@ -241,6 +296,19 @@ A few save- and import-path internals change **unconditionally** (independent of
|
||||
|
||||
These are behavior changes that take effect on upgrade regardless of `ENABLE_VERSIONING_CAPTURE`; no operator action is required.
|
||||
|
||||
### Cross-entity version activity stream
|
||||
|
||||
A read-only companion to the version-history endpoints: each entity type gains a `GET /api/v1/{chart,dashboard,dataset}/<uuid>/activity/` endpoint returning a chronological, access-filtered stream of edits — the entity's own edits plus, for charts and dashboards, transitive edits to related entities during their association windows. Datasets have no related layer in V2, so `include=related` returns an empty stream for a dataset and `include=all` reduces to the dataset's own edits.
|
||||
|
||||
| Param | Type | Default | Purpose |
|
||||
|---|---|---|---|
|
||||
| `since` / `until` | ISO 8601 | — | Bound `issued_at` |
|
||||
| `include` | `self` \| `related` \| `all` | `all` | Own edits, related edits, or both |
|
||||
| `q` | string | — | Case-insensitive search over the full history, applied before pagination (so `count` reflects matches) |
|
||||
| `page` / `page_size` | integer | `0` / `25` | Pagination (`page_size` clamped to 200) |
|
||||
|
||||
Authorization reuses the resource's `can_read` permission and per-object `raise_for_access`; related-entity rows are visibility-filtered to what the caller may see. The stream is empty unless version capture is on (`ENABLE_VERSIONING_CAPTURE`).
|
||||
|
||||
### Webhook alerts/reports block private/internal hosts by default
|
||||
|
||||
Webhook alert/report dispatch (`WebhookNotification.send`) now validates the target URL's host against the same private/internal-IP block applied to dataset import URLs. If the resolved host is in a loopback, link-local, private (RFC-1918), shared-CGNAT, or multicast range, the webhook is rejected with `NotificationParamException`.
|
||||
|
||||
@@ -71,7 +71,7 @@ x-common-build: &common-build
|
||||
context: .
|
||||
target: ${SUPERSET_BUILD_TARGET:-dev} # can use `dev` (default) or `lean`
|
||||
cache_from:
|
||||
- apache/superset-cache:3.10-slim-trixie
|
||||
- apache/superset-cache:3.11-slim-trixie
|
||||
args:
|
||||
DEV_MODE: "true"
|
||||
INCLUDE_CHROMIUM: ${INCLUDE_CHROMIUM:-false}
|
||||
|
||||
@@ -33,7 +33,7 @@ x-common-build: &common-build
|
||||
context: .
|
||||
target: dev
|
||||
cache_from:
|
||||
- apache/superset-cache:3.10-slim-trixie
|
||||
- apache/superset-cache:3.11-slim-trixie
|
||||
|
||||
services:
|
||||
redis:
|
||||
|
||||
@@ -38,7 +38,7 @@ x-common-build: &common-build
|
||||
context: .
|
||||
target: ${SUPERSET_BUILD_TARGET:-dev} # can use `dev` (default) or `lean`
|
||||
cache_from:
|
||||
- apache/superset-cache:3.10-slim-trixie
|
||||
- apache/superset-cache:3.11-slim-trixie
|
||||
args:
|
||||
DEV_MODE: "true"
|
||||
INCLUDE_CHROMIUM: ${INCLUDE_CHROMIUM:-false}
|
||||
|
||||
@@ -87,6 +87,7 @@ class CeleryConfig:
|
||||
"superset.tasks.scheduler",
|
||||
"superset.tasks.thumbnails",
|
||||
"superset.tasks.cache",
|
||||
"superset.tasks.export_dashboard_excel",
|
||||
)
|
||||
result_backend = f"redis://{REDIS_HOST}:{REDIS_PORT}/{REDIS_RESULTS_DB}"
|
||||
worker_prefetch_multiplier = 1
|
||||
|
||||
@@ -99,7 +99,7 @@ See [Connecting AI Clients](#connecting-ai-clients) for Claude Code, Claude Web,
|
||||
## Prerequisites
|
||||
|
||||
- Apache Superset 5.0+ running and accessible
|
||||
- Python 3.10+
|
||||
- Python 3.11+
|
||||
- The `fastmcp` package (`pip install fastmcp`)
|
||||
|
||||
---
|
||||
|
||||
@@ -379,7 +379,7 @@ functioning across environments.
|
||||
Make sure your machine meets the [OS dependencies](https://superset.apache.org/docs/installation/pypi#os-dependencies) before following these steps.
|
||||
You also need to install MySQL.
|
||||
|
||||
Ensure that you are using Python version 3.9, 3.10 or 3.11, then proceed with:
|
||||
Ensure that you are using Python version 3.11 or 3.12, then proceed with:
|
||||
|
||||
```bash
|
||||
# Create a virtual environment and activate it (recommended)
|
||||
|
||||
@@ -82,7 +82,7 @@ If applicable, add screenshots or recordings.
|
||||
|
||||
### Environment
|
||||
- Superset version: [e.g., 3.0.0]
|
||||
- Python version: [e.g., 3.9.7]
|
||||
- Python version: [e.g., 3.11.7]
|
||||
- Node version: [e.g., 18.17.0]
|
||||
- Database: [e.g., PostgreSQL 14]
|
||||
- Browser: [e.g., Chrome 120]
|
||||
@@ -125,7 +125,7 @@ No error messages in browser console or server logs.
|
||||
|
||||
### Environment
|
||||
- Superset version: 3.0.0
|
||||
- Python version: 3.9.16
|
||||
- Python version: 3.11.16
|
||||
- Database: PostgreSQL 14.9
|
||||
- Browser: Chrome 120.0.6099.71
|
||||
- OS: macOS 14.2
|
||||
|
||||
@@ -52,7 +52,7 @@ Everything you need to contribute to the Apache Superset project. This section i
|
||||
## Development Resources
|
||||
|
||||
### Prerequisites
|
||||
- **Python**: 3.9, 3.10, or 3.11
|
||||
- **Python**: 3.11 or 3.12
|
||||
- **Node.js**: 18.x or 20.x
|
||||
- **npm**: 9.x or 10.x
|
||||
- **Git**: Basic understanding
|
||||
|
||||
99
docs/docs/using-superset/exporting-dashboard-data.mdx
Normal file
99
docs/docs/using-superset/exporting-dashboard-data.mdx
Normal file
@@ -0,0 +1,99 @@
|
||||
---
|
||||
title: Exporting Dashboard Data to Excel
|
||||
hide_title: true
|
||||
sidebar_position: 7
|
||||
version: 1
|
||||
---
|
||||
|
||||
# Exporting Dashboard Data to Excel
|
||||
|
||||
Superset can export every chart on a dashboard to a single Excel workbook, with
|
||||
each chart's underlying data rendered as its own worksheet. The export reflects
|
||||
the dashboard's currently applied filters and runs asynchronously: when it
|
||||
finishes, the requesting user receives an email with a time-limited download
|
||||
link.
|
||||
|
||||
## Using the export
|
||||
|
||||
From a dashboard, open the **... (actions) → Download** submenu and choose
|
||||
**Export Data to Excel**. The action appears for users who have the dashboard
|
||||
`can_export` permission. You'll see a confirmation that the export is being
|
||||
prepared; the workbook arrives by email when it's ready.
|
||||
|
||||
A second option, **Export Images to Excel**, embeds each non-table chart as a
|
||||
rendered image (tables stay tabular) instead of exporting raw data. Because it
|
||||
renders charts through the headless webdriver, this option only appears when the
|
||||
webdriver screenshot feature flags are enabled (see the prerequisites below);
|
||||
which viz types stay tabular is controlled by `EXCEL_EXPORT_TABLE_VIZ_TYPES`.
|
||||
|
||||
Notes on the generated workbook:
|
||||
|
||||
- One worksheet per chart, named `{chart_id} - {chart title}` (truncated to
|
||||
Excel's 31-character limit; the chart id keeps names unique).
|
||||
- Charts nested in tabs are included.
|
||||
- Data reflects the dashboard's active filter state at the time of export.
|
||||
- A chart with no saved query context is skipped and listed in the email; open
|
||||
the chart in Explore and re-save it to include it next time.
|
||||
- Row counts per sheet are capped the same way as the chart-level CSV/Excel
|
||||
export (`ROW_LIMIT`, bounded by `SQL_MAX_ROW`), and never exceed Excel's
|
||||
per-sheet maximum.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
This feature is **disabled by default**. It requires:
|
||||
|
||||
1. **The `boto3` dependency.** It is not installed by default; install it with
|
||||
`pip install apache-superset[excel-export]`. Without it, exports fail and the
|
||||
user receives a failure email.
|
||||
2. **An S3 bucket.** Set `EXCEL_EXPORT_S3_BUCKET`. Until it is set, the export
|
||||
endpoint returns `501` and the menu action surfaces a "not configured"
|
||||
message.
|
||||
3. **A running Celery worker.** The export runs as a Celery task. If no worker
|
||||
is running, the request is accepted but nothing is produced.
|
||||
4. **A configured SMTP transport.** The download link is delivered by email
|
||||
using the same settings as alerts & reports (`SMTP_*`,
|
||||
`EMAIL_REPORTS_SUBJECT_PREFIX`).
|
||||
|
||||
**Export Images to Excel** additionally requires a working headless webdriver —
|
||||
the same infrastructure scheduled reports and thumbnails use (`WEBDRIVER_*`,
|
||||
plus the `ENABLE_DASHBOARD_SCREENSHOT_ENDPOINTS` and
|
||||
`ENABLE_DASHBOARD_DOWNLOAD_WEBDRIVER_SCREENSHOT` feature flags). The menu option
|
||||
is hidden when those flags are off; if the webdriver is unreachable, image
|
||||
charts come back empty even though the data export path still works.
|
||||
|
||||
Deployments that override `CELERY_CONFIG` must add
|
||||
`"superset.tasks.export_dashboard_excel"` to the `imports` tuple, or the task
|
||||
will not register.
|
||||
|
||||
## Configuration keys
|
||||
|
||||
| Key | Default | Description |
|
||||
| --- | --- | --- |
|
||||
| `EXCEL_EXPORT_S3_BUCKET` | `None` | Destination bucket. Required; `501` if unset. |
|
||||
| `EXCEL_EXPORT_S3_KEY_PREFIX` | `"dashboard-exports/"` | Key prefix: `{prefix}{dashboard_id}/{job_id}.xlsx`. |
|
||||
| `EXCEL_EXPORT_LINK_TTL_SECONDS` | `86400` | Lifetime of the pre-signed download URL (24h). |
|
||||
| `EXCEL_EXPORT_S3_CLIENT_KWARGS` | `{}` | Extra kwargs for `boto3.client("s3", ...)` — e.g. `region_name`, or `endpoint_url` for MinIO/LocalStack. |
|
||||
| `EXCEL_EXPORT_TABLE_VIZ_TYPES` | `None` | Viz types kept tabular in **Export Images to Excel** mode; every other type is embedded as an image. `None` uses the built-in default (`table`, `pivot_table`, `pivot_table_v2`). |
|
||||
|
||||
Credentials and region resolve through the standard boto3 chain (environment
|
||||
variables, shared config, or instance role) unless overridden via
|
||||
`EXCEL_EXPORT_S3_CLIENT_KWARGS`. The worker needs `s3:PutObject` on the bucket.
|
||||
|
||||
## Security considerations
|
||||
|
||||
- The emailed link is a **pre-signed S3 URL**: anyone who holds it can download
|
||||
the workbook until it expires. Keep the bucket **private**, enable
|
||||
encryption, and consider a lifecycle rule to delete objects after a few days.
|
||||
Lower `EXCEL_EXPORT_LINK_TTL_SECONDS` if 24 hours is too long for your data.
|
||||
- The export runs with the requesting user's permissions; each chart's query is
|
||||
access-checked, so users only ever receive data they are entitled to.
|
||||
|
||||
## Limitations
|
||||
|
||||
- **Embedded dashboards / guest tokens are not supported** in this version,
|
||||
because guest users have no email address to deliver the link to. Logged-in
|
||||
users viewing an embedded dashboard can still use the export.
|
||||
- The default **Export Data to Excel** mode exports data only (no visual
|
||||
styling). Use **Export Images to Excel** to embed rendered chart images, which
|
||||
requires the webdriver infrastructure described in the prerequisites.
|
||||
- Scheduled/automated exports are not part of this feature.
|
||||
@@ -44,12 +44,12 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@ant-design/icons": "^6.2.5",
|
||||
"@docusaurus/core": "^3.10.1",
|
||||
"@docusaurus/faster": "^3.10.1",
|
||||
"@docusaurus/plugin-client-redirects": "^3.10.1",
|
||||
"@docusaurus/preset-classic": "3.10.1",
|
||||
"@docusaurus/theme-live-codeblock": "^3.10.1",
|
||||
"@docusaurus/theme-mermaid": "^3.10.1",
|
||||
"@docusaurus/core": "^3.10.2",
|
||||
"@docusaurus/faster": "^3.10.2",
|
||||
"@docusaurus/plugin-client-redirects": "^3.10.2",
|
||||
"@docusaurus/preset-classic": "3.10.2",
|
||||
"@docusaurus/theme-live-codeblock": "^3.10.2",
|
||||
"@docusaurus/theme-mermaid": "^3.10.2",
|
||||
"@emotion/core": "^11.0.0",
|
||||
"@emotion/react": "^11.13.3",
|
||||
"@emotion/styled": "^11.14.1",
|
||||
@@ -58,14 +58,14 @@
|
||||
"@fontsource/inter": "^5.2.8",
|
||||
"@mdx-js/react": "^3.1.1",
|
||||
"@saucelabs/theme-github-codeblock": "^0.3.0",
|
||||
"@storybook/addon-docs": "^10.4.5",
|
||||
"@storybook/addon-docs": "^10.5.0",
|
||||
"@superset-ui/core": "^0.20.4",
|
||||
"@swc/core": "^1.15.43",
|
||||
"antd": "^6.5.0",
|
||||
"baseline-browser-mapping": "^2.10.40",
|
||||
"caniuse-lite": "^1.0.30001803",
|
||||
"docusaurus-plugin-openapi-docs": "^5.1.1",
|
||||
"docusaurus-theme-openapi-docs": "^5.1.1",
|
||||
"antd": "^6.5.1",
|
||||
"baseline-browser-mapping": "^2.10.43",
|
||||
"caniuse-lite": "^1.0.30001805",
|
||||
"docusaurus-plugin-openapi-docs": "^5.1.2",
|
||||
"docusaurus-theme-openapi-docs": "^5.1.2",
|
||||
"js-yaml": "^5.2.0",
|
||||
"json-bigint": "^1.0.0",
|
||||
"prism-react-renderer": "^2.4.1",
|
||||
@@ -77,20 +77,20 @@
|
||||
"react-table": "^7.8.0",
|
||||
"remark-import-partial": "^0.0.2",
|
||||
"reselect": "^5.2.0",
|
||||
"storybook": "^10.4.5",
|
||||
"storybook": "^10.5.0",
|
||||
"swagger-ui-react": "^5.32.8",
|
||||
"swc-loader": "^0.2.7",
|
||||
"tinycolor2": "^1.4.2",
|
||||
"unist-util-visit": "^5.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@docusaurus/module-type-aliases": "^3.10.1",
|
||||
"@docusaurus/tsconfig": "^3.10.1",
|
||||
"@docusaurus/module-type-aliases": "^3.10.2",
|
||||
"@docusaurus/tsconfig": "^3.10.2",
|
||||
"@eslint/js": "^9.39.2",
|
||||
"@types/js-yaml": "^4.0.9",
|
||||
"@types/react": "^19.1.8",
|
||||
"@typescript-eslint/eslint-plugin": "^8.59.3",
|
||||
"@typescript-eslint/parser": "^8.63.0",
|
||||
"@typescript-eslint/eslint-plugin": "^8.64.0",
|
||||
"@typescript-eslint/parser": "^8.64.0",
|
||||
"eslint": "^9.39.2",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
"eslint-plugin-prettier": "^5.5.6",
|
||||
@@ -98,7 +98,7 @@
|
||||
"globals": "^17.7.0",
|
||||
"prettier": "^3.9.5",
|
||||
"typescript": "~6.0.3",
|
||||
"typescript-eslint": "^8.63.0",
|
||||
"typescript-eslint": "^8.64.0",
|
||||
"webpack": "^5.108.2"
|
||||
},
|
||||
"browserslist": {
|
||||
@@ -124,8 +124,6 @@
|
||||
"serialize-javascript": "7.0.5",
|
||||
"d3-color": "3.1.0",
|
||||
"ws": "^8.21.0",
|
||||
"@docusaurus/core/@docusaurus/utils/gray-matter/js-yaml": "^3.15.0",
|
||||
"@docusaurus/core/**/js-yaml": "^4.3.0",
|
||||
"docusaurus-plugin-openapi-docs/**/js-yaml": "^4.3.0"
|
||||
},
|
||||
"packageManager": "yarn@1.22.22+sha1.ac34549e6aa8e7ead463a7407e1c7390f61a6610"
|
||||
|
||||
903
docs/yarn.lock
903
docs/yarn.lock
File diff suppressed because it is too large
Load Diff
@@ -29,7 +29,7 @@ maintainers:
|
||||
- name: craig-rueda
|
||||
email: craig@craigrueda.com
|
||||
url: https://github.com/craig-rueda
|
||||
version: 0.21.0 # See [README](https://github.com/apache/superset/blob/master/helm/superset/README.md#versioning) for version details.
|
||||
version: 0.22.0 # 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
|
||||
|
||||
@@ -125,6 +125,13 @@ Alternatively, perform a fresh install. This is a one-time migration; subsequent
|
||||
| fullnameOverride | string | `nil` | Provide a name to override the full names of resources |
|
||||
| globalPodAnnotations | object | `{}` | Global pod annotations to be added to all pods Use this to set annotations that apply to all Superset components Component-specific podAnnotations will be merged with these global annotations |
|
||||
| hostAliases | list | `[]` | Custom hostAliases for all superset pods # https://kubernetes.io/docs/tasks/network/customize-hosts-file-for-pods/ |
|
||||
| httproute | object | see `values.yaml` | Gateway API HTTPRoute for exposing Superset via a Gateway. Requires the Gateway API CRDs (gateway.networking.k8s.io/v1) installed in the cluster. |
|
||||
| httproute.annotations | object | `{}` | Annotations to add to the HTTPRoute |
|
||||
| httproute.apiVersion | string | `"gateway.networking.k8s.io/v1"` | HTTPRoute apiVersion. Override to gateway.networking.k8s.io/v1beta1 for older Gateway API installations that have not promoted HTTPRoute to v1. |
|
||||
| httproute.hostnames | list | `[]` | Hostnames that match against the HTTP Host header (templated) |
|
||||
| httproute.labels | object | `{}` | Additional labels to add to the HTTPRoute |
|
||||
| httproute.parentRefs | list | `[]` | Gateways this HTTPRoute attaches to |
|
||||
| httproute.rules | list | `[{"matches":[{"path":{"type":"PathPrefix","value":"/"}}]}]` | Routing rules. Each rule is backed by the Superset service. Set `weight` per rule to leave room for traffic splitting (defaults to 1). When `supersetWebsockets.enabled` is true, an extra rule routing `supersetWebsockets.ingress.path` to the `-ws` service is appended automatically, mirroring the ingress behavior. |
|
||||
| image.pullPolicy | string | `"IfNotPresent"` | |
|
||||
| image.repository | string | `"apachesuperset.docker.scarf.sh/apache/superset"` | |
|
||||
| image.tag | string | `nil` | |
|
||||
@@ -246,6 +253,60 @@ Alternatively, perform a fresh install. This is a one-time migration; subsequent
|
||||
| supersetCeleryFlower.startupProbe.successThreshold | int | `1` | |
|
||||
| supersetCeleryFlower.startupProbe.timeoutSeconds | int | `1` | |
|
||||
| supersetCeleryFlower.topologySpreadConstraints | list | `[]` | TopologySpreadConstrains to be added to supersetCeleryFlower deployments |
|
||||
| supersetMcp.affinity | object | `{}` | Affinity to be added to supersetMcp deployment |
|
||||
| supersetMcp.command | list | a `superset mcp run` command | Command |
|
||||
| supersetMcp.containerSecurityContext | object | `{}` | |
|
||||
| supersetMcp.deploymentAdditionalPodSpec | object | `{}` | Custom pod spec to be added to supersetMcp deployment |
|
||||
| supersetMcp.deploymentAnnotations | object | `{}` | Annotations to be added to supersetMcp deployment |
|
||||
| supersetMcp.deploymentLabels | object | `{}` | Labels to be added to supersetMcp deployment |
|
||||
| supersetMcp.enabled | bool | `false` | Enables the Superset MCP Server. To expose it via the shared ingress at /mcp, also set supersetMcp.ingress.enabled=true. WARNING: this requires fastMCP to be installed, which can be done by installing `apache-superset[fastmcp]` |
|
||||
| supersetMcp.extraContainers | list | `[]` | Launch additional containers into supersetMcp pods |
|
||||
| supersetMcp.extraInitContainers | list | `[]` | Extra init containers appended after supersetMcp initContainers |
|
||||
| supersetMcp.forceReload | bool | `false` | If true, forces deployment to reload on each upgrade |
|
||||
| supersetMcp.ingress.enabled | bool | `false` | If true, the MCP server will be exposed via the ingress /mcp subpath |
|
||||
| supersetMcp.ingress.path | string | `"/mcp"` | |
|
||||
| supersetMcp.ingress.pathType | string | `"Prefix"` | |
|
||||
| supersetMcp.initContainers | list | a container waiting for postgres and redis | List of init containers |
|
||||
| supersetMcp.lifecycle | object | `{}` | Container lifecycle hooks for the worker pod |
|
||||
| supersetMcp.livenessProbe.failureThreshold | int | `3` | |
|
||||
| supersetMcp.livenessProbe.httpGet.path | string | `"/health"` | |
|
||||
| supersetMcp.livenessProbe.httpGet.port | string | `"mcp"` | |
|
||||
| supersetMcp.livenessProbe.initialDelaySeconds | int | `15` | |
|
||||
| supersetMcp.livenessProbe.periodSeconds | int | `15` | |
|
||||
| supersetMcp.livenessProbe.successThreshold | int | `1` | |
|
||||
| supersetMcp.livenessProbe.timeoutSeconds | int | `3` | |
|
||||
| supersetMcp.podAnnotations | object | `{}` | Annotations to be added to supersetMcp pods |
|
||||
| supersetMcp.podDisruptionBudget | object | `{"enabled":false,"maxUnavailable":1,"minAvailable":1}` | Sets the [pod disruption budget](https://kubernetes.io/docs/tasks/run-application/configure-pdb/) for supersetMcp pods |
|
||||
| supersetMcp.podDisruptionBudget.enabled | bool | `false` | Whether the pod disruption budget should be created |
|
||||
| supersetMcp.podDisruptionBudget.maxUnavailable | int | `1` | If set, minAvailable must not be set - see https://kubernetes.io/docs/tasks/run-application/configure-pdb/\#specifying-a-poddisruptionbudget |
|
||||
| supersetMcp.podDisruptionBudget.minAvailable | int | `1` | If set, maxUnavailable must not be set - see https://kubernetes.io/docs/tasks/run-application/configure-pdb/\#specifying-a-poddisruptionbudget |
|
||||
| supersetMcp.podLabels | object | `{}` | Labels to be added to supersetMcp pods |
|
||||
| supersetMcp.podSecurityContext | object | `{}` | |
|
||||
| supersetMcp.priorityClassName | string | `nil` | Set priorityClassName for supersetMcp pods |
|
||||
| supersetMcp.readinessProbe.failureThreshold | int | `3` | |
|
||||
| supersetMcp.readinessProbe.httpGet.path | string | `"/health"` | |
|
||||
| supersetMcp.readinessProbe.httpGet.port | string | `"mcp"` | |
|
||||
| supersetMcp.readinessProbe.initialDelaySeconds | int | `15` | |
|
||||
| supersetMcp.readinessProbe.periodSeconds | int | `15` | |
|
||||
| supersetMcp.readinessProbe.successThreshold | int | `1` | |
|
||||
| supersetMcp.readinessProbe.timeoutSeconds | int | `3` | |
|
||||
| supersetMcp.replicaCount | int | `1` | |
|
||||
| supersetMcp.resources | object | `{}` | Resource settings for the supersetMcp pods - these settings overwrite might existing values from the global resources object defined above. |
|
||||
| supersetMcp.service.annotations | object | `{}` | |
|
||||
| supersetMcp.service.loadBalancerIP | string | `nil` | |
|
||||
| supersetMcp.service.nodePort.http | int | `"nil"` | |
|
||||
| supersetMcp.service.port | int | `5008` | |
|
||||
| supersetMcp.service.type | string | `"ClusterIP"` | |
|
||||
| supersetMcp.startupProbe.failureThreshold | int | `60` | |
|
||||
| supersetMcp.startupProbe.httpGet.path | string | `"/health"` | |
|
||||
| supersetMcp.startupProbe.httpGet.port | string | `"mcp"` | |
|
||||
| supersetMcp.startupProbe.initialDelaySeconds | int | `15` | |
|
||||
| supersetMcp.startupProbe.periodSeconds | int | `5` | |
|
||||
| supersetMcp.startupProbe.successThreshold | int | `1` | |
|
||||
| supersetMcp.startupProbe.timeoutSeconds | int | `3` | |
|
||||
| supersetMcp.strategy | object | `{}` | |
|
||||
| supersetMcp.terminationGracePeriodSeconds | string | `nil` | Pod termination grace period (seconds) for the worker pod so in-flight tasks can drain before SIGKILL |
|
||||
| supersetMcp.topologySpreadConstraints | list | `[]` | TopologySpreadConstrains to be added to supersetMcp deployments |
|
||||
| supersetNode.affinity | object | `{}` | Affinity to be added to supersetNode deployment |
|
||||
| supersetNode.autoscaling.enabled | bool | `false` | |
|
||||
| supersetNode.autoscaling.maxReplicas | int | `100` | |
|
||||
@@ -305,11 +366,13 @@ Alternatively, perform a fresh install. This is a one-time migration; subsequent
|
||||
| supersetWebsockets.deploymentAnnotations | object | `{}` | |
|
||||
| supersetWebsockets.enabled | bool | `false` | This is only required if you intend to use `GLOBAL_ASYNC_QUERIES` in `ws` mode see https://superset.apache.org/docs/contributing/misc#async-chart-queries |
|
||||
| supersetWebsockets.extraContainers | list | `[]` | Launch additional containers into supersetWebsockets pods |
|
||||
| supersetWebsockets.extraInitContainers | list | `[]` | Extra init containers appended after supersetWebsockets initContainers |
|
||||
| supersetWebsockets.image.pullPolicy | string | `"IfNotPresent"` | |
|
||||
| supersetWebsockets.image.repository | string | `"oneacrefund/superset-websocket"` | There is no official image (yet), this one is community-supported |
|
||||
| supersetWebsockets.image.tag | string | `"latest"` | |
|
||||
| supersetWebsockets.ingress.path | string | `"/ws"` | |
|
||||
| supersetWebsockets.ingress.pathType | string | `"Prefix"` | |
|
||||
| supersetWebsockets.initContainers | list | a container waiting for redis | List of initContainers |
|
||||
| supersetWebsockets.livenessProbe.failureThreshold | int | `3` | |
|
||||
| supersetWebsockets.livenessProbe.httpGet.path | string | `"/health"` | |
|
||||
| supersetWebsockets.livenessProbe.httpGet.port | string | `"ws"` | |
|
||||
|
||||
@@ -761,3 +761,9 @@ app.kubernetes.io/name: {{ include "superset.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/component: worker
|
||||
{{- end }}
|
||||
|
||||
{{- define "supersetMcp.selectorLabels" -}}
|
||||
app.kubernetes.io/name: {{ include "superset.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/component: mcp
|
||||
{{- end }}
|
||||
|
||||
197
helm/superset/templates/deployment-mcp.yaml
Normal file
197
helm/superset/templates/deployment-mcp.yaml
Normal file
@@ -0,0 +1,197 @@
|
||||
{{/*
|
||||
|
||||
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.
|
||||
|
||||
*/}}
|
||||
|
||||
{{- if .Values.supersetMcp.enabled -}}
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ template "superset.fullname" . }}-mcp
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "superset.componentLabels" (dict "component" "mcp" "root" .) | nindent 4 }}
|
||||
{{- if .Values.supersetMcp.deploymentAnnotations }}
|
||||
annotations: {{- toYaml .Values.supersetMcp.deploymentAnnotations | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
replicas: {{ .Values.supersetMcp.replicaCount }}
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "supersetMcp.selectorLabels" . | nindent 6 }}
|
||||
{{- if .Values.supersetMcp.strategy }}
|
||||
strategy: {{- toYaml .Values.supersetMcp.strategy | nindent 4 }}
|
||||
{{- end }}
|
||||
template:
|
||||
metadata:
|
||||
annotations:
|
||||
checksum/superset_config.py: {{ include "superset.config" . | sha256sum }}
|
||||
checksum/superset_bootstrap.sh: {{ tpl .Values.bootstrapScript . | sha256sum }}
|
||||
checksum/database: {{ .Values.database | toYaml | sha256sum }}
|
||||
checksum/redis: {{ .Values.cache | toYaml | sha256sum }}
|
||||
checksum/config: {{ .Values.config | toYaml | sha256sum }}
|
||||
checksum/featureFlags: {{ .Values.featureFlags | toYaml | sha256sum }}
|
||||
checksum/extraConfigs: {{ .Values.extraConfigs | toYaml | sha256sum }}
|
||||
checksum/extraSecrets: {{ .Values.extraSecrets | toYaml | sha256sum }}
|
||||
checksum/extraSecretEnv: {{ .Values.extraSecretEnv | toYaml | sha256sum }}
|
||||
checksum/configOverrides: {{ .Values.configOverrides | toYaml | sha256sum }}
|
||||
checksum/configOverridesFiles: {{ .Values.configOverridesFiles | toYaml | sha256sum }}
|
||||
{{- if .Values.supersetMcp.forceReload }}
|
||||
# Optionally force the thing to reload
|
||||
force-reload: {{ randAlphaNum 5 | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.supersetMcp.podAnnotations }}
|
||||
{{- toYaml .Values.supersetMcp.podAnnotations | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.globalPodAnnotations }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
labels:
|
||||
{{- include "supersetMcp.selectorLabels" . | nindent 8 }}
|
||||
{{- if .Values.supersetMcp.podLabels }}
|
||||
{{- toYaml .Values.supersetMcp.podLabels | nindent 8 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- if .Values.supersetMcp.deploymentAdditionalPodSpec }}
|
||||
{{- tpl (toYaml .Values.supersetMcp.deploymentAdditionalPodSpec) . | nindent 6 }}
|
||||
{{- end }}
|
||||
{{- if or (.Values.serviceAccount.create) (.Values.serviceAccountName) }}
|
||||
serviceAccountName: {{ template "superset.serviceAccountName" . }}
|
||||
{{- end }}
|
||||
securityContext:
|
||||
runAsUser: {{ .Values.runAsUser }}
|
||||
{{- if .Values.supersetMcp.podSecurityContext }}
|
||||
{{- toYaml .Values.supersetMcp.podSecurityContext | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- if or .Values.supersetMcp.initContainers .Values.supersetMcp.extraInitContainers }}
|
||||
initContainers:
|
||||
{{- if .Values.supersetMcp.initContainers }}
|
||||
{{- tpl (toYaml .Values.supersetMcp.initContainers) . | nindent 6 }}
|
||||
{{- end }}
|
||||
{{- if .Values.supersetMcp.extraInitContainers }}
|
||||
{{- tpl (toYaml .Values.supersetMcp.extraInitContainers) . | nindent 6 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- with .Values.hostAliases }}
|
||||
hostAliases: {{- toYaml . | nindent 6 }}
|
||||
{{- end }}
|
||||
containers:
|
||||
- name: "{{ .Chart.Name }}-mcp"
|
||||
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
|
||||
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||
{{- if .Values.supersetMcp.containerSecurityContext }}
|
||||
securityContext: {{- toYaml .Values.supersetMcp.containerSecurityContext | nindent 12 }}
|
||||
{{- end }}
|
||||
command: {{ tpl (toJson .Values.supersetMcp.command) . }}
|
||||
env:
|
||||
{{- range $key, $value := .Values.extraEnv }}
|
||||
- name: {{ $key | quote}}
|
||||
value: {{ $value | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.extraEnvRaw }}
|
||||
{{- toYaml .Values.extraEnvRaw | nindent 12 }}
|
||||
{{- end }}
|
||||
envFrom:
|
||||
- secretRef:
|
||||
name: {{ tpl .Values.envFromSecret . | quote }}
|
||||
{{- range .Values.envFromSecrets }}
|
||||
- secretRef:
|
||||
name: {{ tpl . $ | quote }}
|
||||
{{- end }}
|
||||
ports:
|
||||
- name: mcp
|
||||
containerPort: {{ .Values.supersetMcp.service.port }}
|
||||
protocol: TCP
|
||||
volumeMounts:
|
||||
- name: superset-config
|
||||
mountPath: {{ .Values.configMountPath | quote }}
|
||||
readOnly: true
|
||||
{{- if .Values.extraConfigs }}
|
||||
- name: superset-extra-config
|
||||
mountPath: {{ .Values.extraConfigMountPath | quote }}
|
||||
readOnly: true
|
||||
{{- end }}
|
||||
{{- with .Values.extraVolumeMounts }}
|
||||
{{- tpl (toYaml .) $ | nindent 12 -}}
|
||||
{{- end }}
|
||||
{{- if .Values.supersetMcp.startupProbe }}
|
||||
startupProbe: {{- .Values.supersetMcp.startupProbe | toYaml | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- if .Values.supersetMcp.readinessProbe }}
|
||||
readinessProbe: {{- .Values.supersetMcp.readinessProbe | toYaml | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- if .Values.supersetMcp.livenessProbe }}
|
||||
livenessProbe: {{- .Values.supersetMcp.livenessProbe | toYaml | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- if .Values.supersetMcp.lifecycle }}
|
||||
lifecycle: {{- .Values.supersetMcp.lifecycle | toYaml | nindent 12 }}
|
||||
{{- end }}
|
||||
resources:
|
||||
{{- if .Values.supersetMcp.resources }}
|
||||
{{- toYaml .Values.supersetMcp.resources | nindent 12 }}
|
||||
{{- else }}
|
||||
{{- toYaml .Values.resources | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- if .Values.supersetMcp.extraContainers }}
|
||||
{{- tpl (toYaml .Values.supersetMcp.extraContainers) . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.nodeSelector }}
|
||||
nodeSelector: {{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- if or .Values.affinity .Values.supersetMcp.affinity }}
|
||||
affinity:
|
||||
{{- with .Values.affinity }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.supersetMcp.affinity }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if .Values.supersetMcp.priorityClassName }}
|
||||
priorityClassName: {{ .Values.supersetMcp.priorityClassName }}
|
||||
{{- end }}
|
||||
{{- if or .Values.topologySpreadConstraints .Values.supersetMcp.topologySpreadConstraints }}
|
||||
topologySpreadConstraints:
|
||||
{{- with .Values.topologySpreadConstraints }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.supersetMcp.topologySpreadConstraints }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- with .Values.tolerations }}
|
||||
tolerations: {{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- if .Values.supersetMcp.terminationGracePeriodSeconds }}
|
||||
terminationGracePeriodSeconds: {{ .Values.supersetMcp.terminationGracePeriodSeconds }}
|
||||
{{- end }}
|
||||
{{- if .Values.imagePullSecrets }}
|
||||
imagePullSecrets: {{- toYaml .Values.imagePullSecrets | nindent 8 }}
|
||||
{{- end }}
|
||||
volumes:
|
||||
- name: superset-config
|
||||
secret:
|
||||
secretName: {{ tpl .Values.configFromSecret . }}
|
||||
{{- if .Values.extraConfigs }}
|
||||
- name: superset-extra-config
|
||||
configMap:
|
||||
name: {{ template "superset.fullname" . }}-extra-config
|
||||
{{- end }}
|
||||
{{- with .Values.extraVolumes }}
|
||||
{{- tpl (toYaml .) $ | nindent 8 -}}
|
||||
{{- end }}
|
||||
{{- end -}}
|
||||
@@ -64,6 +64,15 @@ spec:
|
||||
{{- if .Values.supersetWebsockets.podSecurityContext }}
|
||||
{{- toYaml .Values.supersetWebsockets.podSecurityContext | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- if or .Values.supersetWebsockets.initContainers .Values.supersetWebsockets.extraInitContainers }}
|
||||
initContainers:
|
||||
{{- if .Values.supersetWebsockets.initContainers }}
|
||||
{{- tpl (toYaml .Values.supersetWebsockets.initContainers) . | nindent 6 }}
|
||||
{{- end }}
|
||||
{{- if .Values.supersetWebsockets.extraInitContainers }}
|
||||
{{- tpl (toYaml .Values.supersetWebsockets.extraInitContainers) . | nindent 6 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- with .Values.hostAliases }}
|
||||
hostAliases: {{- toYaml . | nindent 6 }}
|
||||
{{- end }}
|
||||
|
||||
83
helm/superset/templates/httproute.yaml
Normal file
83
helm/superset/templates/httproute.yaml
Normal file
@@ -0,0 +1,83 @@
|
||||
{{/*
|
||||
|
||||
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.
|
||||
|
||||
*/}}
|
||||
|
||||
{{- if .Values.httproute.enabled -}}
|
||||
{{- $fullName := include "superset.fullname" . -}}
|
||||
apiVersion: {{ .Values.httproute.apiVersion | default "gateway.networking.k8s.io/v1" }}
|
||||
kind: HTTPRoute
|
||||
metadata:
|
||||
name: {{ $fullName }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
app: {{ template "superset.name" . }}
|
||||
chart: {{ template "superset.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
{{- if .Values.extraLabels }}
|
||||
{{- toYaml .Values.extraLabels | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- with .Values.httproute.labels }}
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- with .Values.httproute.annotations }}
|
||||
annotations: {{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- with .Values.httproute.parentRefs }}
|
||||
parentRefs:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- with .Values.httproute.hostnames }}
|
||||
hostnames:
|
||||
{{- tpl (toYaml .) $ | nindent 4 }}
|
||||
{{- end }}
|
||||
rules:
|
||||
{{- range .Values.httproute.rules }}
|
||||
- backendRefs:
|
||||
- group: ''
|
||||
kind: Service
|
||||
name: {{ $fullName }}
|
||||
port: {{ $.Values.service.port }}
|
||||
weight: {{ .weight | default 1 }}
|
||||
{{- with .filters }}
|
||||
filters:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .matches }}
|
||||
matches:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .timeouts }}
|
||||
timeouts:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if .Values.supersetWebsockets.enabled }}
|
||||
- backendRefs:
|
||||
- group: ''
|
||||
kind: Service
|
||||
name: {{ $fullName }}-ws
|
||||
port: {{ .Values.supersetWebsockets.service.port }}
|
||||
weight: 1
|
||||
matches:
|
||||
- path:
|
||||
type: PathPrefix
|
||||
value: {{ .Values.supersetWebsockets.ingress.path }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -64,6 +64,15 @@ spec:
|
||||
port:
|
||||
name: ws
|
||||
{{- end }}
|
||||
{{- if and $.Values.supersetMcp.enabled $.Values.supersetMcp.ingress.enabled }}
|
||||
- path: {{ $.Values.supersetMcp.ingress.path }}
|
||||
pathType: {{ $.Values.supersetMcp.ingress.pathType }}
|
||||
backend:
|
||||
service:
|
||||
name: "{{ template "superset.fullname" $ }}-mcp"
|
||||
port:
|
||||
name: mcp
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if .Values.ingress.extraHostsRaw }}
|
||||
{{- toYaml .Values.ingress.extraHostsRaw | nindent 4 }}
|
||||
|
||||
42
helm/superset/templates/pdb-mcp.yaml
Normal file
42
helm/superset/templates/pdb-mcp.yaml
Normal file
@@ -0,0 +1,42 @@
|
||||
{{/*
|
||||
|
||||
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.
|
||||
|
||||
*/}}
|
||||
|
||||
{{- with .Values.supersetMcp.podDisruptionBudget }}
|
||||
{{- if .enabled -}}
|
||||
{{- if and .minAvailable .maxUnavailable }}
|
||||
{{- fail "Only one of minAvailable or maxUnavailable should be set" }}
|
||||
{{- end}}
|
||||
apiVersion: policy/v1
|
||||
kind: PodDisruptionBudget
|
||||
metadata:
|
||||
name: {{ include "superset.fullname" $ }}-mcp-pdb
|
||||
labels:
|
||||
{{- include "superset.componentLabels" (dict "component" "mcp" "root" $) | nindent 4 }}
|
||||
spec:
|
||||
{{- if .minAvailable }}
|
||||
minAvailable: {{ .minAvailable }}
|
||||
{{- end }}
|
||||
{{- if .maxUnavailable }}
|
||||
maxUnavailable: {{ .maxUnavailable }}
|
||||
{{- end }}
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "supersetMcp.selectorLabels" $ | nindent 6 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
46
helm/superset/templates/service-mcp.yaml
Normal file
46
helm/superset/templates/service-mcp.yaml
Normal file
@@ -0,0 +1,46 @@
|
||||
{{/*
|
||||
|
||||
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.
|
||||
|
||||
*/}}
|
||||
|
||||
{{- if .Values.supersetMcp.enabled }}
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: "{{ template "superset.fullname" . }}-mcp"
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "superset.componentLabels" (dict "component" "mcp" "root" .) | nindent 4 }}
|
||||
{{- with .Values.supersetMcp.service.annotations }}
|
||||
annotations: {{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
type: {{ .Values.supersetMcp.service.type }}
|
||||
ports:
|
||||
- port: {{ .Values.supersetMcp.service.port }}
|
||||
targetPort: mcp
|
||||
protocol: TCP
|
||||
name: mcp
|
||||
{{- if and (or (eq .Values.supersetMcp.service.type "NodePort") (eq .Values.supersetMcp.service.type "LoadBalancer")) (not (empty .Values.supersetMcp.service.nodePort.http)) }}
|
||||
nodePort: {{ .Values.supersetMcp.service.nodePort.http }}
|
||||
{{- end }}
|
||||
selector:
|
||||
{{- include "supersetMcp.selectorLabels" . | nindent 4 }}
|
||||
{{- if .Values.supersetMcp.service.loadBalancerIP }}
|
||||
loadBalancerIP: {{ .Values.supersetMcp.service.loadBalancerIP }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -21,6 +21,7 @@ templates:
|
||||
- deployment-beat.yaml
|
||||
- deployment-flower.yaml
|
||||
- deployment-ws.yaml
|
||||
- deployment-mcp.yaml
|
||||
tests:
|
||||
- it: main deployment has new config checksums, not the old connections checksum
|
||||
template: deployment.yaml
|
||||
@@ -130,3 +131,24 @@ tests:
|
||||
- equal:
|
||||
path: 'spec.template.metadata.annotations.team'
|
||||
value: data
|
||||
- it: mcp deployment has config and database checksums
|
||||
template: deployment-mcp.yaml
|
||||
set:
|
||||
supersetMcp:
|
||||
enabled: true
|
||||
asserts:
|
||||
- exists:
|
||||
path: 'spec.template.metadata.annotations["checksum/database"]'
|
||||
- exists:
|
||||
path: 'spec.template.metadata.annotations["checksum/config"]'
|
||||
- it: mcp deployment applies globalPodAnnotations
|
||||
template: deployment-mcp.yaml
|
||||
set:
|
||||
supersetMcp:
|
||||
enabled: true
|
||||
globalPodAnnotations:
|
||||
team: data
|
||||
asserts:
|
||||
- equal:
|
||||
path: 'spec.template.metadata.annotations.team'
|
||||
value: data
|
||||
|
||||
@@ -20,6 +20,8 @@ templates:
|
||||
- deployment-worker.yaml
|
||||
- deployment-beat.yaml
|
||||
- deployment-flower.yaml
|
||||
- deployment-ws.yaml
|
||||
- deployment-mcp.yaml
|
||||
- init-job.yaml
|
||||
tests:
|
||||
- it: renders only the default wait-for container by default
|
||||
@@ -150,6 +152,42 @@ tests:
|
||||
path: spec.template.spec.initContainers[1].name
|
||||
value: prepare-assets
|
||||
|
||||
- it: appends websockets extraInitContainers after wait-for-redis
|
||||
template: deployment-ws.yaml
|
||||
set:
|
||||
supersetWebsockets.enabled: true
|
||||
supersetWebsockets.extraInitContainers:
|
||||
- name: prepare-assets
|
||||
image: busybox
|
||||
asserts:
|
||||
- lengthEqual:
|
||||
path: spec.template.spec.initContainers
|
||||
count: 2
|
||||
- equal:
|
||||
path: spec.template.spec.initContainers[0].name
|
||||
value: wait-for-redis
|
||||
- equal:
|
||||
path: spec.template.spec.initContainers[1].name
|
||||
value: prepare-assets
|
||||
|
||||
- it: appends mcp extraInitContainers after wait-for-postgres-redis
|
||||
template: deployment-mcp.yaml
|
||||
set:
|
||||
supersetMcp.enabled: true
|
||||
supersetMcp.extraInitContainers:
|
||||
- name: prepare-assets
|
||||
image: busybox
|
||||
asserts:
|
||||
- lengthEqual:
|
||||
path: spec.template.spec.initContainers
|
||||
count: 2
|
||||
- equal:
|
||||
path: spec.template.spec.initContainers[0].name
|
||||
value: wait-for-postgres-redis
|
||||
- equal:
|
||||
path: spec.template.spec.initContainers[1].name
|
||||
value: prepare-assets
|
||||
|
||||
- it: appends init job extraInitContainers after wait-for-postgres
|
||||
template: init-job.yaml
|
||||
set:
|
||||
|
||||
@@ -21,9 +21,11 @@ templates:
|
||||
- deployment-beat.yaml
|
||||
- deployment-flower.yaml
|
||||
- deployment-ws.yaml
|
||||
- deployment-mcp.yaml
|
||||
- service.yaml
|
||||
- service-ws.yaml
|
||||
- service-flower.yaml
|
||||
- service-mcp.yaml
|
||||
- init-job.yaml
|
||||
- ingress.yaml
|
||||
- configmap-superset.yaml
|
||||
@@ -34,6 +36,7 @@ templates:
|
||||
- pdb-beat.yaml
|
||||
- pdb-flower.yaml
|
||||
- pdb-ws.yaml
|
||||
- pdb-mcp.yaml
|
||||
|
||||
# These tests validate that Kubernetes recommended labels are consistently applied
|
||||
# across all chart resources per https://kubernetes.io/docs/concepts/overview/working-with-objects/common-labels/
|
||||
@@ -185,6 +188,36 @@ tests:
|
||||
path: metadata.labels["app.kubernetes.io/component"]
|
||||
value: websocket
|
||||
|
||||
# =============================================================================
|
||||
# MCP Deployment Labels
|
||||
# =============================================================================
|
||||
- it: should have all recommended labels on mcp deployment
|
||||
template: deployment-mcp.yaml
|
||||
set:
|
||||
supersetMcp.enabled: true
|
||||
asserts:
|
||||
- isNotNull:
|
||||
path: metadata.labels["app.kubernetes.io/name"]
|
||||
- isNotNull:
|
||||
path: metadata.labels["app.kubernetes.io/instance"]
|
||||
- isNotNull:
|
||||
path: metadata.labels["app.kubernetes.io/version"]
|
||||
- isNotNull:
|
||||
path: metadata.labels["app.kubernetes.io/managed-by"]
|
||||
- isNotNull:
|
||||
path: metadata.labels["app.kubernetes.io/part-of"]
|
||||
- isNotNull:
|
||||
path: metadata.labels["app.kubernetes.io/component"]
|
||||
|
||||
- it: should have correct component label on mcp deployment
|
||||
template: deployment-mcp.yaml
|
||||
set:
|
||||
supersetMcp.enabled: true
|
||||
asserts:
|
||||
- equal:
|
||||
path: metadata.labels["app.kubernetes.io/component"]
|
||||
value: mcp
|
||||
|
||||
# =============================================================================
|
||||
# Service Labels
|
||||
# =============================================================================
|
||||
@@ -249,6 +282,27 @@ tests:
|
||||
path: metadata.labels["app.kubernetes.io/component"]
|
||||
value: flower
|
||||
|
||||
- it: should have all recommended labels on mcp service
|
||||
template: service-mcp.yaml
|
||||
set:
|
||||
supersetMcp.enabled: true
|
||||
asserts:
|
||||
- isNotNull:
|
||||
path: metadata.labels["app.kubernetes.io/name"]
|
||||
- isNotNull:
|
||||
path: metadata.labels["app.kubernetes.io/instance"]
|
||||
- isNotNull:
|
||||
path: metadata.labels["app.kubernetes.io/component"]
|
||||
|
||||
- it: should have correct component label on mcp service
|
||||
template: service-mcp.yaml
|
||||
set:
|
||||
supersetMcp.enabled: true
|
||||
asserts:
|
||||
- equal:
|
||||
path: metadata.labels["app.kubernetes.io/component"]
|
||||
value: mcp
|
||||
|
||||
# =============================================================================
|
||||
# Init Job Labels
|
||||
# =============================================================================
|
||||
@@ -366,6 +420,51 @@ tests:
|
||||
path: spec.template.metadata.labels["app.kubernetes.io/component"]
|
||||
value: worker
|
||||
|
||||
- it: should set selector matchLabels to concrete values on mcp deployment
|
||||
template: deployment-mcp.yaml
|
||||
set:
|
||||
supersetMcp.enabled: true
|
||||
asserts:
|
||||
- equal:
|
||||
path: spec.selector.matchLabels["app.kubernetes.io/name"]
|
||||
value: superset
|
||||
- equal:
|
||||
path: spec.selector.matchLabels["app.kubernetes.io/instance"]
|
||||
value: RELEASE-NAME
|
||||
- equal:
|
||||
path: spec.selector.matchLabels["app.kubernetes.io/component"]
|
||||
value: mcp
|
||||
|
||||
- it: should match pod template labels to the selector on mcp deployment
|
||||
template: deployment-mcp.yaml
|
||||
set:
|
||||
supersetMcp.enabled: true
|
||||
asserts:
|
||||
- equal:
|
||||
path: spec.template.metadata.labels["app.kubernetes.io/name"]
|
||||
value: superset
|
||||
- equal:
|
||||
path: spec.template.metadata.labels["app.kubernetes.io/instance"]
|
||||
value: RELEASE-NAME
|
||||
- equal:
|
||||
path: spec.template.metadata.labels["app.kubernetes.io/component"]
|
||||
value: mcp
|
||||
|
||||
- it: should set selector to concrete values on mcp service
|
||||
template: service-mcp.yaml
|
||||
set:
|
||||
supersetMcp.enabled: true
|
||||
asserts:
|
||||
- equal:
|
||||
path: spec.selector["app.kubernetes.io/name"]
|
||||
value: superset
|
||||
- equal:
|
||||
path: spec.selector["app.kubernetes.io/instance"]
|
||||
value: RELEASE-NAME
|
||||
- equal:
|
||||
path: spec.selector["app.kubernetes.io/component"]
|
||||
value: mcp
|
||||
|
||||
# =============================================================================
|
||||
# Extra Labels Support
|
||||
# =============================================================================
|
||||
@@ -505,6 +604,26 @@ tests:
|
||||
path: spec.selector.matchLabels["app.kubernetes.io/component"]
|
||||
value: websocket
|
||||
|
||||
- it: should have recommended labels and matching selector on mcp pdb
|
||||
template: pdb-mcp.yaml
|
||||
set:
|
||||
supersetMcp.enabled: true
|
||||
supersetMcp.podDisruptionBudget.enabled: true
|
||||
supersetMcp.podDisruptionBudget.maxUnavailable: null
|
||||
asserts:
|
||||
- equal:
|
||||
path: metadata.labels["app.kubernetes.io/instance"]
|
||||
value: RELEASE-NAME
|
||||
- equal:
|
||||
path: metadata.labels["app.kubernetes.io/component"]
|
||||
value: mcp
|
||||
- equal:
|
||||
path: spec.selector.matchLabels["app.kubernetes.io/instance"]
|
||||
value: RELEASE-NAME
|
||||
- equal:
|
||||
path: spec.selector.matchLabels["app.kubernetes.io/component"]
|
||||
value: mcp
|
||||
|
||||
- it: should use recommended labels on init job pod template
|
||||
template: init-job.yaml
|
||||
set:
|
||||
|
||||
@@ -246,6 +246,40 @@ ingress:
|
||||
# hosts:
|
||||
# - chart-example.local
|
||||
|
||||
# -- Gateway API HTTPRoute for exposing Superset via a Gateway.
|
||||
# Requires the Gateway API CRDs (gateway.networking.k8s.io/v1) installed in the cluster.
|
||||
# @default -- see `values.yaml`
|
||||
httproute:
|
||||
enabled: false
|
||||
# -- HTTPRoute apiVersion. Override to gateway.networking.k8s.io/v1beta1 for
|
||||
# older Gateway API installations that have not promoted HTTPRoute to v1.
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
# -- Additional labels to add to the HTTPRoute
|
||||
labels: {}
|
||||
# -- Annotations to add to the HTTPRoute
|
||||
annotations: {}
|
||||
# -- Gateways this HTTPRoute attaches to
|
||||
parentRefs: []
|
||||
# - name: my-gateway
|
||||
# namespace: gateway-system
|
||||
# sectionName: https
|
||||
# -- Hostnames that match against the HTTP Host header (templated)
|
||||
hostnames: []
|
||||
# - chart-example.local
|
||||
# -- Routing rules. Each rule is backed by the Superset service. Set `weight`
|
||||
# per rule to leave room for traffic splitting (defaults to 1). When
|
||||
# `supersetWebsockets.enabled` is true, an extra rule routing
|
||||
# `supersetWebsockets.ingress.path` to the `-ws` service is appended
|
||||
# automatically, mirroring the ingress behavior.
|
||||
rules:
|
||||
- matches:
|
||||
- path:
|
||||
type: PathPrefix
|
||||
value: /
|
||||
# weight: 1
|
||||
# filters: []
|
||||
# timeouts: {}
|
||||
|
||||
resources: {}
|
||||
# We usually recommend not to specify default resources and to leave this as a conscious
|
||||
# choice for the user. This also increases chances charts run on environments with little
|
||||
@@ -867,6 +901,38 @@ supersetWebsockets:
|
||||
# -- (int)
|
||||
http: nil
|
||||
command: []
|
||||
# -- List of initContainers
|
||||
# @default -- a container waiting for redis
|
||||
initContainers:
|
||||
- name: wait-for-redis
|
||||
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
|
||||
imagePullPolicy: "{{ .Values.image.pullPolicy }}"
|
||||
envFrom:
|
||||
- secretRef:
|
||||
name: "{{ tpl .Values.envFromSecret . }}"
|
||||
command:
|
||||
- /bin/bash
|
||||
- -c
|
||||
- |
|
||||
# See supersetNode.initContainers for the rationale.
|
||||
SECONDS=0
|
||||
until (exec 3<>/dev/tcp/"$REDIS_HOST"/"$REDIS_PORT") 2>/dev/null; do
|
||||
if [ "$SECONDS" -ge 120 ]; then
|
||||
echo "timeout waiting for redis at $REDIS_HOST:$REDIS_PORT after 120s" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "waiting for redis at $REDIS_HOST:$REDIS_PORT (elapsed ${SECONDS}s)"
|
||||
sleep 2
|
||||
done
|
||||
echo "redis at $REDIS_HOST:$REDIS_PORT is up"
|
||||
resources:
|
||||
limits:
|
||||
memory: "256Mi"
|
||||
requests:
|
||||
cpu: "250m"
|
||||
memory: "128Mi"
|
||||
# -- Extra init containers appended after supersetWebsockets initContainers
|
||||
extraInitContainers: []
|
||||
resources: {}
|
||||
# -- Launch additional containers into supersetWebsockets pods
|
||||
extraContainers: []
|
||||
@@ -912,6 +978,144 @@ supersetWebsockets:
|
||||
# -- Set priorityClassName for supersetWebsockets pods
|
||||
priorityClassName: ~
|
||||
|
||||
|
||||
supersetMcp:
|
||||
# -- Enables the Superset MCP Server. To expose it via the shared ingress at /mcp,
|
||||
# also set supersetMcp.ingress.enabled=true.
|
||||
# WARNING: this requires fastMCP to be installed, which can be done by installing `apache-superset[fastmcp]`
|
||||
enabled: false
|
||||
replicaCount: 1
|
||||
# -- Sets the [pod disruption budget](https://kubernetes.io/docs/tasks/run-application/configure-pdb/) for supersetMcp pods
|
||||
podDisruptionBudget:
|
||||
# -- Whether the pod disruption budget should be created
|
||||
enabled: false
|
||||
# -- If set, maxUnavailable must not be set - see https://kubernetes.io/docs/tasks/run-application/configure-pdb/\#specifying-a-poddisruptionbudget
|
||||
minAvailable: 1
|
||||
# -- If set, minAvailable must not be set - see https://kubernetes.io/docs/tasks/run-application/configure-pdb/\#specifying-a-poddisruptionbudget
|
||||
maxUnavailable: 1
|
||||
# -- Command
|
||||
# @default -- a `superset mcp run` command
|
||||
command:
|
||||
- "/bin/sh"
|
||||
- "-c"
|
||||
- ". {{ .Values.configMountPath }}/superset_bootstrap.sh; superset mcp run --host 0.0.0.0 --port {{ .Values.supersetMcp.service.port }}"
|
||||
# -- If true, forces deployment to reload on each upgrade
|
||||
forceReload: false
|
||||
ingress:
|
||||
# -- If true, the MCP server will be exposed via the ingress /mcp subpath
|
||||
enabled: false
|
||||
path: /mcp
|
||||
pathType: Prefix
|
||||
service:
|
||||
type: ClusterIP
|
||||
annotations: {}
|
||||
loadBalancerIP: ~
|
||||
port: 5008
|
||||
nodePort:
|
||||
# -- (int)
|
||||
http: nil
|
||||
startupProbe:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: mcp
|
||||
initialDelaySeconds: 15
|
||||
timeoutSeconds: 3
|
||||
failureThreshold: 60
|
||||
periodSeconds: 5
|
||||
successThreshold: 1
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: mcp
|
||||
initialDelaySeconds: 15
|
||||
timeoutSeconds: 3
|
||||
failureThreshold: 3
|
||||
periodSeconds: 15
|
||||
successThreshold: 1
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: mcp
|
||||
initialDelaySeconds: 15
|
||||
timeoutSeconds: 3
|
||||
failureThreshold: 3
|
||||
periodSeconds: 15
|
||||
successThreshold: 1
|
||||
# -- List of init containers
|
||||
# @default -- a container waiting for postgres and redis
|
||||
initContainers:
|
||||
- name: wait-for-postgres-redis
|
||||
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
|
||||
imagePullPolicy: "{{ .Values.image.pullPolicy }}"
|
||||
envFrom:
|
||||
- secretRef:
|
||||
name: "{{ tpl .Values.envFromSecret . }}"
|
||||
command:
|
||||
- /bin/bash
|
||||
- -c
|
||||
- |
|
||||
# See supersetNode.initContainers for the rationale.
|
||||
SECONDS=0
|
||||
wait_for() {
|
||||
local host=$1 port=$2 name=$3
|
||||
until (exec 3<>/dev/tcp/"$host"/"$port") 2>/dev/null; do
|
||||
if [ "$SECONDS" -ge 120 ]; then
|
||||
echo "timeout waiting for $name at $host:$port after 120s" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "waiting for $name at $host:$port (elapsed ${SECONDS}s)"
|
||||
sleep 2
|
||||
done
|
||||
echo "$name at $host:$port is up"
|
||||
}
|
||||
wait_for "$DB_HOST" "$DB_PORT" postgres
|
||||
wait_for "$REDIS_HOST" "$REDIS_PORT" redis
|
||||
resources:
|
||||
limits:
|
||||
memory: "256Mi"
|
||||
requests:
|
||||
cpu: "250m"
|
||||
memory: "128Mi"
|
||||
# -- Extra init containers appended after supersetMcp initContainers
|
||||
extraInitContainers: []
|
||||
# -- Launch additional containers into supersetMcp pods
|
||||
extraContainers: []
|
||||
# -- Annotations to be added to supersetMcp deployment
|
||||
deploymentAnnotations: {}
|
||||
# -- Labels to be added to supersetMcp deployment
|
||||
deploymentLabels: {}
|
||||
# -- Custom pod spec to be added to supersetMcp deployment
|
||||
deploymentAdditionalPodSpec: {}
|
||||
# -- Affinity to be added to supersetMcp deployment
|
||||
affinity: {}
|
||||
# -- TopologySpreadConstrains to be added to supersetMcp deployments
|
||||
topologySpreadConstraints: []
|
||||
# -- Annotations to be added to supersetMcp pods
|
||||
podAnnotations: {}
|
||||
# -- Labels to be added to supersetMcp pods
|
||||
podLabels: {}
|
||||
strategy: {}
|
||||
# type: RollingUpdate
|
||||
# rollingUpdate:
|
||||
# maxSurge: 25%
|
||||
# maxUnavailable: 25%
|
||||
# -- Container lifecycle hooks for the worker pod
|
||||
lifecycle: {}
|
||||
# -- Pod termination grace period (seconds) for the worker pod so in-flight tasks can drain before SIGKILL
|
||||
terminationGracePeriodSeconds: ~
|
||||
# -- Resource settings for the supersetMcp pods - these settings overwrite might existing values from the global resources object defined above.
|
||||
resources: {}
|
||||
# limits:
|
||||
# cpu: 100m
|
||||
# memory: 128Mi
|
||||
# requests:
|
||||
# cpu: 100m
|
||||
# memory: 128Mi
|
||||
podSecurityContext: {}
|
||||
containerSecurityContext: {}
|
||||
# -- Set priorityClassName for supersetMcp pods
|
||||
priorityClassName: ~
|
||||
|
||||
init:
|
||||
# Configure resources
|
||||
# Warning: fab command consumes a lot of ram and can
|
||||
|
||||
@@ -24,13 +24,12 @@ name = "apache_superset"
|
||||
description = "A modern, enterprise-ready business intelligence web application"
|
||||
readme = "README.md"
|
||||
dynamic = ["version", "scripts", "entry-points"]
|
||||
requires-python = ">=3.10"
|
||||
requires-python = ">=3.11"
|
||||
license = { file="LICENSE.txt" }
|
||||
authors = [
|
||||
{ name = "Apache Software Foundation", email = "dev@superset.apache.org" },
|
||||
]
|
||||
classifiers = [
|
||||
"Programming Language :: Python :: 3.10",
|
||||
"Programming Language :: Python :: 3.11",
|
||||
"Programming Language :: Python :: 3.12",
|
||||
]
|
||||
@@ -63,7 +62,7 @@ dependencies = [
|
||||
"flask-session>=0.4.0, <1.0",
|
||||
"flask-wtf>=1.3.0, <2.0",
|
||||
"geopy",
|
||||
"greenlet<=3.5.1, >=3.5.1",
|
||||
"greenlet<=3.5.3, >=3.5.3",
|
||||
"gunicorn>=26.0.0, <27; sys_platform != 'win32'",
|
||||
"hashids>=1.3.1, <2",
|
||||
# holidays>=0.45 required for security fix
|
||||
@@ -84,7 +83,7 @@ dependencies = [
|
||||
"packaging",
|
||||
# --------------------------
|
||||
# pandas and related (wanting pandas[performance] without numba as it's 100+MB and not needed)
|
||||
"pandas[excel]>=2.1.4, <2.4",
|
||||
"pandas[excel]>=2.3.3, <2.4",
|
||||
"bottleneck", # recommended performance dependency for pandas, see https://pandas.pydata.org/docs/getting_started/install.html#performance-dependencies-recommended
|
||||
# --------------------------
|
||||
"parsedatetime",
|
||||
@@ -113,7 +112,7 @@ dependencies = [
|
||||
"sqlglot>=30.12.0, <31",
|
||||
# newer pandas needs 0.9+
|
||||
"tabulate>=0.10.0, <1.0",
|
||||
"typing-extensions>=4, <5",
|
||||
"typing-extensions>=4.16.0, <5",
|
||||
"waitress; sys_platform == 'win32'",
|
||||
"watchdog>=6.0.0",
|
||||
"wtforms>=3.2.2, <4",
|
||||
@@ -126,7 +125,7 @@ dependencies = [
|
||||
athena = ["pyathena[pandas]>=2, <4"]
|
||||
aurora-data-api = ["preset-sqlalchemy-aurora-data-api>=0.2.8,<0.3"]
|
||||
bigquery = [
|
||||
"pandas-gbq>=0.19.1",
|
||||
"pandas-gbq>=0.35.0",
|
||||
"sqlalchemy-bigquery>=1.17.0",
|
||||
"google-cloud-bigquery>=3.42.1",
|
||||
]
|
||||
@@ -149,11 +148,15 @@ dremio = ["sqlalchemy-dremio>=1.2.1, <4"]
|
||||
drill = ["sqlalchemy-drill>=1.1.10, <2"]
|
||||
druid = ["pydruid>=0.6.5,<0.7"]
|
||||
duckdb = ["duckdb>=1.5.4,<2", "duckdb-engine>=0.17.0"]
|
||||
dynamodb = ["pydynamodb>=0.4.2"]
|
||||
dynamodb = ["pydynamodb>=0.8.2"]
|
||||
solr = ["sqlalchemy-solr >= 0.2.4.3"]
|
||||
elasticsearch = ["elasticsearch-dbapi>=0.2.13, <0.3.0"]
|
||||
exasol = ["sqlalchemy-exasol>=2.4.0, <8.0"]
|
||||
excel = ["xlrd>=2.0.2, <2.1"]
|
||||
# Async dashboard "Export Data/Images to Excel": uploads the workbook to S3 and
|
||||
# emails a pre-signed link. boto3 is imported lazily by superset.utils.s3, so
|
||||
# installing this extra is only required to actually run exports.
|
||||
excel-export = ["boto3"]
|
||||
fastmcp = [
|
||||
"fastmcp>=3.4.3,<4.0",
|
||||
# tiktoken backs the response-size-guard token estimator. Without
|
||||
@@ -167,7 +170,6 @@ gevent = ["gevent>=26.4.0"]
|
||||
gsheets = ["shillelagh[gsheetsapi]>=1.4.4, <2"]
|
||||
hana = ["hdbcli==2.29.25", "sqlalchemy_hana==3.0.3"]
|
||||
hive = [
|
||||
"pyhive[hive]>=0.6.5;python_version<'3.11'",
|
||||
"pyhive[hive_pure_sasl]>=0.7.0",
|
||||
"tableschema",
|
||||
"thrift>=0.23.0, <1.0.0",
|
||||
@@ -201,7 +203,6 @@ singlestore = ["sqlalchemy-singlestoredb>=1.2.1, <2"]
|
||||
snowflake = ["snowflake-sqlalchemy>=1.10.2, <2"]
|
||||
sqlite = ["syntaqlite>=0.7.0,<0.8.0"]
|
||||
spark = [
|
||||
"pyhive[hive]>=0.6.5;python_version<'3.11'",
|
||||
"pyhive[hive_pure_sasl]>=0.7",
|
||||
"tableschema",
|
||||
"thrift>=0.23.0, <1",
|
||||
@@ -213,7 +214,7 @@ tdengine = [
|
||||
teradata = ["teradatasql>=20.0.0.62"]
|
||||
thumbnails = [] # deprecated, will be removed in 7.0
|
||||
vertica = ["sqlalchemy-vertica-python>= 0.6.3, < 0.7"]
|
||||
netezza = ["nzalchemy>=11.0.2, < 11.2"]
|
||||
netezza = ["nzalchemy>= 11.1.2, < 11.2"]
|
||||
starrocks = ["starrocks>=1.3.3, <2"]
|
||||
doris = ["pydoris>=1.2.0, <2.0.0"]
|
||||
oceanbase = ["oceanbase_py>=0.0.1.2"]
|
||||
@@ -344,8 +345,8 @@ exclude = [
|
||||
line-length = 88
|
||||
indent-width = 4
|
||||
|
||||
# Assume Python 3.10
|
||||
target-version = "py310"
|
||||
# Assume Python 3.11
|
||||
target-version = "py311"
|
||||
|
||||
[tool.ruff.lint]
|
||||
# Enable Pyflakes (`F`) and a subset of the pycodestyle (`E`) codes by default.
|
||||
|
||||
10
pytest.ini
10
pytest.ini
@@ -29,12 +29,12 @@ filterwarnings =
|
||||
ignore
|
||||
always::sqlalchemy.exc.RemovedIn20Warning
|
||||
error:Passing a string to Connection.execute\(\) is deprecated:sqlalchemy.exc.RemovedIn20Warning
|
||||
# error:"Query" object is being merged into a Session:sqlalchemy.exc.RemovedIn20Warning
|
||||
# error:"SavedQuery" object is being merged into a Session:sqlalchemy.exc.RemovedIn20Warning
|
||||
# error:"SqlaTable" object is being merged into a Session:sqlalchemy.exc.RemovedIn20Warning
|
||||
error:"Query" object is being merged into a Session:sqlalchemy.exc.RemovedIn20Warning
|
||||
error:"SavedQuery" object is being merged into a Session:sqlalchemy.exc.RemovedIn20Warning
|
||||
error:"SqlaTable" object is being merged into a Session:sqlalchemy.exc.RemovedIn20Warning
|
||||
# error:"SqlMetric" object is being merged into a Session:sqlalchemy.exc.RemovedIn20Warning
|
||||
# error:"TableColumn" object is being merged into a Session:sqlalchemy.exc.RemovedIn20Warning
|
||||
# error:"TaggedObject" object is being merged into a Session:sqlalchemy.exc.RemovedIn20Warning
|
||||
error:"TableColumn" object is being merged into a Session:sqlalchemy.exc.RemovedIn20Warning
|
||||
error:"TaggedObject" object is being merged into a Session:sqlalchemy.exc.RemovedIn20Warning
|
||||
error:The autoload parameter is deprecated:sqlalchemy.exc.RemovedIn20Warning
|
||||
error:The current statement is being autocommitted using implicit autocommit:sqlalchemy.exc.RemovedIn20Warning
|
||||
error:The connection.execute\(\) method:sqlalchemy.exc.RemovedIn20Warning
|
||||
|
||||
@@ -164,7 +164,7 @@ google-auth==2.53.0
|
||||
# via
|
||||
# -r requirements/base.in
|
||||
# shillelagh
|
||||
greenlet==3.5.1
|
||||
greenlet==3.5.3
|
||||
# via
|
||||
# apache-superset (pyproject.toml)
|
||||
# shillelagh
|
||||
@@ -275,7 +275,7 @@ packaging==25.0
|
||||
# kombu
|
||||
# limits
|
||||
# shillelagh
|
||||
pandas==2.1.4
|
||||
pandas==2.3.3
|
||||
# via apache-superset (pyproject.toml)
|
||||
paramiko==3.5.1
|
||||
# via
|
||||
@@ -331,6 +331,8 @@ pyparsing==3.2.3
|
||||
# via apache-superset (pyproject.toml)
|
||||
pysocks==1.7.1
|
||||
# via urllib3
|
||||
python-calamine==0.8.2
|
||||
# via pandas
|
||||
python-dateutil==2.9.0.post0
|
||||
# via
|
||||
# apache-superset (pyproject.toml)
|
||||
@@ -427,7 +429,7 @@ trio==0.33.0
|
||||
# trio-websocket
|
||||
trio-websocket==0.12.2
|
||||
# via selenium
|
||||
typing-extensions==4.15.0
|
||||
typing-extensions==4.16.0
|
||||
# via
|
||||
# apache-superset (pyproject.toml)
|
||||
# alembic
|
||||
|
||||
@@ -340,7 +340,6 @@ gevent==26.4.0
|
||||
google-api-core==2.23.0
|
||||
# via
|
||||
# google-cloud-bigquery
|
||||
# google-cloud-bigquery-storage
|
||||
# google-cloud-core
|
||||
# pandas-gbq
|
||||
# sqlalchemy-bigquery
|
||||
@@ -350,7 +349,6 @@ google-auth==2.53.0
|
||||
# google-api-core
|
||||
# google-auth-oauthlib
|
||||
# google-cloud-bigquery
|
||||
# google-cloud-bigquery-storage
|
||||
# google-cloud-core
|
||||
# pandas-gbq
|
||||
# pydata-google-auth
|
||||
@@ -365,8 +363,6 @@ google-cloud-bigquery==3.42.1
|
||||
# apache-superset
|
||||
# pandas-gbq
|
||||
# sqlalchemy-bigquery
|
||||
google-cloud-bigquery-storage==2.26.0
|
||||
# via pandas-gbq
|
||||
google-cloud-core==2.4.1
|
||||
# via google-cloud-bigquery
|
||||
google-crc32c==1.6.0
|
||||
@@ -377,7 +373,7 @@ googleapis-common-protos==1.66.0
|
||||
# via
|
||||
# google-api-core
|
||||
# grpcio-status
|
||||
greenlet==3.5.1
|
||||
greenlet==3.5.3
|
||||
# via
|
||||
# -c requirements/base-constraint.txt
|
||||
# apache-superset
|
||||
@@ -638,10 +634,11 @@ packaging==25.0
|
||||
# kombu
|
||||
# limits
|
||||
# matplotlib
|
||||
# pandas-gbq
|
||||
# pytest
|
||||
# shillelagh
|
||||
# sqlalchemy-bigquery
|
||||
pandas==2.1.4
|
||||
pandas==2.3.3
|
||||
# via
|
||||
# -c requirements/base-constraint.txt
|
||||
# apache-superset
|
||||
@@ -649,7 +646,7 @@ pandas==2.1.4
|
||||
# db-dtypes
|
||||
# pandas-gbq
|
||||
# prophet
|
||||
pandas-gbq==0.19.1
|
||||
pandas-gbq==0.35.0
|
||||
# via apache-superset
|
||||
parameterized==0.9.0
|
||||
# via apache-superset
|
||||
@@ -705,18 +702,17 @@ prompt-toolkit==3.0.51
|
||||
prophet==1.2.0
|
||||
# via apache-superset
|
||||
proto-plus==1.25.0
|
||||
# via
|
||||
# google-api-core
|
||||
# google-cloud-bigquery-storage
|
||||
# via google-api-core
|
||||
protobuf==5.29.6
|
||||
# via
|
||||
# google-api-core
|
||||
# google-cloud-bigquery-storage
|
||||
# googleapis-common-protos
|
||||
# grpcio-status
|
||||
# proto-plus
|
||||
psutil==6.1.0
|
||||
# via apache-superset
|
||||
# via
|
||||
# apache-superset
|
||||
# pandas-gbq
|
||||
psycopg2-binary==2.9.12
|
||||
# via apache-superset
|
||||
py-key-value-aio==0.4.4
|
||||
@@ -823,6 +819,10 @@ pytest-mock==3.10.0
|
||||
# via
|
||||
# apache-superset
|
||||
# apache-superset-extensions-cli
|
||||
python-calamine==0.8.2
|
||||
# via
|
||||
# -c requirements/base-constraint.txt
|
||||
# pandas
|
||||
python-dateutil==2.9.0.post0
|
||||
# via
|
||||
# -c requirements/base-constraint.txt
|
||||
@@ -1043,7 +1043,7 @@ trio-websocket==0.12.2
|
||||
# via
|
||||
# -c requirements/base-constraint.txt
|
||||
# selenium
|
||||
typing-extensions==4.15.0
|
||||
typing-extensions==4.16.0
|
||||
# via
|
||||
# -c requirements/base-constraint.txt
|
||||
# alembic
|
||||
|
||||
@@ -133,8 +133,8 @@ def main(docker: bool, frontend: bool, backend: bool) -> None: # noqa: C901
|
||||
requirements = [
|
||||
Requirement(
|
||||
"python",
|
||||
(Version("3.10.0"), Version("3.10.999")),
|
||||
(Version("3.9.0"), Version("3.11.999")),
|
||||
(Version("3.11.0"), Version("3.11.999")),
|
||||
(Version("3.11.0"), Version("3.12.999")),
|
||||
"backend",
|
||||
"python --version",
|
||||
),
|
||||
|
||||
@@ -21,7 +21,7 @@ under the License.
|
||||
|
||||
[](https://badge.fury.io/py/apache-superset-core)
|
||||
[](https://opensource.org/licenses/Apache-2.0)
|
||||
[](https://www.python.org/downloads/)
|
||||
[](https://www.python.org/downloads/)
|
||||
|
||||
The official core package for building Apache Superset backend extensions and integrations. This package provides essential building blocks including base classes, API utilities, type definitions, and decorators for both the host application and extensions.
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ authors = [
|
||||
]
|
||||
license = "Apache-2.0"
|
||||
license-files = ["LICENSE.txt"]
|
||||
requires-python = ">=3.10"
|
||||
requires-python = ">=3.11"
|
||||
keywords = ["superset", "apache", "analytics", "business-intelligence", "extensions", "visualization"]
|
||||
classifiers = [
|
||||
"Development Status :: 3 - Alpha",
|
||||
@@ -34,7 +34,6 @@ classifiers = [
|
||||
"Intended Audience :: Developers",
|
||||
"Operating System :: OS Independent",
|
||||
"Programming Language :: Python :: 3",
|
||||
"Programming Language :: Python :: 3.10",
|
||||
"Programming Language :: Python :: 3.11",
|
||||
"Programming Language :: Python :: 3.12",
|
||||
"Topic :: Database",
|
||||
|
||||
@@ -21,7 +21,7 @@ under the License.
|
||||
|
||||
[](https://badge.fury.io/py/apache-superset-extensions-cli)
|
||||
[](https://opensource.org/licenses/Apache-2.0)
|
||||
[](https://www.python.org/downloads/)
|
||||
[](https://www.python.org/downloads/)
|
||||
|
||||
Official command-line interface for building, bundling, and managing Apache Superset extensions. This CLI tool provides developers with everything needed to create, develop, and package extensions for the Superset ecosystem.
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ authors = [
|
||||
]
|
||||
license = "Apache-2.0"
|
||||
license-files = ["LICENSE.txt"]
|
||||
requires-python = ">=3.10"
|
||||
requires-python = ">=3.11"
|
||||
keywords = ["superset", "apache", "cli", "extensions", "analytics", "business-intelligence", "development-tools"]
|
||||
classifiers = [
|
||||
"Development Status :: 3 - Alpha",
|
||||
@@ -33,7 +33,6 @@ classifiers = [
|
||||
"Intended Audience :: Developers",
|
||||
"Operating System :: OS Independent",
|
||||
"Programming Language :: Python :: 3",
|
||||
"Programming Language :: Python :: 3.10",
|
||||
"Programming Language :: Python :: 3.11",
|
||||
"Programming Language :: Python :: 3.12",
|
||||
"Topic :: Database",
|
||||
|
||||
@@ -111,16 +111,10 @@
|
||||
"no-object-constructor": "error",
|
||||
|
||||
// === Import plugin rules ===
|
||||
// TODO: Fix incorrect named imports in Storybook and other files
|
||||
"import/named": "warn",
|
||||
// TODO: Fix duplicate exports in shared-controls and other modules
|
||||
// Temporarily disabled during OXC migration
|
||||
"import/export": "warn",
|
||||
// TODO: Re-enable after fixing default export patterns across codebase
|
||||
// This is temporarily disabled during OXC migration to unblock CI
|
||||
// Tracking issue: [Create issue after PR merge]
|
||||
"import/no-named-as-default": "off",
|
||||
"import/no-named-as-default-member": "off",
|
||||
"import/named": "error",
|
||||
"import/export": "error",
|
||||
"import/no-named-as-default": "error",
|
||||
"import/no-named-as-default-member": "error",
|
||||
"import/no-mutable-exports": "error",
|
||||
"import/no-amd": "error",
|
||||
"import/first": "error",
|
||||
|
||||
489
superset-frontend/package-lock.json
generated
489
superset-frontend/package-lock.json
generated
@@ -83,13 +83,13 @@
|
||||
"@visx/xychart": "^4.0.0",
|
||||
"ag-grid-community": "36.0.0",
|
||||
"ag-grid-react": "36.0.0",
|
||||
"antd": "^6.0.0",
|
||||
"chrono-node": "^2.9.1",
|
||||
"antd": "^6.5.1",
|
||||
"chrono-node": "^2.10.0",
|
||||
"classnames": "^2.2.5",
|
||||
"content-disposition": "^2.0.1",
|
||||
"d3-scale": "^4.0.2",
|
||||
"dayjs": "^1.11.21",
|
||||
"dom-to-image-more": "^3.10.0",
|
||||
"dom-to-image-more": "^3.10.2",
|
||||
"dom-to-pdf": "^0.3.2",
|
||||
"echarts": "^6.1.0",
|
||||
"fast-glob": "^3.3.2",
|
||||
@@ -128,7 +128,7 @@
|
||||
"react-dnd-html5-backend": "^11.1.3",
|
||||
"react-dom": "^18.3.0",
|
||||
"react-google-recaptcha": "^3.1.0",
|
||||
"react-intersection-observer": "^10.0.3",
|
||||
"react-intersection-observer": "^10.1.0",
|
||||
"react-json-tree": "^0.20.0",
|
||||
"react-lines-ellipsis": "^0.16.1",
|
||||
"react-loadable": "^5.5.0",
|
||||
@@ -178,13 +178,13 @@
|
||||
"@babel/types": "^7.29.7",
|
||||
"@emotion/babel-plugin": "^11.13.5",
|
||||
"@emotion/jest": "^11.14.2",
|
||||
"@formatjs/intl-durationformat": "^0.10.16",
|
||||
"@formatjs/intl-durationformat": "^0.10.17",
|
||||
"@istanbuljs/nyc-config-typescript": "^1.0.1",
|
||||
"@playwright/test": "^1.61.1",
|
||||
"@pmmmwh/react-refresh-webpack-plugin": "^0.6.2",
|
||||
"@storybook/addon-docs": "10.4.6",
|
||||
"@storybook/addon-links": "10.4.6",
|
||||
"@storybook/react-webpack5": "10.4.6",
|
||||
"@storybook/addon-docs": "10.5.0",
|
||||
"@storybook/addon-links": "10.5.0",
|
||||
"@storybook/react-webpack5": "10.5.0",
|
||||
"@storybook/test-runner": "0.24.4",
|
||||
"@svgr/webpack": "^8.1.0",
|
||||
"@swc/core": "^1.15.43",
|
||||
@@ -221,7 +221,7 @@
|
||||
"babel-loader": "^10.1.1",
|
||||
"babel-plugin-dynamic-import-node": "^2.3.3",
|
||||
"babel-plugin-jsx-remove-data-test-id": "^3.0.0",
|
||||
"baseline-browser-mapping": "^2.10.42",
|
||||
"baseline-browser-mapping": "^2.10.43",
|
||||
"cheerio": "1.2.0",
|
||||
"concurrently": "^10.0.3",
|
||||
"copy-webpack-plugin": "^14.0.0",
|
||||
@@ -240,14 +240,13 @@
|
||||
"eslint-plugin-prettier": "^5.5.6",
|
||||
"eslint-plugin-react-prefer-function-component": "^5.0.0",
|
||||
"eslint-plugin-react-you-might-not-need-an-effect": "^1.0.1",
|
||||
"eslint-plugin-storybook": "10.4.6",
|
||||
"eslint-plugin-storybook": "10.5.0",
|
||||
"eslint-plugin-testing-library": "^7.16.2",
|
||||
"eslint-plugin-theme-colors": "file:eslint-rules/eslint-plugin-theme-colors",
|
||||
"fetch-mock": "^12.6.0",
|
||||
"fork-ts-checker-webpack-plugin": "^9.1.0",
|
||||
"history": "^5.3.0",
|
||||
"html-webpack-plugin": "^5.6.7",
|
||||
"http-server": "^14.1.1",
|
||||
"imports-loader": "^5.0.0",
|
||||
"jest": "^30.4.2",
|
||||
"jest-environment-jsdom": "^30.4.1",
|
||||
@@ -273,13 +272,13 @@
|
||||
"source-map": "^0.7.6",
|
||||
"source-map-support": "^0.5.21",
|
||||
"speed-measure-webpack-plugin": "^1.6.0",
|
||||
"storybook": "10.4.6",
|
||||
"storybook": "10.5.0",
|
||||
"style-loader": "^4.0.0",
|
||||
"stylelint": "^17.14.0",
|
||||
"swc-loader": "^0.2.7",
|
||||
"ts-jest": "^29.4.11",
|
||||
"tscw-config": "^1.1.2",
|
||||
"tsx": "^4.23.0",
|
||||
"tsx": "^4.23.1",
|
||||
"typescript": "5.4.5",
|
||||
"unzipper": "^0.12.5",
|
||||
"vm-browserify": "^1.1.2",
|
||||
@@ -4093,38 +4092,38 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@formatjs/bigdecimal": {
|
||||
"version": "0.2.6",
|
||||
"resolved": "https://registry.npmjs.org/@formatjs/bigdecimal/-/bigdecimal-0.2.6.tgz",
|
||||
"integrity": "sha512-aPzKsGQOkQRHUEbyO/ZtYfr4EqaBQnSs6U4tzTla1xBnIdEHgY2GqEqso28UMwWRkzKqqTj5+/6BmuOsRkfn2A==",
|
||||
"version": "0.2.7",
|
||||
"resolved": "https://registry.npmjs.org/@formatjs/bigdecimal/-/bigdecimal-0.2.7.tgz",
|
||||
"integrity": "sha512-B4+XY/e4u5v261r3a37Kq2ax91gPZSKGyVpx8X5dygAggLlUz+6MeBpmAhaBFGB8WQ4JB1qD+QtKHk9aJkEb9Q==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@formatjs/fast-memoize": {
|
||||
"version": "3.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@formatjs/fast-memoize/-/fast-memoize-3.1.6.tgz",
|
||||
"integrity": "sha512-H5aexk1Le7T9TPmscacZ+1pR6CTa2n1wq+HDVGXhH8TzUlQQpeXzZs91dRtmFHrbeNbjPFPfQujUqm7MHgVoXQ==",
|
||||
"version": "3.1.7",
|
||||
"resolved": "https://registry.npmjs.org/@formatjs/fast-memoize/-/fast-memoize-3.1.7.tgz",
|
||||
"integrity": "sha512-zXfhLpvA6T7+efdt9JLbBwZ00tT7NsBMDVnDu8rpHeNNv8KfRZAMo2gkG0k9lK/Nzc//3kJ9pImsfuJxk3KhUA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@formatjs/intl-durationformat": {
|
||||
"version": "0.10.16",
|
||||
"resolved": "https://registry.npmjs.org/@formatjs/intl-durationformat/-/intl-durationformat-0.10.16.tgz",
|
||||
"integrity": "sha512-Ponn8K7eQAA7qeZRRD85lrvsByfeRDxw6aEE9EXapQ47wknptM0aYgumImVsMaBdJikpWYryGAMRZIB7IYYfmQ==",
|
||||
"version": "0.10.17",
|
||||
"resolved": "https://registry.npmjs.org/@formatjs/intl-durationformat/-/intl-durationformat-0.10.17.tgz",
|
||||
"integrity": "sha512-YXm0u5WMaSQ8Gr3th33RFNzoI24nMDScg6iZ9EQZk2CNY3Sg19qklq+FQIuuQEbrDwBlQGrMSDE97m4mETnOxw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@formatjs/bigdecimal": "0.2.6",
|
||||
"@formatjs/intl-localematcher": "0.8.11"
|
||||
"@formatjs/bigdecimal": "0.2.7",
|
||||
"@formatjs/intl-localematcher": "0.8.12"
|
||||
}
|
||||
},
|
||||
"node_modules/@formatjs/intl-localematcher": {
|
||||
"version": "0.8.11",
|
||||
"resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.8.11.tgz",
|
||||
"integrity": "sha512-MzBbR9ifqgtzHwUl2PGEDtRVZGXF9nXPtrMyN6/iKbQaim1Ob7fnPJQMllVkHm3RK74o5VqnLrZIE9egWJhf5g==",
|
||||
"version": "0.8.12",
|
||||
"resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.8.12.tgz",
|
||||
"integrity": "sha512-5H3r5ZJ2jZqHEv9K343lvHmeMDKMxssawAVD2H4J9xtu0ZXb6MlNxwLqdwBxJSHFU0C24KSZnffgmAi+59mK4A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@formatjs/fast-memoize": "3.1.6"
|
||||
"@formatjs/fast-memoize": "3.1.7"
|
||||
}
|
||||
},
|
||||
"node_modules/@gar/promise-retry": {
|
||||
@@ -9239,13 +9238,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rc-component/dropdown": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@rc-component/dropdown/-/dropdown-1.0.2.tgz",
|
||||
"integrity": "sha512-6PY2ecUSYhDPhkNHHb4wfeAya04WhpmUSKzdR60G+kMNVUCX2vjT/AgTS0Lz0I/K6xrPMJ3enQbwVpeN3sHCgg==",
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@rc-component/dropdown/-/dropdown-1.0.3.tgz",
|
||||
"integrity": "sha512-YTST/N6kpqpDz3IMuM/PSSZnrDpSOA6dgHv12gPA90ZTSLv2CoqkZ0+9NtwTY6BeO7dstPblSic2QJg7dSFy/g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@rc-component/trigger": "^3.0.0",
|
||||
"@rc-component/util": "^1.2.1",
|
||||
"@rc-component/util": "^1.11.1",
|
||||
"clsx": "^2.1.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
@@ -9641,9 +9640,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rc-component/table": {
|
||||
"version": "1.10.2",
|
||||
"resolved": "https://registry.npmjs.org/@rc-component/table/-/table-1.10.2.tgz",
|
||||
"integrity": "sha512-b3PjqB9Gp25p5t/zq+9QrbXbodkptT8/zvLmwgd2FNPUUtaYyDnQqfxeD5a7ao8E8lpinLHsi2u2vdfPhyNvAw==",
|
||||
"version": "1.10.4",
|
||||
"resolved": "https://registry.npmjs.org/@rc-component/table/-/table-1.10.4.tgz",
|
||||
"integrity": "sha512-HwoTnrwc29zeoXkXGhWqzJh8FIibGUxi1jM4LtoSzmR9d5Vv5osUQpZxnXKBP8iOCvyD6BQzZm1nXJRcnrxpAg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@rc-component/context": "^2.0.1",
|
||||
@@ -9751,15 +9750,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rc-component/trigger": {
|
||||
"version": "3.9.1",
|
||||
"resolved": "https://registry.npmjs.org/@rc-component/trigger/-/trigger-3.9.1.tgz",
|
||||
"integrity": "sha512-LNsYvz60mrLJ/kRvKcHE7boUvcQfVMCfRqZ71x3Fo9AOiZ1KKIEqkzMA8DNvz2V3Bcvir/vwQNn7JF1NPODQ7Q==",
|
||||
"version": "3.10.1",
|
||||
"resolved": "https://registry.npmjs.org/@rc-component/trigger/-/trigger-3.10.1.tgz",
|
||||
"integrity": "sha512-mXlDN0IXdtV8Yqqm8195ECCyrbmfvvfKvwVvSlH0+qvKD6BUF8gRhEjSy0FOcD1+CcDRHgTiX99LoxfQrmh3Cw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@rc-component/motion": "^1.1.4",
|
||||
"@rc-component/portal": "^2.2.0",
|
||||
"@rc-component/resize-observer": "^1.1.1",
|
||||
"@rc-component/util": "^1.2.1",
|
||||
"@rc-component/motion": "^1.3.3",
|
||||
"@rc-component/portal": "^2.2.1",
|
||||
"@rc-component/resize-observer": "^1.1.2",
|
||||
"@rc-component/util": "^1.11.1",
|
||||
"clsx": "^2.1.1"
|
||||
},
|
||||
"engines": {
|
||||
@@ -10321,16 +10320,16 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@storybook/addon-docs": {
|
||||
"version": "10.4.6",
|
||||
"resolved": "https://registry.npmjs.org/@storybook/addon-docs/-/addon-docs-10.4.6.tgz",
|
||||
"integrity": "sha512-aWAfP5JMiT5a3zBJizwroCRzOCqZwDTJmvsYvwMD3ilIEa/kT1vhf6Xrbk4XIPhDwbh8Hpb/Gfnka1xBYEISWg==",
|
||||
"version": "10.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@storybook/addon-docs/-/addon-docs-10.5.0.tgz",
|
||||
"integrity": "sha512-kbZGdX+mysiY4xezhpcFEwzQ1zSXcMhSS3u09Qt8+w5XetCAMMSv/yAxzpi6z+YoH+EdQ53e1q3MFtPUkzkfUA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@mdx-js/react": "^3.0.0",
|
||||
"@storybook/csf-plugin": "10.4.6",
|
||||
"@storybook/csf-plugin": "10.5.0",
|
||||
"@storybook/icons": "^2.0.2",
|
||||
"@storybook/react-dom-shim": "10.4.6",
|
||||
"@storybook/react-dom-shim": "10.5.0",
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||
"ts-dedent": "^2.0.0"
|
||||
@@ -10341,7 +10340,7 @@
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||
"storybook": "^10.4.6"
|
||||
"storybook": "^10.5.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
@@ -10350,9 +10349,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@storybook/addon-links": {
|
||||
"version": "10.4.6",
|
||||
"resolved": "https://registry.npmjs.org/@storybook/addon-links/-/addon-links-10.4.6.tgz",
|
||||
"integrity": "sha512-VGfERTsGRFmfvNP3SKprFWkC6Od5kXzSutT5PSZjQ/O9NnCdHhd/RILxFDN2TzZn9ywDc7t5b4AldKmSYCv3EQ==",
|
||||
"version": "10.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@storybook/addon-links/-/addon-links-10.5.0.tgz",
|
||||
"integrity": "sha512-pZlBqBjJc9Lo3LbcPx2ch0+BXD/efFQ0x9v7w+siCTs4IfqiePBuMK6ZSBQfxai+x/zHm0vKNTmOikEvP8j1wA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -10365,7 +10364,7 @@
|
||||
"peerDependencies": {
|
||||
"@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||
"storybook": "^10.4.6"
|
||||
"storybook": "^10.5.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
@@ -10377,13 +10376,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@storybook/builder-webpack5": {
|
||||
"version": "10.4.6",
|
||||
"resolved": "https://registry.npmjs.org/@storybook/builder-webpack5/-/builder-webpack5-10.4.6.tgz",
|
||||
"integrity": "sha512-klJUCBlkr1mFqXxsyYc7akIBhT5VOBTRcHChSFXq6Kbh+qQYOvfmgBpY0Tv+f7ffBmzp6gxpTorg7eGxlklxeQ==",
|
||||
"version": "10.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@storybook/builder-webpack5/-/builder-webpack5-10.5.0.tgz",
|
||||
"integrity": "sha512-RFqlqK/wCtI9JzZ45o7aTsh+tDsg1TXn8KcLimBPh/Dfp77wZsZaOD+eS+0Fb8d2EbOgReLS500KjZruX3f3JQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@storybook/core-webpack": "10.4.6",
|
||||
"@storybook/core-webpack": "10.5.0",
|
||||
"case-sensitive-paths-webpack-plugin": "^2.4.0",
|
||||
"cjs-module-lexer": "^1.2.3",
|
||||
"css-loader": "^7.1.2",
|
||||
@@ -10391,6 +10390,7 @@
|
||||
"fork-ts-checker-webpack-plugin": "^9.1.0",
|
||||
"html-webpack-plugin": "^5.5.0",
|
||||
"magic-string": "^0.30.5",
|
||||
"semver": "^7.7.3",
|
||||
"style-loader": "^4.0.0",
|
||||
"terser-webpack-plugin": "^5.3.17",
|
||||
"ts-dedent": "^2.0.0",
|
||||
@@ -10404,7 +10404,7 @@
|
||||
"url": "https://opencollective.com/storybook"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"storybook": "^10.4.6"
|
||||
"storybook": "^10.5.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"typescript": {
|
||||
@@ -10413,9 +10413,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@storybook/core-webpack": {
|
||||
"version": "10.4.6",
|
||||
"resolved": "https://registry.npmjs.org/@storybook/core-webpack/-/core-webpack-10.4.6.tgz",
|
||||
"integrity": "sha512-DDhpgaFGb1AC0lzfR2LOozCj+uT14tsr2R9551PHgcC3ru1yfhL2DNbIjdiMuQP8nVm+2HKeXWhybJGYtk9z9g==",
|
||||
"version": "10.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@storybook/core-webpack/-/core-webpack-10.5.0.tgz",
|
||||
"integrity": "sha512-8O/h7nk1h91w4DBtZo6yo89cvPxzryTcYaFxOsSG5jrn/HMWxZIcyXm3nu3metCbTffnVBu2pmLuHaiCkv/9Ng==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -10426,13 +10426,13 @@
|
||||
"url": "https://opencollective.com/storybook"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"storybook": "^10.4.6"
|
||||
"storybook": "^10.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@storybook/csf-plugin": {
|
||||
"version": "10.4.6",
|
||||
"resolved": "https://registry.npmjs.org/@storybook/csf-plugin/-/csf-plugin-10.4.6.tgz",
|
||||
"integrity": "sha512-NILLxDqpA/JR/AazGWpsz+4fadJwRU4uhHephGtYpVOWnQA/DkJfKT6zpcJVq8+QA8A2zKMLX3GVKsXIrxjuDA==",
|
||||
"version": "10.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@storybook/csf-plugin/-/csf-plugin-10.5.0.tgz",
|
||||
"integrity": "sha512-R7VFw6FnDZTWct0ekOcFnTfDgdHnnAuQW+AbGG9A9IZPvyH9uLJivK7L86+r9MITRrO2+v81HaFDsT/OFk6ZkQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -10445,7 +10445,7 @@
|
||||
"peerDependencies": {
|
||||
"esbuild": "*",
|
||||
"rollup": "*",
|
||||
"storybook": "^10.4.6",
|
||||
"storybook": "^10.5.0",
|
||||
"vite": "*",
|
||||
"webpack": "*"
|
||||
},
|
||||
@@ -10483,17 +10483,17 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@storybook/preset-react-webpack": {
|
||||
"version": "10.4.6",
|
||||
"resolved": "https://registry.npmjs.org/@storybook/preset-react-webpack/-/preset-react-webpack-10.4.6.tgz",
|
||||
"integrity": "sha512-D6EjK1sknC/1GmdWQjV38HEP+tBxJ5ObNuCUWQzGsJqsiq45HaOemZbIyJqxp3dYx2/YpFd0bawn7PlOP4yNOQ==",
|
||||
"version": "10.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@storybook/preset-react-webpack/-/preset-react-webpack-10.5.0.tgz",
|
||||
"integrity": "sha512-x26YF06xSR8sYhHn/cOmbJl8VGQhOWGd49teU80cCwdUHTSu98jVAPyGQhuGmHEw3WndnWarIxXIu1iGhZ414w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@storybook/core-webpack": "10.4.6",
|
||||
"@storybook/core-webpack": "10.5.0",
|
||||
"@storybook/react-docgen-typescript-plugin": "1.0.6--canary.9.0c3f3b7.0",
|
||||
"@types/semver": "^7.7.1",
|
||||
"magic-string": "^0.30.5",
|
||||
"react-docgen": "^7.1.1",
|
||||
"react-docgen": "^8.0.2",
|
||||
"resolve": "^1.22.8",
|
||||
"semver": "^7.7.3",
|
||||
"tsconfig-paths": "^4.2.0",
|
||||
@@ -10506,7 +10506,7 @@
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||
"storybook": "^10.4.6"
|
||||
"storybook": "^10.5.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"typescript": {
|
||||
@@ -10515,14 +10515,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@storybook/react": {
|
||||
"version": "10.4.6",
|
||||
"resolved": "https://registry.npmjs.org/@storybook/react/-/react-10.4.6.tgz",
|
||||
"integrity": "sha512-9Y7YecrVFe1/01KYjfOLxVqTg2Aq+IO6TEv6sC2U0PfD0AWCSCmQ91QqgBpN/XW4aFFWoiZNinyXMUlU8zxy2w==",
|
||||
"version": "10.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@storybook/react/-/react-10.5.0.tgz",
|
||||
"integrity": "sha512-2IhddiREy7NqAqnFsEOfW6HBG7azIcLxhRQYploSsaemOncR29xhzvAZsG+xlWgrtvxv4h3fYQTTR4TNn8CgPQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@storybook/global": "^5.0.0",
|
||||
"@storybook/react-dom-shim": "10.4.6",
|
||||
"@storybook/react-dom-shim": "10.5.0",
|
||||
"react-docgen": "^8.0.2",
|
||||
"react-docgen-typescript": "^2.2.2"
|
||||
},
|
||||
@@ -10535,7 +10535,7 @@
|
||||
"@types/react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||
"storybook": "^10.4.6",
|
||||
"storybook": "^10.5.0",
|
||||
"typescript": ">= 4.9.x"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
@@ -10615,9 +10615,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@storybook/react-dom-shim": {
|
||||
"version": "10.4.6",
|
||||
"resolved": "https://registry.npmjs.org/@storybook/react-dom-shim/-/react-dom-shim-10.4.6.tgz",
|
||||
"integrity": "sha512-iGNmKzrq9vgl2PDrYAnZKI+yvac3Ym+lJXXuQaqlFRS23zA5MNm4EBX+rAG7WulqchoK6NaZ0KQOs2mAgEpTMg==",
|
||||
"version": "10.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@storybook/react-dom-shim/-/react-dom-shim-10.5.0.tgz",
|
||||
"integrity": "sha512-GwGA6zDj4Cfw6vGsdfPKfF39L0W6solNbbnjdjGa57m2ooASkidLhrXo2wgC9wh3o/jcfonmYPDRGY6sEhGDtg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
@@ -10629,7 +10629,7 @@
|
||||
"@types/react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||
"storybook": "^10.4.6"
|
||||
"storybook": "^10.5.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
@@ -10641,15 +10641,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@storybook/react-webpack5": {
|
||||
"version": "10.4.6",
|
||||
"resolved": "https://registry.npmjs.org/@storybook/react-webpack5/-/react-webpack5-10.4.6.tgz",
|
||||
"integrity": "sha512-34rOHFRa4NrBnMKsQMq8QTvw65QQJUtasYfEOw1/Pa9+CFWfFQZ3kfDLRxatphUyc0rbKxmVrVE4SFEMY/eMsA==",
|
||||
"version": "10.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@storybook/react-webpack5/-/react-webpack5-10.5.0.tgz",
|
||||
"integrity": "sha512-Z5Tpg0jNelMOzxfP47oH+AESyol/52WzariOJB6/rUAj5S9vMb/IM7KrF/3QQUa/j3om6dmclxA83CUhGgreig==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@storybook/builder-webpack5": "10.4.6",
|
||||
"@storybook/preset-react-webpack": "10.4.6",
|
||||
"@storybook/react": "10.4.6"
|
||||
"@storybook/builder-webpack5": "10.5.0",
|
||||
"@storybook/preset-react-webpack": "10.5.0",
|
||||
"@storybook/react": "10.5.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
@@ -10658,7 +10658,7 @@
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||
"storybook": "^10.4.6",
|
||||
"storybook": "^10.5.0",
|
||||
"typescript": ">= 4.9.x"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
@@ -10667,28 +10667,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@storybook/react/node_modules/react-docgen": {
|
||||
"version": "8.0.3",
|
||||
"resolved": "https://registry.npmjs.org/react-docgen/-/react-docgen-8.0.3.tgz",
|
||||
"integrity": "sha512-aEZ9qP+/M+58x2qgfSFEWH1BxLyHe5+qkLNJOZQb5iGS017jpbRnoKhNRrXPeA6RfBrZO5wZrT9DMC1UqE1f1w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.28.0",
|
||||
"@babel/traverse": "^7.28.0",
|
||||
"@babel/types": "^7.28.2",
|
||||
"@types/babel__core": "^7.20.5",
|
||||
"@types/babel__traverse": "^7.20.7",
|
||||
"@types/doctrine": "^0.0.9",
|
||||
"@types/resolve": "^1.20.2",
|
||||
"doctrine": "^3.0.0",
|
||||
"resolve": "^1.22.1",
|
||||
"strip-indent": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^20.9.0 || >=22"
|
||||
}
|
||||
},
|
||||
"node_modules/@storybook/test-runner": {
|
||||
"version": "0.24.4",
|
||||
"resolved": "https://registry.npmjs.org/@storybook/test-runner/-/test-runner-0.24.4.tgz",
|
||||
@@ -14449,16 +14427,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/antd": {
|
||||
"version": "6.5.0",
|
||||
"resolved": "https://registry.npmjs.org/antd/-/antd-6.5.0.tgz",
|
||||
"integrity": "sha512-9zbVc9UukfGuqCvIAov01nlpDQWfARNmZQyt21ZhqLX7ilXmi4cdkp12xA48WEmXRXwZvno8A03qQuGE9JG8fg==",
|
||||
"version": "6.5.1",
|
||||
"resolved": "https://registry.npmjs.org/antd/-/antd-6.5.1.tgz",
|
||||
"integrity": "sha512-VZVVF9zYI6S0NHqboVhCoY9Iiqj6dphW1NPB+sEaAf2HuIQ0haXWXj7ZvAXTRDzusktV6+cvvrSZEdRi4twATg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@ant-design/colors": "^8.0.1",
|
||||
"@ant-design/cssinjs": "^2.1.2",
|
||||
"@ant-design/cssinjs-utils": "^2.1.2",
|
||||
"@ant-design/fast-color": "^3.0.1",
|
||||
"@ant-design/icons": "^6.3.1",
|
||||
"@ant-design/icons": "^6.3.2",
|
||||
"@ant-design/react-slick": "~2.0.0",
|
||||
"@babel/runtime": "^7.29.2",
|
||||
"@rc-component/cascader": "~1.17.0",
|
||||
@@ -14467,7 +14445,7 @@
|
||||
"@rc-component/color-picker": "~3.1.1",
|
||||
"@rc-component/dialog": "~1.10.0",
|
||||
"@rc-component/drawer": "~1.4.2",
|
||||
"@rc-component/dropdown": "~1.0.2",
|
||||
"@rc-component/dropdown": "~1.0.3",
|
||||
"@rc-component/form": "~1.8.5",
|
||||
"@rc-component/image": "~1.9.0",
|
||||
"@rc-component/input": "~1.3.1",
|
||||
@@ -14488,13 +14466,13 @@
|
||||
"@rc-component/slider": "~1.1.1",
|
||||
"@rc-component/steps": "~1.2.2",
|
||||
"@rc-component/switch": "~1.0.3",
|
||||
"@rc-component/table": "~1.10.2",
|
||||
"@rc-component/table": "~1.10.4",
|
||||
"@rc-component/tabs": "~1.11.0",
|
||||
"@rc-component/tooltip": "~1.4.0",
|
||||
"@rc-component/tour": "~2.4.0",
|
||||
"@rc-component/tree": "~1.3.2",
|
||||
"@rc-component/tree-select": "~1.11.0",
|
||||
"@rc-component/trigger": "^3.9.1",
|
||||
"@rc-component/trigger": "^3.10.0",
|
||||
"@rc-component/upload": "~1.1.1",
|
||||
"@rc-component/util": "^1.11.1",
|
||||
"clsx": "^2.1.1",
|
||||
@@ -14907,17 +14885,45 @@
|
||||
}
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "1.16.0",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.16.0.tgz",
|
||||
"integrity": "sha512-6hp5CwvTPlN2A31g5dxnwAX0orzM7pmCRDLnZSX772mv8WDqICwFjowHuPs04Mc8deIld1+ejhtaMn5vp6b+1w==",
|
||||
"version": "1.18.1",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.18.1.tgz",
|
||||
"integrity": "sha512-3nTvFlvpn9Zu/RkHUqtc7/+al4UpRW5az71ap5zccp6e8RAYEzhMTecX8Dz1wWDYrPpUoB1HAQEGEAEvUr7S9g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.16.0",
|
||||
"form-data": "^4.0.5",
|
||||
"https-proxy-agent": "^5.0.1",
|
||||
"proxy-from-env": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/axios/node_modules/agent-base": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
|
||||
"integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"debug": "4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/axios/node_modules/https-proxy-agent": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
|
||||
"integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"agent-base": "6",
|
||||
"debug": "4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/axios/node_modules/proxy-from-env": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz",
|
||||
@@ -15235,9 +15241,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/baseline-browser-mapping": {
|
||||
"version": "2.10.42",
|
||||
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.42.tgz",
|
||||
"integrity": "sha512-c/jurFrDLyui7o1J86yLkRu4LMsTYcBohveus7/I2Hzdn9KIP2bdJPTue/lR1KH46enoPbD77GKeSYNdyPoD3Q==",
|
||||
"version": "2.10.43",
|
||||
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.43.tgz",
|
||||
"integrity": "sha512-AjYpR78kDWAY3Efj+cDTFH9t9SCoL7OoTp1BOb0mQV7S+6CiLwnWM3FyxhJtdPufDFKzmCSFoUncKjWgJEZTCQ==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
@@ -15247,26 +15253,6 @@
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/basic-auth": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz",
|
||||
"integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"safe-buffer": "5.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/basic-auth/node_modules/safe-buffer": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/batch": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz",
|
||||
@@ -16402,9 +16388,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/chrono-node": {
|
||||
"version": "2.9.1",
|
||||
"resolved": "https://registry.npmjs.org/chrono-node/-/chrono-node-2.9.1.tgz",
|
||||
"integrity": "sha512-nqP8Zp11efCYQIESXPxeDM8ikzN5BDb3Zzou+a66fZq+X2hzKFdsNLQE2/uBAh//BZEMbaMo1eTnagK7hOenAg==",
|
||||
"version": "2.10.0",
|
||||
"resolved": "https://registry.npmjs.org/chrono-node/-/chrono-node-2.10.0.tgz",
|
||||
"integrity": "sha512-5fJ4zr5W/5DEf+8FMPMXF2qk9L5dc1rAP9Pw009iMlKAghPgx5o7aUcnjEMe6PTwqiqTa5yzmfSm05EHuwr31Q==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
|
||||
@@ -17248,16 +17234,6 @@
|
||||
"integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/corser": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/corser/-/corser-2.0.1.tgz",
|
||||
"integrity": "sha512-utCYNzRSQIZNPIcGZdQc92UVJYAhtGAteCFg0yRaFm8f0P+CPtyGyHXJcGXnffjCybUCEx3FQ2G7U3/o9eIkVQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/cosmiconfig": {
|
||||
"version": "8.3.6",
|
||||
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz",
|
||||
@@ -18676,9 +18652,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/dom-to-image-more": {
|
||||
"version": "3.10.0",
|
||||
"resolved": "https://registry.npmjs.org/dom-to-image-more/-/dom-to-image-more-3.10.0.tgz",
|
||||
"integrity": "sha512-APrFEimSmH4phJKs8DlURuSr3BFwDqNi62l14bx73Wrhx0OhE4dd0qzZR+4E3sH8PnHxvax1LOrosC9oXRFA5A==",
|
||||
"version": "3.10.2",
|
||||
"resolved": "https://registry.npmjs.org/dom-to-image-more/-/dom-to-image-more-3.10.2.tgz",
|
||||
"integrity": "sha512-+ZNbiRB7Fpsfzn8WSCmAIKUFSXp8uahlI+LsY8t8oWtAATqokeKS3eD3oQikheouap6aVMht8y0b4oAobWRr9w==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/dom-to-pdf": {
|
||||
@@ -18721,9 +18697,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/dompurify": {
|
||||
"version": "3.4.11",
|
||||
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.11.tgz",
|
||||
"integrity": "sha512-zhlUV12GsaRzMsf9q5M254YhA4+VuF0fG+QFqu6aYpoGlKtz+w8//jBcGVYBgQkR5GHjUomejY84AV+/uPbWdw==",
|
||||
"version": "3.4.12",
|
||||
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.12.tgz",
|
||||
"integrity": "sha512-zQvGet8Z2sWbQhCmfFz/T5QWH2oBmjnqK3qvOjaqaNLrLEF912WamU+ohnTp0TCep/MFVHpdJuCZEdFOdTnEFg==",
|
||||
"license": "(MPL-2.0 OR Apache-2.0)",
|
||||
"optionalDependencies": {
|
||||
"@types/trusted-types": "^2.0.7"
|
||||
@@ -19848,17 +19824,18 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-storybook": {
|
||||
"version": "10.4.6",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-storybook/-/eslint-plugin-storybook-10.4.6.tgz",
|
||||
"integrity": "sha512-CfGSXn6zFspeYTU8R7v797MOmJFj8xc6MWf/oGuRwbKeMoSwnliR+OlXSjMZYM1D6gfmwiuH1VX58LSHdn+ZPg==",
|
||||
"version": "10.5.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-storybook/-/eslint-plugin-storybook-10.5.0.tgz",
|
||||
"integrity": "sha512-UyhbK11baKAYqzyDUHlwDlm1aP/wxPMR0vFmsxA5984BGaPwarhoXUWng1Xa0cd9BdPbQ+zr/y8ADk6XxtwkYg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "^8.48.0",
|
||||
"@typescript-eslint/utils": "^8.48.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": ">=8",
|
||||
"storybook": "^10.4.6"
|
||||
"storybook": "^10.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-testing-library": {
|
||||
@@ -23617,61 +23594,6 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/http-server": {
|
||||
"version": "14.1.1",
|
||||
"resolved": "https://registry.npmjs.org/http-server/-/http-server-14.1.1.tgz",
|
||||
"integrity": "sha512-+cbxadF40UXd9T01zUHgA+rlo2Bg1Srer4+B4NwIHdaGxAGGv59nYRnGGDJ9LBk7alpS0US+J+bLLdQOOkJq4A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"basic-auth": "^2.0.1",
|
||||
"chalk": "^4.1.2",
|
||||
"corser": "^2.0.1",
|
||||
"he": "^1.2.0",
|
||||
"html-encoding-sniffer": "^3.0.0",
|
||||
"http-proxy": "^1.18.1",
|
||||
"mime": "^1.6.0",
|
||||
"minimist": "^1.2.6",
|
||||
"opener": "^1.5.1",
|
||||
"portfinder": "^1.0.28",
|
||||
"secure-compare": "3.0.1",
|
||||
"union": "~0.5.0",
|
||||
"url-join": "^4.0.1"
|
||||
},
|
||||
"bin": {
|
||||
"http-server": "bin/http-server"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/http-server/node_modules/html-encoding-sniffer": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz",
|
||||
"integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"whatwg-encoding": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/http-server/node_modules/whatwg-encoding": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz",
|
||||
"integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==",
|
||||
"deprecated": "Use @exodus/bytes instead for a more spec-conformant and faster implementation",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"iconv-lite": "0.6.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/https-proxy-agent": {
|
||||
"version": "7.0.6",
|
||||
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz",
|
||||
@@ -33085,20 +33007,6 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/portfinder": {
|
||||
"version": "1.0.38",
|
||||
"resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.38.tgz",
|
||||
"integrity": "sha512-rEwq/ZHlJIKw++XtLAO8PPuOQA/zaPJOZJ37BVuN97nLpMJeuDVLVGRwbFoBgLudgdTMP2hdRJP++H+8QOA3vg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"async": "^3.2.6",
|
||||
"debug": "^4.3.6"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 10.12"
|
||||
}
|
||||
},
|
||||
"node_modules/possible-typed-array-names": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz",
|
||||
@@ -35136,17 +35044,17 @@
|
||||
}
|
||||
},
|
||||
"node_modules/react-docgen": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/react-docgen/-/react-docgen-7.1.1.tgz",
|
||||
"integrity": "sha512-hlSJDQ2synMPKFZOsKo9Hi8WWZTC7POR8EmWvTSjow+VDgKzkmjQvFm2fk0tmRw+f0vTOIYKlarR0iL4996pdg==",
|
||||
"version": "8.0.3",
|
||||
"resolved": "https://registry.npmjs.org/react-docgen/-/react-docgen-8.0.3.tgz",
|
||||
"integrity": "sha512-aEZ9qP+/M+58x2qgfSFEWH1BxLyHe5+qkLNJOZQb5iGS017jpbRnoKhNRrXPeA6RfBrZO5wZrT9DMC1UqE1f1w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.18.9",
|
||||
"@babel/traverse": "^7.18.9",
|
||||
"@babel/types": "^7.18.9",
|
||||
"@types/babel__core": "^7.18.0",
|
||||
"@types/babel__traverse": "^7.18.0",
|
||||
"@babel/core": "^7.28.0",
|
||||
"@babel/traverse": "^7.28.0",
|
||||
"@babel/types": "^7.28.2",
|
||||
"@types/babel__core": "^7.20.5",
|
||||
"@types/babel__traverse": "^7.20.7",
|
||||
"@types/doctrine": "^0.0.9",
|
||||
"@types/resolve": "^1.20.2",
|
||||
"doctrine": "^3.0.0",
|
||||
@@ -35154,7 +35062,7 @@
|
||||
"strip-indent": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.14.0"
|
||||
"node": "^20.9.0 || >=22"
|
||||
}
|
||||
},
|
||||
"node_modules/react-docgen-typescript": {
|
||||
@@ -35218,9 +35126,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/react-intersection-observer": {
|
||||
"version": "10.0.3",
|
||||
"resolved": "https://registry.npmjs.org/react-intersection-observer/-/react-intersection-observer-10.0.3.tgz",
|
||||
"integrity": "sha512-luICLMbs0zxTO/70Zy7K5jOXkABPEVSAF8T3FdZUlctsrIaPLmx8TZe2SSA+CY2HGWfz2INyNTnp82pxNNsShA==",
|
||||
"version": "10.1.0",
|
||||
"resolved": "https://registry.npmjs.org/react-intersection-observer/-/react-intersection-observer-10.1.0.tgz",
|
||||
"integrity": "sha512-V8HDu3+Llg6OEhOxx8LnUSS0t4VS+1Xk9ZatkI8Jct/H0CwKnqFTCu8NT3q7ghJTghTdIrEMPSWr2dkKPG+gdQ==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"react": "^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||
@@ -37024,13 +36932,6 @@
|
||||
"compute-scroll-into-view": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/secure-compare": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/secure-compare/-/secure-compare-3.0.1.tgz",
|
||||
"integrity": "sha512-AckIIV90rPDcBcglUwXPF3kg0P0qmPsPXAj6BBEENQE1p5yA1xfmDJzfi1Tappj37Pv2mVbKpL3Z1T+Nn7k1Qw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/seedrandom": {
|
||||
"version": "3.0.5",
|
||||
"resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-3.0.5.tgz",
|
||||
@@ -38380,20 +38281,22 @@
|
||||
}
|
||||
},
|
||||
"node_modules/storybook": {
|
||||
"version": "10.4.6",
|
||||
"resolved": "https://registry.npmjs.org/storybook/-/storybook-10.4.6.tgz",
|
||||
"integrity": "sha512-6wkA6LxfDSSilloITsrFOJfsnw0mDUP2h8Ls+lRt8oRsudtz2RWFhLv+Toiwg6NW7hUpdTDc2hzR7DztJid6+A==",
|
||||
"version": "10.5.0",
|
||||
"resolved": "https://registry.npmjs.org/storybook/-/storybook-10.5.0.tgz",
|
||||
"integrity": "sha512-dRhM/kSSvHQR8DmZO41v5sJuz9U6zDjjR2gRBTgZN2RBSXbmF0Brvgszrvvxyx2VfxuYKzhB+xumKwWkwlBtig==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@storybook/global": "^5.0.0",
|
||||
"@storybook/icons": "^2.0.2",
|
||||
"@testing-library/dom": "^10.4.1",
|
||||
"@testing-library/jest-dom": "^6.9.1",
|
||||
"@testing-library/user-event": "^14.6.1",
|
||||
"@vitest/expect": "3.2.4",
|
||||
"@vitest/spy": "3.2.4",
|
||||
"@webcontainer/env": "^1.1.1",
|
||||
"esbuild": "^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0 || ^0.25.0 || ^0.26.0 || ^0.27.0 || ^0.28.0",
|
||||
"jsonc-parser": "^3.3.1",
|
||||
"open": "^10.2.0",
|
||||
"oxc-parser": "^0.127.0",
|
||||
"oxc-resolver": "^11.19.1",
|
||||
@@ -38412,7 +38315,7 @@
|
||||
"peerDependencies": {
|
||||
"@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||
"prettier": "^2 || ^3",
|
||||
"vite-plus": "^0.1.15"
|
||||
"vite-plus": "^0.1.15 || ^0.2.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
@@ -38426,6 +38329,26 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/storybook/node_modules/@testing-library/dom": {
|
||||
"version": "10.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz",
|
||||
"integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.10.4",
|
||||
"@babel/runtime": "^7.12.5",
|
||||
"@types/aria-query": "^5.0.1",
|
||||
"aria-query": "5.3.0",
|
||||
"dom-accessibility-api": "^0.5.9",
|
||||
"lz-string": "^1.5.0",
|
||||
"picocolors": "1.1.1",
|
||||
"pretty-format": "^27.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/storybook/node_modules/@testing-library/user-event": {
|
||||
"version": "14.6.1",
|
||||
"resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.6.1.tgz",
|
||||
@@ -38440,6 +38363,16 @@
|
||||
"@testing-library/dom": ">=7.21.4"
|
||||
}
|
||||
},
|
||||
"node_modules/storybook/node_modules/aria-query": {
|
||||
"version": "5.3.0",
|
||||
"resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz",
|
||||
"integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"dequal": "^2.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/storybook/node_modules/define-lazy-prop": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz",
|
||||
@@ -38469,6 +38402,13 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/storybook/node_modules/jsonc-parser": {
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz",
|
||||
"integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/storybook/node_modules/open": {
|
||||
"version": "10.2.0",
|
||||
"resolved": "https://registry.npmjs.org/open/-/open-10.2.0.tgz",
|
||||
@@ -40354,9 +40294,9 @@
|
||||
"license": "0BSD"
|
||||
},
|
||||
"node_modules/tsx": {
|
||||
"version": "4.23.0",
|
||||
"resolved": "https://registry.npmjs.org/tsx/-/tsx-4.23.0.tgz",
|
||||
"integrity": "sha512-eUdUIaCr963q2h5u3+QwvYp0+eqPvn+egeqZUm0hwERCqqx1E3kK5ehbGCvqSE5MQAULr67ww0cA3jKc3YkM1w==",
|
||||
"version": "4.23.1",
|
||||
"resolved": "https://registry.npmjs.org/tsx/-/tsx-4.23.1.tgz",
|
||||
"integrity": "sha512-GQHnkIfxyx1wYCOS/wonik5MVRZU9hi1TEZmzGZSCJB1y9YgoZ8H6itNE/u4suE+yLmOzuE4E5S4TZ/ZX2wcWQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -40835,18 +40775,6 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/union": {
|
||||
"version": "0.5.0",
|
||||
"resolved": "https://registry.npmjs.org/union/-/union-0.5.0.tgz",
|
||||
"integrity": "sha512-N6uOhuW6zO95P3Mel2I2zMsbsanvvtgn6jVqJv4vbVcz/JN0OkL9suomjQGmWtxJQXOCqUJvquc1sMeNz/IwlA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"qs": "^6.4.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/union-value": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz",
|
||||
@@ -41025,9 +40953,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/unplugin/node_modules/picomatch": {
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
|
||||
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
|
||||
"version": "4.0.5",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz",
|
||||
"integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -41168,13 +41096,6 @@
|
||||
"integrity": "sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/url-join": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz",
|
||||
"integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/url-template": {
|
||||
"version": "2.0.8",
|
||||
"resolved": "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz",
|
||||
@@ -43656,7 +43577,7 @@
|
||||
"d3-time": "^3.1.0",
|
||||
"d3-time-format": "^4.1.0",
|
||||
"dayjs": "^1.11.21",
|
||||
"dompurify": "^3.4.11",
|
||||
"dompurify": "^3.4.12",
|
||||
"fetch-retry": "^6.0.0",
|
||||
"handlebars": "^4.7.9",
|
||||
"jed": "^1.1.1",
|
||||
@@ -44039,7 +43960,7 @@
|
||||
"dependencies": {
|
||||
"d3": "^3.5.17",
|
||||
"d3-tip": "^0.9.1",
|
||||
"dompurify": "^3.4.11",
|
||||
"dompurify": "^3.4.12",
|
||||
"fast-safe-stringify": "^2.1.1",
|
||||
"lodash": "^4.18.1",
|
||||
"lodash-es": "^4.18.1",
|
||||
|
||||
@@ -84,7 +84,7 @@
|
||||
"prune": "rm -rf ./{packages,plugins}/*/{node_modules,lib,esm,tsconfig.tsbuildinfo,package-lock.json} ./.temp_cache",
|
||||
"storybook": "cross-env NODE_ENV=development BABEL_ENV=development storybook dev -p 6006",
|
||||
"test-storybook": "test-storybook",
|
||||
"test-storybook:ci": "concurrently --kill-others --success first --names \"SB,TEST\" --prefix-colors \"magenta,blue\" \"npx http-server storybook-static --port 6006 --silent\" \"npx wait-on tcp:127.0.0.1:6006 && npm run test-storybook -- --maxWorkers=2\"",
|
||||
"test-storybook:ci": "concurrently --kill-others --success first --names \"SB,TEST\" --prefix-colors \"magenta,blue\" \"python3 -m http.server 6006 --directory storybook-static\" \"npx wait-on tcp:127.0.0.1:6006 && npm run test-storybook -- --maxWorkers=2\"",
|
||||
"tdd": "cross-env NODE_ENV=test NODE_OPTIONS=\"--max-old-space-size=8192\" jest --watch",
|
||||
"test": "cross-env NODE_ENV=test NODE_OPTIONS=\"--max-old-space-size=8192\" jest --max-workers=80% --silent",
|
||||
"test-loud": "cross-env NODE_ENV=test NODE_OPTIONS=\"--max-old-space-size=8192\" jest --max-workers=80%",
|
||||
@@ -168,13 +168,13 @@
|
||||
"@visx/xychart": "^4.0.0",
|
||||
"ag-grid-community": "36.0.0",
|
||||
"ag-grid-react": "36.0.0",
|
||||
"antd": "^6.0.0",
|
||||
"chrono-node": "^2.9.1",
|
||||
"antd": "^6.5.1",
|
||||
"chrono-node": "^2.10.0",
|
||||
"classnames": "^2.2.5",
|
||||
"content-disposition": "^2.0.1",
|
||||
"d3-scale": "^4.0.2",
|
||||
"dayjs": "^1.11.21",
|
||||
"dom-to-image-more": "^3.10.0",
|
||||
"dom-to-image-more": "^3.10.2",
|
||||
"dom-to-pdf": "^0.3.2",
|
||||
"echarts": "^6.1.0",
|
||||
"fast-glob": "^3.3.2",
|
||||
@@ -213,7 +213,7 @@
|
||||
"react-dnd-html5-backend": "^11.1.3",
|
||||
"react-dom": "^18.3.0",
|
||||
"react-google-recaptcha": "^3.1.0",
|
||||
"react-intersection-observer": "^10.0.3",
|
||||
"react-intersection-observer": "^10.1.0",
|
||||
"react-json-tree": "^0.20.0",
|
||||
"react-lines-ellipsis": "^0.16.1",
|
||||
"react-loadable": "^5.5.0",
|
||||
@@ -263,13 +263,13 @@
|
||||
"@babel/types": "^7.29.7",
|
||||
"@emotion/babel-plugin": "^11.13.5",
|
||||
"@emotion/jest": "^11.14.2",
|
||||
"@formatjs/intl-durationformat": "^0.10.16",
|
||||
"@formatjs/intl-durationformat": "^0.10.17",
|
||||
"@istanbuljs/nyc-config-typescript": "^1.0.1",
|
||||
"@playwright/test": "^1.61.1",
|
||||
"@pmmmwh/react-refresh-webpack-plugin": "^0.6.2",
|
||||
"@storybook/addon-docs": "10.4.6",
|
||||
"@storybook/addon-links": "10.4.6",
|
||||
"@storybook/react-webpack5": "10.4.6",
|
||||
"@storybook/addon-docs": "10.5.0",
|
||||
"@storybook/addon-links": "10.5.0",
|
||||
"@storybook/react-webpack5": "10.5.0",
|
||||
"@storybook/test-runner": "0.24.4",
|
||||
"@svgr/webpack": "^8.1.0",
|
||||
"@swc/core": "^1.15.43",
|
||||
@@ -306,7 +306,7 @@
|
||||
"babel-loader": "^10.1.1",
|
||||
"babel-plugin-dynamic-import-node": "^2.3.3",
|
||||
"babel-plugin-jsx-remove-data-test-id": "^3.0.0",
|
||||
"baseline-browser-mapping": "^2.10.42",
|
||||
"baseline-browser-mapping": "^2.10.43",
|
||||
"cheerio": "1.2.0",
|
||||
"concurrently": "^10.0.3",
|
||||
"copy-webpack-plugin": "^14.0.0",
|
||||
@@ -325,14 +325,13 @@
|
||||
"eslint-plugin-prettier": "^5.5.6",
|
||||
"eslint-plugin-react-prefer-function-component": "^5.0.0",
|
||||
"eslint-plugin-react-you-might-not-need-an-effect": "^1.0.1",
|
||||
"eslint-plugin-storybook": "10.4.6",
|
||||
"eslint-plugin-storybook": "10.5.0",
|
||||
"eslint-plugin-testing-library": "^7.16.2",
|
||||
"eslint-plugin-theme-colors": "file:eslint-rules/eslint-plugin-theme-colors",
|
||||
"fetch-mock": "^12.6.0",
|
||||
"fork-ts-checker-webpack-plugin": "^9.1.0",
|
||||
"history": "^5.3.0",
|
||||
"html-webpack-plugin": "^5.6.7",
|
||||
"http-server": "^14.1.1",
|
||||
"imports-loader": "^5.0.0",
|
||||
"jest": "^30.4.2",
|
||||
"jest-environment-jsdom": "^30.4.1",
|
||||
@@ -358,13 +357,13 @@
|
||||
"source-map": "^0.7.6",
|
||||
"source-map-support": "^0.5.21",
|
||||
"speed-measure-webpack-plugin": "^1.6.0",
|
||||
"storybook": "10.4.6",
|
||||
"storybook": "10.5.0",
|
||||
"style-loader": "^4.0.0",
|
||||
"stylelint": "^17.14.0",
|
||||
"swc-loader": "^0.2.7",
|
||||
"ts-jest": "^29.4.11",
|
||||
"tscw-config": "^1.1.2",
|
||||
"tsx": "^4.23.0",
|
||||
"tsx": "^4.23.1",
|
||||
"typescript": "5.4.5",
|
||||
"unzipper": "^0.12.5",
|
||||
"vm-browserify": "^1.1.2",
|
||||
|
||||
@@ -18,8 +18,7 @@
|
||||
*/
|
||||
import { Jed as BaseJed, JedOptions, DomainData, Translations } from './jed';
|
||||
|
||||
export * from './jed';
|
||||
export { default as __hack_reexport_jed } from './jed';
|
||||
export { Translations, DomainConfig, DomainData, JedOptions } from './jed';
|
||||
|
||||
/**
|
||||
* Superset supported languages.
|
||||
|
||||
@@ -152,7 +152,9 @@ export const dndAdhocFilterControl: SharedControlConfig<
|
||||
type: 'DndFilterSelect',
|
||||
label: t('Filters'),
|
||||
default: [],
|
||||
description: '',
|
||||
description: t(
|
||||
'Add columns to filter by. When typing or pasting filter values, commas will separate values into multiple entries. To include a comma within a value, wrap it in double quotes: "San Francisco, CA"',
|
||||
),
|
||||
mapStateToProps: ({ datasource, form_data }) => ({
|
||||
columns: isDataset(datasource)
|
||||
? datasource.columns.filter(c => c.filterable)
|
||||
|
||||
@@ -19,8 +19,7 @@
|
||||
export { default as sharedControls } from './sharedControls';
|
||||
// React control components
|
||||
export { default as sharedControlComponents } from './components';
|
||||
export { aggregationControl } from './customControls';
|
||||
export * from './components';
|
||||
export * from './customControls';
|
||||
export * from './components';
|
||||
export * from './mixins';
|
||||
export * from './dndControls';
|
||||
|
||||
@@ -68,6 +68,9 @@ export const D3_FORMAT_OPTIONS: [string, string][] = [
|
||||
'MEMORY_TRANSFER_RATE_BINARY',
|
||||
t('Memory transfer rate in bytes - binary (1024B => 1KiB/s)'),
|
||||
],
|
||||
['LENGTH', t('Length in m (12345m => 12.35km)')],
|
||||
['LENGTH_CM_KM', t('Length in cm (12345678cm => 123.46km)')],
|
||||
['LENGTH_CM_M', t('Length in cm (12345cm => 123.45m)')],
|
||||
];
|
||||
|
||||
export const D3_TIME_FORMAT_DOCS = t(
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
"d3-time": "^3.1.0",
|
||||
"d3-time-format": "^4.1.0",
|
||||
"dayjs": "^1.11.21",
|
||||
"dompurify": "^3.4.11",
|
||||
"dompurify": "^3.4.12",
|
||||
"fetch-retry": "^6.0.0",
|
||||
"handlebars": "^4.7.9",
|
||||
"jed": "^1.1.1",
|
||||
|
||||
@@ -22,7 +22,6 @@ import * as CategoricalColorNamespace from './CategoricalColorNamespace';
|
||||
export { CategoricalColorNamespace };
|
||||
export { default as CategoricalColorScale } from './CategoricalColorScale';
|
||||
export { default as CategoricalScheme } from './CategoricalScheme';
|
||||
export * from './CategoricalScheme';
|
||||
export { default as getCategoricalSchemeRegistry } from './CategoricalSchemeRegistrySingleton';
|
||||
export { default as ColorScheme } from './ColorScheme';
|
||||
export * from './ColorScheme';
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import Markdown from 'markdown-to-jsx';
|
||||
import MarkdownToJsx from 'markdown-to-jsx';
|
||||
import AtomicDesign from './atomic-design.png';
|
||||
|
||||
export default {
|
||||
@@ -25,7 +25,7 @@ export default {
|
||||
|
||||
export const DesignSystem = () => (
|
||||
<>
|
||||
<Markdown>
|
||||
<MarkdownToJsx>
|
||||
{`
|
||||
# Superset Design System
|
||||
|
||||
@@ -39,7 +39,7 @@ export const DesignSystem = () => (
|
||||
|
||||
While the Superset Design System will use Atomic Design principles, we choose a different language to describe the elements.
|
||||
`}
|
||||
</Markdown>
|
||||
</MarkdownToJsx>
|
||||
<table style={{ borderCollapse: 'collapse', margin: '16px 0' }}>
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
@@ -17,14 +17,14 @@
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import Markdown from 'markdown-to-jsx';
|
||||
import MarkdownToJsx from 'markdown-to-jsx';
|
||||
|
||||
export default {
|
||||
title: 'Design System/Components/DropdownContainer/Overview',
|
||||
};
|
||||
|
||||
export const Overview = () => (
|
||||
<Markdown>
|
||||
<MarkdownToJsx>
|
||||
{`
|
||||
# Usage
|
||||
|
||||
@@ -41,5 +41,5 @@ The component accepts any React element which ensures a high level of variabilit
|
||||
To check the component in detail and its interactions, check the [DropdownContainer](/story/design-system-components-dropdowncontainer--component) page.
|
||||
|
||||
`}
|
||||
</Markdown>
|
||||
</MarkdownToJsx>
|
||||
);
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import Markdown from 'markdown-to-jsx';
|
||||
import MarkdownToJsx from 'markdown-to-jsx';
|
||||
|
||||
export default {
|
||||
title: 'Design System/Components/MetadataBar/Overview',
|
||||
@@ -25,7 +25,7 @@ export default {
|
||||
|
||||
export const MetadataBarOverview = () => (
|
||||
<>
|
||||
<Markdown>
|
||||
<MarkdownToJsx>
|
||||
{`
|
||||
# Metadata bar
|
||||
|
||||
@@ -42,8 +42,8 @@ Some of the common applications in Superset are:
|
||||
|
||||
## [Basic example]((./?path=/docs/design-system-components-metadatabar-examples--basic)
|
||||
`}
|
||||
</Markdown>
|
||||
<Markdown>
|
||||
</MarkdownToJsx>
|
||||
<MarkdownToJsx>
|
||||
{`
|
||||
## Variations
|
||||
|
||||
@@ -62,9 +62,9 @@ This process is important to make sure the new type is reviewed by the design te
|
||||
To check each content type in detail and its interactions, check the [MetadataBar](/story/design-system-components-metadatabar-examples--basic) page.
|
||||
Below you can find the configurations for each content type:
|
||||
`}
|
||||
</Markdown>
|
||||
</MarkdownToJsx>
|
||||
|
||||
<Markdown>
|
||||
<MarkdownToJsx>
|
||||
{`
|
||||
\`\`\`
|
||||
export enum MetadataType {
|
||||
@@ -79,9 +79,9 @@ export enum MetadataType {
|
||||
};
|
||||
\`\`\`
|
||||
`}
|
||||
</Markdown>
|
||||
</MarkdownToJsx>
|
||||
|
||||
<Markdown>
|
||||
<MarkdownToJsx>
|
||||
{`
|
||||
\`\`\`
|
||||
export type Dashboards = {
|
||||
@@ -92,9 +92,9 @@ export type Dashboards = {
|
||||
};
|
||||
\`\`\`
|
||||
`}
|
||||
</Markdown>
|
||||
</MarkdownToJsx>
|
||||
|
||||
<Markdown>
|
||||
<MarkdownToJsx>
|
||||
{`
|
||||
\`\`\`
|
||||
export type Description = {
|
||||
@@ -104,9 +104,9 @@ export type Description = {
|
||||
};
|
||||
\`\`\`
|
||||
`}
|
||||
</Markdown>
|
||||
</MarkdownToJsx>
|
||||
|
||||
<Markdown>
|
||||
<MarkdownToJsx>
|
||||
{`
|
||||
\`\`\`
|
||||
export type LastModified = {
|
||||
@@ -117,9 +117,9 @@ export type LastModified = {
|
||||
};
|
||||
\`\`\`
|
||||
`}
|
||||
</Markdown>
|
||||
</MarkdownToJsx>
|
||||
|
||||
<Markdown>
|
||||
<MarkdownToJsx>
|
||||
{`
|
||||
\`\`\`
|
||||
export type Owner = {
|
||||
@@ -131,9 +131,9 @@ export type Owner = {
|
||||
};
|
||||
\`\`\`
|
||||
`}
|
||||
</Markdown>
|
||||
</MarkdownToJsx>
|
||||
|
||||
<Markdown>
|
||||
<MarkdownToJsx>
|
||||
{`
|
||||
\`\`\`
|
||||
export type Rows = {
|
||||
@@ -143,9 +143,9 @@ export type Rows = {
|
||||
};
|
||||
\`\`\`
|
||||
`}
|
||||
</Markdown>
|
||||
</MarkdownToJsx>
|
||||
|
||||
<Markdown>
|
||||
<MarkdownToJsx>
|
||||
{`
|
||||
\`\`\`
|
||||
export type Sql = {
|
||||
@@ -155,9 +155,9 @@ export type Sql = {
|
||||
};
|
||||
\`\`\`
|
||||
`}
|
||||
</Markdown>
|
||||
</MarkdownToJsx>
|
||||
|
||||
<Markdown>
|
||||
<MarkdownToJsx>
|
||||
{`
|
||||
\`\`\`
|
||||
export type Table = {
|
||||
@@ -167,9 +167,9 @@ export type Table = {
|
||||
};
|
||||
\`\`\`
|
||||
`}
|
||||
</Markdown>
|
||||
</MarkdownToJsx>
|
||||
|
||||
<Markdown>
|
||||
<MarkdownToJsx>
|
||||
{`
|
||||
\`\`\`
|
||||
export type Tags = {
|
||||
@@ -179,6 +179,6 @@ export type Tags = {
|
||||
};
|
||||
\`\`\`
|
||||
`}
|
||||
</Markdown>
|
||||
</MarkdownToJsx>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -57,9 +57,12 @@ import {
|
||||
getSuffixIcon,
|
||||
dropDownRenderHelper,
|
||||
handleFilterOptionHelper,
|
||||
makeQuoteAwareTokenizer,
|
||||
mapOptions,
|
||||
getOption,
|
||||
isObject,
|
||||
splitWithQuoteEscaping,
|
||||
stripSurroundingQuotes,
|
||||
isEqual as utilsIsEqual,
|
||||
} from './utils';
|
||||
import {
|
||||
@@ -173,6 +176,21 @@ const AsyncSelect = forwardRef(
|
||||
// request is still pending.
|
||||
const inFlightFetchesRef = useRef(0);
|
||||
const mappedMode = isSingleMode ? undefined : 'multiple';
|
||||
|
||||
const reconcileTokensRef = useRef<(tokens: string[]) => void>(() => {});
|
||||
const fullSelectOptionsRef = useRef<SelectOptionsType>(EMPTY_OPTIONS);
|
||||
|
||||
const quoteAwareTokenSeparators = useMemo(() => {
|
||||
const tokenize = makeQuoteAwareTokenizer(tokenSeparators);
|
||||
return (input: string) => {
|
||||
const tokens = tokenize(input);
|
||||
if (tokens.length !== 1 || tokens[0] !== input) {
|
||||
reconcileTokensRef.current(tokens);
|
||||
}
|
||||
return tokens;
|
||||
};
|
||||
}, [tokenSeparators]);
|
||||
|
||||
const allowFetch = !fetchOnlyOnSearch || inputValue;
|
||||
const [maxTagCount, setMaxTagCount] = useState(
|
||||
propsMaxTagCount ?? MAX_TAG_COUNT,
|
||||
@@ -281,6 +299,39 @@ const AsyncSelect = forwardRef(
|
||||
onSelect?.(selectedItem, option);
|
||||
};
|
||||
|
||||
// The underlying Select silently drops tokens it cannot match against the
|
||||
// rendered options. That happens whenever tokenization outpaces the
|
||||
// debounced option registration, e.g. dead-key keyboard layouts deliver a
|
||||
// closing quote and a separator in a single input event.
|
||||
reconcileTokensRef.current = (tokens: string[]) => {
|
||||
if (isSingleMode || !allowNewOptions) {
|
||||
return;
|
||||
}
|
||||
setTimeout(() => {
|
||||
tokens.forEach(token => {
|
||||
const matched = getOption(token, fullSelectOptionsRef.current, true);
|
||||
const matchedValue = isObject(matched) ? matched.value : matched;
|
||||
if (hasOption(matchedValue ?? token, selectValueRef.current)) {
|
||||
return;
|
||||
}
|
||||
const option = isObject(matched)
|
||||
? (matched as AntdLabeledValue)
|
||||
: { label: token, value: token, isNewOption: true };
|
||||
if (!matched) {
|
||||
setSelectOptions(previous =>
|
||||
hasOption(token, previous, true)
|
||||
? previous
|
||||
: [option, ...previous],
|
||||
);
|
||||
}
|
||||
handleOnSelect(
|
||||
{ label: option.label, value: option.value } as AntdLabeledValue,
|
||||
option as AntdLabeledValue,
|
||||
);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const handleOnDeselect: SelectProps['onDeselect'] = (value, option) => {
|
||||
if (Array.isArray(selectValue)) {
|
||||
if (isLabeledValue(value)) {
|
||||
@@ -318,6 +369,8 @@ const AsyncSelect = forwardRef(
|
||||
[onError],
|
||||
);
|
||||
|
||||
fullSelectOptionsRef.current = fullSelectOptions;
|
||||
|
||||
const mergeData = useCallback(
|
||||
(data: SelectOptionsType) => {
|
||||
let mergedData: SelectOptionsType = [];
|
||||
@@ -394,6 +447,14 @@ const AsyncSelect = forwardRef(
|
||||
initialOptionsRef.current = accumulated;
|
||||
if (!fetchOnlyOnSearch && accumulated.length >= totalCount) {
|
||||
setAllValuesLoaded(true);
|
||||
// Once every base value is loaded, searches are served by
|
||||
// client-side filtering (fetchPage short-circuits), so the
|
||||
// full set must reach the live options even when this
|
||||
// response lands mid-search — otherwise the dropdown stays
|
||||
// empty for the active search.
|
||||
if (!matchesCurrentSearch) {
|
||||
mergeData(accumulated);
|
||||
}
|
||||
}
|
||||
fetchedQueries.current.set(key, totalCount);
|
||||
if (matchesCurrentSearch) {
|
||||
@@ -455,10 +516,11 @@ const AsyncSelect = forwardRef(
|
||||
const handleOnSearch = debounce((search: string) => {
|
||||
const searchValue = search.trim();
|
||||
if (allowNewOptions) {
|
||||
const newOption = searchValue &&
|
||||
!hasOption(searchValue, fullSelectOptions, true) && {
|
||||
label: searchValue,
|
||||
value: searchValue,
|
||||
const unquotedSearch = stripSurroundingQuotes(searchValue);
|
||||
const newOption = unquotedSearch &&
|
||||
!hasOption(unquotedSearch, fullSelectOptions, true) && {
|
||||
label: unquotedSearch,
|
||||
value: unquotedSearch,
|
||||
isNewOption: true,
|
||||
};
|
||||
const cleanSelectOptions = fullSelectOptions.filter(
|
||||
@@ -695,22 +757,11 @@ const AsyncSelect = forwardRef(
|
||||
setSelectValue(value);
|
||||
}
|
||||
} else {
|
||||
// antd v6 widened `tokenSeparators` to `string[] | (input => string[])`;
|
||||
// Superset always uses the array form.
|
||||
// Superset's prop is the array form; antd receives the function form
|
||||
const separators = Array.isArray(tokenSeparators)
|
||||
? tokenSeparators
|
||||
: [];
|
||||
const token = separators.find((token: string) =>
|
||||
pastedText.includes(token),
|
||||
);
|
||||
const array = token
|
||||
? uniq(
|
||||
pastedText
|
||||
.split(token)
|
||||
.map(s => s.trim())
|
||||
.filter(Boolean),
|
||||
)
|
||||
: [pastedText.trim()].filter(Boolean);
|
||||
const array = uniq(splitWithQuoteEscaping(pastedText, separators));
|
||||
const values = (
|
||||
await Promise.all(array.map(item => getPastedTextValue(item)))
|
||||
).filter(item => item !== undefined) as AntdLabeledValue[];
|
||||
@@ -791,7 +842,7 @@ const AsyncSelect = forwardRef(
|
||||
optionRender={option => <Space>{option.label || option.value}</Space>}
|
||||
placeholder={placeholder}
|
||||
showSearch={shouldShowSearch}
|
||||
tokenSeparators={tokenSeparators}
|
||||
tokenSeparators={quoteAwareTokenSeparators}
|
||||
builtinPlacements={DROPDOWN_BUILTIN_PLACEMENTS}
|
||||
value={selectValue}
|
||||
suffixIcon={getSuffixIcon(
|
||||
|
||||
@@ -390,6 +390,93 @@ test('removes duplicated values', async () => {
|
||||
expect(values[3]).toHaveTextContent('d');
|
||||
});
|
||||
|
||||
test('typing an unquoted comma splits the value into a chip', async () => {
|
||||
render(<Select {...defaultProps} mode="multiple" allowNewOptions />);
|
||||
await type('Australia');
|
||||
expect(await findSelectOption('Australia')).toBeInTheDocument();
|
||||
await type(',', undefined, false);
|
||||
const values = await findAllSelectValues();
|
||||
expect(values.length).toBe(1);
|
||||
expect(values[0]).toHaveTextContent('Australia');
|
||||
});
|
||||
|
||||
test('closing quote and separator arriving in a single input event still create the chip', async () => {
|
||||
render(<Select {...defaultProps} mode="multiple" allowNewOptions />);
|
||||
await open();
|
||||
await type('"Australia, U');
|
||||
// dead-key keyboard layouts deliver the closing quote together with the
|
||||
// next character in one input event
|
||||
fireEvent.change(getSelect(), { target: { value: '"Australia, US",' } });
|
||||
await waitFor(() =>
|
||||
expect(getElementsByClassName('.ant-select-selection-item')).toHaveLength(
|
||||
1,
|
||||
),
|
||||
);
|
||||
expect(getElementByClassName('.ant-select-selection-item')).toHaveTextContent(
|
||||
'Australia, US',
|
||||
);
|
||||
});
|
||||
|
||||
test('an options prop update mid-typing keeps the created option tokenizable', async () => {
|
||||
const { rerender } = render(
|
||||
<Select {...defaultProps} mode="multiple" allowNewOptions />,
|
||||
);
|
||||
await type('"Australia, US"');
|
||||
expect(await findSelectOption('Australia, US')).toBeInTheDocument();
|
||||
rerender(
|
||||
<Select
|
||||
{...defaultProps}
|
||||
options={[...OPTIONS]}
|
||||
mode="multiple"
|
||||
allowNewOptions
|
||||
/>,
|
||||
);
|
||||
await type(',', undefined, false);
|
||||
await waitFor(() =>
|
||||
expect(getElementsByClassName('.ant-select-selection-item')).toHaveLength(
|
||||
1,
|
||||
),
|
||||
);
|
||||
expect(getElementByClassName('.ant-select-selection-item')).toHaveTextContent(
|
||||
'Australia, US',
|
||||
);
|
||||
});
|
||||
|
||||
test('typing a comma inside double quotes keeps the value as a single chip', async () => {
|
||||
render(<Select {...defaultProps} mode="multiple" allowNewOptions />);
|
||||
await type('"Australia, US"');
|
||||
expect(await findSelectOption('Australia, US')).toBeInTheDocument();
|
||||
await type(',', undefined, false);
|
||||
const values = await findAllSelectValues();
|
||||
expect(values.length).toBe(1);
|
||||
expect(values[0]).toHaveTextContent('Australia, US');
|
||||
});
|
||||
|
||||
test('prevents the default paste action when pasted values are consumed', async () => {
|
||||
render(<Select {...defaultProps} mode="multiple" allowNewOptions />);
|
||||
const input = getElementByClassName('.ant-select-input');
|
||||
const paste = createEvent.paste(input, {
|
||||
clipboardData: {
|
||||
getData: () => `${OPTIONS[0].label},${OPTIONS[1].label}`,
|
||||
},
|
||||
});
|
||||
fireEvent(input, paste);
|
||||
await findAllSelectValues();
|
||||
expect(paste.defaultPrevented).toBe(true);
|
||||
});
|
||||
|
||||
test('allows the default paste action when nothing is consumable', async () => {
|
||||
render(<Select {...defaultProps} mode="multiple" />);
|
||||
const input = getElementByClassName('.ant-select-input');
|
||||
const paste = createEvent.paste(input, {
|
||||
clipboardData: {
|
||||
getData: () => 'zzz,yyy',
|
||||
},
|
||||
});
|
||||
fireEvent(input, paste);
|
||||
expect(paste.defaultPrevented).toBe(false);
|
||||
});
|
||||
|
||||
test('trims whitespace from pasted comma-separated values', async () => {
|
||||
render(<Select {...defaultProps} mode="multiple" allowNewOptions />);
|
||||
const input = getElementByClassName('.ant-select-input');
|
||||
|
||||
@@ -49,10 +49,13 @@ import {
|
||||
hasOption,
|
||||
isLabeledValue,
|
||||
isObject,
|
||||
makeQuoteAwareTokenizer,
|
||||
mapOptions,
|
||||
mapValues,
|
||||
sortComparatorWithSearchHelper,
|
||||
sortSelectedFirstHelper,
|
||||
splitWithQuoteEscaping,
|
||||
stripSurroundingQuotes,
|
||||
isEqual as utilsIsEqual,
|
||||
} from './utils';
|
||||
import { RawValue, SelectOptionsType, SelectProps } from './types';
|
||||
@@ -192,6 +195,19 @@ const Select = forwardRef(
|
||||
|
||||
const mappedMode = isSingleMode ? undefined : 'multiple';
|
||||
|
||||
const reconcileTokensRef = useRef<(tokens: string[]) => void>(() => {});
|
||||
|
||||
const quoteAwareTokenSeparators = useMemo(() => {
|
||||
const tokenize = makeQuoteAwareTokenizer(tokenSeparators);
|
||||
return (input: string) => {
|
||||
const tokens = tokenize(input);
|
||||
if (tokens.length !== 1 || tokens[0] !== input) {
|
||||
reconcileTokensRef.current(tokens);
|
||||
}
|
||||
return tokens;
|
||||
};
|
||||
}, [tokenSeparators]);
|
||||
|
||||
const sortSelectedFirst = useCallback(
|
||||
(a: AntdLabeledValue, b: AntdLabeledValue) =>
|
||||
sortSelectedFirstHelper(a, b, selectValue),
|
||||
@@ -267,6 +283,11 @@ const Select = forwardRef(
|
||||
);
|
||||
}, [selectOptions, selectValue, sortSelectedFirst]);
|
||||
|
||||
const fullSelectOptionsRef = useRef(fullSelectOptions);
|
||||
fullSelectOptionsRef.current = fullSelectOptions;
|
||||
const selectValueRef = useRef(selectValue);
|
||||
selectValueRef.current = selectValue;
|
||||
|
||||
const enabledOptions = useMemo(
|
||||
() => visibleOptions.filter(option => !option.disabled),
|
||||
[visibleOptions],
|
||||
@@ -366,6 +387,42 @@ const Select = forwardRef(
|
||||
onSelect?.(selectedItem, option);
|
||||
};
|
||||
|
||||
// The underlying Select silently drops tokens it cannot match against the
|
||||
// rendered options. That happens whenever tokenization outpaces the
|
||||
// debounced option registration, e.g. dead-key keyboard layouts deliver a
|
||||
// closing quote and a separator in a single input event.
|
||||
reconcileTokensRef.current = (tokens: string[]) => {
|
||||
if (isSingleMode || !allowNewOptions) {
|
||||
return;
|
||||
}
|
||||
setTimeout(() => {
|
||||
tokens.forEach(token => {
|
||||
const matched = getOption(token, fullSelectOptionsRef.current, true);
|
||||
const matchedValue = isObject(matched) ? matched.value : matched;
|
||||
if (hasOption(matchedValue ?? token, selectValueRef.current)) {
|
||||
return;
|
||||
}
|
||||
const option = isObject(matched)
|
||||
? (matched as AntdLabeledValue)
|
||||
: { label: token, value: token, isNewOption: true };
|
||||
if (!matched) {
|
||||
const addOption = (previous: SelectOptionsType) =>
|
||||
hasOption(token, previous, true)
|
||||
? previous
|
||||
: [option, ...previous];
|
||||
setSelectOptions(addOption);
|
||||
setVisibleOptions(addOption);
|
||||
}
|
||||
handleOnSelect(
|
||||
(labelInValue
|
||||
? { label: option.label, value: option.value }
|
||||
: option.value) as string | AntdLabeledValue,
|
||||
option as AntdLabeledValue,
|
||||
);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const clear = () => {
|
||||
if (isSingleMode) {
|
||||
setSelectValue(undefined);
|
||||
@@ -424,12 +481,14 @@ const Select = forwardRef(
|
||||
const optionsWithoutTemporary = ensureIsArray(fullSelectOptions).filter(
|
||||
opt => !opt.isNewOption,
|
||||
);
|
||||
const unquotedSearch = stripSurroundingQuotes(searchValue);
|
||||
const shouldCreateNewOption =
|
||||
searchValue && !hasOption(searchValue, optionsWithoutTemporary, true);
|
||||
unquotedSearch &&
|
||||
!hasOption(unquotedSearch, optionsWithoutTemporary, true);
|
||||
|
||||
const newOption = shouldCreateNewOption && {
|
||||
label: searchValue,
|
||||
value: searchValue,
|
||||
label: unquotedSearch,
|
||||
value: unquotedSearch,
|
||||
isNewOption: true,
|
||||
};
|
||||
const cleanSelectOptions = ensureIsArray(fullSelectOptions).filter(
|
||||
@@ -721,22 +780,11 @@ const Select = forwardRef(
|
||||
setSelectValue(value);
|
||||
}
|
||||
} else {
|
||||
// antd v6 widened `tokenSeparators` to `string[] | (input => string[])`;
|
||||
// Superset always uses the array form.
|
||||
// Superset's prop is the array form; antd receives the function form
|
||||
const separators = Array.isArray(tokenSeparators)
|
||||
? tokenSeparators
|
||||
: [];
|
||||
const token = separators.find((token: string) =>
|
||||
pastedText.includes(token),
|
||||
);
|
||||
const array = token
|
||||
? uniq(
|
||||
pastedText
|
||||
.split(token)
|
||||
.map(item => item.trim())
|
||||
.filter(Boolean),
|
||||
)
|
||||
: [pastedText.trim()].filter(Boolean);
|
||||
const array = uniq(splitWithQuoteEscaping(pastedText, separators));
|
||||
|
||||
const newOptions: SelectOptionsType = [];
|
||||
// When `allowNewOptionsOnPaste` is set, accept pasted values that are
|
||||
@@ -762,6 +810,10 @@ const Select = forwardRef(
|
||||
})
|
||||
.filter(item => item !== undefined);
|
||||
|
||||
if (values.length > 0) {
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
if (newOptions.length > 0) {
|
||||
const updatedOptions = [...fullSelectOptions, ...newOptions];
|
||||
setSelectOptions(updatedOptions);
|
||||
@@ -854,7 +906,7 @@ const Select = forwardRef(
|
||||
}
|
||||
onClear={handleClear}
|
||||
placeholder={placeholder}
|
||||
tokenSeparators={tokenSeparators}
|
||||
tokenSeparators={quoteAwareTokenSeparators}
|
||||
value={selectValue}
|
||||
virtual={
|
||||
virtual !== undefined
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
/**
|
||||
* 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 {
|
||||
splitWithQuoteEscaping,
|
||||
stripSurroundingQuotes,
|
||||
makeQuoteAwareTokenizer,
|
||||
} from './utils';
|
||||
|
||||
test('stripSurroundingQuotes removes matching surrounding double quotes', () => {
|
||||
expect(stripSurroundingQuotes('"foo"')).toBe('foo');
|
||||
});
|
||||
|
||||
test('stripSurroundingQuotes trims whitespace before stripping', () => {
|
||||
expect(stripSurroundingQuotes(' "foo" ')).toBe('foo');
|
||||
});
|
||||
|
||||
test('stripSurroundingQuotes leaves text untouched when only one side is quoted', () => {
|
||||
expect(stripSurroundingQuotes('"foo')).toBe('"foo');
|
||||
expect(stripSurroundingQuotes('foo"')).toBe('foo"');
|
||||
});
|
||||
|
||||
test('stripSurroundingQuotes preserves quotes in the middle of the string', () => {
|
||||
expect(stripSurroundingQuotes('a"b"c')).toBe('a"b"c');
|
||||
});
|
||||
|
||||
test('stripSurroundingQuotes returns an empty string for `""`', () => {
|
||||
expect(stripSurroundingQuotes('""')).toBe('');
|
||||
});
|
||||
|
||||
test('stripSurroundingQuotes does not strip a single lone quote', () => {
|
||||
expect(stripSurroundingQuotes('"')).toBe('"');
|
||||
});
|
||||
|
||||
test('stripSurroundingQuotes returns an empty string for empty/whitespace input', () => {
|
||||
expect(stripSurroundingQuotes('')).toBe('');
|
||||
expect(stripSurroundingQuotes(' ')).toBe('');
|
||||
});
|
||||
|
||||
test('stripSurroundingQuotes unescapes doubled quotes when stripping', () => {
|
||||
expect(stripSurroundingQuotes('"Bob ""The Builder"", Inc"')).toBe(
|
||||
'Bob "The Builder", Inc',
|
||||
);
|
||||
expect(stripSurroundingQuotes('"a""b"')).toBe('a"b');
|
||||
});
|
||||
|
||||
test('splitWithQuoteEscaping splits by separator and trims tokens', () => {
|
||||
expect(splitWithQuoteEscaping('a, b ,c', [','])).toEqual(['a', 'b', 'c']);
|
||||
});
|
||||
|
||||
test('splitWithQuoteEscaping treats doubled quotes inside a quoted region as a literal quote', () => {
|
||||
expect(splitWithQuoteEscaping('"Bob ""The Builder"", Inc"', [','])).toEqual([
|
||||
'Bob "The Builder", Inc',
|
||||
]);
|
||||
expect(splitWithQuoteEscaping('"a ""b""",c', [','])).toEqual(['a "b"', 'c']);
|
||||
});
|
||||
|
||||
test('splitWithQuoteEscaping preserves separator characters inside double quotes', () => {
|
||||
expect(splitWithQuoteEscaping('"a, b",c', [','])).toEqual(['a, b', 'c']);
|
||||
});
|
||||
|
||||
test('splitWithQuoteEscaping strips quote characters from the output tokens', () => {
|
||||
expect(splitWithQuoteEscaping('"foo","bar"', [','])).toEqual(['foo', 'bar']);
|
||||
});
|
||||
|
||||
test('splitWithQuoteEscaping drops empty tokens from adjacent or edge separators', () => {
|
||||
expect(splitWithQuoteEscaping('a,,b', [','])).toEqual(['a', 'b']);
|
||||
expect(splitWithQuoteEscaping(',a,b,', [','])).toEqual(['a', 'b']);
|
||||
});
|
||||
|
||||
test('splitWithQuoteEscaping treats unclosed quotes as opening a region that runs to end', () => {
|
||||
expect(splitWithQuoteEscaping('"a, b', [','])).toEqual(['a, b']);
|
||||
});
|
||||
|
||||
test('splitWithQuoteEscaping returns the original text when no separator is present', () => {
|
||||
expect(splitWithQuoteEscaping('hello world', [','])).toEqual(['hello world']);
|
||||
});
|
||||
|
||||
test('splitWithQuoteEscaping strips surrounding quotes when no separator is present', () => {
|
||||
expect(splitWithQuoteEscaping('"Canada"', [','])).toEqual(['Canada']);
|
||||
expect(splitWithQuoteEscaping('"Bob ""B"""', [','])).toEqual(['Bob "B"']);
|
||||
});
|
||||
|
||||
test('splitWithQuoteEscaping uses the first separator from the list that appears in the text', () => {
|
||||
expect(splitWithQuoteEscaping('a;b,c', [',', ';'])).toEqual(['a;b', 'c']);
|
||||
expect(splitWithQuoteEscaping('a;b', [',', ';'])).toEqual(['a', 'b']);
|
||||
});
|
||||
|
||||
test('splitWithQuoteEscaping supports multi-character separators', () => {
|
||||
expect(splitWithQuoteEscaping('a, b, c', [', '])).toEqual(['a', 'b', 'c']);
|
||||
});
|
||||
|
||||
test('makeQuoteAwareTokenizer returns input unchanged while quotes are open', () => {
|
||||
const tokenize = makeQuoteAwareTokenizer([',']);
|
||||
expect(tokenize('"Australia, US')).toEqual(['"Australia, US']);
|
||||
});
|
||||
|
||||
test('makeQuoteAwareTokenizer returns input unchanged when separators only appear inside quotes', () => {
|
||||
const tokenize = makeQuoteAwareTokenizer([',']);
|
||||
expect(tokenize('"Australia, US"')).toEqual(['"Australia, US"']);
|
||||
});
|
||||
|
||||
test('makeQuoteAwareTokenizer returns input unchanged when no separator is present', () => {
|
||||
const tokenize = makeQuoteAwareTokenizer([',']);
|
||||
expect(tokenize('Australia')).toEqual(['Australia']);
|
||||
});
|
||||
|
||||
test('makeQuoteAwareTokenizer splits on a trailing unquoted separator', () => {
|
||||
const tokenize = makeQuoteAwareTokenizer([',']);
|
||||
expect(tokenize('Australia,')).toEqual(['Australia']);
|
||||
});
|
||||
|
||||
test('makeQuoteAwareTokenizer splits mixed quoted and unquoted values', () => {
|
||||
const tokenize = makeQuoteAwareTokenizer([',']);
|
||||
expect(tokenize('"Australia, Austria",Canada')).toEqual([
|
||||
'Australia, Austria',
|
||||
'Canada',
|
||||
]);
|
||||
});
|
||||
|
||||
test('makeQuoteAwareTokenizer detects any separator from the list outside quotes', () => {
|
||||
const tokenize = makeQuoteAwareTokenizer([',', '\n']);
|
||||
expect(tokenize('a\nb')).toEqual(['a', 'b']);
|
||||
expect(tokenize('"a\nb"')).toEqual(['"a\nb"']);
|
||||
});
|
||||
@@ -201,6 +201,15 @@ export const dropDownRenderHelper = (
|
||||
);
|
||||
};
|
||||
|
||||
// Strips surrounding double quotes from a string, e.g. `"foo"` → `foo`.
|
||||
export function stripSurroundingQuotes(text: string): string {
|
||||
const trimmed = text.trim();
|
||||
if (trimmed.length > 1 && trimmed.startsWith('"') && trimmed.endsWith('"')) {
|
||||
return trimmed.slice(1, -1).replace(/""/g, '"');
|
||||
}
|
||||
return trimmed;
|
||||
}
|
||||
|
||||
export const handleFilterOptionHelper = (
|
||||
search: string,
|
||||
option: AntdLabeledValue,
|
||||
@@ -216,7 +225,7 @@ export const handleFilterOptionHelper = (
|
||||
}
|
||||
|
||||
if (filterOption) {
|
||||
const searchValue = search.trim().toLowerCase();
|
||||
const searchValue = stripSurroundingQuotes(search).toLowerCase();
|
||||
if (optionFilterProps?.length) {
|
||||
return optionFilterProps.some(prop => {
|
||||
const optionProp = option?.[prop as keyof CustomLabeledValue]
|
||||
@@ -250,3 +259,67 @@ export const mapOptions = (values: SelectOptionsType): Record<string, any>[] =>
|
||||
key: opt.value,
|
||||
...opt,
|
||||
}));
|
||||
|
||||
// Splits text by separators, preserving commas inside double quotes.
|
||||
export function splitWithQuoteEscaping(
|
||||
text: string,
|
||||
separators: string[],
|
||||
): string[] {
|
||||
const separator = separators.find(sep => text.includes(sep));
|
||||
if (!separator) {
|
||||
return [stripSurroundingQuotes(text)].filter(Boolean);
|
||||
}
|
||||
|
||||
const results: string[] = [];
|
||||
let current = '';
|
||||
let inQuotes = false;
|
||||
|
||||
for (let i = 0; i < text.length; i += 1) {
|
||||
const char = text[i];
|
||||
|
||||
if (char === '"') {
|
||||
if (inQuotes && text[i + 1] === '"') {
|
||||
current += '"';
|
||||
i += 1;
|
||||
} else {
|
||||
inQuotes = !inQuotes;
|
||||
}
|
||||
} else if (!inQuotes && text.startsWith(separator, i)) {
|
||||
results.push(current.trim());
|
||||
current = '';
|
||||
i += separator.length - 1;
|
||||
} else {
|
||||
current += char;
|
||||
}
|
||||
}
|
||||
|
||||
if (current.trim()) {
|
||||
results.push(current.trim());
|
||||
}
|
||||
|
||||
return results.filter(Boolean);
|
||||
}
|
||||
|
||||
function hasUnquotedSeparator(text: string, separators: string[]): boolean {
|
||||
let inQuotes = false;
|
||||
for (let i = 0; i < text.length; i += 1) {
|
||||
if (text[i] === '"') {
|
||||
inQuotes = !inQuotes;
|
||||
} else if (!inQuotes && separators.some(sep => text.startsWith(sep, i))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Quote-aware tokenizer for antd's function form of `tokenSeparators`.
|
||||
// Returning the input unchanged tells the Select not to tokenize, so typing
|
||||
// continues while quotes are open or separators only appear inside them.
|
||||
export function makeQuoteAwareTokenizer(
|
||||
separators: string[],
|
||||
): (input: string) => string[] {
|
||||
return (input: string) =>
|
||||
hasUnquotedSeparator(input, separators)
|
||||
? splitWithQuoteEscaping(input, separators)
|
||||
: [input];
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import Markdown from 'markdown-to-jsx';
|
||||
import MarkdownToJsx from 'markdown-to-jsx';
|
||||
|
||||
export default {
|
||||
title: 'Design System/Components/Table/TableOverview',
|
||||
@@ -24,7 +24,7 @@ export default {
|
||||
|
||||
export const Overview = () => (
|
||||
<>
|
||||
<Markdown>
|
||||
<MarkdownToJsx>
|
||||
{`
|
||||
# Table
|
||||
|
||||
@@ -44,9 +44,9 @@ This component provides a general use Table.
|
||||
### [Basic example](./?path=/docs/design-system-components-table-examples--basic)
|
||||
|
||||
`}
|
||||
</Markdown>
|
||||
</MarkdownToJsx>
|
||||
|
||||
<Markdown>
|
||||
<MarkdownToJsx>
|
||||
{`
|
||||
### Data and Columns
|
||||
|
||||
@@ -169,8 +169,8 @@ By default, each column will render the value as simple text. Often you will wan
|
||||
Cell Renderers are React components provided to the optional \`render\` attribute on a column definition that enables injecting a specific React component to enable this.
|
||||
|
||||
`}
|
||||
</Markdown>
|
||||
<Markdown>
|
||||
</MarkdownToJsx>
|
||||
<MarkdownToJsx>
|
||||
{`
|
||||
|
||||
For convenience and consistency, the Table component provides pre-built Cell Renderers for:
|
||||
@@ -193,8 +193,8 @@ The following data types can be displayed in table cells.
|
||||
The table can be set to a loading state simply by setting the loading prop to true | false
|
||||
|
||||
`}
|
||||
</Markdown>
|
||||
<Markdown>
|
||||
</MarkdownToJsx>
|
||||
<MarkdownToJsx>
|
||||
{`
|
||||
---
|
||||
|
||||
@@ -204,8 +204,8 @@ The table displays a set number of rows at a time, the user navigates the table
|
||||
The default page size and page size options for the menu are configurable via the \`pageSizeOptions\` and \`defaultPageSize\` props.
|
||||
NOTE: Pagination controls will only display when the data for the table has more records than the default page size.
|
||||
`}
|
||||
</Markdown>
|
||||
<Markdown>
|
||||
</MarkdownToJsx>
|
||||
<MarkdownToJsx>
|
||||
{`
|
||||
|
||||
\`\`\`
|
||||
@@ -222,8 +222,8 @@ contained in the dataset on the server being paged through. When the user naviga
|
||||
function enabling data fetching to occur when the user changes the page.
|
||||
|
||||
`}
|
||||
</Markdown>
|
||||
<Markdown>
|
||||
</MarkdownToJsx>
|
||||
<MarkdownToJsx>
|
||||
{`
|
||||
|
||||
\`\`\`
|
||||
@@ -293,8 +293,8 @@ NOTE: Row event handlers will be ignored when table is running with \`virtualize
|
||||
Support for row event handlers may be added in future versions of the Table.
|
||||
|
||||
`}
|
||||
</Markdown>
|
||||
<Markdown>
|
||||
</MarkdownToJsx>
|
||||
<MarkdownToJsx>
|
||||
{`
|
||||
|
||||
---
|
||||
@@ -348,8 +348,8 @@ The prop \`resizable\` enables table columns to be resized by the user dragging
|
||||
column to increase or decrease the columns' width
|
||||
|
||||
`}
|
||||
</Markdown>
|
||||
<Markdown>
|
||||
</MarkdownToJsx>
|
||||
<MarkdownToJsx>
|
||||
{`
|
||||
|
||||
### [Drag & Drop Columns](./?path=/docs/design-system-components-table-examples--reorderable-columns)
|
||||
@@ -368,6 +368,6 @@ const handleDrop = (ev:Event) => {
|
||||
}
|
||||
\`\`\`
|
||||
`}
|
||||
</Markdown>
|
||||
</MarkdownToJsx>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import Markdown from 'markdown-to-jsx';
|
||||
import MarkdownToJsx from 'markdown-to-jsx';
|
||||
|
||||
export default {
|
||||
title: 'Design System/Components/Table/Cell Renderers/ActionCell/Overview"',
|
||||
@@ -25,7 +25,7 @@ export default {
|
||||
|
||||
export const ActionCell = () => (
|
||||
<>
|
||||
<Markdown>
|
||||
<MarkdownToJsx>
|
||||
{`
|
||||
# ActionCell
|
||||
|
||||
@@ -34,6 +34,6 @@ specific to the data in the table row that the cell is a member of.
|
||||
|
||||
### [Basic example](./?path=/docs/design-system-components-table-cell-renderers-actioncell--basic)
|
||||
`}
|
||||
</Markdown>
|
||||
</MarkdownToJsx>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import NumberFormatter from '../NumberFormatter';
|
||||
|
||||
export type LengthConvertType = 'm => km' | 'cm => km' | 'cm => m';
|
||||
|
||||
export default function createLengthFormatter(
|
||||
config: {
|
||||
description?: string;
|
||||
id?: string;
|
||||
label?: string;
|
||||
convertType?: LengthConvertType;
|
||||
} = {},
|
||||
) {
|
||||
const { description, id, label, convertType } = config;
|
||||
|
||||
return new NumberFormatter({
|
||||
description,
|
||||
formatFunc: (value: number) => {
|
||||
if (convertType === 'm => km') {
|
||||
return `${(value / 1000).toFixed(2)}km`;
|
||||
}
|
||||
if (convertType === 'cm => km') {
|
||||
return `${(value / 100_000).toFixed(2)}km`;
|
||||
}
|
||||
if (convertType === 'cm => m') {
|
||||
return `${(value / 100).toFixed(2)}m`;
|
||||
}
|
||||
return value.toString();
|
||||
},
|
||||
id: id ?? 'length_format',
|
||||
label: label ?? `Length formatter`,
|
||||
});
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user