Compare commits

...

191 Commits

Author SHA1 Message Date
Evan Rusackas
1a16b2acec fix(semantic-layers): show a friendly warning when schema enrichment falls back
Enrichment failures (connection refused, driver quirks, etc.) were
toasted to the user verbatim, which reads as raw internals and varies
by driver. Replace it with a stable, translatable message pointing at
the server logs, where the full exception is already recorded.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-24 13:42:56 -07:00
dependabot[bot]
83ea9a1025 chore(deps): bump js-yaml from 5.2.1 to 5.2.2 in /docs (#42395)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-24 13:33:36 -07:00
dependabot[bot]
e9f61c1e66 chore(deps): bump postcss from 8.5.15 to 8.5.23 in /superset-frontend (#42396)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-24 13:33:22 -07:00
dependabot[bot]
857a194c66 chore(deps): bump postcss from 8.5.16 to 8.5.23 in /docs (#42397)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-24 13:33:09 -07:00
Joe Li
5ffdac1871 fix(mcp): align pooled screenshot override signature (#42384) 2026-07-24 13:32:31 -07:00
Joe Li
52552c8278 test(dashboard): migrate dashboard force-refresh control to Playwright (#41433)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-24 13:32:09 -07:00
Joe Li
134cae07ae fix(ui): update stale Ant Design v6 internal class selectors (#42146)
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-24 13:31:45 -07:00
Evan Rusackas
f3fa1c7d4f fix(reports): write a single execution log row per report run (#29857) (#41966)
Co-authored-by: Claude Code <noreply@anthropic.com>
2026-07-24 13:30:31 -07:00
Evan Rusackas
99841fb504 fix(async): include datasets and rev claims in guest channel HMAC (#41487)
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-24 13:29:58 -07:00
Evan Rusackas
3a53c4ebc3 chore(deps): raise SQLAlchemy lower bound to >=1.4.43 (#41123)
Co-authored-by: Amin Ghadersohi <amin.ghadersohi@gmail.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-24 13:29:30 -07:00
Joe Li
f7d0ec3a2c chore: add @rusackas to migration code owners (#42398) 2026-07-24 13:18:33 -07:00
Bhargava Vadlamani
7eceebce1c feat(dbspec): Support apache datafusion dbspec (#42374) 2026-07-24 11:56:30 -07:00
Amin Ghadersohi
3bdf134aaa fix(logging): stop noisy LocalProxy-not-mapped warning for guest users (#42306)
Co-authored-by: Claude <noreply@anthropic.com>
2026-07-24 13:06:20 -04:00
ViktorGo86
65528a5b76 docs(map-tiles): add Yandex Maps Tiles API configuration (#42375) 2026-07-24 22:19:20 +07:00
Alejandro Solares
0792f98910 fix(security): bump pillow from 12.2.0 to 12.3.0 (#42362) 2026-07-24 21:49:27 +07:00
Alejandro Solares
67c3fea0ce fix(security): bump pyasn1 from 0.6.3 to 0.6.4 (#42363) 2026-07-24 21:46:21 +07:00
dependabot[bot]
d2ea5e9a1a chore(deps-dev): bump brace-expansion from 1.1.15 to 1.1.16 in /superset-embedded-sdk (#42369)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-24 21:23:48 +07:00
dependabot[bot]
0b9a9c5d03 chore(deps): bump body-parser from 1.20.5 to 1.20.6 in /docs (#42370)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-24 21:23:31 +07:00
dependabot[bot]
16de95f024 chore(deps): bump immer from 11.1.11 to 11.1.15 in /superset-frontend (#42378)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-24 21:23:14 +07:00
dependabot[bot]
5b5e5cf82d chore(deps): bump actions/checkout from 7.0.0 to 7.0.1 (#42376)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-24 21:23:00 +07:00
dependabot[bot]
542416ac6e chore(deps): bump @deck.gl/mapbox from 9.3.6 to 9.3.7 in /superset-frontend in the deckgl group (#42377)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-24 21:21:20 +07:00
SkinnyPigeon
4f017de532 docs(gunicorn): correct dead links in values.yaml (#42385) 2026-07-24 21:20:46 +07:00
suvankardas216
a1142b0f91 fix(dataset): disable duplicate button when name is empty (#42217)
Co-authored-by: AS-MAC-1123 <as-mac-1123@AS-MAC-1123.local>
Co-authored-by: Evan Rusackas <evan@rusackas.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-24 00:24:37 -07:00
Jean Massucatto
4ee500e47b fix(explore): render Jinja before validating legacy chart filters (#41996) 2026-07-23 22:05:14 -07:00
Ujjwal Jain
3ff5dbfe81 fix(native-filters): use FILTER_STATE_CACHE_CONFIG timeout for dynamic filter option queries (#38910) 2026-07-23 21:01:54 -07:00
dependabot[bot]
cfb04a6e79 chore(deps-dev): bump databricks-sql-connector from 4.2.6 to 4.3.0 (#42347)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Joe Li <joe@preset.io>
Co-authored-by: Evan Rusackas <evan@preset.io>
2026-07-23 20:57:58 -07:00
dependabot[bot]
49f4e84b48 chore(deps): bump flask-compress from 1.17 to 1.24 (#42346)
Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Joe Li <joe@preset.io>
2026-07-23 19:21:29 -07:00
dependabot[bot]
921f75d544 chore(deps): bump pillow from 12.2.0 to 12.3.0 (#42348)
Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Joe Li <joe@preset.io>
2026-07-23 19:21:17 -07:00
Ramachandran A G
bcf0361a91 feat(KustoKQL): Add support for NULL / IS NOT NULL operator (#37890)
Co-authored-by: ag-ramachandran <ramacg@microsoft.com>
Co-authored-by: Joe Li <joe@preset.io>
2026-07-23 18:28:37 -07:00
jenwitteng
5776aff50a fix(charts): handle async (202) chart-data responses in StatefulChart (#42157)
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Co-authored-by: Evan Rusackas <evan@preset.io>
2026-07-23 18:01:05 -07:00
Hans Yu
14c96761e5 chore: SQLAlchemy User cascade backref warnings are irrelevant (#42360) 2026-07-23 17:16:38 -07:00
Abdul Rehman
d41f0febae fix(api): add example to get_export_ids_schema so Swagger "Try it out" pre-fills a valid array (#42265) 2026-07-23 17:15:24 -07:00
jesperct
c43effa4a3 fix(explore): show the beginning date on time-series x-axis line charts (#42046) 2026-07-23 17:14:30 -07:00
Evan Rusackas
206fe7ab12 fix(embedded): stop rejecting guest chart data built from control-specific params keys (#42295)
Co-authored-by: Claude Code <noreply@anthropic.com>
2026-07-23 13:31:04 -07:00
dependabot[bot]
1049826bc1 chore(deps): bump sqlalchemy-continuum from 1.6.0 to 1.7.0 (#42351)
Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Joe Li <joe@preset.io>
2026-07-23 12:56:11 -07:00
dependabot[bot]
6317113ee8 chore(deps): bump pydantic from 2.11.7 to 2.13.4 (#42350)
Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Joe Li <joe@preset.io>
2026-07-23 12:56:03 -07:00
dependabot[bot]
fdb9c152f0 chore(deps): bump nh3 from 0.3.5 to 0.3.6 (#42349)
Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Joe Li <joe@preset.io>
2026-07-23 12:55:56 -07:00
Amin Ghadersohi
2317d9cf91 fix(mcp): truncate query-tool responses instead of hard-failing (#42244) 2026-07-23 14:38:49 -04:00
yousoph
df8bbb548a fix(native-filters): keep filter value input caret at inline start (#42323)
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 11:26:56 -07:00
dependabot[bot]
6b02a423ef chore(deps-dev): bump the storybook group in /superset-frontend with 5 updates (#42355)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-24 00:39:08 +07:00
dependabot[bot]
f2848d951c chore(deps-dev): update taos-ws-py requirement from >=0.6.9 to >=0.7.0 (#42344)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-23 10:27:56 -07:00
JUST.in DO IT
cb319c9b81 fix(mcp): trust dataset is_dttm flag when applying time_grain to VARCHAR temporal columns (#42288) 2026-07-23 10:00:22 -07:00
dependabot[bot]
cc8edd2231 chore(deps): bump ag-grid from 36.0.0 to 36.0.1 in /superset-frontend (#42338)
Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: hainenber <dotronghai96@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: hainenber <dotronghai96@gmail.com>
2026-07-23 22:21:37 +07:00
Yash Shrivastava
c5f6d33d21 docs: add pattern to the list of organisations using superset (#42341) 2026-07-23 22:11:17 +07:00
Evan Rusackas
2e72080a16 chore(deps): bump echarts to 6.1.0 with locale and containLabel guards (#42315) (#42321)
Co-authored-by: Claude Code <noreply@anthropic.com>
Co-authored-by: Amin Ghadersohi <amin.ghadersohi@gmail.com>
2026-07-23 21:48:11 +07:00
dependabot[bot]
6654318491 chore(deps): bump caniuse-lite from 1.0.30001805 to 1.0.30001806 in /docs (#42333)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-23 21:46:27 +07:00
dependabot[bot]
ab553c37ab chore(deps-dev): bump @formatjs/intl-durationformat from 0.10.17 to 0.10.18 in /superset-frontend (#42337)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-23 21:37:30 +07:00
dependabot[bot]
873da606dd chore(deps): bump github/codeql-action/init from 4.37.0 to 4.37.1 (#42334)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-23 21:36:39 +07:00
dependabot[bot]
1dd3103c24 chore(deps): bump github/codeql-action/analyze from 4.37.0 to 4.37.1 (#42331)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-23 21:36:16 +07:00
dependabot[bot]
2926d6f6a9 chore(deps): bump actions/labeler from 6.2.0 to 7.0.0 (#42332)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-23 21:34:54 +07:00
Evan Rusackas
67924ad35e fix(dashboard): offer Exit edit mode when there is nothing to discard (#42208)
Co-authored-by: Claude Code <noreply@anthropic.com>
2026-07-22 18:43:49 -07:00
David
ef459c21e8 fix(helm): add MCP HTTPRoute configuration (#42219) 2026-07-22 17:08:16 -07:00
Amitesh Gupta
3ed8889a01 fix: Added PostgreSQL 17.X to the supported database versions table in (#42280) 2026-07-22 16:24:13 -07:00
yousoph
17bd286ae9 fix(forecast): resolve time grain robustly for Prophet forecasting (#42145)
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-22 16:08:57 -07:00
yousoph
32937f24d2 fix(heatmap): correct tooltip axis value lookup and percentage calculations and add tests (#41864)
Signed-off-by: yousoph <sophieyou12@gmail.com>
Co-authored-by: Kamil Gabryjelski <kamil.gabryjelski@gmail.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-07-22 15:34:10 -07:00
Elizabeth Thompson
e075133a83 fix(pandas_postprocessing): avoid FutureWarning for max/min in boxplot MINMAX (#42272) 2026-07-22 15:02:14 -07:00
Joe Li
8d034ef65c fix(plugin-chart-echarts): import the -obj locale build so time axes render (#42317)
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-22 14:53:59 -07:00
Joe Li
641713f623 fix: Revert "chore(deps): bump echarts from 5.6.0 to 6.1.0 in /superset-frontend" (#42314)
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-22 12:40:56 -07:00
Joe Li
40d9e7d048 fix(ag-grid-table): avoid ambiguous build query import (#42313) 2026-07-22 11:30:45 -07:00
Hans Yu
19159d58c8 refactor: engine enforce SQLAlchemy 2.0 (#42277) 2026-07-22 11:11:48 -07:00
Grégoire
894c0191d6 fix(superset_app_root): when used with oauth (#38033)
Signed-off-by: Grégoire Bellon-Gervais <gregoire.bellon-gervais@docaposte.fr>
Co-authored-by: Evan Rusackas <evan@preset.io>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-22 10:34:43 -07:00
Joe Li
49b4243129 test(dashboard): migrate dashboard load smoke test to Playwright (#41432)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 10:32:07 -07:00
dependabot[bot]
ac41f61d4a chore(deps): bump nanoid from 5.0.9 to 6.0.0 in /superset-frontend (#42230)
Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: hainenber <dotronghai96@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: hainenber <dotronghai96@gmail.com>
Co-authored-by: Joe Li <joe@preset.io>
Co-authored-by: Evan <evan@preset.io>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-22 10:28:51 -07:00
dependabot[bot]
f50b7b7154 chore(deps): bump actions/setup-go from 6.5.0 to 7.0.0 (#42303)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-22 10:28:11 -07:00
Zack
be5744c431 fix(chart): updates counties of kenya map (#38019)
Co-authored-by: Zack Adams <zack@Zacks-Laptop.local>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Evan <evan@preset.io>
Co-authored-by: Evan Rusackas <evan@rusackas.com>
2026-07-22 10:17:29 -07:00
SkinnyPigeon
8c5d465a65 feat(datasets): add RLS filter indicator badge to dataset list and explore view (#38807)
Co-authored-by: Evan <evan@preset.io>
2026-07-22 10:07:52 -07:00
Evan Rusackas
c5935b6904 feat(table/pivot-table): correct non-additive totals/subtotals via DB rollup [SIP-216] (#41184)
Co-authored-by: Superset Dev <dev@superset.apache.org>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Amin Ghadersohi <amin.ghadersohi@gmail.com>
2026-07-22 10:06:05 -07:00
Evan Rusackas
10ff470702 fix(ag-grid-table): respect row limit with server pagination (#41346)
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-22 10:03:33 -07:00
Amin Ghadersohi
1c0f259e38 refactor(mcp): dedupe list-tool schemas and delete dead middleware (#41923) 2026-07-22 12:29:59 -04:00
Alexandru Soare
b8f3b768d4 fix(sqllab): Fall back to empty editor tab when linked query no longer exists (#42241) 2026-07-22 15:30:42 +03:00
dependabot[bot]
6e1954fd51 chore(deps): bump ws from 8.21.0 to 8.21.1 in /superset-websocket (#42301)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-22 02:21:25 -07:00
dependabot[bot]
248f6e1064 chore(deps): bump zizmorcore/zizmor-action from 0.5.7 to 0.6.0 (#42302)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-22 02:21:21 -07:00
dependabot[bot]
46c5e30533 chore(deps-dev): bump oxlint from 1.73.0 to 1.74.0 in /superset-frontend (#42304)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-22 02:21:17 -07:00
Mehmet Salih Yavuz
b71b58e821 fix(explore): render stopped state when a chart query is cancelled (#42270) 2026-07-22 11:14:08 +03:00
Damian Pendrak
1392fbc9b2 fix(sql): validate Custom SQL metric has an aggregate under GROUP BY (#42199) 2026-07-22 09:28:57 +02:00
Mafi
a086b2eae9 fix(clickhouse): retry adhoc column type probe with comment-safe SQL (#42298)
Co-authored-by: Matt Fitzgerald <matt.fitzgerald@preset.io>
2026-07-22 02:39:49 -04:00
Pawan
788165b5bb fix(frontend): jest testRegex matches Windows path separators (#41863) 2026-07-21 20:32:33 -07:00
dependabot[bot]
60a7c18204 chore(deps): bump svgo from 3.3.3 to 3.3.4 in /docs (#42286)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-21 17:55:25 -07:00
dependabot[bot]
db1959b9b6 chore(deps): bump fast-uri from 3.1.2 to 3.1.4 in /superset-frontend/cypress-base (#42292)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-21 17:55:20 -07:00
dependabot[bot]
936b8a84ae chore(deps): bump fast-uri from 3.1.3 to 3.1.4 in /superset-frontend (#42293)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-21 17:55:15 -07:00
dependabot[bot]
37ef2f381e chore(deps): bump fast-uri from 3.1.3 to 3.1.4 in /docs (#42294)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-21 17:55:11 -07:00
Amin Ghadersohi
cae61b51e1 fix(cache): QueryCacheManager.get() should fail open on cache backend errors (#42252) 2026-07-21 20:05:00 -04:00
dependabot[bot]
9c08240fdc chore(deps): bump dompurify from 3.4.11 to 3.4.12 in /docs (#42287)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-21 16:44:49 -07:00
Igor Khrol
072ff01406 fix: disable recaptcha for LDAP authentication (#36857)
Co-authored-by: Igor Khrol <khroliz@Igors-MacBook-Pro-2.local>
2026-07-21 16:31:12 -07:00
Keonik
8b1ef3a4cb feat(helm): Add annotations to secrets manifests (#40803)
Co-authored-by: Superset Dev <dev@superset.apache.org>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-21 16:27:55 -07:00
JUST.in DO IT
d62dbdb694 fix(chat): prevent main content reload when toggling chat panel (#42143) 2026-07-21 16:27:29 -07:00
Aleksey
2ddea33bb6 fix(models): inline calculated column expression in raw-records queries (#34784) (#42040)
Co-authored-by: Evan Rusackas <evan@preset.io>
2026-07-21 16:23:59 -07:00
Ville Brofeldt
15d7d36580 chore: remove deprecated from_dttm and to_dttm jinja vars (#42279) 2026-07-21 15:07:36 -07:00
dependabot[bot]
ab8e23d874 chore(deps-dev): bump svgo from 3.3.3 to 3.3.4 in /superset-frontend (#42285)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-21 14:45:12 -07:00
Jean Massucatto
1b882c1f47 test(explore): cover annotation layer link app-root prefix in subdire… (#41997) 2026-07-21 14:05:30 -07:00
dependabot[bot]
8329481c2e chore(deps-dev): bump the typescript-eslint group across 1 directory with 2 updates (#42258)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-21 14:04:48 -07:00
dependabot[bot]
c95c8086f5 chore(deps-dev): bump webpack-bundle-analyzer from 5.3.0 to 5.3.1 in /superset-frontend (#42261)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-21 14:04:44 -07:00
dependabot[bot]
cfac785541 chore(deps): bump fuse.js from 7.4.2 to 7.5.0 in /superset-frontend (#42262)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Joe Li <joe@preset.io>
2026-07-21 14:04:40 -07:00
dependabot[bot]
b97a7f5f94 chore(deps-dev): bump fast-uri from 3.1.2 to 3.1.4 in /superset-embedded-sdk (#42282)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-21 14:04:30 -07:00
Amin Ghadersohi
e5c418a187 fix(mcp): normalize bracket-shorthand time ranges in query_dataset (#42144) 2026-07-21 15:42:04 -04:00
Michael S. Molina
34ebe3d22a feat(extensions): add a Storage API for extensions (#39171)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Evan Rusackas <evan@preset.io>
Co-authored-by: Amin Ghadersohi <amin.ghadersohi@gmail.com>
Co-authored-by: Benyovszky Máté <benyovszky.mate.work@outlook.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-21 16:23:56 -03:00
SBIN2010
0dd06f3b7b fix: dashboard filter regress (#35218)
Co-authored-by: Evan Rusackas <evan@preset.io>
2026-07-21 21:04:04 +03:00
Hans Yu
40a13883ea refactor: do not cascade to SqlMetric (#42221)
Co-authored-by: Evan Rusackas <evan@rusackas.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-21 10:26:01 -07:00
Evan Rusackas
f2967264d2 fix(ci): diff pre-commit changed files against the live base branch tip (#42152)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-21 10:20:57 -07:00
Evan Rusackas
706a65cb02 fix(docs): allow *.run.app in CSP for the Kapa widget backend (#42276)
Co-authored-by: Amin Ghadersohi <amin.ghadersohi@gmail.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-21 10:18:13 -07:00
Evan Rusackas
f9378baba8 test(sqla): add the jinja orderby calculated column to the session (#42274)
Co-authored-by: Claude Code <noreply@anthropic.com>
2026-07-21 10:16:29 -07:00
Evan Rusackas
e1a265447f fix(charts): use chart name in CSV/XLSX/zip export filenames (#42193)
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-21 10:16:17 -07:00
Amin Ghadersohi
f999afaac0 fix(mcp): coerce float rowcount to int in ChartData to prevent PydanticSerializationError (#42140) 2026-07-21 10:10:33 -07:00
Elizabeth Thompson
1a862476e1 fix(dashboard): add cacheKey, dashboardId, and format context to screenshot download error logs (#42121)
Co-authored-by: Claude <noreply@anthropic.com>
2026-07-21 10:10:14 -07:00
Taras Pashkevych
df34b5d277 fix(drill-detail): paginate Elasticsearch samples via engine cursor (#39509) 2026-07-21 10:09:28 -07:00
Evan Rusackas
b362d36019 chore: remove deck.gl JavaScript tooltip controls and ENABLE_JAVASCRIPT_CONTROLS (#42126)
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-21 10:01:25 -07:00
Evan Rusackas
666b6805c4 test(sql): prove Oracle GROUP BY stays explicit for virtual-dataset charts (#42255)
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-21 09:59:34 -07:00
dependabot[bot]
3fa7cc5986 chore(deps): bump react-diff-viewer-continued from 4.3.0 to 4.4.0 in /superset-frontend (#42263)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Evan <evan@preset.io>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-21 09:47:05 -07:00
dependabot[bot]
7f4d151a37 chore(deps): bump body-parser from 2.2.1 to 2.3.0 in /superset-websocket/utils/client-ws-app (#42264)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-21 09:46:56 -07:00
dependabot[bot]
5efbd5b157 chore(deps-dev): bump brace-expansion from 5.0.6 to 5.0.7 in /superset-websocket (#42267)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-21 09:46:48 -07:00
Hugh A. Miles II
00cb3037e7 feat(dashboard): export dashboard chart data to Excel (async, S3 + email) (#41133) 2026-07-21 12:17:00 -04:00
Hans Yu
6c58afe6ac refactor: do not cascade to TableColumn (#42222) 2026-07-21 09:00:47 -07:00
Evan Rusackas
f751716867 fix(trino): quote nested ROW field paths per-segment in physical column expressions (#41946)
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-21 04:27:24 -07:00
dependabot[bot]
bafe5ad9ba chore(deps): bump actions/setup-java from 5.5.0 to 5.6.0 (#42260)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-21 01:15:32 -07:00
dependabot[bot]
a1d4cda0cb chore(deps-dev): bump typescript-eslint from 8.63.0 to 8.64.0 in /docs in the typescript-eslint group (#42259)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-21 01:15:28 -07:00
Evan Rusackas
2d3cbc162e fix(db_engine_specs): map var_string to STRING for MySQL/StarRocks (#41868)
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-21 00:11:46 -07:00
Evan Rusackas
e4005f02c6 fix(sqla): render Jinja templates in calculated columns used via orderby adhoc metrics (#41870)
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-21 00:11:26 -07:00
jesperct
8296fe8ce4 fix(home): restore navigation for saved query cards (#41912) 2026-07-20 17:33:32 -07:00
Elizabeth Thompson
4b659da5c4 fix(reports): positive per-tile chart readiness check for tiled screenshots (#42119)
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: yousoph <sophieyou12@gmail.com>
2026-07-20 17:31:45 -07:00
worker24h
b4529c2654 feat: add distance unit (#24444)
Co-authored-by: xuxiaobing <xuxiaobing@neolix.cn>
Co-authored-by: Claude Code <noreply@anthropic.com>
Co-authored-by: Evan <evan@preset.io>
Co-authored-by: Evan Rusackas <evan@rusackas.com>
2026-07-20 16:25:48 -07:00
Evan Rusackas
034823e99b chore: replace deprecated datetime.utcnow()/utcfromtimestamp() (#41502)
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 15:37:57 -07:00
Evan Rusackas
abd6dc8e44 refactor: set cascade_backrefs=False for SavedQuery (#42212)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-20 15:37:28 -07:00
Evan Rusackas
b3757870cc fix(sqllab): apply SQL_QUERY_MUTATOR in SQL Lab when MUTATE_AFTER_SPLIT is set (#41127)
Co-authored-by: Lucas Wolkersdorfer <lucas.wolkersdorfer@rise-world.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 15:36:45 -07:00
dependabot[bot]
158e321992 chore(deps): bump axios from 1.16.0 to 1.18.1 in /superset-frontend (#42251)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-20 11:45:40 -07:00
Evan Rusackas
590357731b feat(ci): cancel CI runs when hold label applied, re-run on removal (#40387)
Co-authored-by: Claude <claude@anthropic.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Đỗ Trọng Hải <41283691+hainenber@users.noreply.github.com>
2026-07-20 10:35:26 -07:00
Elizabeth Thompson
64053271e8 fix(views): remove stray space in @deprecated new_target log message (#42218) 2026-07-20 10:35:02 -07:00
Matthew Chiang
940e2c34a2 fix(Calendar Heatmap): Add Back chart options for Calendar Heatmap (#26230)
Co-authored-by: Claude <claude@anthropic.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Evan Rusackas <evan@rusackas.com>
2026-07-20 10:32:35 -07:00
Đỗ Trọng Hải
d65a816b39 chore(lint): toggle import/no-named-as-default to error level + fix all violations (#42214)
Signed-off-by: hainenber <dotronghai96@gmail.com>
2026-07-20 10:22:15 -07:00
Evan Rusackas
48faca5b8d refactor: set cascade_backrefs=False for SqlaTable (#42213)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-20 10:22:00 -07:00
Evan Rusackas
9178faf9b1 refactor: set cascade_backrefs=False for Query (#42210)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-20 10:20:09 -07:00
PRATHAMESH HUKKERI
15bc73facf test(table): add regression test for pagination reset on cell click (#42155)
Co-authored-by: Prathamesh Hukkeri <prathamesh04@users.noreply.github.com>
2026-07-20 10:15:29 -07:00
Evan Rusackas
e0d0eb6d02 fix(build): deterministic echarts locale imports; fingerprint loaded config (#42154)
Co-authored-by: Superset Dev <dev@superset.apache.org>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-20 10:13:58 -07:00
Đỗ Trọng Hải
1f81b700c1 chore(ci): upgrade GHA runner image to Ubuntu 26.04 (#42191)
Signed-off-by: hainenber <dotronghai96@gmail.com>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: David <39565245+dmunozv04@users.noreply.github.com>
Co-authored-by: Hans Yu <hans.yu@outlook.de>
Co-authored-by: Shaitan <105581038+sha174n@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Rehan Islam <2025eb01502@online.bits-pilani.ac.in>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: J0s3-H3nr1qu3 <hareboom@gmail.com>
Co-authored-by: José Teixeira <jose.teixeira@douroeci.com>
2026-07-20 09:43:19 -07:00
Jean Massucatto
3a3f087869 fix(native-filters): support double-quote escaping for comma in filte… (#39068)
Co-authored-by: Evan <evan@preset.io>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 09:42:52 -07:00
Evan Rusackas
f03a66db9c fix(dataset): apply HOURS OFFSET to all temporal columns, not just the time column (#41489)
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 09:23:20 -07:00
Adolfo Carvalho
515dfef955 fix(dashboard import): Importing existing dashboard via UI won't update charts and datasets (#34880)
Co-authored-by: Evan Rusackas <evan@preset.io>
Co-authored-by: Joe Li <joe@preset.io>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-20 09:22:06 -07:00
Evan Rusackas
5a17ae1224 chore: drop Python 3.10 support, require Python 3.11+ (#42045)
Signed-off-by: hainenber <dotronghai96@gmail.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Co-authored-by: hainenber <dotronghai96@gmail.com>
2026-07-20 08:16:22 -07:00
Mehmet Salih Yavuz
c1e660fac8 fix(databases): reset import file entry after invalid file error (#42240) 2026-07-20 18:06:44 +03:00
dependabot[bot]
19ca088de6 chore(deps): bump baseline-browser-mapping from 2.10.42 to 2.10.43 in /docs (#42227)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-20 07:44:06 -07:00
dependabot[bot]
57dc3c0208 chore(deps): bump antd from 6.5.0 to 6.5.1 in /superset-frontend (#42234)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-20 21:42:51 +07:00
dependabot[bot]
ceffbe80f9 chore(deps): bump hot-shots from 16.0.0 to 17.0.0 in /superset-websocket (#42236)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-20 21:42:00 +07:00
dependabot[bot]
eed41b6435 chore(deps): bump actions/setup-node from 6.4.0 to 7.0.0 (#42229)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-20 21:33:36 +07:00
J0s3-H3nr1qu3
277c814c5a fix(i18n): review and complete Portuguese (pt_PT) translation catalog (#42137)
Co-authored-by: José Teixeira <jose.teixeira@douroeci.com>
2026-07-20 14:37:43 +01:00
dependabot[bot]
7e63b29741 chore(deps): bump antd from 6.5.0 to 6.5.1 in /docs (#42226)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-20 03:56:10 -07:00
dependabot[bot]
b5ae7cbd0d chore(deps): bump caniuse-lite from 1.0.30001803 to 1.0.30001805 in /docs (#42228)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-20 03:56:03 -07:00
dependabot[bot]
e044d7783a chore(deps): bump dompurify from 3.4.11 to 3.4.12 in /superset-frontend (#42231)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-20 03:55:59 -07:00
dependabot[bot]
9e8b9ac8cf chore(deps-dev): bump tsx from 4.23.0 to 4.23.1 in /superset-frontend (#42232)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-20 03:55:55 -07:00
dependabot[bot]
19588826c8 chore(deps-dev): bump baseline-browser-mapping from 2.10.42 to 2.10.43 in /superset-frontend (#42233)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-20 03:55:50 -07:00
dependabot[bot]
8b415502cf chore(deps): bump chrono-node from 2.9.1 to 2.10.0 in /superset-frontend (#42235)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-20 03:55:43 -07:00
Rehan Islam
09148d0af6 fix(time-table): correctly sort computed columns (#41976) 2026-07-19 20:56:53 -07:00
Shaitan
3e40bebba8 fix(import): enforce write permission for objects created by legacy import paths (#42205)
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-19 20:50:58 -07:00
Hans Yu
36dbff091f refactor: do not cascade to TaggedObject (#42223) 2026-07-19 20:18:53 -07:00
David
9e9b7c4bbd feat(ci): run helm-unittest on pull requests (#42206) 2026-07-20 07:36:19 +07:00
dependabot[bot]
42a2aede78 chore(deps): bump pandas from 2.1.4 to 2.3.3 (#42192)
Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Amin Ghadersohi <amin.ghadersohi@gmail.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-18 15:42:02 -07:00
lguichard78
c4d50472a9 fix(login): oauth and ldap login ignoring superset_app_root (#34657) 2026-07-18 14:58:22 -07:00
Younsung Lee
cd045886d0 feat(helm): add Gateway API HTTPRoute support (#41073)
Signed-off-by: younsl <cysl@kakao.com>
2026-07-18 14:57:02 -07:00
Jean Massucatto
751f5eb663 fix(dashboard): disable Discard button when there are no unsaved changes (#40832)
Co-authored-by: Evan Rusackas <evan@preset.io>
2026-07-18 14:15:17 -07:00
serdukow
4e098b6f38 fix(ag-grid-table): use t('Main') for time comparison column keys to fix i18n (#40681)
Co-authored-by: Evan Rusackas <evan@preset.io>
Co-authored-by: Claude <noreply@anthropic.com>
2026-07-18 13:00:53 -07:00
David
5ee4a81906 feat(helm): add Superset MCP server templates (#40507) 2026-07-18 12:59:40 -07:00
Mike Bridge
caf017bd0b feat(versioning): cross-entity version activity view (#41076)
Co-authored-by: Mike Bridge <michael.bridge@ext.preset.io>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-18 11:06:54 -07:00
jenwitteng
a83171bce6 fix(database): capture result metadata after fetch (#42127)
Signed-off-by: Jenwit Amonpongitsara <jenwit.amonpongitsara@agoda.com>
2026-07-18 10:54:36 -07:00
Đỗ Trọng Hải
6c13ab6657 feat(ci): optimize Storybook testing in CI by replacing http-server with Python3 static server (#41956)
Signed-off-by: hainenber <dotronghai96@gmail.com>
2026-07-18 10:53:54 -07:00
Đỗ Trọng Hải
b9ede492b7 chore(lint): toggle import/named and import/export lint rules to error level (#42189)
Signed-off-by: hainenber <dotronghai96@gmail.com>
2026-07-18 10:53:40 -07:00
Gagandeep Singh Choudhary
fb29db6119 fix(sqllab): preserve database state on SET_DATABASES (#41281)
Co-authored-by: Joe Li <joe@preset.io>
Co-authored-by: Evan <evan@preset.io>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-18 10:52:45 -07:00
David
0a66e4ea2d fix(helm): support initContainers in supersetWebsockets (#42201) 2026-07-18 10:29:42 -07:00
AYUSHI RAI
3e0f9e60c0 fix(charts): preserve minute/second precision in X-axis time labels f… (#41505)
Co-authored-by: Evan Rusackas <evan@rusackas.com>
Co-authored-by: Claude <noreply@anthropic.com>
2026-07-18 10:28:03 -07:00
Durgaprasad M L
ff1cf5f24e fix(table): hide search dropdown when search box is disabled (#41772) 2026-07-18 10:23:54 -07:00
dependabot[bot]
023b60c8f0 chore(deps-dev): bump pandas-gbq from 0.19.1 to 0.35.0 (#42161)
Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-07-18 07:23:17 -07:00
dependabot[bot]
2ada286ee9 chore(deps-dev): update pydynamodb requirement from >=0.4.2 to >=0.8.2 (#42162)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-18 07:23:13 -07:00
dependabot[bot]
42e5640f60 chore(deps-dev): update nzalchemy requirement from <11.2,>=11.0.2 to >=11.1.2,<11.2 (#42164)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-18 07:23:09 -07:00
dependabot[bot]
74703906df chore(deps): bump dom-to-image-more from 3.10.0 to 3.10.2 in /superset-frontend (#42180)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-18 21:15:23 +07:00
dependabot[bot]
3c23394675 chore(deps-dev): bump eslint from 10.6.0 to 10.7.0 in /superset-websocket (#42159)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-18 16:12:08 +07:00
dependabot[bot]
b6ce28ff72 chore(deps): bump typing-extensions from 4.15.0 to 4.16.0 (#42165)
Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-07-18 16:11:46 +07:00
dependabot[bot]
79eff6b6f1 chore(deps): bump greenlet from 3.5.1 to 3.5.3 (#42166)
Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-07-18 16:08:28 +07:00
dependabot[bot]
a58012fc0f chore(deps): bump the docusaurus-openapi group in /docs with 2 updates (#42195)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-18 16:05:39 +07:00
dependabot[bot]
dab5f30842 chore(deps): bump @docusaurus/faster from 3.10.1 to 3.10.2 in /docs (#42179)
Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: hainenber <dotronghai96@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Đỗ Trọng Hải <41283691+hainenber@users.noreply.github.com>
Co-authored-by: hainenber <dotronghai96@gmail.com>
2026-07-18 15:55:18 +07:00
dependabot[bot]
8299e7f87c chore(deps-dev): bump storybook from 10.4.6 to 10.5.0 in /superset-frontend (#42185)
Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: hainenber <dotronghai96@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: hainenber <dotronghai96@gmail.com>
2026-07-18 15:41:22 +07:00
dependabot[bot]
f6acf68dfa chore(deps): bump react-intersection-observer from 10.0.3 to 10.1.0 in /superset-frontend (#42181)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-18 13:31:08 +07:00
dependabot[bot]
cce77b42f6 chore(deps-dev): bump @formatjs/intl-durationformat from 0.10.16 to 0.10.17 in /superset-frontend (#42184)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-18 13:11:17 +07:00
dependabot[bot]
e495fd80f6 chore(deps-dev): bump eslint from 10.6.0 to 10.7.0 in /superset-frontend (#42188)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-18 13:01:56 +07:00
dependabot[bot]
bda62cb28d chore(deps-dev): bump hdbcli from 2.29.23 to 2.29.25 (#42170)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-18 12:38:16 +07:00
Đỗ Trọng Hải
45354994a6 build(deps): update @rjsf deps to v6 (#41955)
Signed-off-by: hainenber <dotronghai96@gmail.com>
2026-07-18 10:54:40 +07:00
Abhishek Kumbhar
0f61d9a3fb fix(bigquery): ensure BigQuery client uses project from engine URI (#41975) 2026-07-17 20:05:34 -07:00
Evan Rusackas
b432f8c917 fix(docs): use modern driver package for CrateDB (#42125)
Co-authored-by: Andreas Motl <andreas.motl@crate.io>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-18 10:05:09 +07:00
Igor Shargin
25f6c6c80b fix(pivot-table): add bottom border to last grouped row (#36081)
Co-authored-by: Evan <evan@preset.io>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Evan Rusackas <evan@rusackas.com>
2026-07-17 19:26:55 -07:00
Evan Rusackas
ce8d4397cd test(jinja): prove current_user_* macros produce collision-free cache keys (#42122)
Co-authored-by: Amin Ghadersohi <amin.ghadersohi@gmail.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-17 16:50:11 -07:00
Evan Rusackas
68297886d4 fix(ci): stop concurrency cancellation from bricking required checks on approval-gated PRs (#42148)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 16:38:27 -07:00
SBIN2010
91f814abea feat(pie): add the ability to make half a donut (#35459)
Co-authored-by: Enzo Martellucci <52219496+EnxDev@users.noreply.github.com>
Co-authored-by: Amin Ghadersohi <amin.ghadersohi@gmail.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-17 16:29:23 -07:00
dependabot[bot]
6a330c251b chore(deps): bump redis from 5.3.1 to 8.0.1 (#41813)
Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Evan Rusackas <evan@rusackas.com>
Co-authored-by: Evan Rusackas <evan@preset.io>
Co-authored-by: Joe Li <joe@preset.io>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 15:25:51 -07:00
Joe Li
5bf26f77f8 fix(label): restore spacing between icon and label text (#42141)
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 15:05:48 -07:00
Elizabeth Thompson
5750d82426 fix(pandas_postprocessing): avoid FutureWarning for mean/median in boxplot (#42004) 2026-07-17 15:02:40 -07:00
686 changed files with 60152 additions and 19588 deletions

2
.github/CODEOWNERS vendored
View File

@@ -1,6 +1,6 @@
# Notify all committers of DB migration changes, per SIP-59
/superset/migrations/ @mistercrunch @michael-s-molina @betodealmeida @eschutho @sadpandajoe
/superset/migrations/ @mistercrunch @michael-s-molina @betodealmeida @eschutho @sadpandajoe @rusackas
# Notify some committers of changes in the components

View File

@@ -50,9 +50,8 @@ body:
attributes:
label: Python version
options:
- "3.9"
- "3.10"
- "3.11"
- "3.12"
- Not applicable
- I don't know
validations:

View File

@@ -10,7 +10,6 @@ updates:
- package-ecosystem: "npm"
ignore:
- dependency-name: "@rjsf/*"
# TODO: remove below entries once the application supports React >= 19.0.0
- dependency-name: "react"
update-types: ["version-update:semver-major"]
@@ -49,6 +48,32 @@ updates:
labels:
- npm
- dependabot
groups:
rjsf:
patterns:
- "@rjsf/*"
typescript-eslint:
patterns:
- "@typescript-eslint/*"
- "typescript-eslint"
babel:
patterns:
- "@babel/*"
deckgl:
patterns:
- "@deck.gl/*"
lumagl:
patterns:
- "@luma.gl/*"
storybook:
patterns:
- "@storybook/*"
- "storybook"
- "eslint-plugin-storybook"
ag-grid:
patterns:
- "ag-grid-react"
- "ag-grid-community"
open-pull-requests-limit: 30
versioning-strategy: increase
cooldown:
@@ -83,6 +108,22 @@ updates:
directory: "/docs/"
schedule:
interval: "daily"
groups:
storybook:
patterns:
- "@storybook/*"
- "storybook"
docusaurus:
patterns:
- "@docusaurus/*"
docusaurus-openapi:
patterns:
- "docusaurus-plugin-openapi-docs"
- "docusaurus-theme-openapi-docs"
typescript-eslint:
patterns:
- "@typescript-eslint/*"
- "typescript-eslint"
open-pull-requests-limit: 10
versioning-strategy: increase
cooldown:

View File

@@ -23,7 +23,7 @@ on:
jobs:
bump-python-package:
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
permissions:
actions: write
contents: write
@@ -31,7 +31,7 @@ jobs:
checks: write
steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: true
ref: master
@@ -42,7 +42,7 @@ jobs:
- name: Set up Python ${{ inputs.python-version }}
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: "3.10"
python-version: "3.11"
- name: Install uv
run: pip install uv

View File

@@ -19,10 +19,10 @@ concurrency:
jobs:
check-python-deps:
runs-on: ubuntu-22.04
runs-on: ubuntu-26.04
steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
submodules: recursive

View File

@@ -19,13 +19,13 @@ concurrency:
jobs:
check_db_migration_conflict:
name: Check DB migration conflict
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
permissions:
contents: read
pull-requests: write
steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Check and notify

View File

@@ -16,7 +16,7 @@ concurrency:
jobs:
changes:
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
timeout-minutes: 10
permissions:
contents: read
@@ -26,7 +26,7 @@ jobs:
frontend: ${{ steps.check.outputs.frontend }}
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Check for file changes
@@ -42,7 +42,7 @@ jobs:
# analysis runners don't spin up. push/schedule runs always proceed:
# the change-detector returns "all changed" for non-PR events.
if: needs.changes.outputs.python == 'true' || needs.changes.outputs.frontend == 'true'
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
timeout-minutes: 30
permissions:
actions: read
@@ -58,13 +58,13 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # v4.37.0
uses: github/codeql-action/init@7188fc363630916deb702c7fdcf4e481b751f97a # v4.37.1
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
@@ -75,6 +75,6 @@ jobs:
# queries: security-extended,security-and-quality
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # v4.37.0
uses: github/codeql-action/analyze@7188fc363630916deb702c7fdcf4e481b751f97a # v4.37.1
with:
category: "/language:${{matrix.language}}"

View File

@@ -24,10 +24,10 @@ permissions:
jobs:
dependency-review:
if: github.event_name == 'pull_request'
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
steps:
- name: "Checkout Repository"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: "Dependency Review"
@@ -48,10 +48,10 @@ jobs:
python-dependency-liccheck:
# NOTE: Configuration for liccheck lives in our pyproject.yml.
# You cannot use a liccheck.ini file in this workflow.
runs-on: ubuntu-22.04
runs-on: ubuntu-26.04
steps:
- name: "Checkout Repository"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

View File

@@ -19,7 +19,7 @@ concurrency:
jobs:
changes:
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
timeout-minutes: 10
permissions:
contents: read
@@ -30,7 +30,7 @@ jobs:
docker: ${{ steps.check.outputs.docker }}
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Check for file changes
@@ -40,14 +40,14 @@ jobs:
token: ${{ secrets.GITHUB_TOKEN }}
setup_matrix:
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
timeout-minutes: 5
outputs:
matrix_config: ${{ steps.set_matrix.outputs.matrix_config }}
steps:
- id: set_matrix
run: |
MATRIX_CONFIG=$(if [ "${{ github.event_name }}" == "pull_request" ]; then echo '["dev", "lean"]'; else echo '["dev", "lean", "py310", "websocket", "dockerize", "py311", "py312"]'; fi)
MATRIX_CONFIG=$(if [ "${{ github.event_name }}" == "pull_request" ]; then echo '["dev", "lean"]'; else echo '["dev", "lean", "websocket", "dockerize", "py311", "py312"]'; fi)
echo "matrix_config=${MATRIX_CONFIG}" >> $GITHUB_OUTPUT
echo $GITHUB_OUTPUT
@@ -58,7 +58,7 @@ jobs:
needs.changes.outputs.python == 'true' ||
needs.changes.outputs.frontend == 'true' ||
needs.changes.outputs.docker == 'true'
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
timeout-minutes: 60
strategy:
matrix:
@@ -71,7 +71,7 @@ jobs:
steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
@@ -123,13 +123,20 @@ jobs:
# pull timeouts, 504/401 on push, ECONNRESET) that otherwise fail
# the whole job. buildx reuses the buildkit layer cache from the
# failed attempt, so a retry mostly re-does just the failed push.
#
# supersetbot's "dev"/"lean" presets pin their own --build-arg
# PY_VER, which lands ahead of --extra-flags on the assembled
# buildx command line; docker/buildx keeps the last value for a
# repeated --build-arg key, so appending PY_VER here overrides
# supersetbot's pin and keeps the build on the Dockerfile's own
# supported Python version.
for attempt in 1 2 3; do
if supersetbot docker \
$PUSH_OR_LOAD \
--preset "$BUILD_PRESET" \
--context "$EVENT" \
--context-ref "$RELEASE" $FORCE_LATEST \
--extra-flags "--build-arg INCLUDE_CHROMIUM=false --tag $IMAGE_TAG" \
--extra-flags "--build-arg PY_VER=3.11.14-slim-trixie --build-arg INCLUDE_CHROMIUM=false --tag $IMAGE_TAG" \
$PLATFORM_ARG; then
break
fi
@@ -173,11 +180,11 @@ jobs:
# goal is to check that building the latest image works, not required for all PR pushes
needs: changes
if: github.event_name == 'push' && github.ref == 'refs/heads/master' && needs.changes.outputs.docker == 'true'
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
timeout-minutes: 30
steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Free up disk space

View File

@@ -15,7 +15,7 @@ jobs:
# gate on. Restrict to the canonical repo: forks cannot mint a valid OIDC
# token for this package and must not publish.
if: github.repository == 'apache/superset'
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
permissions:
contents: read
id-token: write # required for npm trusted publishing (OIDC)
@@ -23,7 +23,7 @@ jobs:
run:
working-directory: superset-embedded-sdk
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
# Note: registry-url is intentionally omitted. When set, actions/setup-node
@@ -31,7 +31,7 @@ jobs:
# token, which makes npm attempt token auth and skip the OIDC
# trusted-publishing exchange. With no .npmrc auth line, npm authenticates
# via OIDC against the default registry (registry.npmjs.org).
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version-file: "./superset-embedded-sdk/.nvmrc"
- run: npm ci

View File

@@ -16,15 +16,15 @@ concurrency:
jobs:
embedded-sdk-test:
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
defaults:
run:
working-directory: superset-embedded-sdk
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version-file: "./superset-embedded-sdk/.nvmrc"
registry-url: "https://registry.npmjs.org"

View File

@@ -11,7 +11,7 @@ permissions:
jobs:
config:
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
outputs:
has-secrets: ${{ steps.check.outputs.has-secrets }}
steps:
@@ -29,15 +29,15 @@ jobs:
needs: config
if: needs.config.outputs.has-secrets
name: Generate Report
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
submodules: recursive
- name: Setup Java
uses: actions/setup-java@0f481fcb613427c0f801b606911222b5b6f3083a # v5.5.0
uses: actions/setup-java@03ad4de0992f5dab5e18fcb136590ce7c4a0ac95 # v5.6.0
with:
distribution: "temurin"
java-version: "11"

View File

@@ -19,7 +19,7 @@ concurrency:
jobs:
validate-all-ghas:
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
permissions:
contents: read
# Required for the zizmor action to upload its SARIF results to
@@ -27,12 +27,12 @@ jobs:
security-events: write
steps:
- name: Checkout Repository
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Set up Node.js
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: "20"
@@ -46,4 +46,4 @@ jobs:
run: bash .github/workflows/github-action-validator.sh
- name: Check for security issues on GHA workflows
uses: zizmorcore/zizmor-action@192e21d79ab29983730a13d1382995c2307fbcaa # v0.5.7
uses: zizmorcore/zizmor-action@6599ee8b7a49aef6a770f63d261d214911a7ce02 # v0.6.0

115
.github/workflows/hold-label-ci-gate.yml vendored Normal file
View File

@@ -0,0 +1,115 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
name: Hold Label CI Gate
on:
pull_request:
types: [labeled, unlabeled]
permissions: {}
jobs:
cancel-on-hold:
name: Cancel CI runs when hold label applied
if: github.event.action == 'labeled' && startsWith(github.event.label.name, 'hold')
runs-on: ubuntu-26.04
permissions:
actions: write
pull-requests: read
steps:
- name: Cancel in-progress workflow runs
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const { owner, repo } = context.repo;
const sha = context.payload.pull_request.head.sha;
const { data: { workflow_runs: runs } } =
await github.rest.actions.listWorkflowRunsForRepo({
owner,
repo,
head_sha: sha,
per_page: 100,
});
const active = runs.filter(r =>
['in_progress', 'queued', 'waiting', 'requested', 'pending'].includes(r.status)
);
core.info(`Found ${active.length} active run(s) to cancel for SHA ${sha}`);
for (const run of active) {
try {
await github.rest.actions.cancelWorkflowRun({
owner,
repo,
run_id: run.id,
});
core.info(`Cancelled run ${run.id} (${run.name})`);
} catch (err) {
core.warning(`Could not cancel run ${run.id}: ${err.message}`);
}
}
rerun-on-unhold:
name: Re-run CI when hold label removed
if: github.event.action == 'unlabeled' && startsWith(github.event.label.name, 'hold')
runs-on: ubuntu-24.04
permissions:
actions: write
pull-requests: read
steps:
- name: Re-trigger cancelled workflow runs
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const { owner, repo } = context.repo;
const sha = context.payload.pull_request.head.sha;
// Check that no other hold* labels remain on the PR
const labels = context.payload.pull_request.labels.map(l => l.name);
const stillHeld = labels.some(l => l.startsWith('hold'));
if (stillHeld) {
core.info('PR still has a hold label — skipping re-run.');
return;
}
const { data: { workflow_runs: runs } } =
await github.rest.actions.listWorkflowRunsForRepo({
owner,
repo,
head_sha: sha,
per_page: 100,
});
const cancelled = runs.filter(r => r.conclusion === 'cancelled');
core.info(`Found ${cancelled.length} cancelled run(s) to re-trigger for SHA ${sha}`);
for (const run of cancelled) {
try {
await github.rest.actions.reRunWorkflow({
owner,
repo,
run_id: run.id,
});
core.info(`Re-triggered run ${run.id} (${run.name})`);
} catch (err) {
core.warning(`Could not re-run ${run.id}: ${err.message}`);
}
}

View File

@@ -9,14 +9,14 @@ on:
jobs:
superbot-orglabel:
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
permissions:
contents: read
pull-requests: write
issues: write
steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

View File

@@ -12,9 +12,9 @@ jobs:
permissions:
contents: read
pull-requests: write
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
steps:
- uses: actions/labeler@b8dd2d9be0f68b860e7dae5dae7d772984eacd6d # v6.2.0
- uses: actions/labeler@bf12e9b00b37c5c0ca2b87b79b2daf7891dbda13 # v7.0.0
with:
sync-labels: true

View File

@@ -6,13 +6,13 @@ on:
jobs:
latest-release:
name: Add/update tag to new release
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
permissions:
contents: write
steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
submodules: recursive

View File

@@ -15,15 +15,15 @@ concurrency:
jobs:
license_check:
name: License Check
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
submodules: recursive
- name: Setup Java
uses: actions/setup-java@0f481fcb613427c0f801b606911222b5b6f3083a # v5.5.0
uses: actions/setup-java@03ad4de0992f5dab5e18fcb136590ce7c4a0ac95 # v5.6.0
with:
distribution: "temurin"
java-version: "11"

View File

@@ -17,7 +17,7 @@ concurrency:
jobs:
check-hold-label:
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
steps:
- name: Check for 'hold' label
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0

View File

@@ -8,20 +8,26 @@ on:
# Possible values: https://help.github.com/en/actions/reference/events-that-trigger-workflows#pull-request-event-pull_request
types: [opened, edited, reopened, synchronize]
# cancel previous workflow jobs for PRs
# Serialize runs per PR without cancelling: the `edited` trigger means a PR
# opened and then edited has two queued runs for the same head SHA. On
# first-time-contributor PRs those runs start together when a maintainer
# approves workflows, and cancel-in-progress lets the older run cancel the
# newer one — leaving a permanently-cancelled required check on the head SHA
# that blocks merging until manually re-run. This job takes seconds, so let
# queued runs complete instead.
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
cancel-in-progress: true
cancel-in-progress: false
jobs:
lint-check:
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
permissions:
contents: read
pull-requests: write
steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
submodules: recursive

View File

@@ -23,7 +23,7 @@ concurrency:
jobs:
pre-commit:
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
timeout-minutes: 20
strategy:
matrix:
@@ -33,7 +33,7 @@ jobs:
python-version: ${{ github.event_name == 'pull_request' && fromJSON('["current"]') || fromJSON('["current", "next"]') }}
steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
submodules: recursive
@@ -47,13 +47,13 @@ jobs:
python-version: ${{ matrix.python-version }}
- name: Setup Go
uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
- name: Install helm-docs
run: go install github.com/norwoodj/helm-docs/cmd/helm-docs@v1.14.2
- name: Setup Node.js
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version-file: "superset-frontend/.nvmrc"
cache: "npm"
@@ -81,7 +81,6 @@ jobs:
id: changed_files
env:
EVENT_NAME: ${{ github.event_name }}
BASE_SHA: ${{ github.event.pull_request.base.sha }}
BEFORE_SHA: ${{ github.event.before }}
run: |
set -euo pipefail
@@ -95,7 +94,15 @@ jobs:
# Resolve the commit to diff against.
base=""
if [ "${EVENT_NAME}" = "pull_request" ]; then
base="${BASE_SHA}"
# HEAD is the PR merge commit, so its first parent is the current
# tip of the base branch. github.event.pull_request.base.sha is
# NOT that: GitHub freezes it at PR creation, so on a long-lived
# PR it points at the original branch point and the diff picks up
# all of the base branch's churn since then — thousands of paths,
# enough for the CHANGED_FILES env var below to exceed the
# kernel's per-variable size limit and kill the step with
# "Argument list too long" before bash even starts.
base="$(git rev-parse HEAD^1 2>/dev/null || true)"
elif [ -n "${BEFORE_SHA:-}" ] && \
[ "${BEFORE_SHA}" != "0000000000000000000000000000000000000000" ]; then
base="${BEFORE_SHA}"
@@ -114,6 +121,15 @@ jobs:
# Files present in HEAD that changed since the base (drop deletions).
files="$(git diff --name-only --diff-filter=ACMRT "${base}...HEAD")"
# Env vars have a hard per-variable size limit (E2BIG at step
# start). A PR that legitimately touches thousands of files is
# better served by --all-files anyway.
if [ "$(printf '%s' "${files}" | wc -c)" -gt 100000 ]; then
echo "::notice::Changed-file list too large to pass via env; falling back to --all-files."
echo "mode=all" >> "$GITHUB_OUTPUT"
exit 0
fi
if [ -z "${files}" ]; then
echo "mode=none" >> "$GITHUB_OUTPUT"
else

View File

@@ -11,7 +11,7 @@ permissions:
jobs:
config:
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
outputs:
has-secrets: ${{ steps.check.outputs.has-secrets }}
steps:
@@ -29,11 +29,11 @@ jobs:
needs: config
if: needs.config.outputs.has-secrets
name: Bump version and publish package(s)
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
permissions:
contents: write
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
# pulls all commits (needed for lerna / semantic release to correctly version)
@@ -50,7 +50,7 @@ jobs:
- name: Install Node.js
if: env.HAS_TAGS
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version-file: "./superset-frontend/.nvmrc"

View File

@@ -40,7 +40,7 @@ concurrency:
jobs:
config:
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
outputs:
has-secrets: ${{ steps.check.outputs.has-secrets }}
latest-release: ${{ steps.latest.outputs.tag }}
@@ -93,16 +93,16 @@ jobs:
needs: config
if: needs.config.outputs.has-secrets == '1'
name: docker-rebuild
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
strategy:
# Mirror the same matrix the release publisher uses so every variant
# operators consume from Docker Hub gets the refreshed base.
matrix:
build_preset: ["dev", "lean", "py310", "websocket", "dockerize", "py311", "py312"]
build_preset: ["dev", "lean", "websocket", "dockerize", "py311", "py312"]
fail-fast: false
steps:
- name: "Checkout release tag: ${{ needs.config.outputs.latest-release }}"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ needs.config.outputs.latest-release }}
fetch-depth: 0
@@ -117,7 +117,7 @@ jobs:
build: "true"
- name: Use Node.js 20
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: 20
@@ -155,7 +155,7 @@ jobs:
notify-on-failure:
needs: [config, docker-rebuild]
if: failure() && needs.config.outputs.has-secrets == '1'
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
permissions:
contents: read
issues: write

View File

@@ -153,7 +153,7 @@ jobs:
- name: Checkout PR code (only if build needed)
if: steps.auth.outputs.authorized == 'true' && steps.check.outputs.build_needed == 'true'
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ steps.check.outputs.target_sha }}
persist-credentials: false

View File

@@ -19,7 +19,7 @@ concurrency:
jobs:
test-load-examples:
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
env:
PYTHONPATH: ${{ github.workspace }}
SUPERSET_CONFIG: tests.integration_tests.superset_test_config
@@ -41,7 +41,7 @@ jobs:
- 16379:6379
steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
submodules: recursive

View File

@@ -33,7 +33,7 @@ permissions:
jobs:
config:
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
outputs:
has-secrets: ${{ steps.check.outputs.has-secrets }}
steps:
@@ -57,21 +57,21 @@ jobs:
(github.event_name != 'workflow_run' ||
github.event.workflow_run.head_repository.full_name == github.repository)
name: Build & Deploy
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
steps:
- name: "Checkout ${{ github.event.workflow_run.head_sha || github.sha }}"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ github.event.workflow_run.head_sha || github.sha }}
persist-credentials: false
submodules: recursive
- name: Set up Node.js
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version-file: "./docs/.nvmrc"
- name: Setup Python
uses: ./.github/actions/setup-backend/
- uses: actions/setup-java@0f481fcb613427c0f801b606911222b5b6f3083a # v5.5.0
- uses: actions/setup-java@03ad4de0992f5dab5e18fcb136590ce7c4a0ac95 # v5.6.0
with:
distribution: "zulu"
java-version: "21"

View File

@@ -28,7 +28,7 @@ jobs:
name: Link Checking
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
# Do not bump this linkinator-action version without opening
@@ -67,18 +67,18 @@ jobs:
# Build docs when PR changes docs/** (uses committed databases.json)
if: github.event_name == 'pull_request'
name: Build (PR trigger)
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
defaults:
run:
working-directory: docs
steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
submodules: recursive
- name: Set up Node.js
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version-file: "./docs/.nvmrc"
- name: yarn install
@@ -106,19 +106,19 @@ jobs:
github.event.workflow_run.conclusion == 'success' &&
github.event.workflow_run.head_repository.full_name == github.repository
name: Build (after integration tests)
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
defaults:
run:
working-directory: docs
steps:
- name: "Checkout PR head: ${{ github.event.workflow_run.head_sha }}"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ github.event.workflow_run.head_sha }}
persist-credentials: false
submodules: recursive
- name: Set up Node.js
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version-file: "./docs/.nvmrc"
- name: yarn install

View File

@@ -28,7 +28,7 @@ concurrency:
jobs:
changes:
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
timeout-minutes: 10
permissions:
contents: read
@@ -38,7 +38,7 @@ jobs:
frontend: ${{ steps.check.outputs.frontend }}
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Check for file changes
@@ -50,8 +50,7 @@ jobs:
cypress-matrix:
needs: changes
if: (needs.changes.outputs.python == 'true' || needs.changes.outputs.frontend == 'true') && github.event.pull_request.draft == false
# Somehow one test flakes on 24.04 for unknown reasons, this is the only GHA left on 22.04
runs-on: ubuntu-22.04
runs-on: ubuntu-26.04
timeout-minutes: 30
permissions:
contents: read
@@ -97,21 +96,21 @@ jobs:
# Conditional checkout based on context
- name: Checkout for push or pull_request event
if: github.event_name == 'push' || github.event_name == 'pull_request'
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
submodules: recursive
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}
- name: Checkout using ref (workflow_dispatch)
if: github.event_name == 'workflow_dispatch' && github.event.inputs.ref != ''
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
ref: ${{ github.event.inputs.ref }}
submodules: recursive
- name: Checkout using PR ID (workflow_dispatch)
if: github.event_name == 'workflow_dispatch' && github.event.inputs.pr_id != ''
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
ref: refs/pull/${{ github.event.inputs.pr_id }}/merge
@@ -128,7 +127,7 @@ jobs:
with:
run: testdata
- name: Setup Node.js
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version-file: "./superset-frontend/.nvmrc"
cache: "npm"
@@ -173,7 +172,7 @@ jobs:
playwright-tests:
needs: changes
if: needs.changes.outputs.python == 'true' || needs.changes.outputs.frontend == 'true'
runs-on: ubuntu-22.04
runs-on: ubuntu-26.04
timeout-minutes: 30
permissions:
contents: read
@@ -207,21 +206,21 @@ jobs:
# Conditional checkout based on context (same as Cypress workflow)
- name: Checkout for push or pull_request event
if: github.event_name == 'push' || github.event_name == 'pull_request'
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
submodules: recursive
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}
- name: Checkout using ref (workflow_dispatch)
if: github.event_name == 'workflow_dispatch' && github.event.inputs.ref != ''
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
ref: ${{ github.event.inputs.ref }}
submodules: recursive
- name: Checkout using PR ID (workflow_dispatch)
if: github.event_name == 'workflow_dispatch' && github.event.inputs.pr_id != ''
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
ref: refs/pull/${{ github.event.inputs.pr_id }}/merge
@@ -238,7 +237,7 @@ jobs:
with:
run: playwright_testdata
- name: Setup Node.js
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version-file: "./superset-frontend/.nvmrc"
cache: "npm"
@@ -301,7 +300,7 @@ jobs:
cypress-matrix-required:
needs: [changes, cypress-matrix]
if: always()
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
timeout-minutes: 5
permissions: {}
steps:
@@ -323,7 +322,7 @@ jobs:
playwright-tests-required:
needs: [changes, playwright-tests]
if: always()
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
timeout-minutes: 5
permissions: {}
steps:

View File

@@ -19,7 +19,7 @@ concurrency:
jobs:
test-superset-extensions-cli-package:
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
timeout-minutes: 30
strategy:
matrix:
@@ -31,7 +31,7 @@ jobs:
working-directory: superset-extensions-cli
steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
submodules: recursive

View File

@@ -21,13 +21,13 @@ permissions:
jobs:
frontend-build:
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
timeout-minutes: 30
outputs:
should-run: ${{ steps.check.outputs.frontend }}
steps:
- name: Checkout Code
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
fetch-depth: 0
@@ -51,7 +51,7 @@ jobs:
git show -s --format=raw HEAD
docker buildx build \
-t $TAG \
--cache-from=type=registry,ref=apache/superset-cache:3.10-slim-trixie \
--cache-from=type=registry,ref=apache/superset-cache:3.11-slim-trixie \
--target superset-node-ci \
.
@@ -74,7 +74,7 @@ jobs:
matrix:
shard: [1, 2, 3, 4, 5, 6, 7, 8]
fail-fast: false
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
timeout-minutes: 20
steps:
- name: Download Docker Image Artifact
@@ -104,13 +104,13 @@ jobs:
report-coverage:
needs: [sharded-jest-tests]
if: needs.frontend-build.outputs.should-run == 'true'
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
timeout-minutes: 15
permissions:
id-token: write
steps:
- name: Checkout Code
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
fetch-depth: 0
@@ -146,7 +146,7 @@ jobs:
lint-frontend:
needs: frontend-build
if: needs.frontend-build.outputs.should-run == 'true'
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
timeout-minutes: 20
steps:
- name: Download Docker Image Artifact
@@ -171,7 +171,7 @@ jobs:
validate-frontend:
needs: frontend-build
if: needs.frontend-build.outputs.should-run == 'true'
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
timeout-minutes: 20
steps:
- name: Download Docker Image Artifact
@@ -191,7 +191,7 @@ jobs:
test-storybook:
needs: frontend-build
if: needs.frontend-build.outputs.should-run == 'true'
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
timeout-minutes: 25
steps:
- name: Download Docker Image Artifact

View File

@@ -2,24 +2,27 @@ name: "Helm: lint and test charts"
on:
pull_request:
types: [opened, edited, reopened, synchronize]
types: [opened, reopened, synchronize]
paths:
- "helm/**"
permissions:
contents: read
# cancel previous workflow jobs for PRs
# Serialize runs per PR without cancelling: when a first-time contributor's
# queued runs are approved together, cancel-in-progress lets an older run
# cancel a newer one, leaving a permanently-cancelled required check on the
# head SHA. Queued runs are cheap here, so let them all complete.
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
cancel-in-progress: true
cancel-in-progress: false
jobs:
lint-test:
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
submodules: recursive
@@ -28,7 +31,7 @@ jobs:
- name: Set up Helm
uses: azure/setup-helm@9bc31f4ebc9c6b171d7bfbaa5d006ae7abdb4310 # v5.0.1
with:
version: v3.16.4
version: v3.21.3
- name: Setup Python
uses: ./.github/actions/setup-backend/
@@ -56,3 +59,9 @@ jobs:
CT_LINT_CONF: lintconf.yaml
CT_SINCE: HEAD
CT_CHART_REPOS: bitnami=https://charts.bitnami.com/bitnami
- name: Set up helm-unittest
run: helm plugin install https://github.com/helm-unittest/helm-unittest --version v1.1.1
- name: Run helm-unittest
run: helm unittest helm/superset

View File

@@ -20,7 +20,7 @@ on:
jobs:
release:
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
permissions:
contents: write
pull-requests: write
@@ -29,7 +29,7 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ inputs.ref || github.ref_name }}
persist-credentials: true

View File

@@ -24,7 +24,7 @@ concurrency:
jobs:
changes:
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
timeout-minutes: 10
permissions:
contents: read
@@ -34,7 +34,7 @@ jobs:
frontend: ${{ steps.check.outputs.frontend }}
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Check for file changes
@@ -48,7 +48,7 @@ jobs:
playwright-tests-experimental:
needs: changes
if: needs.changes.outputs.python == 'true' || needs.changes.outputs.frontend == 'true'
runs-on: ubuntu-22.04
runs-on: ubuntu-26.04
timeout-minutes: 30
continue-on-error: true
permissions:
@@ -83,21 +83,21 @@ jobs:
# Conditional checkout based on context (same as Cypress workflow)
- name: Checkout for push or pull_request event
if: github.event_name == 'push' || github.event_name == 'pull_request'
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
submodules: recursive
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}
- name: Checkout using ref (workflow_dispatch)
if: github.event_name == 'workflow_dispatch' && github.event.inputs.ref != ''
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
ref: ${{ github.event.inputs.ref }}
submodules: recursive
- name: Checkout using PR ID (workflow_dispatch)
if: github.event_name == 'workflow_dispatch' && github.event.inputs.pr_id != ''
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
ref: refs/pull/${{ github.event.inputs.pr_id }}/merge
@@ -114,7 +114,7 @@ jobs:
with:
run: playwright_testdata
- name: Setup Node.js
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version-file: "./superset-frontend/.nvmrc"
cache: "npm"

View File

@@ -20,7 +20,7 @@ concurrency:
jobs:
changes:
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
timeout-minutes: 10
permissions:
contents: read
@@ -29,7 +29,7 @@ jobs:
python: ${{ steps.check.outputs.python }}
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Check for file changes
@@ -41,7 +41,7 @@ jobs:
test-mysql:
needs: changes
if: needs.changes.outputs.python == 'true'
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
timeout-minutes: 45
permissions:
id-token: write
@@ -72,7 +72,7 @@ jobs:
- 16379:6379
steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
submodules: recursive
@@ -127,7 +127,7 @@ jobs:
test-postgres:
needs: changes
if: needs.changes.outputs.python == 'true'
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
timeout-minutes: 45
permissions:
id-token: write
@@ -157,7 +157,7 @@ jobs:
- 16379:6379
steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
submodules: recursive
@@ -188,7 +188,7 @@ jobs:
test-sqlite:
needs: changes
if: needs.changes.outputs.python == 'true'
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
timeout-minutes: 45
permissions:
id-token: write
@@ -207,7 +207,7 @@ jobs:
- 16379:6379
steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
submodules: recursive
@@ -243,7 +243,7 @@ jobs:
test-postgres-required:
needs: [changes, test-postgres]
if: always()
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
timeout-minutes: 5
steps:
- name: Check test-postgres result

View File

@@ -16,7 +16,7 @@ concurrency:
jobs:
changes:
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
timeout-minutes: 10
permissions:
contents: read
@@ -25,7 +25,7 @@ jobs:
python: ${{ steps.check.outputs.python }}
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Check for file changes
@@ -37,7 +37,7 @@ jobs:
test-postgres-presto:
needs: changes
if: needs.changes.outputs.python == 'true'
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
timeout-minutes: 45
permissions:
id-token: write
@@ -72,7 +72,7 @@ jobs:
- 16379:6379
steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
submodules: recursive
@@ -100,7 +100,7 @@ jobs:
test-postgres-hive:
needs: changes
if: needs.changes.outputs.python == 'true'
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
timeout-minutes: 45
permissions:
id-token: write
@@ -127,7 +127,7 @@ jobs:
- 16379:6379
steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
submodules: recursive

View File

@@ -21,7 +21,7 @@ concurrency:
jobs:
changes:
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
timeout-minutes: 10
permissions:
contents: read
@@ -30,7 +30,7 @@ jobs:
python: ${{ steps.check.outputs.python }}
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Check for file changes
@@ -42,7 +42,7 @@ jobs:
unit-tests:
needs: changes
if: needs.changes.outputs.python == 'true'
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
timeout-minutes: 30
permissions:
id-token: write
@@ -61,7 +61,7 @@ jobs:
SQLALCHEMY_WARN_20: "1"
steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
submodules: recursive
@@ -99,7 +99,7 @@ jobs:
unit-tests-required:
needs: [changes, unit-tests]
if: always()
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
timeout-minutes: 5
steps:
- name: Check unit-tests result

View File

@@ -20,7 +20,7 @@ permissions:
jobs:
post-comment:
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
# Only act when the Translations workflow failed (which means a regression
# was detected — the workflow exits 1 on regression).
if: github.event.workflow_run.conclusion == 'failure'

View File

@@ -19,13 +19,13 @@ concurrency:
jobs:
frontend-check-translations:
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
permissions:
contents: read
pull-requests: read
steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
submodules: recursive
@@ -38,7 +38,7 @@ jobs:
- name: Setup Node.js
if: steps.check.outputs.frontend
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version-file: "./superset-frontend/.nvmrc"
cache: "npm"
@@ -55,13 +55,13 @@ jobs:
npm run build-translation
babel-extract:
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
permissions:
contents: read
pull-requests: read
steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
submodules: recursive

View File

@@ -21,15 +21,15 @@ concurrency:
jobs:
app-checks:
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
timeout-minutes: 20
steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Setup Node.js
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version-file: './superset-websocket/.nvmrc'
- name: Install dependencies

View File

@@ -15,7 +15,7 @@ on:
jobs:
supersetbot:
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
if: >
github.event_name == 'workflow_dispatch' ||
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '@supersetbot'))
@@ -38,7 +38,7 @@ jobs:
});
- name: "Checkout ( ${{ github.sha }} )"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

View File

@@ -27,7 +27,7 @@ jobs:
# zizmor: ignore[artipacked] - required persisted credentials to push synced requirement changes back to remote
- name: Checkout source code
if: ${{ steps.dependabot-metadata.outputs.package-ecosystem == 'pip' }}
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ github.event.pull_request.head.sha }}
persist-credentials: true

View File

@@ -32,7 +32,7 @@ concurrency:
jobs:
config:
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
outputs:
has-secrets: ${{ steps.check.outputs.has-secrets }}
steps:
@@ -50,17 +50,17 @@ jobs:
needs: config
if: needs.config.outputs.has-secrets
name: docker-release
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
permissions:
contents: write
strategy:
matrix:
build_preset:
["dev", "lean", "py310", "websocket", "dockerize", "py311", "py312"]
["dev", "lean", "websocket", "dockerize", "py311", "py312"]
fail-fast: false
steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
fetch-depth: 0
@@ -75,7 +75,7 @@ jobs:
- name: Use Node.js 20
# zizmor: ignore[cache-poisoning] - node only runs the supersetbot CLI; no dependency cache is enabled
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: 20
package-manager-cache: false
@@ -120,20 +120,20 @@ jobs:
update-prs-with-release-info:
needs: config
if: needs.config.outputs.has-secrets
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
permissions:
contents: read
pull-requests: write
steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
fetch-depth: 0
- name: Use Node.js 20
# zizmor: ignore[cache-poisoning] - node only runs the supersetbot CLI; no dependency cache is enabled
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: 20
package-manager-cache: false

View File

@@ -11,7 +11,7 @@ permissions:
jobs:
config:
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
outputs:
has-secrets: ${{ steps.check.outputs.has-secrets }}
steps:
@@ -28,16 +28,16 @@ jobs:
process-and-upload:
needs: config
if: needs.config.outputs.has-secrets
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
name: Generate Reports
steps:
- name: Checkout Repository
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Set up Node.js
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version-file: "./superset-frontend/.nvmrc"

View File

@@ -7,7 +7,7 @@ on:
jobs:
welcome:
runs-on: ubuntu-24.04
runs-on: ubuntu-26.04
if: github.event.pull_request.author_association == 'FIRST_TIME_CONTRIBUTOR'
permissions:
pull-requests: write

View File

@@ -31,9 +31,10 @@ repos:
types-simplejson,
types-python-dateutil,
types-requests,
# types-redis 4.6.0.5 is failing mypy
# because of https://github.com/python/typeshed/pull/10531
types-redis==4.6.0.4,
# types-redis is intentionally absent: redis-py ships its own
# bundled types (py.typed, since 4.6+/5.x), while the stub
# package is unmaintained (frozen at the 4.6.0.x API surface).
# Installing the stub would shadow the accurate inline types.
types-pytz,
types-croniter,
types-PyYAML,

View File

@@ -15,8 +15,8 @@
# limitations under the License.
#
# Python version installed; we need 3.10-3.11
PYTHON=`command -v python3.11 || command -v python3.10`
# Python version installed; we need 3.11-3.12
PYTHON=`command -v python3.11 || command -v python3.12`
.PHONY: install superset venv pre-commit up down logs ps nuke ports open
@@ -76,7 +76,7 @@ update-js:
venv:
# Create a virtual environment and activate it (recommended)
if ! [ -x "${PYTHON}" ]; then echo "You need Python 3.10 or 3.11 installed"; exit 1; fi
if ! [ -x "${PYTHON}" ]; then echo "You need Python 3.11 or 3.12 installed"; exit 1; fi
test -d venv || ${PYTHON} -m venv venv # setup a python3 virtualenv
. venv/bin/activate

View File

@@ -14,7 +14,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
FROM python:3.10-slim-trixie
FROM python:3.11-slim-trixie
RUN useradd --user-group --create-home --no-log-init --shell /bin/bash superset

View File

@@ -14,7 +14,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
FROM python:3.10-slim-trixie
FROM python:3.11-slim-trixie
RUN useradd --user-group --create-home --no-log-init --shell /bin/bash superset

View File

@@ -14,7 +14,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
FROM python:3.10-slim-trixie
FROM python:3.11-slim-trixie
ARG VERSION
RUN git clone --depth 1 --branch ${VERSION} https://github.com/apache/superset.git /superset

View File

@@ -14,7 +14,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
FROM python:3.10-slim-trixie
FROM python:3.11-slim-trixie
RUN apt-get update -y
RUN apt-get install -y \

View File

@@ -168,6 +168,11 @@ categories:
url: https://www.now.vn/
contributors: ["@davidkohcw"]
- name: Pattern
url: https://www.pattern.com
contributors: ["@alephys26", "@hladush", "@sanketjadhavSF"]
logo: pattern_logo.png
- name: Qunar
url: https://www.qunar.com/
contributors: ["@flametest"]

View File

@@ -24,6 +24,88 @@ assists people when migrating to a new version.
## Next
### Dashboard "Export Data to Excel" requires a Celery worker and S3 bucket
A new dashboard action exports every chart's data to a single multi-sheet
`.xlsx` asynchronously. It is disabled by default and turns on only when
`EXCEL_EXPORT_S3_BUCKET` is set (the endpoint returns `501` otherwise). It also
requires a running Celery worker and a configured SMTP transport, since the task
emails the requesting user a pre-signed download link. New config keys:
`EXCEL_EXPORT_S3_BUCKET`, `EXCEL_EXPORT_S3_KEY_PREFIX`,
`EXCEL_EXPORT_LINK_TTL_SECONDS`, `EXCEL_EXPORT_S3_CLIENT_KWARGS`, and
`EXCEL_EXPORT_TABLE_VIZ_TYPES`.
The feature depends on `boto3`, which is **not** installed by default; install it
with `pip install apache-superset[excel-export]`.
A second mode, **Export Images to Excel**, embeds non-table charts as rendered
images (which viz types stay tabular is controlled by
`EXCEL_EXPORT_TABLE_VIZ_TYPES`). It renders through the headless webdriver, so the
menu option only appears when the webdriver screenshot feature flags
(`ENABLE_DASHBOARD_SCREENSHOT_ENDPOINTS`,
`ENABLE_DASHBOARD_DOWNLOAD_WEBDRIVER_SCREENSHOT`) are enabled.
Deployments that override `CELERY_CONFIG` must add
`"superset.tasks.export_dashboard_excel"` to their `imports` tuple, or the task
will not register and exports will silently never run.
### SQL_QUERY_MUTATOR now honors MUTATE_AFTER_SPLIT in SQL Lab
SQL Lab now applies `SQL_QUERY_MUTATOR` according to `MUTATE_AFTER_SPLIT`, matching the documented semantics and the chart/query path. This only affects deployments that define `SQL_QUERY_MUTATOR` in `superset_config.py`:
- With `MUTATE_AFTER_SPLIT = True`, the mutator previously never ran in SQL Lab; it now runs on each individual statement (including on engines like BigQuery and Kusto that execute multiple statements as one block, where each statement is mutated before the statements are joined).
- With `MUTATE_AFTER_SPLIT = False` (the default), multi-statement SQL Lab queries previously applied the mutator to each statement separately; the mutator now runs once on the whole un-split query, as documented. Single-statement queries are unaffected.
- With `MUTATE_AFTER_SPLIT = False` on engines that execute statements individually, the mutator's output is re-parsed to split it into statements. A mutator that emits SQL Superset's parser cannot parse will now fail with a clear parse error before execution, and one that strips a query down to nothing raises an invalid-SQL error instead of executing an empty query.
### Python 3.10 support removed
Python 3.10 is no longer supported. Superset now requires **Python 3.11 or higher**.
Update your environment (virtualenv, Docker base image, CI configuration, etc.) to
Python 3.11+ before upgrading. The `apache/superset-cache:3.10-slim-trixie` and
`py310` Docker image variants are no longer published.
### `from_dttm` and `to_dttm` Jinja template variables removed
The `{{ from_dttm }}` and `{{ to_dttm }}` Jinja template variables, deprecated since
v5.0, have been removed from the Jinja context and are no longer available in virtual
dataset SQL or custom SQL expressions.
Replace usages with the `get_time_filter()` function. For example:
```sql
-- Before
SELECT * FROM tbl
WHERE dttm_col > '{{ from_dttm }}' AND dttm_col < '{{ to_dttm }}'
-- After
{% set tf = get_time_filter("dttm_col") %}
SELECT * FROM tbl
WHERE dttm_col > {{ tf.from_expr }} AND dttm_col <= {{ tf.to_expr }}
```
Note that `from_expr` and `to_expr` are already fully-formatted SQL expressions (e.g.
`TO_TIMESTAMP('2024-01-01', ...)`) — do not wrap them in single quotes.
### Removed deck.gl JavaScript tooltip/data-mutator controls and ENABLE_JAVASCRIPT_CONTROLS
The `ENABLE_JAVASCRIPT_CONTROLS` feature flag and the deck.gl chart controls it gated
(`js_tooltip`, `js_onclick_href`, `js_data_mutator`, and the GeoJSON layer's label/icon
JavaScript-mode generators) have been removed. These controls let users write arbitrary
JavaScript, sandboxed via Node's `vm` module, to customize deck.gl tooltips, click
behavior, and data transforms; the flag defaulted off and the feature saw negligible use.
The deck.gl "Extra data for JS" control (`js_columns`) has also been removed. It only
ever existed to feed extra columns into the JavaScript controls above; deck.gl's
built-in field-based tooltips and cross-filtering already pull in any columns they need
via `tooltip_contents`/`cross_filter_column`, so this control had no remaining purpose.
Any chart layer whose "Advanced" control panel section only contained this control no
longer has an "Advanced" section.
Any saved charts with these fields set will simply ignore them going forward and fall back
to deck.gl's built-in field-based tooltips (`tooltip_contents`/`tooltip_template`) and
native click/cross-filter behavior. No migration is required; the fields are dropped
silently on next save.
### Owners, dashboard roles, and RLS roles replaced by Subjects
Superset now uses subject-based access assignments for dashboards, charts, datasets,
@@ -112,6 +194,8 @@ in a later major version.
- [41044](https://github.com/apache/superset/issues/41044): Removes the deprecated `AVOID_COLORS_COLLISION` feature flag (it defaulted to `True`). Color-collision avoidance is now permanently enabled; any config override setting it to `False` is ignored.
- [41813](https://github.com/apache/superset/pull/41813): `redis` (the Python client, `redis-py`) is bumped from 5.3.1 to 8.0.1. redis-py 8 changes several connection defaults; Superset's own Redis-backed features (`GLOBAL_ASYNC_QUERIES_CACHE_BACKEND`, `DISTRIBUTED_COORDINATION_CONFIG`, and the MCP Redis store) explicitly pin the pre-upgrade behavior so this bump is a no-op for them: the wire protocol stays RESP2 (not the new RESP3 default, which requires Redis/Sentinel 6+ to speak `HELLO`) and there is still no socket timeout by default (redis-py 8 defaults to 5s, which could otherwise newly time out large cached payloads or slow networks). The no-timeout default can now be overridden via two new config keys, `CACHE_REDIS_SOCKET_TIMEOUT` / `CACHE_REDIS_SOCKET_CONNECT_TIMEOUT`, on any `CacheConfig` dict using `CACHE_TYPE: RedisCache` or `RedisSentinelCache`. Separately, redis-py 6+ changed the default for `ssl_check_hostname` from `False` to `True` for SSL connections using `ssl_cert_reqs="required"` (the default) — this is a security improvement, so it has **not** been reverted; deployments with `CACHE_REDIS_SSL=True` whose certificates lack a hostname matching the connection address should set `CACHE_REDIS_SSL_CERT_REQS="none"` (disables cert verification entirely, matching hostname-check bypass) or replace the certificate. General-purpose cache/results backends configured via `CACHE_CONFIG` / `DATA_CACHE_CONFIG` / `RESULTS_BACKEND` with `CACHE_TYPE: RedisCache` go through `flask-caching`'s own Redis backend (outside Superset's code) and are subject to the same new defaults; pass `socket_timeout` / `protocol` via `CACHE_OPTIONS` there if needed. Celery broker and result-backend connections (built by `kombu`, also outside Superset's code) keep their no-socket-timeout behavior (`kombu` passes `socket_timeout=None` explicitly) but do **not** pin the wire protocol, so they follow redis-py's RESP3 default — which requires a Redis server new enough to speak `HELLO` (Redis 6+). Deployments using a pre-6.0 Redis server (EOL) as a Celery broker should upgrade the server before taking this bump.
- [39925](https://github.com/apache/superset/pull/39925): URL prefixing for `SUPERSET_APP_ROOT` subdirectory deployments is now handled automatically by helpers in `src/utils/navigationUtils` (`openInNewTab`, `redirect`, `getShareableUrl`, `<AppLink>`). Direct imports of `ensureAppRoot` / `makeUrl` from `src/utils/pathUtils` are forbidden outside `navigationUtils.ts` (enforced by a static-invariant test); contributors writing new code should use the focused helpers instead. No runtime behaviour change for existing callers — all 19 prior call sites have been migrated and four pre-existing double-prefix and missing-prefix bugs are fixed as part of the migration.
- [39925](https://github.com/apache/superset/pull/39925): `SupersetClient.getUrl()` now strips a single leading application-root segment from the supplied `endpoint` before building the request URL, so a caller that accidentally pre-prefixes its endpoint (for example by wrapping it with `ensureAppRoot` before passing it to the client) no longer produces a doubled `/superset/superset/...` URL under subdirectory deployment. The strip is **single-pass** — a genuine `/superset/superset/<slug>` route is preserved, not collapsed — and **silent** (no console warning); the static-invariant test remains the primary signal for pre-prefixing at the call site, and this runtime strip is a safety net beneath it. Code that intentionally targeted a literal `/<app_root>/<app_root>/...` endpoint through `getUrl` (a configuration that has no legitimate use under the prefixing model) would have its first redundant segment removed.
@@ -204,6 +288,22 @@ The pivot table chart's `First` and `Last` aggregations now return the first and
The `error` and `response` parameters of the `retryDelay` and `retryOn` callbacks in `FetchRetryOptions` (exported from `@superset-ui/core`) are now typed `Error | null` and `Response | null` to match the actual call-site signature provided by `fetch-retry`. Because these parameter types are contravariant, consumers who typed their callbacks with the non-nullable `(attempt: number, error: Error, response: Response) => number` will get a TypeScript compile error. Widen your callback signatures to accept `Error | null` / `Response | null`.
### Pivot Table totals are now computed by the database (per-metric "Aggregation function" control removed)
Pivot Table subtotals and grand totals are now computed by the database at each
rollup level instead of re-aggregating the already-aggregated cell values on the
client. This fixes long-standing incorrect totals for non-additive metrics
(ratios such as `SUM(a)/SUM(b)`, `COUNT_DISTINCT`, `AVG`, percentiles, etc.),
which previously summed the displayed cell values.
As a result the per-table **"Aggregation function"** control (which let you pick
how totals were aggregated client-side, e.g. Sum/Average/Count) has been
removed: totals now always reflect the metric's own definition evaluated at the
total's granularity. For additive metrics (`SUM`/`COUNT`/`MIN`/`MAX`) the result
is unchanged. Saved charts that set `aggregateFunction` will ignore it; no
migration is required. If you previously relied on a plain sum-of-cells total
for a non-additive metric, that specific behavior is no longer available.
### `thumbnail_url` removed from dashboard list API response
The `thumbnail_url` field has been removed from `GET /api/v1/dashboard/` list responses. External consumers relying on this field must now construct the thumbnail URL client-side using `id` and `changed_on_utc`:
@@ -214,6 +314,12 @@ The `thumbnail_url` field has been removed from `GET /api/v1/dashboard/` list re
The thumbnail endpoint redirects to the current digest URL regardless of whether the supplied digest is exact. If the image is not yet cached, that digest URL may return `202` and trigger async generation. Using `changed_on_utc` as the digest is sufficient for cache-busting purposes.
### Dashboard import can overwrite related charts, datasets, and databases
Re-importing an existing dashboard previously overwrote only the dashboard itself; its related charts, datasets, and databases were never updated (the importer hardcoded `overwrite=False` for them). They can now be overwritten as part of the import.
A new `overwrite_all` form field controls this, and defaults to `false` everywhere, so existing behavior is preserved: passing `overwrite=true` alone still overwrites only the dashboard, exactly as before. To also overwrite the related charts, datasets, and databases on the `/api/v1/dashboard/import/` endpoint, pass `overwrite_all=true` explicitly. The import modal in the UI exposes this as an "also overwrite all assets" checkbox, and the CLI `superset import-dashboards` and the `ImportDashboardsCommand` likewise default `overwrite_all` to `false`.
### Tagging fix for `create_all`-bootstrapped schemas
Only affects deployments whose metadata schema was created with SQLAlchemy's `create_all` (rather than `superset db upgrade`) on a foreign-key-enforcing backend — PostgreSQL, or MySQL with `FOREIGN_KEY_CHECKS=1`. Such schemas carry three invalid foreign keys on `tagged_object.object_id` that break tagging (`TAGGING_SYSTEM = True`) with a `ForeignKeyViolation`. Schemas built via `superset db upgrade` are unaffected.
@@ -239,6 +345,19 @@ A few save- and import-path internals change **unconditionally** (independent of
These are behavior changes that take effect on upgrade regardless of `ENABLE_VERSIONING_CAPTURE`; no operator action is required.
### Cross-entity version activity stream
A read-only companion to the version-history endpoints: each entity type gains a `GET /api/v1/{chart,dashboard,dataset}/<uuid>/activity/` endpoint returning a chronological, access-filtered stream of edits — the entity's own edits plus, for charts and dashboards, transitive edits to related entities during their association windows. Datasets have no related layer in V2, so `include=related` returns an empty stream for a dataset and `include=all` reduces to the dataset's own edits.
| Param | Type | Default | Purpose |
|---|---|---|---|
| `since` / `until` | ISO 8601 | — | Bound `issued_at` |
| `include` | `self` \| `related` \| `all` | `all` | Own edits, related edits, or both |
| `q` | string | — | Case-insensitive search over the full history, applied before pagination (so `count` reflects matches) |
| `page` / `page_size` | integer | `0` / `25` | Pagination (`page_size` clamped to 200) |
Authorization reuses the resource's `can_read` permission and per-object `raise_for_access`; related-entity rows are visibility-filtered to what the caller may see. The stream is empty unless version capture is on (`ENABLE_VERSIONING_CAPTURE`).
### Webhook alerts/reports block private/internal hosts by default
Webhook alert/report dispatch (`WebhookNotification.send`) now validates the target URL's host against the same private/internal-IP block applied to dataset import URLs. If the resolved host is in a loopback, link-local, private (RFC-1918), shared-CGNAT, or multicast range, the webhook is rejected with `NotificationParamException`.
@@ -491,6 +610,12 @@ The partial-index replacement is dialect-dependent: PostgreSQL uses a native `WH
**Importer behavior:** importing a dashboard YAML whose UUID matches an existing **soft-deleted** dashboard is treated as an implicit restore-with-update — **and this happens even when `overwrite` is not set**. This is a deliberate asymmetry with active rows: an active dashboard imported without `overwrite=true` is returned unchanged (the import never mutates it), but a soft-deleted UUID match is restored *and* has the upload's contents applied regardless of the `overwrite` argument, on the reasoning that re-importing a deleted dashboard's exact UUID is an explicit request to bring it back. The restore preserves the original PK and all pre-deletion relationship rows (`dashboard_slices` junctions, editor/viewer subjects, tags). Callers whose imports must never mutate existing state should treat bundles that may contain previously deleted UUIDs accordingly. The operation is permission-gated: it requires `can_write` and editorship of the deleted row (or admin) — non-editors get `ImportFailedError`, and callers without `can_write` get `ImportFailedError` instead of silently receiving the soft-deleted row.
### Engine spec capability flag: `supports_offset`
A new `BaseEngineSpec.supports_offset` attribute (default `True`) indicates whether a database engine supports the SQL `OFFSET` clause. Engines that do not support `OFFSET` — such as Elasticsearch SQL and OpenDistro — opt out by setting it to `False`, and Superset uses each engine's cursor API to paginate drill-to-detail samples instead of emitting `OFFSET`. Downstream forks maintaining custom engine specs may set the flag to `False` (and implement `fetch_data_with_cursor`) to avoid crashes when paginated drill-to-detail queries are run against engines without `OFFSET` support.
**Note on deep-pagination cost:** Cursor-based engines (including Elasticsearch and OpenDistro) are forward-only, so reaching page `N` of a drill-to-detail view issues `N` round trips to the cluster. Deep pagination is therefore linear in page number; users paginating into the hundreds or thousands will notice added latency compared to `OFFSET`-capable engines.
### Granular Export Controls
A new feature flag `GRANULAR_EXPORT_CONTROLS` introduces three fine-grained permissions that replace the legacy `can_csv` permission:
@@ -527,6 +652,10 @@ Added a new combined datasource list endpoint at `GET /api/v1/datasource/` to se
The minimum required version of `clickhouse-connect` has been raised to `>=0.13.0`. If you are using the ClickHouse connector, please upgrade your `clickhouse-connect` package. The `_mutate_label` workaround that appended hash suffixes to column aliases has also been removed, as it is no longer needed with modern versions of the driver.
### Kenya Country Map: Updated Administrative Divisions
The Kenya country map has been updated to reflect the 47 counties established under Kenya's 2010 constitution, replacing the outdated 8-province boundaries from the Natural Earth dataset. County keys now use ISO 3166-2:KE codes (`KE-01` through `KE-47`), replacing the former province codes (`KE-110`, `KE-200`, ..., `KE-800`). Dashboards that join on the old province codes will need to re-key their datasets to use the new county codes.
### MCP Tool Observability
MCP (Model Context Protocol) tools now include enhanced observability instrumentation for monitoring and debugging:
@@ -735,6 +864,7 @@ See `superset/mcp_service/PRODUCTION.md` for deployment guides.
---
- [38358](https://github.com/apache/superset/pull/38358): Switched CrateDB PyPI package from `crate[sqlalchemy]` to `sqlalchemy-cratedb`.
- [35621](https://github.com/apache/superset/pull/35621): The default hash algorithm has changed from MD5 to SHA-256 for improved security and FedRAMP compliance. This affects cache keys for thumbnails, dashboard digests, chart digests, and filter option names. Existing cached data will be invalidated upon upgrade. To opt out of this change and maintain backward compatibility, set `HASH_ALGORITHM = "md5"` in your `superset_config.py`.
- [35062](https://github.com/apache/superset/pull/35062): Changed the function signature of `setupExtensions` to `setupCodeOverrides` with options as arguments.

View File

@@ -71,7 +71,7 @@ x-common-build: &common-build
context: .
target: ${SUPERSET_BUILD_TARGET:-dev} # can use `dev` (default) or `lean`
cache_from:
- apache/superset-cache:3.10-slim-trixie
- apache/superset-cache:3.11-slim-trixie
args:
DEV_MODE: "true"
INCLUDE_CHROMIUM: ${INCLUDE_CHROMIUM:-false}

View File

@@ -33,7 +33,7 @@ x-common-build: &common-build
context: .
target: dev
cache_from:
- apache/superset-cache:3.10-slim-trixie
- apache/superset-cache:3.11-slim-trixie
services:
redis:

View File

@@ -38,7 +38,7 @@ x-common-build: &common-build
context: .
target: ${SUPERSET_BUILD_TARGET:-dev} # can use `dev` (default) or `lean`
cache_from:
- apache/superset-cache:3.10-slim-trixie
- apache/superset-cache:3.11-slim-trixie
args:
DEV_MODE: "true"
INCLUDE_CHROMIUM: ${INCLUDE_CHROMIUM:-false}

View File

@@ -87,6 +87,7 @@ class CeleryConfig:
"superset.tasks.scheduler",
"superset.tasks.thumbnails",
"superset.tasks.cache",
"superset.tasks.export_dashboard_excel",
)
result_backend = f"redis://{REDIS_HOST}:{REDIS_PORT}/{REDIS_RESULTS_DB}"
worker_prefetch_multiplier = 1

View File

@@ -149,10 +149,10 @@ database engine on a separate host or container.
Superset supports the following database engines/versions:
| Database Engine | Supported Versions |
| ----------------------------------------- | ---------------------------------------- |
| [PostgreSQL](https://www.postgresql.org/) | 10.X, 11.X, 12.X, 13.X, 14.X, 15.X, 16.X |
| [MySQL](https://www.mysql.com/) | 5.7, 8.X |
| Database Engine | Supported Versions |
| ----------------------------------------- | ---------------------------------------------- |
| [PostgreSQL](https://www.postgresql.org/) | 10.X, 11.X, 12.X, 13.X, 14.X, 15.X, 16.X, 17.X |
| [MySQL](https://www.mysql.com/) | 5.7, 8.X |
Use the following database drivers and connection strings:

View File

@@ -25,6 +25,33 @@ DECKGL_BASE_MAP = [
]
```
[Yandex Tiles API](https://yandex.ru/maps-api/docs/tiles-api/request.html) can be used as a custom tile provider. The URL must include the `apikey` from the [Yandex Developer Dashboard](https://developer.tech.yandex.ru/services), tile coordinates (`x`, `y`, and `z`), and the required map layer parameters.
```python
DECKGL_BASE_MAP = [
[
"tile://https://tiles.api-maps.yandex.ru/v1/tiles/"
"?apikey=YOUR_YANDEX_API_KEY"
"&lang=ru_RU"
"&x={x}&y={y}&z={z}"
"&l=map"
"&projection=web_mercator"
"&maptype=map",
"Yandex Maps - Web Mercator",
],
[
"tile://https://tiles.api-maps.yandex.ru/v1/tiles/"
"?apikey=YOUR_YANDEX_API_KEY"
"&lang=ru_RU"
"&x={x}&y={y}&z={z}"
"&l=map"
"&projection=wgs84_mercator"
"&maptype=map",
"Yandex Maps - WGS84 Mercator",
],
]
```
Default values are:
```python
DECKGL_BASE_MAP = [
@@ -56,6 +83,7 @@ CORS_OPTIONS: dict[Any, Any] = {
"https://tile.openstreetmap.org",
"https://tile.osm.ch",
"https://your_personal_url/{z}/{x}/{y}.png",
"https://tiles.api-maps.yandex.ru",
]
}
@@ -72,6 +100,7 @@ TALISMAN_CONFIG = {
"https://tile.openstreetmap.org",
"https://tile.osm.ch",
"https://your_personal_url/{z}/{x}/{y}.png",
"https://tiles.api-maps.yandex.ru",
],
...
}

View File

@@ -99,7 +99,7 @@ See [Connecting AI Clients](#connecting-ai-clients) for Claude Code, Claude Web,
## Prerequisites
- Apache Superset 5.0+ running and accessible
- Python 3.10+
- Python 3.11+
- The `fastmcp` package (`pip install fastmcp`)
---

View File

@@ -39,8 +39,6 @@ made available in the Jinja context:
- `columns`: columns which to group by in the query
- `filter`: filters applied in the query
- `from_dttm`: start `datetime` value from the selected time range (`None` if undefined). **Note:** Only available in virtual datasets when a time range filter is applied in Explore/Chart views—not available in standalone SQL Lab queries. (deprecated beginning in version 5.0, use `get_time_filter` instead)
- `to_dttm`: end `datetime` value from the selected time range (`None` if undefined). **Note:** Only available in virtual datasets when a time range filter is applied in Explore/Chart views—not available in standalone SQL Lab queries. (deprecated beginning in version 5.0, use `get_time_filter` instead)
- `groupby`: columns which to group by in the query (deprecated)
- `metrics`: aggregate expressions in the query
- `row_limit`: row limit of the query
@@ -49,85 +47,26 @@ made available in the Jinja context:
- `time_column`: temporal column of the query (`None` if undefined)
- `time_grain`: selected time grain (`None` if undefined)
For example, to add a time range to a virtual dataset, you can write the following:
For example, to add a time range to a virtual dataset, use the `get_time_filter` macro:
```sql
{% set tf = get_time_filter("dttm_col") %}
SELECT *
FROM tbl
WHERE dttm_col > '{{ from_dttm }}' and dttm_col < '{{ to_dttm }}'
WHERE dttm_col > {{ tf.from_expr }} AND dttm_col <= {{ tf.to_expr }}
```
You can also use [Jinja's logic](https://jinja.palletsprojects.com/en/2.11.x/templates/#tests)
to make your query robust to clearing the timerange filter:
```sql
SELECT *
FROM tbl
WHERE (
{% if from_dttm is not none %}
dttm_col > '{{ from_dttm }}' AND
{% endif %}
{% if to_dttm is not none %}
dttm_col < '{{ to_dttm }}' AND
{% endif %}
1 = 1
)
```
The `1 = 1` at the end ensures a value is present for the `WHERE` clause even when
the time filter is not set. For many database engines, this could be replaced with `true`.
Note that the Jinja parameters are called within _double_ brackets in the query and with
_single_ brackets in the logic blocks.
### Understanding Context Availability
Some Jinja variables like `from_dttm`, `to_dttm`, and `filter` are **only available when a chart or dashboard provides them**. They are populated from:
Some Jinja variables like `filter` are **only available when a chart or dashboard provides them**. They are populated from:
- Time range filters applied in Explore/Chart views
- Dashboard native filters
- Filter components
**These variables are NOT available in standalone SQL Lab queries** because there's no filter context. If you try to use `{{ from_dttm }}` directly in SQL Lab, you'll get an "undefined parameter" error.
#### Testing Time-Filtered Queries in SQL Lab
To test queries that use time variables in SQL Lab, you have several options:
**Option 1: Use Jinja defaults (recommended)**
```sql
SELECT *
FROM tbl
WHERE dttm_col > '{{ from_dttm | default("2024-01-01", true) }}'
AND dttm_col < '{{ to_dttm | default("2024-12-31", true) }}'
```
**Option 2: Use SQL Lab Parameters**
Set parameters in the SQL Lab UI (Parameters menu):
```json
{
"from_dttm": "2024-01-01",
"to_dttm": "2024-12-31"
}
```
**Option 3: Use `{% set %}` for testing**
```sql
{% set from_dttm = "2024-01-01" %}
{% set to_dttm = "2024-12-31" %}
SELECT *
FROM tbl
WHERE dttm_col > '{{ from_dttm }}' AND dttm_col < '{{ to_dttm }}'
```
:::tip
When you save a SQL Lab query as a virtual dataset and use it in a chart with time filters,
the actual filter values will override any defaults or test values you set.
:::
To add custom functionality to the Jinja context, you need to overload the default Jinja
context in your environment by defining the `JINJA_CONTEXT_ADDONS` in your superset configuration
(`superset_config.py`). Objects referenced in this dictionary are made available for users to use
@@ -479,10 +418,13 @@ Here's a concrete example:
### Time Filter
The `{{ get_time_filter() }}` macro returns the time filter applied to a specific column. This is useful if you want
to handle time filters inside the virtual dataset, as by default the time filter is placed on the outer query. This can
considerably improve performance, as many databases and query engines are able to optimize the query better
if the temporal filter is placed on the inner query, as opposed to the outer query.
The `{{ get_time_filter() }}` macro is the standard way to reference the selected time range
in a virtual dataset. It returns a `TimeFilter` object whose `from_expr` and `to_expr`
properties are fully-formatted SQL expressions for the start and end of the range — use them
directly in your `WHERE` clause without quoting.
Placing the filter inside the virtual dataset (rather than relying on it being applied to
the outer query) also gives many database engines the opportunity to optimize the query better.
The macro takes the following parameters:

View File

@@ -379,7 +379,7 @@ functioning across environments.
Make sure your machine meets the [OS dependencies](https://superset.apache.org/docs/installation/pypi#os-dependencies) before following these steps.
You also need to install MySQL.
Ensure that you are using Python version 3.9, 3.10 or 3.11, then proceed with:
Ensure that you are using Python version 3.11 or 3.12, then proceed with:
```bash
# Create a virtual environment and activate it (recommended)

View File

@@ -82,7 +82,7 @@ If applicable, add screenshots or recordings.
### Environment
- Superset version: [e.g., 3.0.0]
- Python version: [e.g., 3.9.7]
- Python version: [e.g., 3.11.7]
- Node version: [e.g., 18.17.0]
- Database: [e.g., PostgreSQL 14]
- Browser: [e.g., Chrome 120]
@@ -125,7 +125,7 @@ No error messages in browser console or server logs.
### Environment
- Superset version: 3.0.0
- Python version: 3.9.16
- Python version: 3.11.16
- Database: PostgreSQL 14.9
- Browser: Chrome 120.0.6099.71
- OS: macOS 14.2

View File

@@ -163,10 +163,6 @@ The architecture leverages Webpack's Module Federation to enable dynamic loading
Extensions configure Webpack to expose their entry points:
```javascript
externalsType: 'window',
externals: {
'@apache-superset/core': 'superset',
},
plugins: [
new ModuleFederationPlugin({
name: 'my_extension',
@@ -178,6 +174,7 @@ plugins: [
react: { singleton: true, import: false },
'react-dom': { singleton: true, import: false },
antd: { singleton: true, import: false },
'@apache-superset/core': { singleton: true, import: false },
},
}),
]
@@ -187,9 +184,7 @@ This configuration does several important things:
**`exposes`** - Declares which modules are available to the host application. Superset always loads extensions by requesting the `./index` module from the remote container — this is a fixed convention, not a configurable value. Extensions must expose exactly `'./index': './src/index.tsx'` and place all API registrations (views, commands, menus, editors, event listeners) in that file. The module is executed as a side effect when the extension loads, so any call to `views.registerView`, `commands.registerCommand`, etc. made at the top level of `index.tsx` will run automatically.
**`externals` and `externalsType`** - Tell Webpack that when the extension imports `@apache-superset/core`, it should use `window.superset` at runtime instead of bundling its own copy. This ensures extensions use the host's implementation of shared packages.
**`shared`** - Prevents duplication of common libraries like React and Ant Design. The `singleton: true` setting ensures only one instance of each library exists, avoiding version conflicts and reducing bundle size.
**`shared`** - Prevents duplication of common libraries like React and Ant Design, and, for `@apache-superset/core`, is the mechanism that gives each extension an isolated context (see below). The `singleton: true` setting ensures only one *logical* instance of each library exists — for `react`/`react-dom`/`antd` that means the host's actual instance is reused; for `@apache-superset/core` it means the extension's container defers to whatever module the host's loader supplies for it at init time, which is not the same object for every extension (see [Runtime Resolution](#runtime-resolution)).
### Runtime Resolution
@@ -200,25 +195,30 @@ The following diagram illustrates the module loading process:
Here's what happens at runtime:
1. **Extension Registration**: When an extension is registered, Superset stores its remote entry URL
2. **Dynamic Loading**: When the extension is activated, the host fetches the remote entry file
3. **Module Resolution**: The extension imports `@apache-superset/core`, which resolves to `window.superset`
4. **Execution**: The extension code runs with access to the host's APIs and shared dependencies
2. **Dynamic Loading**: When the extension is activated, the host fetches the remote entry file, then initializes Module Federation sharing (`__webpack_init_sharing__`) and looks up the extension's container on `window`
3. **Per-Extension Scope Injection**: Before calling `container.init()`, the loader builds a **per-container copy** of the webpack share scope in which the `@apache-superset/core` entry is replaced with a synthetic module — a copy of the host's own `window.superset` implementations with `extensions.getContext` bound to that one extension's isolated context object. Because Module Federation caches the resolved module per container, every import of `@apache-superset/core` inside that extension resolves to this pre-bound copy for the lifetime of the container, and because each container gets its own independent scope object, extensions loading in parallel cannot see each other's context.
4. **Execution**: The extension code runs with access to the host's APIs (via its per-extension `@apache-superset/core` instance) and shared dependencies (`react`, `react-dom`, `antd`)
### Host API Setup
On the Superset side, the APIs are mapped to `window.superset` during application bootstrap:
On the Superset side, the real implementations backing `@apache-superset/core` (`commands`, `views`, `menus`, `extensions`, etc.) are assigned onto `window.superset` during application bootstrap, once the current user is known:
```typescript
// eslint-disable-next-line no-restricted-syntax
import * as supersetCore from '@apache-superset/core';
import { commands, views, menus, extensions /* ... */ } from 'src/core';
export default function setupExtensionsAPI() {
window.superset = {
...supersetCore,
};
}
window.superset = {
...supersetCore,
commands,
views,
menus,
extensions,
// ...
};
```
This function runs before any extensions are loaded, ensuring the APIs are available when extensions import from `@apache-superset/core`.
This runs before any extensions are loaded. `window.superset` is not itself what an extension's `@apache-superset/core` import resolves to — it is the source object the loader reads from when building each extension's per-container scoped instance (see [Runtime Resolution](#runtime-resolution)), so every extension ends up sharing the same underlying `commands`/`views`/`menus` singletons but with its own `extensions.getContext()`.
### Benefits

View File

@@ -47,13 +47,14 @@ Extension developers have access to pre-built UI components via `@apache-superse
## Next Steps
- **[Quick Start](./quick-start.md)** - Build your first extension with a complete walkthrough
- **[Architecture](./architecture.md)** - Design principles and system overview
- **[Dependencies](./dependencies.md)** - Managing dependencies and understanding API stability
- **[Contribution Types](./contribution-types.md)** - Available extension points
- **[Development](./development.md)** - Project structure, APIs, and development workflow
- **[Deployment](./deployment.md)** - Packaging and deploying extensions
- **[MCP Integration](./mcp.md)** - Adding AI agent capabilities using extensions
- **[Security](./security.md)** - Security considerations and best practices
- **[Tasks](./tasks.md)** - Framework for creating and managing long running tasks
- **[Community Extensions](./registry.md)** - Browse extensions shared by the community
- **[Quick Start](./quick-start)** - Build your first extension with a complete walkthrough
- **[Architecture](./architecture)** - Design principles and system overview
- **[Dependencies](./dependencies)** - Managing dependencies and understanding API stability
- **[Contribution Types](./contribution-types)** - Available extension points
- **[Development](./development)** - Project structure, APIs, and development workflow
- **[Deployment](./deployment)** - Packaging and deploying extensions
- **[MCP Integration](./mcp)** - Adding AI agent capabilities using extensions
- **[Security](./security)** - Security considerations and best practices
- **[Storage](./storage)** - Managed storage API for persisting extension data
- **[Tasks](./tasks)** - Framework for creating and managing long running tasks
- **[Community Extensions](./registry)** - Browse extensions shared by the community

View File

@@ -223,7 +223,7 @@ The `@apache-superset/core` package must be listed in both `peerDependencies` (t
**`frontend/webpack.config.js`**
The webpack configuration requires specific settings for Module Federation. Key settings include `externalsType: "window"` and `externals` to map `@apache-superset/core` to `window.superset` at runtime, `import: false` for shared modules to use the host's React instead of bundling a separate copy, and `remoteEntry.[contenthash].js` for cache busting.
The webpack configuration requires specific settings for Module Federation. `@apache-superset/core` is declared as a `shared` singleton alongside `react`/`react-dom`/`antd` — Superset injects a per-extension instance of the package into the container's share scope at load time, so the extension's own webpack config only needs to mark it `shared` with `singleton: true`, not resolve it itself. `import: false` on each shared entry means the extension doesn't bundle its own copy and instead uses the instance the host (or, for `@apache-superset/core`, the loader) provides. `remoteEntry.[contenthash].js` gives the built remote entry file a content hash for cache busting.
**Convention**: Superset always loads extensions by requesting the `./index` module from the Module Federation container. The `exposes` entry must be exactly `'./index': './src/index.tsx'` — do not rename or add additional entries. All API registrations must be reachable from that file. See [Architecture](./architecture.md#module-federation) for a full explanation.
@@ -255,11 +255,6 @@ module.exports = (env, argv) => {
resolve: {
extensions: ['.ts', '.tsx', '.js', '.jsx'],
},
// Map @apache-superset/core imports to window.superset at runtime
externalsType: 'window',
externals: {
'@apache-superset/core': 'superset',
},
module: {
rules: [
{
@@ -292,6 +287,10 @@ module.exports = (env, argv) => {
requiredVersion: packageConfig.peerDependencies['antd'],
import: false,
},
'@apache-superset/core': {
singleton: true,
import: false, // Resolved to a per-extension instance by the loader
},
},
}),
],
@@ -498,7 +497,7 @@ Here's what happens when your extension loads:
1. **Superset starts**: Reads `manifest.json` from the `.supx` bundle and loads the backend entrypoint
2. **Backend registration**: `entrypoint.py` imports your API class, triggering the [`@api`](https://github.com/apache/superset/blob/master/superset-core/src/superset_core/rest_api/decorators.py) decorator to register it automatically
3. **Frontend loads**: When SQL Lab opens, Superset fetches the remote entry file
4. **Module Federation**: Webpack loads your extension module and resolves `@apache-superset/core` to `window.superset`
4. **Module Federation**: Webpack loads your extension module; the extension's `@apache-superset/core` import resolves to a per-extension instance injected into its container's share scope by the loader
5. **Registration**: The module executes at load time, calling `views.registerView` to register your panel
6. **Rendering**: When the user opens your panel, React renders `<HelloWorldPanel />`
7. **API call**: The component fetches data from `/extensions/my-org/hello-world/message`

View File

@@ -0,0 +1,465 @@
---
title: Storage
sidebar_position: 8
---
<!--
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.
-->
# Storage
Superset Extensions have access to a managed storage API for persisting data. The storage system provides multiple tiers with different persistence characteristics, allowing extensions to choose the right storage for their needs.
Each extension receives its own isolated storage namespace. When Superset loads your extension, it binds storage to your extension's unique identifier, ensuring data privacy—two extensions using the same key will never collide, and extensions cannot access each other's data.
Storage is always accessed through the extension context via `getContext()`. This binding to the context is what ties every operation to the current extension's namespace.
## Storage Tiers
| Tier | Storage Type | Context Property | Use Case |
| ---- | ----------------- | ------------------------------------------ | -------------------------------------- |
| 1 | Browser storage | `ctx.storage.local`, `ctx.storage.session` | UI state, wizard progress, draft forms |
| 2 | Server-side cache | `ctx.storage.ephemeral` | Job progress, temporary results |
| 3 | Database | `ctx.storage.persistent` | Saved artifacts, durable config |
## Tier 1: Local State
Browser-based storage that persists on the user's device. Use this for UI state and settings that don't need to sync across devices.
### Why Use the API Instead of localStorage Directly?
You might wonder why extensions should use `ctx.storage.local` instead of directly accessing `window.localStorage`. The managed API provides several benefits:
- **Automatic namespacing**: Each extension's data is isolated. Two extensions using the same key name won't collide.
- **User isolation**: By default, data is scoped to the current user, preventing data leakage between users on shared devices.
- **Clean uninstall**: When an extension is uninstalled, all its data can be cleanly removed using prefix-based deletion.
- **Future sandboxing**: The async API is designed for a future sandboxed execution model where extensions run in isolated contexts without direct DOM access.
- **Consistent patterns**: The same API shape works across all storage tiers, making it easy to switch between them.
### localState
Data persists across browser sessions until explicitly deleted or the user clears browser storage.
```typescript
import { extensions } from '@apache-superset/core';
const ctx = extensions.getContext();
// Save sidebar state
await ctx.storage.local.set('sidebar_collapsed', true);
// Retrieve it later
const isCollapsed = await ctx.storage.local.get('sidebar_collapsed');
// Remove it
await ctx.storage.local.remove('sidebar_collapsed');
```
### sessionState
Data is cleared when the browser tab is closed. Use for transient state within a single session.
```typescript
import { extensions } from '@apache-superset/core';
const ctx = extensions.getContext();
// Save wizard progress (lost when tab closes)
await ctx.storage.session.set('wizard_step', 3);
await ctx.storage.session.set('unsaved_form', { name: 'Draft' });
// Retrieve on page reload within same tab
const step = await ctx.storage.session.get('wizard_step');
```
Tier 1 has no `shared` accessor. Browser storage is per-device, so a "shared" value would only be visible to other users of that same browser, not to other users of the extension generally — see `.shared` on [Tier 2](#tier-2-ephemeral-state) or [Tier 3](#tier-3-persistent-state) for storage that's actually shared across users.
### When to Use Tier 1
- UI state (sidebar collapsed, panel sizes)
- Recently used items
- Draft form values
- Any data acceptable to lose if user clears browser
### Limitations
- Per-browser, per-device (not shared across devices)
- Subject to browser storage quotas (~5-10 MB)
- Not accessible from backend code
## Tier 2: Ephemeral State
Server-side cache storage with automatic TTL expiration. Use for temporary data that needs to be shared between frontend and backend, or persist across page reloads.
TTL is required for every `set` call. The maximum allowed TTL is controlled by `MAX_TTL` in the server configuration.
### Frontend Usage
```typescript
import { extensions } from '@apache-superset/core';
const ctx = extensions.getContext();
// Store with a 5-minute TTL
await ctx.storage.ephemeral.set('job_progress', { pct: 42, status: 'running' }, { ttl: 300 });
// Retrieve
const progress = await ctx.storage.ephemeral.get('job_progress');
// Remove
await ctx.storage.ephemeral.remove('job_progress');
```
### Backend Usage
```python
from superset_core.extensions.context import get_context
from superset_core.extensions.storage.ephemeral import EphemeralSetOptions
ctx = get_context()
# Store job progress with a 5-minute TTL
ctx.storage.ephemeral.set(
'job_progress', {'pct': 42, 'status': 'running'}, EphemeralSetOptions(ttl=300)
)
# Retrieve
progress = ctx.storage.ephemeral.get('job_progress')
# Remove
ctx.storage.ephemeral.remove('job_progress')
```
### Shared State
For data that needs to be visible to all users:
```typescript
import { extensions } from '@apache-superset/core';
const ctx = extensions.getContext();
await ctx.storage.ephemeral.shared.set('shared_result', { data: [1, 2, 3] }, { ttl: 3600 });
const result = await ctx.storage.ephemeral.shared.get('shared_result');
```
```python
from superset_core.extensions.context import get_context
from superset_core.extensions.storage.ephemeral import EphemeralSetOptions
ctx = get_context()
ctx.storage.ephemeral.shared.set(
'shared_result', {'data': [1, 2, 3]}, EphemeralSetOptions(ttl=3600)
)
result = ctx.storage.ephemeral.shared.get('shared_result')
```
### When to Use Tier 2
- Background job progress indicators
- Cross-request intermediate state
- Query result previews
- Temporary computation results
- Any data that can be recomputed if lost
### Limitations
- Not guaranteed to survive server restarts
- Subject to cache eviction under memory pressure
- TTL-based expiration (data disappears after timeout)
- TTL is required on every `set` call
## Tier 3: Persistent State
Database-backed storage that survives server restarts, cache evictions, and browser clears. Use for any data that must not be lost.
### Frontend Usage
```typescript
import { extensions } from '@apache-superset/core';
const ctx = extensions.getContext();
// Store a saved SQL snippet
await ctx.storage.persistent.set('snippet:top_customers', { sql: 'SELECT ...' });
// Retrieve
const snippet = await ctx.storage.persistent.get('snippet:top_customers');
// Remove
await ctx.storage.persistent.remove('snippet:top_customers');
```
### Backend Usage
```python
from superset_core.extensions.context import get_context
ctx = get_context()
# Store a saved SQL snippet
ctx.storage.persistent.set('snippet:top_customers', {'sql': 'SELECT ...'})
# Retrieve
snippet = ctx.storage.persistent.get('snippet:top_customers')
# Remove
ctx.storage.persistent.remove('snippet:top_customers')
```
### Shared State
For data that should be visible to all users of the extension:
```typescript
import { extensions } from '@apache-superset/core';
const ctx = extensions.getContext();
await ctx.storage.persistent.shared.set('global_config', { version: 2 });
const config = await ctx.storage.persistent.shared.get('global_config');
```
```python
from superset_core.extensions.context import get_context
ctx = get_context()
ctx.storage.persistent.shared.set('global_config', {'version': 2})
config = ctx.storage.persistent.shared.get('global_config')
```
### Listing Entries
Both the frontend and backend accessors support listing entries in the caller's scope, without needing to know every key in advance. `page` and `pageSize`/`page_size` are required on every call — `list()` always returns one page of results, never the whole result set, so there's no default that could make that fact easy to miss. Check the returned `count` (total entries matching the scope/filters, across all pages) against `pageSize`/`page_size` to know whether more pages exist.
```typescript
import { extensions } from '@apache-superset/core';
const ctx = extensions.getContext();
// Filter by resource
const result = await ctx.storage.persistent.list({
resourceType: 'dashboard',
resourceUuid: '1234-uuid',
page: 0,
pageSize: 25,
});
result.entries.forEach(entry => {
console.log(entry.key, entry.value, entry.codec);
});
console.log(result.count); // total matching entries across all pages
// Shared (global) scope
const shared = await ctx.storage.persistent.shared.list({ page: 0, pageSize: 10 });
```
```python
from superset_core.extensions.context import get_context
from superset_core.extensions.storage.persistent import PersistentListOptions
ctx = get_context()
# Filter by resource
result = ctx.storage.persistent.list(
PersistentListOptions(
resource_type="dashboard",
resource_uuid="1234-uuid",
page=0,
page_size=25,
)
)
for entry in result.entries:
print(entry.key, entry.value, entry.codec)
print(result.count) # total matching entries across all pages
# Shared (global) scope
shared = ctx.storage.persistent.shared.list(PersistentListOptions(page=0, page_size=10))
```
`resource_type`/`resource_uuid` filter to entries linked to one resource — since a single resource can have several keyed entries (e.g. `"layout"`, `"notes"`), this is how an extension enumerates all of them without tracking key names itself.
There is no fixed limit on `page_size`, but the combined size of a requested page's values is checked against `MAX_LIST_PAYLOAD_SIZE` (see [Quotas](#quotas)) before any row's value is read from the database — a page that would exceed it is rejected rather than silently truncated, so reduce `page_size` and retry if that happens.
Backend `list()` decodes every entry's value unconditionally. The REST API backing the frontend's `list()` call is more restrictive: an entry written with a codec that isn't safe to decode over the wire (e.g. `pickle`) comes back with `value: null` (its `codec` is still reported) rather than being decoded.
### Enumerating and Managing Storage from the Backend
`ctx.storage.persistent.list()` covers the common case of listing an extension's own entries. Backend extension code that needs lower-level bulk operations — for example, a cleanup routine that removes storage linked to resources that no longer exist, using filters `list()` doesn't expose — can use `superset_core.extensions.storage.dao.ExtensionStorageDAO` instead:
```python
from superset_core.extensions.storage.dao import ExtensionStorageDAO
# All entries this extension has linked to a given resource type
entries = ExtensionStorageDAO.filter_by(resource_type="my-resource-type")
# Bulk-delete rows for resources that no longer exist
orphaned = [e for e in entries if e.resource_uuid not in my_extension_live_resource_ids()]
ExtensionStorageDAO.delete(orphaned)
```
`ExtensionStorageDAO` is automatically scoped to the calling extension's own rows — `extension_id` is never a parameter you pass, so there is no way to reach another extension's storage through this API. It supports the standard DAO operations `find_all`, `find_one_or_none`, `filter_by`, `query`, `update`, and `delete`. `create()` is not supported — it's a raw insert with no upsert dedup, quota check, or locking against the key `.set()` writes to, so use `ctx.storage.persistent.set()` to write a value instead.
### When to Use Tier 3
- Extension configuration that must survive restarts
- User-specific saved artifacts that need to roam across devices and browsers (e.g. saved SQL snippets, annotations)
- Any data where loss is unacceptable
### Limitations
- Higher latency than Tiers 12 (database round-trip per operation)
- Subject to the per-value size limit configured via `EXTENSIONS_PERSISTENT_STORAGE.MAX_VALUE_SIZE` (see [Quotas](#quotas))
- Subject to the per-extension quota configured via `EXTENSIONS_PERSISTENT_STORAGE.QUOTA_PER_EXTENSION` (see [Quotas](#quotas))
- Requires a database migration when first deployed
## Working with Binary Data
Tiers 2 and 3 accept a `codec` option describing how `value` is encoded — `"json"` (the default) for JSON-native values, or `"binary"` for raw bytes. `list()` and `get()` report which codec an entry was written with via `entry.codec`.
### Backend
Backend code talks to the storage DAO directly and works with real Python `bytes` — no extra flag is needed:
```python
from superset_core.extensions.context import get_context
from superset_core.extensions.storage.persistent import PersistentSetOptions
ctx = get_context()
with open('logo.png', 'rb') as f:
png_bytes = f.read()
ctx.storage.persistent.set('logo', png_bytes, PersistentSetOptions(codec='binary'))
stored = ctx.storage.persistent.get('logo') # raw bytes back, unchanged
```
### Frontend
The frontend SDK talks to the backend over a JSON REST API, which has no byte type — a binary value must be base64-encoded to travel in a JSON request body. There is no way for the SDK to infer this from a JS value's type, so it is never detected automatically: set `isBinary: true` explicitly whenever `value` is binary.
```typescript
import { extensions } from '@apache-superset/core';
const ctx = extensions.getContext();
const pngBytes = new Uint8Array([0x89, 0x50, 0x4e, 0x47 /* ... */]);
await ctx.storage.persistent.set('logo', pngBytes, { isBinary: true });
```
`get()` returns a binary entry's value exactly as stored on the wire — a base64 string, not a `Uint8Array` — so decode it yourself:
```typescript
const base64 = await ctx.storage.persistent.get<string>('logo');
const bytes = Uint8Array.from(atob(base64), c => c.charCodeAt(0));
```
`list()` entries report `isBinary` alongside `codec`, so you know which entries need decoding before you read `value`:
```typescript
const result = await ctx.storage.persistent.list({ page: 0, pageSize: 10 });
result.entries.forEach(entry => {
const value = entry.isBinary
? Uint8Array.from(atob(entry.value as string), c => c.charCodeAt(0))
: entry.value;
});
```
## Key Patterns
All storage keys are automatically namespaced:
| Scope | Key Pattern |
| ---------------------- | -------------------------------------------------- |
| User-scoped | `superset-ext:{extension_id}:user:{user_id}:{key}` |
| Shared (Tiers 2 and 3) | `superset-ext:{extension_id}:shared:{key}` |
This ensures:
- Extensions cannot accidentally access each other's data
- Users cannot see other users' data (by default)
- Clean prefix-based deletion on uninstall
## Configuration
### Tier 2: Ephemeral Storage
Administrators can configure the server-side cache backend in `superset_config.py`:
```python
EXTENSIONS_EPHEMERAL_STORAGE = {
# Use Redis for better performance in production
"CACHE_TYPE": "RedisCache",
"CACHE_REDIS_URL": "redis://localhost:6379/2",
"MAX_TTL": 604800, # 7 days maximum TTL
"MAX_VALUE_SIZE": 100 * 1024, # 100 KB maximum per stored value
}
```
For development, the default `SupersetMetastoreCache` stores data in the metadata database.
### Tier 3: Persistent Storage
Tier 3 values are stored in the `extension_storage` database table. Values are stored unencrypted by default; encryption is opt-in per write, available via a `PersistentSetOptions`-shaped `encrypt` option:
```typescript
import { extensions } from '@apache-superset/core';
const ctx = extensions.getContext();
await ctx.storage.persistent.set('api_token', 'sk-...', { encrypt: true });
const token = await ctx.storage.persistent.get('api_token');
```
```python
from superset_core.extensions.context import get_context
from superset_core.extensions.storage.persistent import PersistentSetOptions
ctx = get_context()
ctx.storage.persistent.set('api_token', 'sk-...', PersistentSetOptions(encrypt=True))
token = ctx.storage.persistent.get('api_token')
```
Encryption reuses Superset's existing `EncryptedType` (from `sqlalchemy-utils`) rather than a separate mechanism — the same infrastructure used for database connection credentials. The key is not configured directly: user-scoped values are encrypted with a key derived per-user via HMAC-SHA256 from the deployment's `SECRET_KEY`, so ciphertext for one user cannot be decrypted as another's; shared/global values (written via `.shared`) use `SECRET_KEY` directly. The encryption engine (AES-CBC by default) can be changed for the whole deployment via the existing `SQLALCHEMY_ENCRYPTED_FIELD_ENGINE` config, the same setting that controls encryption for database credentials elsewhere in Superset — there is no separate key list or rotation mechanism specific to extension storage. When `SECRET_KEY` is rotated, extension storage rows are re-encrypted by the existing `SecretsMigrator` tooling alongside database credentials, with no extension-specific steps required.
### Quotas
Persistent storage is subject to per-value, per-list-page, and per-extension size limits, configured in `superset_config.py`:
```python
EXTENSIONS_PERSISTENT_STORAGE = {
# Maximum total bytes an extension may store across all of its rows
# (global, every user's, and shared). Defaults to 100 MB.
"QUOTA_PER_EXTENSION": 100 * 1024 * 1024,
# Maximum size (in bytes) of a single stored value. Defaults to 1 MB.
"MAX_VALUE_SIZE": 1024 * 1024,
# Maximum combined value size (in bytes) that a single list() page may
# return. Defaults to 10 MB.
"MAX_LIST_PAYLOAD_SIZE": 10 * 1024 * 1024,
}
```
A write that would push the extension's total stored size over `QUOTA_PER_EXTENSION` is rejected — the frontend SDK's `set()` call rejects with an HTTP 413 response, and backend code calling `ctx.storage.persistent.set()` sees the corresponding exception raised. Overwriting an existing key nets out that key's own current size against usage first, so replacing a value with one of the same or smaller size never spuriously fails even when the extension is already near its quota.
A write whose encoded value exceeds `MAX_VALUE_SIZE` is rejected outright, independently of the total quota.
A `list()` call whose requested page would return more than `MAX_LIST_PAYLOAD_SIZE` combined bytes of value data is rejected — reduce `page`/`pageSize` and retry. This check runs against the page's stored sizes before any value is read from the database, so an oversized request fails fast. Because `list()`'s response is consumed as JSON in the browser, raising `MAX_LIST_PAYLOAD_SIZE` substantially above the default risks client-side memory and parse-time issues — treat the default as already generous rather than a floor to build up from.

View File

@@ -52,7 +52,7 @@ Everything you need to contribute to the Apache Superset project. This section i
## Development Resources
### Prerequisites
- **Python**: 3.9, 3.10, or 3.11
- **Python**: 3.11 or 3.12
- **Node.js**: 18.x or 20.x
- **npm**: 9.x or 10.x
- **Git**: Basic understanding

View File

@@ -0,0 +1,99 @@
---
title: Exporting Dashboard Data to Excel
hide_title: true
sidebar_position: 7
version: 1
---
# Exporting Dashboard Data to Excel
Superset can export every chart on a dashboard to a single Excel workbook, with
each chart's underlying data rendered as its own worksheet. The export reflects
the dashboard's currently applied filters and runs asynchronously: when it
finishes, the requesting user receives an email with a time-limited download
link.
## Using the export
From a dashboard, open the **... (actions) → Download** submenu and choose
**Export Data to Excel**. The action appears for users who have the dashboard
`can_export` permission. You'll see a confirmation that the export is being
prepared; the workbook arrives by email when it's ready.
A second option, **Export Images to Excel**, embeds each non-table chart as a
rendered image (tables stay tabular) instead of exporting raw data. Because it
renders charts through the headless webdriver, this option only appears when the
webdriver screenshot feature flags are enabled (see the prerequisites below);
which viz types stay tabular is controlled by `EXCEL_EXPORT_TABLE_VIZ_TYPES`.
Notes on the generated workbook:
- One worksheet per chart, named `{chart_id} - {chart title}` (truncated to
Excel's 31-character limit; the chart id keeps names unique).
- Charts nested in tabs are included.
- Data reflects the dashboard's active filter state at the time of export.
- A chart with no saved query context is skipped and listed in the email; open
the chart in Explore and re-save it to include it next time.
- Row counts per sheet are capped the same way as the chart-level CSV/Excel
export (`ROW_LIMIT`, bounded by `SQL_MAX_ROW`), and never exceed Excel's
per-sheet maximum.
## Prerequisites
This feature is **disabled by default**. It requires:
1. **The `boto3` dependency.** It is not installed by default; install it with
`pip install apache-superset[excel-export]`. Without it, exports fail and the
user receives a failure email.
2. **An S3 bucket.** Set `EXCEL_EXPORT_S3_BUCKET`. Until it is set, the export
endpoint returns `501` and the menu action surfaces a "not configured"
message.
3. **A running Celery worker.** The export runs as a Celery task. If no worker
is running, the request is accepted but nothing is produced.
4. **A configured SMTP transport.** The download link is delivered by email
using the same settings as alerts & reports (`SMTP_*`,
`EMAIL_REPORTS_SUBJECT_PREFIX`).
**Export Images to Excel** additionally requires a working headless webdriver —
the same infrastructure scheduled reports and thumbnails use (`WEBDRIVER_*`,
plus the `ENABLE_DASHBOARD_SCREENSHOT_ENDPOINTS` and
`ENABLE_DASHBOARD_DOWNLOAD_WEBDRIVER_SCREENSHOT` feature flags). The menu option
is hidden when those flags are off; if the webdriver is unreachable, image
charts come back empty even though the data export path still works.
Deployments that override `CELERY_CONFIG` must add
`"superset.tasks.export_dashboard_excel"` to the `imports` tuple, or the task
will not register.
## Configuration keys
| Key | Default | Description |
| --- | --- | --- |
| `EXCEL_EXPORT_S3_BUCKET` | `None` | Destination bucket. Required; `501` if unset. |
| `EXCEL_EXPORT_S3_KEY_PREFIX` | `"dashboard-exports/"` | Key prefix: `{prefix}{dashboard_id}/{job_id}.xlsx`. |
| `EXCEL_EXPORT_LINK_TTL_SECONDS` | `86400` | Lifetime of the pre-signed download URL (24h). |
| `EXCEL_EXPORT_S3_CLIENT_KWARGS` | `{}` | Extra kwargs for `boto3.client("s3", ...)` — e.g. `region_name`, or `endpoint_url` for MinIO/LocalStack. |
| `EXCEL_EXPORT_TABLE_VIZ_TYPES` | `None` | Viz types kept tabular in **Export Images to Excel** mode; every other type is embedded as an image. `None` uses the built-in default (`table`, `pivot_table`, `pivot_table_v2`). |
Credentials and region resolve through the standard boto3 chain (environment
variables, shared config, or instance role) unless overridden via
`EXCEL_EXPORT_S3_CLIENT_KWARGS`. The worker needs `s3:PutObject` on the bucket.
## Security considerations
- The emailed link is a **pre-signed S3 URL**: anyone who holds it can download
the workbook until it expires. Keep the bucket **private**, enable
encryption, and consider a lifecycle rule to delete objects after a few days.
Lower `EXCEL_EXPORT_LINK_TTL_SECONDS` if 24 hours is too long for your data.
- The export runs with the requesting user's permissions; each chart's query is
access-checked, so users only ever receive data they are entitled to.
## Limitations
- **Embedded dashboards / guest tokens are not supported** in this version,
because guest users have no email address to deliver the link to. Logged-in
users viewing an embedded dashboard can still use the export.
- The default **Export Data to Excel** mode exports data only (no visual
styling). Use **Export Images to Excel** to embed rendered chart images, which
requires the webdriver infrastructure described in the prerequisites.
- Scheduled/automated exports are not part of this feature.

View File

@@ -146,7 +146,9 @@ The `where_in` filter converts the list to SQL format: `('value1', 'value2', 'va
### Time Filters
For charts with time range filters:
`get_time_filter()` is the standard way to reference the selected time range in a virtual dataset.
It returns a `TimeFilter` object with `from_expr` and `to_expr` — fully-formatted SQL expressions
that should be used directly in `WHERE` clauses without quoting.
| Macro | Description |
|-------|-------------|
@@ -198,17 +200,9 @@ GROUP BY category
## Testing Templates in SQL Lab
Some variables like `from_dttm` and `filter_values()` only work when filters are applied from dashboards or charts. To test in SQL Lab:
Some variables like `filter_values()` only work when filters are applied from dashboards or charts. To test in SQL Lab:
**Option 1: Use defaults**
```sql
SELECT *
FROM orders
WHERE date >= '{{ from_dttm | default("2024-01-01", true) }}'
```
**Option 2: Set test parameters**
**Option 1: Set test parameters**
Add to the Parameters menu:
@@ -220,7 +214,7 @@ Add to the Parameters menu:
}
```
**Option 3: Use `{% set %}`**
**Option 2: Use `{% set %}`**
```sql
{% set start_date = "2024-01-01" %}

View File

@@ -44,12 +44,12 @@
},
"dependencies": {
"@ant-design/icons": "^6.2.5",
"@docusaurus/core": "^3.10.1",
"@docusaurus/faster": "^3.10.1",
"@docusaurus/plugin-client-redirects": "^3.10.1",
"@docusaurus/preset-classic": "3.10.1",
"@docusaurus/theme-live-codeblock": "^3.10.1",
"@docusaurus/theme-mermaid": "^3.10.1",
"@docusaurus/core": "^3.10.2",
"@docusaurus/faster": "^3.10.2",
"@docusaurus/plugin-client-redirects": "^3.10.2",
"@docusaurus/preset-classic": "3.10.2",
"@docusaurus/theme-live-codeblock": "^3.10.2",
"@docusaurus/theme-mermaid": "^3.10.2",
"@emotion/core": "^11.0.0",
"@emotion/react": "^11.13.3",
"@emotion/styled": "^11.14.1",
@@ -58,15 +58,15 @@
"@fontsource/inter": "^5.2.8",
"@mdx-js/react": "^3.1.1",
"@saucelabs/theme-github-codeblock": "^0.3.0",
"@storybook/addon-docs": "^10.4.5",
"@storybook/addon-docs": "^10.5.0",
"@superset-ui/core": "^0.20.4",
"@swc/core": "^1.15.43",
"antd": "^6.5.0",
"baseline-browser-mapping": "^2.10.40",
"caniuse-lite": "^1.0.30001803",
"docusaurus-plugin-openapi-docs": "^5.1.1",
"docusaurus-theme-openapi-docs": "^5.1.1",
"js-yaml": "^5.2.0",
"antd": "^6.5.1",
"baseline-browser-mapping": "^2.10.43",
"caniuse-lite": "^1.0.30001806",
"docusaurus-plugin-openapi-docs": "^5.1.2",
"docusaurus-theme-openapi-docs": "^5.1.2",
"js-yaml": "^5.2.2",
"json-bigint": "^1.0.0",
"prism-react-renderer": "^2.4.1",
"react": "^18.3.1",
@@ -77,20 +77,20 @@
"react-table": "^7.8.0",
"remark-import-partial": "^0.0.2",
"reselect": "^5.2.0",
"storybook": "^10.4.5",
"storybook": "^10.5.0",
"swagger-ui-react": "^5.32.8",
"swc-loader": "^0.2.7",
"tinycolor2": "^1.4.2",
"unist-util-visit": "^5.1.0"
},
"devDependencies": {
"@docusaurus/module-type-aliases": "^3.10.1",
"@docusaurus/tsconfig": "^3.10.1",
"@docusaurus/module-type-aliases": "^3.10.2",
"@docusaurus/tsconfig": "^3.10.2",
"@eslint/js": "^9.39.2",
"@types/js-yaml": "^4.0.9",
"@types/react": "^19.1.8",
"@typescript-eslint/eslint-plugin": "^8.59.3",
"@typescript-eslint/parser": "^8.63.0",
"@typescript-eslint/eslint-plugin": "^8.64.0",
"@typescript-eslint/parser": "^8.64.0",
"eslint": "^9.39.2",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-prettier": "^5.5.6",
@@ -98,7 +98,7 @@
"globals": "^17.7.0",
"prettier": "^3.9.5",
"typescript": "~6.0.3",
"typescript-eslint": "^8.63.0",
"typescript-eslint": "^8.64.0",
"webpack": "^5.108.2"
},
"browserslist": {
@@ -124,8 +124,6 @@
"serialize-javascript": "7.0.5",
"d3-color": "3.1.0",
"ws": "^8.21.0",
"@docusaurus/core/@docusaurus/utils/gray-matter/js-yaml": "^3.15.0",
"@docusaurus/core/**/js-yaml": "^4.3.0",
"docusaurus-plugin-openapi-docs/**/js-yaml": "^4.3.0"
},
"packageManager": "yarn@1.22.22+sha1.ac34549e6aa8e7ead463a7407e1c7390f61a6610"

View File

@@ -82,12 +82,14 @@ const sidebars = {
items: [
'extensions/extension-points/sqllab',
'extensions/extension-points/editors',
'extensions/extension-points/chat',
],
},
'extensions/development',
'extensions/deployment',
'extensions/mcp',
'extensions/security',
'extensions/storage',
'extensions/tasks',
'extensions/registry',
],

View File

@@ -1,16 +1,16 @@
{
"generated": "2026-04-17T17:08:35.132Z",
"statistics": {
"totalDatabases": 80,
"withDocumentation": 80,
"withConnectionString": 80,
"withDrivers": 28,
"totalDatabases": 81,
"withDocumentation": 81,
"withConnectionString": 81,
"withDrivers": 29,
"withAuthMethods": 5,
"supportsJoins": 74,
"supportsSubqueries": 77,
"supportsJoins": 75,
"supportsSubqueries": 78,
"supportsDynamicSchema": 29,
"supportsCatalog": 20,
"averageScore": 54,
"averageScore": 53,
"maxScore": 201,
"byCategory": {
"Cloud - AWS": [
@@ -20,6 +20,7 @@
],
"Query Engines": [
"Amazon Athena",
"Apache DataFusion",
"Apache Drill",
"Apache Hive",
"Apache Impala",
@@ -94,6 +95,7 @@
"Vertica"
],
"Apache Projects": [
"Apache DataFusion",
"Apache Doris",
"Apache Drill",
"Apache Druid",
@@ -108,6 +110,7 @@
"Databricks Interactive Cluster"
],
"Open Source": [
"Apache DataFusion",
"Apache Doris",
"Apache Drill",
"Apache Druid",
@@ -3672,7 +3675,7 @@
"drivers": [
{
"name": "crate",
"pypi_package": "crate[sqlalchemy]",
"pypi_package": "sqlalchemy-cratedb",
"connection_string": "crate://{host}:{port}",
"is_recommended": true
}
@@ -9698,6 +9701,97 @@
"supports_dynamic_schema": true,
"supports_catalog": true,
"supports_dynamic_catalog": true
},
"Apache DataFusion": {
"time_grains": {
"SECOND": true,
"FIVE_SECONDS": true,
"THIRTY_SECONDS": true,
"MINUTE": true,
"FIVE_MINUTES": true,
"TEN_MINUTES": true,
"FIFTEEN_MINUTES": true,
"THIRTY_MINUTES": true,
"HALF_HOUR": false,
"HOUR": true,
"SIX_HOURS": false,
"DAY": true,
"WEEK": true,
"WEEK_STARTING_SUNDAY": false,
"WEEK_STARTING_MONDAY": false,
"WEEK_ENDING_SATURDAY": false,
"WEEK_ENDING_SUNDAY": false,
"MONTH": true,
"QUARTER": true,
"QUARTER_YEAR": false,
"YEAR": true
},
"module": "superset.db_engine_specs.datafusion",
"limit_method": 1,
"limit_clause": true,
"joins": true,
"subqueries": true,
"alias_in_select": true,
"alias_in_orderby": true,
"time_groupby_inline": false,
"alias_to_source_column": false,
"order_by_not_in_select": true,
"expressions_in_orderby": false,
"cte_in_subquery": true,
"max_column_name": null,
"sql_comments": true,
"escaped_colons": true,
"masked_encrypted_extra": false,
"column_type_mapping": false,
"function_names": false,
"user_impersonation": false,
"file_upload": false,
"get_extra_table_metadata": false,
"dbapi_exception_mapping": false,
"custom_errors": false,
"dynamic_schema": false,
"catalog": false,
"dynamic_catalog": false,
"ssh_tunneling": true,
"query_cancelation": false,
"get_metrics": false,
"where_latest_partition": false,
"expand_data": false,
"query_cost_estimation": false,
"sql_validation": false,
"score": 24,
"max_score": 201,
"documentation": {
"description": "DataFusion is a highly performant query engine",
"logo": "datafusion.png",
"homepage_url": "https://datafusion.apache.org/",
"categories": [
"Query Engines",
"Open Source",
"Apache Projects"
],
"pypi_packages": [
"flightsql-dbapi"
],
"connection_string": "datafusion://host:port",
"drivers": [
{
"name": "Arrow Flight SQL (Recommended)",
"pypi_package": "flightsql-dbapi",
"connection_string": "datafusion://host:port",
"is_recommended": true
}
],
"category": "Apache Projects"
},
"engine": "datafusion",
"engine_name": "Apache DataFusion",
"engine_aliases": [],
"default_driver": "flightsql",
"supports_file_upload": false,
"supports_dynamic_schema": false,
"supports_catalog": false,
"supports_dynamic_catalog": false
}
}
}

View File

@@ -28,8 +28,9 @@ RewriteRule ^(.*)$ https://superset.apache.org/$1 [R=301,L]
# - *.googleapis.com, *.google.com, *.gstatic.com: Google Calendar embed, kapa.ai reCAPTCHA - all of these loaded with user consent, following policy laid out in https://privacy.apache.org/faq/committers.html
# - github.com, *.github.com, *.githubusercontent.com: GitHub user-attachment images in docs (apex github.com serves user-attachments/* assets). Discussed/resolved in this thread: https://issues.apache.org/jira/browse/INFRA-25701?filter=-2 (DPA in place with GitHub)
# - *.algolia.net, *.algolianet.com: Algolia DocSearch. Approved here: https://privacy.apache.org/faq/committers.html
# - *.run.app: Google-owned domain (Google Cloud Run) used by the kapa.ai widget backend - only reached after explicit user acceptance when opening the widget, allowable per the policy laid out in https://privacy.apache.org/faq/committers.html
# See: https://infra.apache.org/tools/csp.html
SetEnv CSP_PROJECT_DOMAINS "widget.kapa.ai https://*.googleapis.com/ https://*.google.com/ https://*.gstatic.com/ https://github.com/ https://*.github.com/ https://*.githubusercontent.com/ https://*.algolia.net/ https://*.algolianet.com/"
SetEnv CSP_PROJECT_DOMAINS "widget.kapa.ai https://*.googleapis.com/ https://*.google.com/ https://*.gstatic.com/ https://github.com/ https://*.github.com/ https://*.githubusercontent.com/ https://*.algolia.net/ https://*.algolianet.com/ https://*.run.app/"
# REDIRECTS

View File

@@ -405,12 +405,6 @@
"default": true,
"lifecycle": "deprecated",
"description": "Enable drill-to-detail functionality in charts"
},
{
"name": "ENABLE_JAVASCRIPT_CONTROLS",
"default": false,
"lifecycle": "deprecated",
"description": "Allow JavaScript in chart controls. WARNING: XSS security vulnerability!"
}
]
}

BIN
docs/static/img/databases/datafusion.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
docs/static/img/logos/pattern_logo.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

File diff suppressed because it is too large Load Diff

View File

@@ -29,7 +29,7 @@ maintainers:
- name: craig-rueda
email: craig@craigrueda.com
url: https://github.com/craig-rueda
version: 0.21.0 # See [README](https://github.com/apache/superset/blob/master/helm/superset/README.md#versioning) for version details.
version: 0.22.3 # See [README](https://github.com/apache/superset/blob/master/helm/superset/README.md#versioning) for version details.
dependencies:
- name: postgresql
version: 16.7.27

View File

@@ -23,7 +23,7 @@ NOTE: This file is generated by helm-docs: https://github.com/norwoodj/helm-docs
# superset
![Version: 0.21.0](https://img.shields.io/badge/Version-0.21.0-informational?style=flat-square)
![Version: 0.22.3](https://img.shields.io/badge/Version-0.22.3-informational?style=flat-square)
Apache Superset is a modern, enterprise-ready business intelligence web application
@@ -125,6 +125,13 @@ Alternatively, perform a fresh install. This is a one-time migration; subsequent
| fullnameOverride | string | `nil` | Provide a name to override the full names of resources |
| globalPodAnnotations | object | `{}` | Global pod annotations to be added to all pods Use this to set annotations that apply to all Superset components Component-specific podAnnotations will be merged with these global annotations |
| hostAliases | list | `[]` | Custom hostAliases for all superset pods # https://kubernetes.io/docs/tasks/network/customize-hosts-file-for-pods/ |
| httproute | object | see `values.yaml` | Gateway API HTTPRoute for exposing Superset via a Gateway. Requires the Gateway API CRDs (gateway.networking.k8s.io/v1) installed in the cluster. |
| httproute.annotations | object | `{}` | Annotations to add to the HTTPRoute |
| httproute.apiVersion | string | `"gateway.networking.k8s.io/v1"` | HTTPRoute apiVersion. Override to gateway.networking.k8s.io/v1beta1 for older Gateway API installations that have not promoted HTTPRoute to v1. |
| httproute.hostnames | list | `[]` | Hostnames that match against the HTTP Host header (templated) |
| httproute.labels | object | `{}` | Additional labels to add to the HTTPRoute |
| httproute.parentRefs | list | `[]` | Gateways this HTTPRoute attaches to |
| httproute.rules | list | `[{"matches":[{"path":{"type":"PathPrefix","value":"/"}}]}]` | Routing rules. Each rule is backed by the Superset service. Set `weight` per rule to leave room for traffic splitting (defaults to 1). When `supersetWebsockets.enabled` is true, an extra rule routing `supersetWebsockets.ingress.path` to the `-ws` service is appended automatically, mirroring the ingress behavior. When both `supersetMcp.enabled` and `supersetMcp.httproute.enabled` are true, an extra rule routing `supersetMcp.httproute.path` to the `-mcp` service is also appended. |
| image.pullPolicy | string | `"IfNotPresent"` | |
| image.repository | string | `"apachesuperset.docker.scarf.sh/apache/superset"` | |
| image.tag | string | `nil` | |
@@ -169,7 +176,10 @@ Alternatively, perform a fresh install. This is a one-time migration; subsequent
| redis | object | see `values.yaml` | Configuration values for the Redis dependency. ref: https://github.com/bitnami/charts/blob/master/bitnami/redis More documentation can be found here: https://artifacthub.io/packages/helm/bitnami/redis |
| resources | object | `{}` | |
| runAsUser | int | `0` | User ID directive. This user must have enough permissions to run the bootstrap script Running containers as root is not recommended in production. Change this to another UID - e.g. 1000 to be more secure |
| secretEnv | object | `{"create":true}` | Specify rather or not helm should create the secret described in `secret-env.yaml` template |
| secretConfig | object | `{"annotations":{}}` | Specify whether Helm should apply additional settings to a secret containing configuration files |
| secretConfig.annotations | object | `{}` | Annotations to be added to the secret which contains configuration files |
| secretEnv | object | `{"annotations":{},"create":true}` | Specify rather or not helm should create the secret described in `secret-env.yaml` template |
| secretEnv.annotations | object | `{}` | Annotations to be added to the secret |
| secretEnv.create | bool | `true` | Change to false in order to support externally created secret (Binami "Sealed Secrets" for Kubernetes or External Secrets Operator) note: when externally creating the secret, the chart still expects to pull values from a secret with the name of the release defaults to `release-name-superset-env` - full logic located in _helpers.tpl file: `define "superset.fullname"` |
| service.annotations | object | `{}` | |
| service.loadBalancerIP | string | `nil` | |
@@ -246,6 +256,62 @@ Alternatively, perform a fresh install. This is a one-time migration; subsequent
| supersetCeleryFlower.startupProbe.successThreshold | int | `1` | |
| supersetCeleryFlower.startupProbe.timeoutSeconds | int | `1` | |
| supersetCeleryFlower.topologySpreadConstraints | list | `[]` | TopologySpreadConstrains to be added to supersetCeleryFlower deployments |
| supersetMcp.affinity | object | `{}` | Affinity to be added to supersetMcp deployment |
| supersetMcp.command | list | a `superset mcp run` command | Command |
| supersetMcp.containerSecurityContext | object | `{}` | |
| supersetMcp.deploymentAdditionalPodSpec | object | `{}` | Custom pod spec to be added to supersetMcp deployment |
| supersetMcp.deploymentAnnotations | object | `{}` | Annotations to be added to supersetMcp deployment |
| supersetMcp.deploymentLabels | object | `{}` | Labels to be added to supersetMcp deployment |
| supersetMcp.enabled | bool | `false` | Enables the Superset MCP Server. To expose it via the shared ingress at /mcp, also set supersetMcp.ingress.enabled=true. WARNING: this requires fastMCP to be installed, which can be done by installing `apache-superset[fastmcp]` |
| supersetMcp.extraContainers | list | `[]` | Launch additional containers into supersetMcp pods |
| supersetMcp.extraInitContainers | list | `[]` | Extra init containers appended after supersetMcp initContainers |
| supersetMcp.forceReload | bool | `false` | If true, forces deployment to reload on each upgrade |
| supersetMcp.httproute.enabled | bool | `false` | If true, the MCP server will be exposed via the HTTPRoute /mcp subpath |
| supersetMcp.httproute.path | string | `"/mcp"` | |
| supersetMcp.ingress.enabled | bool | `false` | If true, the MCP server will be exposed via the ingress /mcp subpath |
| supersetMcp.ingress.path | string | `"/mcp"` | |
| supersetMcp.ingress.pathType | string | `"Prefix"` | |
| supersetMcp.initContainers | list | a container waiting for postgres and redis | List of init containers |
| supersetMcp.lifecycle | object | `{}` | Container lifecycle hooks for the worker pod |
| supersetMcp.livenessProbe.failureThreshold | int | `3` | |
| supersetMcp.livenessProbe.httpGet.path | string | `"/health"` | |
| supersetMcp.livenessProbe.httpGet.port | string | `"mcp"` | |
| supersetMcp.livenessProbe.initialDelaySeconds | int | `15` | |
| supersetMcp.livenessProbe.periodSeconds | int | `15` | |
| supersetMcp.livenessProbe.successThreshold | int | `1` | |
| supersetMcp.livenessProbe.timeoutSeconds | int | `3` | |
| supersetMcp.podAnnotations | object | `{}` | Annotations to be added to supersetMcp pods |
| supersetMcp.podDisruptionBudget | object | `{"enabled":false,"maxUnavailable":1,"minAvailable":1}` | Sets the [pod disruption budget](https://kubernetes.io/docs/tasks/run-application/configure-pdb/) for supersetMcp pods |
| supersetMcp.podDisruptionBudget.enabled | bool | `false` | Whether the pod disruption budget should be created |
| supersetMcp.podDisruptionBudget.maxUnavailable | int | `1` | If set, minAvailable must not be set - see https://kubernetes.io/docs/tasks/run-application/configure-pdb/\#specifying-a-poddisruptionbudget |
| supersetMcp.podDisruptionBudget.minAvailable | int | `1` | If set, maxUnavailable must not be set - see https://kubernetes.io/docs/tasks/run-application/configure-pdb/\#specifying-a-poddisruptionbudget |
| supersetMcp.podLabels | object | `{}` | Labels to be added to supersetMcp pods |
| supersetMcp.podSecurityContext | object | `{}` | |
| supersetMcp.priorityClassName | string | `nil` | Set priorityClassName for supersetMcp pods |
| supersetMcp.readinessProbe.failureThreshold | int | `3` | |
| supersetMcp.readinessProbe.httpGet.path | string | `"/health"` | |
| supersetMcp.readinessProbe.httpGet.port | string | `"mcp"` | |
| supersetMcp.readinessProbe.initialDelaySeconds | int | `15` | |
| supersetMcp.readinessProbe.periodSeconds | int | `15` | |
| supersetMcp.readinessProbe.successThreshold | int | `1` | |
| supersetMcp.readinessProbe.timeoutSeconds | int | `3` | |
| supersetMcp.replicaCount | int | `1` | |
| supersetMcp.resources | object | `{}` | Resource settings for the supersetMcp pods - these settings overwrite might existing values from the global resources object defined above. |
| supersetMcp.service.annotations | object | `{}` | |
| supersetMcp.service.loadBalancerIP | string | `nil` | |
| supersetMcp.service.nodePort.http | int | `"nil"` | |
| supersetMcp.service.port | int | `5008` | |
| supersetMcp.service.type | string | `"ClusterIP"` | |
| supersetMcp.startupProbe.failureThreshold | int | `60` | |
| supersetMcp.startupProbe.httpGet.path | string | `"/health"` | |
| supersetMcp.startupProbe.httpGet.port | string | `"mcp"` | |
| supersetMcp.startupProbe.initialDelaySeconds | int | `15` | |
| supersetMcp.startupProbe.periodSeconds | int | `5` | |
| supersetMcp.startupProbe.successThreshold | int | `1` | |
| supersetMcp.startupProbe.timeoutSeconds | int | `3` | |
| supersetMcp.strategy | object | `{}` | |
| supersetMcp.terminationGracePeriodSeconds | string | `nil` | Pod termination grace period (seconds) for the worker pod so in-flight tasks can drain before SIGKILL |
| supersetMcp.topologySpreadConstraints | list | `[]` | TopologySpreadConstrains to be added to supersetMcp deployments |
| supersetNode.affinity | object | `{}` | Affinity to be added to supersetNode deployment |
| supersetNode.autoscaling.enabled | bool | `false` | |
| supersetNode.autoscaling.maxReplicas | int | `100` | |
@@ -300,16 +366,19 @@ Alternatively, perform a fresh install. This is a one-time migration; subsequent
| supersetWebsockets.affinity | object | `{}` | Affinity to be added to supersetWebsockets deployment |
| supersetWebsockets.command | list | `[]` | |
| supersetWebsockets.config | object | see `values.yaml` | The config.json to pass to the server, see https://github.com/apache/superset/tree/master/superset-websocket Note that the configuration can also read from environment variables (which will have priority), see https://github.com/apache/superset/blob/master/superset-websocket/src/config.ts for a list of supported variables |
| supersetWebsockets.configAnnotations | object | `{}` | Annotations to be added to the secret which contains config.json |
| supersetWebsockets.containerSecurityContext | object | `{}` | |
| supersetWebsockets.deploymentAdditionalPodSpec | object | `{}` | Custom pod spec to be added to supersetWebsockets deployment |
| supersetWebsockets.deploymentAnnotations | object | `{}` | |
| supersetWebsockets.enabled | bool | `false` | This is only required if you intend to use `GLOBAL_ASYNC_QUERIES` in `ws` mode see https://superset.apache.org/docs/contributing/misc#async-chart-queries |
| supersetWebsockets.extraContainers | list | `[]` | Launch additional containers into supersetWebsockets pods |
| supersetWebsockets.extraInitContainers | list | `[]` | Extra init containers appended after supersetWebsockets initContainers |
| supersetWebsockets.image.pullPolicy | string | `"IfNotPresent"` | |
| supersetWebsockets.image.repository | string | `"oneacrefund/superset-websocket"` | There is no official image (yet), this one is community-supported |
| supersetWebsockets.image.tag | string | `"latest"` | |
| supersetWebsockets.ingress.path | string | `"/ws"` | |
| supersetWebsockets.ingress.pathType | string | `"Prefix"` | |
| supersetWebsockets.initContainers | list | a container waiting for redis | List of initContainers |
| supersetWebsockets.livenessProbe.failureThreshold | int | `3` | |
| supersetWebsockets.livenessProbe.httpGet.path | string | `"/health"` | |
| supersetWebsockets.livenessProbe.httpGet.port | string | `"ws"` | |

View File

@@ -761,3 +761,9 @@ app.kubernetes.io/name: {{ include "superset.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/component: worker
{{- end }}
{{- define "supersetMcp.selectorLabels" -}}
app.kubernetes.io/name: {{ include "superset.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/component: mcp
{{- end }}

View File

@@ -0,0 +1,197 @@
{{/*
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
{{- if .Values.supersetMcp.enabled -}}
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ template "superset.fullname" . }}-mcp
namespace: {{ .Release.Namespace }}
labels:
{{- include "superset.componentLabels" (dict "component" "mcp" "root" .) | nindent 4 }}
{{- if .Values.supersetMcp.deploymentAnnotations }}
annotations: {{- toYaml .Values.supersetMcp.deploymentAnnotations | nindent 4 }}
{{- end }}
spec:
replicas: {{ .Values.supersetMcp.replicaCount }}
selector:
matchLabels:
{{- include "supersetMcp.selectorLabels" . | nindent 6 }}
{{- if .Values.supersetMcp.strategy }}
strategy: {{- toYaml .Values.supersetMcp.strategy | nindent 4 }}
{{- end }}
template:
metadata:
annotations:
checksum/superset_config.py: {{ include "superset.config" . | sha256sum }}
checksum/superset_bootstrap.sh: {{ tpl .Values.bootstrapScript . | sha256sum }}
checksum/database: {{ .Values.database | toYaml | sha256sum }}
checksum/redis: {{ .Values.cache | toYaml | sha256sum }}
checksum/config: {{ .Values.config | toYaml | sha256sum }}
checksum/featureFlags: {{ .Values.featureFlags | toYaml | sha256sum }}
checksum/extraConfigs: {{ .Values.extraConfigs | toYaml | sha256sum }}
checksum/extraSecrets: {{ .Values.extraSecrets | toYaml | sha256sum }}
checksum/extraSecretEnv: {{ .Values.extraSecretEnv | toYaml | sha256sum }}
checksum/configOverrides: {{ .Values.configOverrides | toYaml | sha256sum }}
checksum/configOverridesFiles: {{ .Values.configOverridesFiles | toYaml | sha256sum }}
{{- if .Values.supersetMcp.forceReload }}
# Optionally force the thing to reload
force-reload: {{ randAlphaNum 5 | quote }}
{{- end }}
{{- if .Values.supersetMcp.podAnnotations }}
{{- toYaml .Values.supersetMcp.podAnnotations | nindent 8 }}
{{- end }}
{{- with .Values.globalPodAnnotations }}
{{- toYaml . | nindent 8 }}
{{- end }}
labels:
{{- include "supersetMcp.selectorLabels" . | nindent 8 }}
{{- if .Values.supersetMcp.podLabels }}
{{- toYaml .Values.supersetMcp.podLabels | nindent 8 }}
{{- end }}
spec:
{{- if .Values.supersetMcp.deploymentAdditionalPodSpec }}
{{- tpl (toYaml .Values.supersetMcp.deploymentAdditionalPodSpec) . | nindent 6 }}
{{- end }}
{{- if or (.Values.serviceAccount.create) (.Values.serviceAccountName) }}
serviceAccountName: {{ template "superset.serviceAccountName" . }}
{{- end }}
securityContext:
runAsUser: {{ .Values.runAsUser }}
{{- if .Values.supersetMcp.podSecurityContext }}
{{- toYaml .Values.supersetMcp.podSecurityContext | nindent 8 }}
{{- end }}
{{- if or .Values.supersetMcp.initContainers .Values.supersetMcp.extraInitContainers }}
initContainers:
{{- if .Values.supersetMcp.initContainers }}
{{- tpl (toYaml .Values.supersetMcp.initContainers) . | nindent 6 }}
{{- end }}
{{- if .Values.supersetMcp.extraInitContainers }}
{{- tpl (toYaml .Values.supersetMcp.extraInitContainers) . | nindent 6 }}
{{- end }}
{{- end }}
{{- with .Values.hostAliases }}
hostAliases: {{- toYaml . | nindent 6 }}
{{- end }}
containers:
- name: "{{ .Chart.Name }}-mcp"
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
{{- if .Values.supersetMcp.containerSecurityContext }}
securityContext: {{- toYaml .Values.supersetMcp.containerSecurityContext | nindent 12 }}
{{- end }}
command: {{ tpl (toJson .Values.supersetMcp.command) . }}
env:
{{- range $key, $value := .Values.extraEnv }}
- name: {{ $key | quote}}
value: {{ $value | quote }}
{{- end }}
{{- if .Values.extraEnvRaw }}
{{- toYaml .Values.extraEnvRaw | nindent 12 }}
{{- end }}
envFrom:
- secretRef:
name: {{ tpl .Values.envFromSecret . | quote }}
{{- range .Values.envFromSecrets }}
- secretRef:
name: {{ tpl . $ | quote }}
{{- end }}
ports:
- name: mcp
containerPort: {{ .Values.supersetMcp.service.port }}
protocol: TCP
volumeMounts:
- name: superset-config
mountPath: {{ .Values.configMountPath | quote }}
readOnly: true
{{- if .Values.extraConfigs }}
- name: superset-extra-config
mountPath: {{ .Values.extraConfigMountPath | quote }}
readOnly: true
{{- end }}
{{- with .Values.extraVolumeMounts }}
{{- tpl (toYaml .) $ | nindent 12 -}}
{{- end }}
{{- if .Values.supersetMcp.startupProbe }}
startupProbe: {{- .Values.supersetMcp.startupProbe | toYaml | nindent 12 }}
{{- end }}
{{- if .Values.supersetMcp.readinessProbe }}
readinessProbe: {{- .Values.supersetMcp.readinessProbe | toYaml | nindent 12 }}
{{- end }}
{{- if .Values.supersetMcp.livenessProbe }}
livenessProbe: {{- .Values.supersetMcp.livenessProbe | toYaml | nindent 12 }}
{{- end }}
{{- if .Values.supersetMcp.lifecycle }}
lifecycle: {{- .Values.supersetMcp.lifecycle | toYaml | nindent 12 }}
{{- end }}
resources:
{{- if .Values.supersetMcp.resources }}
{{- toYaml .Values.supersetMcp.resources | nindent 12 }}
{{- else }}
{{- toYaml .Values.resources | nindent 12 }}
{{- end }}
{{- if .Values.supersetMcp.extraContainers }}
{{- tpl (toYaml .Values.supersetMcp.extraContainers) . | nindent 8 }}
{{- end }}
{{- with .Values.nodeSelector }}
nodeSelector: {{- toYaml . | nindent 8 }}
{{- end }}
{{- if or .Values.affinity .Values.supersetMcp.affinity }}
affinity:
{{- with .Values.affinity }}
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.supersetMcp.affinity }}
{{- toYaml . | nindent 8 }}
{{- end }}
{{- end }}
{{- if .Values.supersetMcp.priorityClassName }}
priorityClassName: {{ .Values.supersetMcp.priorityClassName }}
{{- end }}
{{- if or .Values.topologySpreadConstraints .Values.supersetMcp.topologySpreadConstraints }}
topologySpreadConstraints:
{{- with .Values.topologySpreadConstraints }}
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.supersetMcp.topologySpreadConstraints }}
{{- toYaml . | nindent 8 }}
{{- end }}
{{- end }}
{{- with .Values.tolerations }}
tolerations: {{- toYaml . | nindent 8 }}
{{- end }}
{{- if .Values.supersetMcp.terminationGracePeriodSeconds }}
terminationGracePeriodSeconds: {{ .Values.supersetMcp.terminationGracePeriodSeconds }}
{{- end }}
{{- if .Values.imagePullSecrets }}
imagePullSecrets: {{- toYaml .Values.imagePullSecrets | nindent 8 }}
{{- end }}
volumes:
- name: superset-config
secret:
secretName: {{ tpl .Values.configFromSecret . }}
{{- if .Values.extraConfigs }}
- name: superset-extra-config
configMap:
name: {{ template "superset.fullname" . }}-extra-config
{{- end }}
{{- with .Values.extraVolumes }}
{{- tpl (toYaml .) $ | nindent 8 -}}
{{- end }}
{{- end -}}

View File

@@ -64,6 +64,15 @@ spec:
{{- if .Values.supersetWebsockets.podSecurityContext }}
{{- toYaml .Values.supersetWebsockets.podSecurityContext | nindent 8 }}
{{- end }}
{{- if or .Values.supersetWebsockets.initContainers .Values.supersetWebsockets.extraInitContainers }}
initContainers:
{{- if .Values.supersetWebsockets.initContainers }}
{{- tpl (toYaml .Values.supersetWebsockets.initContainers) . | nindent 6 }}
{{- end }}
{{- if .Values.supersetWebsockets.extraInitContainers }}
{{- tpl (toYaml .Values.supersetWebsockets.extraInitContainers) . | nindent 6 }}
{{- end }}
{{- end }}
{{- with .Values.hostAliases }}
hostAliases: {{- toYaml . | nindent 6 }}
{{- end }}

View File

@@ -0,0 +1,95 @@
{{/*
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
{{- if .Values.httproute.enabled -}}
{{- $fullName := include "superset.fullname" . -}}
apiVersion: {{ .Values.httproute.apiVersion | default "gateway.networking.k8s.io/v1" }}
kind: HTTPRoute
metadata:
name: {{ $fullName }}
namespace: {{ .Release.Namespace }}
labels:
app: {{ template "superset.name" . }}
chart: {{ template "superset.chart" . }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
{{- if .Values.extraLabels }}
{{- toYaml .Values.extraLabels | nindent 4 }}
{{- end }}
{{- with .Values.httproute.labels }}
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.httproute.annotations }}
annotations: {{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{- with .Values.httproute.parentRefs }}
parentRefs:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.httproute.hostnames }}
hostnames:
{{- tpl (toYaml .) $ | nindent 4 }}
{{- end }}
rules:
{{- range .Values.httproute.rules }}
- backendRefs:
- group: ''
kind: Service
name: {{ $fullName }}
port: {{ $.Values.service.port }}
weight: {{ .weight | default 1 }}
{{- with .filters }}
filters:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .matches }}
matches:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .timeouts }}
timeouts:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- end }}
{{- if .Values.supersetWebsockets.enabled }}
- backendRefs:
- group: ''
kind: Service
name: {{ $fullName }}-ws
port: {{ .Values.supersetWebsockets.service.port }}
weight: 1
matches:
- path:
type: PathPrefix
value: {{ .Values.supersetWebsockets.ingress.path }}
{{- end }}
{{- if and .Values.supersetMcp.enabled .Values.supersetMcp.httproute.enabled }}
- backendRefs:
- group: ''
kind: Service
name: {{ $fullName }}-mcp
port: {{ .Values.supersetMcp.service.port }}
weight: 1
matches:
- path:
type: PathPrefix
value: {{ .Values.supersetMcp.httproute.path }}
{{- end }}
{{- end }}

View File

@@ -64,6 +64,15 @@ spec:
port:
name: ws
{{- end }}
{{- if and $.Values.supersetMcp.enabled $.Values.supersetMcp.ingress.enabled }}
- path: {{ $.Values.supersetMcp.ingress.path }}
pathType: {{ $.Values.supersetMcp.ingress.pathType }}
backend:
service:
name: "{{ template "superset.fullname" $ }}-mcp"
port:
name: mcp
{{- end }}
{{- end }}
{{- if .Values.ingress.extraHostsRaw }}
{{- toYaml .Values.ingress.extraHostsRaw | nindent 4 }}

View File

@@ -0,0 +1,42 @@
{{/*
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
{{- with .Values.supersetMcp.podDisruptionBudget }}
{{- if .enabled -}}
{{- if and .minAvailable .maxUnavailable }}
{{- fail "Only one of minAvailable or maxUnavailable should be set" }}
{{- end}}
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: {{ include "superset.fullname" $ }}-mcp-pdb
labels:
{{- include "superset.componentLabels" (dict "component" "mcp" "root" $) | nindent 4 }}
spec:
{{- if .minAvailable }}
minAvailable: {{ .minAvailable }}
{{- end }}
{{- if .maxUnavailable }}
maxUnavailable: {{ .maxUnavailable }}
{{- end }}
selector:
matchLabels:
{{- include "supersetMcp.selectorLabels" $ | nindent 6 }}
{{- end }}
{{- end }}

View File

@@ -24,6 +24,9 @@ metadata:
namespace: {{ .Release.Namespace }}
labels:
{{- include "superset.labels" . | nindent 4 }}
{{- if .Values.secretEnv.annotations }}
annotations: {{- toYaml .Values.secretEnv.annotations | nindent 4 }}
{{- end }}
type: Opaque
stringData:
DB_HOST: {{ include "superset.db.host" . | quote }}

View File

@@ -24,6 +24,9 @@ metadata:
namespace: {{ .Release.Namespace }}
labels:
{{- include "superset.labels" . | nindent 4 }}
{{- if .Values.secretConfig.annotations }}
annotations: {{- toYaml .Values.secretConfig.annotations | nindent 4 }}
{{- end }}
type: Opaque
stringData:
superset_config.py: |

View File

@@ -25,6 +25,9 @@ metadata:
namespace: {{ .Release.Namespace }}
labels:
{{- include "superset.labels" . | nindent 4 }}
{{- if .Values.supersetWebsockets.configAnnotations }}
annotations: {{- toYaml .Values.supersetWebsockets.configAnnotations | nindent 4 }}
{{- end }}
type: Opaque
stringData:
config.json: |

View File

@@ -0,0 +1,46 @@
{{/*
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
{{- if .Values.supersetMcp.enabled }}
apiVersion: v1
kind: Service
metadata:
name: "{{ template "superset.fullname" . }}-mcp"
namespace: {{ .Release.Namespace }}
labels:
{{- include "superset.componentLabels" (dict "component" "mcp" "root" .) | nindent 4 }}
{{- with .Values.supersetMcp.service.annotations }}
annotations: {{- toYaml . | nindent 4 }}
{{- end }}
spec:
type: {{ .Values.supersetMcp.service.type }}
ports:
- port: {{ .Values.supersetMcp.service.port }}
targetPort: mcp
protocol: TCP
name: mcp
{{- if and (or (eq .Values.supersetMcp.service.type "NodePort") (eq .Values.supersetMcp.service.type "LoadBalancer")) (not (empty .Values.supersetMcp.service.nodePort.http)) }}
nodePort: {{ .Values.supersetMcp.service.nodePort.http }}
{{- end }}
selector:
{{- include "supersetMcp.selectorLabels" . | nindent 4 }}
{{- if .Values.supersetMcp.service.loadBalancerIP }}
loadBalancerIP: {{ .Values.supersetMcp.service.loadBalancerIP }}
{{- end }}
{{- end }}

View File

@@ -21,6 +21,7 @@ templates:
- deployment-beat.yaml
- deployment-flower.yaml
- deployment-ws.yaml
- deployment-mcp.yaml
tests:
- it: main deployment has new config checksums, not the old connections checksum
template: deployment.yaml
@@ -130,3 +131,24 @@ tests:
- equal:
path: 'spec.template.metadata.annotations.team'
value: data
- it: mcp deployment has config and database checksums
template: deployment-mcp.yaml
set:
supersetMcp:
enabled: true
asserts:
- exists:
path: 'spec.template.metadata.annotations["checksum/database"]'
- exists:
path: 'spec.template.metadata.annotations["checksum/config"]'
- it: mcp deployment applies globalPodAnnotations
template: deployment-mcp.yaml
set:
supersetMcp:
enabled: true
globalPodAnnotations:
team: data
asserts:
- equal:
path: 'spec.template.metadata.annotations.team'
value: data

View File

@@ -0,0 +1,92 @@
#
# 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.
#
suite: HTTPRoute
templates:
- httproute.yaml
tests:
- it: routes the general Superset path
set:
httproute.enabled: true
asserts:
- lengthEqual:
path: spec.rules
count: 1
- equal:
path: spec.rules[0].backendRefs[0].name
value: RELEASE-NAME-superset
- equal:
path: spec.rules[0].backendRefs[0].port
value: 8088
- equal:
path: spec.rules[0].matches[0].path.value
value: /
- it: routes the WebSocket path when WebSockets are enabled
set:
httproute.enabled: true
supersetWebsockets.enabled: true
asserts:
- lengthEqual:
path: spec.rules
count: 2
- equal:
path: spec.rules[1].backendRefs[0].name
value: RELEASE-NAME-superset-ws
- equal:
path: spec.rules[1].backendRefs[0].port
value: 8080
- equal:
path: spec.rules[1].matches[0].path.value
value: /ws
- it: does not route the WebSocket path when WebSockets are disabled
set:
httproute.enabled: true
supersetWebsockets.enabled: false
asserts:
- lengthEqual:
path: spec.rules
count: 1
- it: routes the MCP path when MCP HTTPRoute is enabled
set:
httproute.enabled: true
supersetMcp.enabled: true
supersetMcp.httproute.enabled: true
asserts:
- lengthEqual:
path: spec.rules
count: 2
- equal:
path: spec.rules[1].backendRefs[0].name
value: RELEASE-NAME-superset-mcp
- equal:
path: spec.rules[1].backendRefs[0].port
value: 5008
- equal:
path: spec.rules[1].matches[0].path.value
value: /mcp
- it: does not route MCP when MCP HTTPRoute is disabled
set:
httproute.enabled: true
supersetMcp.enabled: true
supersetMcp.httproute.enabled: false
asserts:
- lengthEqual:
path: spec.rules
count: 1

View File

@@ -20,6 +20,8 @@ templates:
- deployment-worker.yaml
- deployment-beat.yaml
- deployment-flower.yaml
- deployment-ws.yaml
- deployment-mcp.yaml
- init-job.yaml
tests:
- it: renders only the default wait-for container by default
@@ -150,6 +152,42 @@ tests:
path: spec.template.spec.initContainers[1].name
value: prepare-assets
- it: appends websockets extraInitContainers after wait-for-redis
template: deployment-ws.yaml
set:
supersetWebsockets.enabled: true
supersetWebsockets.extraInitContainers:
- name: prepare-assets
image: busybox
asserts:
- lengthEqual:
path: spec.template.spec.initContainers
count: 2
- equal:
path: spec.template.spec.initContainers[0].name
value: wait-for-redis
- equal:
path: spec.template.spec.initContainers[1].name
value: prepare-assets
- it: appends mcp extraInitContainers after wait-for-postgres-redis
template: deployment-mcp.yaml
set:
supersetMcp.enabled: true
supersetMcp.extraInitContainers:
- name: prepare-assets
image: busybox
asserts:
- lengthEqual:
path: spec.template.spec.initContainers
count: 2
- equal:
path: spec.template.spec.initContainers[0].name
value: wait-for-postgres-redis
- equal:
path: spec.template.spec.initContainers[1].name
value: prepare-assets
- it: appends init job extraInitContainers after wait-for-postgres
template: init-job.yaml
set:

View File

@@ -21,9 +21,11 @@ templates:
- deployment-beat.yaml
- deployment-flower.yaml
- deployment-ws.yaml
- deployment-mcp.yaml
- service.yaml
- service-ws.yaml
- service-flower.yaml
- service-mcp.yaml
- init-job.yaml
- ingress.yaml
- configmap-superset.yaml
@@ -34,6 +36,7 @@ templates:
- pdb-beat.yaml
- pdb-flower.yaml
- pdb-ws.yaml
- pdb-mcp.yaml
# These tests validate that Kubernetes recommended labels are consistently applied
# across all chart resources per https://kubernetes.io/docs/concepts/overview/working-with-objects/common-labels/
@@ -185,6 +188,36 @@ tests:
path: metadata.labels["app.kubernetes.io/component"]
value: websocket
# =============================================================================
# MCP Deployment Labels
# =============================================================================
- it: should have all recommended labels on mcp deployment
template: deployment-mcp.yaml
set:
supersetMcp.enabled: true
asserts:
- isNotNull:
path: metadata.labels["app.kubernetes.io/name"]
- isNotNull:
path: metadata.labels["app.kubernetes.io/instance"]
- isNotNull:
path: metadata.labels["app.kubernetes.io/version"]
- isNotNull:
path: metadata.labels["app.kubernetes.io/managed-by"]
- isNotNull:
path: metadata.labels["app.kubernetes.io/part-of"]
- isNotNull:
path: metadata.labels["app.kubernetes.io/component"]
- it: should have correct component label on mcp deployment
template: deployment-mcp.yaml
set:
supersetMcp.enabled: true
asserts:
- equal:
path: metadata.labels["app.kubernetes.io/component"]
value: mcp
# =============================================================================
# Service Labels
# =============================================================================
@@ -249,6 +282,27 @@ tests:
path: metadata.labels["app.kubernetes.io/component"]
value: flower
- it: should have all recommended labels on mcp service
template: service-mcp.yaml
set:
supersetMcp.enabled: true
asserts:
- isNotNull:
path: metadata.labels["app.kubernetes.io/name"]
- isNotNull:
path: metadata.labels["app.kubernetes.io/instance"]
- isNotNull:
path: metadata.labels["app.kubernetes.io/component"]
- it: should have correct component label on mcp service
template: service-mcp.yaml
set:
supersetMcp.enabled: true
asserts:
- equal:
path: metadata.labels["app.kubernetes.io/component"]
value: mcp
# =============================================================================
# Init Job Labels
# =============================================================================
@@ -366,6 +420,51 @@ tests:
path: spec.template.metadata.labels["app.kubernetes.io/component"]
value: worker
- it: should set selector matchLabels to concrete values on mcp deployment
template: deployment-mcp.yaml
set:
supersetMcp.enabled: true
asserts:
- equal:
path: spec.selector.matchLabels["app.kubernetes.io/name"]
value: superset
- equal:
path: spec.selector.matchLabels["app.kubernetes.io/instance"]
value: RELEASE-NAME
- equal:
path: spec.selector.matchLabels["app.kubernetes.io/component"]
value: mcp
- it: should match pod template labels to the selector on mcp deployment
template: deployment-mcp.yaml
set:
supersetMcp.enabled: true
asserts:
- equal:
path: spec.template.metadata.labels["app.kubernetes.io/name"]
value: superset
- equal:
path: spec.template.metadata.labels["app.kubernetes.io/instance"]
value: RELEASE-NAME
- equal:
path: spec.template.metadata.labels["app.kubernetes.io/component"]
value: mcp
- it: should set selector to concrete values on mcp service
template: service-mcp.yaml
set:
supersetMcp.enabled: true
asserts:
- equal:
path: spec.selector["app.kubernetes.io/name"]
value: superset
- equal:
path: spec.selector["app.kubernetes.io/instance"]
value: RELEASE-NAME
- equal:
path: spec.selector["app.kubernetes.io/component"]
value: mcp
# =============================================================================
# Extra Labels Support
# =============================================================================
@@ -505,6 +604,26 @@ tests:
path: spec.selector.matchLabels["app.kubernetes.io/component"]
value: websocket
- it: should have recommended labels and matching selector on mcp pdb
template: pdb-mcp.yaml
set:
supersetMcp.enabled: true
supersetMcp.podDisruptionBudget.enabled: true
supersetMcp.podDisruptionBudget.maxUnavailable: null
asserts:
- equal:
path: metadata.labels["app.kubernetes.io/instance"]
value: RELEASE-NAME
- equal:
path: metadata.labels["app.kubernetes.io/component"]
value: mcp
- equal:
path: spec.selector.matchLabels["app.kubernetes.io/instance"]
value: RELEASE-NAME
- equal:
path: spec.selector.matchLabels["app.kubernetes.io/component"]
value: mcp
- it: should use recommended labels on init job pod template
template: init-job.yaml
set:

View File

@@ -61,6 +61,8 @@ secretEnv:
# -- Change to false in order to support externally created secret (Binami "Sealed Secrets" for Kubernetes or External Secrets Operator)
# note: when externally creating the secret, the chart still expects to pull values from a secret with the name of the release defaults to `release-name-superset-env` - full logic located in _helpers.tpl file: `define "superset.fullname"`
create: true
# -- Annotations to be added to the secret
annotations: {}
# -- Specify service account name to be used
serviceAccountName: ~
@@ -82,6 +84,11 @@ bootstrapScript: |
# Note: this secret must have the key superset_config.py in it and can include other files as well
configFromSecret: '{{ template "superset.fullname" . }}-config'
# -- Specify whether Helm should apply additional settings to a secret containing configuration files
secretConfig:
# -- Annotations to be added to the secret which contains configuration files
annotations: {}
# -- The name of the secret which we will use to populate env vars in deployed pods
# This can be useful for secret keys, etc.
envFromSecret: '{{ template "superset.fullname" . }}-env'
@@ -91,13 +98,13 @@ envFromSecrets: []
# -- Extra environment variables that will be passed into pods
extraEnv: {}
# Different gunicorn settings, refer to the gunicorn documentation
# https://docs.gunicorn.org/en/stable/settings.html#
# https://gunicorn.org/reference/settings/
# These variables are used as Flags at the gunicorn startup
# https://github.com/apache/superset/blob/master/docker/run-server.sh#L22
# https://github.com/apache/superset/blob/master/docker/entrypoints/run-server.sh#L22
# Extend timeout to allow long running queries.
# GUNICORN_TIMEOUT: 300
# Increase the gunicorn worker amount, can improve performance drastically
# See: https://docs.gunicorn.org/en/stable/design.html#how-many-workers
# See: https://gunicorn.org/design/#how-many-workers
# SERVER_WORKER_AMOUNT: 4
# WORKER_MAX_REQUESTS: 0
# WORKER_MAX_REQUESTS_JITTER: 0
@@ -246,6 +253,42 @@ ingress:
# hosts:
# - chart-example.local
# -- Gateway API HTTPRoute for exposing Superset via a Gateway.
# Requires the Gateway API CRDs (gateway.networking.k8s.io/v1) installed in the cluster.
# @default -- see `values.yaml`
httproute:
enabled: false
# -- HTTPRoute apiVersion. Override to gateway.networking.k8s.io/v1beta1 for
# older Gateway API installations that have not promoted HTTPRoute to v1.
apiVersion: gateway.networking.k8s.io/v1
# -- Additional labels to add to the HTTPRoute
labels: {}
# -- Annotations to add to the HTTPRoute
annotations: {}
# -- Gateways this HTTPRoute attaches to
parentRefs: []
# - name: my-gateway
# namespace: gateway-system
# sectionName: https
# -- Hostnames that match against the HTTP Host header (templated)
hostnames: []
# - chart-example.local
# -- Routing rules. Each rule is backed by the Superset service. Set `weight`
# per rule to leave room for traffic splitting (defaults to 1). When
# `supersetWebsockets.enabled` is true, an extra rule routing
# `supersetWebsockets.ingress.path` to the `-ws` service is appended
# automatically, mirroring the ingress behavior. When both `supersetMcp.enabled` and
# `supersetMcp.httproute.enabled` are true, an extra rule routing
# `supersetMcp.httproute.path` to the `-mcp` service is also appended.
rules:
- matches:
- path:
type: PathPrefix
value: /
# weight: 1
# filters: []
# timeouts: {}
resources: {}
# We usually recommend not to specify default resources and to leave this as a conscious
# choice for the user. This also increases chances charts run on environments with little
@@ -858,6 +901,8 @@ supersetWebsockets:
"jwtSecret": "CHANGE-ME",
"jwtCookieName": "async-token",
}
# -- Annotations to be added to the secret which contains config.json
configAnnotations: {}
service:
type: ClusterIP
annotations: {}
@@ -867,6 +912,38 @@ supersetWebsockets:
# -- (int)
http: nil
command: []
# -- List of initContainers
# @default -- a container waiting for redis
initContainers:
- name: wait-for-redis
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: "{{ .Values.image.pullPolicy }}"
envFrom:
- secretRef:
name: "{{ tpl .Values.envFromSecret . }}"
command:
- /bin/bash
- -c
- |
# See supersetNode.initContainers for the rationale.
SECONDS=0
until (exec 3<>/dev/tcp/"$REDIS_HOST"/"$REDIS_PORT") 2>/dev/null; do
if [ "$SECONDS" -ge 120 ]; then
echo "timeout waiting for redis at $REDIS_HOST:$REDIS_PORT after 120s" >&2
exit 1
fi
echo "waiting for redis at $REDIS_HOST:$REDIS_PORT (elapsed ${SECONDS}s)"
sleep 2
done
echo "redis at $REDIS_HOST:$REDIS_PORT is up"
resources:
limits:
memory: "256Mi"
requests:
cpu: "250m"
memory: "128Mi"
# -- Extra init containers appended after supersetWebsockets initContainers
extraInitContainers: []
resources: {}
# -- Launch additional containers into supersetWebsockets pods
extraContainers: []
@@ -912,6 +989,147 @@ supersetWebsockets:
# -- Set priorityClassName for supersetWebsockets pods
priorityClassName: ~
supersetMcp:
# -- Enables the Superset MCP Server. To expose it via the shared ingress at /mcp,
# also set supersetMcp.ingress.enabled=true.
# WARNING: this requires fastMCP to be installed, which can be done by installing `apache-superset[fastmcp]`
enabled: false
replicaCount: 1
# -- Sets the [pod disruption budget](https://kubernetes.io/docs/tasks/run-application/configure-pdb/) for supersetMcp pods
podDisruptionBudget:
# -- Whether the pod disruption budget should be created
enabled: false
# -- If set, maxUnavailable must not be set - see https://kubernetes.io/docs/tasks/run-application/configure-pdb/\#specifying-a-poddisruptionbudget
minAvailable: 1
# -- If set, minAvailable must not be set - see https://kubernetes.io/docs/tasks/run-application/configure-pdb/\#specifying-a-poddisruptionbudget
maxUnavailable: 1
# -- Command
# @default -- a `superset mcp run` command
command:
- "/bin/sh"
- "-c"
- ". {{ .Values.configMountPath }}/superset_bootstrap.sh; superset mcp run --host 0.0.0.0 --port {{ .Values.supersetMcp.service.port }}"
# -- If true, forces deployment to reload on each upgrade
forceReload: false
ingress:
# -- If true, the MCP server will be exposed via the ingress /mcp subpath
enabled: false
path: /mcp
pathType: Prefix
httproute:
# -- If true, the MCP server will be exposed via the HTTPRoute /mcp subpath
enabled: false
path: /mcp
service:
type: ClusterIP
annotations: {}
loadBalancerIP: ~
port: 5008
nodePort:
# -- (int)
http: nil
startupProbe:
httpGet:
path: /health
port: mcp
initialDelaySeconds: 15
timeoutSeconds: 3
failureThreshold: 60
periodSeconds: 5
successThreshold: 1
livenessProbe:
httpGet:
path: /health
port: mcp
initialDelaySeconds: 15
timeoutSeconds: 3
failureThreshold: 3
periodSeconds: 15
successThreshold: 1
readinessProbe:
httpGet:
path: /health
port: mcp
initialDelaySeconds: 15
timeoutSeconds: 3
failureThreshold: 3
periodSeconds: 15
successThreshold: 1
# -- List of init containers
# @default -- a container waiting for postgres and redis
initContainers:
- name: wait-for-postgres-redis
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: "{{ .Values.image.pullPolicy }}"
envFrom:
- secretRef:
name: "{{ tpl .Values.envFromSecret . }}"
command:
- /bin/bash
- -c
- |
# See supersetNode.initContainers for the rationale.
SECONDS=0
wait_for() {
local host=$1 port=$2 name=$3
until (exec 3<>/dev/tcp/"$host"/"$port") 2>/dev/null; do
if [ "$SECONDS" -ge 120 ]; then
echo "timeout waiting for $name at $host:$port after 120s" >&2
exit 1
fi
echo "waiting for $name at $host:$port (elapsed ${SECONDS}s)"
sleep 2
done
echo "$name at $host:$port is up"
}
wait_for "$DB_HOST" "$DB_PORT" postgres
wait_for "$REDIS_HOST" "$REDIS_PORT" redis
resources:
limits:
memory: "256Mi"
requests:
cpu: "250m"
memory: "128Mi"
# -- Extra init containers appended after supersetMcp initContainers
extraInitContainers: []
# -- Launch additional containers into supersetMcp pods
extraContainers: []
# -- Annotations to be added to supersetMcp deployment
deploymentAnnotations: {}
# -- Labels to be added to supersetMcp deployment
deploymentLabels: {}
# -- Custom pod spec to be added to supersetMcp deployment
deploymentAdditionalPodSpec: {}
# -- Affinity to be added to supersetMcp deployment
affinity: {}
# -- TopologySpreadConstrains to be added to supersetMcp deployments
topologySpreadConstraints: []
# -- Annotations to be added to supersetMcp pods
podAnnotations: {}
# -- Labels to be added to supersetMcp pods
podLabels: {}
strategy: {}
# type: RollingUpdate
# rollingUpdate:
# maxSurge: 25%
# maxUnavailable: 25%
# -- Container lifecycle hooks for the worker pod
lifecycle: {}
# -- Pod termination grace period (seconds) for the worker pod so in-flight tasks can drain before SIGKILL
terminationGracePeriodSeconds: ~
# -- Resource settings for the supersetMcp pods - these settings overwrite might existing values from the global resources object defined above.
resources: {}
# limits:
# cpu: 100m
# memory: 128Mi
# requests:
# cpu: 100m
# memory: 128Mi
podSecurityContext: {}
containerSecurityContext: {}
# -- Set priorityClassName for supersetMcp pods
priorityClassName: ~
init:
# Configure resources
# Warning: fab command consumes a lot of ram and can

View File

@@ -24,13 +24,12 @@ name = "apache_superset"
description = "A modern, enterprise-ready business intelligence web application"
readme = "README.md"
dynamic = ["version", "scripts", "entry-points"]
requires-python = ">=3.10"
requires-python = ">=3.11"
license = { file="LICENSE.txt" }
authors = [
{ name = "Apache Software Foundation", email = "dev@superset.apache.org" },
]
classifiers = [
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
]
@@ -63,7 +62,7 @@ dependencies = [
"flask-session>=0.4.0, <1.0",
"flask-wtf>=1.3.0, <2.0",
"geopy",
"greenlet<=3.5.1, >=3.5.1",
"greenlet<=3.5.3, >=3.5.3",
"gunicorn>=26.0.0, <27; sys_platform != 'win32'",
"hashids>=1.3.1, <2",
# holidays>=0.45 required for security fix
@@ -84,7 +83,7 @@ dependencies = [
"packaging",
# --------------------------
# pandas and related (wanting pandas[performance] without numba as it's 100+MB and not needed)
"pandas[excel]>=2.1.4, <2.4",
"pandas[excel]>=2.3.3, <2.4",
"bottleneck", # recommended performance dependency for pandas, see https://pandas.pydata.org/docs/getting_started/install.html#performance-dependencies-recommended
# --------------------------
"parsedatetime",
@@ -100,20 +99,20 @@ dependencies = [
"pyarrow>=24.0.0, <25", # before upgrading pyarrow, check that all db dependencies support this, see e.g. https://github.com/apache/superset/pull/34693
"pyyaml>=6.0.3, <7.0.0",
"PyJWT>=2.4.0, <3.0",
"redis>=5.0.0, <6.0",
"redis>=5.0.0, <9.0",
"rison>=2.0.1, <3.0",
"selenium>=4.45.0, <5.0",
"shillelagh[gsheetsapi]>=1.4.4, <2.0",
"sshtunnel>=0.4.0, <0.5",
"simplejson>=4.1.1",
"slack_sdk>=3.43.0, <4",
"sqlalchemy>=1.4, <2",
"sqlalchemy>=1.4.43, <2", # 1.4.43 adds the python-oracledb (oracle+oracledb) dialect
"sqlalchemy-continuum>=1.6.0, <2.0.0",
"sqlalchemy-utils>=0.42.1, <0.43", # expanding lowerbound to work with pydoris
"sqlglot>=30.12.0, <31",
# newer pandas needs 0.9+
"tabulate>=0.10.0, <1.0",
"typing-extensions>=4, <5",
"typing-extensions>=4.16.0, <5",
"waitress; sys_platform == 'win32'",
"watchdog>=6.0.0",
"wtforms>=3.2.2, <4",
@@ -126,7 +125,7 @@ dependencies = [
athena = ["pyathena[pandas]>=2, <4"]
aurora-data-api = ["preset-sqlalchemy-aurora-data-api>=0.2.8,<0.3"]
bigquery = [
"pandas-gbq>=0.19.1",
"pandas-gbq>=0.35.0",
"sqlalchemy-bigquery>=1.17.0",
"google-cloud-bigquery>=3.42.1",
]
@@ -140,20 +139,25 @@ d1 = [
]
databend = ["databend-sqlalchemy>=0.5.5, <1.0"]
databricks = [
"databricks-sql-connector==4.2.6",
"databricks-sql-connector>=4.2.6, <4.4.0",
"databricks-sqlalchemy==1.0.5",
]
datafusion = ["flightsql-dbapi>=0.2.0, <0.3"]
db2 = ["ibm-db-sa>0.3.8, <=0.4.4"]
denodo = ["denodo-sqlalchemy>=2.0.5,<2.1.0"]
dremio = ["sqlalchemy-dremio>=1.2.1, <4"]
drill = ["sqlalchemy-drill>=1.1.10, <2"]
druid = ["pydruid>=0.6.5,<0.7"]
duckdb = ["duckdb>=1.5.4,<2", "duckdb-engine>=0.17.0"]
dynamodb = ["pydynamodb>=0.4.2"]
dynamodb = ["pydynamodb>=0.8.2"]
solr = ["sqlalchemy-solr >= 0.2.4.3"]
elasticsearch = ["elasticsearch-dbapi>=0.2.13, <0.3.0"]
exasol = ["sqlalchemy-exasol>=2.4.0, <8.0"]
excel = ["xlrd>=2.0.2, <2.1"]
# Async dashboard "Export Data/Images to Excel": uploads the workbook to S3 and
# emails a pre-signed link. boto3 is imported lazily by superset.utils.s3, so
# installing this extra is only required to actually run exports.
excel-export = ["boto3"]
fastmcp = [
"fastmcp>=3.4.3,<4.0",
# tiktoken backs the response-size-guard token estimator. Without
@@ -165,9 +169,8 @@ firebird = ["sqlalchemy-firebird>=0.8.0, <2.2"]
firebolt = ["firebolt-sqlalchemy>=1.0.0, <2"]
gevent = ["gevent>=26.4.0"]
gsheets = ["shillelagh[gsheetsapi]>=1.4.4, <2"]
hana = ["hdbcli==2.29.23", "sqlalchemy_hana==3.0.3"]
hana = ["hdbcli==2.29.25", "sqlalchemy_hana==3.0.3"]
hive = [
"pyhive[hive]>=0.6.5;python_version<'3.11'",
"pyhive[hive_pure_sasl]>=0.7.0",
"tableschema",
"thrift>=0.23.0, <1.0.0",
@@ -201,19 +204,18 @@ singlestore = ["sqlalchemy-singlestoredb>=1.2.1, <2"]
snowflake = ["snowflake-sqlalchemy>=1.10.2, <2"]
sqlite = ["syntaqlite>=0.7.0,<0.8.0"]
spark = [
"pyhive[hive]>=0.6.5;python_version<'3.11'",
"pyhive[hive_pure_sasl]>=0.7",
"tableschema",
"thrift>=0.23.0, <1",
]
tdengine = [
"taospy>=2.8.9",
"taos-ws-py>=0.6.9"
"taos-ws-py>=0.7.0"
]
teradata = ["teradatasql>=20.0.0.62"]
thumbnails = [] # deprecated, will be removed in 7.0
vertica = ["sqlalchemy-vertica-python>= 0.6.3, < 0.7"]
netezza = ["nzalchemy>=11.0.2, < 11.2"]
netezza = ["nzalchemy>= 11.1.2, < 11.2"]
starrocks = ["starrocks>=1.3.3, <2"]
doris = ["pydoris>=1.2.0, <2.0.0"]
oceanbase = ["oceanbase_py>=0.0.1.2"]
@@ -344,8 +346,8 @@ exclude = [
line-length = 88
indent-width = 4
# Assume Python 3.10
target-version = "py310"
# Assume Python 3.11
target-version = "py311"
[tool.ruff.lint]
# Enable Pyflakes (`F`) and a subset of the pycodestyle (`E`) codes by default.

View File

@@ -29,18 +29,16 @@ filterwarnings =
ignore
always::sqlalchemy.exc.RemovedIn20Warning
error:Passing a string to Connection.execute\(\) is deprecated:sqlalchemy.exc.RemovedIn20Warning
# error:"Query" object is being merged into a Session:sqlalchemy.exc.RemovedIn20Warning
# error:"SavedQuery" object is being merged into a Session:sqlalchemy.exc.RemovedIn20Warning
# error:"SqlaTable" object is being merged into a Session:sqlalchemy.exc.RemovedIn20Warning
# error:"SqlMetric" object is being merged into a Session:sqlalchemy.exc.RemovedIn20Warning
# error:"TableColumn" object is being merged into a Session:sqlalchemy.exc.RemovedIn20Warning
# error:"TaggedObject" object is being merged into a Session:sqlalchemy.exc.RemovedIn20Warning
error:"Query" object is being merged into a Session:sqlalchemy.exc.RemovedIn20Warning
error:"SavedQuery" object is being merged into a Session:sqlalchemy.exc.RemovedIn20Warning
error:"SqlaTable" object is being merged into a Session:sqlalchemy.exc.RemovedIn20Warning
error:"SqlMetric" object is being merged into a Session:sqlalchemy.exc.RemovedIn20Warning
error:"TableColumn" object is being merged into a Session:sqlalchemy.exc.RemovedIn20Warning
error:"TaggedObject" object is being merged into a Session:sqlalchemy.exc.RemovedIn20Warning
error:The autoload parameter is deprecated:sqlalchemy.exc.RemovedIn20Warning
error:The current statement is being autocommitted using implicit autocommit:sqlalchemy.exc.RemovedIn20Warning
error:The connection.execute\(\) method:sqlalchemy.exc.RemovedIn20Warning
# error:The current statement is being autocommitted using implicit autocommit:sqlalchemy.exc.RemovedIn20Warning
error:The current statement is being autocommitted using implicit autocommit:sqlalchemy.exc.RemovedIn20Warning
error:The ``declarative_base\(\)`` function is now available:sqlalchemy.exc.RemovedIn20Warning
error:The Engine.execute\(\) method is considered legacy:sqlalchemy.exc.RemovedIn20Warning
error:The legacy calling style of select\(\) is deprecated:sqlalchemy.exc.RemovedIn20Warning
error:The "whens" argument to case:sqlalchemy.exc.RemovedIn20Warning
# error:"User" object is being merged into a Session:sqlalchemy.exc.RemovedIn20Warning

View File

@@ -28,6 +28,8 @@ babel==2.17.0
# via flask-babel
backoff==2.2.1
# via apache-superset (pyproject.toml)
backports-zstd==1.6.0
# via flask-compress
bcrypt==4.3.0
# via paramiko
billiard==4.2.1
@@ -130,7 +132,7 @@ flask-babel==3.1.0
# via flask-appbuilder
flask-caching==2.3.1
# via apache-superset (pyproject.toml)
flask-compress==1.17
flask-compress==1.24
# via apache-superset (pyproject.toml)
flask-cors==6.0.5
# via apache-superset (pyproject.toml)
@@ -164,7 +166,7 @@ google-auth==2.53.0
# via
# -r requirements/base.in
# shillelagh
greenlet==3.5.1
greenlet==3.5.3
# via
# apache-superset (pyproject.toml)
# shillelagh
@@ -244,7 +246,7 @@ msgpack==1.2.1
# via apache-superset (pyproject.toml)
msgspec==0.19.0
# via flask-session
nh3==0.3.5
nh3==0.3.6
# via apache-superset (pyproject.toml)
numexpr==2.10.2
# via -r requirements/base.in
@@ -275,7 +277,7 @@ packaging==25.0
# kombu
# limits
# shillelagh
pandas==2.1.4
pandas==2.3.3
# via apache-superset (pyproject.toml)
paramiko==3.5.1
# via
@@ -285,7 +287,7 @@ parsedatetime==2.6
# via apache-superset (pyproject.toml)
pgsanity==0.2.9
# via apache-superset (pyproject.toml)
pillow==12.2.0
pillow==12.3.0
# via apache-superset (pyproject.toml)
platformdirs==4.3.8
# via requests-cache
@@ -300,17 +302,17 @@ pyarrow==24.0.0
# -r requirements/base.in
# apache-superset (pyproject.toml)
# apache-superset-core
pyasn1==0.6.3
pyasn1==0.6.4
# via pyasn1-modules
pyasn1-modules==0.4.2
# via google-auth
pycparser==2.22
# via cffi
pydantic==2.11.7
pydantic==2.13.4
# via
# apache-superset (pyproject.toml)
# apache-superset-core
pydantic-core==2.33.2
pydantic-core==2.46.4
# via pydantic
pygeohash==3.2.2
# via apache-superset (pyproject.toml)
@@ -321,7 +323,6 @@ pyjwt==2.13.0
# apache-superset (pyproject.toml)
# flask-appbuilder
# flask-jwt-extended
# redis
pynacl==1.6.2
# via paramiko
pyopenssl==26.3.0
@@ -332,6 +333,8 @@ pyparsing==3.2.3
# via apache-superset (pyproject.toml)
pysocks==1.7.1
# via urllib3
python-calamine==0.8.2
# via pandas
python-dateutil==2.9.0.post0
# via
# apache-superset (pyproject.toml)
@@ -353,7 +356,7 @@ pyyaml==6.0.3
# via
# apache-superset (pyproject.toml)
# apispec
redis==5.3.1
redis==8.0.1
# via apache-superset (pyproject.toml)
referencing==0.36.2
# via
@@ -407,7 +410,7 @@ sqlalchemy==1.4.54
# shillelagh
# sqlalchemy-continuum
# sqlalchemy-utils
sqlalchemy-continuum==1.6.0
sqlalchemy-continuum==1.7.0
# via apache-superset (pyproject.toml)
sqlalchemy-utils==0.42.1
# via
@@ -428,7 +431,7 @@ trio==0.33.0
# trio-websocket
trio-websocket==0.12.2
# via selenium
typing-extensions==4.15.0
typing-extensions==4.16.0
# via
# apache-superset (pyproject.toml)
# alembic
@@ -442,7 +445,7 @@ typing-extensions==4.15.0
# selenium
# shillelagh
# typing-inspection
typing-inspection==0.4.1
typing-inspection==0.4.2
# via pydantic
tzdata==2025.2
# via
@@ -495,5 +498,3 @@ xlsxwriter==3.2.9
# via
# apache-superset (pyproject.toml)
# pandas
zstandard==0.23.0
# via flask-compress

View File

@@ -64,6 +64,10 @@ backoff==2.2.1
# apache-superset
backports-tarfile==1.2.0
# via jaraco-context
backports-zstd==1.6.0
# via
# -c requirements/base-constraint.txt
# flask-compress
bcrypt==4.3.0
# via
# -c requirements/base-constraint.txt
@@ -276,7 +280,7 @@ flask-caching==2.3.1
# via
# -c requirements/base-constraint.txt
# apache-superset
flask-compress==1.17
flask-compress==1.24
# via
# -c requirements/base-constraint.txt
# apache-superset
@@ -340,7 +344,6 @@ gevent==26.4.0
google-api-core==2.23.0
# via
# google-cloud-bigquery
# google-cloud-bigquery-storage
# google-cloud-core
# pandas-gbq
# sqlalchemy-bigquery
@@ -350,7 +353,6 @@ google-auth==2.53.0
# google-api-core
# google-auth-oauthlib
# google-cloud-bigquery
# google-cloud-bigquery-storage
# google-cloud-core
# pandas-gbq
# pydata-google-auth
@@ -365,8 +367,6 @@ google-cloud-bigquery==3.42.1
# apache-superset
# pandas-gbq
# sqlalchemy-bigquery
google-cloud-bigquery-storage==2.26.0
# via pandas-gbq
google-cloud-core==2.4.1
# via google-cloud-bigquery
google-crc32c==1.6.0
@@ -377,7 +377,7 @@ googleapis-common-protos==1.66.0
# via
# google-api-core
# grpcio-status
greenlet==3.5.1
greenlet==3.5.3
# via
# -c requirements/base-constraint.txt
# apache-superset
@@ -574,7 +574,7 @@ msgspec==0.19.0
# flask-session
mysqlclient==2.2.8
# via apache-superset
nh3==0.3.5
nh3==0.3.6
# via
# -c requirements/base-constraint.txt
# apache-superset
@@ -638,10 +638,11 @@ packaging==25.0
# kombu
# limits
# matplotlib
# pandas-gbq
# pytest
# shillelagh
# sqlalchemy-bigquery
pandas==2.1.4
pandas==2.3.3
# via
# -c requirements/base-constraint.txt
# apache-superset
@@ -649,7 +650,7 @@ pandas==2.1.4
# db-dtypes
# pandas-gbq
# prophet
pandas-gbq==0.19.1
pandas-gbq==0.35.0
# via apache-superset
parameterized==0.9.0
# via apache-superset
@@ -668,7 +669,7 @@ pgsanity==0.2.9
# via
# -c requirements/base-constraint.txt
# apache-superset
pillow==12.2.0
pillow==12.3.0
# via
# -c requirements/base-constraint.txt
# apache-superset
@@ -705,18 +706,17 @@ prompt-toolkit==3.0.51
prophet==1.2.0
# via apache-superset
proto-plus==1.25.0
# via
# google-api-core
# google-cloud-bigquery-storage
# via google-api-core
protobuf==5.29.6
# via
# google-api-core
# google-cloud-bigquery-storage
# googleapis-common-protos
# grpcio-status
# proto-plus
psutil==6.1.0
# via apache-superset
# via
# apache-superset
# pandas-gbq
psycopg2-binary==2.9.12
# via apache-superset
py-key-value-aio==0.4.4
@@ -728,7 +728,7 @@ pyarrow==24.0.0
# apache-superset-core
# db-dtypes
# pandas-gbq
pyasn1==0.6.3
pyasn1==0.6.4
# via
# -c requirements/base-constraint.txt
# pyasn1-modules
@@ -742,7 +742,7 @@ pycparser==2.22
# via
# -c requirements/base-constraint.txt
# cffi
pydantic==2.11.7
pydantic==2.13.4
# via
# -c requirements/base-constraint.txt
# apache-superset
@@ -751,7 +751,7 @@ pydantic==2.11.7
# mcp
# openapi-pydantic
# pydantic-settings
pydantic-core==2.33.2
pydantic-core==2.46.4
# via
# -c requirements/base-constraint.txt
# pydantic
@@ -784,7 +784,6 @@ pyjwt==2.13.0
# flask-appbuilder
# flask-jwt-extended
# mcp
# redis
pylint==3.3.7
# via apache-superset
pynacl==1.6.2
@@ -824,6 +823,10 @@ pytest-mock==3.10.0
# via
# apache-superset
# apache-superset-extensions-cli
python-calamine==0.8.2
# via
# -c requirements/base-constraint.txt
# pandas
python-dateutil==2.9.0.post0
# via
# -c requirements/base-constraint.txt
@@ -870,7 +873,7 @@ pyyaml==6.0.3
# fastmcp-slim
# jsonschema-path
# pre-commit
redis==5.3.1
redis==8.0.1
# via
# -c requirements/base-constraint.txt
# apache-superset
@@ -988,7 +991,7 @@ sqlalchemy==1.4.54
# sqlalchemy-utils
sqlalchemy-bigquery==1.17.0
# via apache-superset
sqlalchemy-continuum==1.6.0
sqlalchemy-continuum==1.7.0
# via
# -c requirements/base-constraint.txt
# apache-superset
@@ -1044,7 +1047,7 @@ trio-websocket==0.12.2
# via
# -c requirements/base-constraint.txt
# selenium
typing-extensions==4.15.0
typing-extensions==4.16.0
# via
# -c requirements/base-constraint.txt
# alembic
@@ -1067,7 +1070,7 @@ typing-extensions==4.15.0
# shillelagh
# starlette
# typing-inspection
typing-inspection==0.4.1
typing-inspection==0.4.2
# via
# -c requirements/base-constraint.txt
# mcp
@@ -1169,7 +1172,4 @@ zope-event==5.0
zope-interface==5.4.0
# via gevent
zstandard==0.23.0
# via
# -c requirements/base-constraint.txt
# flask-compress
# trino
# via trino

View File

@@ -93,7 +93,7 @@ def find_models(module: ModuleType) -> list[type[Model]]: # noqa: C901
# where the current model is out-of-sync with the existing table after a
# downgrade
sqlalchemy_uri = current_app.config["SQLALCHEMY_DATABASE_URI"]
engine = create_engine(sqlalchemy_uri)
engine = create_engine(sqlalchemy_uri, future=True)
Base = automap_base() # noqa: N806
Base.prepare(engine, reflect=True)
seen = set()

View File

@@ -133,8 +133,8 @@ def main(docker: bool, frontend: bool, backend: bool) -> None: # noqa: C901
requirements = [
Requirement(
"python",
(Version("3.10.0"), Version("3.10.999")),
(Version("3.9.0"), Version("3.11.999")),
(Version("3.11.0"), Version("3.11.999")),
(Version("3.11.0"), Version("3.12.999")),
"backend",
"python --version",
),

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