Compare commits

..
640 changed files with 48029 additions and 77142 deletions
+8 -61
View File
@@ -5,10 +5,6 @@ updates:
directory: "/"
schedule:
interval: "daily"
groups:
security:
applies-to: "security-updates"
patterns: ["*"]
cooldown:
default-days: 7
@@ -24,6 +20,14 @@ updates:
- dependency-name: "@types/react-dom"
update-types: ["version-update:semver-major"]
- dependency-name: "react-icons"
# JSDOM v30 doesn't play well with Jest v30
# Source: https://jestjs.io/blog#known-issues
# GH thread: https://github.com/jsdom/jsdom/issues/3492
- dependency-name: "jest-environment-jsdom"
# `@swc/plugin-transform-imports` doesn't work with current Webpack-SWC hybrid setup
# See https://github.com/apache/superset/pull/37384#issuecomment-3793991389
# TODO: remove the plugin once Lodash usage has been migrated to a more readily tree-shakeable alternative
- dependency-name: "@swc/plugin-transform-imports"
# deck.gl and luma.gl share strict peer constraints across the root and
# plugin workspaces, and root overrides pin their transitive versions.
# Upgrade both families together in a manually validated change.
@@ -57,9 +61,6 @@ updates:
- npm
- dependabot
groups:
security:
applies-to: "security-updates"
patterns: ["*"]
rjsf:
patterns:
- "@rjsf/*"
@@ -79,23 +80,6 @@ updates:
patterns:
- "ag-grid-react"
- "ag-grid-community"
swc:
patterns:
- "@swc/core"
- "@swc/plugin-emotion"
- "@swc/plugin-transform-imports"
jsonforms:
patterns:
- "@jsonforms/*"
visx:
patterns:
- "@visx/*"
emotion:
patterns:
- "@emotion/*"
fontsource:
patterns:
- "@fontsource/*"
open-pull-requests-limit: 30
versioning-strategy: increase
cooldown:
@@ -114,10 +98,6 @@ updates:
labels:
- pip
- dependabot
groups:
security:
applies-to: "security-updates"
patterns: ["*"]
cooldown:
default-days: 7
@@ -125,10 +105,6 @@ updates:
directory: ".github/actions"
schedule:
interval: "daily"
groups:
security:
applies-to: "security-updates"
patterns: ["*"]
open-pull-requests-limit: 10
versioning-strategy: increase
cooldown:
@@ -139,9 +115,6 @@ updates:
schedule:
interval: "daily"
groups:
security:
applies-to: "security-updates"
patterns: ["*"]
storybook:
patterns:
- "@storybook/*"
@@ -169,10 +142,6 @@ updates:
labels:
- npm
- dependabot
groups:
security:
applies-to: "security-updates"
patterns: ["*"]
versioning-strategy: increase
cooldown:
default-days: 7
@@ -184,29 +153,7 @@ updates:
labels:
- npm
- dependabot
groups:
security:
applies-to: "security-updates"
patterns: ["*"]
open-pull-requests-limit: 10
versioning-strategy: increase
cooldown:
default-days: 7
- package-ecosystem: "npm"
directory: "/superset-embedded-sdk/"
schedule:
interval: "daily"
labels:
- npm
- dependabot
groups:
security:
applies-to: "security-updates"
patterns: ["*"]
babel:
patterns:
- "@babel/*"
versioning-strategy: increase
cooldown:
default-days: 7
@@ -1,71 +0,0 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
name: Check OpenAPI spec drift
on:
push:
branches:
- "master"
- "[0-9].[0-9]*"
pull_request:
types: [synchronize, opened, reopened, ready_for_review]
# No `paths:` filter on purpose, matching enforce-single-migration-head: a
# required check that never runs for a given PR blocks that PR forever. The
# job is ~10s, so it fires on every PR rather than guessing which file edits
# can move the spec.
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
cancel-in-progress: true
permissions:
contents: read
jobs:
check-openapi-spec-drift:
runs-on: ubuntu-26.04
steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Setup Python
uses: ./.github/actions/setup-backend/
with:
# base.txt pins apispec, which decides the generated output: 6.10.0
# renders marshmallow 4's unknown=RAISE as "additionalProperties":
# false while the pinned 6.6.1 does not. Regenerating off-pin
# produces a spec no CI run can reproduce.
requirements-type: base
- name: Regenerate the spec
env:
# No SUPERSET_CONFIG_PATH: the published spec documents the routes a
# default deployment registers. A config enabling feature flags adds
# paths that would 404 for everyone who has not enabled them.
SUPERSET__SQLALCHEMY_DATABASE_URI: "sqlite:///:memory:"
FLASK_APP: "superset.app:create_app()"
run: superset update-api-docs
- name: Assert the published spec is up to date
run: |
if ! git diff --quiet -- docs/static/resources/openapi.json; then
echo "::error::docs/static/resources/openapi.json is stale."
echo "Regenerate it on the pinned requirements, with no config file:"
echo " SUPERSET__SQLALCHEMY_DATABASE_URI='sqlite:///:memory:' \\"
echo " FLASK_APP='superset.app:create_app()' superset update-api-docs"
git diff --stat -- docs/static/resources/openapi.json
exit 1
fi
+2 -2
View File
@@ -67,7 +67,7 @@ jobs:
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4.37.9
uses: github/codeql-action/init@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4.37.7
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
@@ -78,6 +78,6 @@ jobs:
# queries: security-extended,security-and-quality
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4.37.9
uses: github/codeql-action/analyze@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4.37.7
with:
category: "/language:${{matrix.language}}"
-21
View File
@@ -66,27 +66,6 @@ jobs:
- name: "Set up liccheck"
run: |
# liccheck (as of 0.9.2) still does a bare `import pkg_resources`
# without declaring setuptools as a dependency, relying on it
# having historically been bundled. setuptools 81+ (installed
# above via requirements/base.txt) dropped the pkg_resources
# subpackage entirely, so liccheck's own import breaks outright.
#
# Reinstalling an older setuptools would restore pkg_resources but
# would also downgrade the *real* setuptools install, which then
# trips liccheck's own working_set.resolve() -- it cross-checks
# requirements/base.txt's declared `setuptools==84.0.0` against
# what's actually installed, and a downgrade makes those disagree.
#
# Instead, vendor just the pkg_resources/ package files from an
# old setuptools wheel into site-packages, leaving the real
# setuptools install (and its dist-info metadata) untouched. This
# gives liccheck an importable pkg_resources whose own working-set
# scan still correctly reports the real installed setuptools
# version, so no conflict is raised.
pip download "setuptools<81" --no-deps -d /tmp/old-setuptools
python -m zipfile -e /tmp/old-setuptools/setuptools-*.whl /tmp/old-setuptools-extracted/
cp -r /tmp/old-setuptools-extracted/pkg_resources "$(python -c 'import site; print(site.getsitepackages()[0])')/"
uv pip install --system liccheck
- name: "Run liccheck"
run: |
+1 -1
View File
@@ -266,7 +266,7 @@ jobs:
actions-timeline:
needs: [docker-build, docker-compose-image-tag]
if: always()
runs-on: ubuntu-slim
runs-on: ubuntu-26.04
permissions:
actions: read
steps:
+1 -1
View File
@@ -37,7 +37,7 @@ jobs:
persist-credentials: false
submodules: recursive
- name: Setup Java
uses: actions/setup-java@dd06d9cba3e5552c54d9f8ea23572deb30010f7c # v6.0.0
uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5.7.0
with:
distribution: "temurin"
java-version: "11"
@@ -19,7 +19,7 @@ concurrency:
jobs:
validate-all-ghas:
runs-on: ubuntu-26.04 # Don't switch to ubuntu-slim as zizmore-action requires Docker
runs-on: ubuntu-26.04
permissions:
contents: read
# Required for the zizmor action to upload its SARIF results to
@@ -34,7 +34,7 @@ jobs:
- name: Set up Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version-file: "./superset-frontend/.nvmrc"
node-version: "20"
- name: Install Dependencies
# Versions are pinned to avoid ad-hoc, unpinned package installs.
+2 -2
View File
@@ -26,7 +26,7 @@ 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-slim
runs-on: ubuntu-26.04
permissions:
actions: write
pull-requests: read
@@ -69,7 +69,7 @@ jobs:
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-slim
runs-on: ubuntu-24.04
permissions:
actions: write
pull-requests: read
+1 -1
View File
@@ -23,7 +23,7 @@ jobs:
persist-credentials: false
submodules: recursive
- name: Setup Java
uses: actions/setup-java@dd06d9cba3e5552c54d9f8ea23572deb30010f7c # v6.0.0
uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5.7.0
with:
distribution: "temurin"
java-version: "11"
+1 -1
View File
@@ -202,7 +202,7 @@ jobs:
actions-timeline:
needs: pre-commit
if: always()
runs-on: ubuntu-slim
runs-on: ubuntu-26.04
steps:
- uses: Kesin11/actions-timeline@57fc93f20c6da7fbc14063c6d24a2a5627c799ad # v3.2.0
with:
+3 -3
View File
@@ -118,7 +118,7 @@ jobs:
node-version-file: "./docs/.nvmrc"
- name: Setup Python
uses: ./.github/actions/setup-backend/
- uses: actions/setup-java@dd06d9cba3e5552c54d9f8ea23572deb30010f7c # v6.0.0
- uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5.7.0
with:
distribution: "zulu"
java-version: "21"
@@ -141,7 +141,7 @@ jobs:
yarn install --check-cache
- name: Download database diagnostics (if triggered by integration tests)
if: github.event_name == 'workflow_run' && github.event.workflow_run.conclusion == 'success'
uses: dawidd6/action-download-artifact@d63b86af1b34672e53c440b1b83979861906bad7 # v24
uses: dawidd6/action-download-artifact@b6e2e70617bc3265edd6dab6c906732b2f1ae151 # v21
continue-on-error: true
with:
workflow: superset-python-integrationtest.yml
@@ -150,7 +150,7 @@ jobs:
path: docs/src/data/
- name: Try to download latest diagnostics (for push/dispatch triggers)
if: github.event_name != 'workflow_run'
uses: dawidd6/action-download-artifact@d63b86af1b34672e53c440b1b83979861906bad7 # v24
uses: dawidd6/action-download-artifact@b6e2e70617bc3265edd6dab6c906732b2f1ae151 # v21
continue-on-error: true
with:
workflow: superset-python-integrationtest.yml
+1 -1
View File
@@ -140,7 +140,7 @@ jobs:
run: |
yarn install --check-cache
- name: Download database diagnostics from integration tests
uses: dawidd6/action-download-artifact@d63b86af1b34672e53c440b1b83979861906bad7 # v24
uses: dawidd6/action-download-artifact@b6e2e70617bc3265edd6dab6c906732b2f1ae151 # v21
with:
workflow: superset-python-integrationtest.yml
run_id: ${{ github.event.workflow_run.id }}
+1 -1
View File
@@ -354,7 +354,7 @@ jobs:
actions-timeline:
needs: [cypress-matrix, playwright-tests, cypress-matrix-required, playwright-tests-required]
if: always()
runs-on: ubuntu-slim
runs-on: ubuntu-26.04
permissions:
actions: read
steps:
@@ -74,7 +74,7 @@ jobs:
actions-timeline:
needs: test-superset-extensions-cli-package
if: always()
runs-on: ubuntu-slim
runs-on: ubuntu-26.04
steps:
- uses: Kesin11/actions-timeline@57fc93f20c6da7fbc14063c6d24a2a5627c799ad # v3.2.0
with:
+2 -3
View File
@@ -97,7 +97,6 @@ jobs:
mkdir -p ${{ github.workspace }}/superset-frontend/coverage
docker run \
-v ${{ github.workspace }}/superset-frontend/coverage:/app/superset-frontend/coverage \
-e CI=true \
--rm $TAG \
bash -c \
"npm run test -- --coverage --shard=${{ matrix.shard }}/8 --coverageReporters=json"
@@ -111,7 +110,7 @@ jobs:
report-coverage:
needs: [sharded-jest-tests]
if: needs.frontend-build.outputs.should-run == 'true'
runs-on: ubuntu-slim
runs-on: ubuntu-26.04
timeout-minutes: 15
permissions:
id-token: write
@@ -206,7 +205,7 @@ jobs:
actions-timeline:
needs: [report-coverage, lint-frontend, validate-frontend, test-storybook]
if: always()
runs-on: ubuntu-slim
runs-on: ubuntu-26.04
permissions:
actions: read
steps:
+1 -1
View File
@@ -188,7 +188,7 @@ jobs:
actions-timeline:
needs: playwright-tests-experimental
if: always()
runs-on: ubuntu-slim
runs-on: ubuntu-26.04
permissions:
actions: read
steps:
@@ -257,7 +257,7 @@ jobs:
actions-timeline:
needs: [test-mysql, test-postgres, test-sqlite, test-postgres-required]
if: always()
runs-on: ubuntu-slim
runs-on: ubuntu-26.04
permissions:
actions: read
steps:
@@ -165,7 +165,7 @@ jobs:
actions-timeline:
needs: [test-postgres-presto, test-postgres-hive]
if: always()
runs-on: ubuntu-slim
runs-on: ubuntu-26.04
permissions:
actions: read
steps:
@@ -125,7 +125,7 @@ jobs:
unit-tests-required:
needs: [changes, unit-tests]
if: always()
runs-on: ubuntu-slim
runs-on: ubuntu-26.04
timeout-minutes: 5
permissions:
contents: read
@@ -20,7 +20,7 @@ permissions:
jobs:
post-comment:
runs-on: ubuntu-slim
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'
+1 -1
View File
@@ -160,7 +160,7 @@ jobs:
actions-timeline:
needs: [frontend-check-translations, babel-extract]
if: always()
runs-on: ubuntu-slim
runs-on: ubuntu-26.04
permissions:
actions: read
steps:
+3 -3
View File
@@ -35,10 +35,10 @@ jobs:
- name: Install dependencies
working-directory: ./superset-websocket
run: npm ci
- name: lint
- name: eslint
working-directory: ./superset-websocket
run: npm run lint-check
- name: typescript check
run: npm run eslint -- . --quiet
- name: typescript checks
working-directory: ./superset-websocket
run: npm run type
- name: code format check
+3 -3
View File
@@ -88,9 +88,9 @@ repos:
language: system
pass_filenames: true
files: ^superset-frontend/.*\.(js|jsx|ts|tsx)$
- id: oxlint-docs
name: oxlint (docs)
entry: bash -c 'cd docs && FILES=$(printf "%s\n" "$@" | sed "s|^docs/||" | tr "\n" " ") && yarn lint --fix --quiet $FILES'
- id: eslint-docs
name: eslint (docs)
entry: bash -c 'cd docs && FILES=$(printf "%s\n" "$@" | sed "s|^docs/||" | tr "\n" " ") && yarn eslint --fix --quiet $FILES'
language: system
pass_filenames: true
files: ^docs/.*\.(js|jsx|ts|tsx)$
-1
View File
@@ -10,7 +10,6 @@
.stylelintignore
.flake8
.nvmrc
.npmrc
.rat-excludes
.swcrc
.*log
-5
View File
@@ -441,11 +441,6 @@ categories:
url: https://bestpair.info/
contributors: ["@stevensuting"]
- name: Veremes
url: https://www.veremes.com/
logo: veremes.svg
contributors: ["@verdier"]
- name: Virtuoso QA
url: https://www.virtuosoqa.com
+2 -48
View File
@@ -24,51 +24,7 @@ assists people when migrating to a new version.
## Next
- **[BREAKING] `SemanticLayer` and `SemanticView` are now classified in the
Flask-AppBuilder role sets**, so `sync_role_definitions` (run on
`superset init` and on startup) stops granting the built-in **Gamma** role
write access to them. `SemanticLayer` is treated like `Database`
(`READ_ONLY_MODEL_VIEWS`): create/edit/delete become **admin-only**, while
read stays broadly available (its configuration is returned masked).
`SemanticView` is treated like `Dataset` (`GAMMA_READ_ONLY_MODEL_VIEWS`):
writes are Alpha-tier, reads Gamma-tier. Its custom read endpoints
(`views`, `connections`) are mapped to `can_read` so they remain
accessible under the read-only classification. A deployment relying on
Gamma users creating or editing semantic layers/views must grant those
permissions through a custom role. A migration retires the now-unused
`can_views` / `can_connections` permissions left on the `SemanticLayer`
view menu by earlier builds. Two upgrade-time notes on that migration:
it seeds the `SemanticLayer` view menu and its `can_read` PVM if absent, so
even a fresh or flag-off install gains that permission (harmless — the
endpoints 404 while `SEMANTIC_LAYERS` is off); and retiring the stale
permissions remaps any role that held them onto `can_read`, a small
widening — a custom role granted only `can_views` or `can_connections` gains
`can_read` (the semantic-layer list and its masked-configuration detail),
which it could not previously reach. Operators who hand-rolled semantic-layer
roles should re-audit them after upgrading. The feature remains gated behind
the default-off `SEMANTIC_LAYERS` flag.
### Archived dataset purge requires impact confirmation
`GET /api/v1/dataset/<uuid>/purge-impact` returns the charts and distinct
dashboards affected by permanently deleting an archived dataset, together with
an opaque `impact_token`. The dataset purge endpoint now requires that token in
the JSON body as `confirmed_impact_token`. API clients that call
`POST /api/v1/dataset/<uuid>/purge` must fetch and display the impact first;
requests with a missing or malformed token are rejected with 400.
The server rechecks the dependency identities immediately before mutation. If
they changed, purge performs no deletion and returns 409 with a refreshed impact
payload. Clients must display the new impact and obtain renewed confirmation
before retrying. Preview or recheck failures fail closed rather than treating
unknown impact as zero. Chart and dashboard purge endpoints are unchanged.
- `SAMPLES_ROW_LIMIT` is now the default for `/datasource/samples` requests without a valid explicit `per_page`, rather than a hard per-request ceiling; explicit limits are honored up to the existing global row-limit ceiling, matching `/chart/data` SAMPLES requests.
- The `cockroachdb` extra (`pip install apache-superset[cockroachdb]`) now installs `sqlalchemy-cockroachdb` instead of the abandoned `cockroachdb` package, whose SQLAlchemy dialect could not be imported under SQLAlchemy 2.0. Existing environments with the old package installed should `pip uninstall cockroachdb && pip install sqlalchemy-cockroachdb` (or simply reinstall the extra) to restore CockroachDB connectivity.
### Native Value filter "Select all" always targets the whole column
The native "Value" filter's bulk "Select all" / "Clear" controls now operate on the entire loaded set of column values regardless of any text typed into the filter's search box. Previously the "Select all (N)" count briefly flickered to the search-scoped count before settling on the full-column count, and clicking "Select all" while searching could select only the currently matching subset. Search-scoped bulk selection was never a supported feature; the count is now stable and always matches what "Select all" selects (the full column). No configuration change is required.
### MCP tool results preserve stored string values
@@ -273,10 +229,8 @@ Behavior changes to be aware of:
fail fast at the first phase check rather than erroring at setup.
- Dashboard reports whose charts have not mounted are no longer captured
blank: readiness is polled until the deadline, and the report fails loudly
if charts never mount. Large tiled reports also retry Chromium screenshot
stalls and suspicious uniform tiles, while persistent screenshot timeouts
fail loudly. Large tiled thumbnails use the same bounded retries, but retain
their previous failure contract after a persistent timeout.
if charts never mount. Thumbnails and non-report screenshots keep their
previous behavior.
### Embedded (guest token) API responses no longer echo database errors
+3 -3
View File
@@ -62,8 +62,8 @@ yarn version:remove:developer_docs <version> # Remove developer docs version
yarn version:remove:components <version> # Remove components version
# Quality Checks
yarn typecheck # TypeScript validation
yarn lint # Lint TypeScript/JavaScript files
yarn typecheck # TypeScript validation
yarn eslint # Lint TypeScript/JavaScript files
```
## 📁 Documentation Structure
@@ -431,7 +431,7 @@ yarn build
yarn typecheck
# Linting issues
yarn lint
yarn eslint
```
### Version Issues
@@ -14,20 +14,6 @@ Users can configure automated alerts and reports to send dashboards or charts to
Alerts and reports are disabled by default. To turn them on, you'll need to change configuration settings and install a suitable headless browser in your environment.
## Content Format Options
When scheduling an alert or report, you can choose the format used to deliver the dashboard or chart:
- **PDF** a full-page screenshot rendered as a PDF attachment. Available for both dashboards and charts.
- **PNG** a screenshot delivered as an attachment. Emails embed the image inline in the message body; Slack and webhook recipients receive it as an uploaded file. Available for both dashboards and charts.
- **CSV** chart data attached as a `.csv` file. Available for charts only.
- **XLSX (Excel)** chart data attached as a `.xlsx` file. Available for charts only. If the chart's data spans multiple server-paginated files, email delivery detects the bundle and renames the attachment to `.zip`; Slack and webhook deliveries always name the file with an `.xlsx` extension even when the contents are a multi-file ZIP archive.
- **Text** chart data embedded directly in the email or Slack message body. Available only for charts using a text-based visualization type (e.g. Table, Pivot Table, Paired t-test).
Dashboard reports and alerts are limited to the PDF and PNG formats; the CSV, XLSX, and Text options are only available when scheduling a report or alert for an individual chart.
For alerts (not scheduled reports), PNG/PDF screenshots and chart CSV/XLSX data are only generated when the `ALERTS_ATTACH_REPORTS` [feature flag](/admin-docs/configuration/configuring-superset#feature-flags) is enabled (the default); with it disabled, an alert notification is still sent, but without the attachment.
## Requirements
### Commons
-21
View File
@@ -76,27 +76,6 @@ value defined in `DATA_CACHE_CONFIG`.
Note, that by setting the cache timeout to `-1`, caching for charting data can be disabled, either
per chart, dataset or database, or by default if set in `DATA_CACHE_CONFIG`.
Native filter option queries (the dropdown values for native filters) go through this same
chart-data cache, but their freshness needs often differ from regular chart queries, especially for
datasets whose visible values change frequently, including RLS-constrained datasets. Set
`NATIVE_FILTER_OPTIONS_CACHE_TIMEOUT` in `superset_config.py` to give these queries a dedicated
timeout, checked before the chart/dataset/database chain and the `DATA_CACHE_CONFIG` default above:
```python
NATIVE_FILTER_OPTIONS_CACHE_TIMEOUT = 60 # seconds
```
- `None` (default): native filter option queries fall through to the normal
chart/dataset/database/`DATA_CACHE_CONFIG` resolution chain.
- `-1`: disables caching for native filter option queries entirely.
- `0`: passed directly to the cache backend; behavior is backend-specific, so use `-1` if the intent
is to disable caching.
- A positive integer: cache native filter option queries for that many seconds.
This setting only applies to requests detected as native filter option queries. It takes precedence
over the per-chart/dataset/database timeouts, but not over an explicit per-request
`custom_cache_timeout` override (e.g. "Force refresh").
## Limiting Cached Result Size
Very large chart or SQL query results can flood the cache backend (Redis/Memcached), evicting many
@@ -566,55 +566,6 @@ def FLASK_APP_MUTATOR(app: Flask) -> None:
app.before_request_funcs.setdefault(None, []).append(make_session_permanent)
```
## Carrying extra data through chart and dashboard exports
Deployments often attach their own metadata to charts and dashboards — an owning
team, a catalogue entry, a cost centre — and need it to survive an export/import
round trip between environments. `EXTRA_ASSET_EXPORT_FIELDS` and
`EXTRA_ASSET_IMPORT_HANDLER` let you do that without forking the export commands.
The export hook receives the model and the asset type (`"chart"` or `"dashboard"`)
and returns a mapping, which is serialised under the `extra` key of the asset's
YAML. The import hook receives the model, the asset type and that same mapping,
once the asset exists and has an id:
```python
# superset_config.py
def _export_fields(model, asset_type):
return {"owning_team": lookup_team(model)}
def _import_handler(model, asset_type, extra):
if team := extra.get("owning_team"):
assign_team(model, team)
EXTRA_ASSET_EXPORT_FIELDS = _export_fields
EXTRA_ASSET_IMPORT_HANDLER = _import_handler
```
The exported YAML then carries:
```yaml
slice_name: Revenue by region
...
extra:
owning_team: analytics-platform
```
A few things worth knowing:
- **Both hooks are optional and default to `None`.** With neither configured,
exported files are byte-for-byte what they were before, and imports behave
identically.
- **Everything lives under the single `extra` key.** The import schemas reject
unknown top-level fields, so namespacing under `extra` keeps that strictness
while leaving you free to change the shape of your own payload later.
- **An export hook returning `None` or an empty mapping writes nothing**, so
assets without your metadata do not gain an empty `extra` block.
- **The import handler runs after the asset is created or updated**, which means
you can rely on `model.id`. Raising from it will fail the import.
## Customizing the landing page (index view)
The page served at `/` is rendered by an index view. By default Superset registers
@@ -83,26 +83,6 @@ The optional username flag **-u** sets the user used for the datasource import.
superset import_datasources -p <path / filename> -u 'admin'
```
## Importing a Directory of Assets
The `import_directory` command imports a directory of exported assets (databases, datasets,
dashboards, charts) in the same layout produced by the ZIP-based export. Saved queries and tags
included in a full export are not imported by this command:
```bash
superset import_directory <path / directory>
```
As with `import_datasources`, the optional username flag **-u** sets the user assigned as the
owner of the imported assets. The default is 'admin'. Example:
```bash
superset import_directory <path / directory> -u 'admin'
```
If the specified user does not exist, the command fails immediately with an error rather than
importing the assets without an owner.
## Dashboard Import Overwrite Behavior
When importing a dashboard ZIP with the **overwrite** option enabled, any existing charts that are part of the dashboard are **replaced** rather than duplicated. This applies to:
@@ -253,58 +253,6 @@ def my_custom_auth_factory(app):
MCP_AUTH_FACTORY = my_custom_auth_factory
```
### Embedded Guest Authentication
Superset's [embedded dashboards](/user-docs/using-superset/embedding) feature mints short-lived **guest tokens** for anonymous/embedded viewers. The MCP server can accept these same guest tokens, so an embedded guest (e.g. an in-app chatbot next to an embedded dashboard) can call MCP tools scoped to the dashboards/resources named in its token.
This is opt-in and reuses the existing core guest-token configuration -- there is no MCP-specific guest secret or audience.
```python
# superset_config.py
FEATURE_FLAGS = {"EMBEDDED_SUPERSET": True} # required -- guest tokens only exist when this is on
MCP_EMBEDDED_GUEST_AUTH_ENABLED = True # opt-in for the MCP transport (default False)
```
Present the guest token the same way as any other bearer token:
```bash
curl -X POST http://localhost:5008/mcp \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer YOUR_GUEST_TOKEN' \
-d '{"jsonrpc": "2.0", "method": "tools/list", "id": 1}'
```
**How it works**
- A dedicated guest-token verifier validates the token against the same `GUEST_TOKEN_JWT_SECRET` / `GUEST_TOKEN_JWT_ALGO` / `GUEST_TOKEN_JWT_AUDIENCE` config used by embedded dashboards, replays the embedded structural checks, and enforces revocation (global version bumps and per-dashboard `guest_token_revoked_before` cutoffs). It runs *before* the JWT verifier described above, since guest tokens are signed with a different key/algorithm and would otherwise be rejected at the transport.
- A verified guest resolves to a Superset guest user as the highest-priority identity, so it's never downgraded to API-key / `MCP_DEV_USERNAME` / dev-mode resolution. Data access is scoped by the same checks (dataset allowlist, dashboard access, row-level security) that apply to embedded dashboard views.
- Guests are restricted to a default-deny allow-list, `MCP_GUEST_ALLOWED_TOOLS`, regardless of `MCP_RBAC_ENABLED`. Sensitive enumeration tools like `find_users` and `get_instance_info` are denied simply by being absent from the default list.
- Setting `MCP_AUTH_FACTORY` bypasses this whole path: a configured factory is tried first, and the default factory that wires up the guest-token verifier is never reached. If you rely on a custom auth factory (e.g. your own OIDC provider) alongside guest auth, that factory must verify guest tokens itself -- otherwise they're rejected regardless of `MCP_EMBEDDED_GUEST_AUTH_ENABLED`.
```python
# superset_config.py
MCP_GUEST_ALLOWED_TOOLS = {
"get_dashboard_info",
"get_dashboard_layout",
"list_dashboards",
"list_charts",
"get_chart_info",
"get_chart_data",
"get_chart_preview",
} # default
```
**Deployment requirements**
- The MCP server and the service that mints guest tokens (the Superset web app) must share `GUEST_TOKEN_JWT_SECRET` and `GUEST_TOKEN_JWT_AUDIENCE`. Set `GUEST_TOKEN_JWT_AUDIENCE` explicitly -- if it's unset, audience validation falls back to the URL host, which can differ between the two services and cause every guest token to fail validation.
- The `GUEST_ROLE_NAME` role (default `Public`) must exist -- a guest token is rejected if it does not.
- Don't set `MCP_DEV_USERNAME` on a deployment that also serves embedded guests.
- Restart the MCP process after toggling `EMBEDDED_SUPERSET` or `MCP_EMBEDDED_GUEST_AUTH_ENABLED` -- guest auth is wired up once at startup.
:::warning
`GUEST_TOKEN_JWT_SECRET` guards both the web embedding and MCP guest-auth surfaces. With `MCP_EMBEDDED_GUEST_AUTH_ENABLED` on, leaving it at its insecure default isn't just a forgery risk -- the MCP server refuses to start (`MCPAuthConfigError`) until you set a real secret shared with the guest-token minting service.
:::
---
## Connecting AI Clients
@@ -557,8 +505,6 @@ All MCP settings go in `superset_config.py`. Defaults are defined in `superset/m
| `MCP_DEV_USERNAME` | -- | Superset username for development mode (no auth) |
| `MCP_RBAC_ENABLED` | `True` | Enforce Superset's role-based access control on MCP tool calls. When `True`, each tool checks that the authenticated user has the required FAB permission before executing. Disable only for testing or trusted-network deployments. |
| `MCP_DISABLED_TOOLS` | `set()` | Set of tool names to remove from the MCP server at startup. Disabled tools are never advertised to AI clients during tool discovery. Useful when a custom extension tool should replace a built-in Superset tool. See [Disabling built-in tools](#disabling-built-in-tools). |
| `MCP_DISABLED_CHART_PLUGINS` | `frozenset()` | Set of chart type plugin names (e.g. `"handlebars"`) to hide from `generate_chart`. Does not affect `get_chart_type_schema`. See [Disabling chart type plugins](#disabling-chart-type-plugins). |
| `MCP_CHART_PLUGIN_ENABLED_FUNC` | `None` | Callable `(chart_type: str) -> bool` evaluated per registry lookup for dynamic enable/disable decisions. Takes precedence over `MCP_DISABLED_CHART_PLUGINS` when set. See [Disabling chart type plugins](#disabling-chart-type-plugins). |
### Authentication
@@ -575,8 +521,6 @@ All MCP settings go in `superset_config.py`. Defaults are defined in `superset/m
| `MCP_JWT_DEBUG_ERRORS` | `False` | Log detailed JWT errors server-side (never exposed in HTTP responses per RFC 6750) |
| `MCP_AUTH_FACTORY` | `None` | Custom auth provider factory `(flask_app) -> auth_provider`. Takes precedence over built-in JWT |
| `MCP_USER_RESOLVER` | `None` | Custom function `(app, access_token) -> username` to extract a Superset username from a validated JWT token. When `None`, the default resolver checks `preferred_username`, `username`, `email`, and `sub` claims in that order. |
| `MCP_EMBEDDED_GUEST_AUTH_ENABLED` | `False` | Accept embedded [guest tokens](#embedded-guest-authentication) as Bearer auth. Also requires the `EMBEDDED_SUPERSET` feature flag. |
| `MCP_GUEST_ALLOWED_TOOLS` | see [default list](#embedded-guest-authentication) | The only tool names callable by embedded guests (default-deny), regardless of `MCP_RBAC_ENABLED`. |
### Response Size Guard
@@ -949,39 +893,6 @@ MCP_DISABLED_TOOLS = {"extensions.myorg.myextension.some_tool"}
Specifying a tool name that does not exist logs a warning at startup and is otherwise ignored — it will not prevent the server from starting.
:::
## Disabling chart type plugins
The `generate_chart` tool dispatches per chart type (`xy`, `table`, `pie`, `pivot_table`, `mixed_timeseries`, `handlebars`, `big_number`, `histogram`, `box_plot`, `waterfall`) to a registered chart type plugin. Two settings let operators enable or disable individual chart type plugins at runtime, without a code deploy.
### Static deny-list
Set `MCP_DISABLED_CHART_PLUGINS` in your `superset_config.py` to a set of chart type names:
```python
# superset_config.py
# Emergency kill switch: hide "handlebars" from all callers
MCP_DISABLED_CHART_PLUGINS = {"handlebars"}
```
Disabled chart types stay registered but are filtered out at lookup time: they're never listed in `generate_chart`'s supported chart types, and `generate_chart` calls for them are rejected. `get_chart_type_schema` consults its own static schema/example map rather than the registry filter, so a disabled chart type's schema remains queryable through that tool even though `generate_chart` will reject it.
### Dynamic predicate
For per-request control (A/B tests, gradual rollout, entitlement checks), set `MCP_CHART_PLUGIN_ENABLED_FUNC` to a callable. It's evaluated as `enabled_func(chart_type: str) -> bool` on every registry lookup, and it takes precedence over `MCP_DISABLED_CHART_PLUGINS` when set:
```python
# superset_config.py
from flask import g
def MCP_CHART_PLUGIN_ENABLED_FUNC(chart_type: str) -> bool:
flags = getattr(g, "feature_flags", {})
return flags.get(f"mcp_chart_{chart_type}", True)
```
The callable must be cheap and in-process (consult already-loaded feature flags or request-local context) -- do not perform network I/O per call. If it raises, the registry fails closed (the plugin is hidden) and logs a warning.
## Security Best Practices
- **Use TLS** for all production MCP endpoints -- place the server behind a reverse proxy with HTTPS
-54
View File
@@ -88,27 +88,6 @@ THEME_DARK = {
# - OS preference detection is automatically enabled
```
### Default Theme Mode
By default, Superset mimics the visitor's OS/browser preference (light or dark) for
sessions that don't have a saved user preference. Use `THEME_DEFAULT_MODE` to override
that starting point instance-wide for the standard application:
```python
# Default theme mode for sessions without a saved user preference.
# One of "default" (always light), "dark" (always dark), or "system" (mimic OS preference).
THEME_DEFAULT_MODE = "dark"
```
- `"system"` (the default) preserves the existing behavior of following the OS/browser
preference, provided a dark theme is configured (`THEME_DARK` is not `None`). If no dark
theme is available, Superset always starts in light mode regardless of this setting.
- `"default"` or `"dark"` forces that starting mode for first-time visitors; users can still switch themes manually afterward if both `THEME_DEFAULT` and `THEME_DARK` are available.
- A user's own saved preference, once they toggle the theme switcher, always takes precedence over `THEME_DEFAULT_MODE`.
- `THEME_DEFAULT_MODE` has no effect on embedded dashboards: the embed SDK sets the
starting mode via its own `themeMode` URL parameter, which takes precedence and falls
back to light mode when the parameter is absent.
### App Branding
The application name shown in the browser title bar and navigation can be
@@ -240,39 +219,6 @@ Font URLs are validated against a configurable allowlist. By default, fonts from
This feature works with the stock Docker image - no custom build required!
## Results Grid Configuration Overrides
Superset exposes a handful of opt-in tokens that customize the appearance of
the results grid in SQL Lab. These tokens have no effect unless explicitly
set, since the results grid otherwise falls back to its built-in defaults.
```python
THEME_DEFAULT = {
"token": {
"colorPrimary": "#2893B3",
# ... other Ant Design tokens
# Results grid overrides
"resultsGridRowHeight": 32,
"resultsGridHeaderFontSize": 13,
"resultsGridHeaderFontWeight": 600,
"resultsGridBorderRadius": 4,
"resultsGridNoStriping": True,
}
}
```
| Token | Type | Description |
| --- | --- | --- |
| `resultsGridRowHeight` | `number` | Row and header height, in pixels. |
| `resultsGridHeaderFontSize` | `number` | Header cell font size, in pixels. |
| `resultsGridHeaderFontWeight` | `number` | Header cell font weight. |
| `resultsGridBorderRadius` | `number` | Border radius applied to the grid and its wrapper, in pixels. |
| `resultsGridNoStriping` | `boolean` | When `true`, disables alternating row background striping. |
These tokens can also be set through the theme CRUD interface's JSON editor,
alongside any other Superset-specific tokens.
## ECharts Configuration Overrides
:::note
-85
View File
@@ -132,33 +132,6 @@ tables in the **Permissions** dropdown. To select the data sources you want to a
You can then confirm with users assigned to the **Gamma** role that they see the
objects (dashboards and slices) associated with the tables you just extended them.
### Actionable Access-Denied Messages
When a viewer opens a chart or dashboard built on a dataset they don't have access to, Superset
shows a plain-language error naming the dataset (or tables, for SQL Lab) and, when known, the
dataset owners to contact. You can also point users at your own access-request process by setting
`PERMISSION_INSTRUCTIONS_LINK` in `superset_config.py`:
```python
PERMISSION_INSTRUCTIONS_LINK = (
"https://access.example.com/request?dataset={datasource_name}&table={table_names}&user={username}"
)
```
The URL may include any of the following placeholders, which are substituted with URL-encoded
values so the link can deep-link into an internal ticketing or access-request tool with the
denied resource pre-filled:
- `{datasource_id}` — id of the denied dataset (chart/dashboard errors only)
- `{datasource_name}` — name of the denied dataset (chart/dashboard errors only)
- `{table_names}` — comma-separated denied table names (SQL Lab/table errors only)
- `{username}` — the requesting user's username
Only the placeholders that apply to the triggering error type are filled in; the rest are replaced
with an empty string, so a single URL template can cover both chart/dashboard and SQL Lab denials.
A URL with no placeholders is used as-is, and leaving `PERMISSION_INSTRUCTIONS_LINK` unset (the
default) omits the "Request access" link, falling back to owner-contact guidance.
### Subjects
A **subject** is a unified identity that can be granted access to Superset resources such as
@@ -270,42 +243,6 @@ Each subject in the response includes flat scalar ids (`user_id`, `role_id`, `gr
than a nested object, so callers can match directly on whichever id they already have — only the
id field matching the subject's `type` is populated; the others are `null`.
#### Extending Editorship with EXTRA_EDITORS_RESOLVER
Deployments that grant edit access to a dashboard or chart through a mechanism outside
Superset's own Subject-based `editors` list — for example, a folder-permission system or an
internal directory service — can plug that logic in with `EXTRA_EDITORS_RESOLVER`:
```python
def extra_editors_resolver(resource):
# `resource` is the Dashboard or Slice instance being checked.
# Return Subject instances, raw subject ids, or dicts with an `id` key.
return [...]
EXTRA_EDITORS_RESOLVER = extra_editors_resolver
```
The resolver's result is unioned with the resource's own `editors` for editorship checks: it
feeds `is_editor`, `raise_for_editorship`, save-as, and soft-delete restore. When
`EXTRA_EDITORS_RESOLVER` is configured, the usual lockout-prevention behavior — automatically
re-adding a non-admin who removes themselves from a resource's editors — is skipped, since the
deployment has its own way of keeping the resource editable. This skip is global to the setting,
not per-resource: it still applies on a resource where the resolver currently returns no
subjects, so a resolver that can't guarantee an alternate editor for every resource can let the
last editor remove themselves and leave it uneditable by non-admins.
Resolved subject ids are also surfaced as `extra_editors` in the chart and dashboard `GET`
responses, so API clients can distinguish resolver-granted editorship from the resource's own
`editors` list. This field is attached after serialization and isn't part of the OpenAPI response
schema, so generated API clients won't see it as a typed field.
Because the resolver is arbitrary per-deployment Python rather than a SQL-expressible condition,
editorship it grants cannot be reflected in list-view filtering (for example, the soft-deleted
archive is scoped to editors via a SQL query). It does still run once per row on chart and
dashboard list responses to populate `extra_editors`, so a slow or unavailable external resolver
affects ordinary list requests, not just direct per-object checks.
### Dashboard Access Control
Access to dashboards is managed via editors (subjects that have edit permissions to the dashboard).
@@ -646,28 +583,6 @@ SELECT * FROM (
queries run against tables that have associated datasets with RLS filters will then have
the appropriate predicates injected automatically.
#### RLS Indicator in the Dataset List and Explore
When a dataset has one or more RLS filters that apply to it, Superset shows a lock
icon badge next to the dataset name in the **Datasets** list and next to the dataset
selector in **Explore**. Hovering over the badge shows a tooltip listing each
applicable filter's name, filter type (Regular or Base), group key (if any), assigned
subjects (labeled "Roles" in the tooltip, but may include users and groups too), and
clause.
This badge also surfaces filters that are inherited from the physical tables
referenced by a virtual (SQL-based) dataset, as described above. Inherited filters
are marked "from underlying table" in the tooltip, and a summary note is shown
whenever any of the listed filters are inherited rather than assigned directly to
the dataset. Inherited-filter detection depends on Superset's SQL parser being able
to identify the referenced tables and match them to a physical dataset by name,
schema, and database, so it's best-effort: unparseable or unmatched references won't
surface a filter on the badge even if one would apply at query time.
The badge is a visibility aid only — it does not change which filters are applied to
a query. Use the RLS REST API described below if you need to confirm exactly which
filters affect a dataset.
#### Checking RLS Filters via the API
You can use the RLS REST API to audit which filters are configured and which datasets
@@ -284,6 +284,8 @@ automatically run whenever you make a Git commit.
#### Running Pre-commit Manually
Before pushing, run `pre-commit run --all-files` to catch issues locally before CI.
You can also run the pre-commit checks manually in various ways:
- **Run pre-commit on all files (same as CI):**
@@ -493,8 +495,8 @@ Frontend assets (TypeScript, JavaScript, CSS, and images) must be compiled in or
First, be sure you are using the following versions of Node.js and npm:
- `Node.js`: Version 24 (see `superset-frontend/.nvmrc` for the exact version)
- `npm`: Version 11
- `Node.js`: Version 22 (LTS)
- `npm`: Version 10
We recommend using [nvm](https://github.com/nvm-sh/nvm) to manage your node environment:
@@ -507,8 +509,8 @@ export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion
cd superset-frontend
nvm install
nvm use
nvm install --lts
nvm use --lts
```
Or if you use the default macOS starting with Catalina shell `zsh`, try:
@@ -114,8 +114,8 @@ function MyExtension() {
## Source Links
- [Story file](https://github.com/apache/superset/blob/master/superset-frontend/packages/superset-core/src/components/Alert/Alert.stories.tsx)
- [Component source](https://github.com/apache/superset/blob/master/superset-frontend/packages/superset-core/src/components/Alert/index.tsx)
- [Story file](https://github.com/apache/superset/blob/master/superset-frontend/packages/superset-core/src/ui/components/Alert/Alert.stories.tsx)
- [Component source](https://github.com/apache/superset/blob/master/superset-frontend/packages/superset-core/src/ui/components/Alert/index.tsx)
---
@@ -47,8 +47,8 @@ export function MyExtensionPanel() {
Components in `@apache-superset/core/components` are automatically documented here. To add a new extension component:
1. Add the component to `superset-frontend/packages/superset-core/src/components/`
2. Export it from `superset-frontend/packages/superset-core/src/components/index.ts`
1. Add the component to `superset-frontend/packages/superset-core/src/ui/components/`
2. Export it from `superset-frontend/packages/superset-core/src/ui/components/index.ts`
3. Create a Storybook story with an `Interactive` export:
```tsx
@@ -49,10 +49,10 @@ curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
| Method | Endpoint | Description |
| ------ | ---------------------------------------------------------------------- | ------------------------------- |
| `GET` | [Get the CSRF token](/developer-docs/6.1.0/api/get-the-csrf-token) | `/api/v1/security/csrf_token/` |
| `POST` | [Get a guest token](/developer-docs/6.1.0/api/get-a-guest-token) | `/api/v1/security/guest_token/` |
| `POST` | [Create security login](/developer-docs/6.1.0/api/create-security-login) | `/api/v1/security/login` |
| `POST` | [Create security refresh](/developer-docs/6.1.0/api/create-security-refresh) | `/api/v1/security/refresh` |
| `GET` | [Get the CSRF token](/developer-docs/api/get-the-csrf-token) | `/api/v1/security/csrf_token/` |
| `POST` | [Get a guest token](/developer-docs/api/get-a-guest-token) | `/api/v1/security/guest_token/` |
| `POST` | [Create security login](/developer-docs/api/create-security-login) | `/api/v1/security/login` |
| `POST` | [Create security refresh](/developer-docs/api/create-security-refresh) | `/api/v1/security/refresh` |
---
@@ -65,34 +65,34 @@ curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
| Method | Endpoint | Description |
| -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------- |
| `DELETE` | [Bulk delete dashboards](/developer-docs/6.1.0/api/bulk-delete-dashboards) | `/api/v1/dashboard/` |
| `GET` | [Get a list of dashboards](/developer-docs/6.1.0/api/get-a-list-of-dashboards) | `/api/v1/dashboard/` |
| `POST` | [Create a new dashboard](/developer-docs/6.1.0/api/create-a-new-dashboard) | `/api/v1/dashboard/` |
| `GET` | [Get metadata information about this API resource (dashboard--info)](/developer-docs/6.1.0/api/get-metadata-information-about-this-api-resource-dashboard-info) | `/api/v1/dashboard/_info` |
| `GET` | [Get a dashboard detail information](/developer-docs/6.1.0/api/get-a-dashboard-detail-information) | `/api/v1/dashboard/{id_or_slug}` |
| `GET` | [Get a dashboard's chart definitions.](/developer-docs/6.1.0/api/get-a-dashboards-chart-definitions) | `/api/v1/dashboard/{id_or_slug}/charts` |
| `POST` | [Create a copy of an existing dashboard](/developer-docs/6.1.0/api/create-a-copy-of-an-existing-dashboard) | `/api/v1/dashboard/{id_or_slug}/copy/` |
| `GET` | [Get dashboard's datasets](/developer-docs/6.1.0/api/get-dashboards-datasets) | `/api/v1/dashboard/{id_or_slug}/datasets` |
| `DELETE` | [Delete a dashboard's embedded configuration](/developer-docs/6.1.0/api/delete-a-dashboards-embedded-configuration) | `/api/v1/dashboard/{id_or_slug}/embedded` |
| `GET` | [Get the dashboard's embedded configuration](/developer-docs/6.1.0/api/get-the-dashboards-embedded-configuration) | `/api/v1/dashboard/{id_or_slug}/embedded` |
| `POST` | [Set a dashboard's embedded configuration](/developer-docs/6.1.0/api/set-a-dashboards-embedded-configuration) | `/api/v1/dashboard/{id_or_slug}/embedded` |
| `PUT` | [Update dashboard by id_or_slug embedded](/developer-docs/6.1.0/api/update-dashboard-by-id-or-slug-embedded) | `/api/v1/dashboard/{id_or_slug}/embedded` |
| `GET` | [Get dashboard's tabs](/developer-docs/6.1.0/api/get-dashboards-tabs) | `/api/v1/dashboard/{id_or_slug}/tabs` |
| `DELETE` | [Delete a dashboard](/developer-docs/6.1.0/api/delete-a-dashboard) | `/api/v1/dashboard/{pk}` |
| `PUT` | [Update a dashboard](/developer-docs/6.1.0/api/update-a-dashboard) | `/api/v1/dashboard/{pk}` |
| `POST` | [Compute and cache a screenshot (dashboard-pk-cache-dashboard-screenshot)](/developer-docs/6.1.0/api/compute-and-cache-a-screenshot-dashboard-pk-cache-dashboard-screenshot) | `/api/v1/dashboard/{pk}/cache_dashboard_screenshot/` |
| `PUT` | [Update chart customizations configuration for a dashboard.](/developer-docs/6.1.0/api/update-chart-customizations-configuration-for-a-dashboard) | `/api/v1/dashboard/{pk}/chart_customizations` |
| `PUT` | [Update colors configuration for a dashboard.](/developer-docs/6.1.0/api/update-colors-configuration-for-a-dashboard) | `/api/v1/dashboard/{pk}/colors` |
| `GET` | [Export dashboard as example bundle](/developer-docs/6.1.0/api/export-dashboard-as-example-bundle) | `/api/v1/dashboard/{pk}/export_as_example/` |
| `DELETE` | [Remove the dashboard from the user favorite list](/developer-docs/6.1.0/api/remove-the-dashboard-from-the-user-favorite-list) | `/api/v1/dashboard/{pk}/favorites/` |
| `POST` | [Mark the dashboard as favorite for the current user](/developer-docs/6.1.0/api/mark-the-dashboard-as-favorite-for-the-current-user) | `/api/v1/dashboard/{pk}/favorites/` |
| `PUT` | [Update native filters configuration for a dashboard.](/developer-docs/6.1.0/api/update-native-filters-configuration-for-a-dashboard) | `/api/v1/dashboard/{pk}/filters` |
| `GET` | [Get a computed screenshot from cache (dashboard-pk-screenshot-digest)](/developer-docs/6.1.0/api/get-a-computed-screenshot-from-cache-dashboard-pk-screenshot-digest) | `/api/v1/dashboard/{pk}/screenshot/{digest}/` |
| `GET` | [Get dashboard's thumbnail](/developer-docs/6.1.0/api/get-dashboards-thumbnail) | `/api/v1/dashboard/{pk}/thumbnail/{digest}/` |
| `GET` | [Download multiple dashboards as YAML files](/developer-docs/6.1.0/api/download-multiple-dashboards-as-yaml-files) | `/api/v1/dashboard/export/` |
| `GET` | [Check favorited dashboards for current user](/developer-docs/6.1.0/api/check-favorited-dashboards-for-current-user) | `/api/v1/dashboard/favorite_status/` |
| `POST` | [Import dashboard(s) with associated charts/datasets/databases](/developer-docs/6.1.0/api/import-dashboard-s-with-associated-charts-datasets-databases) | `/api/v1/dashboard/import/` |
| `GET` | [Get related fields data (dashboard-related-column-name)](/developer-docs/6.1.0/api/get-related-fields-data-dashboard-related-column-name) | `/api/v1/dashboard/related/{column_name}` |
| `DELETE` | [Bulk delete dashboards](/developer-docs/api/bulk-delete-dashboards) | `/api/v1/dashboard/` |
| `GET` | [Get a list of dashboards](/developer-docs/api/get-a-list-of-dashboards) | `/api/v1/dashboard/` |
| `POST` | [Create a new dashboard](/developer-docs/api/create-a-new-dashboard) | `/api/v1/dashboard/` |
| `GET` | [Get metadata information about this API resource (dashboard--info)](/developer-docs/api/get-metadata-information-about-this-api-resource-dashboard-info) | `/api/v1/dashboard/_info` |
| `GET` | [Get a dashboard detail information](/developer-docs/api/get-a-dashboard-detail-information) | `/api/v1/dashboard/{id_or_slug}` |
| `GET` | [Get a dashboard's chart definitions.](/developer-docs/api/get-a-dashboards-chart-definitions) | `/api/v1/dashboard/{id_or_slug}/charts` |
| `POST` | [Create a copy of an existing dashboard](/developer-docs/api/create-a-copy-of-an-existing-dashboard) | `/api/v1/dashboard/{id_or_slug}/copy/` |
| `GET` | [Get dashboard's datasets](/developer-docs/api/get-dashboards-datasets) | `/api/v1/dashboard/{id_or_slug}/datasets` |
| `DELETE` | [Delete a dashboard's embedded configuration](/developer-docs/api/delete-a-dashboards-embedded-configuration) | `/api/v1/dashboard/{id_or_slug}/embedded` |
| `GET` | [Get the dashboard's embedded configuration](/developer-docs/api/get-the-dashboards-embedded-configuration) | `/api/v1/dashboard/{id_or_slug}/embedded` |
| `POST` | [Set a dashboard's embedded configuration](/developer-docs/api/set-a-dashboards-embedded-configuration) | `/api/v1/dashboard/{id_or_slug}/embedded` |
| `PUT` | [Update dashboard by id_or_slug embedded](/developer-docs/api/update-dashboard-by-id-or-slug-embedded) | `/api/v1/dashboard/{id_or_slug}/embedded` |
| `GET` | [Get dashboard's tabs](/developer-docs/api/get-dashboards-tabs) | `/api/v1/dashboard/{id_or_slug}/tabs` |
| `DELETE` | [Delete a dashboard](/developer-docs/api/delete-a-dashboard) | `/api/v1/dashboard/{pk}` |
| `PUT` | [Update a dashboard](/developer-docs/api/update-a-dashboard) | `/api/v1/dashboard/{pk}` |
| `POST` | [Compute and cache a screenshot (dashboard-pk-cache-dashboard-screenshot)](/developer-docs/api/compute-and-cache-a-screenshot-dashboard-pk-cache-dashboard-screenshot) | `/api/v1/dashboard/{pk}/cache_dashboard_screenshot/` |
| `PUT` | [Update chart customizations configuration for a dashboard.](/developer-docs/api/update-chart-customizations-configuration-for-a-dashboard) | `/api/v1/dashboard/{pk}/chart_customizations` |
| `PUT` | [Update colors configuration for a dashboard.](/developer-docs/api/update-colors-configuration-for-a-dashboard) | `/api/v1/dashboard/{pk}/colors` |
| `GET` | [Export dashboard as example bundle](/developer-docs/api/export-dashboard-as-example-bundle) | `/api/v1/dashboard/{pk}/export_as_example/` |
| `DELETE` | [Remove the dashboard from the user favorite list](/developer-docs/api/remove-the-dashboard-from-the-user-favorite-list) | `/api/v1/dashboard/{pk}/favorites/` |
| `POST` | [Mark the dashboard as favorite for the current user](/developer-docs/api/mark-the-dashboard-as-favorite-for-the-current-user) | `/api/v1/dashboard/{pk}/favorites/` |
| `PUT` | [Update native filters configuration for a dashboard.](/developer-docs/api/update-native-filters-configuration-for-a-dashboard) | `/api/v1/dashboard/{pk}/filters` |
| `GET` | [Get a computed screenshot from cache (dashboard-pk-screenshot-digest)](/developer-docs/api/get-a-computed-screenshot-from-cache-dashboard-pk-screenshot-digest) | `/api/v1/dashboard/{pk}/screenshot/{digest}/` |
| `GET` | [Get dashboard's thumbnail](/developer-docs/api/get-dashboards-thumbnail) | `/api/v1/dashboard/{pk}/thumbnail/{digest}/` |
| `GET` | [Download multiple dashboards as YAML files](/developer-docs/api/download-multiple-dashboards-as-yaml-files) | `/api/v1/dashboard/export/` |
| `GET` | [Check favorited dashboards for current user](/developer-docs/api/check-favorited-dashboards-for-current-user) | `/api/v1/dashboard/favorite_status/` |
| `POST` | [Import dashboard(s) with associated charts/datasets/databases](/developer-docs/api/import-dashboard-s-with-associated-charts-datasets-databases) | `/api/v1/dashboard/import/` |
| `GET` | [Get related fields data (dashboard-related-column-name)](/developer-docs/api/get-related-fields-data-dashboard-related-column-name) | `/api/v1/dashboard/related/{column_name}` |
</details>
@@ -101,26 +101,26 @@ curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
| Method | Endpoint | Description |
| -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------- |
| `DELETE` | [Bulk delete charts](/developer-docs/6.1.0/api/bulk-delete-charts) | `/api/v1/chart/` |
| `GET` | [Get a list of charts](/developer-docs/6.1.0/api/get-a-list-of-charts) | `/api/v1/chart/` |
| `POST` | [Create a new chart](/developer-docs/6.1.0/api/create-a-new-chart) | `/api/v1/chart/` |
| `GET` | [Get metadata information about this API resource (chart--info)](/developer-docs/6.1.0/api/get-metadata-information-about-this-api-resource-chart-info) | `/api/v1/chart/_info` |
| `GET` | [Get a chart detail information](/developer-docs/6.1.0/api/get-a-chart-detail-information) | `/api/v1/chart/{id_or_uuid}` |
| `DELETE` | [Delete a chart](/developer-docs/6.1.0/api/delete-a-chart) | `/api/v1/chart/{pk}` |
| `PUT` | [Update a chart](/developer-docs/6.1.0/api/update-a-chart) | `/api/v1/chart/{pk}` |
| `GET` | [Compute and cache a screenshot (chart-pk-cache-screenshot)](/developer-docs/6.1.0/api/compute-and-cache-a-screenshot-chart-pk-cache-screenshot) | `/api/v1/chart/{pk}/cache_screenshot/` |
| `GET` | [Return payload data response for a chart](/developer-docs/6.1.0/api/return-payload-data-response-for-a-chart) | `/api/v1/chart/{pk}/data/` |
| `DELETE` | [Remove the chart from the user favorite list](/developer-docs/6.1.0/api/remove-the-chart-from-the-user-favorite-list) | `/api/v1/chart/{pk}/favorites/` |
| `POST` | [Mark the chart as favorite for the current user](/developer-docs/6.1.0/api/mark-the-chart-as-favorite-for-the-current-user) | `/api/v1/chart/{pk}/favorites/` |
| `GET` | [Get a computed screenshot from cache (chart-pk-screenshot-digest)](/developer-docs/6.1.0/api/get-a-computed-screenshot-from-cache-chart-pk-screenshot-digest) | `/api/v1/chart/{pk}/screenshot/{digest}/` |
| `GET` | [Get chart thumbnail](/developer-docs/6.1.0/api/get-chart-thumbnail) | `/api/v1/chart/{pk}/thumbnail/{digest}/` |
| `POST` | [Return payload data response for the given query (chart-data)](/developer-docs/6.1.0/api/return-payload-data-response-for-the-given-query-chart-data) | `/api/v1/chart/data` |
| `GET` | [Return payload data response for the given query (chart-data-cache-key)](/developer-docs/6.1.0/api/return-payload-data-response-for-the-given-query-chart-data-cache-key) | `/api/v1/chart/data/{cache_key}` |
| `GET` | [Download multiple charts as YAML files](/developer-docs/6.1.0/api/download-multiple-charts-as-yaml-files) | `/api/v1/chart/export/` |
| `GET` | [Check favorited charts for current user](/developer-docs/6.1.0/api/check-favorited-charts-for-current-user) | `/api/v1/chart/favorite_status/` |
| `POST` | [Import chart(s) with associated datasets and databases](/developer-docs/6.1.0/api/import-chart-s-with-associated-datasets-and-databases) | `/api/v1/chart/import/` |
| `GET` | [Get related fields data (chart-related-column-name)](/developer-docs/6.1.0/api/get-related-fields-data-chart-related-column-name) | `/api/v1/chart/related/{column_name}` |
| `PUT` | [Warm up the cache for the chart](/developer-docs/6.1.0/api/warm-up-the-cache-for-the-chart) | `/api/v1/chart/warm_up_cache` |
| `DELETE` | [Bulk delete charts](/developer-docs/api/bulk-delete-charts) | `/api/v1/chart/` |
| `GET` | [Get a list of charts](/developer-docs/api/get-a-list-of-charts) | `/api/v1/chart/` |
| `POST` | [Create a new chart](/developer-docs/api/create-a-new-chart) | `/api/v1/chart/` |
| `GET` | [Get metadata information about this API resource (chart--info)](/developer-docs/api/get-metadata-information-about-this-api-resource-chart-info) | `/api/v1/chart/_info` |
| `GET` | [Get a chart detail information](/developer-docs/api/get-a-chart-detail-information) | `/api/v1/chart/{id_or_uuid}` |
| `DELETE` | [Delete a chart](/developer-docs/api/delete-a-chart) | `/api/v1/chart/{pk}` |
| `PUT` | [Update a chart](/developer-docs/api/update-a-chart) | `/api/v1/chart/{pk}` |
| `GET` | [Compute and cache a screenshot (chart-pk-cache-screenshot)](/developer-docs/api/compute-and-cache-a-screenshot-chart-pk-cache-screenshot) | `/api/v1/chart/{pk}/cache_screenshot/` |
| `GET` | [Return payload data response for a chart](/developer-docs/api/return-payload-data-response-for-a-chart) | `/api/v1/chart/{pk}/data/` |
| `DELETE` | [Remove the chart from the user favorite list](/developer-docs/api/remove-the-chart-from-the-user-favorite-list) | `/api/v1/chart/{pk}/favorites/` |
| `POST` | [Mark the chart as favorite for the current user](/developer-docs/api/mark-the-chart-as-favorite-for-the-current-user) | `/api/v1/chart/{pk}/favorites/` |
| `GET` | [Get a computed screenshot from cache (chart-pk-screenshot-digest)](/developer-docs/api/get-a-computed-screenshot-from-cache-chart-pk-screenshot-digest) | `/api/v1/chart/{pk}/screenshot/{digest}/` |
| `GET` | [Get chart thumbnail](/developer-docs/api/get-chart-thumbnail) | `/api/v1/chart/{pk}/thumbnail/{digest}/` |
| `POST` | [Return payload data response for the given query (chart-data)](/developer-docs/api/return-payload-data-response-for-the-given-query-chart-data) | `/api/v1/chart/data` |
| `GET` | [Return payload data response for the given query (chart-data-cache-key)](/developer-docs/api/return-payload-data-response-for-the-given-query-chart-data-cache-key) | `/api/v1/chart/data/{cache_key}` |
| `GET` | [Download multiple charts as YAML files](/developer-docs/api/download-multiple-charts-as-yaml-files) | `/api/v1/chart/export/` |
| `GET` | [Check favorited charts for current user](/developer-docs/api/check-favorited-charts-for-current-user) | `/api/v1/chart/favorite_status/` |
| `POST` | [Import chart(s) with associated datasets and databases](/developer-docs/api/import-chart-s-with-associated-datasets-and-databases) | `/api/v1/chart/import/` |
| `GET` | [Get related fields data (chart-related-column-name)](/developer-docs/api/get-related-fields-data-chart-related-column-name) | `/api/v1/chart/related/{column_name}` |
| `PUT` | [Warm up the cache for the chart](/developer-docs/api/warm-up-the-cache-for-the-chart) | `/api/v1/chart/warm_up_cache` |
</details>
@@ -129,25 +129,25 @@ curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
| Method | Endpoint | Description |
| -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------- |
| `DELETE` | [Bulk delete datasets](/developer-docs/6.1.0/api/bulk-delete-datasets) | `/api/v1/dataset/` |
| `GET` | [Get a list of datasets](/developer-docs/6.1.0/api/get-a-list-of-datasets) | `/api/v1/dataset/` |
| `POST` | [Create a new dataset](/developer-docs/6.1.0/api/create-a-new-dataset) | `/api/v1/dataset/` |
| `GET` | [Get metadata information about this API resource (dataset--info)](/developer-docs/6.1.0/api/get-metadata-information-about-this-api-resource-dataset-info) | `/api/v1/dataset/_info` |
| `GET` | [Get a dataset](/developer-docs/6.1.0/api/get-a-dataset) | `/api/v1/dataset/{id_or_uuid}` |
| `GET` | [Get charts and dashboards count associated to a dataset](/developer-docs/6.1.0/api/get-charts-and-dashboards-count-associated-to-a-dataset) | `/api/v1/dataset/{id_or_uuid}/related_objects` |
| `DELETE` | [Delete a dataset](/developer-docs/6.1.0/api/delete-a-dataset) | `/api/v1/dataset/{pk}` |
| `PUT` | [Update a dataset](/developer-docs/6.1.0/api/update-a-dataset) | `/api/v1/dataset/{pk}` |
| `DELETE` | [Delete a dataset column](/developer-docs/6.1.0/api/delete-a-dataset-column) | `/api/v1/dataset/{pk}/column/{column_id}` |
| `GET` | [Get dataset drill info](/developer-docs/6.1.0/api/get-dataset-drill-info) | `/api/v1/dataset/{pk}/drill_info/` |
| `DELETE` | [Delete a dataset metric](/developer-docs/6.1.0/api/delete-a-dataset-metric) | `/api/v1/dataset/{pk}/metric/{metric_id}` |
| `PUT` | [Refresh and update columns of a dataset](/developer-docs/6.1.0/api/refresh-and-update-columns-of-a-dataset) | `/api/v1/dataset/{pk}/refresh` |
| `GET` | [Get distinct values from field data (dataset-distinct-column-name)](/developer-docs/6.1.0/api/get-distinct-values-from-field-data-dataset-distinct-column-name) | `/api/v1/dataset/distinct/{column_name}` |
| `POST` | [Duplicate a dataset](/developer-docs/6.1.0/api/duplicate-a-dataset) | `/api/v1/dataset/duplicate` |
| `GET` | [Download multiple datasets as YAML files](/developer-docs/6.1.0/api/download-multiple-datasets-as-yaml-files) | `/api/v1/dataset/export/` |
| `POST` | [Retrieve a table by name, or create it if it does not exist](/developer-docs/6.1.0/api/retrieve-a-table-by-name-or-create-it-if-it-does-not-exist) | `/api/v1/dataset/get_or_create/` |
| `POST` | [Import dataset(s) with associated databases](/developer-docs/6.1.0/api/import-dataset-s-with-associated-databases) | `/api/v1/dataset/import/` |
| `GET` | [Get related fields data (dataset-related-column-name)](/developer-docs/6.1.0/api/get-related-fields-data-dataset-related-column-name) | `/api/v1/dataset/related/{column_name}` |
| `PUT` | [Warm up the cache for each chart powered by the given table](/developer-docs/6.1.0/api/warm-up-the-cache-for-each-chart-powered-by-the-given-table) | `/api/v1/dataset/warm_up_cache` |
| `DELETE` | [Bulk delete datasets](/developer-docs/api/bulk-delete-datasets) | `/api/v1/dataset/` |
| `GET` | [Get a list of datasets](/developer-docs/api/get-a-list-of-datasets) | `/api/v1/dataset/` |
| `POST` | [Create a new dataset](/developer-docs/api/create-a-new-dataset) | `/api/v1/dataset/` |
| `GET` | [Get metadata information about this API resource (dataset--info)](/developer-docs/api/get-metadata-information-about-this-api-resource-dataset-info) | `/api/v1/dataset/_info` |
| `GET` | [Get a dataset](/developer-docs/api/get-a-dataset) | `/api/v1/dataset/{id_or_uuid}` |
| `GET` | [Get charts and dashboards count associated to a dataset](/developer-docs/api/get-charts-and-dashboards-count-associated-to-a-dataset) | `/api/v1/dataset/{id_or_uuid}/related_objects` |
| `DELETE` | [Delete a dataset](/developer-docs/api/delete-a-dataset) | `/api/v1/dataset/{pk}` |
| `PUT` | [Update a dataset](/developer-docs/api/update-a-dataset) | `/api/v1/dataset/{pk}` |
| `DELETE` | [Delete a dataset column](/developer-docs/api/delete-a-dataset-column) | `/api/v1/dataset/{pk}/column/{column_id}` |
| `GET` | [Get dataset drill info](/developer-docs/api/get-dataset-drill-info) | `/api/v1/dataset/{pk}/drill_info/` |
| `DELETE` | [Delete a dataset metric](/developer-docs/api/delete-a-dataset-metric) | `/api/v1/dataset/{pk}/metric/{metric_id}` |
| `PUT` | [Refresh and update columns of a dataset](/developer-docs/api/refresh-and-update-columns-of-a-dataset) | `/api/v1/dataset/{pk}/refresh` |
| `GET` | [Get distinct values from field data (dataset-distinct-column-name)](/developer-docs/api/get-distinct-values-from-field-data-dataset-distinct-column-name) | `/api/v1/dataset/distinct/{column_name}` |
| `POST` | [Duplicate a dataset](/developer-docs/api/duplicate-a-dataset) | `/api/v1/dataset/duplicate` |
| `GET` | [Download multiple datasets as YAML files](/developer-docs/api/download-multiple-datasets-as-yaml-files) | `/api/v1/dataset/export/` |
| `POST` | [Retrieve a table by name, or create it if it does not exist](/developer-docs/api/retrieve-a-table-by-name-or-create-it-if-it-does-not-exist) | `/api/v1/dataset/get_or_create/` |
| `POST` | [Import dataset(s) with associated databases](/developer-docs/api/import-dataset-s-with-associated-databases) | `/api/v1/dataset/import/` |
| `GET` | [Get related fields data (dataset-related-column-name)](/developer-docs/api/get-related-fields-data-dataset-related-column-name) | `/api/v1/dataset/related/{column_name}` |
| `PUT` | [Warm up the cache for each chart powered by the given table](/developer-docs/api/warm-up-the-cache-for-each-chart-powered-by-the-given-table) | `/api/v1/dataset/warm_up_cache` |
</details>
@@ -156,36 +156,36 @@ curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
| Method | Endpoint | Description |
| -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------- |
| `GET` | [Get a list of databases](/developer-docs/6.1.0/api/get-a-list-of-databases) | `/api/v1/database/` |
| `POST` | [Create a new database](/developer-docs/6.1.0/api/create-a-new-database) | `/api/v1/database/` |
| `GET` | [Get metadata information about this API resource (database--info)](/developer-docs/6.1.0/api/get-metadata-information-about-this-api-resource-database-info) | `/api/v1/database/_info` |
| `DELETE` | [Delete a database](/developer-docs/6.1.0/api/delete-a-database) | `/api/v1/database/{pk}` |
| `GET` | [Get a database](/developer-docs/6.1.0/api/get-a-database) | `/api/v1/database/{pk}` |
| `PUT` | [Change a database](/developer-docs/6.1.0/api/change-a-database) | `/api/v1/database/{pk}` |
| `GET` | [Get all catalogs from a database](/developer-docs/6.1.0/api/get-all-catalogs-from-a-database) | `/api/v1/database/{pk}/catalogs/` |
| `GET` | [Get a database connection info](/developer-docs/6.1.0/api/get-a-database-connection-info) | `/api/v1/database/{pk}/connection` |
| `GET` | [Get function names supported by a database](/developer-docs/6.1.0/api/get-function-names-supported-by-a-database) | `/api/v1/database/{pk}/function_names/` |
| `GET` | [Get charts and dashboards count associated to a database](/developer-docs/6.1.0/api/get-charts-and-dashboards-count-associated-to-a-database) | `/api/v1/database/{pk}/related_objects/` |
| `GET` | [The list of the database schemas where to upload information](/developer-docs/6.1.0/api/the-list-of-the-database-schemas-where-to-upload-information) | `/api/v1/database/{pk}/schemas_access_for_file_upload/` |
| `GET` | [Get all schemas from a database](/developer-docs/6.1.0/api/get-all-schemas-from-a-database) | `/api/v1/database/{pk}/schemas/` |
| `GET` | [Get database select star for table (database-pk-select-star-table-name)](/developer-docs/6.1.0/api/get-database-select-star-for-table-database-pk-select-star-table-name) | `/api/v1/database/{pk}/select_star/{table_name}/` |
| `GET` | [Get database select star for table (database-pk-select-star-table-name-schema-name)](/developer-docs/6.1.0/api/get-database-select-star-for-table-database-pk-select-star-table-name-schema-name) | `/api/v1/database/{pk}/select_star/{table_name}/{schema_name}/` |
| `POST` | [Re-sync all permissions for a database connection](/developer-docs/6.1.0/api/re-sync-all-permissions-for-a-database-connection) | `/api/v1/database/{pk}/sync_permissions/` |
| `GET` | [Get table extra metadata (database-pk-table-extra-table-name-schema-name)](/developer-docs/6.1.0/api/get-table-extra-metadata-database-pk-table-extra-table-name-schema-name) | `/api/v1/database/{pk}/table_extra/{table_name}/{schema_name}/` |
| `GET` | [Get table metadata](/developer-docs/6.1.0/api/get-table-metadata) | `/api/v1/database/{pk}/table_metadata/` |
| `GET` | [Get table extra metadata (database-pk-table-metadata-extra)](/developer-docs/6.1.0/api/get-table-extra-metadata-database-pk-table-metadata-extra) | `/api/v1/database/{pk}/table_metadata/extra/` |
| `GET` | [Get database table metadata](/developer-docs/6.1.0/api/get-database-table-metadata) | `/api/v1/database/{pk}/table/{table_name}/{schema_name}/` |
| `GET` | [Get a list of tables for given database](/developer-docs/6.1.0/api/get-a-list-of-tables-for-given-database) | `/api/v1/database/{pk}/tables/` |
| `POST` | [Upload a file to a database table](/developer-docs/6.1.0/api/upload-a-file-to-a-database-table) | `/api/v1/database/{pk}/upload/` |
| `POST` | [Validate arbitrary SQL](/developer-docs/6.1.0/api/validate-arbitrary-sql) | `/api/v1/database/{pk}/validate_sql/` |
| `GET` | [Get names of databases currently available](/developer-docs/6.1.0/api/get-names-of-databases-currently-available) | `/api/v1/database/available/` |
| `GET` | [Download database(s) and associated dataset(s) as a zip file](/developer-docs/6.1.0/api/download-database-s-and-associated-dataset-s-as-a-zip-file) | `/api/v1/database/export/` |
| `POST` | [Import database(s) with associated datasets](/developer-docs/6.1.0/api/import-database-s-with-associated-datasets) | `/api/v1/database/import/` |
| `GET` | [Receive personal access tokens from OAuth2](/developer-docs/6.1.0/api/receive-personal-access-tokens-from-o-auth-2) | `/api/v1/database/oauth2/` |
| `GET` | [Get related fields data (database-related-column-name)](/developer-docs/6.1.0/api/get-related-fields-data-database-related-column-name) | `/api/v1/database/related/{column_name}` |
| `POST` | [Test a database connection](/developer-docs/6.1.0/api/test-a-database-connection) | `/api/v1/database/test_connection/` |
| `POST` | [Upload a file and returns file metadata](/developer-docs/6.1.0/api/upload-a-file-and-returns-file-metadata) | `/api/v1/database/upload_metadata/` |
| `POST` | [Validate database connection parameters](/developer-docs/6.1.0/api/validate-database-connection-parameters) | `/api/v1/database/validate_parameters/` |
| `GET` | [Get a list of databases](/developer-docs/api/get-a-list-of-databases) | `/api/v1/database/` |
| `POST` | [Create a new database](/developer-docs/api/create-a-new-database) | `/api/v1/database/` |
| `GET` | [Get metadata information about this API resource (database--info)](/developer-docs/api/get-metadata-information-about-this-api-resource-database-info) | `/api/v1/database/_info` |
| `DELETE` | [Delete a database](/developer-docs/api/delete-a-database) | `/api/v1/database/{pk}` |
| `GET` | [Get a database](/developer-docs/api/get-a-database) | `/api/v1/database/{pk}` |
| `PUT` | [Change a database](/developer-docs/api/change-a-database) | `/api/v1/database/{pk}` |
| `GET` | [Get all catalogs from a database](/developer-docs/api/get-all-catalogs-from-a-database) | `/api/v1/database/{pk}/catalogs/` |
| `GET` | [Get a database connection info](/developer-docs/api/get-a-database-connection-info) | `/api/v1/database/{pk}/connection` |
| `GET` | [Get function names supported by a database](/developer-docs/api/get-function-names-supported-by-a-database) | `/api/v1/database/{pk}/function_names/` |
| `GET` | [Get charts and dashboards count associated to a database](/developer-docs/api/get-charts-and-dashboards-count-associated-to-a-database) | `/api/v1/database/{pk}/related_objects/` |
| `GET` | [The list of the database schemas where to upload information](/developer-docs/api/the-list-of-the-database-schemas-where-to-upload-information) | `/api/v1/database/{pk}/schemas_access_for_file_upload/` |
| `GET` | [Get all schemas from a database](/developer-docs/api/get-all-schemas-from-a-database) | `/api/v1/database/{pk}/schemas/` |
| `GET` | [Get database select star for table (database-pk-select-star-table-name)](/developer-docs/api/get-database-select-star-for-table-database-pk-select-star-table-name) | `/api/v1/database/{pk}/select_star/{table_name}/` |
| `GET` | [Get database select star for table (database-pk-select-star-table-name-schema-name)](/developer-docs/api/get-database-select-star-for-table-database-pk-select-star-table-name-schema-name) | `/api/v1/database/{pk}/select_star/{table_name}/{schema_name}/` |
| `POST` | [Re-sync all permissions for a database connection](/developer-docs/api/re-sync-all-permissions-for-a-database-connection) | `/api/v1/database/{pk}/sync_permissions/` |
| `GET` | [Get table extra metadata (database-pk-table-extra-table-name-schema-name)](/developer-docs/api/get-table-extra-metadata-database-pk-table-extra-table-name-schema-name) | `/api/v1/database/{pk}/table_extra/{table_name}/{schema_name}/` |
| `GET` | [Get table metadata](/developer-docs/api/get-table-metadata) | `/api/v1/database/{pk}/table_metadata/` |
| `GET` | [Get table extra metadata (database-pk-table-metadata-extra)](/developer-docs/api/get-table-extra-metadata-database-pk-table-metadata-extra) | `/api/v1/database/{pk}/table_metadata/extra/` |
| `GET` | [Get database table metadata](/developer-docs/api/get-database-table-metadata) | `/api/v1/database/{pk}/table/{table_name}/{schema_name}/` |
| `GET` | [Get a list of tables for given database](/developer-docs/api/get-a-list-of-tables-for-given-database) | `/api/v1/database/{pk}/tables/` |
| `POST` | [Upload a file to a database table](/developer-docs/api/upload-a-file-to-a-database-table) | `/api/v1/database/{pk}/upload/` |
| `POST` | [Validate arbitrary SQL](/developer-docs/api/validate-arbitrary-sql) | `/api/v1/database/{pk}/validate_sql/` |
| `GET` | [Get names of databases currently available](/developer-docs/api/get-names-of-databases-currently-available) | `/api/v1/database/available/` |
| `GET` | [Download database(s) and associated dataset(s) as a zip file](/developer-docs/api/download-database-s-and-associated-dataset-s-as-a-zip-file) | `/api/v1/database/export/` |
| `POST` | [Import database(s) with associated datasets](/developer-docs/api/import-database-s-with-associated-datasets) | `/api/v1/database/import/` |
| `GET` | [Receive personal access tokens from OAuth2](/developer-docs/api/receive-personal-access-tokens-from-o-auth-2) | `/api/v1/database/oauth2/` |
| `GET` | [Get related fields data (database-related-column-name)](/developer-docs/api/get-related-fields-data-database-related-column-name) | `/api/v1/database/related/{column_name}` |
| `POST` | [Test a database connection](/developer-docs/api/test-a-database-connection) | `/api/v1/database/test_connection/` |
| `POST` | [Upload a file and returns file metadata](/developer-docs/api/upload-a-file-and-returns-file-metadata) | `/api/v1/database/upload_metadata/` |
| `POST` | [Validate database connection parameters](/developer-docs/api/validate-database-connection-parameters) | `/api/v1/database/validate_parameters/` |
</details>
@@ -196,7 +196,7 @@ curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
| Method | Endpoint | Description |
| ------ | ------------------------------------------------------------------------------------------------------------------------------------------ | ------------------ |
| `GET` | [Assemble Explore related information in a single endpoint](/developer-docs/6.1.0/api/assemble-explore-related-information-in-a-single-endpoint) | `/api/v1/explore/` |
| `GET` | [Assemble Explore related information in a single endpoint](/developer-docs/api/assemble-explore-related-information-in-a-single-endpoint) | `/api/v1/explore/` |
</details>
@@ -205,13 +205,13 @@ curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
| Method | Endpoint | Description |
| ------ | -------------------------------------------------------------------------------------------------------------------- | ------------------------------------ |
| `GET` | [Get the bootstrap data for SqlLab page](/developer-docs/6.1.0/api/get-the-bootstrap-data-for-sql-lab-page) | `/api/v1/sqllab/` |
| `POST` | [Estimate the SQL query execution cost](/developer-docs/6.1.0/api/estimate-the-sql-query-execution-cost) | `/api/v1/sqllab/estimate/` |
| `POST` | [Execute a SQL query](/developer-docs/6.1.0/api/execute-a-sql-query) | `/api/v1/sqllab/execute/` |
| `POST` | [Export SQL query results to CSV with streaming](/developer-docs/6.1.0/api/export-sql-query-results-to-csv-with-streaming) | `/api/v1/sqllab/export_streaming/` |
| `GET` | [Export the SQL query results to a CSV](/developer-docs/6.1.0/api/export-the-sql-query-results-to-a-csv) | `/api/v1/sqllab/export/{client_id}/` |
| `POST` | [Format SQL code](/developer-docs/6.1.0/api/format-sql-code) | `/api/v1/sqllab/format_sql/` |
| `GET` | [Get the result of a SQL query execution](/developer-docs/6.1.0/api/get-the-result-of-a-sql-query-execution) | `/api/v1/sqllab/results/` |
| `GET` | [Get the bootstrap data for SqlLab page](/developer-docs/api/get-the-bootstrap-data-for-sql-lab-page) | `/api/v1/sqllab/` |
| `POST` | [Estimate the SQL query execution cost](/developer-docs/api/estimate-the-sql-query-execution-cost) | `/api/v1/sqllab/estimate/` |
| `POST` | [Execute a SQL query](/developer-docs/api/execute-a-sql-query) | `/api/v1/sqllab/execute/` |
| `POST` | [Export SQL query results to CSV with streaming](/developer-docs/api/export-sql-query-results-to-csv-with-streaming) | `/api/v1/sqllab/export_streaming/` |
| `GET` | [Export the SQL query results to a CSV](/developer-docs/api/export-the-sql-query-results-to-a-csv) | `/api/v1/sqllab/export/{client_id}/` |
| `POST` | [Format SQL code](/developer-docs/api/format-sql-code) | `/api/v1/sqllab/format_sql/` |
| `GET` | [Get the result of a SQL query execution](/developer-docs/api/get-the-result-of-a-sql-query-execution) | `/api/v1/sqllab/results/` |
</details>
@@ -220,23 +220,23 @@ curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
| Method | Endpoint | Description |
| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------- |
| `GET` | [Get a list of queries](/developer-docs/6.1.0/api/get-a-list-of-queries) | `/api/v1/query/` |
| `GET` | [Get query detail information](/developer-docs/6.1.0/api/get-query-detail-information) | `/api/v1/query/{pk}` |
| `GET` | [Get distinct values from field data (query-distinct-column-name)](/developer-docs/6.1.0/api/get-distinct-values-from-field-data-query-distinct-column-name) | `/api/v1/query/distinct/{column_name}` |
| `GET` | [Get related fields data (query-related-column-name)](/developer-docs/6.1.0/api/get-related-fields-data-query-related-column-name) | `/api/v1/query/related/{column_name}` |
| `POST` | [Manually stop a query with client_id](/developer-docs/6.1.0/api/manually-stop-a-query-with-client-id) | `/api/v1/query/stop` |
| `GET` | [Get a list of queries that changed after last_updated_ms](/developer-docs/6.1.0/api/get-a-list-of-queries-that-changed-after-last-updated-ms) | `/api/v1/query/updated_since` |
| `DELETE` | [Bulk delete saved queries](/developer-docs/6.1.0/api/bulk-delete-saved-queries) | `/api/v1/saved_query/` |
| `GET` | [Get a list of saved queries](/developer-docs/6.1.0/api/get-a-list-of-saved-queries) | `/api/v1/saved_query/` |
| `POST` | [Create a saved query](/developer-docs/6.1.0/api/create-a-saved-query) | `/api/v1/saved_query/` |
| `GET` | [Get metadata information about this API resource (saved-query--info)](/developer-docs/6.1.0/api/get-metadata-information-about-this-api-resource-saved-query-info) | `/api/v1/saved_query/_info` |
| `DELETE` | [Delete a saved query](/developer-docs/6.1.0/api/delete-a-saved-query) | `/api/v1/saved_query/{pk}` |
| `GET` | [Get a saved query](/developer-docs/6.1.0/api/get-a-saved-query) | `/api/v1/saved_query/{pk}` |
| `PUT` | [Update a saved query](/developer-docs/6.1.0/api/update-a-saved-query) | `/api/v1/saved_query/{pk}` |
| `GET` | [Get distinct values from field data (saved-query-distinct-column-name)](/developer-docs/6.1.0/api/get-distinct-values-from-field-data-saved-query-distinct-column-name) | `/api/v1/saved_query/distinct/{column_name}` |
| `GET` | [Download multiple saved queries as YAML files](/developer-docs/6.1.0/api/download-multiple-saved-queries-as-yaml-files) | `/api/v1/saved_query/export/` |
| `POST` | [Import saved queries with associated databases](/developer-docs/6.1.0/api/import-saved-queries-with-associated-databases) | `/api/v1/saved_query/import/` |
| `GET` | [Get related fields data (saved-query-related-column-name)](/developer-docs/6.1.0/api/get-related-fields-data-saved-query-related-column-name) | `/api/v1/saved_query/related/{column_name}` |
| `GET` | [Get a list of queries](/developer-docs/api/get-a-list-of-queries) | `/api/v1/query/` |
| `GET` | [Get query detail information](/developer-docs/api/get-query-detail-information) | `/api/v1/query/{pk}` |
| `GET` | [Get distinct values from field data (query-distinct-column-name)](/developer-docs/api/get-distinct-values-from-field-data-query-distinct-column-name) | `/api/v1/query/distinct/{column_name}` |
| `GET` | [Get related fields data (query-related-column-name)](/developer-docs/api/get-related-fields-data-query-related-column-name) | `/api/v1/query/related/{column_name}` |
| `POST` | [Manually stop a query with client_id](/developer-docs/api/manually-stop-a-query-with-client-id) | `/api/v1/query/stop` |
| `GET` | [Get a list of queries that changed after last_updated_ms](/developer-docs/api/get-a-list-of-queries-that-changed-after-last-updated-ms) | `/api/v1/query/updated_since` |
| `DELETE` | [Bulk delete saved queries](/developer-docs/api/bulk-delete-saved-queries) | `/api/v1/saved_query/` |
| `GET` | [Get a list of saved queries](/developer-docs/api/get-a-list-of-saved-queries) | `/api/v1/saved_query/` |
| `POST` | [Create a saved query](/developer-docs/api/create-a-saved-query) | `/api/v1/saved_query/` |
| `GET` | [Get metadata information about this API resource (saved-query--info)](/developer-docs/api/get-metadata-information-about-this-api-resource-saved-query-info) | `/api/v1/saved_query/_info` |
| `DELETE` | [Delete a saved query](/developer-docs/api/delete-a-saved-query) | `/api/v1/saved_query/{pk}` |
| `GET` | [Get a saved query](/developer-docs/api/get-a-saved-query) | `/api/v1/saved_query/{pk}` |
| `PUT` | [Update a saved query](/developer-docs/api/update-a-saved-query) | `/api/v1/saved_query/{pk}` |
| `GET` | [Get distinct values from field data (saved-query-distinct-column-name)](/developer-docs/api/get-distinct-values-from-field-data-saved-query-distinct-column-name) | `/api/v1/saved_query/distinct/{column_name}` |
| `GET` | [Download multiple saved queries as YAML files](/developer-docs/api/download-multiple-saved-queries-as-yaml-files) | `/api/v1/saved_query/export/` |
| `POST` | [Import saved queries with associated databases](/developer-docs/api/import-saved-queries-with-associated-databases) | `/api/v1/saved_query/import/` |
| `GET` | [Get related fields data (saved-query-related-column-name)](/developer-docs/api/get-related-fields-data-saved-query-related-column-name) | `/api/v1/saved_query/related/{column_name}` |
</details>
@@ -245,8 +245,8 @@ curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
| Method | Endpoint | Description |
| ------ | -------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
| `GET` | [Get possible values for a datasource column](/developer-docs/6.1.0/api/get-possible-values-for-a-datasource-column) | `/api/v1/datasource/{datasource_type}/{datasource_id}/column/{column_name}/values/` |
| `POST` | [Validate a SQL expression against a datasource](/developer-docs/6.1.0/api/validate-a-sql-expression-against-a-datasource) | `/api/v1/datasource/{datasource_type}/{datasource_id}/validate_expression/` |
| `GET` | [Get possible values for a datasource column](/developer-docs/api/get-possible-values-for-a-datasource-column) | `/api/v1/datasource/{datasource_type}/{datasource_id}/column/{column_name}/values/` |
| `POST` | [Validate a SQL expression against a datasource](/developer-docs/api/validate-a-sql-expression-against-a-datasource) | `/api/v1/datasource/{datasource_type}/{datasource_id}/validate_expression/` |
</details>
@@ -255,8 +255,8 @@ curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
| Method | Endpoint | Description |
| ------ | -------------------------------------------------------------------------------------------------------------------- | ------------------------------------ |
| `GET` | [Return an AdvancedDataTypeResponse](/developer-docs/6.1.0/api/return-an-advanced-data-type-response) | `/api/v1/advanced_data_type/convert` |
| `GET` | [Return a list of available advanced data types](/developer-docs/6.1.0/api/return-a-list-of-available-advanced-data-types) | `/api/v1/advanced_data_type/types` |
| `GET` | [Return an AdvancedDataTypeResponse](/developer-docs/api/return-an-advanced-data-type-response) | `/api/v1/advanced_data_type/convert` |
| `GET` | [Return a list of available advanced data types](/developer-docs/api/return-a-list-of-available-advanced-data-types) | `/api/v1/advanced_data_type/types` |
</details>
@@ -267,21 +267,21 @@ curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
| Method | Endpoint | Description |
| -------- | ------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------- |
| `DELETE` | [Bulk delete tags](/developer-docs/6.1.0/api/bulk-delete-tags) | `/api/v1/tag/` |
| `GET` | [Get a list of tags](/developer-docs/6.1.0/api/get-a-list-of-tags) | `/api/v1/tag/` |
| `POST` | [Create a tag](/developer-docs/6.1.0/api/create-a-tag) | `/api/v1/tag/` |
| `GET` | [Get metadata information about tag API endpoints](/developer-docs/6.1.0/api/get-metadata-information-about-tag-api-endpoints) | `/api/v1/tag/_info` |
| `POST` | [Add tags to an object](/developer-docs/6.1.0/api/add-tags-to-an-object) | `/api/v1/tag/{object_type}/{object_id}/` |
| `DELETE` | [Delete a tagged object](/developer-docs/6.1.0/api/delete-a-tagged-object) | `/api/v1/tag/{object_type}/{object_id}/{tag}/` |
| `DELETE` | [Delete a tag](/developer-docs/6.1.0/api/delete-a-tag) | `/api/v1/tag/{pk}` |
| `GET` | [Get a tag detail information](/developer-docs/6.1.0/api/get-a-tag-detail-information) | `/api/v1/tag/{pk}` |
| `PUT` | [Update a tag](/developer-docs/6.1.0/api/update-a-tag) | `/api/v1/tag/{pk}` |
| `DELETE` | [Delete tag by pk favorites](/developer-docs/6.1.0/api/delete-tag-by-pk-favorites) | `/api/v1/tag/{pk}/favorites/` |
| `POST` | [Create tag by pk favorites](/developer-docs/6.1.0/api/create-tag-by-pk-favorites) | `/api/v1/tag/{pk}/favorites/` |
| `POST` | [Bulk create tags and tagged objects](/developer-docs/6.1.0/api/bulk-create-tags-and-tagged-objects) | `/api/v1/tag/bulk_create` |
| `GET` | [Get tag favorite status](/developer-docs/6.1.0/api/get-tag-favorite-status) | `/api/v1/tag/favorite_status/` |
| `GET` | [Get all objects associated with a tag](/developer-docs/6.1.0/api/get-all-objects-associated-with-a-tag) | `/api/v1/tag/get_objects/` |
| `GET` | [Get related fields data (tag-related-column-name)](/developer-docs/6.1.0/api/get-related-fields-data-tag-related-column-name) | `/api/v1/tag/related/{column_name}` |
| `DELETE` | [Bulk delete tags](/developer-docs/api/bulk-delete-tags) | `/api/v1/tag/` |
| `GET` | [Get a list of tags](/developer-docs/api/get-a-list-of-tags) | `/api/v1/tag/` |
| `POST` | [Create a tag](/developer-docs/api/create-a-tag) | `/api/v1/tag/` |
| `GET` | [Get metadata information about tag API endpoints](/developer-docs/api/get-metadata-information-about-tag-api-endpoints) | `/api/v1/tag/_info` |
| `POST` | [Add tags to an object](/developer-docs/api/add-tags-to-an-object) | `/api/v1/tag/{object_type}/{object_id}/` |
| `DELETE` | [Delete a tagged object](/developer-docs/api/delete-a-tagged-object) | `/api/v1/tag/{object_type}/{object_id}/{tag}/` |
| `DELETE` | [Delete a tag](/developer-docs/api/delete-a-tag) | `/api/v1/tag/{pk}` |
| `GET` | [Get a tag detail information](/developer-docs/api/get-a-tag-detail-information) | `/api/v1/tag/{pk}` |
| `PUT` | [Update a tag](/developer-docs/api/update-a-tag) | `/api/v1/tag/{pk}` |
| `DELETE` | [Delete tag by pk favorites](/developer-docs/api/delete-tag-by-pk-favorites) | `/api/v1/tag/{pk}/favorites/` |
| `POST` | [Create tag by pk favorites](/developer-docs/api/create-tag-by-pk-favorites) | `/api/v1/tag/{pk}/favorites/` |
| `POST` | [Bulk create tags and tagged objects](/developer-docs/api/bulk-create-tags-and-tagged-objects) | `/api/v1/tag/bulk_create` |
| `GET` | [Get tag favorite status](/developer-docs/api/get-tag-favorite-status) | `/api/v1/tag/favorite_status/` |
| `GET` | [Get all objects associated with a tag](/developer-docs/api/get-all-objects-associated-with-a-tag) | `/api/v1/tag/get_objects/` |
| `GET` | [Get related fields data (tag-related-column-name)](/developer-docs/api/get-related-fields-data-tag-related-column-name) | `/api/v1/tag/related/{column_name}` |
</details>
@@ -290,20 +290,20 @@ curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
| Method | Endpoint | Description |
| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------- |
| `DELETE` | [Delete multiple annotation layers in a bulk operation](/developer-docs/6.1.0/api/delete-multiple-annotation-layers-in-a-bulk-operation) | `/api/v1/annotation_layer/` |
| `GET` | [Get a list of annotation layers (annotation-layer)](/developer-docs/6.1.0/api/get-a-list-of-annotation-layers-annotation-layer) | `/api/v1/annotation_layer/` |
| `POST` | [Create an annotation layer (annotation-layer)](/developer-docs/6.1.0/api/create-an-annotation-layer-annotation-layer) | `/api/v1/annotation_layer/` |
| `GET` | [Get metadata information about this API resource (annotation-layer--info)](/developer-docs/6.1.0/api/get-metadata-information-about-this-api-resource-annotation-layer-info) | `/api/v1/annotation_layer/_info` |
| `DELETE` | [Delete annotation layer (annotation-layer-pk)](/developer-docs/6.1.0/api/delete-annotation-layer-annotation-layer-pk) | `/api/v1/annotation_layer/{pk}` |
| `GET` | [Get an annotation layer (annotation-layer-pk)](/developer-docs/6.1.0/api/get-an-annotation-layer-annotation-layer-pk) | `/api/v1/annotation_layer/{pk}` |
| `PUT` | [Update an annotation layer (annotation-layer-pk)](/developer-docs/6.1.0/api/update-an-annotation-layer-annotation-layer-pk) | `/api/v1/annotation_layer/{pk}` |
| `DELETE` | [Bulk delete annotation layers](/developer-docs/6.1.0/api/bulk-delete-annotation-layers) | `/api/v1/annotation_layer/{pk}/annotation/` |
| `GET` | [Get a list of annotation layers (annotation-layer-pk-annotation)](/developer-docs/6.1.0/api/get-a-list-of-annotation-layers-annotation-layer-pk-annotation) | `/api/v1/annotation_layer/{pk}/annotation/` |
| `POST` | [Create an annotation layer (annotation-layer-pk-annotation)](/developer-docs/6.1.0/api/create-an-annotation-layer-annotation-layer-pk-annotation) | `/api/v1/annotation_layer/{pk}/annotation/` |
| `DELETE` | [Delete annotation layer (annotation-layer-pk-annotation-annotation-id)](/developer-docs/6.1.0/api/delete-annotation-layer-annotation-layer-pk-annotation-annotation-id) | `/api/v1/annotation_layer/{pk}/annotation/{annotation_id}` |
| `GET` | [Get an annotation layer (annotation-layer-pk-annotation-annotation-id)](/developer-docs/6.1.0/api/get-an-annotation-layer-annotation-layer-pk-annotation-annotation-id) | `/api/v1/annotation_layer/{pk}/annotation/{annotation_id}` |
| `PUT` | [Update an annotation layer (annotation-layer-pk-annotation-annotation-id)](/developer-docs/6.1.0/api/update-an-annotation-layer-annotation-layer-pk-annotation-annotation-id) | `/api/v1/annotation_layer/{pk}/annotation/{annotation_id}` |
| `GET` | [Get related fields data (annotation-layer-related-column-name)](/developer-docs/6.1.0/api/get-related-fields-data-annotation-layer-related-column-name) | `/api/v1/annotation_layer/related/{column_name}` |
| `DELETE` | [Delete multiple annotation layers in a bulk operation](/developer-docs/api/delete-multiple-annotation-layers-in-a-bulk-operation) | `/api/v1/annotation_layer/` |
| `GET` | [Get a list of annotation layers (annotation-layer)](/developer-docs/api/get-a-list-of-annotation-layers-annotation-layer) | `/api/v1/annotation_layer/` |
| `POST` | [Create an annotation layer (annotation-layer)](/developer-docs/api/create-an-annotation-layer-annotation-layer) | `/api/v1/annotation_layer/` |
| `GET` | [Get metadata information about this API resource (annotation-layer--info)](/developer-docs/api/get-metadata-information-about-this-api-resource-annotation-layer-info) | `/api/v1/annotation_layer/_info` |
| `DELETE` | [Delete annotation layer (annotation-layer-pk)](/developer-docs/api/delete-annotation-layer-annotation-layer-pk) | `/api/v1/annotation_layer/{pk}` |
| `GET` | [Get an annotation layer (annotation-layer-pk)](/developer-docs/api/get-an-annotation-layer-annotation-layer-pk) | `/api/v1/annotation_layer/{pk}` |
| `PUT` | [Update an annotation layer (annotation-layer-pk)](/developer-docs/api/update-an-annotation-layer-annotation-layer-pk) | `/api/v1/annotation_layer/{pk}` |
| `DELETE` | [Bulk delete annotation layers](/developer-docs/api/bulk-delete-annotation-layers) | `/api/v1/annotation_layer/{pk}/annotation/` |
| `GET` | [Get a list of annotation layers (annotation-layer-pk-annotation)](/developer-docs/api/get-a-list-of-annotation-layers-annotation-layer-pk-annotation) | `/api/v1/annotation_layer/{pk}/annotation/` |
| `POST` | [Create an annotation layer (annotation-layer-pk-annotation)](/developer-docs/api/create-an-annotation-layer-annotation-layer-pk-annotation) | `/api/v1/annotation_layer/{pk}/annotation/` |
| `DELETE` | [Delete annotation layer (annotation-layer-pk-annotation-annotation-id)](/developer-docs/api/delete-annotation-layer-annotation-layer-pk-annotation-annotation-id) | `/api/v1/annotation_layer/{pk}/annotation/{annotation_id}` |
| `GET` | [Get an annotation layer (annotation-layer-pk-annotation-annotation-id)](/developer-docs/api/get-an-annotation-layer-annotation-layer-pk-annotation-annotation-id) | `/api/v1/annotation_layer/{pk}/annotation/{annotation_id}` |
| `PUT` | [Update an annotation layer (annotation-layer-pk-annotation-annotation-id)](/developer-docs/api/update-an-annotation-layer-annotation-layer-pk-annotation-annotation-id) | `/api/v1/annotation_layer/{pk}/annotation/{annotation_id}` |
| `GET` | [Get related fields data (annotation-layer-related-column-name)](/developer-docs/api/get-related-fields-data-annotation-layer-related-column-name) | `/api/v1/annotation_layer/related/{column_name}` |
</details>
@@ -312,14 +312,14 @@ curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
| Method | Endpoint | Description |
| -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------- |
| `DELETE` | [Bulk delete CSS templates](/developer-docs/6.1.0/api/bulk-delete-css-templates) | `/api/v1/css_template/` |
| `GET` | [Get a list of CSS templates](/developer-docs/6.1.0/api/get-a-list-of-css-templates) | `/api/v1/css_template/` |
| `POST` | [Create a CSS template](/developer-docs/6.1.0/api/create-a-css-template) | `/api/v1/css_template/` |
| `GET` | [Get metadata information about this API resource (css-template--info)](/developer-docs/6.1.0/api/get-metadata-information-about-this-api-resource-css-template-info) | `/api/v1/css_template/_info` |
| `DELETE` | [Delete a CSS template](/developer-docs/6.1.0/api/delete-a-css-template) | `/api/v1/css_template/{pk}` |
| `GET` | [Get a CSS template](/developer-docs/6.1.0/api/get-a-css-template) | `/api/v1/css_template/{pk}` |
| `PUT` | [Update a CSS template](/developer-docs/6.1.0/api/update-a-css-template) | `/api/v1/css_template/{pk}` |
| `GET` | [Get related fields data (css-template-related-column-name)](/developer-docs/6.1.0/api/get-related-fields-data-css-template-related-column-name) | `/api/v1/css_template/related/{column_name}` |
| `DELETE` | [Bulk delete CSS templates](/developer-docs/api/bulk-delete-css-templates) | `/api/v1/css_template/` |
| `GET` | [Get a list of CSS templates](/developer-docs/api/get-a-list-of-css-templates) | `/api/v1/css_template/` |
| `POST` | [Create a CSS template](/developer-docs/api/create-a-css-template) | `/api/v1/css_template/` |
| `GET` | [Get metadata information about this API resource (css-template--info)](/developer-docs/api/get-metadata-information-about-this-api-resource-css-template-info) | `/api/v1/css_template/_info` |
| `DELETE` | [Delete a CSS template](/developer-docs/api/delete-a-css-template) | `/api/v1/css_template/{pk}` |
| `GET` | [Get a CSS template](/developer-docs/api/get-a-css-template) | `/api/v1/css_template/{pk}` |
| `PUT` | [Update a CSS template](/developer-docs/api/update-a-css-template) | `/api/v1/css_template/{pk}` |
| `GET` | [Get related fields data (css-template-related-column-name)](/developer-docs/api/get-related-fields-data-css-template-related-column-name) | `/api/v1/css_template/related/{column_name}` |
</details>
@@ -330,8 +330,8 @@ curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
| Method | Endpoint | Description |
| ------ | ----------------------------------------------------------------------------------------------------- | ----------------------------------- |
| `POST` | [Create a new dashboard's permanent link](/developer-docs/6.1.0/api/create-a-new-dashboards-permanent-link) | `/api/v1/dashboard/{pk}/permalink` |
| `GET` | [Get dashboard's permanent link state](/developer-docs/6.1.0/api/get-dashboards-permanent-link-state) | `/api/v1/dashboard/permalink/{key}` |
| `POST` | [Create a new dashboard's permanent link](/developer-docs/api/create-a-new-dashboards-permanent-link) | `/api/v1/dashboard/{pk}/permalink` |
| `GET` | [Get dashboard's permanent link state](/developer-docs/api/get-dashboards-permanent-link-state) | `/api/v1/dashboard/permalink/{key}` |
</details>
@@ -340,8 +340,8 @@ curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
| Method | Endpoint | Description |
| ------ | -------------------------------------------------------------------------------------------------------------------- | --------------------------------- |
| `POST` | [Create a new permanent link (explore-permalink)](/developer-docs/6.1.0/api/create-a-new-permanent-link-explore-permalink) | `/api/v1/explore/permalink` |
| `GET` | [Get chart's permanent link state](/developer-docs/6.1.0/api/get-charts-permanent-link-state) | `/api/v1/explore/permalink/{key}` |
| `POST` | [Create a new permanent link (explore-permalink)](/developer-docs/api/create-a-new-permanent-link-explore-permalink) | `/api/v1/explore/permalink` |
| `GET` | [Get chart's permanent link state](/developer-docs/api/get-charts-permanent-link-state) | `/api/v1/explore/permalink/{key}` |
</details>
@@ -350,8 +350,8 @@ curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
| Method | Endpoint | Description |
| ------ | ------------------------------------------------------------------------------------------------------------------ | -------------------------------- |
| `POST` | [Create a new permanent link (sqllab-permalink)](/developer-docs/6.1.0/api/create-a-new-permanent-link-sqllab-permalink) | `/api/v1/sqllab/permalink` |
| `GET` | [Get permanent link state for SQLLab editor.](/developer-docs/6.1.0/api/get-permanent-link-state-for-sql-lab-editor) | `/api/v1/sqllab/permalink/{key}` |
| `POST` | [Create a new permanent link (sqllab-permalink)](/developer-docs/api/create-a-new-permanent-link-sqllab-permalink) | `/api/v1/sqllab/permalink` |
| `GET` | [Get permanent link state for SQLLab editor.](/developer-docs/api/get-permanent-link-state-for-sql-lab-editor) | `/api/v1/sqllab/permalink/{key}` |
</details>
@@ -360,7 +360,7 @@ curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
| Method | Endpoint | Description |
| ------ | ---------------------------------------------------------------------------------------------------------------------------- | ----------------------------------- |
| `GET` | [Get a report schedule log (embedded-dashboard-uuid)](/developer-docs/6.1.0/api/get-a-report-schedule-log-embedded-dashboard-uuid) | `/api/v1/embedded_dashboard/{uuid}` |
| `GET` | [Get a report schedule log (embedded-dashboard-uuid)](/developer-docs/api/get-a-report-schedule-log-embedded-dashboard-uuid) | `/api/v1/embedded_dashboard/{uuid}` |
</details>
@@ -369,10 +369,10 @@ curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
| Method | Endpoint | Description |
| -------- | ----------------------------------------------------------------------------------------------------- | ------------------------------------------- |
| `POST` | [Create a dashboard's filter state](/developer-docs/6.1.0/api/create-a-dashboards-filter-state) | `/api/v1/dashboard/{pk}/filter_state` |
| `DELETE` | [Delete a dashboard's filter state value](/developer-docs/6.1.0/api/delete-a-dashboards-filter-state-value) | `/api/v1/dashboard/{pk}/filter_state/{key}` |
| `GET` | [Get a dashboard's filter state value](/developer-docs/6.1.0/api/get-a-dashboards-filter-state-value) | `/api/v1/dashboard/{pk}/filter_state/{key}` |
| `PUT` | [Update a dashboard's filter state value](/developer-docs/6.1.0/api/update-a-dashboards-filter-state-value) | `/api/v1/dashboard/{pk}/filter_state/{key}` |
| `POST` | [Create a dashboard's filter state](/developer-docs/api/create-a-dashboards-filter-state) | `/api/v1/dashboard/{pk}/filter_state` |
| `DELETE` | [Delete a dashboard's filter state value](/developer-docs/api/delete-a-dashboards-filter-state-value) | `/api/v1/dashboard/{pk}/filter_state/{key}` |
| `GET` | [Get a dashboard's filter state value](/developer-docs/api/get-a-dashboards-filter-state-value) | `/api/v1/dashboard/{pk}/filter_state/{key}` |
| `PUT` | [Update a dashboard's filter state value](/developer-docs/api/update-a-dashboards-filter-state-value) | `/api/v1/dashboard/{pk}/filter_state/{key}` |
</details>
@@ -381,10 +381,10 @@ curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
| Method | Endpoint | Description |
| -------- | -------------------------------------------------------------------------------- | --------------------------------- |
| `POST` | [Create a new form_data](/developer-docs/6.1.0/api/create-a-new-form-data) | `/api/v1/explore/form_data` |
| `DELETE` | [Delete a form_data](/developer-docs/6.1.0/api/delete-a-form-data) | `/api/v1/explore/form_data/{key}` |
| `GET` | [Get a form_data](/developer-docs/6.1.0/api/get-a-form-data) | `/api/v1/explore/form_data/{key}` |
| `PUT` | [Update an existing form_data](/developer-docs/6.1.0/api/update-an-existing-form-data) | `/api/v1/explore/form_data/{key}` |
| `POST` | [Create a new form_data](/developer-docs/api/create-a-new-form-data) | `/api/v1/explore/form_data` |
| `DELETE` | [Delete a form_data](/developer-docs/api/delete-a-form-data) | `/api/v1/explore/form_data/{key}` |
| `GET` | [Get a form_data](/developer-docs/api/get-a-form-data) | `/api/v1/explore/form_data/{key}` |
| `PUT` | [Update an existing form_data](/developer-docs/api/update-an-existing-form-data) | `/api/v1/explore/form_data/{key}` |
</details>
@@ -395,17 +395,17 @@ curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
| Method | Endpoint | Description |
| -------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------- |
| `DELETE` | [Bulk delete report schedules](/developer-docs/6.1.0/api/bulk-delete-report-schedules) | `/api/v1/report/` |
| `GET` | [Get a list of report schedules](/developer-docs/6.1.0/api/get-a-list-of-report-schedules) | `/api/v1/report/` |
| `POST` | [Create a report schedule](/developer-docs/6.1.0/api/create-a-report-schedule) | `/api/v1/report/` |
| `GET` | [Get metadata information about this API resource (report--info)](/developer-docs/6.1.0/api/get-metadata-information-about-this-api-resource-report-info) | `/api/v1/report/_info` |
| `DELETE` | [Delete a report schedule](/developer-docs/6.1.0/api/delete-a-report-schedule) | `/api/v1/report/{pk}` |
| `GET` | [Get a report schedule](/developer-docs/6.1.0/api/get-a-report-schedule) | `/api/v1/report/{pk}` |
| `PUT` | [Update a report schedule](/developer-docs/6.1.0/api/update-a-report-schedule) | `/api/v1/report/{pk}` |
| `GET` | [Get a list of report schedule logs](/developer-docs/6.1.0/api/get-a-list-of-report-schedule-logs) | `/api/v1/report/{pk}/log/` |
| `GET` | [Get a report schedule log (report-pk-log-log-id)](/developer-docs/6.1.0/api/get-a-report-schedule-log-report-pk-log-log-id) | `/api/v1/report/{pk}/log/{log_id}` |
| `GET` | [Get related fields data (report-related-column-name)](/developer-docs/6.1.0/api/get-related-fields-data-report-related-column-name) | `/api/v1/report/related/{column_name}` |
| `GET` | [Get slack channels](/developer-docs/6.1.0/api/get-slack-channels) | `/api/v1/report/slack_channels/` |
| `DELETE` | [Bulk delete report schedules](/developer-docs/api/bulk-delete-report-schedules) | `/api/v1/report/` |
| `GET` | [Get a list of report schedules](/developer-docs/api/get-a-list-of-report-schedules) | `/api/v1/report/` |
| `POST` | [Create a report schedule](/developer-docs/api/create-a-report-schedule) | `/api/v1/report/` |
| `GET` | [Get metadata information about this API resource (report--info)](/developer-docs/api/get-metadata-information-about-this-api-resource-report-info) | `/api/v1/report/_info` |
| `DELETE` | [Delete a report schedule](/developer-docs/api/delete-a-report-schedule) | `/api/v1/report/{pk}` |
| `GET` | [Get a report schedule](/developer-docs/api/get-a-report-schedule) | `/api/v1/report/{pk}` |
| `PUT` | [Update a report schedule](/developer-docs/api/update-a-report-schedule) | `/api/v1/report/{pk}` |
| `GET` | [Get a list of report schedule logs](/developer-docs/api/get-a-list-of-report-schedule-logs) | `/api/v1/report/{pk}/log/` |
| `GET` | [Get a report schedule log (report-pk-log-log-id)](/developer-docs/api/get-a-report-schedule-log-report-pk-log-log-id) | `/api/v1/report/{pk}/log/{log_id}` |
| `GET` | [Get related fields data (report-related-column-name)](/developer-docs/api/get-related-fields-data-report-related-column-name) | `/api/v1/report/related/{column_name}` |
| `GET` | [Get slack channels](/developer-docs/api/get-slack-channels) | `/api/v1/report/slack_channels/` |
</details>
@@ -416,17 +416,17 @@ curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
| Method | Endpoint | Description |
| -------- | ---------------------------------------------------------------------------------------------------------------- | ----------------------------------------------- |
| `GET` | [Get security roles](/developer-docs/6.1.0/api/get-security-roles) | `/api/v1/security/roles/` |
| `POST` | [Create security roles](/developer-docs/6.1.0/api/create-security-roles) | `/api/v1/security/roles/` |
| `GET` | [Get security roles info](/developer-docs/6.1.0/api/get-security-roles-info) | `/api/v1/security/roles/_info` |
| `DELETE` | [Delete security roles by pk](/developer-docs/6.1.0/api/delete-security-roles-by-pk) | `/api/v1/security/roles/{pk}` |
| `GET` | [Get security roles by pk](/developer-docs/6.1.0/api/get-security-roles-by-pk) | `/api/v1/security/roles/{pk}` |
| `PUT` | [Update security roles by pk](/developer-docs/6.1.0/api/update-security-roles-by-pk) | `/api/v1/security/roles/{pk}` |
| `PUT` | [Update security roles by role_id groups](/developer-docs/6.1.0/api/update-security-roles-by-role-id-groups) | `/api/v1/security/roles/{role_id}/groups` |
| `POST` | [Create security roles by role_id permissions](/developer-docs/6.1.0/api/create-security-roles-by-role-id-permissions) | `/api/v1/security/roles/{role_id}/permissions` |
| `GET` | [Get security roles by role_id permissions](/developer-docs/6.1.0/api/get-security-roles-by-role-id-permissions) | `/api/v1/security/roles/{role_id}/permissions/` |
| `PUT` | [Update security roles by role_id users](/developer-docs/6.1.0/api/update-security-roles-by-role-id-users) | `/api/v1/security/roles/{role_id}/users` |
| `GET` | [List roles](/developer-docs/6.1.0/api/list-roles) | `/api/v1/security/roles/search/` |
| `GET` | [Get security roles](/developer-docs/api/get-security-roles) | `/api/v1/security/roles/` |
| `POST` | [Create security roles](/developer-docs/api/create-security-roles) | `/api/v1/security/roles/` |
| `GET` | [Get security roles info](/developer-docs/api/get-security-roles-info) | `/api/v1/security/roles/_info` |
| `DELETE` | [Delete security roles by pk](/developer-docs/api/delete-security-roles-by-pk) | `/api/v1/security/roles/{pk}` |
| `GET` | [Get security roles by pk](/developer-docs/api/get-security-roles-by-pk) | `/api/v1/security/roles/{pk}` |
| `PUT` | [Update security roles by pk](/developer-docs/api/update-security-roles-by-pk) | `/api/v1/security/roles/{pk}` |
| `PUT` | [Update security roles by role_id groups](/developer-docs/api/update-security-roles-by-role-id-groups) | `/api/v1/security/roles/{role_id}/groups` |
| `POST` | [Create security roles by role_id permissions](/developer-docs/api/create-security-roles-by-role-id-permissions) | `/api/v1/security/roles/{role_id}/permissions` |
| `GET` | [Get security roles by role_id permissions](/developer-docs/api/get-security-roles-by-role-id-permissions) | `/api/v1/security/roles/{role_id}/permissions/` |
| `PUT` | [Update security roles by role_id users](/developer-docs/api/update-security-roles-by-role-id-users) | `/api/v1/security/roles/{role_id}/users` |
| `GET` | [List roles](/developer-docs/api/list-roles) | `/api/v1/security/roles/search/` |
</details>
@@ -435,12 +435,12 @@ curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
| Method | Endpoint | Description |
| -------- | ------------------------------------------------------------------------------ | ------------------------------ |
| `GET` | [Get security users](/developer-docs/6.1.0/api/get-security-users) | `/api/v1/security/users/` |
| `POST` | [Create security users](/developer-docs/6.1.0/api/create-security-users) | `/api/v1/security/users/` |
| `GET` | [Get security users info](/developer-docs/6.1.0/api/get-security-users-info) | `/api/v1/security/users/_info` |
| `DELETE` | [Delete security users by pk](/developer-docs/6.1.0/api/delete-security-users-by-pk) | `/api/v1/security/users/{pk}` |
| `GET` | [Get security users by pk](/developer-docs/6.1.0/api/get-security-users-by-pk) | `/api/v1/security/users/{pk}` |
| `PUT` | [Update security users by pk](/developer-docs/6.1.0/api/update-security-users-by-pk) | `/api/v1/security/users/{pk}` |
| `GET` | [Get security users](/developer-docs/api/get-security-users) | `/api/v1/security/users/` |
| `POST` | [Create security users](/developer-docs/api/create-security-users) | `/api/v1/security/users/` |
| `GET` | [Get security users info](/developer-docs/api/get-security-users-info) | `/api/v1/security/users/_info` |
| `DELETE` | [Delete security users by pk](/developer-docs/api/delete-security-users-by-pk) | `/api/v1/security/users/{pk}` |
| `GET` | [Get security users by pk](/developer-docs/api/get-security-users-by-pk) | `/api/v1/security/users/{pk}` |
| `PUT` | [Update security users by pk](/developer-docs/api/update-security-users-by-pk) | `/api/v1/security/users/{pk}` |
</details>
@@ -449,9 +449,9 @@ curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
| Method | Endpoint | Description |
| ------ | ------------------------------------------------------------------------------------ | ------------------------------------ |
| `GET` | [Get security permissions](/developer-docs/6.1.0/api/get-security-permissions) | `/api/v1/security/permissions/` |
| `GET` | [Get security permissions info](/developer-docs/6.1.0/api/get-security-permissions-info) | `/api/v1/security/permissions/_info` |
| `GET` | [Get security permissions by pk](/developer-docs/6.1.0/api/get-security-permissions-by-pk) | `/api/v1/security/permissions/{pk}` |
| `GET` | [Get security permissions](/developer-docs/api/get-security-permissions) | `/api/v1/security/permissions/` |
| `GET` | [Get security permissions info](/developer-docs/api/get-security-permissions-info) | `/api/v1/security/permissions/_info` |
| `GET` | [Get security permissions by pk](/developer-docs/api/get-security-permissions-by-pk) | `/api/v1/security/permissions/{pk}` |
</details>
@@ -460,12 +460,12 @@ curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
| Method | Endpoint | Description |
| -------- | -------------------------------------------------------------------------------------- | ---------------------------------- |
| `GET` | [Get security resources](/developer-docs/6.1.0/api/get-security-resources) | `/api/v1/security/resources/` |
| `POST` | [Create security resources](/developer-docs/6.1.0/api/create-security-resources) | `/api/v1/security/resources/` |
| `GET` | [Get security resources info](/developer-docs/6.1.0/api/get-security-resources-info) | `/api/v1/security/resources/_info` |
| `DELETE` | [Delete security resources by pk](/developer-docs/6.1.0/api/delete-security-resources-by-pk) | `/api/v1/security/resources/{pk}` |
| `GET` | [Get security resources by pk](/developer-docs/6.1.0/api/get-security-resources-by-pk) | `/api/v1/security/resources/{pk}` |
| `PUT` | [Update security resources by pk](/developer-docs/6.1.0/api/update-security-resources-by-pk) | `/api/v1/security/resources/{pk}` |
| `GET` | [Get security resources](/developer-docs/api/get-security-resources) | `/api/v1/security/resources/` |
| `POST` | [Create security resources](/developer-docs/api/create-security-resources) | `/api/v1/security/resources/` |
| `GET` | [Get security resources info](/developer-docs/api/get-security-resources-info) | `/api/v1/security/resources/_info` |
| `DELETE` | [Delete security resources by pk](/developer-docs/api/delete-security-resources-by-pk) | `/api/v1/security/resources/{pk}` |
| `GET` | [Get security resources by pk](/developer-docs/api/get-security-resources-by-pk) | `/api/v1/security/resources/{pk}` |
| `PUT` | [Update security resources by pk](/developer-docs/api/update-security-resources-by-pk) | `/api/v1/security/resources/{pk}` |
</details>
@@ -474,12 +474,12 @@ curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
| Method | Endpoint | Description |
| -------- | -------------------------------------------------------------------------------------------------------------- | ---------------------------------------------- |
| `GET` | [Get security permissions resources](/developer-docs/6.1.0/api/get-security-permissions-resources) | `/api/v1/security/permissions-resources/` |
| `POST` | [Create security permissions resources](/developer-docs/6.1.0/api/create-security-permissions-resources) | `/api/v1/security/permissions-resources/` |
| `GET` | [Get security permissions resources info](/developer-docs/6.1.0/api/get-security-permissions-resources-info) | `/api/v1/security/permissions-resources/_info` |
| `DELETE` | [Delete security permissions resources by pk](/developer-docs/6.1.0/api/delete-security-permissions-resources-by-pk) | `/api/v1/security/permissions-resources/{pk}` |
| `GET` | [Get security permissions resources by pk](/developer-docs/6.1.0/api/get-security-permissions-resources-by-pk) | `/api/v1/security/permissions-resources/{pk}` |
| `PUT` | [Update security permissions resources by pk](/developer-docs/6.1.0/api/update-security-permissions-resources-by-pk) | `/api/v1/security/permissions-resources/{pk}` |
| `GET` | [Get security permissions resources](/developer-docs/api/get-security-permissions-resources) | `/api/v1/security/permissions-resources/` |
| `POST` | [Create security permissions resources](/developer-docs/api/create-security-permissions-resources) | `/api/v1/security/permissions-resources/` |
| `GET` | [Get security permissions resources info](/developer-docs/api/get-security-permissions-resources-info) | `/api/v1/security/permissions-resources/_info` |
| `DELETE` | [Delete security permissions resources by pk](/developer-docs/api/delete-security-permissions-resources-by-pk) | `/api/v1/security/permissions-resources/{pk}` |
| `GET` | [Get security permissions resources by pk](/developer-docs/api/get-security-permissions-resources-by-pk) | `/api/v1/security/permissions-resources/{pk}` |
| `PUT` | [Update security permissions resources by pk](/developer-docs/api/update-security-permissions-resources-by-pk) | `/api/v1/security/permissions-resources/{pk}` |
</details>
@@ -488,14 +488,14 @@ curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
| Method | Endpoint | Description |
| -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------ |
| `DELETE` | [Bulk delete RLS rules](/developer-docs/6.1.0/api/bulk-delete-rls-rules) | `/api/v1/rowlevelsecurity/` |
| `GET` | [Get a list of RLS](/developer-docs/6.1.0/api/get-a-list-of-rls) | `/api/v1/rowlevelsecurity/` |
| `POST` | [Create a new RLS rule](/developer-docs/6.1.0/api/create-a-new-rls-rule) | `/api/v1/rowlevelsecurity/` |
| `GET` | [Get metadata information about this API resource (rowlevelsecurity--info)](/developer-docs/6.1.0/api/get-metadata-information-about-this-api-resource-rowlevelsecurity-info) | `/api/v1/rowlevelsecurity/_info` |
| `DELETE` | [Delete an RLS](/developer-docs/6.1.0/api/delete-an-rls) | `/api/v1/rowlevelsecurity/{pk}` |
| `GET` | [Get an RLS](/developer-docs/6.1.0/api/get-an-rls) | `/api/v1/rowlevelsecurity/{pk}` |
| `PUT` | [Update an RLS rule](/developer-docs/6.1.0/api/update-an-rls-rule) | `/api/v1/rowlevelsecurity/{pk}` |
| `GET` | [Get related fields data (rowlevelsecurity-related-column-name)](/developer-docs/6.1.0/api/get-related-fields-data-rowlevelsecurity-related-column-name) | `/api/v1/rowlevelsecurity/related/{column_name}` |
| `DELETE` | [Bulk delete RLS rules](/developer-docs/api/bulk-delete-rls-rules) | `/api/v1/rowlevelsecurity/` |
| `GET` | [Get a list of RLS](/developer-docs/api/get-a-list-of-rls) | `/api/v1/rowlevelsecurity/` |
| `POST` | [Create a new RLS rule](/developer-docs/api/create-a-new-rls-rule) | `/api/v1/rowlevelsecurity/` |
| `GET` | [Get metadata information about this API resource (rowlevelsecurity--info)](/developer-docs/api/get-metadata-information-about-this-api-resource-rowlevelsecurity-info) | `/api/v1/rowlevelsecurity/_info` |
| `DELETE` | [Delete an RLS](/developer-docs/api/delete-an-rls) | `/api/v1/rowlevelsecurity/{pk}` |
| `GET` | [Get an RLS](/developer-docs/api/get-an-rls) | `/api/v1/rowlevelsecurity/{pk}` |
| `PUT` | [Update an RLS rule](/developer-docs/api/update-an-rls-rule) | `/api/v1/rowlevelsecurity/{pk}` |
| `GET` | [Get related fields data (rowlevelsecurity-related-column-name)](/developer-docs/api/get-related-fields-data-rowlevelsecurity-related-column-name) | `/api/v1/rowlevelsecurity/related/{column_name}` |
</details>
@@ -506,8 +506,8 @@ curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
| Method | Endpoint | Description |
| ------ | -------------------------------------------------------------------- | ------------------------ |
| `GET` | [Export all assets](/developer-docs/6.1.0/api/export-all-assets) | `/api/v1/assets/export/` |
| `POST` | [Import multiple assets](/developer-docs/6.1.0/api/import-multiple-assets) | `/api/v1/assets/import/` |
| `GET` | [Export all assets](/developer-docs/api/export-all-assets) | `/api/v1/assets/export/` |
| `POST` | [Import multiple assets](/developer-docs/api/import-multiple-assets) | `/api/v1/assets/import/` |
</details>
@@ -516,7 +516,7 @@ curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
| Method | Endpoint | Description |
| ------ | ---------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------- |
| `POST` | [Invalidate cache records and remove the database records](/developer-docs/6.1.0/api/invalidate-cache-records-and-remove-the-database-records) | `/api/v1/cachekey/invalidate` |
| `POST` | [Invalidate cache records and remove the database records](/developer-docs/api/invalidate-cache-records-and-remove-the-database-records) | `/api/v1/cachekey/invalidate` |
</details>
@@ -525,10 +525,10 @@ curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
| Method | Endpoint | Description |
| ------ | ---------------------------------------------------------------------------------------------- | ------------------------------ |
| `GET` | [Get a list of logs](/developer-docs/6.1.0/api/get-a-list-of-logs) | `/api/v1/log/` |
| `POST` | [Create log](/developer-docs/6.1.0/api/create-log) | `/api/v1/log/` |
| `GET` | [Get a log detail information](/developer-docs/6.1.0/api/get-a-log-detail-information) | `/api/v1/log/{pk}` |
| `GET` | [Get recent activity data for a user](/developer-docs/6.1.0/api/get-recent-activity-data-for-a-user) | `/api/v1/log/recent_activity/` |
| `GET` | [Get a list of logs](/developer-docs/api/get-a-list-of-logs) | `/api/v1/log/` |
| `POST` | [Create log](/developer-docs/api/create-log) | `/api/v1/log/` |
| `GET` | [Get a log detail information](/developer-docs/api/get-a-log-detail-information) | `/api/v1/log/{pk}` |
| `GET` | [Get recent activity data for a user](/developer-docs/api/get-recent-activity-data-for-a-user) | `/api/v1/log/recent_activity/` |
</details>
@@ -539,9 +539,9 @@ curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
| Method | Endpoint | Description |
| ------ | ---------------------------------------------------------------------- | ------------------- |
| `GET` | [Get the user object](/developer-docs/6.1.0/api/get-the-user-object) | `/api/v1/me/` |
| `PUT` | [Update the current user](/developer-docs/6.1.0/api/update-the-current-user) | `/api/v1/me/` |
| `GET` | [Get the user roles](/developer-docs/6.1.0/api/get-the-user-roles) | `/api/v1/me/roles/` |
| `GET` | [Get the user object](/developer-docs/api/get-the-user-object) | `/api/v1/me/` |
| `PUT` | [Update the current user](/developer-docs/api/update-the-current-user) | `/api/v1/me/` |
| `GET` | [Get the user roles](/developer-docs/api/get-the-user-roles) | `/api/v1/me/roles/` |
</details>
@@ -550,7 +550,7 @@ curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
| Method | Endpoint | Description |
| ------ | -------------------------------------------------------------- | ----------------------------------- |
| `GET` | [Get the user avatar](/developer-docs/6.1.0/api/get-the-user-avatar) | `/api/v1/user/{user_id}/avatar.png` |
| `GET` | [Get the user avatar](/developer-docs/api/get-the-user-avatar) | `/api/v1/user/{user_id}/avatar.png` |
</details>
@@ -559,7 +559,7 @@ curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
| Method | Endpoint | Description |
| ------ | ---------------------------------------- | --------------- |
| `GET` | [Get menu](/developer-docs/6.1.0/api/get-menu) | `/api/v1/menu/` |
| `GET` | [Get menu](/developer-docs/api/get-menu) | `/api/v1/menu/` |
</details>
@@ -568,7 +568,7 @@ curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
| Method | Endpoint | Description |
| ------ | -------------------------------------------------------------------------- | ---------------------------- |
| `GET` | [Get all available domains](/developer-docs/6.1.0/api/get-all-available-domains) | `/api/v1/available_domains/` |
| `GET` | [Get all available domains](/developer-docs/api/get-all-available-domains) | `/api/v1/available_domains/` |
</details>
@@ -577,7 +577,7 @@ curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
| Method | Endpoint | Description |
| ------ | ---------------------------------------------------------------------------------------------- | ---------------------- |
| `GET` | [Read off of the Redis events stream](/developer-docs/6.1.0/api/read-off-of-the-redis-events-stream) | `/api/v1/async_event/` |
| `GET` | [Read off of the Redis events stream](/developer-docs/api/read-off-of-the-redis-events-stream) | `/api/v1/async_event/` |
</details>
@@ -586,7 +586,7 @@ curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
| Method | Endpoint | Description |
| ------ | ---------------------------------------------------------------------------- | ------------------------- |
| `GET` | [Get api by version openapi](/developer-docs/6.1.0/api/get-api-by-version-openapi) | `/api/{version}/_openapi` |
| `GET` | [Get api by version openapi](/developer-docs/api/get-api-by-version-openapi) | `/api/{version}/_openapi` |
</details>
@@ -597,12 +597,12 @@ curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
| Method | Endpoint | Description |
| -------- | -------------------------------------------------------------------------------- | ------------------------------- |
| `GET` | [Get security groups](/developer-docs/6.1.0/api/get-security-groups) | `/api/v1/security/groups/` |
| `POST` | [Create security groups](/developer-docs/6.1.0/api/create-security-groups) | `/api/v1/security/groups/` |
| `GET` | [Get security groups info](/developer-docs/6.1.0/api/get-security-groups-info) | `/api/v1/security/groups/_info` |
| `DELETE` | [Delete security groups by pk](/developer-docs/6.1.0/api/delete-security-groups-by-pk) | `/api/v1/security/groups/{pk}` |
| `GET` | [Get security groups by pk](/developer-docs/6.1.0/api/get-security-groups-by-pk) | `/api/v1/security/groups/{pk}` |
| `PUT` | [Update security groups by pk](/developer-docs/6.1.0/api/update-security-groups-by-pk) | `/api/v1/security/groups/{pk}` |
| `GET` | [Get security groups](/developer-docs/api/get-security-groups) | `/api/v1/security/groups/` |
| `POST` | [Create security groups](/developer-docs/api/create-security-groups) | `/api/v1/security/groups/` |
| `GET` | [Get security groups info](/developer-docs/api/get-security-groups-info) | `/api/v1/security/groups/_info` |
| `DELETE` | [Delete security groups by pk](/developer-docs/api/delete-security-groups-by-pk) | `/api/v1/security/groups/{pk}` |
| `GET` | [Get security groups by pk](/developer-docs/api/get-security-groups-by-pk) | `/api/v1/security/groups/{pk}` |
| `PUT` | [Update security groups by pk](/developer-docs/api/update-security-groups-by-pk) | `/api/v1/security/groups/{pk}` |
</details>
@@ -611,20 +611,20 @@ curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
| Method | Endpoint | Description |
| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------- |
| `DELETE` | [Bulk delete themes](/developer-docs/6.1.0/api/bulk-delete-themes) | `/api/v1/theme/` |
| `GET` | [Get a list of themes](/developer-docs/6.1.0/api/get-a-list-of-themes) | `/api/v1/theme/` |
| `POST` | [Create a theme](/developer-docs/6.1.0/api/create-a-theme) | `/api/v1/theme/` |
| `GET` | [Get metadata information about this API resource (theme--info)](/developer-docs/6.1.0/api/get-metadata-information-about-this-api-resource-theme-info) | `/api/v1/theme/_info` |
| `DELETE` | [Delete a theme](/developer-docs/6.1.0/api/delete-a-theme) | `/api/v1/theme/{pk}` |
| `GET` | [Get a theme](/developer-docs/6.1.0/api/get-a-theme) | `/api/v1/theme/{pk}` |
| `PUT` | [Update a theme](/developer-docs/6.1.0/api/update-a-theme) | `/api/v1/theme/{pk}` |
| `PUT` | [Set a theme as the system dark theme](/developer-docs/6.1.0/api/set-a-theme-as-the-system-dark-theme) | `/api/v1/theme/{pk}/set_system_dark` |
| `PUT` | [Set a theme as the system default theme](/developer-docs/6.1.0/api/set-a-theme-as-the-system-default-theme) | `/api/v1/theme/{pk}/set_system_default` |
| `GET` | [Download multiple themes as YAML files](/developer-docs/6.1.0/api/download-multiple-themes-as-yaml-files) | `/api/v1/theme/export/` |
| `POST` | [Import themes from a ZIP file](/developer-docs/6.1.0/api/import-themes-from-a-zip-file) | `/api/v1/theme/import/` |
| `GET` | [Get related fields data (theme-related-column-name)](/developer-docs/6.1.0/api/get-related-fields-data-theme-related-column-name) | `/api/v1/theme/related/{column_name}` |
| `DELETE` | [Clear the system dark theme](/developer-docs/6.1.0/api/clear-the-system-dark-theme) | `/api/v1/theme/unset_system_dark` |
| `DELETE` | [Clear the system default theme](/developer-docs/6.1.0/api/clear-the-system-default-theme) | `/api/v1/theme/unset_system_default` |
| `DELETE` | [Bulk delete themes](/developer-docs/api/bulk-delete-themes) | `/api/v1/theme/` |
| `GET` | [Get a list of themes](/developer-docs/api/get-a-list-of-themes) | `/api/v1/theme/` |
| `POST` | [Create a theme](/developer-docs/api/create-a-theme) | `/api/v1/theme/` |
| `GET` | [Get metadata information about this API resource (theme--info)](/developer-docs/api/get-metadata-information-about-this-api-resource-theme-info) | `/api/v1/theme/_info` |
| `DELETE` | [Delete a theme](/developer-docs/api/delete-a-theme) | `/api/v1/theme/{pk}` |
| `GET` | [Get a theme](/developer-docs/api/get-a-theme) | `/api/v1/theme/{pk}` |
| `PUT` | [Update a theme](/developer-docs/api/update-a-theme) | `/api/v1/theme/{pk}` |
| `PUT` | [Set a theme as the system dark theme](/developer-docs/api/set-a-theme-as-the-system-dark-theme) | `/api/v1/theme/{pk}/set_system_dark` |
| `PUT` | [Set a theme as the system default theme](/developer-docs/api/set-a-theme-as-the-system-default-theme) | `/api/v1/theme/{pk}/set_system_default` |
| `GET` | [Download multiple themes as YAML files](/developer-docs/api/download-multiple-themes-as-yaml-files) | `/api/v1/theme/export/` |
| `POST` | [Import themes from a ZIP file](/developer-docs/api/import-themes-from-a-zip-file) | `/api/v1/theme/import/` |
| `GET` | [Get related fields data (theme-related-column-name)](/developer-docs/api/get-related-fields-data-theme-related-column-name) | `/api/v1/theme/related/{column_name}` |
| `DELETE` | [Clear the system dark theme](/developer-docs/api/clear-the-system-dark-theme) | `/api/v1/theme/unset_system_dark` |
| `DELETE` | [Clear the system default theme](/developer-docs/api/clear-the-system-default-theme) | `/api/v1/theme/unset_system_default` |
</details>
@@ -633,14 +633,14 @@ curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
| Method | Endpoint | Description |
| -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------ |
| `GET` | [Get security user registrations](/developer-docs/6.1.0/api/get-security-user-registrations) | `/api/v1/security/user_registrations/` |
| `POST` | [Create security user registrations](/developer-docs/6.1.0/api/create-security-user-registrations) | `/api/v1/security/user_registrations/` |
| `GET` | [Get security user registrations info](/developer-docs/6.1.0/api/get-security-user-registrations-info) | `/api/v1/security/user_registrations/_info` |
| `DELETE` | [Delete security user registrations by pk](/developer-docs/6.1.0/api/delete-security-user-registrations-by-pk) | `/api/v1/security/user_registrations/{pk}` |
| `GET` | [Get security user registrations by pk](/developer-docs/6.1.0/api/get-security-user-registrations-by-pk) | `/api/v1/security/user_registrations/{pk}` |
| `PUT` | [Update security user registrations by pk](/developer-docs/6.1.0/api/update-security-user-registrations-by-pk) | `/api/v1/security/user_registrations/{pk}` |
| `GET` | [Get distinct values from field data (security-user-registrations-distinct-column-name)](/developer-docs/6.1.0/api/get-distinct-values-from-field-data-security-user-registrations-distinct-column-name) | `/api/v1/security/user_registrations/distinct/{column_name}` |
| `GET` | [Get related fields data (security-user-registrations-related-column-name)](/developer-docs/6.1.0/api/get-related-fields-data-security-user-registrations-related-column-name) | `/api/v1/security/user_registrations/related/{column_name}` |
| `GET` | [Get security user registrations](/developer-docs/api/get-security-user-registrations) | `/api/v1/security/user_registrations/` |
| `POST` | [Create security user registrations](/developer-docs/api/create-security-user-registrations) | `/api/v1/security/user_registrations/` |
| `GET` | [Get security user registrations info](/developer-docs/api/get-security-user-registrations-info) | `/api/v1/security/user_registrations/_info` |
| `DELETE` | [Delete security user registrations by pk](/developer-docs/api/delete-security-user-registrations-by-pk) | `/api/v1/security/user_registrations/{pk}` |
| `GET` | [Get security user registrations by pk](/developer-docs/api/get-security-user-registrations-by-pk) | `/api/v1/security/user_registrations/{pk}` |
| `PUT` | [Update security user registrations by pk](/developer-docs/api/update-security-user-registrations-by-pk) | `/api/v1/security/user_registrations/{pk}` |
| `GET` | [Get distinct values from field data (security-user-registrations-distinct-column-name)](/developer-docs/api/get-distinct-values-from-field-data-security-user-registrations-distinct-column-name) | `/api/v1/security/user_registrations/distinct/{column_name}` |
| `GET` | [Get related fields data (security-user-registrations-related-column-name)](/developer-docs/api/get-related-fields-data-security-user-registrations-related-column-name) | `/api/v1/security/user_registrations/related/{column_name}` |
</details>
+1 -1
View File
@@ -58,7 +58,7 @@ A modern, enterprise-ready business intelligence web application.
[**Why Superset?**](#why-superset) |
[**Supported Databases**](#supported-databases) |
[**Installation and Configuration**](#installation-and-configuration) |
[**Release Notes**](https://github.com/apache/superset/releases) |
[**Release Notes**](https://github.com/apache/superset/blob/master/RELEASING/README.md#release-notes-for-recent-releases) |
[**Get Involved**](#get-involved) |
[**Contributor Guide**](#contributor-guide) |
[**Resources**](#resources) |
@@ -328,12 +328,6 @@ Conditional formatting rules highlight cells based on their values. Rules can be
Each rule has a **"Use gradient"** toggle: enabled applies a varying opacity (lighter = further from threshold), disabled applies a solid fill at full opacity regardless of value.
For numeric rules, the optional **"Min bound"** / **"Max bound"** fields let you override the auto-detected color range with fixed values instead of relying on the minimum/maximum found in the data — useful when you want consistent coloring across dashboards or data refreshes.
Set **"Bound unit"** to **"% of column"** to express the bounds as percentages of either the column maximum or **"Column sum"**, which adds the absolute values in the column so positive and negative values do not cancel into an unstable denominator. A non-positive maximum or zero sum falls back to the automatic data range. A percentage center based on **"Column sum"** must still resolve inside the color range to activate diverging colors. This option is unavailable with server pagination because the browser only receives one page of rows and cannot calculate a stable full-column denominator; existing percentage rules also use the automatic range while server pagination is enabled.
For a diverging scale, set a **"Center value"** together with **"Low color"**, **"Mid color"**, and **"High color"**. Values below and above the center interpolate toward the corresponding endpoint color. Turning off **"Use gradient"** disables this interpolation and applies the base color as a solid fill.
Each rule's color is set with a full color picker rather than a fixed dropdown of presets. Pick any custom color, or use the **Colors** preset swatches, which reference theme tokens (success, warning, error, and their background variants) so a rule's color updates automatically if the active theme changes, including switching between light and dark mode.
When a rule targets a column with an active time comparison, a **Trend colors** preset also appears, letting you color cells green for an increase and red for a decrease (or the reverse).
@@ -412,18 +406,6 @@ ECharts option overrides bypass Superset's validation layer. Invalid option keys
When the **Search Box** is visible in a Table chart, the **Download** action exports only the rows currently visible after the search filter is applied — not the full underlying dataset. This matches the visual output and is intentional. To export the full dataset regardless of search state, use the **Download as CSV** option from the chart's three-dot menu in the dashboard or from the Explore chart toolbar before applying a search filter.
### Exporting a Chart as an Image or PDF
Alongside the raw-data export options (CSV, JSON, Excel), a chart's three-dot menu — in a dashboard or from the Explore chart toolbar — offers a few ways to export a visual snapshot of the chart:
- **Export screenshot (jpeg)** — a single-click JPEG screenshot of the chart.
- **Export screenshot (png)** — opens a submenu with **Transparent background** and **Solid background** options. The solid option uses the current theme's background color. PNG produces a higher-quality image than the JPEG export.
- **Export as PDF** — downloads the chart as a PDF file.
The dropdown menu is briefly hidden while the screenshot or PDF is being captured so it doesn't appear in the exported file. In Explore, these image and PDF options are available from the **Export All Data** submenu, and also from the **Export current view** submenu when the chart type supports current-view export.
These menu items respect your permissions: the dashboard export menu only appears if you can download, and the image/PDF options are disabled if you lack image-export permission.
### Sharing a Specific Tab
When a dashboard has tabs, each tab gets its own shareable URL. Navigate to the tab you want to share and copy the URL from your browser's address bar — the tab anchor is encoded in the URL so that anyone opening the link lands directly on that tab.
-15
View File
@@ -88,21 +88,6 @@ embedDashboard({
If the callback returns `null` or is not provided, Superset uses its own permalink URL as a fallback.
### Permalink origin rewriting
This rewrite only applies to the non-embedded permalink path — it has no effect on embedded dashboards. When Superset is not embedded, it rewrites the origin of any permalink URL it generates to `window.location.origin` before showing it to the user, which keeps a proxied or subdirectory-deployed Superset from handing out a permalink that points at an internal hostname the user's browser can't reach.
When Superset **is** embedded, this rewrite is skipped entirely regardless of the flag below: a `resolvePermalinkUrl` callback's return value is used as-is, and if no callback is provided (or it fails), the backend-supplied URL is also returned as-is.
If your reverse proxy correctly forwards `X-Forwarded-Host` and you'd rather non-embedded permalinks carry the backend's literal origin, opt out of the rewrite with `EMBEDDED_DISABLE_PERMALINK_ORIGIN_REWRITE`:
```python
# superset_config.py
EMBEDDED_DISABLE_PERMALINK_ORIGIN_REWRITE = True
```
This defaults to `False` (rewrite enabled) and only affects non-embedded permalinks. Flipping the default would regress the common proxied/subdirectory deployment by exposing an unreachable internal host in copied permalinks.
---
## Feature Flags for Embedded Mode
@@ -151,20 +151,6 @@ see some data!
You should see months in the rows and Department and Travel Class in the columns. Publish this chart
to your existing Tutorial Dashboard you created earlier.
:::note
Row and column totals/subtotals for the Pivot Table are correct even for non-additive metrics,
such as ratios (`SUM(a)/SUM(b)`), `COUNT_DISTINCT`, `AVG`, and percentiles, not just additive ones
like `SUM` or `COUNT`. Totals derive client-side, by reducing the same full-detail query results
used to build the table, only when every selected metric is additive; if any selected metric is
non-additive, Superset instead issues a database query at each total's own granularity for all
metrics, so the total reflects each metric's own definition evaluated at that level rather than an
incorrect combination of the displayed cells. Because of this, there's no separate "Aggregation
function" control for totals in the Pivot Table: a total always reflects the metric's own
definition. The Table chart's **Show summary** row is different: its **Summary aggregation**
control can override a simple metric's own aggregation (to Sum or Average) for the summary row
only — metrics built from custom SQL keep their own aggregation regardless.
:::
### Line Chart
In this section, we are going to create a line chart to understand the average price of a ticket by
@@ -70,24 +70,5 @@ alert or report is removed, and the reason is shown. Charts that belong to
dashboards are removed from those dashboards as part of the deletion; the
dashboards themselves are left in place.
Before an archived dataset is deleted permanently, Superset checks which
charts still use it and which dashboards contain those charts. The confirmation
shows the total number of affected charts and dashboards, identifies the ones
you are allowed to access, and reports the remaining objects only as restricted
counts. Restricted names, identifiers, and links are not displayed. Archived
dependents are included because they can still be recovered after the dataset
is gone.
Deleting the dataset does not delete those charts or dashboards. They remain
in place without a usable dataset and may therefore be broken. If there are no
dependents, the confirmation explicitly reports zero affected charts and
dashboards.
The dependency check fails closed. While it is loading, or if its result is
unavailable, permanent deletion is disabled; cancel or retry the check. Superset
checks again when you submit. If dependencies changed while the confirmation
was open, the refreshed impact replaces the previous result and you must type
DELETE again before proceeding.
Objects are also deleted permanently on their own once they have been in the
archive longer than the retention window, without anyone acting.
@@ -78,18 +78,6 @@ Charts are **not saved by default**. The workflow is intentionally iterative:
To skip the preview and save immediately, include "and save it" in your prompt.
:::
:::info Deployment-specific chart types
Use `get_chart_type_schema` before generating a chart to discover the types
available on your Superset instance. Some deployments expose additional
feature-gated visualizations. For example, a deployment with an AG Grid pivot
extension enabled can expose `interactive_pivot`, which supports interactive
row groups, pivot columns, totals, and period-over-period comparisons. Pair
`comparison_period` (for example, `1 year ago`) with `comparison_type`
(`values`, `difference`, `percentage`, or `ratio`). It is distinct from the
built-in `pivot_table` chart type and is not offered when the host visualization
is unavailable.
:::
### Create Dashboards
Build dashboards from a collection of charts:
@@ -260,12 +248,11 @@ Ask your admin for the MCP server URL and any authentication tokens you need.
### Datasets
| Tool | Description |
| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------- |
| `list_datasets` | List datasets with filtering and search |
| `get_dataset_info` | Get dataset metadata (columns, metrics, schema details) |
| `create_virtual_dataset` | Create a virtual dataset from a SQL query |
| `update_dataset_metric` | Update a saved metric's expression, name, verbose_name, or format (affects every chart using it; requires dataset ownership) |
| Tool | Description |
| ------------------------ | ------------------------------------------------ |
| `list_datasets` | List datasets with filtering and search |
| `get_dataset_info` | Get dataset metadata (columns, metrics, filters) |
| `create_virtual_dataset` | Create a virtual dataset from a SQL query |
### Charts
+71
View File
@@ -0,0 +1,71 @@
/* eslint-env node */
/**
* 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.
*/
const typescriptEslintParser = require('@typescript-eslint/parser');
const typescriptEslintPlugin = require('@typescript-eslint/eslint-plugin');
const js = require('@eslint/js');
const ts = require('typescript-eslint');
const react = require('eslint-plugin-react');
const globals = require('globals');
const { defineConfig, globalIgnores } = require('eslint/config');
module.exports = defineConfig([
{
files: ['**/*.{js,jsx,ts,tsx}'],
},
globalIgnores(['build/**/*', '.docusaurus/**/*', 'node_modules/**/*']),
js.configs.recommended,
...ts.configs.recommended,
{
files: ['eslint.config.js'],
rules: {
'@typescript-eslint/no-require-imports': 'off',
},
},
{
languageOptions: {
parser: typescriptEslintParser,
parserOptions: {
ecmaFeatures: {
jsx: true,
},
ecmaVersion: 2020,
sourceType: 'module',
},
globals: {
...globals.browser,
...globals.node,
},
},
plugins: {
typescript: typescriptEslintPlugin,
react,
},
rules: {
'react/react-in-jsx-scope': 'off',
'react/prop-types': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
},
settings: {
react: {
version: 'detect',
},
},
},
]);
-139
View File
@@ -1,139 +0,0 @@
{
"$schema": "./node_modules/oxlint/configuration_schema.json",
"plugins": [
"typescript",
"react"
],
"categories": {
"correctness": "off"
},
"env": {
"builtin": true,
"browser": true,
"node": true
},
"ignorePatterns": [
"build/**/*",
".docusaurus/**/*",
"node_modules/**/*"
],
"settings": {
"react": {
"version": "18.3.1"
}
},
"options": {
"typeAware": true
},
"rules": {
"constructor-super": "error",
"for-direction": "error",
"getter-return": "error",
"no-async-promise-executor": "error",
"no-case-declarations": "error",
"no-class-assign": "error",
"no-compare-neg-zero": "error",
"no-cond-assign": "error",
"no-const-assign": "error",
"no-constant-binary-expression": "error",
"no-constant-condition": "error",
"no-control-regex": "error",
"no-debugger": "error",
"no-delete-var": "error",
"no-dupe-class-members": "error",
"no-dupe-else-if": "error",
"no-dupe-keys": "error",
"no-duplicate-case": "error",
"no-empty": "error",
"no-empty-character-class": "error",
"no-empty-pattern": "error",
"no-empty-static-block": "error",
"no-ex-assign": "error",
"no-extra-boolean-cast": "error",
"no-fallthrough": "error",
"no-func-assign": "error",
"no-global-assign": "error",
"no-import-assign": "error",
"no-invalid-regexp": "error",
"no-irregular-whitespace": "error",
"no-loss-of-precision": "error",
"no-misleading-character-class": "error",
"no-new-native-nonconstructor": "error",
"no-nonoctal-decimal-escape": "error",
"no-obj-calls": "error",
"no-prototype-builtins": "error",
"no-redeclare": "error",
"no-regex-spaces": "error",
"no-self-assign": "error",
"no-setter-return": "error",
"no-shadow-restricted-names": "error",
"no-sparse-arrays": "error",
"no-this-before-super": "error",
"no-unexpected-multiline": "error",
"no-unreachable": "error",
"no-unsafe-finally": "error",
"no-unsafe-negation": "error",
"no-unsafe-optional-chaining": "error",
"no-unused-labels": "error",
"no-unused-private-class-members": "error",
"no-unused-vars": "error",
"no-useless-backreference": "error",
"no-useless-catch": "error",
"no-useless-escape": "error",
"no-with": "error",
"require-yield": "error",
"use-isnan": "error",
"valid-typeof": "error",
"no-array-constructor": "error",
"no-unused-expressions": "error",
"typescript/ban-ts-comment": "error",
"typescript/no-duplicate-enum-values": "error",
"typescript/no-empty-object-type": "error",
"typescript/no-explicit-any": "error",
"typescript/no-extra-non-null-assertion": "error",
"typescript/no-misused-new": "error",
"typescript/no-namespace": "error",
"typescript/no-non-null-asserted-optional-chain": "error",
"typescript/no-require-imports": "error",
"typescript/no-this-alias": "error",
"typescript/no-unnecessary-type-constraint": "error",
"typescript/no-unsafe-declaration-merging": "error",
"typescript/no-unsafe-function-type": "error",
"typescript/no-wrapper-object-types": "error",
"typescript/prefer-as-const": "error",
"typescript/prefer-namespace-keyword": "error",
"typescript/triple-slash-reference": "error"
},
"overrides": [
{
"files": [
"**/*.ts",
"**/*.tsx",
"**/*.mts",
"**/*.cts"
],
"rules": {
"constructor-super": "off",
"getter-return": "off",
"no-class-assign": "off",
"no-const-assign": "off",
"no-dupe-class-members": "off",
"no-dupe-keys": "off",
"no-func-assign": "off",
"no-import-assign": "off",
"no-new-native-nonconstructor": "off",
"no-obj-calls": "off",
"no-redeclare": "off",
"no-setter-return": "off",
"no-this-before-super": "off",
"no-unreachable": "off",
"no-unsafe-negation": "off",
"no-var": "error",
"no-with": "off",
"prefer-const": "error",
"prefer-rest-params": "error",
"prefer-spread": "error"
}
}
]
}
+19 -13
View File
@@ -29,7 +29,7 @@
"lint:db-metadata": "python3 ../superset/db_engine_specs/lint_metadata.py",
"lint:db-metadata:report": "python3 ../superset/db_engine_specs/lint_metadata.py --markdown -o ../superset/db_engine_specs/METADATA_STATUS.md",
"update:readme-db-logos": "node scripts/generate-database-docs.mjs --update-readme",
"lint": "oxlint --config oxlint.json",
"eslint": "eslint .",
"lint:docs-links": "node scripts/lint-docs-links.mjs",
"version:add": "node scripts/manage-versions.mjs add",
"version:remove": "node scripts/manage-versions.mjs remove",
@@ -58,15 +58,15 @@
"@fontsource/inter": "^5.3.0",
"@mdx-js/react": "^3.1.1",
"@saucelabs/theme-github-codeblock": "^0.3.0",
"@storybook/addon-docs": "^10.5.10",
"@storybook/addon-docs": "^10.5.9",
"@superset-ui/core": "^0.20.4",
"@swc/core": "^1.16.1",
"antd": "^6.6.2",
"baseline-browser-mapping": "^2.11.20",
"caniuse-lite": "^1.0.30001810",
"antd": "^6.6.1",
"baseline-browser-mapping": "^2.11.15",
"caniuse-lite": "^1.0.30001809",
"docusaurus-plugin-openapi-docs": "^5.2.0",
"docusaurus-theme-openapi-docs": "^5.2.0",
"js-yaml": "^5.4.1",
"js-yaml": "^5.3.0",
"json-bigint": "^1.0.0",
"prism-react-renderer": "^2.4.1",
"react": "^18.3.1",
@@ -76,8 +76,8 @@
"react-svg-pan-zoom": "^3.13.1",
"react-table": "^7.8.0",
"remark-import-partial": "^0.0.2",
"reselect": "^5.3.0",
"storybook": "^10.5.10",
"reselect": "^5.2.0",
"storybook": "^10.5.9",
"swagger-ui-react": "^5.32.14",
"swc-loader": "^0.2.7",
"tinycolor2": "^1.4.2",
@@ -85,13 +85,19 @@
},
"devDependencies": {
"@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",
"oxfmt": "^0.65.0",
"oxlint": "^1.80.0",
"oxlint-tsgolint": "^7.0.2001",
"typescript": "7.0.2",
"webpack": "^5.110.1"
"@typescript-eslint/eslint-plugin": "^8.67.0",
"@typescript-eslint/parser": "^8.67.0",
"eslint": "^9.39.2",
"eslint-plugin-react": "^7.37.5",
"globals": "^17.11.0",
"oxfmt": "^0.64.0",
"typescript": "~6.0.3",
"typescript-eslint": "^8.67.0",
"webpack": "^5.109.2"
},
"browserslist": {
"production": [
-51
View File
@@ -1,51 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 26.2.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 238 55" style="enable-background:new 0 0 238 55;" xml:space="preserve">
<path d="M234.9,34.8c-0.9-1.3-2.2-2.2-3.6-2.8c-0.4-0.2-1.2-0.4-2.5-0.8c-1-0.3-1.9-0.6-2.8-1.1c-0.6-0.3-1.1-0.8-1.5-1.4
c-0.3-0.6-0.5-1.3-0.5-1.9c0-1,0.4-2,1.1-2.7c0.7-0.7,1.7-1.1,2.8-1.1c1.1-0.1,2.1,0.3,2.9,1c0.8,0.8,1.2,1.8,1.2,2.9h3.6
c0-2-0.7-3.9-2.1-5.3c-1.5-1.3-3.4-2-5.4-1.9c-2,0-4,0.7-5.5,2.1c-1.5,1.3-2.3,3.2-2.3,5.2c-0.1,1.5,0.4,3.1,1.3,4.3
c0.9,1.1,2.8,2.1,5.8,3.1c1.4,0.4,2.7,1.2,3.8,2.1c0.7,0.8,1.1,1.9,1.1,3c0,1.2-0.5,2.3-1.3,3.1c-0.9,0.8-2.1,1.3-3.3,1.2
c-1.4,0-2.6-0.6-3.5-1.6c-1-1.1-1.5-2.6-1.4-4.1V38h-3.5c-0.1,2.4,0.8,4.7,2.4,6.5c1.5,1.6,3.7,2.5,6,2.4c2.2,0.1,4.4-0.7,6.1-2.2
c1.6-1.4,2.5-3.5,2.4-5.6C236.2,37.6,235.8,36.1,234.9,34.8z"/>
<path d="M117,31.4c0.3-2.4,1.5-4.7,3.3-6.4c1.8-1.6,4.1-2.4,6.5-2.4c2.4-0.1,4.8,0.7,6.7,2.2c1.9,1.8,3.1,4.1,3.6,6.6L117,31.4z
M140.9,34.1c0-4.3-1.3-7.9-3.8-10.6s-6.1-4.2-9.8-4.1c-3.7-0.1-7.4,1.3-10,3.9s-4,6.2-3.9,9.9c-0.1,3.7,1.4,7.2,4,9.8
c2.5,2.7,6.1,4.1,9.8,4.1c2.7,0.1,5.4-0.8,7.7-2.3c2.3-1.7,4.1-4,5.2-6.7h-3.8c-0.8,1.7-2.1,3.2-3.7,4.2c-1.6,1-3.5,1.6-5.4,1.5
c-2.6,0.1-5.1-0.9-7-2.6c-1.9-1.8-3-4.3-3.1-6.9h24L140.9,34.1z"/>
<path d="M175.1,19.6c-1.9,0-3.7,0.4-5.4,1.2c-1.6,0.8-3,2-4,3.5c-0.9-1.5-2.2-2.6-3.8-3.4c-1.7-0.8-3.6-1.3-5.5-1.3
c-1.6,0-3.2,0.3-4.7,0.9c-1.4,0.6-2.6,1.5-3.6,2.6v-2.9h-3.4v26.2h3.3V33.6c0-1.6,0-3.2,0.2-4.8c0.2-0.9,0.4-1.7,0.9-2.4
c0.6-1.1,1.6-2,2.8-2.6c1.3-0.6,2.7-1,4.1-0.9c2.6,0,4.5,0.7,5.7,2.2c1.2,1.4,1.9,3.7,1.9,6.7v14.7h3.3V33.6c0-1.6,0-3.2,0.3-4.8
c0.2-0.9,0.5-1.7,0.9-2.4c0.6-1.1,1.6-2,2.7-2.6c1.2-0.6,2.6-1,4-0.9c2.6,0,4.5,0.7,5.7,2.2s1.7,3.9,1.7,7.4v13.9h3.3V33.1
c0-4.7-0.8-8.2-2.5-10.3S178.7,19.6,175.1,19.6z"/>
<path d="M193.1,31.4c0.3-2.4,1.5-4.7,3.3-6.4c1.8-1.6,4.1-2.4,6.5-2.4c2.4-0.1,4.9,0.7,6.8,2.2c1.9,1.8,3.1,4.1,3.5,6.6L193.1,31.4z
M216.9,34.1c0-4.3-1.3-7.9-3.8-10.6s-6.1-4.2-9.8-4.1c-3.7-0.1-7.4,1.3-10,3.9s-4,6.2-3.9,9.9c-0.1,3.7,1.4,7.2,4,9.8
c2.5,2.7,6.1,4.2,9.8,4.1c2.7,0,5.4-0.8,7.7-2.3c2.3-1.7,4.1-4,5.2-6.7h-3.8c-0.8,1.7-2.1,3.2-3.8,4.2c-1.6,1-3.5,1.5-5.4,1.5
c-2.6,0.1-5.2-0.9-7.1-2.6c-1.9-1.8-3-4.3-3.1-6.9h24L216.9,34.1L216.9,34.1z"/>
<path d="M108.4,20.7c-1.1,0.7-2,1.5-2.7,2.6v-3.1h-3.2v26.2h3.5V30.6c0-2.4,0.5-4.1,1.4-5.2c0.9-1.1,2.4-1.7,4.6-1.9v-3.7
C110.6,19.8,109.4,20.1,108.4,20.7z"/>
<path d="M74.6,31.4c0.3-2.4,1.5-4.7,3.3-6.4c1.8-1.6,4.1-2.4,6.5-2.4c2.4-0.1,4.8,0.7,6.7,2.2c1.9,1.8,3.1,4.1,3.5,6.6L74.6,31.4z
M98.5,34.1c0-4.3-1.3-7.9-3.8-10.6s-6.1-4.2-9.8-4.1c-3.7-0.1-7.4,1.3-10,3.9s-4,6.2-3.9,9.9c-0.1,3.7,1.4,7.2,4,9.8
c2.5,2.7,6.1,4.1,9.8,4.1c2.7,0,5.4-0.8,7.7-2.3c2.3-1.7,4.1-4,5.1-6.7h-3.8c-0.8,1.7-2.1,3.2-3.7,4.2s-3.5,1.5-5.4,1.5
c-2.6,0.1-5.1-0.9-7-2.6c-1.9-1.8-3-4.3-3.1-6.9h24L98.5,34.1z"/>
<path d="M47.4,11.7c-1.7-4-4.2-8.4-8.5-10.1C34.2,0,29.1,1,25.4,4.2c-2.7,2.4-4.3,6.1-4.8,11L20.4,16c-0.1,1.3-0.3,2.6-0.3,3.8
c-0.8-3.5-0.5-5.9-0.7-9.7c-0.8,0.4-1.2,1.2-1.2,2.1c0,0.2-1-0.4-1.2-0.3c-0.8,0.4-1.6-1-2-1.5c-0.2,0.4-0.4,0.7-0.7,1.1
C14,11,13.5,11,13,10.5c-0.4,1-1.6,0.5-2.7,0.5c0.6,1,0.8,2-0.1,2.4c0.1,0.1,0.9,0.3,0.9,0.5c-0.3,0.4-1.3,0-1.8-0.1v0.8
c-1.4-0.8-3.7-2.3-2.9,0.9c-1,0.2-0.5,0-0.5,0.9c-0.4,0.1-0.4,0.1-0.4,0.6c-1.2-0.6-2.2,4.9-2.1,6.5c0.9,0.2,1,0.5,1.5,1.4
c-0.7,0.3-1.1,1-1.6,1.3L4,26.6c-0.6,0.3-1.1,0.7-1.5,1.3c0.2-0.3,0.6,0.4,0.5,0.3L2.6,28c0.1,0.4,0.3,0.8,0.4,1.2
c-0.8,0.3-0.6,0.6-1.1,1.3c0.2,0,0.5,0.1,0.7,0.1c-0.4,0-0.5,1.9-0.4,2.2c0.2-0.4,0.6-0.9,0.8-1.4l0.5,0.5l-0.7,0.6
c1.8,0.5-0.2,1.7,0.6,3.1C3.6,34.8,4,34.7,4,33.8l0.4,0.3c-0.2,0.3-1.4,2.6-0.3,2.6c0.1,0,0.1,3.8,0.3,4.8C4.6,41.3,4.8,41,5,40.6
c0,0.6,0.3,0.8,0.1,1.5c1.8-0.5,1.1,0.5,0.4,1.4c0.6-0.1,1.2-0.3,1.8-0.5c0.8-0.3,0.1,1.1,0.4,1.1c0.3,0,1.2-1.8,1.4-2.1v0.6
c0.4-0.2,1.8-2,2-2c0.2,0.3,0.3,0.7,0.2,1.1c1.6-2,3-4.2,4-6.6c0.1,0.1,0.2,0.2,0.4,0.2c-0.2,0-4.1,7.7-4.1,8.1l0.9-0.2
c-0.3,0.6-0.5,1.2-0.6,1.8c1.6-0.2,0.9,1.2,0.9,2.5c1.3-0.8,3.2-1.3,2.5,0.9c0.4-0.2,0.9-0.4,1.3-0.6c-1.1,0.4,0.5,2.6,0.7,3.2
c0.2,0.7,2.3,0.2,3,0.4c0.7-1.1,1,0.2,1.2,1.3s1.4-0.6,1.9-0.4c0.4,0.1-0.3,2.7,1.2,1.6c0.6-0.5,0.8,0.4,1.7-0.5
c0,0,2.7,0.4,2.6,0.4c0.5-2.6,2.5-0.1,2.2-2.4h0.6c-0.1-2,2,0.9,2-2c0-0.7-1.6-1.5,0.4-0.9c-0.2-0.9,0.2-1.1-0.8-1.3
c-0.1-0.2-0.1-0.4,0.1-0.5c0.9,0,2.5,1.7,3.1,0.9c0.2-0.2-0.8-2-0.9-2.5c0.5,0.1,1.1-0.1,1.6,0c-0.9-0.5-0.3-0.6-1.4-0.9
c0.9-1.7,2.6-0.1,3.4-1.4c-1.7,0.3-2.6-3.3-1.5-3.6c-0.9-0.8-1.6-1-2.3-1.9c-1.8-2.3,1.7,0.4,2.3,0.9c0-0.4,0.2-0.9,0.2-1.3l0.9,0.8
c0-0.2,0.1-0.4,0.1-0.6c0.8,0.7,1.9,1,2.9,0.9c-0.2-0.5,0-0.6-0.2-1.1c0.8,0.2,1.3,0,2.2,0.1c-0.6-1.8,1.5-1.7,2.9-2.1
c2.3-0.7-1.4-1-1.6-1.2c-0.4-0.4,0.5-0.9,0.6-0.9s-0.8-1.1-0.6-0.8c-0.3-1-2.6-0.3-0.6-1.6c-0.9-0.2-2.1-0.4-2.1-1.6
c0.7-0.1,1.5-0.2,2.2-0.4c-0.5-0.4-0.9-1.1-1.5-1.4l0.5-0.2c-2.8-0.5,0.3-2.7,1-4c-1.9,0.4-2-1.1-3.7-1.3l0.8-0.7
c-0.9,0-1.9-0.1-2.8-0.3c0.2-1,0.9-1.9,1.9-2.2c-3.1-1.5-2.4-3.8-5.6-4.7l0.7-0.7c-0.9-1.3-1.6-0.4-2.6-0.7
c-2.1-0.6-1.9,2.3-1.9-1.1c0,0.4-0.5-0.4-0.6-0.6c-0.8,0.5-3.4,2.6-3.9,2.1C26.1,12,26,12.2,25.5,13c-0.3,0.3-1.3,0.9-1.1,0.5
c-0.6,0.9-0.6,4.3-1.3,6.6c0-1.2,0.2-2.4,0.3-3.6l0.1-0.9c0.4-4.1,1.7-7.1,3.8-8.9c2.8-2.4,6.7-3.1,10.3-2c3.4,1.2,5.5,5.4,7,9.1
L57,46.5h2.7l13.2-34.7h-3.5L58.5,41.2L47.4,11.7z"/>
</svg>

Before

Width:  |  Height:  |  Size: 5.3 KiB

+9176 -7410
View File
File diff suppressed because it is too large Load Diff
+6 -23
View File
@@ -1,30 +1,14 @@
{
// This file is not used in compilation. It is here just for a nice editor experience.
// "extends": "@docusaurus/tsconfig",
// First compilerOptions section comes from above commented @docusaurus/tsconfig
// We moved them here to help with TS v7 migration so whenever Docusaurus readily supports TS v7,
// re-install @docusaurus/tsconfig and remove said section.
// Commented options are overriden in the next section.
"extends": "@docusaurus/tsconfig",
"compilerOptions": {
"allowJs": true,
// "esModuleInterop": true,
// "jsx": "preserve",
"target": "ES2022",
"lib": ["ES2022", "DOM"],
// "moduleResolution": "bundler",
"module": "esnext",
"noEmit": true,
// "paths": {
// "@site/*": ["./*"]
// },
// "skipLibCheck": true,
"baseUrl": ".",
"ignoreDeprecations": "6.0",
"skipLibCheck": true,
"noImplicitAny": false,
"strict": false,
"jsx": "react-jsx",
"moduleResolution": "bundler",
"moduleResolution": "node",
"resolveJsonModule": true,
"esModuleInterop": true,
"types": ["@docusaurus/module-type-aliases"],
@@ -39,10 +23,9 @@
// Runtime resolution uses webpack alias pointing to actual source (see src/webpack.extend.ts)
// Using /ui path matches the established pattern used throughout the Superset codebase
"@apache-superset/core/components": ["./src/types/apache-superset-core"],
"@site/*": ["./*"],
"*": ["./src/*", "./node_modules/*"]
"*": ["src/*", "node_modules/*"]
}
},
"include": ["./src/**/*.ts", "./src/**/*.tsx", "./src/**/*.d.ts"],
"exclude": ["./node_modules", "../superset-frontend/**/*", "src/shims/**"]
"include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.d.ts"],
"exclude": ["node_modules", "../superset-frontend/**/*", "src/shims/**"]
}
+1559 -671
View File
File diff suppressed because it is too large Load Diff
+15 -28
View File
@@ -16,7 +16,7 @@
# under the License.
[build-system]
requires = ["setuptools>=84.0.0", "wheel"]
requires = ["setuptools>=40.9.0", "wheel"]
build-backend = "setuptools.build_meta"
[project]
@@ -44,7 +44,7 @@ dependencies = [
# without the ``base.txt`` lock file (#40962).
"cachetools>=7.1.7, <8",
"celery>=5.6.3, <6.0.0",
"click>=8.5.0",
"click>=8.4.2",
"click-option-group",
"colorama",
"flask-cors>=6.0.5, <7.0",
@@ -67,7 +67,7 @@ dependencies = [
"flask-sqlalchemy>=3.1.1, <4.0",
"flask-wtf>=1.3.0, <2.0",
"geopy",
"greenlet<=3.5.5, >=3.5.5",
"greenlet<=3.5.4, >=3.5.4",
"gunicorn>=26.0.0, <27; sys_platform != 'win32'",
"hashids>=1.3.1, <2",
# holidays>=0.45 required for security fix
@@ -83,7 +83,7 @@ dependencies = [
"marshmallow>=3.0, <5",
"marshmallow-union>=0.1.15.post1",
"msgpack>=1.2.0, <1.3",
"nh3>=0.3.7, <0.4",
"nh3>=0.3.5, <0.4",
"numpy>=1.23.5, <2.5",
"packaging",
# --------------------------
@@ -109,14 +109,11 @@ dependencies = [
"shillelagh[gsheetsapi]>=1.4.5, <2.0",
"sshtunnel>=0.4.0, <0.5",
"simplejson>=4.1.2",
"simplejson>=4.1.1",
"slack_sdk>=3.43.0, <4",
"sqlalchemy>=2.0.52, <2.1",
"sqlalchemy-continuum>=1.6.0, <2.0.0",
"sqlalchemy-utils>=0.42.1, <0.43", # expanding lowerbound to work with pydoris
# Dialect-specific gaps/bugs against this pin are worked around in
# superset/sql/dialects/ (e.g. starrocks.py); check there for anything
# that can be cleaned up when bumping
"sqlglot>=30.17.0, <31", # 30.16.0 adds Trino inline UDF IF/CASE routine statement parsing
# newer pandas needs 0.9+
"tabulate>=0.10.0, <1.0",
@@ -138,24 +135,14 @@ athena = ["pyathena[pandas]>=3.35.4, <4"]
# superset/db_engine_specs/aurora.py's known_incompatibilities metadata.
aurora-data-api = ["preset-sqlalchemy-aurora-data-api>=0.2.8,<0.3"]
bigquery = [
"pandas-gbq>=0.35.2",
"pandas-gbq>=0.35.1",
# 1.17.1 is likely the final release: googleapis/python-bigquery-sqlalchemy
# was archived 2026-05-16. Both 1.17.0 and 1.17.1 support SQLAlchemy 1.4/2.0.
"sqlalchemy-bigquery>=1.17.2",
"google-cloud-bigquery>=3.42.3",
]
clickhouse = ["clickhouse-connect>=1.7.2, <2.0"]
# The `cockroachdb` PyPI package (last released 2021) is abandoned and its
# SQLAlchemy dialect cannot even import under SQLAlchemy 2.0 (it references
# sqlalchemy.dialects.postgresql.psycopg2.PGCompiler_psycopg2, removed in
# 2.0). sqlalchemy-cockroachdb is the actively maintained replacement,
# already linked from CockroachDbEngineSpec.metadata's docs_url, and
# registers the same `cockroachdb` SQLAlchemy dialect entry point.
# sqlalchemy-cockroachdb depends only on SQLAlchemy itself, not on a DBAPI
# driver, so psycopg2-binary is pinned alongside it (matching the `postgres`
# extra) to keep this extra self-contained -- CockroachDB speaks the
# PostgreSQL wire protocol, so psycopg2 is what actually opens connections.
cockroachdb = ["sqlalchemy-cockroachdb>=2.0.0, <3", "psycopg2-binary==2.9.12"]
clickhouse = ["clickhouse-connect>=1.7.1, <2.0"]
cockroachdb = ["cockroachdb>=0.3.5, <0.4"]
crate = ["sqlalchemy-cratedb>=0.43.1, <1"]
# sqlalchemy-d1's only release (0.1.0, Nov 2025) pins sqlalchemy<2,>=1.4,
# explicitly excluding SQLAlchemy 2.0. See superset/db_engine_specs/d1.py's
@@ -199,11 +186,11 @@ excel = ["xlrd>=2.0.2, <2.1"]
excel-export = ["boto3"]
fastmcp = [
"fastmcp>=3.4.7,<4.0",
"mcp>=1.29.1,<3.0",
"mcp>=1.29.1,<2.0",
# tiktoken backs the response-size-guard token estimator. Without
# it, the middleware falls back to a coarser character-based
# heuristic that under-counts JSON-heavy MCP responses.
"tiktoken>=0.14.0,<1.0",
"tiktoken>=0.13.0,<1.0",
]
# sqlalchemy-firebird >=2.0.0 unconditionally requires SQLAlchemy 2.0 on
# Python >=3.8 (which covers Superset's >=3.11 floor), with no dual-compat
@@ -213,7 +200,7 @@ firebird = ["sqlalchemy-firebird>=2.2.0"]
firebolt = ["firebolt-sqlalchemy>=1.1.2, <2"]
gevent = ["gevent>=26.8.0"]
gsheets = ["shillelagh[gsheetsapi]>=1.4.5, <2"]
hana = ["hdbcli==2.29.27", "sqlalchemy_hana==3.0.3"]
hana = ["hdbcli==2.29.25", "sqlalchemy_hana==3.0.3"]
hive = [
"pyhive[hive_pure_sasl]>=0.7.0",
"tableschema",
@@ -249,7 +236,7 @@ pinot = ["pinotdb>=5.0.0, <10.0.0"]
playwright = ["playwright>=1.62.0, <2"]
postgres = ["psycopg2-binary==2.9.12"]
presto = ["pyhive[presto]>=0.6.5"]
trino = ["trino>=0.339.0"]
trino = ["trino>=0.338.0"]
prophet = ["prophet>=1.4.0, <2"]
# sqlalchemy-redshift cuts hard from SQLAlchemy 1.4-only (0.8.x) to 2.0-only
# (>=1.0.0) with no dual-compat release. Bumped now that Superset's own
@@ -263,7 +250,7 @@ risingwave = ["sqlalchemy-risingwave>=2.0.0"]
shillelagh = ["shillelagh[all]>=1.4.5, <2"]
singlestore = ["sqlalchemy-singlestoredb>=1.2.1, <2"]
snowflake = ["snowflake-sqlalchemy>=1.11.0, <2"]
sqlite = ["syntaqlite>=0.9.0,<0.10.0"]
sqlite = ["syntaqlite>=0.7.0,<0.8.0"]
spark = [
"pyhive[hive_pure_sasl]>=0.7",
"tableschema",
@@ -273,7 +260,7 @@ tdengine = [
"taospy>=2.8.10",
"taos-ws-py>=0.7.0"
]
teradata = ["teradatasql>=20.0.0.66"]
teradata = ["teradatasql>=20.0.0.65"]
thumbnails = [] # deprecated, will be removed in 7.0
vertica = ["sqlalchemy-vertica-python>= 0.6.3, < 0.7"]
netezza = ["nzalchemy>= 11.1.2, < 11.2"]
@@ -307,7 +294,7 @@ development = [
"ruff",
"sqloxide",
"statsd",
"syntaqlite>=0.9.0,<0.10.0",
"syntaqlite>=0.7.0,<0.8.0",
]
[project.urls]
+2 -2
View File
@@ -52,11 +52,11 @@ marshmallow-sqlalchemy>=1.5.0
# needed for python 3.12 support
openapi-schema-validator>=0.6.3
# Pin setuptools <85 until all dependencies migrate from pkg_resources to importlib.metadata
# Pin setuptools <81 until all dependencies migrate from pkg_resources to importlib.metadata
# pkg_resources is deprecated and will be removed in setuptools 81+ (around 2025-11-30)
# Known affected packages: Preset's 'clients' package
# See docs/docs/contributing/pkg-resources-migration.md for details
setuptools<85
setuptools<81
# google-auth 2.53+ dropped its transitive dependency on cachetools, which is
# imported directly by superset.db_engine_specs.aws_iam. We declare cachetools
+8 -7
View File
@@ -58,7 +58,7 @@ cffi==2.0.0
# pynacl
charset-normalizer==3.4.2
# via requests
click==8.5.0
click==8.4.2
# via
# apache-superset (pyproject.toml)
# celery
@@ -163,16 +163,16 @@ google-auth==2.53.0
# via
# -r requirements/base.in
# shillelagh
greenlet==3.5.5
greenlet==3.5.4
# via
# apache-superset (pyproject.toml)
# shillelagh
# sqlalchemy
gunicorn==26.2.0
gunicorn==26.0.0
# via apache-superset (pyproject.toml)
hashids==1.3.1
# via apache-superset (pyproject.toml)
holidays==0.103
holidays==0.102
# via apache-superset (pyproject.toml)
humanize==4.12.3
# via apache-superset (pyproject.toml)
@@ -240,7 +240,7 @@ msgpack==1.2.1
# via apache-superset (pyproject.toml)
msgspec==0.19.0
# via flask-session
nh3==0.3.7
nh3==0.3.6
# via apache-superset (pyproject.toml)
numexpr==2.10.2
# via -r requirements/base.in
@@ -263,6 +263,7 @@ packaging==25.0
# apache-superset (pyproject.toml)
# apispec
# deprecation
# gunicorn
# kombu
# limits
# shillelagh
@@ -366,11 +367,11 @@ rpds-py==0.25.0
# via
# jsonschema
# referencing
setuptools==84.0.0
setuptools==80.9.0
# via -r requirements/base.in
shillelagh==1.4.5
# via apache-superset (pyproject.toml)
simplejson==4.1.2
simplejson==4.1.1
# via apache-superset (pyproject.toml)
six==1.17.0
# via
+1 -1
View File
@@ -16,5 +16,5 @@
# specific language governing permissions and limitations
# under the License.
#
-e .[development,bigquery,cockroachdb,druid,duckdb,fastmcp,gevent,gsheets,mysql,postgres,presto,prophet,trino,thumbnails]
-e .[development,bigquery,druid,duckdb,fastmcp,gevent,gsheets,mysql,postgres,presto,prophet,trino,thumbnails]
-e ./superset-extensions-cli[test]
+13 -15
View File
@@ -131,7 +131,7 @@ charset-normalizer==3.4.2
# via
# -c requirements/base-constraint.txt
# requests
click==8.5.0
click==8.4.2
# via
# -c requirements/base-constraint.txt
# apache-superset
@@ -375,7 +375,7 @@ googleapis-common-protos==1.66.0
# via
# google-api-core
# grpcio-status
greenlet==3.5.5
greenlet==3.5.4
# via
# -c requirements/base-constraint.txt
# apache-superset
@@ -391,7 +391,7 @@ grpcio==1.83.0
# grpcio-status
grpcio-status==1.60.1
# via google-api-core
gunicorn==26.2.0
gunicorn==26.0.0
# via
# -c requirements/base-constraint.txt
# apache-superset
@@ -403,7 +403,7 @@ hashids==1.3.1
# via
# -c requirements/base-constraint.txt
# apache-superset
holidays==0.103
holidays==0.102
# via
# -c requirements/base-constraint.txt
# apache-superset
@@ -569,7 +569,7 @@ msgspec==0.19.0
# flask-session
mysqlclient==2.2.8
# via apache-superset
nh3==0.3.7
nh3==0.3.6
# via
# -c requirements/base-constraint.txt
# apache-superset
@@ -624,6 +624,7 @@ packaging==25.0
# duckdb-engine
# fastmcp-slim
# google-cloud-bigquery
# gunicorn
# kombu
# limits
# matplotlib
@@ -639,7 +640,7 @@ pandas==2.3.3
# db-dtypes
# pandas-gbq
# prophet
pandas-gbq==0.35.2
pandas-gbq==0.35.1
# via apache-superset
parameterized==0.9.0
# via apache-superset
@@ -663,7 +664,7 @@ pillow==12.3.0
# -c requirements/base-constraint.txt
# apache-superset
# matplotlib
pip==26.2.1
pip==25.1.1
# via apache-superset
platformdirs==4.3.8
# via
@@ -920,7 +921,7 @@ secretstorage==3.5.0
# via keyring
semver==3.0.4
# via apache-superset-extensions-cli
setuptools==84.0.0
setuptools==80.9.0
# via
# -c requirements/base-constraint.txt
# nodeenv
@@ -932,7 +933,7 @@ shillelagh==1.4.5
# via
# -c requirements/base-constraint.txt
# apache-superset
simplejson==4.1.2
simplejson==4.1.1
# via
# -c requirements/base-constraint.txt
# apache-superset
@@ -961,13 +962,10 @@ sqlalchemy==2.0.52
# marshmallow-sqlalchemy
# shillelagh
# sqlalchemy-bigquery
# sqlalchemy-cockroachdb
# sqlalchemy-continuum
# sqlalchemy-utils
sqlalchemy-bigquery==1.17.2
# via apache-superset
sqlalchemy-cockroachdb==2.0.4
# via apache-superset
sqlalchemy-continuum==1.7.0
# via
# -c requirements/base-constraint.txt
@@ -997,13 +995,13 @@ starlette==1.3.1
# mcp
statsd==4.0.1
# via apache-superset
syntaqlite==0.9.0
syntaqlite==0.7.1
# via apache-superset
tabulate==0.10.0
# via
# -c requirements/base-constraint.txt
# apache-superset
tiktoken==0.14.0
tiktoken==0.13.0
# via apache-superset
tomli-w==1.2.0
# via apache-superset-extensions-cli
@@ -1013,7 +1011,7 @@ tqdm==4.67.1
# via
# cmdstanpy
# prophet
trino==0.339.0
trino==0.338.0
# via apache-superset
typing-extensions==4.16.0
# via
+3 -3
View File
@@ -289,11 +289,11 @@ function extractArgs(args, regexes) {
* For example: `superset-frontend/foo/bar.ts` -> `foo/bar.ts`
*
* @param {string[]} args
* @param {string} packageName
* @param {string} package
* @returns {string[]}
*/
function removePackageSegment(args, packageName) {
const packageSegment = packageName.concat(sep);
function removePackageSegment(args, package) {
const packageSegment = package.concat(sep);
return args.map((arg) => {
const normalizedPath = normalize(arg);
@@ -390,3 +390,19 @@ def get_session() -> scoped_session:
:returns: The SQLAlchemy scoped session instance.
"""
raise NotImplementedError("Function will be replaced during initialization")
__all__ = [
"Dataset",
"Database",
"Chart",
"Dashboard",
"User",
"Role",
"Group",
"Tag",
"KeyValue",
"Subject",
"CoreModel",
"get_session",
]
@@ -183,3 +183,10 @@ def prompt(
"MCP prompt decorator not initialized. "
"This decorator should be replaced during Superset startup."
)
__all__ = [
"tool",
"prompt",
"ToolAnnotations",
]
@@ -55,3 +55,9 @@ class SavedQueryDAO(BaseDAO[SavedQuery]):
model_cls = None
base_filter = None
id_column_name = "id"
__all__ = [
"QueryDAO",
"SavedQueryDAO",
]
@@ -71,3 +71,9 @@ class SavedQuery(CoreModel):
database_id: int | None
description: str | None
user_id: int | None
__all__ = [
"Query",
"SavedQuery",
]
@@ -46,3 +46,6 @@ def get_sqlglot_dialect(database: "Database") -> Dialects:
:returns: The SQLGlot dialect enum corresponding to the database.
"""
raise NotImplementedError("Function will be replaced during initialization")
__all__ = ["get_sqlglot_dialect"]
@@ -165,3 +165,13 @@ class AsyncQueryHandle:
:returns: True if cancellation was successful
"""
raise NotImplementedError("Method will be replaced during initialization")
__all__ = [
"QueryStatus",
"QueryOptions",
"QueryResult",
"StatementResult",
"AsyncQueryHandle",
"CacheOptions",
]
@@ -27,3 +27,6 @@ class RestApi(BaseApi):
"""
allow_browser_login = True
__all__ = ["RestApi"]
@@ -98,3 +98,6 @@ def api(
"API decorator not initialized. "
"This decorator should be replaced during Superset startup."
)
__all__ = ["api"]
@@ -164,3 +164,6 @@ class AbstractSemanticViewDAO(BaseDAO[SemanticViewModel]):
:return: SemanticViewModel instance or None
"""
...
__all__ = ["AbstractSemanticLayerDAO", "AbstractSemanticViewDAO"]
@@ -97,3 +97,6 @@ def semantic_layer(
"Semantic layer decorator not initialized. "
"This decorator should be replaced during Superset startup."
)
__all__ = ["semantic_layer"]
@@ -21,7 +21,6 @@ from abc import ABC, abstractmethod
from typing import Any, Generic, TypeVar
from pydantic import BaseModel
from superset_core.semantic_layers.view import SemanticView
ConfigT = TypeVar("ConfigT", bound=BaseModel)
@@ -80,3 +80,6 @@ class SemanticViewModel(CoreModel):
semantic_layer_uuid: UUID
created_on: datetime | None
changed_on: datetime | None
__all__ = ["SemanticLayerModel", "SemanticViewModel"]
@@ -146,8 +146,6 @@ class Operator(str, enum.Enum):
NOT_IN = "NOT IN"
LIKE = "LIKE"
NOT_LIKE = "NOT LIKE"
ILIKE = "ILIKE"
NOT_ILIKE = "NOT ILIKE"
IS_NULL = "IS NULL"
IS_NOT_NULL = "IS NOT NULL"
ADHOC = "ADHOC"
@@ -71,3 +71,6 @@ class TaskDAO(BaseDAO[Task]):
:returns: Task instance or None if not found or not active
"""
...
__all__ = ["TaskDAO"]
@@ -144,3 +144,9 @@ def get_context() -> TaskContext:
)
"""
raise NotImplementedError("Function will be replaced during initialization")
__all__ = [
"task",
"get_context",
]
@@ -161,3 +161,9 @@ class TaskSubscriber(CoreModel):
changed_on: datetime | None
created_by_fk: int | None
changed_by_fk: int | None
__all__ = [
"Task",
"TaskSubscriber",
]
@@ -226,3 +226,12 @@ class TaskContext(ABC):
cleanup_partial_work()
"""
...
__all__ = [
"TaskStatus",
"TaskScope",
"TaskProperties",
"TaskContext",
"TaskOptions",
]
-1
View File
@@ -1 +0,0 @@
../superset-frontend/.npmrc
+2261 -2108
View File
File diff suppressed because it is too large Load Diff
+10 -10
View File
@@ -37,18 +37,18 @@
"jwt-decode": "^4.0.0"
},
"devDependencies": {
"@babel/cli": "^8.0.1",
"@babel/core": "^8.0.1",
"@babel/preset-env": "^8.0.1",
"@babel/preset-typescript": "^8.0.1",
"@types/node": "^26.4.0",
"babel-loader": "^10.1.1",
"jsdom": "^30.0.1",
"@babel/cli": "^7.29.7",
"@babel/core": "^7.29.7",
"@babel/preset-env": "^7.29.7",
"@babel/preset-typescript": "7.29.7",
"@types/node": "^25.4.0",
"babel-loader": "^9.1.3",
"jsdom": "^26.1.0",
"tscw-config": "^1.1.2",
"typescript": "^7.0.2",
"typescript": "^5.9.3",
"vitest": "^4.0.18",
"webpack": "^5.110.0",
"webpack-cli": "^7.2.3"
"webpack": "^5.94.0",
"webpack-cli": "^5.1.4"
},
"repository": {
"type": "git",
-2
View File
@@ -1,7 +1,5 @@
{
"compilerOptions": {
"rootDir": "./src",
// syntax rules
"strict": true,
-1
View File
@@ -1 +0,0 @@
min-release-age=3
+151 -115
View File
@@ -2086,6 +2086,14 @@
"node": ">=8"
}
},
"node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
"integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
"dependencies": {
"sprintf-js": "~1.0.2"
}
},
"node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
@@ -2099,6 +2107,18 @@
"node": ">=8"
}
},
"node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": {
"version": "3.15.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.15.1.tgz",
"integrity": "sha512-S99WuO3HlhO3XN41EtYUNl9zzXjoJx7QvmipxsJVxtCBT0YHEFy+iOJhjSvrmV12nYhWpZaM8lPHkJm0yUMbag==",
"dependencies": {
"argparse": "^1.0.7",
"esprima": "^4.0.0"
},
"bin": {
"js-yaml": "bin/js-yaml.js"
}
},
"node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
@@ -3163,15 +3183,11 @@
]
},
"node_modules/baseline-browser-mapping": {
"version": "2.11.20",
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.20.tgz",
"integrity": "sha512-H0ulySigv6icDJ1F7SjtdCD6PrhTpdYCmP0CactWy1+ekh0AFd0o1Wn5T8b+hnTmdBx19u9yhL6wvCylXMY7zw==",
"license": "Apache-2.0",
"version": "2.9.19",
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.19.tgz",
"integrity": "sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==",
"bin": {
"baseline-browser-mapping": "dist/cli.cjs"
},
"engines": {
"node": ">=6.0.0"
"baseline-browser-mapping": "dist/cli.js"
}
},
"node_modules/bcrypt-pbkdf": {
@@ -3199,9 +3215,9 @@
"integrity": "sha512-Fc8Ne62jJlKHiG/ajlonC4Sd66Pq68fFwK4ihJGNZpGqboc324SQk+lRvMzpPRuJOmfrJefdG8/7JdWX4bzJ2Q=="
},
"node_modules/brace-expansion": {
"version": "5.0.9",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz",
"integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==",
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.8.tgz",
"integrity": "sha512-JZyDyq3D4AUifKTPOB7DELf6XsB3WdPuNxCtob1vFXPsSXhdAiHBWJ/tJ8HAc9aH84BK+5JFZLNkJKx3G9kzQg==",
"dev": true,
"license": "MIT",
"peer": true,
@@ -3213,9 +3229,9 @@
}
},
"node_modules/browserslist": {
"version": "4.28.8",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.8.tgz",
"integrity": "sha512-V2NpofLblG64mfOtSgDhOJESZEGogzDMBv/q+W6oc4LXWP/q75eOXoOaaOu1EOadB9U4Bwx/e0yzbvwKH8zalA==",
"version": "4.28.1",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz",
"integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==",
"funding": [
{
"type": "opencollective",
@@ -3230,13 +3246,12 @@
"url": "https://github.com/sponsors/ai"
}
],
"license": "MIT",
"dependencies": {
"baseline-browser-mapping": "^2.11.12",
"caniuse-lite": "^1.0.30001809",
"electron-to-chromium": "^1.5.402",
"node-releases": "^2.0.53",
"update-browserslist-db": "^1.3.0"
"baseline-browser-mapping": "^2.9.0",
"caniuse-lite": "^1.0.30001759",
"electron-to-chromium": "^1.5.263",
"node-releases": "^2.0.27",
"update-browserslist-db": "^1.2.0"
},
"bin": {
"browserslist": "cli.js"
@@ -3330,9 +3345,9 @@
}
},
"node_modules/caniuse-lite": {
"version": "1.0.30001810",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001810.tgz",
"integrity": "sha512-TITQPUkaz+aVk5GL6NhOdwk1aEaNTSDPsGFWrTuhKGtjTF70jL/Oht2W4c6rXUe5fu7Ie19VIahAXHIIiWWNeg==",
"version": "1.0.30001769",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001769.tgz",
"integrity": "sha512-BCfFL1sHijQlBGWBMuJyhZUhzo7wer5sVj9hqekB/7xn0Ypy+pER/edCYQm4exbXj4WiySGp40P8UuTh6w1srg==",
"funding": [
{
"type": "opencollective",
@@ -3346,8 +3361,7 @@
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"license": "CC-BY-4.0"
]
},
"node_modules/caseless": {
"version": "0.12.0",
@@ -3820,13 +3834,9 @@
}
},
"node_modules/d3-color": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz",
"integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==",
"license": "ISC",
"engines": {
"node": ">=12"
}
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/d3-color/-/d3-color-1.4.1.tgz",
"integrity": "sha512-p2sTHSLCJI2QKunbGb7ocOh7DgTAn8IrLx21QRc/BSnodXM4sv6aLQlnfpvehFMLZEfBc6g9pH9SWQccFYfJ9Q=="
},
"node_modules/d3-format": {
"version": "1.4.5",
@@ -4003,10 +4013,9 @@
}
},
"node_modules/electron-to-chromium": {
"version": "1.5.418",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.418.tgz",
"integrity": "sha512-UzS26r3AEbG5wSoGVpJKqwHIU9zwQN7LHdVIThDrJpS0I5KdlXFMEb8543fhc9dVnIIAST6ar8rhwa00AL5MlA==",
"license": "ISC"
"version": "1.5.286",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.286.tgz",
"integrity": "sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A=="
},
"node_modules/emoji-regex": {
"version": "8.0.0",
@@ -4115,7 +4124,6 @@
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
"integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
"license": "MIT",
"engines": {
"node": ">=6"
}
@@ -4309,6 +4317,18 @@
"url": "https://opencollective.com/eslint"
}
},
"node_modules/esprima": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
"bin": {
"esparse": "bin/esparse.js",
"esvalidate": "bin/esvalidate.js"
},
"engines": {
"node": ">=4"
}
},
"node_modules/esquery": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz",
@@ -4834,9 +4854,9 @@
"license": "MIT"
},
"node_modules/glob/node_modules/brace-expansion": {
"version": "1.1.18",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz",
"integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==",
"version": "1.1.16",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.16.tgz",
"integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==",
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0",
@@ -5566,19 +5586,9 @@
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
},
"node_modules/js-yaml": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.1.tgz",
"integrity": "sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/puzrin"
},
{
"type": "github",
"url": "https://github.com/sponsors/nodeca"
}
],
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
"integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
"license": "MIT",
"dependencies": {
"argparse": "^2.0.1"
@@ -6638,13 +6648,9 @@
}
},
"node_modules/node-releases": {
"version": "2.0.54",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.54.tgz",
"integrity": "sha512-YHs7BmmcsdAI5Ozuf8JZo6PT0mv2GIWC9vMfvUC3dp65M8hn7Ux8CPL+2oBI7juNuj9d0ndhTcznq2ODBps9cQ==",
"license": "MIT",
"engines": {
"node": ">=18"
}
"version": "2.0.27",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz",
"integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA=="
},
"node_modules/npm-run-path": {
"version": "4.0.1",
@@ -7842,6 +7848,11 @@
"node": ">=8"
}
},
"node_modules/sprintf-js": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
"integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g=="
},
"node_modules/sshpk": {
"version": "1.18.0",
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz",
@@ -8004,9 +8015,9 @@
"license": "MIT"
},
"node_modules/test-exclude/node_modules/brace-expansion": {
"version": "1.1.18",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz",
"integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==",
"version": "1.1.16",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.16.tgz",
"integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==",
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0",
@@ -8356,9 +8367,9 @@
}
},
"node_modules/update-browserslist-db": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.3.2.tgz",
"integrity": "sha512-UQ+MSxlhRm1bzjhU+DcuXfjFO1FzNtqhK5+9Yvlp90ItDLk5vT932A0rFu619nf7RVS+Y/VeaUW1jaRDqZ8VJw==",
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz",
"integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==",
"funding": [
{
"type": "opencollective",
@@ -8373,7 +8384,6 @@
"url": "https://github.com/sponsors/ai"
}
],
"license": "MIT",
"dependencies": {
"escalade": "^3.2.0",
"picocolors": "^1.1.1"
@@ -9832,7 +9842,7 @@
"debug": "4.4.0",
"execa": "4.1.0",
"istanbul-lib-coverage": "^3.0.0",
"js-yaml": "4.3.1",
"js-yaml": "4.1.1",
"nyc": "15.1.0",
"tinyglobby": "^0.2.14"
},
@@ -10111,7 +10121,7 @@
"requires": {
"@eslint/object-schema": "^3.0.5",
"debug": "^4.3.1",
"minimatch": ">=10"
"minimatch": "^10.2.4"
}
},
"@eslint/config-helpers": {
@@ -10203,10 +10213,18 @@
"camelcase": "^5.3.1",
"find-up": "^4.1.0",
"get-package-type": "^0.1.0",
"js-yaml": "4.3.1",
"js-yaml": "4.1.1",
"resolve-from": "^5.0.0"
},
"dependencies": {
"argparse": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
"integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
"requires": {
"sprintf-js": "~1.0.2"
}
},
"find-up": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
@@ -10216,6 +10234,14 @@
"path-exists": "^4.0.0"
}
},
"js-yaml": {
"version": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.15.1.tgz",
"integrity": "sha512-S99WuO3HlhO3XN41EtYUNl9zzXjoJx7QvmipxsJVxtCBT0YHEFy+iOJhjSvrmV12nYhWpZaM8lPHkJm0yUMbag==",
"requires": {
"argparse": "^1.0.7",
"esprima": "^4.0.0"
}
},
"locate-path": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
@@ -11131,9 +11157,9 @@
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="
},
"baseline-browser-mapping": {
"version": "2.11.20",
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.20.tgz",
"integrity": "sha512-H0ulySigv6icDJ1F7SjtdCD6PrhTpdYCmP0CactWy1+ekh0AFd0o1Wn5T8b+hnTmdBx19u9yhL6wvCylXMY7zw=="
"version": "2.9.19",
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.19.tgz",
"integrity": "sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg=="
},
"bcrypt-pbkdf": {
"version": "1.0.2",
@@ -11159,9 +11185,9 @@
"integrity": "sha512-Fc8Ne62jJlKHiG/ajlonC4Sd66Pq68fFwK4ihJGNZpGqboc324SQk+lRvMzpPRuJOmfrJefdG8/7JdWX4bzJ2Q=="
},
"brace-expansion": {
"version": "5.0.9",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz",
"integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==",
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.8.tgz",
"integrity": "sha512-JZyDyq3D4AUifKTPOB7DELf6XsB3WdPuNxCtob1vFXPsSXhdAiHBWJ/tJ8HAc9aH84BK+5JFZLNkJKx3G9kzQg==",
"dev": true,
"peer": true,
"requires": {
@@ -11169,15 +11195,15 @@
}
},
"browserslist": {
"version": "4.28.8",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.8.tgz",
"integrity": "sha512-V2NpofLblG64mfOtSgDhOJESZEGogzDMBv/q+W6oc4LXWP/q75eOXoOaaOu1EOadB9U4Bwx/e0yzbvwKH8zalA==",
"version": "4.28.1",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz",
"integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==",
"requires": {
"baseline-browser-mapping": "^2.11.12",
"caniuse-lite": "^1.0.30001809",
"electron-to-chromium": "^1.5.402",
"node-releases": "^2.0.53",
"update-browserslist-db": "^1.3.0"
"baseline-browser-mapping": "^2.9.0",
"caniuse-lite": "^1.0.30001759",
"electron-to-chromium": "^1.5.263",
"node-releases": "^2.0.27",
"update-browserslist-db": "^1.2.0"
}
},
"buffer-crc32": {
@@ -11237,9 +11263,9 @@
"integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="
},
"caniuse-lite": {
"version": "1.0.30001810",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001810.tgz",
"integrity": "sha512-TITQPUkaz+aVk5GL6NhOdwk1aEaNTSDPsGFWrTuhKGtjTF70jL/Oht2W4c6rXUe5fu7Ie19VIahAXHIIiWWNeg=="
"version": "1.0.30001769",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001769.tgz",
"integrity": "sha512-BCfFL1sHijQlBGWBMuJyhZUhzo7wer5sVj9hqekB/7xn0Ypy+pER/edCYQm4exbXj4WiySGp40P8UuTh6w1srg=="
},
"caseless": {
"version": "0.12.0",
@@ -11604,9 +11630,9 @@
}
},
"d3-color": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz",
"integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA=="
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/d3-color/-/d3-color-1.4.1.tgz",
"integrity": "sha512-p2sTHSLCJI2QKunbGb7ocOh7DgTAn8IrLx21QRc/BSnodXM4sv6aLQlnfpvehFMLZEfBc6g9pH9SWQccFYfJ9Q=="
},
"d3-format": {
"version": "1.4.5",
@@ -11618,7 +11644,7 @@
"resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-1.4.0.tgz",
"integrity": "sha512-V9znK0zc3jOPV4VD2zZn0sDhZU3WAE2bmlxdIwwQPPzPjvyLkd8B3JUVdS1IDUFDkWZ72c9qnv1GK2ZagTZ8EA==",
"requires": {
"d3-color": "3.1.0"
"d3-color": "1"
}
},
"d3-scale": {
@@ -11738,9 +11764,9 @@
}
},
"electron-to-chromium": {
"version": "1.5.418",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.418.tgz",
"integrity": "sha512-UzS26r3AEbG5wSoGVpJKqwHIU9zwQN7LHdVIThDrJpS0I5KdlXFMEb8543fhc9dVnIIAST6ar8rhwa00AL5MlA=="
"version": "1.5.286",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.286.tgz",
"integrity": "sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A=="
},
"emoji-regex": {
"version": "8.0.0",
@@ -11866,7 +11892,7 @@
"imurmurhash": "^0.1.4",
"is-glob": "^4.0.0",
"json-stable-stringify-without-jsonify": "^1.0.1",
"minimatch": ">=10",
"minimatch": "^10.2.4",
"natural-compare": "^1.4.0",
"optionator": "^0.9.3"
},
@@ -11955,6 +11981,11 @@
"eslint-visitor-keys": "^5.0.1"
}
},
"esprima": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
},
"esquery": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz",
@@ -12303,7 +12334,7 @@
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "<10",
"minimatch": "^3.1.1",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
},
@@ -12314,9 +12345,9 @@
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
},
"brace-expansion": {
"version": "1.1.18",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz",
"integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==",
"version": "1.1.16",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.16.tgz",
"integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==",
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@@ -12327,7 +12358,7 @@
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
"integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
"requires": {
"brace-expansion": "1.1.18"
"brace-expansion": "^1.1.7"
}
}
}
@@ -12821,9 +12852,9 @@
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
},
"js-yaml": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.1.tgz",
"integrity": "sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==",
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
"integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
"requires": {
"argparse": "^2.0.1"
}
@@ -13404,7 +13435,7 @@
"dev": true,
"peer": true,
"requires": {
"brace-expansion": ">=5.0.9"
"brace-expansion": "^5.0.5"
}
},
"minimist": {
@@ -13483,9 +13514,9 @@
}
},
"node-releases": {
"version": "2.0.54",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.54.tgz",
"integrity": "sha512-YHs7BmmcsdAI5Ozuf8JZo6PT0mv2GIWC9vMfvUC3dp65M8hn7Ux8CPL+2oBI7juNuj9d0ndhTcznq2ODBps9cQ=="
"version": "2.0.27",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz",
"integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA=="
},
"npm-run-path": {
"version": "4.0.1",
@@ -14352,6 +14383,11 @@
"which": "^2.0.1"
}
},
"sprintf-js": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
"integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g=="
},
"sshpk": {
"version": "1.18.0",
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz",
@@ -14458,7 +14494,7 @@
"requires": {
"@istanbuljs/schema": "^0.1.2",
"glob": "^7.1.4",
"minimatch": "<10"
"minimatch": "^3.0.4"
},
"dependencies": {
"balanced-match": {
@@ -14467,9 +14503,9 @@
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
},
"brace-expansion": {
"version": "1.1.18",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz",
"integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==",
"version": "1.1.16",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.16.tgz",
"integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==",
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@@ -14480,7 +14516,7 @@
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
"integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
"requires": {
"brace-expansion": "1.1.18"
"brace-expansion": "^1.1.7"
}
}
}
@@ -14712,9 +14748,9 @@
"integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw=="
},
"update-browserslist-db": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.3.2.tgz",
"integrity": "sha512-UQ+MSxlhRm1bzjhU+DcuXfjFO1FzNtqhK5+9Yvlp90ItDLk5vT932A0rFu619nf7RVS+Y/VeaUW1jaRDqZ8VJw==",
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz",
"integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==",
"requires": {
"escalade": "^3.2.0",
"picocolors": "^1.1.1"
+2 -8
View File
@@ -30,20 +30,14 @@
"overrides": {
"@babel/core": "^7.29.6",
"@cypress/code-coverage": {
"js-yaml": "4.3.1"
"js-yaml": "4.1.1"
},
"@cypress/request": "^3.0.0",
"cypress": {
"form-data": "^2.3.4"
},
"d3-interpolate": {
"d3-color": "3.1.0"
},
"minimatch@<10": {
"brace-expansion": "1.1.18"
},
"minimatch@>=10": {
"brace-expansion": ">=5.0.9"
"brace-expansion": ">=5.0.8"
},
"qs": "^6.14.2",
"uuid": "^11.1.1"
@@ -1,5 +1,5 @@
{
"name": "@superset-ui/eslint-plugin-i18n-strings",
"name": "eslint-plugin-i18n-strings",
"version": "1.0.0",
"description": "Warns about translation variables",
"keywords": [],
@@ -1,5 +1,5 @@
{
"name": "@superset-ui/eslint-plugin-icons",
"name": "eslint-plugin-icons",
"version": "1.0.0",
"description": "Warns about direct usage of Ant Design icons",
"keywords": [],
@@ -1,5 +1,5 @@
{
"name": "@superset-ui/eslint-plugin-theme-colors",
"name": "eslint-plugin-theme-colors",
"version": "1.0.0",
"description": "Warns about rgb(a)/hex/literal colors",
"keywords": [],
+3 -3
View File
@@ -37,9 +37,9 @@
require('tsx/cjs');
const tsParser = require('@typescript-eslint/parser');
const themeColorsPlugin = require('@superset-ui/eslint-plugin-theme-colors');
const iconsPlugin = require('@superset-ui/eslint-plugin-icons');
const i18nStringsPlugin = require('@superset-ui/eslint-plugin-i18n-strings');
const themeColorsPlugin = require('eslint-plugin-theme-colors');
const iconsPlugin = require('eslint-plugin-icons');
const i18nStringsPlugin = require('eslint-plugin-i18n-strings');
module.exports = [
// Files this config applies to. Flat config has no `--ext`; globs live here.
+10 -15
View File
@@ -18,19 +18,6 @@
*/
// timezone for unit tests
process.env.TZ = 'America/New_York';
const reporters = ['default'];
// HTML reporter is not used on CI so skipping its generation for saving time
if (!process.env.CI) {
reporters.push([
'./node_modules/jest-html-reporter',
{
pageTitle: 'Test Report',
},
]);
}
module.exports = {
// [/\\] matches both path separators so the suite also collects on
// native Windows, where jest hands the regex backslash-separated paths.
@@ -90,7 +77,7 @@ module.exports = {
// @ant-design/colors and @ant-design/fast-color are allowed through because
// @ant-design/icons >= 6.3 deep-imports the ESM build of @ant-design/colors
// from its CJS output, so babel-jest must transform those files.
'node_modules/(?!@ant-design/(colors|fast-color)|@formatjs/.*|d3-(array|interpolate|color|time|scale|time-format|format|selection)|internmap|@mapbox/tiny-sdf|remark-gfm|(?!@ngrx|(?!deck.gl)|d3-scale)|markdown-table|micromark-*.|decode-named-character-reference|character-entities|mdast-util-*.|unist-util-*.|ccount|escape-string-regexp|nanoid|uuid|@rjsf/*.|@x0k/.*|echarts|zrender|fetch-mock|pretty-ms|parse-ms|ol|@babel/runtime|@emotion|cheerio|cheerio/lib|parse5|dom-serializer|entities|htmlparser2|rehype-sanitize|hast-util-sanitize|unified|unist-.*|hast-.*|hastscript|refractor|rehype-.*|remark-.*|mdast-.*|micromark-.*|parse-entities|character-reference-invalid|is-alphanumerical|is-alphabetical|is-decimal|is-hexadecimal|property-information|space-separated-tokens|comma-separated-tokens|bail|devlop|zwitch|longest-streak|geostyler|geostyler-.*|(?!geostyler)lodash|react-error-boundary|react-json-tree|react-base16-styling|lodash-es|rbush|quickselect|react-diff-viewer-continued|storybook/*.|json-stringify-pretty-compact|@x0k/json-schema-merge|content-disposition)',
'node_modules/(?!@ant-design/(colors|fast-color)|@formatjs/.*|d3-(array|interpolate|color|time|scale|time-format|format|selection)|internmap|@mapbox/tiny-sdf|remark-gfm|(?!@ngrx|(?!deck.gl)|d3-scale)|markdown-table|micromark-*.|decode-named-character-reference|character-entities|mdast-util-*.|unist-util-*.|ccount|escape-string-regexp|nanoid|uuid|@rjsf/*.|@x0k/.*|echarts|zrender|fetch-mock|pretty-ms|parse-ms|ol|@babel/runtime|@emotion|cheerio|cheerio/lib|parse5|dom-serializer|entities|htmlparser2|rehype-sanitize|hast-util-sanitize|unified|unist-.*|hast-.*|hastscript|refractor|rehype-.*|remark-.*|mdast-.*|micromark-.*|parse-entities|character-reference-invalid|is-alphanumerical|is-alphabetical|is-decimal|is-hexadecimal|property-information|space-separated-tokens|comma-separated-tokens|bail|devlop|zwitch|longest-streak|geostyler|geostyler-.*|(?!geostyler)lodash|react-error-boundary|react-json-tree|react-base16-styling|lodash-es|rbush|quickselect|react-diff-viewer-continued|storybook/*.|json-stringify-pretty-compact|@x0k/json-schema-merge)',
],
preset: 'ts-jest',
transform: {
@@ -101,6 +88,14 @@ module.exports = {
__DEV__: true,
caches: true,
},
reporters: reporters,
reporters: [
'default',
[
'./node_modules/jest-html-reporter',
{
pageTitle: 'Test Report',
},
],
],
testTimeout: 20000,
};
+1 -1
View File
@@ -113,7 +113,7 @@
// === Import plugin rules ===
"import/named": "error",
"import/export": "error",
"import/no-named-as-default": "warn",
"import/no-named-as-default": "error",
"import/no-named-as-default-member": "error",
"import/no-mutable-exports": "error",
"import/no-amd": "error",
+1340 -2239
View File
File diff suppressed because it is too large Load Diff
+35 -47
View File
@@ -79,7 +79,7 @@
"playwright:report": "playwright show-report",
"docs:screenshots": "playwright test --config=playwright/generators/playwright.config.ts docs/",
"prod": "npm run build",
"prune": "rm -rf ./{packages,plugins}/*/{node_modules,lib,esm,tsconfig.tsbuildinfo,package-lock.json} ./.temp_cache ./coverage ./storybook-static",
"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\" \"python3 -m http.server 6006 --directory storybook-static\" \"npx wait-on tcp:127.0.0.1:6006 && npm run test-storybook -- --maxWorkers=2\"",
@@ -146,6 +146,7 @@
"@superset-ui/plugin-chart-world-map": "file:./plugins/plugin-chart-world-map",
"@superset-ui/preset-chart-deckgl": "file:./plugins/preset-chart-deckgl",
"@superset-ui/switchboard": "file:./packages/superset-ui-switchboard",
"@types/d3-format": "^3.0.1",
"@types/d3-selection": "^3.0.11",
"@types/d3-time-format": "^4.0.3",
"@types/react-google-recaptcha": "^2.1.9",
@@ -157,10 +158,10 @@
"@visx/xychart": "^4.0.0",
"ag-grid-community": "36.1.0",
"ag-grid-react": "36.1.0",
"antd": "^6.6.2",
"antd": "^6.6.1",
"chrono-node": "^2.10.1",
"classnames": "^2.2.5",
"content-disposition": "^3.0.0",
"content-disposition": "^2.0.1",
"d3-scale": "^4.0.2",
"dayjs": "^1.11.23",
"dom-to-image-more": "^3.10.2",
@@ -184,7 +185,7 @@
"json-stringify-pretty-compact": "^4.0.0",
"lodash": "^4.18.1",
"lodash-es": "^4.18.1",
"mapbox-gl": "^3.29.0",
"mapbox-gl": "^3.28.1",
"markdown-to-jsx": "^9.10.2",
"match-sorter": "^8.3.0",
"memoize-one": "^6.0.0",
@@ -192,7 +193,6 @@
"mustache": "^4.2.0",
"nanoid": "^6.0.1",
"ol": "^10.10.0",
"postcss": "^8.5.26",
"query-string": "9.5.0",
"re-resizable": "^6.11.2",
"react": "^18.3.0",
@@ -203,7 +203,7 @@
"react-dnd-html5-backend": "^11.1.3",
"react-dom": "^18.3.0",
"react-google-recaptcha": "^3.1.0",
"react-intersection-observer": "^11.0.1",
"react-intersection-observer": "^11.0.0",
"react-json-tree": "^0.20.0",
"react-lines-ellipsis": "^0.16.1",
"react-loadable": "^5.5.0",
@@ -256,21 +256,18 @@
"@formatjs/intl-durationformat": "^0.10.18",
"@istanbuljs/nyc-config-typescript": "^1.0.1",
"@playwright/test": "^1.62.1",
"@pmmmwh/react-refresh-webpack-plugin": "^0.6.3",
"@storybook/addon-docs": "10.5.10",
"@storybook/addon-links": "10.5.10",
"@storybook/react-webpack5": "10.5.10",
"@pmmmwh/react-refresh-webpack-plugin": "^0.6.2",
"@storybook/addon-docs": "10.5.9",
"@storybook/addon-links": "10.5.9",
"@storybook/react-webpack5": "10.5.9",
"@storybook/test-runner": "0.24.4",
"@superset-ui/eslint-plugin-i18n-strings": "file:eslint-rules/eslint-plugin-i18n-strings",
"@superset-ui/eslint-plugin-icons": "file:eslint-rules/eslint-plugin-icons",
"@superset-ui/eslint-plugin-theme-colors": "file:eslint-rules/eslint-plugin-theme-colors",
"@svgr/webpack": "^8.1.0",
"@swc/core": "^1.16.1",
"@swc/plugin-emotion": "^15.0.0",
"@swc/plugin-transform-imports": "^13.0.0",
"@testing-library/dom": "^10.4.1",
"@testing-library/jest-dom": "^7.0.1",
"@testing-library/react": "^16.3.3",
"@testing-library/react": "^15.0.0",
"@testing-library/user-event": "^12.8.3",
"@types/content-disposition": "^0.5.9",
"@types/dom-to-image": "^2.6.7",
@@ -280,7 +277,7 @@
"@types/json-bigint": "^1.0.4",
"@types/lodash-es": "^4.17.12",
"@types/mousetrap": "^1.6.15",
"@types/node": "^26.4.0",
"@types/node": "^26.2.0",
"@types/react": "^18.3.0",
"@types/react-dom": "^18.3.0",
"@types/react-loadable": "^5.5.11",
@@ -292,36 +289,39 @@
"@types/rison": "0.1.0",
"@types/tinycolor2": "^1.4.3",
"@types/unzipper": "^0.10.11",
"@typescript-eslint/eslint-plugin": "^8.68.0",
"@typescript-eslint/eslint-plugin": "^8.67.0",
"@typescript-eslint/parser": "^8.63.0",
"babel-jest": "^30.5.0",
"babel-jest": "^30.4.1",
"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.11.20",
"baseline-browser-mapping": "^2.11.15",
"cheerio": "1.2.0",
"concurrently": "^10.0.5",
"copy-webpack-plugin": "^14.0.0",
"cross-env": "^10.1.0",
"css-loader": "^7.1.5",
"eslint": "^10.9.1",
"css-loader": "^7.1.4",
"eslint": "^10.8.1",
"eslint-import-resolver-alias": "^1.1.2",
"eslint-import-resolver-typescript": "^4.4.5",
"eslint-plugin-i18n-strings": "file:eslint-rules/eslint-plugin-i18n-strings",
"eslint-plugin-icons": "file:eslint-rules/eslint-plugin-icons",
"eslint-plugin-import": "^2.32.0",
"eslint-plugin-jest-dom": "^5.10.1",
"eslint-plugin-lodash": "^8.0.0",
"eslint-plugin-no-only-tests": "^3.4.0",
"eslint-plugin-react-prefer-function-component": "^5.0.0",
"eslint-plugin-react-you-might-not-need-an-effect": "^1.0.2",
"eslint-plugin-storybook": "10.5.10",
"eslint-plugin-react-you-might-not-need-an-effect": "^1.0.1",
"eslint-plugin-storybook": "10.5.9",
"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.8",
"imports-loader": "^5.0.0",
"jest": "^30.4.2",
"jest-environment-jsdom": "^30.5.0",
"jest-environment-jsdom": "^30.4.1",
"jest-html-reporter": "^4.4.0",
"jest-websocket-mock": "^2.5.0",
"js-yaml-loader": "^1.2.2",
@@ -329,10 +329,10 @@
"lerna": "^10.0.1",
"lightningcss": "^1.33.0",
"mini-css-extract-plugin": "^2.10.2",
"minimizer-webpack-plugin": "^5.8.0",
"minimizer-webpack-plugin": "^5.6.1",
"open-cli": "^9.0.0",
"oxfmt": "^0.65.0",
"oxlint": "^1.80.0",
"oxfmt": "^0.64.0",
"oxlint": "^1.79.0",
"po2json": "^0.4.5",
"postcss-styled-syntax": "^0.7.2",
"process": "^0.11.10",
@@ -343,7 +343,7 @@
"source-map": "^0.8.0",
"source-map-support": "^0.5.21",
"speed-measure-webpack-plugin": "^1.6.0",
"storybook": "10.5.10",
"storybook": "10.5.9",
"style-loader": "^4.0.0",
"stylelint": "^17.14.1",
"swc-loader": "^0.2.7",
@@ -353,10 +353,10 @@
"typescript": "5.4.5",
"unzipper": "^0.12.5",
"wait-on": "^9.1.0",
"webpack": "^5.110.1",
"webpack-bundle-analyzer": "^5.3.2",
"webpack-cli": "^7.2.3",
"webpack-dev-server": "^6.0.0",
"webpack": "^5.109.2",
"webpack-bundle-analyzer": "^5.3.1",
"webpack-cli": "^7.0.3",
"webpack-dev-server": "^5.2.5",
"webpack-manifest-plugin": "^6.0.1",
"webpack-sources": "^3.5.1",
"webpack-visualizer-plugin2": "^2.0.0"
@@ -383,9 +383,6 @@
"@great-expectations/jsonforms-antd-renderers": {
"antd": "$antd"
},
"@istanbuljs/load-nyc-config": {
"js-yaml": "^3.15.1"
},
"@jest/globals": "^30.4.0",
"@jest/types": "^30.4.0",
"@luma.gl/constants": "~9.2.5",
@@ -395,10 +392,7 @@
"@luma.gl/shadertools": "~9.2.5",
"@luma.gl/webgl": "~9.2.5",
"core-js": "^3.38.1",
"cosmiconfig": {
"js-yaml": "^4.3.1"
},
"dompurify": "^3.4.13",
"dompurify": "^3.4.11",
"esbuild": "^0.28.1",
"eslint-plugin-import": {
"eslint": "$eslint"
@@ -406,7 +400,7 @@
"eslint-plugin-jest-dom": {
"eslint": "$eslint"
},
"fast-uri": "^3.1.7",
"fast-uri": "^3.1.5",
"fast-xml-parser": "^5.8.0",
"http-proxy-middleware": "^2.0.10",
"jest-circus": "^30.4.0",
@@ -414,22 +408,16 @@
"jest-mock": "^30.4.0",
"jest-runtime": "^30.4.0",
"jest-util": "^30.4.0",
"js-yaml-loader": {
"js-yaml": "^3.15.1"
},
"jspdf": "^4.2.0",
"lerna": {
"js-yaml": "^4.3.1"
"js-yaml": "^4.3.0"
},
"minimatch@>=10": {
"brace-expansion": ">=5.0.8"
},
"nanoid@>=3 <4": "3.3.18",
"nwsapi": "^2.2.24",
"nwsapi": "^2.2.13",
"puppeteer": "^22.4.1",
"react-diff-viewer-continued": {
"js-yaml": "^4.3.1"
},
"tar": "^7.5.16",
"typescript-json-schema": "^0.68.0",
"underscore": "^1.13.7",
@@ -33,7 +33,7 @@
"dependencies": {
"chalk": "^6.0.0",
"lodash-es": "^4.18.1",
"yeoman-generator": "^8.3.0",
"yeoman-generator": "^8.2.2",
"yosay": "^3.0.0"
},
"devDependencies": {
@@ -104,7 +104,7 @@
"@emotion/styled": "^11.14.1",
"@testing-library/dom": "^10.4.1",
"@testing-library/jest-dom": "*",
"@testing-library/react": "*",
"@testing-library/react": "^15.0.0",
"@testing-library/user-event": "*",
"@types/lodash": "^4.17.25",
"@types/react": "*",
@@ -550,12 +550,6 @@ export interface ThemeContextType {
canDetectOSPreference: () => boolean;
createDashboardThemeProvider: (themeId: string) => Promise<Theme | null>;
getAppliedThemeId: () => number | null;
/**
* Re-reads the persisted system default/dark themes from the server and
* re-applies them live, so changes made on the Themes admin page take effect
* without a full page reload.
*/
refreshSystemThemes: () => Promise<void>;
}
/**
@@ -39,7 +39,7 @@
"@superset-ui/core": "*",
"@testing-library/dom": "^10.4.1",
"@testing-library/jest-dom": "*",
"@testing-library/react": "*",
"@testing-library/react": "^15.0.0",
"@testing-library/user-event": "*",
"ace-builds": "^1.4.14",
"brace": "^0.11.1",
@@ -489,16 +489,6 @@ export const MultipleValueComparators = [
Comparator.BetweenOrRightEqual,
];
export enum BoundUnit {
Value = 'value',
Percent = 'percent',
}
export enum PercentDenominator {
Sum = 'sum',
Max = 'max',
}
export type ConditionalFormattingConfig = {
operator?: Comparator;
targetValue?: number | string;
@@ -511,14 +501,6 @@ export type ConditionalFormattingConfig = {
useGradient?: boolean;
columnFormatting?: string;
objectFormatting?: ObjectFormattingEnum;
minBound?: number;
maxBound?: number;
centerValue?: number;
lowColor?: RGBColor | string;
midColor?: RGBColor | string;
highColor?: RGBColor | string;
boundUnit?: BoundUnit;
percentDenominator?: PercentDenominator;
};
export type ColorFormatters = {
@@ -16,11 +16,10 @@
* specific language governing permissions and limitations
* under the License.
*/
import memoizeOne, { type MemoizedFn } from 'memoize-one';
import memoizeOne from 'memoize-one';
import { isString, isBoolean } from 'lodash-es';
import { isBlank } from '@apache-superset/core/utils';
import { addAlpha, DataRecord, rgbaToHex } from '@superset-ui/core';
import { type RGBColor } from '@superset-ui/core/components';
import tinycolor from 'tinycolor2';
import {
ColorFormatters,
@@ -29,8 +28,6 @@ import {
MultipleValueComparators,
ResolvedColorFormatterResult,
ColorSchemeEnum,
BoundUnit,
PercentDenominator,
} from '../types';
export const round = (num: number, precision = 0) =>
@@ -75,58 +72,6 @@ export const getOpacity = (
);
};
const parseColorToRgb = (color: RGBColor | string) => {
if (typeof color === 'string') {
const { r, g, b } = tinycolor(color).toRgb();
return { r, g, b };
}
return { r: color.r, g: color.g, b: color.b };
};
export const getDivergingColor = (
value: number,
cutoffValue: number,
centerValue: number,
extremeValue: number,
lowColor: RGBColor | string,
midColor: RGBColor | string,
highColor: RGBColor | string,
): string => {
const clampedValue = Math.min(Math.max(value, cutoffValue), extremeValue);
const belowCenter = clampedValue <= centerValue;
const from = parseColorToRgb(belowCenter ? lowColor : midColor);
const to = parseColorToRgb(belowCenter ? midColor : highColor);
const rangeStart = belowCenter ? cutoffValue : centerValue;
const rangeEnd = belowCenter ? centerValue : extremeValue;
const ratio =
rangeEnd === rangeStart
? 1
: (clampedValue - rangeStart) / (rangeEnd - rangeStart);
return rgbaToHex({
r: from.r + (to.r - from.r) * ratio,
g: from.g + (to.g - from.g) * ratio,
b: from.b + (to.b - from.b) * ratio,
a: 1,
});
};
const isValidDivergingConfig = (
centerValue: number | undefined,
lowColor: RGBColor | string | undefined,
midColor: RGBColor | string | undefined,
highColor: RGBColor | string | undefined,
cutoffValue: number | string,
extremeValue: number | string,
): centerValue is number =>
centerValue !== undefined &&
lowColor !== undefined &&
midColor !== undefined &&
highColor !== undefined &&
typeof cutoffValue === 'number' &&
typeof extremeValue === 'number' &&
centerValue > cutoffValue &&
centerValue < extremeValue;
const isSpecialColor = (value: unknown): value is ColorSchemeEnum =>
Object.values(ColorSchemeEnum).includes(value as ColorSchemeEnum);
@@ -138,61 +83,17 @@ export const getColorFunction = (
targetValueRight,
colorScheme,
useGradient,
minBound: rawMinBound,
maxBound: rawMaxBound,
centerValue: rawCenterValue,
lowColor,
midColor,
highColor,
boundUnit,
percentDenominator,
}: ConditionalFormattingConfig,
columnValues: number[] | string[] | (boolean | null)[],
alpha?: boolean,
) => {
const resolvePercentBound = (bound: number | undefined) => {
if (boundUnit !== BoundUnit.Percent || bound === undefined) {
return bound;
}
const numericColumnValues = (
columnValues as (number | string | boolean | null)[]
).filter((value): value is number => typeof value === 'number');
if (numericColumnValues.length === 0) {
return undefined;
}
// Sum magnitudes independently so mixed signs do not cancel into an
// unstable denominator. A non-positive column maximum cannot produce
// ordered percentage bounds, so it falls back to the automatic range.
const denominatorValue =
percentDenominator === PercentDenominator.Sum
? numericColumnValues.reduce((sum, value) => sum + Math.abs(value), 0)
: numericColumnValues.reduce(
(max, value) => (value > max ? value : max),
-Infinity,
);
if (denominatorValue <= 0) {
return undefined;
}
return (bound / 100) * denominatorValue;
};
const minBound = resolvePercentBound(rawMinBound);
const maxBound = resolvePercentBound(rawMaxBound);
const centerValue = resolvePercentBound(rawCenterValue);
let minOpacity = MIN_OPACITY_BOUNDED;
const maxOpacity = MAX_OPACITY;
let comparatorFunction: (
value: number | string | boolean | null,
allValues: number[] | string[] | (boolean | null)[],
) =>
| false
| {
cutoffValue: number | string;
extremeValue: number | string;
opacityValue?: number;
};
) => false | { cutoffValue: number | string; extremeValue: number | string };
if (operator === undefined || colorScheme === undefined) {
return () => undefined;
}
@@ -216,19 +117,8 @@ export const getColorFunction = (
if (typeof value !== 'number') {
return { cutoffValue: value!, extremeValue: value! };
}
const cutoffValue = minBound ?? Math.min(...allValues);
const extremeValue = maxBound ?? Math.max(...allValues);
const hasManualBound = minBound !== undefined || maxBound !== undefined;
if (cutoffValue > extremeValue) {
return false;
}
if (hasManualBound) {
return {
cutoffValue,
extremeValue,
opacityValue: Math.min(Math.max(value, cutoffValue), extremeValue),
};
}
const cutoffValue = Math.min(...allValues);
const extremeValue = Math.max(...allValues);
return value >= cutoffValue && value <= extremeValue
? { cutoffValue, extremeValue }
: false;
@@ -239,10 +129,7 @@ export const getColorFunction = (
typeof targetValue === 'number' && value > targetValue!
? {
cutoffValue: targetValue!,
extremeValue:
maxBound !== undefined && maxBound > targetValue
? maxBound
: Math.max(...allValues),
extremeValue: Math.max(...allValues),
}
: false;
break;
@@ -251,10 +138,7 @@ export const getColorFunction = (
typeof targetValue === 'number' && value < targetValue!
? {
cutoffValue: targetValue!,
extremeValue:
minBound !== undefined && minBound < targetValue
? minBound
: Math.min(...allValues),
extremeValue: Math.min(...allValues),
}
: false;
break;
@@ -263,10 +147,7 @@ export const getColorFunction = (
typeof targetValue === 'number' && value >= targetValue!
? {
cutoffValue: targetValue!,
extremeValue:
maxBound !== undefined && maxBound > targetValue
? maxBound
: Math.max(...allValues),
extremeValue: Math.max(...allValues),
}
: false;
break;
@@ -275,10 +156,7 @@ export const getColorFunction = (
typeof targetValue === 'number' && value <= targetValue!
? {
cutoffValue: targetValue!,
extremeValue:
minBound !== undefined && minBound < targetValue
? minBound
: Math.min(...allValues),
extremeValue: Math.min(...allValues),
}
: false;
break;
@@ -394,32 +272,7 @@ export const getColorFunction = (
}
const compareResult = comparatorFunction(value, columnValues);
if (compareResult === false) return undefined;
const { cutoffValue, extremeValue, opacityValue } = compareResult;
const resolvedValue = opacityValue ?? value;
if (
useGradient !== false &&
operator === Comparator.None &&
typeof resolvedValue === 'number' &&
isValidDivergingConfig(
centerValue,
lowColor,
midColor,
highColor,
cutoffValue,
extremeValue,
)
) {
return getDivergingColor(
resolvedValue,
cutoffValue as number,
centerValue,
extremeValue as number,
lowColor!,
midColor!,
highColor!,
);
}
const { cutoffValue, extremeValue } = compareResult;
if (typeof colorScheme === 'string') {
if (isSpecialColor(colorScheme)) {
@@ -444,13 +297,7 @@ export const getColorFunction = (
if (alpha === undefined || alpha) {
return addAlpha(
cleanHex,
getOpacity(
opacityValue ?? value,
cutoffValue,
extremeValue,
minOpacity,
maxOpacity,
),
getOpacity(value, cutoffValue, extremeValue, minOpacity, maxOpacity),
);
}
return colorScheme;
@@ -468,47 +315,22 @@ export const getColorFunction = (
if (alpha === undefined || alpha) {
return addAlpha(
baseHexColor,
getOpacity(
opacityValue ?? value,
cutoffValue,
extremeValue,
minOpacity,
maxOpacity,
),
getOpacity(value, cutoffValue, extremeValue, minOpacity, maxOpacity),
);
}
return baseHexColor;
};
};
type GetColorFormatters = (
columnConfig: ConditionalFormattingConfig[] | undefined,
data: DataRecord[],
theme?: Record<string, any>,
alpha?: boolean,
disablePercentBounds?: boolean,
) => ColorFormatters;
export const getColorFormatters: MemoizedFn<GetColorFormatters> = memoizeOne(
export const getColorFormatters = memoizeOne(
(
columnConfig: ConditionalFormattingConfig[] | undefined,
data: DataRecord[],
theme?: Record<string, any>,
alpha?: boolean,
disablePercentBounds = false,
) =>
columnConfig?.reduce(
(acc: ColorFormatters, config: ConditionalFormattingConfig) => {
const colorFunctionConfig =
disablePercentBounds && config.boundUnit === BoundUnit.Percent
? {
...config,
boundUnit: BoundUnit.Value,
minBound: undefined,
maxBound: undefined,
centerValue: undefined,
}
: config;
let resolvedColorScheme = config.colorScheme;
if (
theme &&
@@ -535,7 +357,7 @@ export const getColorFormatters: MemoizedFn<GetColorFormatters> = memoizeOne(
columnFormatting: config?.columnFormatting,
objectFormatting: config?.objectFormatting,
getColorFromValue: getColorFunction(
{ ...colorFunctionConfig, colorScheme: resolvedColorScheme },
{ ...config, colorScheme: resolvedColorScheme },
data.map(row => row[config.column!] as number),
alpha,
),
@@ -21,13 +21,10 @@ import {
Comparator,
getOpacity,
round,
getColorFormatters,
getColorFunction,
getDivergingColor,
BoundUnit,
PercentDenominator,
} from '../../src';
import {
getColorFormatters,
getReadableTextColor,
getNormalizedTextColor,
getTextColorForBackground,
@@ -87,18 +84,6 @@ test('getOpacity', () => {
expect(getOpacity(50, 75, NaN)).toEqual(1);
});
test('getDivergingColor parses string color endpoints', () => {
expect(
getDivergingColor(25, 0, 50, 100, '#ff0000', '#ffffff', '#008000'),
).toEqual('#ff8080');
});
test('getDivergingColor returns the segment endpoint outright when its range has zero width', () => {
expect(
getDivergingColor(10, 10, 10, 20, '#ff0000', '#ffffff', '#008000'),
).toEqual('#ffffff');
});
test('getColorFunction GREATER_THAN', () => {
const colorFunction = getColorFunction(
{
@@ -750,38 +735,6 @@ test('correct column config', () => {
expect(colorFormatters[2].getColorFromValue(100)).toEqual('#FF000087');
});
test('getColorFormatters falls back to automatic bounds for saved percentage rules when requested', () => {
const colorFormatters = getColorFormatters(
[
{
operator: Comparator.None,
colorScheme: '#FF0000',
column: 'count',
useGradient: true,
boundUnit: BoundUnit.Percent,
minBound: 0,
maxBound: 200,
},
{
operator: Comparator.None,
colorScheme: '#00FF00',
column: 'sum',
boundUnit: BoundUnit.Value,
},
],
mockData,
undefined,
undefined,
true,
);
expect(colorFormatters).toHaveLength(2);
expect(colorFormatters[0].column).toBe('count');
expect(colorFormatters[0].getColorFromValue(50)).toEqual('#FF000000');
expect(colorFormatters[0].getColorFromValue(100)).toEqual('#FF0000FF');
expect(colorFormatters[1].column).toBe('sum');
});
test('undefined column config', () => {
const colorFormatters = getColorFormatters(undefined, mockData);
expect(colorFormatters.length).toEqual(0);
@@ -1163,410 +1116,3 @@ test('should strip alpha channel when alpha is false and colorScheme has 9 chars
expect(colorFunction(100)).toEqual('#FF0000');
expect(colorFunction(100)).toHaveLength(7);
});
test('should discard the fixed alpha of a 9-char colorScheme before applying gradient opacity', () => {
const colorFunction = getColorFunction(
{
operator: Comparator.GreaterThan,
targetValue: 50,
colorScheme: '#FF000080',
useGradient: true,
column: 'count',
},
countValues,
);
expect(colorFunction(75)).toEqual('#FF000087');
});
test('getColorFunction GREATER_THAN respects manual maxBound', () => {
const colorFunction = getColorFunction(
{
operator: Comparator.GreaterThan,
targetValue: 0,
maxBound: 100,
colorScheme: '#FF0000',
column: 'count',
},
[25, 50],
);
expect(colorFunction(0)).toBeUndefined();
expect(colorFunction(50)).toEqual('#FF000087');
expect(colorFunction(100)).toEqual('#FF0000FF');
expect(colorFunction(150)).toEqual('#FF0000FF');
});
test('getColorFunction GREATER_THAN ignores a maxBound below its target', () => {
const colorFunction = getColorFunction(
{
operator: Comparator.GreaterThan,
targetValue: 100,
maxBound: 90,
colorScheme: '#FF0000',
column: 'count',
},
[100, 150],
);
expect(colorFunction(125)).toEqual('#FF000087');
expect(colorFunction(150)).toEqual('#FF0000FF');
});
test('getColorFunction LESS_THAN respects manual minBound', () => {
const colorFunction = getColorFunction(
{
operator: Comparator.LessThan,
targetValue: 100,
minBound: 0,
colorScheme: '#FF0000',
column: 'count',
},
[50, 75],
);
expect(colorFunction(100)).toBeUndefined();
expect(colorFunction(50)).toEqual('#FF000087');
expect(colorFunction(0)).toEqual('#FF0000FF');
expect(colorFunction(-50)).toEqual('#FF0000FF');
});
test('getColorFunction LESS_THAN ignores a minBound above its target', () => {
const colorFunction = getColorFunction(
{
operator: Comparator.LessThan,
targetValue: 100,
minBound: 110,
colorScheme: '#FF0000',
column: 'count',
},
[50, 100],
);
expect(colorFunction(75)).toEqual('#FF000087');
expect(colorFunction(50)).toEqual('#FF0000FF');
});
test('getColorFunction GREATER_OR_EQUAL respects manual maxBound', () => {
const colorFunction = getColorFunction(
{
operator: Comparator.GreaterOrEqual,
targetValue: 0,
maxBound: 100,
colorScheme: '#FF0000',
column: 'count',
},
[25, 50],
);
expect(colorFunction(-10)).toBeUndefined();
expect(colorFunction(0)).toEqual('#FF00000D');
expect(colorFunction(50)).toEqual('#FF000087');
expect(colorFunction(100)).toEqual('#FF0000FF');
});
test('getColorFunction LESS_OR_EQUAL respects manual minBound', () => {
const colorFunction = getColorFunction(
{
operator: Comparator.LessOrEqual,
targetValue: 100,
minBound: 0,
colorScheme: '#FF0000',
column: 'count',
},
[50, 75],
);
expect(colorFunction(150)).toBeUndefined();
expect(colorFunction(100)).toEqual('#FF00000D');
expect(colorFunction(50)).toEqual('#FF000087');
expect(colorFunction(0)).toEqual('#FF0000FF');
});
test('getColorFunction NONE respects manual minBound and maxBound', () => {
const colorFunction = getColorFunction(
{
operator: Comparator.None,
colorScheme: '#FF0000',
column: 'count',
minBound: 0,
maxBound: 200,
},
countValues,
);
expect(colorFunction(-10)).toEqual('#FF000000');
expect(colorFunction(0)).toEqual('#FF000000');
expect(colorFunction(100)).toEqual('#FF000080');
expect(colorFunction(200)).toEqual('#FF0000FF');
expect(colorFunction(250)).toEqual('#FF0000FF');
});
test('getColorFunction NONE applies a diverging low/mid/high scale when centerValue and all three colors are set', () => {
const colorFunction = getColorFunction(
{
operator: Comparator.None,
colorScheme: '#000000',
column: 'count',
minBound: 0,
maxBound: 100,
centerValue: 50,
lowColor: { r: 255, g: 0, b: 0, a: 1 },
midColor: { r: 255, g: 255, b: 255, a: 1 },
highColor: { r: 0, g: 128, b: 0, a: 1 },
},
[10, 90],
);
expect(colorFunction(0)).toEqual('#ff0000');
expect(colorFunction(25)).toEqual('#ff8080');
expect(colorFunction(50)).toEqual('#ffffff');
expect(colorFunction(75)).toEqual('#80c080');
expect(colorFunction(100)).toEqual('#008000');
});
test('getColorFunction NONE uses the solid base color when gradient is disabled for a complete diverging config', () => {
const colorFunction = getColorFunction(
{
operator: Comparator.None,
colorScheme: '#000000',
useGradient: false,
column: 'count',
minBound: 0,
maxBound: 100,
centerValue: 50,
lowColor: { r: 255, g: 0, b: 0, a: 1 },
midColor: { r: 255, g: 255, b: 255, a: 1 },
highColor: { r: 0, g: 128, b: 0, a: 1 },
},
[10, 90],
);
expect(colorFunction(25)).toEqual('#000000');
expect(colorFunction(75)).toEqual('#000000');
});
test('getColorFunction NONE ignores an incomplete diverging config and falls back to colorScheme', () => {
const colorFunction = getColorFunction(
{
operator: Comparator.None,
colorScheme: '#FF0000',
column: 'count',
minBound: 0,
maxBound: 100,
centerValue: 50,
lowColor: { r: 255, g: 0, b: 0, a: 1 },
// midColor and highColor intentionally omitted
},
[10, 90],
);
expect(colorFunction(100)).toEqual('#FF0000FF');
});
test('getColorFunction NONE ignores a centerValue outside the min/max range', () => {
const colorFunction = getColorFunction(
{
operator: Comparator.None,
colorScheme: '#FF0000',
column: 'count',
minBound: 0,
maxBound: 100,
centerValue: 150,
lowColor: { r: 255, g: 0, b: 0, a: 1 },
midColor: { r: 255, g: 255, b: 255, a: 1 },
highColor: { r: 0, g: 128, b: 0, a: 1 },
},
[10, 90],
);
expect(colorFunction(100)).toEqual('#FF0000FF');
});
test('getColorFunction NONE resolves percent bounds against column sum', () => {
const colorFunction = getColorFunction(
{
operator: Comparator.None,
colorScheme: '#FF0000',
column: 'count',
boundUnit: BoundUnit.Percent,
percentDenominator: PercentDenominator.Sum,
minBound: 0,
maxBound: 100,
},
[50, 150],
);
// sum = 200, so minBound 0% -> 0, maxBound 100% -> 200 -- the same absolute
// range as the existing 'NONE respects manual minBound and maxBound' test
// above, just reached via percent-of-sum instead of typed directly.
expect(colorFunction(-10)).toEqual('#FF000000');
expect(colorFunction(0)).toEqual('#FF000000');
expect(colorFunction(100)).toEqual('#FF000080');
expect(colorFunction(200)).toEqual('#FF0000FF');
expect(colorFunction(250)).toEqual('#FF0000FF');
});
test('getColorFunction NONE resolves percent bounds against column max', () => {
const colorFunction = getColorFunction(
{
operator: Comparator.None,
colorScheme: '#FF0000',
column: 'count',
boundUnit: BoundUnit.Percent,
percentDenominator: PercentDenominator.Max,
minBound: 0,
maxBound: 100,
},
[10, 40, 90],
);
// max = 90, so maxBound 100% -> 90.
expect(colorFunction(0)).toEqual('#FF000000');
expect(colorFunction(45)).toEqual('#FF000080');
expect(colorFunction(90)).toEqual('#FF0000FF');
});
test('getColorFunction NONE defaults percentDenominator to column max when unset', () => {
const colorFunction = getColorFunction(
{
operator: Comparator.None,
colorScheme: '#FF0000',
column: 'count',
boundUnit: BoundUnit.Percent,
minBound: 0,
maxBound: 100,
},
[10, 40, 90],
);
expect(colorFunction(45)).toEqual('#FF000080');
expect(colorFunction(90)).toEqual('#FF0000FF');
});
test('getColorFunction NONE ignores percentDenominator and treats bounds as absolute when boundUnit is unset', () => {
const colorFunction = getColorFunction(
{
operator: Comparator.None,
colorScheme: '#FF0000',
column: 'count',
percentDenominator: PercentDenominator.Sum,
minBound: 0,
maxBound: 200,
},
[50, 150],
);
// percentDenominator is present but boundUnit is not 'percent', so minBound
// and maxBound are used exactly as typed rather than resolved against the
// sum.
expect(colorFunction(100)).toEqual('#FF000080');
expect(colorFunction(200)).toEqual('#FF0000FF');
});
test('getColorFunction NONE applies a percent-resolved centerValue to the diverging scale', () => {
const colorFunction = getColorFunction(
{
operator: Comparator.None,
colorScheme: '#000000',
column: 'count',
boundUnit: BoundUnit.Percent,
percentDenominator: PercentDenominator.Max,
minBound: 0,
maxBound: 100,
centerValue: 50,
lowColor: { r: 255, g: 0, b: 0, a: 1 },
midColor: { r: 255, g: 255, b: 255, a: 1 },
highColor: { r: 0, g: 128, b: 0, a: 1 },
},
[0, 100],
);
// max = 100, so every bound resolves to exactly the value it names. This
// verifies that boundUnit and percentDenominator also apply to centerValue.
expect(colorFunction(0)).toEqual('#ff0000');
expect(colorFunction(50)).toEqual('#ffffff');
expect(colorFunction(100)).toEqual('#008000');
});
test('getColorFunction NONE degrades percent bounds to unset when the column has no numeric values', () => {
const colorFunction = getColorFunction(
{
operator: Comparator.None,
colorScheme: '#FF0000',
column: 'count',
boundUnit: BoundUnit.Percent,
percentDenominator: PercentDenominator.Sum,
minBound: 0,
maxBound: 100,
},
[],
);
// No numeric values to sum -> both bounds resolve to unset -> the None
// branch's own no-manual-bound path runs Math.min/Math.max on an empty
// array (Infinity/-Infinity), so cutoffValue > extremeValue and every
// value is rejected -- the same degrade-safe "no coloring" outcome Phase
// 1/2 use elsewhere for invalid config shapes.
expect(colorFunction(0)).toBeUndefined();
expect(colorFunction(50)).toBeUndefined();
});
test('getColorFunction NONE falls back to automatic bounds for a non-positive column max', () => {
const colorFunction = getColorFunction(
{
operator: Comparator.None,
colorScheme: '#FF0000',
column: 'count',
boundUnit: BoundUnit.Percent,
percentDenominator: PercentDenominator.Max,
minBound: 0,
maxBound: 100,
},
[-100, -5],
);
// A negative denominator would reverse the configured 0%-100% bounds.
// Treating both as unset preserves an ordered, data-derived range.
expect(colorFunction(-100)).toEqual('#FF000000');
expect(colorFunction(-5)).toEqual('#FF0000FF');
});
test('getColorFunction NONE uses the sum of magnitudes for mixed-sign values', () => {
const colorFunction = getColorFunction(
{
operator: Comparator.None,
colorScheme: '#FF0000',
column: 'count',
boundUnit: BoundUnit.Percent,
percentDenominator: PercentDenominator.Sum,
minBound: 0,
maxBound: 100,
},
[500, -499, 400, -400],
);
// The signed sum is 1, but the magnitude sum is 1799. Using the signed sum
// would make every positive value saturate at the upper endpoint.
expect(colorFunction(-400)).toEqual('#FF000000');
expect(colorFunction(0)).toEqual('#FF000000');
expect(colorFunction(899.5)).toEqual('#FF000080');
expect(colorFunction(1799)).toEqual('#FF0000FF');
});
test('getColorFunction NONE keeps the running column max when a later value is smaller', () => {
const colorFunction = getColorFunction(
{
operator: Comparator.None,
colorScheme: '#FF0000',
column: 'count',
boundUnit: BoundUnit.Percent,
percentDenominator: PercentDenominator.Max,
minBound: 0,
maxBound: 100,
},
[90, 10, 40],
);
// max = 90 regardless of position in the array, so maxBound 100% -> 90.
expect(colorFunction(45)).toEqual('#FF000080');
expect(colorFunction(90)).toEqual('#FF0000FF');
});
test('getColorFunction GREATER_THAN ignores diverging fields even when fully set', () => {
const colorFunction = getColorFunction(
{
operator: Comparator.GreaterThan,
targetValue: 0,
colorScheme: '#FF0000',
column: 'count',
centerValue: 50,
lowColor: { r: 255, g: 0, b: 0, a: 1 },
midColor: { r: 255, g: 255, b: 255, a: 1 },
highColor: { r: 0, g: 128, b: 0, a: 1 },
},
[25, 100],
);
expect(colorFunction(100)).toEqual('#FF0000FF');
});
@@ -53,7 +53,6 @@
"@apache-superset/core": "*",
"@babel/runtime": "^7.29.7",
"@braintree/sanitize-url": "^7.1.2",
"@types/d3-format": "^3.0.4",
"@types/json-bigint": "^1.0.4",
"@visx/responsive": "^4.0.0",
"ace-builds": "^1.44.0",
@@ -90,20 +89,21 @@
"rehype-raw": "^7.0.0",
"rehype-sanitize": "^6.0.0",
"remark-gfm": "^4.0.1",
"reselect": "^5.3.0",
"reselect": "^5.2.0",
"rison": "^0.1.1",
"seedrandom": "^3.0.5",
"xss": "^1.0.15"
},
"devDependencies": {
"@emotion/styled": "^11.14.1",
"@types/d3-format": "^3.0.4",
"@types/d3-interpolate": "^3.0.4",
"@types/d3-scale": "^4.0.9",
"@types/d3-time": "^3.0.4",
"@types/d3-time-format": "^4.0.3",
"@types/jquery": "^4.0.1",
"@types/lodash": "^4.17.25",
"@types/node": "^26.4.0",
"@types/node": "^26.2.0",
"@types/prop-types": "^15.7.15",
"@types/react-syntax-highlighter": "^15.5.13",
"@types/react-table": "^7.7.20",
@@ -119,7 +119,7 @@
"@emotion/styled": "^11.14.1",
"@testing-library/dom": "^10.4.1",
"@testing-library/jest-dom": "*",
"@testing-library/react": "*",
"@testing-library/react": "^15.0.0",
"@testing-library/user-event": "*",
"@types/react": "*",
"@types/react-loadable": "*",
@@ -25,7 +25,6 @@ export enum VizType {
BoxPlot = 'box_plot',
Bubble = 'bubble_v2',
Bullet = 'bullet',
Butterfly = 'butterfly',
Calendar = 'cal_heatmap',
Cartodiagram = 'cartodiagram',
Chord = 'chord',
@@ -146,61 +146,3 @@ test('Calling "onConfirm" only after typing "delete" in the input', async () =>
// confirm input has been cleared
expect(screen.getByTestId('delete-modal-input')).toHaveValue('');
});
test('external disable keeps the destructive action unavailable after confirmation', async () => {
const onConfirm = jest.fn();
render(
<DeleteModal
title="Delete permanently?"
description="This cannot be undone."
onConfirm={onConfirm}
onHide={jest.fn()}
open
disablePrimaryButton
/>,
);
await userEvent.type(screen.getByTestId('delete-modal-input'), 'DELETE');
expect(screen.getByRole('button', { name: 'Delete' })).toBeDisabled();
await userEvent.click(screen.getByRole('button', { name: 'Delete' }));
expect(onConfirm).not.toHaveBeenCalled();
});
test('loading disables the destructive action and exposes busy state', async () => {
render(
<DeleteModal
title="Delete permanently?"
description="Checking dependencies"
onConfirm={jest.fn()}
onHide={jest.fn()}
open
loading
/>,
);
await userEvent.type(screen.getByTestId('delete-modal-input'), 'DELETE');
expect(screen.getByTestId('modal-confirm-button')).toBeDisabled();
expect(screen.getByTestId('antd-modal')).toHaveAttribute('aria-busy', 'true');
});
test('confirmation reset key clears and re-arms type-to-confirm', async () => {
const props = {
title: 'Delete permanently?',
description: 'This cannot be undone.',
onConfirm: jest.fn(),
onHide: jest.fn(),
open: true,
};
const { rerender } = render(
<DeleteModal {...props} confirmationResetKey="initial" />,
);
await userEvent.type(screen.getByTestId('delete-modal-input'), 'DELETE');
expect(screen.getByRole('button', { name: 'Delete' })).toBeEnabled();
rerender(<DeleteModal {...props} confirmationResetKey="impact-changed" />);
expect(screen.getByTestId('delete-modal-input')).toHaveValue('');
expect(screen.getByRole('button', { name: 'Delete' })).toBeDisabled();
});
@@ -40,9 +40,6 @@ export function DeleteModal({
title,
name,
recoverable = false,
disablePrimaryButton = false,
loading = false,
confirmationResetKey,
}: DeleteModalProps) {
// Recoverable (archive) deletes drop the "type DELETE to confirm" step;
// a permanent delete keeps it.
@@ -57,11 +54,6 @@ export function DeleteModal({
}
}, [open]);
useEffect(() => {
setConfirmation('');
setDisableChange(true);
}, [confirmationResetKey]);
// Re-arm the gate alongside clearing the text: resetting only the string
// leaves disableChange=false behind, so a user who typed DELETE, cancelled,
// and reopened would face an enabled Delete button over an empty input.
@@ -84,19 +76,14 @@ export function DeleteModal({
};
const onPressEnter = () => {
if (!disableChange && !disablePrimaryButton && !loading) {
if (!disableChange) {
confirm();
}
};
return (
<Modal
disablePrimaryButton={
disablePrimaryButton ||
loading ||
(showConfirmationInput ? disableChange : false)
}
primaryButtonLoading={loading}
disablePrimaryButton={showConfirmationInput ? disableChange : false}
onHide={hide}
onHandledPrimaryAction={confirm}
primaryButtonName={recoverable ? t('Archive') : t('Delete')}
@@ -104,7 +91,6 @@ export function DeleteModal({
show={open}
name={name}
title={title}
wrapProps={{ 'aria-busy': loading }}
centered
>
{description}

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