Compare commits

...

235 Commits

Author SHA1 Message Date
Đỗ Trọng Hải
ff83620354 feat(sec): harden GHA ref by using its SHA ID to prevent accidental usage of compromised actions (#38782)
Signed-off-by: hainenber <dotronghai96@gmail.com>
(cherry picked from commit 83823911b5)
2026-04-15 08:48:43 -03:00
Luiz Otavio
9549cbb8ba fix(native-filters): prevent infinite recursion in filter scope tree traversal (#39355)
(cherry picked from commit 86575e129b)
2026-04-15 08:22:08 -03:00
Michael S. Molina
1e3c46038c chore: Install setuptools 2026-03-18 13:39:00 -03:00
Michael S. Molina
5731355ff2 fix(chart): prevent chart list from failing when a datasource lacks explore_url (#38721)
(cherry picked from commit fd1c423826)
2026-03-18 13:09:02 -03:00
justinpark
ccaf2c921b remove spec 2026-02-09 10:54:30 -08:00
justinpark
03214c1ca8 theme color change 2026-02-09 10:28:24 -08:00
justinpark
5159c27bdc lint fix 2026-02-09 09:12:08 -08:00
JUST.in DO IT
f3b21ecaa2 fix(world-map): reset hover highlight on mouse out (#37716)
Co-authored-by: Arunodoy18 <arunodoy630@gmail.com>
(cherry picked from commit a04571fa20)
2026-02-06 10:36:34 -08:00
justinpark
677e440a94 remove duplicated configs 2026-02-03 13:38:30 -08:00
JUST.in DO IT
e30a0b0a8f fix(dashboard): Avoid calling loadData for invisible charts on virtual rendering (#37452)
(cherry picked from commit be404f9b84)
2026-02-02 14:36:42 -08:00
justinpark
3f45502bb3 pylint and current_app related change in spec 2026-01-06 08:56:35 -08:00
justinpark
3a6bd39dd7 fix(trino): update query progress using cursor stats (#36872)
(cherry picked from commit 12a266fd2f)
2026-01-05 14:05:42 -08:00
JUST.in DO IT
34ebb8a7dc chore(sqllab): add logging for switching south panel tabs (#36168) (#36369) 2025-12-02 10:32:55 -08:00
Michael S. Molina
853143ad4a fix: Parsing error handling 2025-11-26 10:43:12 -05:00
Michael S. Molina
8060b01b68 fix: Changes ResultSet to include sqlEditorImmutableId when fetching results (#35773)
(cherry picked from commit 337da13ba7)
2025-10-21 14:32:33 -03:00
Michael S. Molina
5f0059bf68 fix: Extension events not fired in SQL Lab tabs (#35753)
(cherry picked from commit fa90ba976c)
2025-10-20 16:46:09 -03:00
Ville Brofeldt
bfd31ccba7 fix: no fs logging of extensions unless flag is set (#35612)
Co-authored-by: Ville Brofeldt <v_brofeldt@apple.com>
(cherry picked from commit bd48e87eeb)
2025-10-15 08:42:35 -03:00
Luiz Otavio
fc9e94e82d fix(csv upload): Correctly casting to string numbers with floating points (e+) (#35586)
(cherry picked from commit 17ebbdd966)
2025-10-13 15:41:05 -03:00
Michael S. Molina
5b39116dea refactor: Organizes the src/core folder (#35119)
(cherry picked from commit bc6859a99d)
2025-09-19 09:29:24 -03:00
Michael S. Molina
84b81b814e fix: SQL Lab tab events (#35105)
(cherry picked from commit e729b2dbb4)
2025-09-11 18:25:49 -03:00
JUST.in DO IT
47485093b9 feat(sqllab extension): core query interface api (#35077)
(cherry picked from commit 078c1701f4)
2025-09-11 18:24:18 -03:00
Michael S. Molina
5c43b13c1e fix: Change database event in core (#35071)
(cherry picked from commit 4c2b27e7f0)
2025-09-09 11:59:09 -03:00
Luiz Otavio
bf7c97d807 fix: Upload CSV as Dataset (#34763)
(cherry picked from commit 1c2b9db4f0)
2025-09-09 10:13:10 -03:00
JUST.in DO IT
fea386309a fix(echarts): rename time series shifted for isTimeComparisonValue (#35022)
(cherry picked from commit bc54b7970a)
2025-09-09 10:09:43 -03:00
Michael S. Molina
e7296ea709 fix: apache-superset-extensions-cli exported files
(cherry picked from commit b0ca61cbe0)
2025-09-02 16:04:49 -03:00
Michael S. Molina
ad81dc6d9a fix: apache-superset-core exported packages (#34977)
(cherry picked from commit 322442d5be)
2025-09-02 15:25:15 -03:00
Michael S. Molina
63612096c1 fix: Add tests to improve test coverage 2025-09-01 10:57:25 -03:00
Michael S. Molina
9bb5a39ec7 fix: Footer test mock 2025-09-01 10:50:09 -03:00
Michael S. Molina
1f5452179c fix: Skip coverage for @apache-superset/core 2025-09-01 10:23:14 -03:00
Michael S. Molina
150d0a3439 fix: Remove useTheme from test files 2025-09-01 10:01:23 -03:00
Michael S. Molina
c5463d6675 fix: Update @apache-superset/core reference in package-lock.json 2025-09-01 09:26:56 -03:00
Michael S. Molina
383f5389f3 fix: Rename apache-superset-cli to apache-superset-extensions-cli (#34883)
(cherry picked from commit bcf156c969)
2025-08-28 15:45:55 -03:00
Joe Li
ccd0ca3c32 fix: Update apache-superset-core dependency to accept rc1 version (#34872)
Co-authored-by: Claude <noreply@anthropic.com>
(cherry picked from commit b558b34faf)
2025-08-28 10:11:56 -03:00
Michael S. Molina
cc62e437dc chore: Adds README and CHANGELOG to apache-superset-core and apache-superset-cli (#34867)
(cherry picked from commit 30c72ba0a3)
2025-08-28 10:08:53 -03:00
Michael S. Molina
9b5634356a chore: Adds a README and CHANGELOG to @apache-superset/core (#34866)
(cherry picked from commit d8a3d29ad9)
2025-08-28 10:08:40 -03:00
Michael S. Molina
8c25808299 chore: Extensions architecture POC (#31934)
Co-authored-by: Ville Brofeldt <ville.brofeldt@apple.com>
Co-authored-by: Ville Brofeldt <ville@Villes-MacBook-Pro-2024.local>
Co-authored-by: Ville Brofeldt <v_brofeldt@apple.com>
(cherry picked from commit a8be5a5a0c)
2025-08-26 13:47:13 -03:00
Michael S. Molina
aa69ce43d9 fix: User-provided Jinja template parameters causing SQL parsing errors (#34802)
(cherry picked from commit e1234b2264)
2025-08-22 15:02:44 -03:00
JUST.in DO IT
878289a2e6 fix: customize column description limit size in db_engine_spec (#34808)
(cherry picked from commit 75af53dc3d)
2025-08-22 14:40:39 -03:00
Vitor Avila
097f576244 feat(file uploads): List only allowed schemas in the file uploads dialog (#32702)
(cherry picked from commit e35145c816)
2025-08-22 11:30:09 -03:00
Michael S. Molina
e986496ef4 fix: Timeseries annotation layers (#34709)
(cherry picked from commit fc95c4fc89)
2025-08-15 13:10:03 -03:00
JUST.in DO IT
752f7aa80c chore(saved_query): Copy link to clipboard before redirect to edit (#34567) 2025-08-07 11:10:05 -07:00
JUST.in DO IT
882aba67d6 fix(echart): broken aggregator due to bigint value (#34580)
(cherry picked from commit 3e12d97e8e)
2025-08-06 15:22:45 -03:00
JUST.in DO IT
2696d3e800 fix: navigate to SQL Lab due to router api updates (#34569)
(cherry picked from commit 53e9cf6d17)
2025-08-06 11:56:00 -03:00
JUST.in DO IT
ab886db246 fix(echarts): rename time series shifted without dimensions (#34541)
(cherry picked from commit 6f5d9c989a)
2025-08-06 11:55:50 -03:00
JUST.in DO IT
8828e59dca fix(table chart): render bigint value in a raw mode (#34556)
(cherry picked from commit 8700a0b939)
2025-08-05 17:15:47 -03:00
JUST.in DO IT
d1ded45633 chore(explore): Add format sql and view in SQL Lab option in View Query (#33341)
(cherry picked from commit 3a3984006c)
2025-08-05 16:11:54 -03:00
JUST.in DO IT
ee2a5915b2 fix(native filters): throws an error when a chart containing a bigint value (#34539)
(cherry picked from commit 2f8939d229)
2025-08-04 16:18:14 -03:00
JUST.in DO IT
bcbf17bdf3 fix(echart): initial chart animation (#34516)
(cherry picked from commit 1a7a381bd5)
2025-08-02 09:39:59 -03:00
Michael S. Molina
c2238b92cc fix: Users can't skip column sync when saving virtual datasets (#34509) 2025-08-02 09:38:48 -03:00
JUST.in DO IT
32accfff7d fix(sqllab): access legacy kv record (#34411)
(cherry picked from commit 762a11b0bb)
2025-07-31 09:29:38 -03:00
jqqin
8a5dff8491 fix(dataset): prevent metric duplication error when editing SQL and adding metric (#33523)
Co-authored-by: QinQin <qinqin@geotab.com>
(cherry picked from commit 2fba789e8d)
2025-07-30 09:11:39 -03:00
Michael S. Molina
c6e628a384 fix: Charts list is displaying empty dataset names when there's no schema (#34315)
(cherry picked from commit 5f11f9097a)
2025-07-25 14:15:34 -03:00
JUST.in DO IT
5eb61ec1b6 fix: extract tables from jinja (#34307) 2025-07-25 09:06:15 -03:00
Joe Li
fb035f4210 fix: Update spacing on echart legends (#34018)
(cherry picked from commit cb6342fc73)
2025-07-24 10:53:58 -03:00
Michael S. Molina
1926e90e12 fix: Saved queries list break if one query can't be parsed (#34289)
(cherry picked from commit 1e5a4e9bdc)
2025-07-24 08:31:14 -03:00
Michael S. Molina
21f77f3717 fix: Bulk select is not respecting the TAGGING_SYSTEM feature flag (#34282)
(cherry picked from commit 11324607d0)
2025-07-23 11:35:34 -03:00
JUST.in DO IT
31098dee40 fix: Matching errorType on superset api error with SupersetError (#34261)
(cherry picked from commit 229d92590a)
2025-07-23 09:41:37 -03:00
JUST.in DO IT
ffcc8a2c53 fix(explore): Display missing dataset for denied access (#34129)
(cherry picked from commit 96cb6030c8)
2025-07-21 08:37:47 -03:00
Michael S. Molina
f313554040 fix: Annotation layer errors (#34074)
(cherry picked from commit d6ed819fe2)
2025-07-14 08:47:15 -03:00
Beto Dealmeida
41c82337b1 chore: pin Marshmallow < 4 (#33978) 2025-07-14 08:45:50 -03:00
Michael S. Molina
465e2a9631 chore: Adds RC4 data to CHANGELOG.md 2025-06-18 13:54:31 -03:00
Michael S. Molina
f906adb551 fix: SQL Lab warning message sizes (#33817)
(cherry picked from commit 775a702b99)
2025-06-18 13:06:01 -03:00
amaannawab923
9a6261b026 fix(Echarts): Echarts Legend Scroll fix (#33779)
Co-authored-by: Amaan Nawab <nelsondrew07@gmail.com>
2025-06-18 09:32:03 -03:00
gpchandran
cff2ce04c0 build: update Dockerfile to 3.11.13-slim-bookworm (#33745)
(cherry picked from commit 7b6885a020)
2025-06-18 09:20:22 -03:00
Mehmet Salih Yavuz
ad10abd8f2 fix(tooltip): Sanitize tooltip html (#33765)
(cherry picked from commit 8fd0fd673f)
2025-06-18 09:20:22 -03:00
Beto Dealmeida
cdbdaf4179 fix: apply d3 format to BigNumber(s) (#33759)
(cherry picked from commit d7d7b7c0e6)
2025-06-18 09:20:22 -03:00
Vladislav Korenkov
4f1ea355c1 fix(create chart page): add missing space between words (#33752) 2025-06-18 09:20:04 -03:00
Ananta Patil
715fe6f6ef fix: sync dot color between dashboard chart and edit chart (#33748)
(cherry picked from commit 78ad6db0c6)
2025-06-18 09:18:24 -03:00
Pat Buxton
cbbf335984 fix(dataset): Fix plural toast messages (#33743)
(cherry picked from commit a64b9ac84f)
2025-06-18 09:18:24 -03:00
Vladislav Korenkov
24ec0c8c10 fix(explore): add gap to the "Cached" button (#33717) 2025-06-18 09:18:03 -03:00
Vladislav Korenkov
be139508f4 fix(Alerts & reports): invalid "Last updated" time formatting (#33719)
(cherry picked from commit 3ef92e5610)
2025-06-18 09:16:52 -03:00
Pat Buxton
77d18498c5 fix(dashboard): show dashboard thumbnail images when retrieved (#33726) 2025-06-18 09:16:26 -03:00
Kasper Mol
94369ca6b5 fix(template_processing): get_filters now works for IS_NULL and IS_NOT_NULL operators (#33296)
(cherry picked from commit cc3460832f)
2025-06-18 09:14:25 -03:00
Paul Rhodes
e5c6d3e388 feat(api): Added uuid to list api calls (#32414)
(cherry picked from commit 8decc9e45f)
2025-06-09 10:48:30 -03:00
Luiz Otavio
e83ac1d696 fix: Migrate charts with empty query_context (#33710)
(cherry picked from commit 08655a7559)
2025-06-09 08:56:34 -03:00
gpchandran
96298a01cf chore: update Dockerfile - Upgrade to 3.11.12 (#33612)
(cherry picked from commit f0b6e87091)
2025-06-09 08:56:34 -03:00
Michael S. Molina
a5f0b24806 chore: Adds RC3 data to CHANGELOG.md 2025-05-28 16:47:24 -03:00
Michael S. Molina
f9ff3259b3 fix: Makes time compare migration more resilient (#33592)
(cherry picked from commit b7ba50033a)
2025-05-28 08:34:38 -03:00
Michael S. Molina
00cd069af2 fix: Missing processor context when rendering Jinja (#33596)
(cherry picked from commit ce9759785a)
2025-05-28 08:34:38 -03:00
Luiz Otavio
cfba5cdc57 fix: Adjust viz migrations to also migrate the queries object (#33285)
Co-authored-by: Michael S. Molina <michael.s.molina@gmail.com>
Co-authored-by: Michael S. Molina <70410625+michael-s-molina@users.noreply.github.com>
(cherry picked from commit 57183da315)
2025-05-26 15:08:17 -03:00
Richard Fogaca Nienkotter
685b259f6f fix(sankey): incorrect nodeValues (#33431)
Co-authored-by: richardfn <richard.fogaca@appsilon.com>
(cherry picked from commit 38868f9ff4)
2025-05-26 15:08:17 -03:00
Vitor Avila
8021a8ce42 fix(AllEntities): Display action buttons according to the user permissions (#33553)
(cherry picked from commit 546945e7a6)
2025-05-23 09:48:07 -03:00
Mike Klumpenaar
979e3a228f fix(user settings): Update forked cosmo theme to resolve down chevron in caret style (#30514) (#30577)
Co-authored-by: garriscp <garriscp@gmail.com>
(cherry picked from commit b7d3ff1e85)
2025-05-23 09:48:07 -03:00
amaannawab923
405fcfc5b1 fix(table): table sort by fix (#33540)
Co-authored-by: Amaan Nawab <nelsondrew07@gmail.com>
Co-authored-by: Geido <60598000+geido@users.noreply.github.com>
2025-05-23 09:47:47 -03:00
Rafael Benitez
a86a156e49 fix(Sqllab): Autocomplete got stuck in UI when open it too fast (#33522)
(cherry picked from commit b4e2406385)
2025-05-23 09:42:21 -03:00
Elizabeth Thompson
ec2b168d7a fix: allow metadata to parse json (#33444)
(cherry picked from commit b050897ebd)
2025-05-23 09:42:21 -03:00
JUST.in DO IT
c54778d7e7 fix(table-chart): time shift is not working (#33425)
(cherry picked from commit dc4474889d)
2025-05-23 09:42:21 -03:00
Syed Bariman Jan
6bdfb7ad6c fix(deckgl): fix deckgl multiple layers chart filter and viewport (#33364)
(cherry picked from commit 29ac507d56)
2025-05-23 09:42:21 -03:00
Mehmet Salih Yavuz
cd12f30db2 fix(Row): don't unload charts while embedded to reduce rerenders (#33422)
(cherry picked from commit 21ca26acd7)
2025-05-23 09:42:21 -03:00
Maxime Beauchemin
602208d68a fix: loading examples from raw.githubusercontent.com fails with 429 errors (#33354)
(cherry picked from commit f045a73e2d)
2025-05-12 13:46:39 -03:00
Đỗ Trọng Hải
8ffcd7e960 fix(be/utils): sync cache timeout for memoized function (#31917)
Signed-off-by: hainenber <dotronghai96@gmail.com>
(cherry picked from commit 4ed05f4ff1)
2025-05-12 12:07:52 -03:00
Shao Yu-Lung (Allen)
782e11b59c fix(i18n): zh_TW pybabel compile error: placeholders are incompatible (#33345) 2025-05-12 12:07:37 -03:00
github-actions[bot]
aeb50c505f chore(🦾): bump python h11 0.14.0 -> 0.16.0 (#33339)
Co-authored-by: GitHub Action <action@github.com>
(cherry picked from commit 82526865d2)
2025-05-12 12:07:20 -03:00
Vitor Avila
2f3658c750 fix: Edge case with metric not getting quoted in sort by when normalize_columns is enabled (#33337)
(cherry picked from commit 9f0ae77341)
2025-05-12 12:07:20 -03:00
Michael S. Molina
7f57df5fa4 fix: Temporal filter conversion in viz migrations (#33224)
(cherry picked from commit 6db3a4d9d2)
2025-05-12 12:07:20 -03:00
Beto Dealmeida
ce6d0d5963 fix: improve function detection (#33306)
(cherry picked from commit 339ba96600)
2025-05-12 12:07:20 -03:00
JUST.in DO IT
8cc6f260c7 fix(echarts): rename time series shifted colnames (#33269)
(cherry picked from commit ef14b529b8)
2025-05-12 12:07:20 -03:00
Beto Dealmeida
ee8edcf4b4 fix: mask password on DB import (#33267) 2025-05-12 12:07:07 -03:00
Daniel Vaz Gaspar
f56757a0e9 fix: LocalProxy is not mapped warning (#33025)
(cherry picked from commit c029b532d4)
2025-05-12 12:06:50 -03:00
Evan Rusackas
850f35add1 fix(histogram): remove extra single quotes (#33248)
(cherry picked from commit d2360b533b)
2025-05-12 12:06:50 -03:00
Vitor Avila
f8b0632f99 fix(DB update): Gracefully handle querry error during DB update (#33250)
(cherry picked from commit de84a534ac)
2025-05-12 12:06:50 -03:00
Sam Firke
a6895e07b0 fix(heatmap): correctly render int and boolean falsy values on axes (#33238)
(cherry picked from commit ac636c73ae)
2025-05-12 12:06:50 -03:00
Vitor Avila
a3c08fd9bf fix(sqllab permalink): Commit SQL Lab permalinks (#33237)
(cherry picked from commit fbd8ae2888)
2025-05-12 12:06:50 -03:00
Vitor Avila
5b178dfbc7 fix(standalone): Ensure correct URL param value for standalone mode (#33234) 2025-05-12 12:06:33 -03:00
JUST.in DO IT
692d47c79d fix(antd): Invalid dashed border in tertiary button (#33291) 2025-04-30 08:17:57 -03:00
Vitor Avila
84b437d0a7 fix(export): Full CSV/Excel exports respecting SQL_MAX_ROW config (#33214)
(cherry picked from commit f7b7aace38)
2025-04-24 15:43:08 -03:00
JUST.in DO IT
f4ea15e477 fix(sqllab): Invalid SQL Error breaks SQL Lab (#33164) 2025-04-24 15:42:55 -03:00
Evan Rusackas
7c46374202 fix(deckgl): Update Arc to properly adjust line width (#33154)
(cherry picked from commit b589d44dfb)
2025-04-24 15:41:24 -03:00
Jacob Amrany
d9c1ee67f5 fix: os.makedirs race condition (#33161)
(cherry picked from commit 00f1fdb3c4)
2025-04-24 15:41:24 -03:00
JUST.in DO IT
35d7e15841 fix(echart): Thrown errors shown after resized (#33143)
(cherry picked from commit 172e5dd095)
2025-04-24 15:41:24 -03:00
JUST.in DO IT
454397fc17 fix(echart): Tooltip date format doesn't follow time grain (#33138)
(cherry picked from commit 7333ffd41e)
2025-04-17 09:46:45 -03:00
Jillian
aab564fa58 fix(lang): patch FAB's LocaleView to redirect to previous page (#31692) 2025-04-17 09:46:26 -03:00
JUST.in DO IT
5e475ecb7b fix(dashboard): invalid active tab state (#33106)
(cherry picked from commit 342e6f3ab0)
2025-04-17 09:43:54 -03:00
Michael S. Molina
0c80ab07f7 fix: Viz migration error handling (#33037)
(cherry picked from commit bc0ffe0d10)
2025-04-17 09:43:54 -03:00
Daniel Höxtermann
03255819a4 fix(playwright): allow screenshotting empty dashboards (#33107)
(cherry picked from commit 2233c02720)
2025-04-17 09:43:54 -03:00
Michael S. Molina
49541333d0 fix: Bump FAB to 4.5.5 2025-04-14 14:14:27 -03:00
Maxime Beauchemin
65c76024f6 fix: resolve recent merge collisio (#33110) 2025-04-14 14:08:42 -03:00
Michael S. Molina
d0aa6338b8 fix: Allows configuration of Selenium Webdriver binary (#33103)
(cherry picked from commit e1f5c49df7)
2025-04-14 14:08:42 -03:00
Daniel Höxtermann
bf2e014cde fix(thumbnails): ensure consistent cache_key (#33109)
(cherry picked from commit 347c174099)
2025-04-14 14:08:42 -03:00
Erkka Tahvanainen
65c9375624 fix(dashboard): Generate screenshot via celery (#32193)
Co-authored-by: Erkka Tahvanainen <erkka.tahvanainen@confidently.fi>
(cherry picked from commit 5656d69c04)
2025-04-14 14:08:42 -03:00
Hossein Khalilian
1a1986a191 fix(docker): fallback to pip if uv is not available (#33087)
(cherry picked from commit 164a07e2be)
2025-04-14 14:08:42 -03:00
Michael S. Molina
d0355d57bf fix: Adds missing __init__ file to commands/logs (#33059)
(cherry picked from commit c1159c53e3)
2025-04-14 14:08:41 -03:00
JUST.in DO IT
e0e2d329e0 fix: improve error type on parse error (#33048)
(cherry picked from commit ed0cd5e7b0)
2025-04-14 14:08:41 -03:00
EmmanuelCbd
f85f3f8b56 fix(export): charts csv export in dashboards (#31720)
(cherry picked from commit 6b7394e789)
2025-04-14 14:08:41 -03:00
JUST.in DO IT
ddecaa4c11 fix(log): Missing failed query log on async queries (#33024)
(cherry picked from commit 9b15e04bc4)
2025-04-14 14:08:41 -03:00
Levis Mbote
8df4b6d4e0 fix: fix bug where dashboard did not enter fullscreen mode. (#32839) 2025-04-14 14:08:41 -03:00
Hugo Lavernhe
052392e24d fix(dashboard): chart fullscreen issue when filter pane is collapsed (#28428)
(cherry picked from commit 629b137bb0)
2025-04-14 14:08:41 -03:00
Hex Café
1b60d36513 fix: show_filters URL parameter is not working (#29422)
Co-authored-by: Evan Rusackas <evan@preset.io>
Co-authored-by: Vitor Avila <vitor.avila@preset.io>
(cherry picked from commit bcb43327b1)
2025-04-14 14:08:41 -03:00
Michael S. Molina
4e8aa6de07 fix: Bar Chart (legacy) migration to keep labels layout (#32965)
(cherry picked from commit 24b1666273)
2025-04-14 14:08:41 -03:00
SBIN2010
e756094efc fix: fixed Add Metrics to Tree Chart (#29158) (#30679)
(cherry picked from commit f5d64176f6)
2025-04-14 14:08:41 -03:00
JUST.in DO IT
6a78260b66 fix(pivot-table): Revert "fix(Pivot Table): Fix column width to respect currency config (#31414)" (#32968)
(cherry picked from commit a36e636a58)
2025-04-14 14:08:41 -03:00
notHuman9504
5620acac61 fix: Clicking in the body of a Markdown component does not put it into edit mode (#32384)
(cherry picked from commit 26743dfcee)
2025-04-14 14:08:41 -03:00
github-actions[bot]
766c795106 chore(🦾): bump python sqlglot 26.1.3 -> 26.11.1 (#32745)
Co-authored-by: GitHub Action <action@github.com>
(cherry picked from commit 66c1a6a875)
2025-04-14 14:08:41 -03:00
Michael S. Molina
5bc3ca295c chore: Adds RC2 data to CHANGELOG.md 2025-04-14 14:08:41 -03:00
JUST.in DO IT
e4d34902d3 fix(sqllab): Invalid display of table column keys (#32763)
(cherry picked from commit 56bf17f879)
2025-04-14 14:08:41 -03:00
Vitor Avila
f27bf9ea64 fix(Jinja): Emit time grain to table charts even if they don't have a temporal column (#32871)
(cherry picked from commit ab22bb1878)
2025-04-14 14:08:41 -03:00
Đỗ Trọng Hải
56f6e1196c fix(backend/async_events): allow user to configure username for Redis authentication in GLOBAL_ASYNC_QUERIES_CACHE_BACKEND (#32372)
Signed-off-by: hainenber <dotronghai96@gmail.com>
Co-authored-by: Ville Brofeldt <33317356+villebro@users.noreply.github.com>
(cherry picked from commit e0ed652ed8)
2025-04-14 14:08:41 -03:00
Luke Hart
2c6cdfe7ad fix: use role_model from security manager (#32873)
(cherry picked from commit 103fedaf92)
2025-04-14 14:08:41 -03:00
SBIN2010
2e0363ec36 fix(ColorPickerControl): change color picker control width (#32851)
(cherry picked from commit 37f626f5e2)
2025-04-14 14:08:41 -03:00
Vitor Avila
34b4edb372 fix(table-chart): Do not show comparison columns config if time_compare is set to [] (#32863)
(cherry picked from commit f0dc1e7527)
2025-04-14 14:08:41 -03:00
Christiaan Baartse
b5bb3c76a0 fix(translation): Dutch translations for Current datetime filter (#31869)
(cherry picked from commit 6c7f089ebb)
2025-04-14 14:08:41 -03:00
Beto Dealmeida
c63a33e76b fix: update dataset/query catalog on DB changes (#32829) 2025-04-14 14:08:41 -03:00
Vitor Avila
ea3a823fff fix(echarts): Sort series by name using naturalCompare (#32850)
(cherry picked from commit 5222f940cc)
2025-04-14 14:08:41 -03:00
JUST.in DO IT
e593bc0a2e fix(log): store navigation path to get correct logging path (#32795)
(cherry picked from commit 4a70065e5f)
2025-04-14 14:08:41 -03:00
Fardin Mustaque
7ed236170d fix: Time Comparison Feature Reverts Metric Labels to Metric Keys in Table Charts (#32665)
Co-authored-by: Fardin Mustaque <fardinmustaque@Fardins-Mac-mini.local>
(cherry picked from commit 7d77dc4fd2)
2025-04-14 14:08:41 -03:00
Chris
c070d9e8e1 fix: key error in frontend on disallowed GSheets (#32792)
(cherry picked from commit 6f69c84d10)
2025-04-14 14:08:41 -03:00
SBIN2010
2bdfe52075 fix: CSV/Excel upload form change column dates description (#32797) 2025-04-14 14:08:41 -03:00
Đỗ Trọng Hải
fd1e44b8f6 fix(sec): resolve CVE-2025-29907 and CVE-2025-25977 by pinning jspdf to v3 (#32802)
Signed-off-by: hainenber <dotronghai96@gmail.com>
2025-04-14 14:08:41 -03:00
Đỗ Trọng Hải
e943604db8 fix(model/helper): represent RLS filter clause in proper textual SQL string (#32406)
Signed-off-by: hainenber <dotronghai96@gmail.com>
(cherry picked from commit ff0529c932)
2025-04-14 14:08:41 -03:00
CharlesNkdl
59d03a3847 fix(excel export): big number truncation handling (#32739)
(cherry picked from commit c0f83a7467)
2025-04-14 14:08:41 -03:00
V9 Developer
231d9a321a fix(config): correct slack image url in talisman (#32778)
(cherry picked from commit 9bb3a5782d)
2025-04-14 14:08:40 -03:00
Ruslan
1c3c6dbe0f fix(css): typos in styles (#28350)
(cherry picked from commit 5ec710efc6)
2025-04-14 14:08:40 -03:00
Vladislav Korenkov
a530da2a36 fix(import): Missing catalog field in saved query schema (#32775)
Co-authored-by: Vladislav Koren'kov <korenkov.vv@dns-shop.ru>
(cherry picked from commit 5866f3ec83)
2025-04-14 14:08:40 -03:00
Antonio Rivero
a6576a1769 fix(sqllab): Pass query_id as kwarg so backoff can see it (#32774)
(cherry picked from commit 01801e3c36)
2025-04-14 14:08:40 -03:00
Vladislav Korenkov
13b97af7f6 fix(chart control): Change default of "Y Axis Title Margin" (#32720)
(cherry picked from commit d319543377)
2025-04-14 14:08:40 -03:00
Elizabeth Thompson
5d333ac6dc fix: do not add calculated columns when syncing (#32761)
(cherry picked from commit 89ce7ba0b0)
2025-03-20 09:44:56 -03:00
Giampaolo Capelli
4a7014b5aa fix: Changing language doesn't affect echarts charts (#31751)
Co-authored-by: Giampaolo Capelli <giampaolo.capelli@docaposte.fr>
(cherry picked from commit 78efb62781)
2025-03-20 09:44:56 -03:00
sowo
f6f1ffae2f fix(contextmenu): uncaught TypeError (#28203)
(cherry picked from commit 29b62f7c0a)
2025-03-20 09:44:56 -03:00
Daniel Höxtermann
6917362d78 fix: ensure datasource permission in explore (#32679)
(cherry picked from commit 9e3052968b)
2025-03-20 09:44:56 -03:00
Paul Rhodes
6119d797e4 fix(import): Ensure import exceptions are logged (#32410)
(cherry picked from commit bc3e19d0a2)
2025-03-20 09:44:56 -03:00
Beto Dealmeida
8ba265ca2b fix: coerce datetime conversion errors (#32683) 2025-03-20 09:44:40 -03:00
JUST.in DO IT
4a189945d8 fix(logging): missing path in event data (#32708)
(cherry picked from commit cd5a94305c)
2025-03-20 09:43:48 -03:00
Beto Dealmeida
9b8194fd8a fix: boolean filters in Explore (#32701)
(cherry picked from commit 41bf215367)
2025-03-20 09:43:48 -03:00
Sam Firke
30e3e2e437 fix(spreadsheet uploads): make file extension comparisons case-insensitive (#32696)
(cherry picked from commit 6a13ab8920)
2025-03-20 09:43:48 -03:00
Đỗ Trọng Hải
980d912cc6 fix(cosmetics): allow toast message to be toggled off when modal is opened (#32691)
Signed-off-by: hainenber <dotronghai96@gmail.com>
(cherry picked from commit f1a222d356)
2025-03-20 09:43:48 -03:00
Michael S. Molina
d2ba0fc9ae fix: Signature of Celery pruner jobs (#32699)
(cherry picked from commit df06bdf33b)
2025-03-20 09:43:48 -03:00
JUST.in DO IT
a1d7f7adcd fix(log): Update recent_activity by event name (#32681)
(cherry picked from commit 449f51aed5)
2025-03-20 09:43:48 -03:00
Michael S. Molina
2ff9faba0e fix: Update RELEASING/README.md (#32678)
(cherry picked from commit b4dd64aa24)
2025-03-20 09:43:47 -03:00
Beto Dealmeida
3f2ddbac82 fix(gsheets): update params from encrypted extra (#32661) 2025-03-20 09:43:29 -03:00
Vitor Avila
24c120135c fix(import): Import a DB connection with expanded rows enabled (#32657)
(cherry picked from commit 0c6d868483)
2025-03-20 09:40:09 -03:00
Andrey Yakir
45cf969d4b fix(dashboard): Ensure dashboardId is included in form_data for embedded mode (#32646)
(cherry picked from commit 777760b096)
2025-03-20 09:40:09 -03:00
Dolph Mathews
43e68c7a0f fix: Upgrade node base image to Debian 12 bookworm (#32652)
(cherry picked from commit 2f6f5c6778)
2025-03-20 09:38:02 -03:00
JUST.in DO IT
1f34e3cf7c fix(welcome): perf on distinct recent activities (#32608)
(cherry picked from commit 832e028b39)
2025-03-17 12:01:23 -03:00
JUST.in DO IT
2f9edd3b0e fix(dashboard): Support bigint value in native filters (#32549)
(cherry picked from commit e7721a8c4d)
2025-03-17 12:01:23 -03:00
Vitor Avila
bdb9f48044 fix(Slack V2): Specify the filename for the Slack upload method (#32599)
(cherry picked from commit 8e021b0c82)
2025-03-17 12:01:23 -03:00
Michael S. Molina
a0321945cc fix: Log table retention policy (#32572)
(cherry picked from commit 89b6d7fb68)
2025-03-17 12:01:23 -03:00
Elizabeth Thompson
586d88c9ca fix: add DateOffset to json serializer (#32532) 2025-03-17 12:01:06 -03:00
JUST.in DO IT
91ba5b3c9e fix(sqllab): Allow clear on schema and catalog (#32515)
(cherry picked from commit 4c3aae7583)
2025-03-17 11:54:59 -03:00
Antonio Rivero
d493c9d3ca fix(migrations): Handle comparator None in old time comparison migration (#32538)
(cherry picked from commit 20e5df501e)
2025-03-17 11:54:59 -03:00
Elizabeth Thompson
d33b81a43c fix: keep calculated columns when datasource is updated (#32523)
(cherry picked from commit 99238dccbb)
2025-03-17 11:52:58 -03:00
Elizabeth Thompson
2df776e944 fix: Show response message as default error (#32507)
(cherry picked from commit c2de749d0e)
2025-03-17 11:52:58 -03:00
Vitor Avila
405bc269d4 fix(Slack): Fix Slack recipients migration to V2 (#32336)
(cherry picked from commit d2e0e2b79c)
2025-03-17 11:52:58 -03:00
Usiel Riedl
d0a5bd83c3 fix(beat): prune_query celery task args fix (#32511)
(cherry picked from commit e98194cdd3)
2025-03-17 11:52:58 -03:00
Kamil Gabryjelski
266fb7f2ad fix(explore): Glitch in a tooltip with metric's name (#32499)
(cherry picked from commit b3dfd4930a)
2025-03-05 14:17:58 -03:00
Daniel Vaz Gaspar
98c0eeccb2 fix: dashboard, chart and dataset import validation (#32500)
(cherry picked from commit fc844d3dfd)
2025-03-05 14:17:58 -03:00
Beto Dealmeida
5f1a5a1f98 fix: skip DB filter when doing OAuth2 (#32486)
(cherry picked from commit 813e79fa9f)
2025-03-05 14:17:58 -03:00
Evan Rusackas
6dd10ab1ca fix(tooltip): displaying <a> tags correctly (#32488)
(cherry picked from commit 6c3886aad0)
2025-03-05 14:17:58 -03:00
Ville Brofeldt
92549ef5c6 fix(plugin-chart-echarts): remove erroneous upper bound value (#32473)
(cherry picked from commit 5766c36372)
2025-03-05 14:17:58 -03:00
Đỗ Trọng Hải
f1291390a3 fix(com/grid-comp/markdown): pin remark-gfm to v3 to allow inline code block by backticks in Markdown (#32420)
Signed-off-by: hainenber <dotronghai96@gmail.com>
2025-03-05 14:16:40 -03:00
Le Xich Long
8a09fd93e1 fix(clickhouse): get_parameters_from_uri failing when secure is true (#32423)
(cherry picked from commit 84b52b2323)
2025-03-05 14:12:31 -03:00
Damian Pendrak
b11fd2f22b fix(viz): update nesting logic to handle multiple dimensions in PartitionViz (#32290)
(cherry picked from commit 6317a91541)
2025-03-05 14:12:31 -03:00
Yuri
d611c25f2a fix(pinot): revert join and subquery flags (#32382)
(cherry picked from commit 822d72c57d)
2025-03-05 13:37:50 -03:00
Daniel Vaz Gaspar
ae3493aee9 fix: bump FAB to 4.5.4 (#32325)
(cherry picked from commit c02a0a00f4)
2025-03-05 13:37:50 -03:00
Beto Dealmeida
654062db27 fix: ensure metric_macro expands templates (#32344) 2025-03-05 10:01:38 -03:00
Dino
09a93d2803 fix: clickhouse-connect engine SSH parameter (#32348)
(cherry picked from commit 8dcae810d4)
2025-03-05 09:47:51 -03:00
Vedant Prajapati
98c82ad24e fix(docker): Configure nginx for consistent port mapping and hot reloading (#32362)
(cherry picked from commit 0f07d78e01)
2025-03-05 09:47:51 -03:00
Beto Dealmeida
3eda2223ca fix(firebolt): allow backslach escape for single quotes (#32350)
(cherry picked from commit 22fe985cfc)
2025-03-05 09:47:51 -03:00
Enzo Martellucci
7ef38fed24 fix(SSHTunnelForm): make the password tooltip visible (#32356)
(cherry picked from commit 4c4b5e8c64)
2025-03-05 09:47:51 -03:00
Levis Mbote
724f2dc5fe fix(roles): Add SqlLabPermalinkRestApi as default sqlab roles. (#32284)
(cherry picked from commit 2c37ddb2f6)
2025-03-05 09:47:51 -03:00
Đỗ Trọng Hải
7aa4cd4eef fix(fe/dashboard-list): display modifier info for Last modified data (#32035)
Signed-off-by: hainenber <dotronghai96@gmail.com>
(cherry picked from commit 88cf2d5c39)
2025-03-05 09:47:51 -03:00
Elizabeth Thompson
b2bd39cc28 fix: revert "fix: remove sort values on stacked totals (#31333)" (#32337)
(cherry picked from commit 422a07b382)
2025-03-05 09:47:51 -03:00
Dmitry Kochnev
e8246ea786 fix: oauth2 trino (#31993)
(cherry picked from commit 7ce1a3445c)
2025-02-21 13:23:31 -03:00
Kamil Gabryjelski
2c03455f61 fix: Download as PDF fails due to cache error (#32332)
(cherry picked from commit 42a3c523ae)
2025-02-21 13:23:31 -03:00
Steven Liu
45045d3a1c fix: keep the tab order (#30888)
Co-authored-by: Steven Liu <steven.l@covergenius.com>
(cherry picked from commit d5a5bd46d2)
2025-02-21 13:23:31 -03:00
Đỗ Trọng Hải
146311101a fix(viz/table): selected column not shown in Conditional Formatting popover (#32272)
Signed-off-by: hainenber <dotronghai96@gmail.com>
(cherry picked from commit dcc9628f31)
2025-02-21 13:23:31 -03:00
Michael S. Molina
c7cc436b0b fix: Decimal values for Histogram bins (#32253)
(cherry picked from commit ffe9244458)
2025-02-14 09:12:31 -03:00
Erkka Tahvanainen
ed217ce903 fix(Datasource): handle undefined datasource_type in fetchSyncedColumns (#32218)
Co-authored-by: Erkka Tahvanainen <erkka.tahvanainen@confidently.fi>
(cherry picked from commit 9da30956c0)
2025-02-14 09:12:31 -03:00
gpchandran
4a298e83d7 fix: upgrade to 3.11.11-slim-bookworm to address critical vulnerabilities (#32240)
(cherry picked from commit ad057324b7)
2025-02-14 09:12:31 -03:00
Elizabeth Thompson
39859e0d17 fix: remove sort values on stacked totals (#31333)
(cherry picked from commit 15fbb195e9)
2025-02-14 09:12:31 -03:00
Maxime Beauchemin
adce138484 docs: adding notes about using uv instead of raw pip (#32239) 2025-02-14 09:12:20 -03:00
Fardin Mustaque
e90b359d3e fix: Update 'Last modified' time when modifying RLS rules (#32227)
Co-authored-by: Fardin Mustaque <fardinmustaque@Fardins-Mac-mini.local>
(cherry picked from commit 52563d3eea)
2025-02-14 09:10:04 -03:00
Daniel Vaz Gaspar
6b95ecda98 chore(ci): fix ephemeral env null issue number (v2) (#32221)
(cherry picked from commit 31d6f5a639)
2025-02-12 16:23:54 -03:00
Daniel Vaz Gaspar
d0417c37b6 chore(ci): fix ephemeral env null issue number (#32220)
(cherry picked from commit 60424c4ccd)
2025-02-12 16:23:54 -03:00
Levis Mbote
c6e764ebbe fix(Scope): Correct issue where filters appear out of scope when sort is unchecked. (#32115)
(cherry picked from commit af3589fe91)
2025-02-12 11:40:29 -03:00
JUST.in DO IT
8b1de4c12c fix(sqllab): close the table tab (#32224)
(cherry picked from commit 937d40cdde)
2025-02-12 11:40:29 -03:00
Maxime Beauchemin
699d22c5fe fix: set Rich tooltip -> 'Show percentage' to false by default (#32212)
(cherry picked from commit d3b854a833)
2025-02-12 11:40:29 -03:00
Enzo Martellucci
8ba36abc87 fix(SaveDatasetModal): repairs field alignment in the SaveDatasetModal component (#32222)
Co-authored-by: Geido <60598000+geido@users.noreply.github.com>
(cherry picked from commit 650fa5ccfb)
2025-02-12 11:40:29 -03:00
Beto Dealmeida
000f2e3780 fix: hidrate datasetsStatus (#32211)
(cherry picked from commit eec54affc3)
2025-02-12 11:40:28 -03:00
Damian Pendrak
9ea2ad5105 fix: handlebars html and css templates reset on dataset update (#32195)
(cherry picked from commit 0f6bd5ea83)
2025-02-12 11:40:28 -03:00
Alex Duan
d83ae362cf fix: TDengine move tdengine.png to databases/ subfolder (#32176)
(cherry picked from commit 06f8f8e608)
2025-02-12 11:40:28 -03:00
Michael S. Molina
ed82e6ac75 fix: Adds an entry to UPDATING.md about DISABLE_LEGACY_DATASOURCE_EDITOR (#32185) 2025-02-12 11:40:16 -03:00
Levis Mbote
53d05a460d fix(sqllab): correct URL format for SQL Lab permalinks (#32154)
(cherry picked from commit f9f8c5d07a)
2025-02-12 11:38:52 -03:00
Jack
8ad24fabc9 fix(virtual dataset sync): Sync virtual dataset columns when changing the SQL query (#30903)
Co-authored-by: Kamil Gabryjelski <kamil.gabryjelski@gmail.com>
(cherry picked from commit f3e7c64de6)
2025-02-12 11:38:52 -03:00
EmmanuelCbd
cbebac9404 fix(docker): Docker python-translation-build (#32163)
(cherry picked from commit 5a8488af36)
2025-02-12 11:38:52 -03:00
Beto Dealmeida
50705e7253 fix: ScreenshotCachePayload serialization (#32156)
(cherry picked from commit e8990f4a36)
2025-02-12 11:38:52 -03:00
Antonio Rivero
e67089b5ce fix(migrations): Handle no params in time comparison migration (#32155)
(cherry picked from commit 6ed9dae2f7)
2025-02-12 11:38:52 -03:00
Đỗ Trọng Hải
923d076603 fix(releasing): fix borked SVN-based image building process (#32151)
Signed-off-by: hainenber <dotronghai96@gmail.com>
(cherry picked from commit ea5879bf2b)
2025-02-12 11:38:52 -03:00
Beto Dealmeida
92bc43e38b fix: move oauth2 capture to get_sqla_engine (#32137)
(cherry picked from commit c7c3b1b0e9)
2025-02-12 11:38:52 -03:00
Michael S. Molina
deb88e4174 fix: Local tarball Docker container is missing zstd dependency (#32135)
(cherry picked from commit c64018d421)
2025-02-12 11:38:52 -03:00
Elizabeth Thompson
faae9cc326 chore(timeseries charts): adjust legend width by padding (#32030)
(cherry picked from commit 8984f88a3e)
2025-02-12 11:38:51 -03:00
Michael S. Molina
890186a8e2 chore: Adds RC1 data to CHANGELOG.md and UPDATING.md 2025-02-04 14:00:05 -03:00
Michael S. Molina
b80aa864a1 fix: No virtual environment when running Docker translation compiler (#32133)
(cherry picked from commit 53d944d013)
2025-02-04 11:50:13 -03:00
Daniel Vaz Gaspar
b63256786d fix(ci): ephemeral env, handle different label, create comment (#32040)
(cherry picked from commit 0cd0fcdecb)
2025-02-04 11:50:13 -03:00
Mehmet Salih Yavuz
95694aa233 fix(datepicker): Full width datepicker on filter value select (#32064)
(cherry picked from commit cde2d49c95)
2025-02-04 11:50:13 -03:00
Michael S. Molina
15c60e8f2b fix: Histogram examples config (#32122) 2025-02-03 14:07:16 -03:00
516 changed files with 28019 additions and 3468 deletions

10
.github/CODEOWNERS vendored
View File

@@ -30,3 +30,13 @@
**/*.geojson @villebro @rusackas
/superset-frontend/plugins/legacy-plugin-chart-country-map/ @villebro @rusackas
# Notify PMC members of changes to extension-related files
/superset-core/ @michael-s-molina @villebro
/superset-extensions-cli/ @michael-s-molina @villebro
/superset/core/ @michael-s-molina @villebro
/superset/extensions/ @michael-s-molina @villebro
/superset-frontend/src/packages/superset-core/ @michael-s-molina @villebro
/superset-frontend/src/core/ @michael-s-molina @villebro
/superset-frontend/src/extensions/ @michael-s-molina @villebro

View File

@@ -1,24 +1,27 @@
name: 'Change Detector'
description: 'Detects file changes for pull request and push events'
name: Change Detector
description: Detects file changes for pull request and push events
inputs:
token:
description: 'GitHub token for authentication'
description: GitHub token for authentication
required: true
outputs:
python:
description: 'Whether Python-related files were changed'
description: Whether Python-related files were changed
value: ${{ steps.change-detector.outputs.python }}
frontend:
description: 'Whether frontend-related files were changed'
description: Whether frontend-related files were changed
value: ${{ steps.change-detector.outputs.frontend }}
docker:
description: 'Whether docker-related files were changed'
description: Whether docker-related files were changed
value: ${{ steps.change-detector.outputs.docker }}
docs:
description: 'Whether docs-related files were changed'
description: Whether docs-related files were changed
value: ${{ steps.change-detector.outputs.docs }}
superset-extensions-cli:
description: Whether superset-extensions-cli package-related files were changed
value: ${{ steps.change-detector.outputs.superset-extensions-cli }}
runs:
using: 'composite'
using: composite
steps:
- name: Detect file changes
id: change-detector

View File

@@ -26,16 +26,16 @@ runs:
- name: Set up QEMU
if: ${{ inputs.build == 'true' }}
uses: docker/setup-qemu-action@v3
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0
- name: Set up Docker Buildx
if: ${{ inputs.build == 'true' }}
uses: docker/setup-buildx-action@v3
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
- name: Try to login to DockerHub
if: ${{ inputs.login-to-dockerhub == 'true' }}
continue-on-error: true
uses: docker/login-action@v3
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
with:
username: ${{ inputs.dockerhub-user }}
password: ${{ inputs.dockerhub-token }}

View File

@@ -322,6 +322,10 @@ updates:
- package-ecosystem: "npm"
directory: "/superset-frontend/packages/superset-ui-core/"
ignore:
# not until React >= 18.0.0
- dependency-name: "react-markdown"
- dependency-name: "remark-gfm"
schedule:
interval: "monthly"
labels:

View File

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

View File

@@ -31,7 +31,7 @@ jobs:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
if: steps.check_queued.outputs.count >= 20
uses: actions/checkout@v4
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- name: Cancel duplicate workflow runs
if: steps.check_queued.outputs.count >= 20

View File

@@ -17,9 +17,8 @@ jobs:
check-python-deps:
runs-on: ubuntu-22.04
steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@v4
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
persist-credentials: false
submodules: recursive

View File

@@ -25,9 +25,9 @@ jobs:
pull-requests: write
steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@v4
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- name: Check and notify
uses: actions/github-script@v7
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
with:
github-token: ${{ github.token }}
script: |

View File

@@ -31,7 +31,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- name: Check for file changes
id: check

View File

@@ -27,9 +27,9 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: "Checkout Repository"
uses: actions/checkout@v4
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- name: "Dependency Review"
uses: actions/dependency-review-action@v4
uses: actions/dependency-review-action@2031cfc080254a8a887f58cffee85186f0e49e48 # v4.9.0
continue-on-error: true
with:
fail-on-severity: critical
@@ -51,16 +51,17 @@ jobs:
runs-on: ubuntu-22.04
steps:
- name: "Checkout Repository"
uses: actions/checkout@v4
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- name: Setup Python
uses: ./.github/actions/setup-backend/
- name: Set up Python
uses: actions/setup-python@v5
with:
requirements-type: base
python-version: "3.11"
cache: "pip"
- name: "Install dependencies and liccheck"
run: pip install -r requirements/base.txt liccheck
- name: "Set up liccheck"
run: |
uv pip install --system liccheck
- name: "Run liccheck"
run: |
# run the checks

View File

@@ -14,7 +14,6 @@ concurrency:
cancel-in-progress: true
jobs:
setup_matrix:
runs-on: ubuntu-24.04
outputs:
@@ -40,9 +39,8 @@ jobs:
IMAGE_TAG: apache/superset:GHA-${{ matrix.build_preset }}-${{ github.run_id }}
steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@v4
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
persist-credentials: false
@@ -91,7 +89,7 @@ jobs:
# in the context of push (using multi-platform build), we need to pull the image locally
- name: Docker pull
if: github.event_name == 'push' && (steps.check.outputs.python || steps.check.outputs.frontend || steps.check.outputs.docker)
run: docker pull $IMAGE_TAG
run: docker pull $IMAGE_TAG
- name: Print docker stats
if: steps.check.outputs.python || steps.check.outputs.frontend || steps.check.outputs.docker
@@ -114,7 +112,7 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@v4
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
persist-credentials: false
- name: Check for file changes

View File

@@ -28,11 +28,11 @@ jobs:
run:
working-directory: superset-embedded-sdk
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6
with:
node-version: "20"
registry-url: 'https://registry.npmjs.org'
registry-url: "https://registry.npmjs.org"
- run: npm ci
- run: npm run ci:release
env:

View File

@@ -18,11 +18,11 @@ jobs:
run:
working-directory: superset-embedded-sdk
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6
with:
node-version: "20"
registry-url: 'https://registry.npmjs.org'
registry-url: "https://registry.npmjs.org"
- run: npm ci
- run: npm test
- run: npm run build

View File

@@ -63,7 +63,7 @@ jobs:
- name: Comment (success)
if: steps.describe-services.outputs.active == 'true'
uses: actions/github-script@v7
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
with:
github-token: ${{github.token}}
script: |

View File

@@ -10,11 +10,11 @@ on:
workflow_dispatch:
inputs:
label_name:
description: 'Label name to simulate label-based /testenv trigger'
description: "Label name to simulate label-based /testenv trigger"
required: true
default: 'testenv-up'
default: "testenv-up"
issue_number:
description: 'Issue or PR number'
description: "Issue or PR number"
required: true
jobs:
@@ -50,17 +50,45 @@ jobs:
echo "result=up" >> $GITHUB_OUTPUT
else
echo "result=noop" >> $GITHUB_OUTPUT
exit 1
fi
- name: Get event SHA
id: get-sha
run: |
echo "sha=${{ github.event.pull_request.head.sha }}" >> $GITHUB_OUTPUT
if: steps.eval-label.outputs.result == 'up'
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
let prSha;
// If event is workflow_dispatch, use the issue_number from inputs
if (context.eventName === "workflow_dispatch") {
const prNumber = "${{ github.event.inputs.issue_number }}";
if (!prNumber) {
console.log("No PR number found.");
return;
}
// Fetch PR details using the provided issue_number
const { data: pr } = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: prNumber
});
prSha = pr.head.sha;
} else {
// If it's not workflow_dispatch, use the PR head sha from the event
prSha = context.payload.pull_request.head.sha;
}
console.log(`PR SHA: ${prSha}`);
core.setOutput("sha", prSha);
- name: Looking for feature flags in PR description
uses: actions/github-script@v7
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
id: eval-feature-flags
if: steps.eval-label.outputs.result == 'up'
with:
script: |
const description = context.payload.pull_request
@@ -80,7 +108,8 @@ jobs:
return results;
- name: Reply with confirmation comment
uses: actions/github-script@v7
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
if: steps.eval-label.outputs.result == 'up'
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
@@ -116,7 +145,7 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: "Checkout ${{ github.ref }} ( ${{ needs.ephemeral-env-label.outputs.sha }} : ${{steps.get-sha.outputs.sha}} )"
uses: actions/checkout@v4
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
ref: ${{ needs.ephemeral-env-label.outputs.sha }}
persist-credentials: false
@@ -145,7 +174,7 @@ jobs:
--extra-flags "--build-arg INCLUDE_CHROMIUM=false"
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
uses: aws-actions/configure-aws-credentials@8df5847569e6427dd6c4fb1cf565c83acfa8afa7 # v6
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
@@ -153,7 +182,7 @@ jobs:
- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v2
uses: aws-actions/amazon-ecr-login@c962da2960ed15f492addc26fffa274485265950 # v2
- name: Load, tag and push image to ECR
id: push-image
@@ -161,8 +190,9 @@ jobs:
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
ECR_REPOSITORY: superset-ci
IMAGE_TAG: apache/superset:${{ needs.ephemeral-env-label.outputs.sha }}-ci
PR_NUMBER: ${{ github.event.inputs.issue_number || github.event.pull_request.number }}
run: |
docker tag $IMAGE_TAG $ECR_REGISTRY/$ECR_REPOSITORY:pr-${{ github.event.inputs.issue_number || github.event.issue.number }}-ci
docker tag $IMAGE_TAG $ECR_REGISTRY/$ECR_REPOSITORY:pr-$PR_NUMBER-ci
docker push -a $ECR_REGISTRY/$ECR_REPOSITORY
ephemeral-env-up:
@@ -175,12 +205,12 @@ jobs:
pull-requests: write
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
persist-credentials: false
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
uses: aws-actions/configure-aws-credentials@8df5847569e6427dd6c4fb1cf565c83acfa8afa7 # v6
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
@@ -188,26 +218,28 @@ jobs:
- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v2
uses: aws-actions/amazon-ecr-login@c962da2960ed15f492addc26fffa274485265950 # v2
- name: Check target image exists in ECR
id: check-image
continue-on-error: true
env:
PR_NUMBER: ${{ github.event.inputs.issue_number || github.event.pull_request.number }}
run: |
aws ecr describe-images \
--registry-id $(echo "${{ steps.login-ecr.outputs.registry }}" | grep -Eo "^[0-9]+") \
--repository-name superset-ci \
--image-ids imageTag=pr-${{ github.event.inputs.issue_number || github.event.issue.number }}-ci
--image-ids imageTag=pr-$PR_NUMBER-ci
- name: Fail on missing container image
if: steps.check-image.outcome == 'failure'
uses: actions/github-script@v7
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
with:
github-token: ${{ github.token }}
script: |
const errMsg = '@${{ github.event.comment.user.login }} Container image not yet published for this PR. Please try again when build is complete.';
github.rest.issues.createComment({
issue_number: ${{ github.event.inputs.issue_number || github.event.issue.number }},
issue_number: ${{ github.event.inputs.issue_number || github.event.pull_request.number }},
owner: context.repo.owner,
repo: context.repo.repo,
body: errMsg
@@ -216,11 +248,11 @@ jobs:
- name: Fill in the new image ID in the Amazon ECS task definition
id: task-def
uses: aws-actions/amazon-ecs-render-task-definition@v1
uses: aws-actions/amazon-ecs-render-task-definition@77954e213ba1f9f9cb016b86a1d4f6fcdea0d57e # v1
with:
task-definition: .github/workflows/ecs-task-definition.json
container-name: superset-ci
image: ${{ steps.login-ecr.outputs.registry }}/superset-ci:pr-${{ github.event.inputs.issue_number || github.event.issue.number }}-ci
image: ${{ steps.login-ecr.outputs.registry }}/superset-ci:pr-${{ github.event.inputs.issue_number || github.event.pull_request.number }}-ci
- name: Update env vars in the Amazon ECS task definition
run: |
@@ -229,29 +261,30 @@ jobs:
- name: Describe ECS service
id: describe-services
run: |
echo "active=$(aws ecs describe-services --cluster superset-ci --services pr-${{ github.event.inputs.issue_number || github.event.issue.number }}-service | jq '.services[] | select(.status == "ACTIVE") | any')" >> $GITHUB_OUTPUT
echo "active=$(aws ecs describe-services --cluster superset-ci --services pr-${{ github.event.inputs.issue_number || github.event.pull_request.number }}-service | jq '.services[] | select(.status == "ACTIVE") | any')" >> $GITHUB_OUTPUT
- name: Create ECS service
id: create-service
if: steps.describe-services.outputs.active != 'true'
env:
ECR_SUBNETS: subnet-0e15a5034b4121710,subnet-0e8efef4a72224974
ECR_SECURITY_GROUP: sg-092ff3a6ae0574d91
PR_NUMBER: ${{ github.event.inputs.issue_number || github.event.pull_request.number }}
run: |
aws ecs create-service \
--cluster superset-ci \
--service-name pr-${{ github.event.inputs.issue_number || github.event.issue.number }}-service \
--service-name pr-$PR_NUMBER-service \
--task-definition superset-ci \
--launch-type FARGATE \
--desired-count 1 \
--platform-version LATEST \
--network-configuration "awsvpcConfiguration={subnets=[$ECR_SUBNETS],securityGroups=[$ECR_SECURITY_GROUP],assignPublicIp=ENABLED}" \
--tags key=pr,value=${{ github.event.inputs.issue_number || github.event.issue.number }} key=github_user,value=${{ github.actor }}
--tags key=pr,value=$PR_NUMBER key=github_user,value=${{ github.actor }}
- name: Deploy Amazon ECS task definition
id: deploy-task
uses: aws-actions/amazon-ecs-deploy-task-definition@v2
uses: aws-actions/amazon-ecs-deploy-task-definition@cbf54ec46642b86ff78c2f5793da6746954cf8ff # v2
with:
task-definition: ${{ steps.task-def.outputs.task-definition }}
service: pr-${{ github.event.inputs.issue_number || github.event.issue.number }}-service
service: pr-${{ github.event.inputs.issue_number || github.event.pull_request.number }}-service
cluster: superset-ci
wait-for-service-stability: true
wait-for-minutes: 10
@@ -259,7 +292,7 @@ jobs:
- name: List tasks
id: list-tasks
run: |
echo "task=$(aws ecs list-tasks --cluster superset-ci --service-name pr-${{ github.event.inputs.issue_number || github.event.issue.number }}-service | jq '.taskArns | first')" >> $GITHUB_OUTPUT
echo "task=$(aws ecs list-tasks --cluster superset-ci --service-name pr-${{ github.event.inputs.issue_number || github.event.pull_request.number }}-service | jq '.taskArns | first')" >> $GITHUB_OUTPUT
- name: Get network interface
id: get-eni
run: |
@@ -270,24 +303,26 @@ jobs:
echo "ip=$(aws ec2 describe-network-interfaces --network-interface-ids ${{ steps.get-eni.outputs.eni }} | jq -r '.NetworkInterfaces | first | .Association.PublicIp')" >> $GITHUB_OUTPUT
- name: Comment (success)
if: ${{ success() }}
uses: actions/github-script@v7
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
with:
github-token: ${{github.token}}
script: |
const issue_number = context.payload.inputs?.issue_number || context.issue.number;
github.rest.issues.createComment({
issue_number: ${{ github.event.inputs.issue_number || github.event.issue.number }},
issue_number: issue_number,
owner: context.repo.owner,
repo: context.repo.repo,
body: '@${{ github.actor }} Ephemeral environment spinning up at http://${{ steps.get-ip.outputs.ip }}:8080. Credentials are `admin`/`admin`. Please allow several minutes for bootstrapping and startup.'
})
body: `@${{ github.actor }} Ephemeral environment spinning up at http://${{ steps.get-ip.outputs.ip }}:8080. Credentials are 'admin'/'admin'. Please allow several minutes for bootstrapping and startup.`
});
- name: Comment (failure)
if: ${{ failure() }}
uses: actions/github-script@v7
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
with:
github-token: ${{github.token}}
script: |
const issue_number = context.payload.inputs?.issue_number || context.issue.number;
github.rest.issues.createComment({
issue_number: ${{ github.event.inputs.issue_number || github.event.issue.number }},
issue_number: issue_number,
owner: context.repo.owner,
repo: context.repo.repo,
body: '@${{ github.event.inputs.user_login || github.event.comment.user.login }} Ephemeral environment creation failed. Please check the Actions logs for details.'

View File

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

View File

@@ -9,17 +9,16 @@ on:
types: [synchronize, opened, reopened, ready_for_review]
jobs:
validate-all-ghas:
runs-on: ubuntu-24.04
steps:
- name: Checkout Repository
uses: actions/checkout@v4
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- name: Set up Node.js
uses: actions/setup-node@v4
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6
with:
node-version: '20'
node-version: "20"
- name: Install Dependencies
run: npm install -g @action-validator/core @action-validator/cli --save-dev

View File

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

View File

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

View File

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

View File

@@ -13,13 +13,13 @@ jobs:
check-hold-label:
runs-on: ubuntu-24.04
steps:
- name: Check for 'hold' label
uses: actions/github-script@v7
with:
github-token: ${{secrets.GITHUB_TOKEN}}
script: |
const payload = context.payload.pull_request
const holdLabelPresent = !!payload.labels.find(label => label.name.includes('hold'))
if (holdLabelPresent) {
core.setFailed('Hold label is present, merge is blocked.')
}
- name: Check for 'hold' label
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
with:
github-token: ${{secrets.GITHUB_TOKEN}}
script: |
const payload = context.payload.pull_request
const holdLabelPresent = !!payload.labels.find(label => label.name.includes('hold'))
if (holdLabelPresent) {
core.setFailed('Hold label is present, merge is blocked.')
}

View File

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

View File

@@ -21,7 +21,7 @@ jobs:
python-version: ["current", "previous"]
steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@v4
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
persist-credentials: false
submodules: recursive

View File

@@ -32,7 +32,7 @@ jobs:
node-version: [20]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
# pulls all commits (needed for lerna / semantic release to correctly version)
fetch-depth: 0
@@ -48,13 +48,13 @@ jobs:
- name: Use Node.js ${{ matrix.node-version }}
if: env.HAS_TAGS
uses: actions/setup-node@v4
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6
with:
node-version: ${{ matrix.node-version }}
- name: Cache npm
if: env.HAS_TAGS
uses: actions/cache@v4
uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5
with:
path: ~/.npm # npm cache files are stored in `~/.npm` on Linux/macOS
key: ${{ runner.OS }}-node-${{ hashFiles('**/package-lock.json') }}
@@ -68,7 +68,7 @@ jobs:
run: echo "dir=$(npm config get cache)" >> $GITHUB_OUTPUT
- name: Cache npm
if: env.HAS_TAGS
uses: actions/cache@v4
uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5
id: npm-cache # use this to check for `cache-hit` (`steps.npm-cache.outputs.cache-hit != 'true'`)
with:
path: ${{ steps.npm-cache-dir-path.outputs.dir }}

View File

@@ -1,4 +1,4 @@
name: Superset CLI tests
name: Superset App CLI tests
on:
push:
@@ -23,7 +23,7 @@ jobs:
SUPERSET__SQLALCHEMY_DATABASE_URI: postgresql+psycopg2://superset:superset@127.0.0.1:15432/superset
services:
postgres:
image: postgres:15-alpine
image: postgres:16-alpine
env:
POSTGRES_USER: superset
POSTGRES_PASSWORD: superset
@@ -37,7 +37,7 @@ jobs:
- 16379:6379
steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@v4
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
persist-credentials: false
submodules: recursive

View File

@@ -30,21 +30,21 @@ jobs:
name: Build & Deploy
runs-on: ubuntu-24.04
steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@v4
- name: "Checkout ${{ github.event.workflow_run.head_sha || github.sha }}"
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
persist-credentials: false
submodules: recursive
- name: Set up Node.js 20
uses: actions/setup-node@v4
- name: Set up Node.js
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6
with:
node-version: '20'
node-version: "20"
- name: Setup Python
uses: ./.github/actions/setup-backend/
- uses: actions/setup-java@v4
- uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5
with:
distribution: 'zulu'
java-version: '21'
distribution: "zulu"
java-version: "21"
- name: Install Graphviz
run: sudo apt-get install -y graphviz
- name: Compute Entity Relationship diagram (ERD)

View File

@@ -18,7 +18,7 @@ jobs:
name: Link Checking
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
# Do not bump this linkinator-action version without opening
# an ASF Infra ticket to allow the new verison first!
- uses: JustinBeckwith/linkinator-action@v1.11.0
@@ -56,14 +56,14 @@ jobs:
working-directory: docs
steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@v4
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
persist-credentials: false
submodules: recursive
- name: Set up Node.js 20
uses: actions/setup-node@v4
- name: Set up Node.js
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6
with:
node-version: '20'
node-version: "20"
- name: yarn install
run: |
yarn install --check-cache

View File

@@ -10,17 +10,17 @@ on:
workflow_dispatch:
inputs:
use_dashboard:
description: 'Use Cypress Dashboard (true/false) [paid service - trigger manually when needed]. You MUST provide a branch and/or PR number below for this to work.'
description: "Use Cypress Dashboard (true/false) [paid service - trigger manually when needed]. You MUST provide a branch and/or PR number below for this to work."
required: false
default: 'false'
default: "false"
ref:
description: 'The branch or tag to checkout'
description: "The branch or tag to checkout"
required: false
default: ''
default: ""
pr_id:
description: 'The pull request ID to checkout'
description: "The pull request ID to checkout"
required: false
default: ''
default: ""
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
@@ -68,20 +68,20 @@ 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@v4
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
persist-credentials: false
submodules: recursive
- name: Checkout using ref (workflow_dispatch)
if: github.event_name == 'workflow_dispatch' && github.event.inputs.ref != ''
uses: actions/checkout@v4
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
persist-credentials: false
ref: ${{ github.event.inputs.ref }}
submodules: recursive
- name: Checkout using PR ID (workflow_dispatch)
if: github.event_name == 'workflow_dispatch' && github.event.inputs.pr_id != ''
uses: actions/checkout@v4
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
persist-credentials: false
ref: refs/pull/${{ github.event.inputs.pr_id }}/merge
@@ -107,7 +107,7 @@ jobs:
run: testdata
- name: Setup Node.js
if: steps.check.outputs.python || steps.check.outputs.frontend
uses: actions/setup-node@v4
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6
with:
node-version: "20"
- name: Install npm dependencies
@@ -137,8 +137,8 @@ jobs:
with:
run: cypress-run-all ${{ env.USE_DASHBOARD }}
- name: Upload Artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7
if: failure()
with:
path: ${{ github.workspace }}/superset-frontend/cypress-base/cypress/screenshots
name: cypress-artifact-${{ github.run_id }}-${{ github.job }}-${{ matrix.browser }}-${{ matrix.parallel_id }}
name: cypress-artifact-${{ github.run_id }}-${{ github.job }}-${{ matrix.browser }}-${{ matrix.parallel_id }}--${{ steps.set-safe-app-root.outputs.safe_app_root }}

View File

@@ -0,0 +1,64 @@
name: Superset Extensions CLI Package Tests
on:
push:
branches:
- "master"
- "[0-9].[0-9]*"
pull_request:
types: [synchronize, opened, reopened, ready_for_review]
# cancel previous workflow jobs for PRs
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
cancel-in-progress: true
jobs:
test-superset-extensions-cli-package:
runs-on: ubuntu-24.04
strategy:
matrix:
python-version: ["previous", "current", "next"]
defaults:
run:
working-directory: superset-extensions-cli
steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
persist-credentials: false
submodules: recursive
- name: Check for file changes
id: check
uses: ./.github/actions/change-detector/
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Setup Python
if: steps.check.outputs.superset-extensions-cli
uses: ./.github/actions/setup-backend/
with:
python-version: ${{ matrix.python-version }}
requirements-type: dev
- name: Run pytest with coverage
if: steps.check.outputs.superset-extensions-cli
run: |
pytest --cov=superset_extensions_cli --cov-report=xml --cov-report=term-missing --cov-report=html -v --tb=short
- name: Upload coverage reports to Codecov
if: steps.check.outputs.superset-extensions-cli
uses: codecov/codecov-action@1af58845a975a7985b0beb0cbe6fbbb71a41dbad # v5
with:
file: ./coverage.xml
flags: superset-extensions-cli
name: superset-extensions-cli-coverage
fail_ci_if_error: false
- name: Upload HTML coverage report
if: steps.check.outputs.superset-extensions-cli
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7
with:
name: superset-extensions-cli-coverage-html
path: htmlcov/

View File

@@ -23,7 +23,7 @@ jobs:
should-run: ${{ steps.check.outputs.frontend }}
steps:
- name: Checkout Code
uses: actions/checkout@v4
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
persist-credentials: false
@@ -52,7 +52,7 @@ jobs:
- name: Upload Docker Image Artifact
if: steps.check.outputs.frontend
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7
with:
name: docker-image
path: docker-image.tar.gz
@@ -67,7 +67,7 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: Download Docker Image Artifact
uses: actions/download-artifact@v4
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
name: docker-image
@@ -84,7 +84,7 @@ jobs:
"npm run test -- --coverage --shard=${{ matrix.shard }}/8 --coverageReporters=json-summary"
- name: Upload Coverage Artifact
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7
with:
name: coverage-artifacts-${{ matrix.shard }}
path: superset-frontend/coverage
@@ -95,7 +95,7 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: Download Coverage Artifacts
uses: actions/download-artifact@v4
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
pattern: coverage-artifacts-*
path: coverage/
@@ -107,7 +107,7 @@ jobs:
run: npx nyc merge coverage/ merged-output/coverage-summary.json
- name: Upload Code Coverage
uses: codecov/codecov-action@v5
uses: codecov/codecov-action@1af58845a975a7985b0beb0cbe6fbbb71a41dbad # v5
with:
flags: javascript
token: ${{ secrets.CODECOV_TOKEN }}
@@ -139,7 +139,7 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: Download Docker Image Artifact
uses: actions/download-artifact@v4
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
name: docker-image
@@ -162,7 +162,7 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: Download Docker Image Artifact
uses: actions/download-artifact@v4
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
name: docker-image
@@ -174,7 +174,7 @@ jobs:
docker run --rm $TAG bash -c \
"npm run plugins:build"
- name: Build Plugins Storybook
- name: Build Storybook and Run Tests
run: |
docker run --rm $TAG bash -c \
"npm run plugins:build-storybook"

View File

@@ -16,21 +16,21 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@v4
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
persist-credentials: false
submodules: recursive
fetch-depth: 0
- name: Set up Helm
uses: azure/setup-helm@v4
uses: azure/setup-helm@1a275c3b69536ee54be43f2070a358922e12c8d4 # v4
with:
version: v3.16.4
- name: Setup Python
uses: ./.github/actions/setup-backend/
with:
install-superset: 'false'
install-superset: "false"
- name: Set up chart-testing
uses: ./.github/actions/chart-testing-action

View File

@@ -29,7 +29,7 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
ref: ${{ inputs.ref || github.ref_name }}
persist-credentials: true
@@ -42,7 +42,7 @@ jobs:
git config user.email "$GITHUB_ACTOR@users.noreply.github.com"
- name: Install Helm
uses: azure/setup-helm@v4
uses: azure/setup-helm@1a275c3b69536ee54be43f2070a358922e12c8d4 # v4
with:
version: v3.5.4
@@ -101,7 +101,7 @@ jobs:
CR_RELEASE_NAME_TEMPLATE: "superset-helm-chart-{{ .Version }}"
- name: Open Pull Request
uses: actions/github-script@v7
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
with:
script: |
const branchName = '${{ env.branch_name }}';

View File

@@ -41,7 +41,7 @@ jobs:
- 16379:6379
steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@v4
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
persist-credentials: false
submodules: recursive
@@ -68,7 +68,7 @@ jobs:
run: |
./scripts/python_tests.sh
- name: Upload code coverage
uses: codecov/codecov-action@v5
uses: codecov/codecov-action@1af58845a975a7985b0beb0cbe6fbbb71a41dbad # v5
with:
flags: python,mysql
token: ${{ secrets.CODECOV_TOKEN }}
@@ -99,7 +99,7 @@ jobs:
- 16379:6379
steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@v4
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
persist-credentials: false
submodules: recursive
@@ -129,7 +129,7 @@ jobs:
run: |
./scripts/python_tests.sh
- name: Upload code coverage
uses: codecov/codecov-action@v5
uses: codecov/codecov-action@1af58845a975a7985b0beb0cbe6fbbb71a41dbad # v5
with:
flags: python,postgres
token: ${{ secrets.CODECOV_TOKEN }}
@@ -152,7 +152,7 @@ jobs:
- 16379:6379
steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@v4
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
persist-credentials: false
submodules: recursive
@@ -181,7 +181,7 @@ jobs:
run: |
./scripts/python_tests.sh
- name: Upload code coverage
uses: codecov/codecov-action@v5
uses: codecov/codecov-action@1af58845a975a7985b0beb0cbe6fbbb71a41dbad # v5
with:
flags: python,sqlite
token: ${{ secrets.CODECOV_TOKEN }}

View File

@@ -48,7 +48,7 @@ jobs:
- 16379:6379
steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@v4
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
persist-credentials: false
submodules: recursive
@@ -77,7 +77,7 @@ jobs:
run: |
./scripts/python_tests.sh -m 'chart_data_flow or sql_json_flow'
- name: Upload code coverage
uses: codecov/codecov-action@v5
uses: codecov/codecov-action@1af58845a975a7985b0beb0cbe6fbbb71a41dbad # v5
with:
flags: python,presto
token: ${{ secrets.CODECOV_TOKEN }}
@@ -108,7 +108,7 @@ jobs:
- 16379:6379
steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@v4
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
persist-credentials: false
submodules: recursive
@@ -145,7 +145,7 @@ jobs:
pip install -e .[hive]
./scripts/python_tests.sh -m 'chart_data_flow or sql_json_flow'
- name: Upload code coverage
uses: codecov/codecov-action@v5
uses: codecov/codecov-action@1af58845a975a7985b0beb0cbe6fbbb71a41dbad # v5
with:
flags: python,hive
token: ${{ secrets.CODECOV_TOKEN }}

View File

@@ -24,7 +24,7 @@ jobs:
PYTHONPATH: ${{ github.workspace }}
steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@v4
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
persist-credentials: false
submodules: recursive
@@ -46,7 +46,7 @@ jobs:
run: |
pytest --durations-min=0.5 --cov-report= --cov=superset ./tests/common ./tests/unit_tests --cache-clear
- name: Upload code coverage
uses: codecov/codecov-action@v5
uses: codecov/codecov-action@1af58845a975a7985b0beb0cbe6fbbb71a41dbad # v5
with:
flags: python,unit
token: ${{ secrets.CODECOV_TOKEN }}

View File

@@ -18,7 +18,7 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@v4
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
persist-credentials: false
submodules: recursive
@@ -31,9 +31,9 @@ jobs:
- name: Setup Node.js
if: steps.check.outputs.frontend
uses: actions/setup-node@v4
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6
with:
node-version: '18'
node-version: "18"
- name: Install dependencies
if: steps.check.outputs.frontend
uses: ./.github/actions/cached-dependencies
@@ -49,7 +49,7 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@v4
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
persist-credentials: false
submodules: recursive

View File

@@ -21,7 +21,7 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@v4
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
persist-credentials: false
- name: Install dependencies

View File

@@ -9,7 +9,7 @@ on:
workflow_dispatch:
inputs:
comment_body:
description: 'Comment Body'
description: "Comment Body"
required: true
type: string
@@ -26,7 +26,7 @@ jobs:
steps:
- name: Quickly add thumbs up!
if: github.event_name == 'issue_comment' && contains(github.event.comment.body, '@supersetbot')
uses: actions/github-script@v7
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
with:
script: |
const [owner, repo] = process.env.GITHUB_REPOSITORY.split('/')
@@ -38,7 +38,7 @@ jobs:
});
- name: "Checkout ( ${{ github.sha }} )"
uses: actions/checkout@v4
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
persist-credentials: false

View File

@@ -16,11 +16,11 @@ on:
force-latest:
required: true
type: choice
default: 'false'
default: "false"
description: Whether to force a latest tag on the release
options:
- 'true'
- 'false'
- "true"
- "false"
jobs:
config:
runs-on: ubuntu-24.04
@@ -42,12 +42,12 @@ jobs:
runs-on: ubuntu-24.04
strategy:
matrix:
build_preset: ["dev", "lean", "py310", "websocket", "dockerize", "py311"]
build_preset:
["dev", "lean", "py310", "websocket", "dockerize", "py311"]
fail-fast: false
steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@v4
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
fetch-depth: 0
@@ -60,7 +60,7 @@ jobs:
build: "true"
- name: Use Node.js 20
uses: actions/setup-node@v4
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6
with:
node-version: 20
@@ -105,14 +105,13 @@ jobs:
contents: read
pull-requests: write
steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@v4
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
fetch-depth: 0
- name: Use Node.js 20
uses: actions/setup-node@v4
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6
with:
node-version: 20

View File

@@ -27,12 +27,12 @@ jobs:
name: Generate Reports
steps:
- name: Checkout Repository
uses: actions/checkout@v4
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- name: Set up Node.js
uses: actions/setup-node@v4
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6
with:
node-version: '20'
node-version: "20"
- name: Install Dependencies
run: npm install

2
.gitignore vendored
View File

@@ -42,7 +42,7 @@ _modules
_static
build
app.db
apache_superset.egg-info/
*.egg-info/
changelog.sh
dist
dump.rdb

View File

@@ -23,7 +23,9 @@ repos:
rev: v1.13.0
hooks:
- id: mypy
name: mypy (main)
args: [--check-untyped-defs]
exclude: ^superset-extensions-cli/
additional_dependencies: [
types-simplejson,
types-python-dateutil,
@@ -38,6 +40,10 @@ repos:
types-paramiko,
types-Markdown,
]
- id: mypy
name: mypy (superset-extensions-cli)
args: [--check-untyped-defs]
files: ^superset-extensions-cli/
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
@@ -83,5 +89,5 @@ repos:
rev: v0.8.0
hooks:
- id: ruff
args: [ --fix ]
args: [--fix]
- id: ruff-format

View File

@@ -32,6 +32,8 @@ apache_superset.egg-info
# json and csv in general cannot have comments
.*json
.*csv
# jinja templates often need to be as-is
.*j2
# Generated doc files
env/*
docs/.htaccess*

View File

@@ -44,3 +44,4 @@ under the License.
- [4.0.1](./CHANGELOG/4.0.1.md)
- [4.0.2](./CHANGELOG/4.0.2.md)
- [4.1.0](./CHANGELOG/4.1.0.md)
- [5.0.0](./CHANGELOG/5.0.0.md)

937
CHANGELOG/5.0.0.md Normal file
View File

@@ -0,0 +1,937 @@
<!--
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.
-->
## Change Log
### 5.0.0 (Wed Jun 18 13:54:10 2025 -0300)
**Database Migrations**
- [#31959](https://github.com/apache/superset/pull/31959) refactor: upload data unification, less permissions and less endpoints (@dpgaspar)
- [#31582](https://github.com/apache/superset/pull/31582) refactor: Removes 5.0 approved legacy charts (@michael-s-molina)
- [#31490](https://github.com/apache/superset/pull/31490) feat: use docker in frontend GHA to parallelize work (@mistercrunch)
- [#30398](https://github.com/apache/superset/pull/30398) feat: add and use UUIDMixin for most models (@mistercrunch)
- [#29649](https://github.com/apache/superset/pull/29649) fix: remove old database constraint on the Dataset model (@betodealmeida)
- [#31447](https://github.com/apache/superset/pull/31447) chore: enforce more ruff rules (@mistercrunch)
- [#31303](https://github.com/apache/superset/pull/31303) feat: Adds helper functions for migrations (@luizotavio32)
**Features**
- [#32052](https://github.com/apache/superset/pull/32052) feat: add connector for Parseable (@AdheipSingh)
- [#32051](https://github.com/apache/superset/pull/32051) feat(sqllab): improve table metadata UI (@justinpark)
- [#29900](https://github.com/apache/superset/pull/29900) feat(sqllab): Replace FilterableTable by AgGrid Table (@justinpark)
- [#31979](https://github.com/apache/superset/pull/31979) feat(fe): upgrade `superset-frontend` to Typescript v5 (@hainenber)
- [#31413](https://github.com/apache/superset/pull/31413) feat: add date format to the email subject (@US579)
- [#31984](https://github.com/apache/superset/pull/31984) feat: run prettier before eslint in pre-commit hooks (@mistercrunch)
- [#31889](https://github.com/apache/superset/pull/31889) feat(CalendarFrame): adding previous calendar quarter (@alexandrusoare)
- [#31796](https://github.com/apache/superset/pull/31796) feat: get docker-compose to work as the backend for Cypress tests (@mistercrunch)
- [#31876](https://github.com/apache/superset/pull/31876) feat: use npm run dev-server in docker-compose (@mistercrunch)
- [#31849](https://github.com/apache/superset/pull/31849) feat: old Firebolt dialect (@betodealmeida)
- [#31840](https://github.com/apache/superset/pull/31840) feat: Mutate SQL query executed by alerts (@Vitor-Avila)
- [#31825](https://github.com/apache/superset/pull/31825) feat: Firebolt sqlglot dialect (@betodealmeida)
- [#31575](https://github.com/apache/superset/pull/31575) feat: redesign labels (@mistercrunch)
- [#31747](https://github.com/apache/superset/pull/31747) feat: improve docker-compose services boot sequence (@mistercrunch)
- [#31760](https://github.com/apache/superset/pull/31760) feat: allowing print() statements to be unbuffered in docker (@mistercrunch)
- [#31486](https://github.com/apache/superset/pull/31486) feat: push predicates into virtual datasets (@betodealmeida)
- [#31518](https://github.com/apache/superset/pull/31518) feat: adds a github action to auto label draft prs (@sadpandajoe)
- [#31740](https://github.com/apache/superset/pull/31740) feat: make CI against 'next' python version not-required (@mistercrunch)
- [#31602](https://github.com/apache/superset/pull/31602) feat(Sqllab): Enabling selection and copying of columns and rows in sql lab and dataset view (@samraHanif0340)
- [#31580](https://github.com/apache/superset/pull/31580) feat(doris): add catalog support for Apache Doris (@liujiwen-up)
- [#25869](https://github.com/apache/superset/pull/25869) feat(plugin): add plugin-chart-cartodiagram (@jansule)
- [#31037](https://github.com/apache/superset/pull/31037) feat(country-map): add map for France with all overseas territories (@tarraschk)
- [#31386](https://github.com/apache/superset/pull/31386) feat(gha): various docker / docker-compose build improvements (@mistercrunch)
- [#31316](https://github.com/apache/superset/pull/31316) feat(sqllab): giving the query history pane a facelift (@mistercrunch)
- [#31273](https://github.com/apache/superset/pull/31273) feat: fine-grain chart data telemetry (@betodealmeida)
- [#31141](https://github.com/apache/superset/pull/31141) feat: add YDB as a new database engine (@vgvoleg)
- [#31261](https://github.com/apache/superset/pull/31261) feat(Handlebars): formatNumber and group helpers (@Vitor-Avila)
- [#31260](https://github.com/apache/superset/pull/31260) feat: use uv in CI (@mistercrunch)
- [#31187](https://github.com/apache/superset/pull/31187) feat(sqllab): Popup notification when download data can exceed row count (@justinpark)
- [#31166](https://github.com/apache/superset/pull/31166) feat: make sure to quote formulas on Excel export (@betodealmeida)
- [#31164](https://github.com/apache/superset/pull/31164) feat: purge OAuth2 tokens when DB changes (@betodealmeida)
- [#30870](https://github.com/apache/superset/pull/30870) feat: make ephemeral env use supersetbot + deprecate build_docker.py (@mistercrunch)
- [#30926](https://github.com/apache/superset/pull/30926) feat(trino,presto): add missing time grains (@villebro)
- [#30884](https://github.com/apache/superset/pull/30884) feat: add logging durations for screenshot async service (@mistercrunch)
- [#29609](https://github.com/apache/superset/pull/29609) feat: add a script to check environment software versions (@mistercrunch)
- [#30081](https://github.com/apache/superset/pull/30081) feat(oauth2): add support for trino (@joaoferrao)
- [#30694](https://github.com/apache/superset/pull/30694) feat: allow exporting all tabs to a single PDF in report (@US579)
- [#30674](https://github.com/apache/superset/pull/30674) feat(oauth): adding necessary changes to support bigquery oauth (@fisjac)
- [#30721](https://github.com/apache/superset/pull/30721) feat(dataset API): Add parameter to optionally render Jinja macros in API response (@Vitor-Avila)
- [#30412](https://github.com/apache/superset/pull/30412) feat: cancel impala query on stop (@wugeer)
- [#30710](https://github.com/apache/superset/pull/30710) feat(helm-chart): Add extraLabels to all resources (@maxforasteiro)
- [#29927](https://github.com/apache/superset/pull/29927) feat(db_engine_specs): added support for Denodo Virtual DataPort (@denodo-research-labs)
- [#30593](https://github.com/apache/superset/pull/30593) feat(number-format): Add duration formatter with colon notation (@gerbermichi)
- [#30559](https://github.com/apache/superset/pull/30559) feat(formatting): Add memory units adaptive formatter to format bytes (@mkopec87)
- [#30501](https://github.com/apache/superset/pull/30501) feat(SQL Lab): better SQL parsing error messages (@betodealmeida)
- [#30390](https://github.com/apache/superset/pull/30390) feat(be/cfg): replace deprecated imp.load_source with importlib.util (@hainenber)
- [#29395](https://github.com/apache/superset/pull/29395) feat(dashboard): update tab drag and drop reordering with positional placement and indicators for UI (@rtexelm)
- [#30380](https://github.com/apache/superset/pull/30380) feat(auth): when user is not logged in, failure to access a dashboard should redirect to login screen (@sfirke)
- [#30364](https://github.com/apache/superset/pull/30364) feat(datasets): Allow swap dataset after deletion (@Antonio-RiveroMartnez)
- [#30336](https://github.com/apache/superset/pull/30336) feat(Digest): Add RLS at digest generation for Charts and Dashboards (@geido)
- [#30266](https://github.com/apache/superset/pull/30266) feat: allow configuring an engine context manager (@betodealmeida)
- [#30323](https://github.com/apache/superset/pull/30323) feat(jinja): add option to format time filters using strftime (@villebro)
- [#29897](https://github.com/apache/superset/pull/29897) feat(explore): Add time shift color control to ECharts (@rtexelm)
- [#30016](https://github.com/apache/superset/pull/30016) feat: Displaying details to Dataset/Database deletion modals (@rusackas)
- [#30142](https://github.com/apache/superset/pull/30142) feat(jinja): add advanced temporal filter functionality (@villebro)
- [#28110](https://github.com/apache/superset/pull/28110) feat(db_engine): Implement user impersonation support for StarRocks (@Woellchen)
- [#30126](https://github.com/apache/superset/pull/30126) feat: OAuth2 database field (@betodealmeida)
- [#30082](https://github.com/apache/superset/pull/30082) feat: Oauth2 in DatabaseSelector (@betodealmeida)
- [#30071](https://github.com/apache/superset/pull/30071) feat: allow create/update OAuth2 DB (@betodealmeida)
- [#29912](https://github.com/apache/superset/pull/29912) feat(GAQ): Add Redis Sentinel Support for Global Async Queries (@nsivarajan)
- [#24308](https://github.com/apache/superset/pull/24308) feat(docker): add GUNICORN_LOGLEVEL env var (@drummerwolli)
- [#29333](https://github.com/apache/superset/pull/29333) feat(alert/reports): adding logic to handle downstream reports when tab is deleted from dashboard (@fisjac)
- [#30002](https://github.com/apache/superset/pull/30002) feat(time_comparison): Support all date formats when computing custom and inherit offsets (@Antonio-RiveroMartnez)
- [#25775](https://github.com/apache/superset/pull/25775) feat: Adding Elestio as deployment option (@kaiwalyakoparkar)
- [#29941](https://github.com/apache/superset/pull/29941) feat(docs): fix bug google chrome < 114 not found (@hoalongnatsu)
- [#29917](https://github.com/apache/superset/pull/29917) feat: Enable injecting custom html into head (@kgabryje)
- [#29875](https://github.com/apache/superset/pull/29875) feat(build): webpack visualizer (@rusackas)
- [#29724](https://github.com/apache/superset/pull/29724) feat: get html (links/styling/img/...) to work in pivot table (@mistercrunch)
- [#29795](https://github.com/apache/superset/pull/29795) feat: adding AntdThemeProvider to storybook config (@rusackas)
- [#29096](https://github.com/apache/superset/pull/29096) feat(alerts): enable tab selection for dashboard alerts/reports (@fisjac)
- [#29553](https://github.com/apache/superset/pull/29553) feat(explorer): Add configs and formatting to discrete comparison columns (@rtexelm)
- [#29627](https://github.com/apache/superset/pull/29627) feat(country map): Adding Hungary (and other touchups) (@rusackas)
**Fixes**
- [#33817](https://github.com/apache/superset/pull/33817) fix: SQL Lab warning message sizes (@michael-s-molina)
- [#33779](https://github.com/apache/superset/pull/33779) fix(Echarts): Echarts Legend Scroll fix (@amaannawab923)
- [#33765](https://github.com/apache/superset/pull/33765) fix(tooltip): Sanitize tooltip html (@msyavuz)
- [#33759](https://github.com/apache/superset/pull/33759) fix: apply d3 format to BigNumber(s) (@betodealmeida)
- [#33752](https://github.com/apache/superset/pull/33752) fix(create chart page): add missing space between words (@Quatters)
- [#33748](https://github.com/apache/superset/pull/33748) fix: sync dot color between dashboard chart and edit chart (@anantaoutlook)
- [#33743](https://github.com/apache/superset/pull/33743) fix(dataset): Fix plural toast messages (@rad-pat)
- [#33717](https://github.com/apache/superset/pull/33717) fix(explore): add gap to the "Cached" button (@Quatters)
- [#33719](https://github.com/apache/superset/pull/33719) fix(Alerts & reports): invalid "Last updated" time formatting (@Quatters)
- [#33726](https://github.com/apache/superset/pull/33726) fix(dashboard): show dashboard thumbnail images when retrieved (@rad-pat)
- [#33296](https://github.com/apache/superset/pull/33296) fix(template_processing): get_filters now works for IS_NULL and IS_NOT_NULL operators (@Prokos)
- [#32414](https://github.com/apache/superset/pull/32414) fix(api): Added uuid to list api calls (@withnale)
- [#33710](https://github.com/apache/superset/pull/33710) fix: Migrate charts with empty query_context (@luizotavio32)
- [#33592](https://github.com/apache/superset/pull/33592) fix: Makes time compare migration more resilient (@michael-s-molina)
- [#33596](https://github.com/apache/superset/pull/33596) fix: Missing processor context when rendering Jinja (@michael-s-molina)
- [#33285](https://github.com/apache/superset/pull/33285) fix: Adjust viz migrations to also migrate the queries object (@luizotavio32)
- [#33431](https://github.com/apache/superset/pull/33431) fix(sankey): incorrect nodeValues (@richardfogaca)
- [#33553](https://github.com/apache/superset/pull/33553) fix(AllEntities): Display action buttons according to the user permissions (@Vitor-Avila)
- [#30577](https://github.com/apache/superset/pull/30577) fix(user settings): Update forked cosmo theme to resolve down chevron in caret style (#30514) (@mklumpen)
- [#33540](https://github.com/apache/superset/pull/33540) fix(table): table sort by fix (@amaannawab923)
- [#33522](https://github.com/apache/superset/pull/33522) fix(Sqllab): Autocomplete got stuck in UI when open it too fast (@rebenitez1802)
- [#33444](https://github.com/apache/superset/pull/33444) fix: allow metadata to parse json (@eschutho)
- [#33425](https://github.com/apache/superset/pull/33425) fix(table-chart): time shift is not working (@justinpark)
- [#33364](https://github.com/apache/superset/pull/33364) fix(deckgl): fix deckgl multiple layers chart filter and viewport (@syedbarimanjan)
- [#33422](https://github.com/apache/superset/pull/33422) fix(Row): don't unload charts while embedded to reduce rerenders (@msyavuz)
- [#33354](https://github.com/apache/superset/pull/33354) fix: loading examples from raw.githubusercontent.com fails with 429 errors (@mistercrunch)
- [#31917](https://github.com/apache/superset/pull/31917) fix(be/utils): sync cache timeout for memoized function (@hainenber)
- [#33345](https://github.com/apache/superset/pull/33345) fix(i18n): zh_TW pybabel compile error: placeholders are incompatible (@bestlong)
- [#33337](https://github.com/apache/superset/pull/33337) fix: Edge case with metric not getting quoted in sort by when normalize_columns is enabled (@Vitor-Avila)
- [#33224](https://github.com/apache/superset/pull/33224) fix: Temporal filter conversion in viz migrations (@michael-s-molina)
- [#33306](https://github.com/apache/superset/pull/33306) fix: improve function detection (@betodealmeida)
- [#33269](https://github.com/apache/superset/pull/33269) fix(echarts): rename time series shifted colnames (@justinpark)
- [#33267](https://github.com/apache/superset/pull/33267) fix: mask password on DB import (@betodealmeida)
- [#33025](https://github.com/apache/superset/pull/33025) fix: LocalProxy is not mapped warning (@dpgaspar)
- [#33248](https://github.com/apache/superset/pull/33248) fix(histogram): remove extra single quotes (@rusackas)
- [#33250](https://github.com/apache/superset/pull/33250) fix(DB update): Gracefully handle querry error during DB update (@Vitor-Avila)
- [#33238](https://github.com/apache/superset/pull/33238) fix(heatmap): correctly render int and boolean falsy values on axes (@sfirke)
- [#33237](https://github.com/apache/superset/pull/33237) fix(sqllab permalink): Commit SQL Lab permalinks (@Vitor-Avila)
- [#33234](https://github.com/apache/superset/pull/33234) fix(standalone): Ensure correct URL param value for standalone mode (@Vitor-Avila)
- [#33291](https://github.com/apache/superset/pull/33291) fix(antd): Invalid dashed border in tertiary button (@justinpark)
- [#33214](https://github.com/apache/superset/pull/33214) fix(export): Full CSV/Excel exports respecting SQL_MAX_ROW config (@Vitor-Avila)
- [#33164](https://github.com/apache/superset/pull/33164) fix(sqllab): Invalid SQL Error breaks SQL Lab (@justinpark)
- [#33154](https://github.com/apache/superset/pull/33154) fix(deckgl): Update Arc to properly adjust line width (@rusackas)
- [#33161](https://github.com/apache/superset/pull/33161) fix: os.makedirs race condition (@jamra)
- [#33143](https://github.com/apache/superset/pull/33143) fix(echart): Thrown errors shown after resized (@justinpark)
- [#33138](https://github.com/apache/superset/pull/33138) fix(echart): Tooltip date format doesn't follow time grain (@justinpark)
- [#31692](https://github.com/apache/superset/pull/31692) fix(lang): patch FAB's LocaleView to redirect to previous page (@pomegranited)
- [#33106](https://github.com/apache/superset/pull/33106) fix(dashboard): invalid active tab state (@justinpark)
- [#33037](https://github.com/apache/superset/pull/33037) fix: Viz migration error handling (@michael-s-molina)
- [#33107](https://github.com/apache/superset/pull/33107) fix(playwright): allow screenshotting empty dashboards (@hxtmdev)
- [#33110](https://github.com/apache/superset/pull/33110) fix: resolve recent merge collisio (@mistercrunch)
- [#33103](https://github.com/apache/superset/pull/33103) fix: Allows configuration of Selenium Webdriver binary (@michael-s-molina)
- [#33109](https://github.com/apache/superset/pull/33109) fix(thumbnails): ensure consistent cache_key (@hxtmdev)
- [#32193](https://github.com/apache/superset/pull/32193) fix(dashboard): Generate screenshot via celery (@tahvane1)
- [#33087](https://github.com/apache/superset/pull/33087) fix(docker): fallback to pip if uv is not available (@hossein-khalilian)
- [#33059](https://github.com/apache/superset/pull/33059) fix: Adds missing **init** file to commands/logs (@michael-s-molina)
- [#33048](https://github.com/apache/superset/pull/33048) fix: improve error type on parse error (@justinpark)
- [#31720](https://github.com/apache/superset/pull/31720) fix(export): charts csv export in dashboards (@EmmanuelCbd)
- [#33024](https://github.com/apache/superset/pull/33024) fix(log): Missing failed query log on async queries (@justinpark)
- [#32839](https://github.com/apache/superset/pull/32839) fix: fix bug where dashboard did not enter fullscreen mode. (@LevisNgigi)
- [#28428](https://github.com/apache/superset/pull/28428) fix(dashboard): chart fullscreen issue when filter pane is collapsed (@hlvhe)
- [#29422](https://github.com/apache/superset/pull/29422) fix: `show_filters` URL parameter is not working (@hexcafe)
- [#32965](https://github.com/apache/superset/pull/32965) fix: Bar Chart (legacy) migration to keep labels layout (@michael-s-molina)
- [#30679](https://github.com/apache/superset/pull/30679) fix: fixed Add Metrics to Tree Chart (#29158) (@SBIN2010)
- [#32968](https://github.com/apache/superset/pull/32968) fix(pivot-table): Revert "fix(Pivot Table): Fix column width to respect currency config (#31414)" (@justinpark)
- [#32384](https://github.com/apache/superset/pull/32384) fix: Clicking in the body of a Markdown component does not put it into edit mode (@notHuman9504)
- [#32763](https://github.com/apache/superset/pull/32763) fix(sqllab): Invalid display of table column keys (@justinpark)
- [#32871](https://github.com/apache/superset/pull/32871) fix(Jinja): Emit time grain to table charts even if they don't have a temporal column (@Vitor-Avila)
- [#32372](https://github.com/apache/superset/pull/32372) fix(backend/async_events): allow user to configure username for Redis authentication in GLOBAL_ASYNC_QUERIES_CACHE_BACKEND (@hainenber)
- [#32873](https://github.com/apache/superset/pull/32873) fix: use role_model from security manager (@lohart13)
- [#32851](https://github.com/apache/superset/pull/32851) fix(ColorPickerControl): change color picker control width (@SBIN2010)
- [#32863](https://github.com/apache/superset/pull/32863) fix(table-chart): Do not show comparison columns config if time_compare is set to [] (@Vitor-Avila)
- [#31869](https://github.com/apache/superset/pull/31869) fix(translation): Dutch translations for Current datetime filter (@christiaan)
- [#32829](https://github.com/apache/superset/pull/32829) fix: update dataset/query catalog on DB changes (@betodealmeida)
- [#32850](https://github.com/apache/superset/pull/32850) fix(echarts): Sort series by name using natural comparison (@Vitor-Avila)
- [#32795](https://github.com/apache/superset/pull/32795) fix(log): store navigation path to get correct logging path (@justinpark)
- [#32665](https://github.com/apache/superset/pull/32665) fix: Time Comparison Feature Reverts Metric Labels to Metric Keys in Table Charts (@fardin-developer)
- [#32792](https://github.com/apache/superset/pull/32792) fix: key error in frontend on disallowed GSheets (@chrisvnimbus)
- [#32797](https://github.com/apache/superset/pull/32797) fix: CSV/Excel upload form change column dates description (@SBIN2010)
- [#32802](https://github.com/apache/superset/pull/32802) fix(sec): resolve CVE-2025-29907 and CVE-2025-25977 by pinning `jspdf` to v3 (@hainenber)
- [#32406](https://github.com/apache/superset/pull/32406) fix(model/helper): represent RLS filter clause in proper textual SQL string (@hainenber)
- [#32739](https://github.com/apache/superset/pull/32739) fix(excel export): big number truncation handling (@CharlesNkdl)
- [#32778](https://github.com/apache/superset/pull/32778) fix(config): correct slack image url in talisman (@v9dev)
- [#28350](https://github.com/apache/superset/pull/28350) fix(css): typos in styles (@Kukusik8)
- [#32775](https://github.com/apache/superset/pull/32775) fix(import): Missing catalog field in saved query schema (@Quatters)
- [#32774](https://github.com/apache/superset/pull/32774) fix(sqllab): Pass query_id as kwarg so backoff can see it (@Antonio-RiveroMartnez)
- [#32720](https://github.com/apache/superset/pull/32720) fix(chart control): Change default of "Y Axis Title Margin" (@Quatters)
- [#32761](https://github.com/apache/superset/pull/32761) fix: do not add calculated columns when syncing (@eschutho)
- [#31751](https://github.com/apache/superset/pull/31751) fix: Changing language doesn't affect echarts charts (@jpchev)
- [#28203](https://github.com/apache/superset/pull/28203) fix(contextmenu): uncaught TypeError (@sowo)
- [#32679](https://github.com/apache/superset/pull/32679) fix: ensure datasource permission in explore (@hxtmdev)
- [#32410](https://github.com/apache/superset/pull/32410) fix(import): Ensure import exceptions are logged (@withnale)
- [#32683](https://github.com/apache/superset/pull/32683) fix: coerce datetime conversion errors (@betodealmeida)
- [#32708](https://github.com/apache/superset/pull/32708) fix(logging): missing path in event data (@justinpark)
- [#32701](https://github.com/apache/superset/pull/32701) fix: boolean filters in Explore (@betodealmeida)
- [#32696](https://github.com/apache/superset/pull/32696) fix(spreadsheet uploads): make file extension comparisons case-insensitive (@sfirke)
- [#32691](https://github.com/apache/superset/pull/32691) fix(cosmetics): allow toast message to be toggled off when modal is opened (@hainenber)
- [#32699](https://github.com/apache/superset/pull/32699) fix: Signature of Celery pruner jobs (@michael-s-molina)
- [#32681](https://github.com/apache/superset/pull/32681) fix(log): Update recent_activity by event name (@justinpark)
- [#32678](https://github.com/apache/superset/pull/32678) fix: Update RELEASING/README.md (@michael-s-molina)
- [#32661](https://github.com/apache/superset/pull/32661) fix(gsheets): update params from encrypted extra (@betodealmeida)
- [#32657](https://github.com/apache/superset/pull/32657) fix(import): Import a DB connection with expanded rows enabled (@Vitor-Avila)
- [#32646](https://github.com/apache/superset/pull/32646) fix(dashboard): Ensure `dashboardId` is included in `form_data` for embedded mode (@mostopalove)
- [#32652](https://github.com/apache/superset/pull/32652) fix: Upgrade node base image to Debian 12 bookworm (@dolph)
- [#32608](https://github.com/apache/superset/pull/32608) fix(welcome): perf on distinct recent activities (@justinpark)
- [#32549](https://github.com/apache/superset/pull/32549) fix(dashboard): Support bigint value in native filters (@justinpark)
- [#32599](https://github.com/apache/superset/pull/32599) fix(Slack V2): Specify the filename for the Slack upload method (@Vitor-Avila)
- [#32572](https://github.com/apache/superset/pull/32572) fix: Log table retention policy (@michael-s-molina)
- [#32532](https://github.com/apache/superset/pull/32532) fix: add DateOffset to json serializer (@eschutho)
- [#32523](https://github.com/apache/superset/pull/32523) fix: keep calculated columns when datasource is updated (@eschutho)
- [#32507](https://github.com/apache/superset/pull/32507) fix: Show response message as default error (@eschutho)
- [#32336](https://github.com/apache/superset/pull/32336) fix(Slack): Fix Slack recipients migration to V2 (@Vitor-Avila)
- [#32511](https://github.com/apache/superset/pull/32511) fix(beat): prune_query celery task args fix (@Usiel)
- [#32499](https://github.com/apache/superset/pull/32499) fix(explore): Glitch in a tooltip with metric's name (@kgabryje)
- [#32486](https://github.com/apache/superset/pull/32486) fix: skip DB filter when doing OAuth2 (@betodealmeida)
- [#32488](https://github.com/apache/superset/pull/32488) fix(tooltip): displaying <a> tags correctly (@rusackas)
- [#32473](https://github.com/apache/superset/pull/32473) fix(plugin-chart-echarts): remove erroneous upper bound value (@villebro)
- [#32420](https://github.com/apache/superset/pull/32420) fix(com/grid-comp/markdown): pin `remark-gfm` to v3 to allow inline code block by backticks in Markdown (@hainenber)
- [#32423](https://github.com/apache/superset/pull/32423) fix(clickhouse): get_parameters_from_uri failing when secure is true (@codenamelxl)
- [#32290](https://github.com/apache/superset/pull/32290) fix(viz): update nesting logic to handle multiple dimensions in PartitionViz (@DamianPendrak)
- [#32382](https://github.com/apache/superset/pull/32382) fix(pinot): revert join and subquery flags (@yuribogomolov)
- [#32325](https://github.com/apache/superset/pull/32325) fix: bump FAB to 4.5.4 (@dpgaspar)
- [#32344](https://github.com/apache/superset/pull/32344) fix: ensure metric_macro expands templates (@betodealmeida)
- [#32348](https://github.com/apache/superset/pull/32348) fix: clickhouse-connect engine SSH parameter (@maybedino)
- [#32362](https://github.com/apache/superset/pull/32362) fix(docker): Configure nginx for consistent port mapping and hot reloading (@vedantprajapati)
- [#32350](https://github.com/apache/superset/pull/32350) fix(firebolt): allow backslach escape for single quotes (@betodealmeida)
- [#32356](https://github.com/apache/superset/pull/32356) fix(SSHTunnelForm): make the password tooltip visible (@EnxDev)
- [#32284](https://github.com/apache/superset/pull/32284) fix(roles): Add SqlLabPermalinkRestApi as default sqlab roles. (@LevisNgigi)
- [#32035](https://github.com/apache/superset/pull/32035) fix(fe/dashboard-list): display modifier info for `Last modified` data (@hainenber)
- [#32337](https://github.com/apache/superset/pull/32337) fix: revert "fix: remove sort values on stacked totals (#31333)" (@eschutho)
- [#31993](https://github.com/apache/superset/pull/31993) fix: oauth2 trino (@aurokk)
- [#32332](https://github.com/apache/superset/pull/32332) fix: Download as PDF fails due to cache error (@kgabryje)
- [#30888](https://github.com/apache/superset/pull/30888) fix: keep the tab order (@US579)
- [#32272](https://github.com/apache/superset/pull/32272) fix(viz/table): selected column not shown in Conditional Formatting popover (@hainenber)
- [#32253](https://github.com/apache/superset/pull/32253) fix: Decimal values for Histogram bins (@michael-s-molina)
- [#32218](https://github.com/apache/superset/pull/32218) fix(Datasource): handle undefined datasource_type in fetchSyncedColumns (@tahvane1)
- [#32240](https://github.com/apache/superset/pull/32240) fix: upgrade to 3.11.11-slim-bookworm to address critical vulnerabilities (@gpchandran)
- [#31333](https://github.com/apache/superset/pull/31333) fix: remove sort values on stacked totals (@eschutho)
- [#32227](https://github.com/apache/superset/pull/32227) fix: Update 'Last modified' time when modifying RLS rules (@fardin-developer)
- [#32115](https://github.com/apache/superset/pull/32115) fix(Scope): Correct issue where filters appear out of scope when sort is unchecked. (@LevisNgigi)
- [#32224](https://github.com/apache/superset/pull/32224) fix(sqllab): close the table tab (@justinpark)
- [#32212](https://github.com/apache/superset/pull/32212) fix: set `Rich tooltip` -> 'Show percentage' to false by default (@mistercrunch)
- [#32222](https://github.com/apache/superset/pull/32222) fix(SaveDatasetModal): repairs field alignment in the SaveDatasetModal component (@EnxDev)
- [#32211](https://github.com/apache/superset/pull/32211) fix: hydrate datasetsStatus (@betodealmeida)
- [#32195](https://github.com/apache/superset/pull/32195) fix: handlebars html and css templates reset on dataset update (@DamianPendrak)
- [#32176](https://github.com/apache/superset/pull/32176) fix: TDengine move tdengine.png to databases/ subfolder (@DuanKuanJun)
- [#32185](https://github.com/apache/superset/pull/32185) fix: Adds an entry to UPDATING.md about DISABLE_LEGACY_DATASOURCE_EDITOR (@michael-s-molina)
- [#32154](https://github.com/apache/superset/pull/32154) fix(sqllab): correct URL format for SQL Lab permalinks (@LevisNgigi)
- [#30903](https://github.com/apache/superset/pull/30903) fix(virtual dataset sync): Sync virtual dataset columns when changing the SQL query (@fisjac)
- [#32163](https://github.com/apache/superset/pull/32163) fix(docker): Docker python-translation-build (@EmmanuelCbd)
- [#32156](https://github.com/apache/superset/pull/32156) fix: ScreenshotCachePayload serialization (@betodealmeida)
- [#32151](https://github.com/apache/superset/pull/32151) fix(releasing): fix borked SVN-based image building process (@hainenber)
- [#32137](https://github.com/apache/superset/pull/32137) fix: copy oauth2 capture to `get_sqla_engine` (@betodealmeida)
- [#32135](https://github.com/apache/superset/pull/32135) fix: Local tarball Docker container is missing zstd dependency (@michael-s-molina)
- [#32133](https://github.com/apache/superset/pull/32133) fix: No virtual environment when running Docker translation compiler (@michael-s-molina)
- [#32040](https://github.com/apache/superset/pull/32040) fix(ci): ephemeral env, handle different label, create comment (@dpgaspar)
- [#32064](https://github.com/apache/superset/pull/32064) fix(datepicker): Full width datepicker on filter value select (@msyavuz)
- [#32122](https://github.com/apache/superset/pull/32122) fix: Histogram examples config (@michael-s-molina)
- [#32053](https://github.com/apache/superset/pull/32053) fix: enforce `ALERT_REPORTS_MAX_CUSTOM_SCREENSHOT_WIDTH` (@betodealmeida)
- [#31757](https://github.com/apache/superset/pull/31757) fix(thumbnail cache): Enabling force parameter on screenshot/thumbnail cache (@fisjac)
- [#32061](https://github.com/apache/superset/pull/32061) fix(DatePicker): Increase z-index over Modal (@geido)
- [#32031](https://github.com/apache/superset/pull/32031) fix(fe/explore): prevent runtime error when editing Dataset-origin Chart with empty title (@hainenber)
- [#32045](https://github.com/apache/superset/pull/32045) fix: Revert "fix: re-enable cypress checks" (@mistercrunch)
- [#32008](https://github.com/apache/superset/pull/32008) fix: re-enable cypress checks (@mistercrunch)
- [#32017](https://github.com/apache/superset/pull/32017) fix: eph env + improve docker images to run in userspace (@mistercrunch)
- [#31340](https://github.com/apache/superset/pull/31340) fix(ci): change ephemeral env to use github labels instead of comments (@dpgaspar)
- [#32025](https://github.com/apache/superset/pull/32025) fix: Filters badge disappeared (@kgabryje)
- [#32015](https://github.com/apache/superset/pull/32015) fix(issue #31927): TimeGrain.WEEK_STARTING_MONDAY (@AdrianMastronardi)
- [#30716](https://github.com/apache/superset/pull/30716) fix: Reordering echart props to fix confidence interval in Mixed Charts (@geotab-data-platform)
- [#32005](https://github.com/apache/superset/pull/32005) fix(sqllab): tab layout truncated (@justinpark)
- [#29417](https://github.com/apache/superset/pull/29417) fix(verbose map): Correct raw metrics handling in verbose map (@mcdogg17)
- [#31962](https://github.com/apache/superset/pull/31962) fix: proper URL building (@betodealmeida)
- [#31941](https://github.com/apache/superset/pull/31941) fix(timezoneselector): Correct the order to match names first (@msyavuz)
- [#25166](https://github.com/apache/superset/pull/25166) fix: correct value for config variable `UPLOAD_FOLDER` (@sebastianliebscher)
- [#31948](https://github.com/apache/superset/pull/31948) fix: Load cached DB metadata as DatasourceName and add catalog to schema_list cache key (@Vitor-Avila)
- [#31809](https://github.com/apache/superset/pull/31809) fix: Prevent undo functionality from referencing incorrect dashboard edits (@fardin-developer)
- [#30949](https://github.com/apache/superset/pull/30949) fix: adjust line type as well as weight for time series (@eschutho)
- [#31933](https://github.com/apache/superset/pull/31933) fix(E2E): Fix flaky Dashboard list delete test (@geido)
- [#31867](https://github.com/apache/superset/pull/31867) fix(date_parser): fixed bug for advanced time range filter (@alexandrusoare)
- [#31873](https://github.com/apache/superset/pull/31873) fix(documentation): updated link to CORS_OPTIONS in Networking Settings (@ankur-zignite91)
- [#31910](https://github.com/apache/superset/pull/31910) fix: add catalog to cache key when getting tables/views (@betodealmeida)
- [#31837](https://github.com/apache/superset/pull/31837) fix(bigquery): return no catalogs when creds not set (@betodealmeida)
- [#31848](https://github.com/apache/superset/pull/31848) fix: d3.count doesn't exist (@mistercrunch)
- [#31830](https://github.com/apache/superset/pull/31830) fix: fix/suppress webpack console warnings (@mistercrunch)
- [#31834](https://github.com/apache/superset/pull/31834) fix(OAuth): Remove masked_encrypted_extra from DB update properties (@Vitor-Avila)
- [#31798](https://github.com/apache/superset/pull/31798) fix(Embedded): Skip CSRF validation for dashboard download endpoints (@Vitor-Avila)
- [#31815](https://github.com/apache/superset/pull/31815) fix(modal): fixed z-index issue (@alexandrusoare)
- [#31774](https://github.com/apache/superset/pull/31774) fix: corrects spelling of USE_ANALAGOUS_COLORS to be USE_ANALOGOUS_COLORS (@rusackas)
- [#31777](https://github.com/apache/superset/pull/31777) fix(oauth): Handle updates to the OAuth config (@Vitor-Avila)
- [#31789](https://github.com/apache/superset/pull/31789) fix(button): change back button styles for dropdown buttons (@msyavuz)
- [#31752](https://github.com/apache/superset/pull/31752) fix: Heatmap sorting (@michael-s-molina)
- [#31742](https://github.com/apache/superset/pull/31742) fix: GHA frontend builds fail when frontends hasn't changed (@mistercrunch)
- [#31732](https://github.com/apache/superset/pull/31732) fix: docker builds in forks (@mistercrunch)
- [#31606](https://github.com/apache/superset/pull/31606) fix: docker-compose-image-tag fails to start (@mistercrunch)
- [#31710](https://github.com/apache/superset/pull/31710) fix(inthewild): Update companies using superset (@gwthm-in)
- [#31673](https://github.com/apache/superset/pull/31673) fix: typo in plugin-chart-echats controls (@vhf)
- [#31688](https://github.com/apache/superset/pull/31688) fix(helm): change values.yaml comments (@sule26)
- [#31588](https://github.com/apache/superset/pull/31588) fix: install uv in docker-bootstrap (@mistercrunch)
- [#31583](https://github.com/apache/superset/pull/31583) fix(docs): get quickstart guide working again (@sfirke)
- [#31561](https://github.com/apache/superset/pull/31561) fix: add various recent issues on master CI (@mistercrunch)
- [#31493](https://github.com/apache/superset/pull/31493) fix: master docker builds fail because of multi-platform builds can't --load (@mistercrunch)
- [#31483](https://github.com/apache/superset/pull/31483) fix: Card component background color (@kgabryje)
- [#31472](https://github.com/apache/superset/pull/31472) fix: Tooltip covers the date selector in native filters (@kgabryje)
- [#31473](https://github.com/apache/superset/pull/31473) fix(explore): Styling issue in Search Metrics input field (@kgabryje)
- [#31449](https://github.com/apache/superset/pull/31449) fix(filter options): full size list item targets (@rusackas)
- [#31458](https://github.com/apache/superset/pull/31458) fix(api): typo api.py (@zero-stroke)
- [#31385](https://github.com/apache/superset/pull/31385) fix: docker refactor (@mistercrunch)
- [#31374](https://github.com/apache/superset/pull/31374) fix(Dashboard): Sync color configuration via dedicated endpoint (@geido)
- [#31411](https://github.com/apache/superset/pull/31411) fix: pkg_resources is getting deprecated (@mistercrunch)
- [#31391](https://github.com/apache/superset/pull/31391) fix: don't include chromium on ephemeral envs (@mistercrunch)
- [#31387](https://github.com/apache/superset/pull/31387) fix: Revert "chore(deps-dev): bump esbuild from 0.20.0 to 0.24.0 in /super… (@sadpandajoe)
- [#31236](https://github.com/apache/superset/pull/31236) fix: ephemeral envs fail on noop (@dpgaspar)
- [#31350](https://github.com/apache/superset/pull/31350) fix(alerts&reports): tabs with userfriendly urls (@tahvane1)
- [#30956](https://github.com/apache/superset/pull/30956) fix: added missing pod labels for init job (@glothriel)
- [#31279](https://github.com/apache/superset/pull/31279) fix(filters): improving the add filter/divider UI. (@rusackas)
- [#31155](https://github.com/apache/superset/pull/31155) fix: helm chart deploy to open PRs to now-protected gh-pages branch (@mistercrunch)
- [#31152](https://github.com/apache/superset/pull/31152) fix: try to re-enable gh-pages (@mistercrunch)
- [#31148](https://github.com/apache/superset/pull/31148) fix: touch helm/ folder to trigger doc deploy in CI (@mistercrunch)
- [#31035](https://github.com/apache/superset/pull/31035) fix: ephemeral environments missing env var (@mistercrunch)
- [#30966](https://github.com/apache/superset/pull/30966) fix(helm-chart): Fix broken PodDisruptionBudget due to introduction of extraLabels. (@theoriginalgri)
- [#30964](https://github.com/apache/superset/pull/30964) fix(Card): Use correct class names for Ant Design 5 Card component (@geido)
- [#30924](https://github.com/apache/superset/pull/30924) fix(helm): use submodule on helm release action (@villebro)
- [#30767](https://github.com/apache/superset/pull/30767) fix(empty dashboards): Allow downloading a screenshot of an empty dashboard (@msyavuz)
- [#30885](https://github.com/apache/superset/pull/30885) fix(docs): add missing bracket in openID config (@samarsrivastav)
- [#30858](https://github.com/apache/superset/pull/30858) fix(chart data): removing query from /chart/data payload when accessing as guest user (@fisjac)
- [#30848](https://github.com/apache/superset/pull/30848) fix(time_comparison): Allow deleting dates when using custom shift (@Antonio-RiveroMartnez)
- [#28524](https://github.com/apache/superset/pull/28524) fix: warning emits an error (@eschutho)
- [#30682](https://github.com/apache/superset/pull/30682) fix(explore): Update tooltip copy for rendering html in tables and pivot tables (@yousoph)
- [#30618](https://github.com/apache/superset/pull/30618) fix(mssql db_engine_spec): adds uniqueidentifier to column_type_mappings (@rparsonsbb)
- [#27142](https://github.com/apache/superset/pull/27142) fix(chart): apply number format in Box Plot tooltip only where necessary (@goto-loop)
- [#30608](https://github.com/apache/superset/pull/30608) fix(country-map): Rename incorrect Vietnam province name for Country Map (@tienhung2812)
- [#30702](https://github.com/apache/superset/pull/30702) fix(Dashboard): DatePicker to not autoclose modal (@geido)
- [#30688](https://github.com/apache/superset/pull/30688) fix: bump FAB to 4.5.2 (@dpgaspar)
- [#30659](https://github.com/apache/superset/pull/30659) fix: Link Checking (@CodeWithEmad)
- [#30661](https://github.com/apache/superset/pull/30661) fix: Domain 'undefined' error in Storybook (@kgabryje)
- [#30626](https://github.com/apache/superset/pull/30626) fix: Module is not defined in Partition chart (@michael-s-molina)
- [#30616](https://github.com/apache/superset/pull/30616) fix(docs): leading whitespace line is causing page title and header to be malformed (@sfirke)
- [#30606](https://github.com/apache/superset/pull/30606) fix: Set correct amount of steps to avoid confusing logs while loading examples (@deathstrokedarksky)
- [#30522](https://github.com/apache/superset/pull/30522) fix(SQL Lab): hang when result set size is too big (@anamitraadhikari)
- [#30443](https://github.com/apache/superset/pull/30443) fix(Jinja metric macro): Support Drill By and Excel/CSV download without a dataset ID (@Vitor-Avila)
- [#30569](https://github.com/apache/superset/pull/30569) fix(dev-server): Revert "chore(fe): bump webpack-related packages to v5" (@geido)
- [#30069](https://github.com/apache/superset/pull/30069) fix(frontend/generator): fix failed Viz plugin build due to missing JSDOM config and dep (@hainenber)
- [#30277](https://github.com/apache/superset/pull/30277) fix(examples): fix examples uri for sqlite (@villebro)
- [#30509](https://github.com/apache/superset/pull/30509) fix(plugin/echarts): correct enum values for LABEL_POSITION map (@hainenber)
- [#30500](https://github.com/apache/superset/pull/30500) fix(sqllab): Remove redundant scrolling (@justinpark)
- [#30349](https://github.com/apache/superset/pull/30349) fix(radar-chart): metric options not available & add `min` option (@goncaloacteixeira)
- [#30493](https://github.com/apache/superset/pull/30493) fix(Package.json): Bump dayjs version (@geido)
- [#30406](https://github.com/apache/superset/pull/30406) fix(language): pt_BR translation (@diegolnasc)
- [#30441](https://github.com/apache/superset/pull/30441) fix: battling cypress' dashboard feature (@mistercrunch)
- [#30430](https://github.com/apache/superset/pull/30430) fix: cypress on master doesn't work because of --parallel flag (@mistercrunch)
- [#29444](https://github.com/apache/superset/pull/29444) fix(plugin/country/map): rectify naming for some Vietnamese provinces (@hainenber)
- [#30388](https://github.com/apache/superset/pull/30388) fix(ECharts): Revert ECharts version bump (@geido)
- [#30340](https://github.com/apache/superset/pull/30340) fix(CI): increase node JS heap size (@rusackas)
- [#30325](https://github.com/apache/superset/pull/30325) fix(db_engine_specs): add a few missing time grains to Postgres spec (@sfirke)
- [#30273](https://github.com/apache/superset/pull/30273) fix(dashboard): invalid button style in undo/redo button (@justinpark)
- [#30099](https://github.com/apache/superset/pull/30099) fix: Move copying translation files before npm run build in Docker (@martyngigg)
- [#30279](https://github.com/apache/superset/pull/30279) fix(install/docker): use zstd-baked image for building superset-frontend in containerized env (@hainenber)
- [#30234](https://github.com/apache/superset/pull/30234) fix(deps): release new embedded sdk (@rusackas)
- [#30237](https://github.com/apache/superset/pull/30237) fix(docs): change flask-oidc url (@drblack666)
- [#30217](https://github.com/apache/superset/pull/30217) fix(sdk): use latest @supserset-ui/switchboard version to avoid pulling empty dependency (@hainenber)
- [#30147](https://github.com/apache/superset/pull/30147) fix(docs): typo in docker-compose.mdx (@alexengrig)
- [#30148](https://github.com/apache/superset/pull/30148) fix: Adds the Deprecated label to Time-series Percent Change chart (@michael-s-molina)
- [#30141](https://github.com/apache/superset/pull/30141) fix(sqllab): race condition when updating same cursor position (@justinpark)
- [#30041](https://github.com/apache/superset/pull/30041) fix: Revert "fix(list/chart views): Chart Properties modal now has transitions" (@rusackas)
- [#30034](https://github.com/apache/superset/pull/30034) fix: Handle zstd encoding in webpack proxy config (@kgabryje)
- [#29916](https://github.com/apache/superset/pull/29916) fix: duplicate `truncateXAxis` option in `BarChart` (@dmitriyVasilievich1986)
- [#30013](https://github.com/apache/superset/pull/30013) fix(translations): Fixed APPLY translation in Spanish (@jvines)
- [#30001](https://github.com/apache/superset/pull/30001) fix: Reports are not sent when selecting to send as PNG, CSV or text (@eschutho)
- [#29686](https://github.com/apache/superset/pull/29686) fix: Removed fixed width constraint from Save button (@goldjee)
- [#29951](https://github.com/apache/superset/pull/29951) fix(i18n): translation fix in server side generated time grains (@Seboeb)
- [#29938](https://github.com/apache/superset/pull/29938) fix: thumbnail url json response was malformed (@eschutho)
- [#29944](https://github.com/apache/superset/pull/29944) fix: only show dataset name in list (@eschutho)
- [#29935](https://github.com/apache/superset/pull/29935) fix: Fix delete_fake_db (@stamplevskiyd)
- [#29522](https://github.com/apache/superset/pull/29522) fix(cli): add impersonate_user to db import (@chessman)
- [#29895](https://github.com/apache/superset/pull/29895) fix(PivotTable): Pass string only to safeHtmlSpan (@geido)
- [#29864](https://github.com/apache/superset/pull/29864) fix: mypy issue on py3.9 + prevent similar issues (@mistercrunch)
- [#29861](https://github.com/apache/superset/pull/29861) fix: mypy fails related to simplejson.dumps (@mistercrunch)
- [#24411](https://github.com/apache/superset/pull/24411) fix(docs): update timescale.png (@mathisve)
- [#29851](https://github.com/apache/superset/pull/29851) fix: Add missing icons (@kgabryje)
- [#29591](https://github.com/apache/superset/pull/29591) fix: machine auth for GAQ enabled deployments (@harshit2283)
- [#29798](https://github.com/apache/superset/pull/29798) fix: set default timezone to UTC for cron timezone conversions (@danielli-ziprecruiter)
- [#28796](https://github.com/apache/superset/pull/28796) fix(list/chart views): Chart Properties modal now has transitions (@rusackas)
- [#29688](https://github.com/apache/superset/pull/29688) fix(ci): release process for labeling PRs (@mistercrunch)
- [#29779](https://github.com/apache/superset/pull/29779) fix: remove --no-optional from docker-compose build (@mistercrunch)
**Others**
- [#33745](https://github.com/apache/superset/pull/33745) build: update Dockerfile to 3.11.13-slim-bookworm (@gpchandran)
- [#33612](https://github.com/apache/superset/pull/33612) chore: update Dockerfile - Upgrade to 3.11.12 (@gpchandran)
- [#33339](https://github.com/apache/superset/pull/33339) chore(🦾): bump python h11 0.14.0 -> 0.16.0 (@github-actions[bot])
- [#32745](https://github.com/apache/superset/pull/32745) chore(🦾): bump python sqlglot 26.1.3 -> 26.11.1 (@github-actions[bot])
- [#32239](https://github.com/apache/superset/pull/32239) docs: adding notes about using uv instead of raw pip (@mistercrunch)
- [#32221](https://github.com/apache/superset/pull/32221) chore(ci): fix ephemeral env null issue number (v2) (@dpgaspar)
- [#32220](https://github.com/apache/superset/pull/32220) chore(ci): fix ephemeral env null issue number (@dpgaspar)
- [#32030](https://github.com/apache/superset/pull/32030) chore(timeseries charts): adjust legend width by padding (@eschutho)
- [#32062](https://github.com/apache/superset/pull/32062) chore: Re-enable asnyc event API tests (@Vitor-Avila)
- [#32004](https://github.com/apache/superset/pull/32004) refactor(Radio): Upgrade Radio Component to Ant Design 5 (@EnxDev)
- [#32054](https://github.com/apache/superset/pull/32054) chore: Add more database-related tests (follow up to #31948) (@Vitor-Avila)
- [#31811](https://github.com/apache/superset/pull/31811) chore(Network Errors): Update network errors on filter bars and charts (@msyavuz)
- [#31794](https://github.com/apache/superset/pull/31794) chore: Removing DASHBOARD_CROSS_FILTERS flag and all that comes with it. (@rusackas)
- [#32013](https://github.com/apache/superset/pull/32013) chore: add UPDATING note for CSV_UPLOAD_MAX_SIZE removal (@dpgaspar)
- [#31961](https://github.com/apache/superset/pull/31961) refactor: Upgrade to React 17 (@kgabryje)
- [#32007](https://github.com/apache/superset/pull/32007) chore(fe): correct typing for sheetsColumnNames (@hainenber)
- [#32000](https://github.com/apache/superset/pull/32000) refactor: Remove CSV upload size limit and related validation (@sha174n)
- [#31421](https://github.com/apache/superset/pull/31421) refactor(Shared_url_query): Fix shared query URL access for SQL Lab users. (@LevisNgigi)
- [#31980](https://github.com/apache/superset/pull/31980) chore: Add FYND to INTHEWILD.md (@darpanjain07)
- [#31976](https://github.com/apache/superset/pull/31976) refactor: Removes the legacy dataset editor (@michael-s-molina)
- [#31858](https://github.com/apache/superset/pull/31858) chore: refactor Alert-related components (@mistercrunch)
- [#31547](https://github.com/apache/superset/pull/31547) chore(deps): bump react-transition-group and @types/react-transition-group in /superset-frontend (@dependabot[bot])
- [#31963](https://github.com/apache/superset/pull/31963) chore(build): enforce eslint rule banning antd imports outside of core Superset components (@rusackas)
- [#31965](https://github.com/apache/superset/pull/31965) chore: fix `tsc` errors (@hainenber)
- [#31860](https://github.com/apache/superset/pull/31860) chore: Empty state refactor (@mistercrunch)
- [#31844](https://github.com/apache/superset/pull/31844) chore: replace selenium user with fixed user (@villebro)
- [#31943](https://github.com/apache/superset/pull/31943) refactor: Removes legacy dashboard endpoints (@michael-s-molina)
- [#31942](https://github.com/apache/superset/pull/31942) refactor: Removes legacy CSS template endpoint (@michael-s-molina)
- [#31819](https://github.com/apache/superset/pull/31819) chore(fe): migrate 6 Enzyme-based unit tests to RTL (@hainenber)
- [#31947](https://github.com/apache/superset/pull/31947) chore: bump FAB to 4.5.3 (@dpgaspar)
- [#30284](https://github.com/apache/superset/pull/30284) chore(GAQ): Remove GLOBAL_ASYNC_QUERIES_REDIS_CONFIG (@nsivarajan)
- [#31926](https://github.com/apache/superset/pull/31926) chore: cypress set up tweaks (@mistercrunch)
- [#31905](https://github.com/apache/superset/pull/31905) chore: Reduces the form_data_key length (@michael-s-molina)
- [#31460](https://github.com/apache/superset/pull/31460) docs: Removed mentioning of .env-non-dev in docker/README.md (@nikelborm)
- [#31907](https://github.com/apache/superset/pull/31907) chore: replace Lodash usage with native JS implementation (@hainenber)
- [#31699](https://github.com/apache/superset/pull/31699) refactor(Menu): Upgrade Menu Component to Ant Design 5 (@geido)
- [#31908](https://github.com/apache/superset/pull/31908) chore(fe): dev deps cleanup (@hainenber)
- [#31916](https://github.com/apache/superset/pull/31916) docs: clarify port configuration for Cypress (@mistercrunch)
- [#29163](https://github.com/apache/superset/pull/29163) refactor(sqllab): migrate share queries via kv by permalink (@justinpark)
- [#29121](https://github.com/apache/superset/pull/29121) perf(dashboard): dashboard list endpoint returning large and unnecessary data (@Always-prog)
- [#31894](https://github.com/apache/superset/pull/31894) chore(config): Deprecating Domain Sharding (@rusackas)
- [#31795](https://github.com/apache/superset/pull/31795) chore: Re-enable skipped tests (@michael-s-molina)
- [#31875](https://github.com/apache/superset/pull/31875) chore: add a disable for pylint (@betodealmeida)
- [#31874](https://github.com/apache/superset/pull/31874) docs: add a note about accessing the dev env's postgres database (@mistercrunch)
- [#31845](https://github.com/apache/superset/pull/31845) chore: add eslint to pre-commit hooks (@mistercrunch)
- [#31847](https://github.com/apache/superset/pull/31847) chore(ci): auto delete branches on merge (@rusackas)
- [#31846](https://github.com/apache/superset/pull/31846) chore: properly import expect from chai in cypress-base/cypress/support/e2e.ts (@mistercrunch)
- [#31831](https://github.com/apache/superset/pull/31831) chore: bump @ant-design/icons to fix fill-rule console warning (@mistercrunch)
- [#31503](https://github.com/apache/superset/pull/31503) chore: python version to 3.11 (while supporting 3.10) (@mistercrunch)
- [#31761](https://github.com/apache/superset/pull/31761) build(eslint): disabling wildcard imports with eslint (@rusackas)
- [#25933](https://github.com/apache/superset/pull/25933) chore(deps): bump selenium 4.14.0+ (@gnought)
- [#31820](https://github.com/apache/superset/pull/31820) chore(tests): Changing the logic for an intermittent tag test (@Vitor-Avila)
- [#31631](https://github.com/apache/superset/pull/31631) refactor(bulk_select): Fix bulk select tagging issues for users (@LevisNgigi)
- [#31019](https://github.com/apache/superset/pull/31019) refactor(date picker): Migrate Date Picker to Ant Design 5 (@msyavuz)
- [#31787](https://github.com/apache/superset/pull/31787) docs: improve dev python environment install (@sha174n)
- [#31797](https://github.com/apache/superset/pull/31797) chore: adding Antonio as a helm codeowner (@eschutho)
- [#31452](https://github.com/apache/superset/pull/31452) refactor(dashboard): Migrate ResizableContainer to TypeScript and functional component (@EnxDev)
- [#31791](https://github.com/apache/superset/pull/31791) chore: Skips integration tests affected by legacy charts removal (@michael-s-molina)
- [#31661](https://github.com/apache/superset/pull/31661) build(deps-dev): bump css-loader from 6.8.1 to 7.1.2 in /superset-frontend (@dependabot[bot])
- [#31668](https://github.com/apache/superset/pull/31668) build(deps-dev): bump css-minimizer-webpack-plugin from 5.0.1 to 7.0.0 in /superset-frontend (@dependabot[bot])
- [#31754](https://github.com/apache/superset/pull/31754) refactor: Removes Apply to all panels filters scope configuration (@michael-s-molina)
- [#31623](https://github.com/apache/superset/pull/31623) refactor(Button): Upgrade Button component to Antd5 (@alexandrusoare)
- [#31756](https://github.com/apache/superset/pull/31756) docs: add Remita to list (@mujibishola)
- [#31750](https://github.com/apache/superset/pull/31750) docs: add cover genius to the user list (@US579)
- [#31412](https://github.com/apache/superset/pull/31412) chore(ff): deprecating `DRILL_TO_DETAIL` feature flag to launch it prime-time (@rusackas)
- [#31718](https://github.com/apache/superset/pull/31718) refactor(Steps): Migrate Steps to Ant Design 5 (@msyavuz)
- [#31537](https://github.com/apache/superset/pull/31537) chore(deps): bump react-virtualized-auto-sizer from 1.0.24 to 1.0.25 in /superset-frontend (@dependabot[bot])
- [#31552](https://github.com/apache/superset/pull/31552) chore(deps-dev): bump eslint-plugin-react-hooks from 4.6.0 to 4.6.2 in /superset-frontend (@dependabot[bot])
- [#31545](https://github.com/apache/superset/pull/31545) chore(deps-dev): bump webpack from 5.94.0 to 5.97.1 in /superset-frontend (@dependabot[bot])
- [#31551](https://github.com/apache/superset/pull/31551) chore(deps-dev): bump eslint-plugin-cypress from 3.5.0 to 3.6.0 in /superset-frontend (@dependabot[bot])
- [#31559](https://github.com/apache/superset/pull/31559) chore(deps): bump abortcontroller-polyfill from 1.7.5 to 1.7.8 in /superset-frontend (@dependabot[bot])
- [#31653](https://github.com/apache/superset/pull/31653) build(deps): update @emotion/cache requirement from ^11.4.0 to ^11.14.0 in /superset-frontend/packages/superset-ui-demo (@dependabot[bot])
- [#31664](https://github.com/apache/superset/pull/31664) build(deps): bump markdown-to-jsx from 7.4.7 to 7.7.2 in /superset-frontend (@dependabot[bot])
- [#31665](https://github.com/apache/superset/pull/31665) build(deps): bump html-webpack-plugin from 5.6.0 to 5.6.3 in /superset-frontend (@dependabot[bot])
- [#31666](https://github.com/apache/superset/pull/31666) build(deps-dev): bump @emotion/babel-plugin from 11.12.0 to 11.13.5 in /superset-frontend (@dependabot[bot])
- [#31667](https://github.com/apache/superset/pull/31667) build(deps-dev): bump jsdom from 24.1.1 to 25.0.1 in /superset-frontend (@dependabot[bot])
- [#31685](https://github.com/apache/superset/pull/31685) build(deps): bump jinja2 from 3.1.4 to 3.1.5 in /superset/translations (@dependabot[bot])
- [#31622](https://github.com/apache/superset/pull/31622) chore: replace `imp` built-in module usage for future Python3.12 usage (@hainenber)
- [#31712](https://github.com/apache/superset/pull/31712) chore(fe/sec): resolve High CVE-2024-21538 and Moderate CVE-2024-55565 by bumping `nanoid` and `cross-spawn` (@hainenber)
- [#31627](https://github.com/apache/superset/pull/31627) chore(helm): bump helm on CI to latest version (@villebro)
- [#31701](https://github.com/apache/superset/pull/31701) chore: add helm code owners (@villebro)
- [#31691](https://github.com/apache/superset/pull/31691) docs: add Open edX to users list (@pomegranited)
- [#31693](https://github.com/apache/superset/pull/31693) refactor(space): Migrate Space to Ant Design 5 (@msyavuz)
- [#31530](https://github.com/apache/superset/pull/31530) chore(deps-dev): bump eslint from 9.14.0 to 9.17.0 in /superset-websocket (@dependabot[bot])
- [#31670](https://github.com/apache/superset/pull/31670) build(deps): update echarts requirement from ^5.4.1 to ^5.6.0 in /superset-frontend/plugins/plugin-chart-echarts (@dependabot[bot])
- [#31652](https://github.com/apache/superset/pull/31652) build(deps): update chalk requirement from ^5.4.0 to ^5.4.1 in /superset-frontend/packages/generator-superset (@dependabot[bot])
- [#31655](https://github.com/apache/superset/pull/31655) build(deps): bump core-js from 3.38.1 to 3.39.0 in /superset-frontend/packages/superset-ui-demo (@dependabot[bot])
- [#31656](https://github.com/apache/superset/pull/31656) build(deps): bump antd from 5.22.5 to 5.22.7 in /docs (@dependabot[bot])
- [#31657](https://github.com/apache/superset/pull/31657) build(deps-dev): update @babel/core requirement from ^7.23.9 to ^7.26.0 in /superset-frontend/packages/superset-ui-demo (@dependabot[bot])
- [#31658](https://github.com/apache/superset/pull/31658) build(deps): update @emotion/react requirement from ^11.13.3 to ^11.14.0 in /superset-frontend/packages/superset-ui-demo (@dependabot[bot])
- [#31662](https://github.com/apache/superset/pull/31662) build(deps-dev): bump @types/node from 22.7.4 to 22.10.3 in /superset-websocket (@dependabot[bot])
- [#31663](https://github.com/apache/superset/pull/31663) build(deps-dev): bump typescript-eslint from 8.12.2 to 8.19.0 in /superset-websocket (@dependabot[bot])
- [#31672](https://github.com/apache/superset/pull/31672) build(deps-dev): update @types/node requirement from ^22.5.4 to ^22.10.3 in /superset-frontend/packages/superset-ui-core (@dependabot[bot])
- [#31633](https://github.com/apache/superset/pull/31633) refactor(empty): Migrate Empty component to Ant Design 5 (@msyavuz)
- [#31607](https://github.com/apache/superset/pull/31607) refactor(Divider): Migrate Divider to Ant Design 5 (@msyavuz)
- [#31310](https://github.com/apache/superset/pull/31310) refactor(moment): Replace Moment.js with DayJs (@msyavuz)
- [#30778](https://github.com/apache/superset/pull/30778) build(deps-dev): update @types/jest requirement from ^29.5.12 to ^29.5.14 in /superset-frontend/plugins/plugin-chart-handlebars (@dependabot[bot])
- [#31526](https://github.com/apache/superset/pull/31526) chore(deps): bump hot-shots from 10.0.0 to 10.2.1 in /superset-websocket (@dependabot[bot])
- [#31538](https://github.com/apache/superset/pull/31538) chore(deps-dev): update @babel/preset-react requirement from ^7.23.3 to ^7.26.3 in /superset-frontend/packages/superset-ui-demo (@dependabot[bot])
- [#31217](https://github.com/apache/superset/pull/31217) chore(deps-dev): bump eslint-plugin-jest-dom from 3.6.5 to 5.5.0 in /superset-frontend (@dependabot[bot])
- [#31541](https://github.com/apache/superset/pull/31541) chore(deps): bump antd from 5.22.2 to 5.22.5 in /docs (@dependabot[bot])
- [#31536](https://github.com/apache/superset/pull/31536) chore(deps): bump prism-react-renderer from 2.4.0 to 2.4.1 in /docs (@dependabot[bot])
- [#30322](https://github.com/apache/superset/pull/30322) build(deps): bump find-my-way and @applitools/eyes-cypress in /superset-frontend/cypress-base (@dependabot[bot])
- [#30789](https://github.com/apache/superset/pull/30789) build(deps-dev): update @types/lodash requirement from ^4.17.7 to ^4.17.13 in /superset-frontend/packages/superset-ui-core (@dependabot[bot])
- [#31523](https://github.com/apache/superset/pull/31523) chore(deps-dev): bump @types/lodash from 4.17.7 to 4.17.13 in /superset-websocket (@dependabot[bot])
- [#31546](https://github.com/apache/superset/pull/31546) chore(deps-dev): bump @types/rison from 0.0.9 to 0.1.0 in /superset-frontend (@dependabot[bot])
- [#31557](https://github.com/apache/superset/pull/31557) chore(deps): bump react-reverse-portal from 2.1.1 to 2.1.2 in /superset-frontend (@dependabot[bot])
- [#31577](https://github.com/apache/superset/pull/31577) docs: add Virtuoso QA to users list (@shubham-rohatgi)
- [#31520](https://github.com/apache/superset/pull/31520) chore(deps): bump debug from 4.3.7 to 4.4.0 in /superset-websocket/utils/client-ws-app (@dependabot[bot])
- [#30474](https://github.com/apache/superset/pull/30474) build(deps-dev): bump thread-loader from 4.0.2 to 4.0.4 in /superset-frontend (@dependabot[bot])
- [#30085](https://github.com/apache/superset/pull/30085) build(deps): bump gh-pages from 5.0.0 to 6.1.1 in /superset-frontend/packages/superset-ui-demo (@dependabot[bot])
- [#31558](https://github.com/apache/superset/pull/31558) chore(deps-dev): bump eslint-import-resolver-typescript from 3.6.3 to 3.7.0 in /superset-frontend (@dependabot[bot])
- [#31521](https://github.com/apache/superset/pull/31521) chore(deps-dev): bump prettier from 3.3.3 to 3.4.2 in /superset-websocket (@dependabot[bot])
- [#30785](https://github.com/apache/superset/pull/30785) build(deps-dev): update @types/underscore requirement from ^1.11.15 to ^1.13.0 in /superset-frontend/plugins/legacy-preset-chart-deckgl (@dependabot[bot])
- [#30779](https://github.com/apache/superset/pull/30779) build(deps-dev): update @types/lodash requirement from ^4.17.7 to ^4.17.13 in /superset-frontend/plugins/plugin-chart-handlebars (@dependabot[bot])
- [#31539](https://github.com/apache/superset/pull/31539) chore(deps-dev): bump webpack from 5.96.1 to 5.97.1 in /docs (@dependabot[bot])
- [#31540](https://github.com/apache/superset/pull/31540) chore(deps): bump @algolia/client-search from 5.15.0 to 5.18.0 in /docs (@dependabot[bot])
- [#27809](https://github.com/apache/superset/pull/27809) build(deps): bump @math.gl/web-mercator from 3.6.3 to 4.0.1 in /superset-frontend/plugins/legacy-preset-chart-deckgl (@dependabot[bot])
- [#31529](https://github.com/apache/superset/pull/31529) chore(deps): update @deck.gl/aggregation-layers requirement from ^9.0.37 to ^9.0.38 in /superset-frontend/plugins/legacy-preset-chart-deckgl (@dependabot[bot])
- [#31572](https://github.com/apache/superset/pull/31572) chore(deps): bump gh-pages from 5.0.0 to 6.2.0 in /superset-frontend/packages/superset-ui-demo (@dependabot[bot])
- [#30458](https://github.com/apache/superset/pull/30458) build(deps): bump @types/d3-format from 1.4.5 to 3.0.4 in /superset-frontend/packages/superset-ui-core (@dependabot[bot])
- [#31542](https://github.com/apache/superset/pull/31542) chore(deps): bump @docsearch/react from 3.6.3 to 3.8.2 in /docs (@dependabot[bot])
- [#31225](https://github.com/apache/superset/pull/31225) chore(deps-dev): bump typescript from 4.9.5 to 5.7.2 in /superset-frontend/packages/superset-ui-demo (@dependabot[bot])
- [#31388](https://github.com/apache/superset/pull/31388) chore(deps): update dompurify requirement from ^3.1.3 to ^3.2.3 in /superset-frontend/plugins/legacy-preset-chart-nvd3 (@dependabot[bot])
- [#31543](https://github.com/apache/superset/pull/31543) chore(deps): bump @storybook/types from 8.1.11 to 8.4.7 in /superset-frontend/packages/superset-ui-demo (@dependabot[bot])
- [#31533](https://github.com/apache/superset/pull/31533) chore(deps): update chalk requirement from ^5.3.0 to ^5.4.0 in /superset-frontend/packages/generator-superset (@dependabot[bot])
- [#31532](https://github.com/apache/superset/pull/31532) chore(deps-dev): update @types/d3-time requirement from ^3.0.3 to ^3.0.4 in /superset-frontend/packages/superset-ui-core (@dependabot[bot])
- [#31531](https://github.com/apache/superset/pull/31531) chore(deps): update yeoman-generator requirement from ^7.3.2 to ^7.4.0 in /superset-frontend/packages/generator-superset (@dependabot[bot])
- [#31525](https://github.com/apache/superset/pull/31525) chore(deps): update @deck.gl/layers requirement from ^9.0.37 to ^9.0.38 in /superset-frontend/plugins/legacy-preset-chart-deckgl (@dependabot[bot])
- [#31524](https://github.com/apache/superset/pull/31524) chore(deps-dev): update @babel/types requirement from ^7.25.6 to ^7.26.3 in /superset-frontend/plugins/plugin-chart-pivot-table (@dependabot[bot])
- [#31389](https://github.com/apache/superset/pull/31389) chore(deps): update @emotion/styled requirement from ^11.3.0 to ^11.14.0 in /superset-frontend/packages/superset-ui-demo (@dependabot[bot])
- [#31519](https://github.com/apache/superset/pull/31519) chore: remove dependency on func_timeout because LGPL (@mistercrunch)
- [#31517](https://github.com/apache/superset/pull/31517) chore: update browser list (@mistercrunch)
- [#31420](https://github.com/apache/superset/pull/31420) refactor(Modal): Upgrade Modal component to Antd5 (@alexandrusoare)
- [#31511](https://github.com/apache/superset/pull/31511) chore: rename `apply_post_process` (@betodealmeida)
- [#31390](https://github.com/apache/superset/pull/31390) chore(gha): bump ubuntu to latest fresh release (@mistercrunch)
- [#31313](https://github.com/apache/superset/pull/31313) chore: deprecate pip-compile-multi in favor or uv (@mistercrunch)
- [#31515](https://github.com/apache/superset/pull/31515) chore: deprecate fossa in favor of liccheck to validate python licenses (@mistercrunch)
- [#31501](https://github.com/apache/superset/pull/31501) chore(code owners): Update CODEOWNERS file to remove a couple inactive contributors (@rusackas)
- [#31496](https://github.com/apache/superset/pull/31496) docs: Update new user for Careem to user's list (@samraHanif0340)
- [#31451](https://github.com/apache/superset/pull/31451) chore: remove numba and llvmlite deps as they are large and we don't use them (@mistercrunch)
- [#30605](https://github.com/apache/superset/pull/30605) chore(translations): German translation update (@gerbermichi)
- [#31262](https://github.com/apache/superset/pull/31262) chore: deprecate `pylint` in favor of `ruff` (@mistercrunch)
- [#31422](https://github.com/apache/superset/pull/31422) docs: CVEs fixed on 4.1.0 v2 (@dpgaspar)
- [#31268](https://github.com/apache/superset/pull/31268) refactor: Migrate AdhocFilterEditPopoverSqlTabContent to TypeScript (@EnxDev)
- [#30196](https://github.com/apache/superset/pull/30196) build(packages): npm build/publish improvements. Making packages publishable again. (@rusackas)
- [#31378](https://github.com/apache/superset/pull/31378) chore(deps): bump nanoid from 3.3.7 to 3.3.8 in /docs (@dependabot[bot])
- [#31381](https://github.com/apache/superset/pull/31381) chore(embedded sdk): bump sdk version number (@rusackas)
- [#31380](https://github.com/apache/superset/pull/31380) chore(embedded sdk): bumping dependencies (@rusackas)
- [#31362](https://github.com/apache/superset/pull/31362) chore(deps): bump nanoid from 5.0.7 to 5.0.9 in /superset-frontend/cypress-base (@dependabot[bot])
- [#31209](https://github.com/apache/superset/pull/31209) chore(deps): bump antd from 5.21.6 to 5.22.2 in /docs (@dependabot[bot])
- [#31219](https://github.com/apache/superset/pull/31219) chore(deps-dev): bump esbuild from 0.20.0 to 0.24.0 in /superset-frontend (@dependabot[bot])
- [#31314](https://github.com/apache/superset/pull/31314) chore(deps): bump path-to-regexp and express in /superset-websocket/utils/client-ws-app (@dependabot[bot])
- [#31220](https://github.com/apache/superset/pull/31220) chore(deps): bump winston from 3.15.0 to 3.17.0 in /superset-websocket (@dependabot[bot])
- [#31218](https://github.com/apache/superset/pull/31218) chore(deps-dev): bump @babel/eslint-parser from 7.23.10 to 7.25.9 in /superset-frontend (@dependabot[bot])
- [#31222](https://github.com/apache/superset/pull/31222) chore(deps-dev): bump @eslint/js from 9.14.0 to 9.16.0 in /superset-websocket (@dependabot[bot])
- [#31352](https://github.com/apache/superset/pull/31352) docs: CVEs fixed on 4.1.0 (@dpgaspar)
- [#31168](https://github.com/apache/superset/pull/31168) refactor(Alert): Migrate Alert component to Ant Design V5 (@LevisNgigi)
- [#31290](https://github.com/apache/superset/pull/31290) chore(FilterBar): move the "Add/edit filters" button in the FilterBar to the settings menu (@alexandrusoare)
- [#31312](https://github.com/apache/superset/pull/31312) refactor(Name_column): Make 'Name' column of Saved Query page into links (@LevisNgigi)
- [#31203](https://github.com/apache/superset/pull/31203) chore(deps): bump deck.gl from 9.0.34 to 9.0.36 in /superset-frontend/plugins/legacy-preset-chart-deckgl (@dependabot[bot])
- [#31275](https://github.com/apache/superset/pull/31275) chore: relax greenlet requirements (@sadpandajoe)
- [#31205](https://github.com/apache/superset/pull/31205) chore(deps-dev): bump typescript from 5.6.3 to 5.7.2 in /docs (@dependabot[bot])
- [#31207](https://github.com/apache/superset/pull/31207) chore(deps): bump @algolia/client-search from 5.12.0 to 5.15.0 in /docs (@dependabot[bot])
- [#31208](https://github.com/apache/superset/pull/31208) chore(deps): bump less from 4.2.0 to 4.2.1 in /docs (@dependabot[bot])
- [#31204](https://github.com/apache/superset/pull/31204) chore(deps-dev): bump @docusaurus/tsconfig from 3.5.2 to 3.6.3 in /docs (@dependabot[bot])
- [#31206](https://github.com/apache/superset/pull/31206) chore(deps): bump swagger-ui-react from 5.17.14 to 5.18.2 in /docs (@dependabot[bot])
- [#31224](https://github.com/apache/superset/pull/31224) chore(deps-dev): bump @types/jest from 29.5.12 to 29.5.14 in /superset-websocket (@dependabot[bot])
- [#31228](https://github.com/apache/superset/pull/31228) chore(deps): bump @types/react-table from 7.7.19 to 7.7.20 in /superset-frontend (@dependabot[bot])
- [#31210](https://github.com/apache/superset/pull/31210) chore(deps-dev): bump @docusaurus/module-type-aliases from 3.5.2 to 3.6.3 in /docs (@dependabot[bot])
- [#31213](https://github.com/apache/superset/pull/31213) chore(deps): bump @ant-design/icons from 5.5.1 to 5.5.2 in /docs (@dependabot[bot])
- [#31230](https://github.com/apache/superset/pull/31230) chore(deps): bump @scarf/scarf from 1.3.0 to 1.4.0 in /superset-frontend (@dependabot[bot])
- [#31259](https://github.com/apache/superset/pull/31259) chore(bug report template): bump Superset versions to reflect 4.1.1 release (@sfirke)
- [#31231](https://github.com/apache/superset/pull/31231) chore(deps): bump re-resizable from 6.10.0 to 6.10.1 in /superset-frontend (@dependabot[bot])
- [#31270](https://github.com/apache/superset/pull/31270) refactor: Split SliceHeaderControls into smaller files (@kgabryje)
- [#30864](https://github.com/apache/superset/pull/30864) docs: adapt docs to suggest 'docker compose up --build' (@mistercrunch)
- [#31034](https://github.com/apache/superset/pull/31034) chore: simplify Dockerfile package install calls with bash wrappers (@mistercrunch)
- [#31214](https://github.com/apache/superset/pull/31214) chore(deps): bump codecov/codecov-action from 4 to 5 (@dependabot[bot])
- [#31250](https://github.com/apache/superset/pull/31250) chore(🦾): bump python flask-migrate subpackage(s) (@github-actions[bot])
- [#31249](https://github.com/apache/superset/pull/31249) chore(🦾): bump python nh3 0.2.18 -> 0.2.19 (@github-actions[bot])
- [#31253](https://github.com/apache/superset/pull/31253) chore(🦾): bump python pyjwt 2.10.0 -> 2.10.1 (@github-actions[bot])
- [#31254](https://github.com/apache/superset/pull/31254) chore: pin greenlet in base dependencies (@mistercrunch)
- [#31186](https://github.com/apache/superset/pull/31186) docs(contributing): how to nuke the docker-compose postgres (@mistercrunch)
- [#31244](https://github.com/apache/superset/pull/31244) perf: Optimize DashboardPage and SyncDashboardState (@kgabryje)
- [#31243](https://github.com/apache/superset/pull/31243) perf: Optimize native filters and cross filters (@kgabryje)
- [#31240](https://github.com/apache/superset/pull/31240) perf: Optimize dashboard grid components (@kgabryje)
- [#31242](https://github.com/apache/superset/pull/31242) perf: Optimize Dashboard components (@kgabryje)
- [#31241](https://github.com/apache/superset/pull/31241) perf: Optimize dashboard chart-related components (@kgabryje)
- [#31182](https://github.com/apache/superset/pull/31182) chore(Tooltip): Upgrade Tooltip to Ant Design 5 (@alexandrusoare)
- [#31193](https://github.com/apache/superset/pull/31193) refactor: Creates the VizType enum (@michael-s-molina)
- [#31165](https://github.com/apache/superset/pull/31165) docs: update slack alert instructions to work with V2 slack API (@PJDuszynski)
- [#28461](https://github.com/apache/superset/pull/28461) chore(🦾): bump python sqlglot 23.6.3 -> 23.15.8 (@github-actions[bot])
- [#31171](https://github.com/apache/superset/pull/31171) chore(🦾): bump python pyparsing 3.1.2 -> 3.2.0 (@github-actions[bot])
- [#31170](https://github.com/apache/superset/pull/31170) chore(deps): cap async_timeout<5.0.0 (@mistercrunch)
- [#31032](https://github.com/apache/superset/pull/31032) refactor: remove more sqlparse (@betodealmeida)
- [#31126](https://github.com/apache/superset/pull/31126) chore(🦾): bump python importlib-metadata 7.1.0 -> 8.5.0 (@github-actions[bot])
- [#29382](https://github.com/apache/superset/pull/29382) chore: deprecate tox in favor of act (@mistercrunch)
- [#31109](https://github.com/apache/superset/pull/31109) chore(🦾): bump python billiard 4.2.0 -> 4.2.1 (@github-actions[bot])
- [#31138](https://github.com/apache/superset/pull/31138) chore(🦾): bump python flask-limiter 3.7.0 -> 3.8.0 (@github-actions[bot])
- [#31140](https://github.com/apache/superset/pull/31140) chore(🦾): bump python mako 1.3.5 -> 1.3.6 (@github-actions[bot])
- [#31127](https://github.com/apache/superset/pull/31127) chore(🦾): bump python celery subpackage(s) (@github-actions[bot])
- [#31128](https://github.com/apache/superset/pull/31128) chore(🦾): bump python humanize 4.9.0 -> 4.11.0 (@github-actions[bot])
- [#31129](https://github.com/apache/superset/pull/31129) chore(🦾): bump python simplejson 3.19.2 -> 3.19.3 (@github-actions[bot])
- [#31130](https://github.com/apache/superset/pull/31130) chore(🦾): bump python numexpr 2.10.1 -> 2.10.2 (@github-actions[bot])
- [#31132](https://github.com/apache/superset/pull/31132) chore(🦾): bump python slack-sdk 3.27.2 -> 3.33.4 (@github-actions[bot])
- [#31133](https://github.com/apache/superset/pull/31133) chore(🦾): bump python pyopenssl 24.1.0 -> 24.2.1 (@github-actions[bot])
- [#31135](https://github.com/apache/superset/pull/31135) chore(🦾): bump python dnspython 2.6.1 -> 2.7.0 (@github-actions[bot])
- [#31136](https://github.com/apache/superset/pull/31136) chore(🦾): bump python zstandard 0.22.0 -> 0.23.0 (@github-actions[bot])
- [#31137](https://github.com/apache/superset/pull/31137) chore(🦾): bump python limits 3.12.0 -> 3.13.0 (@github-actions[bot])
- [#31139](https://github.com/apache/superset/pull/31139) chore(🦾): bump python flask-jwt-extended 4.6.0 -> 4.7.1 (@github-actions[bot])
- [#31125](https://github.com/apache/superset/pull/31125) chore(🦾): bump python gunicorn 22.0.0 -> 23.0.0 (@github-actions[bot])
- [#31124](https://github.com/apache/superset/pull/31124) chore(🦾): bump python zipp 3.19.0 -> 3.21.0 (@github-actions[bot])
- [#31123](https://github.com/apache/superset/pull/31123) chore(🦾): bump python flask-compress 1.15 -> 1.17 (@github-actions[bot])
- [#31108](https://github.com/apache/superset/pull/31108) chore(🦾): bump python dill 0.3.8 -> 0.3.9 (@github-actions[bot])
- [#31116](https://github.com/apache/superset/pull/31116) chore(🦾): bump python email-validator 2.1.1 -> 2.2.0 (@github-actions[bot])
- [#31153](https://github.com/apache/superset/pull/31153) chore(asf): add `gh-pages` to protected branches (@rusackas)
- [#31122](https://github.com/apache/superset/pull/31122) chore(🦾): bump python async-timeout 4.0.3 -> 5.0.1 (@github-actions[bot])
- [#31121](https://github.com/apache/superset/pull/31121) chore(🦾): bump python prompt-toolkit 3.0.44 -> 3.0.48 (@github-actions[bot])
- [#31119](https://github.com/apache/superset/pull/31119) chore(🦾): bump python sqlparse 0.5.0 -> 0.5.2 (@github-actions[bot])
- [#30963](https://github.com/apache/superset/pull/30963) refactor(List): Upgrade List from antdesign4 to antdesign5 (@alexandrusoare)
- [#31113](https://github.com/apache/superset/pull/31113) chore(🦾): bump python mysqlclient 2.2.4 -> 2.2.6 (@github-actions[bot])
- [#31114](https://github.com/apache/superset/pull/31114) chore(🦾): bump python grpcio-status subpackage(s) (@github-actions[bot])
- [#31112](https://github.com/apache/superset/pull/31112) chore(🦾): bump python cycler 0.11.0 -> 0.12.1 (@github-actions[bot])
- [#31091](https://github.com/apache/superset/pull/31091) chore(🦾): bump python croniter 2.0.5 -> 5.0.1 (@github-actions[bot])
- [#31107](https://github.com/apache/superset/pull/31107) chore(🦾): bump python google-auth 2.29.0 -> 2.36.0 (@github-actions[bot])
- [#31106](https://github.com/apache/superset/pull/31106) chore(🦾): bump python psutil 6.0.0 -> 6.1.0 (@github-actions[bot])
- [#31105](https://github.com/apache/superset/pull/31105) chore(🦾): bump python dnspython 2.6.1 -> 2.7.0 (@github-actions[bot])
- [#31102](https://github.com/apache/superset/pull/31102) chore(🦾): bump python markdown 3.6 -> 3.7 (@github-actions[bot])
- [#31101](https://github.com/apache/superset/pull/31101) chore(🦾): bump python pluggy 1.4.0 -> 1.5.0 (@github-actions[bot])
- [#31100](https://github.com/apache/superset/pull/31100) chore(🦾): bump python sqloxide 0.1.43 -> 0.1.51 (@github-actions[bot])
- [#31099](https://github.com/apache/superset/pull/31099) chore(🦾): bump python wheel 0.43.0 -> 0.45.1 (@github-actions[bot])
- [#31098](https://github.com/apache/superset/pull/31098) chore(🦾): bump python pyproject-api 1.6.1 -> 1.8.0 (@github-actions[bot])
- [#31096](https://github.com/apache/superset/pull/31096) chore(🦾): bump python pytest-cov 5.0.0 -> 6.0.0 (@github-actions[bot])
- [#31094](https://github.com/apache/superset/pull/31094) chore(🦾): bump python chardet 5.1.0 -> 5.2.0 (@github-actions[bot])
- [#31093](https://github.com/apache/superset/pull/31093) chore(🦾): bump python jsonpath-ng 1.6.1 -> 1.7.0 (@github-actions[bot])
- [#31092](https://github.com/apache/superset/pull/31092) chore(🦾): bump python sshtunnel subpackage(s) (@github-actions[bot])
- [#31097](https://github.com/apache/superset/pull/31097) chore(🦾): bump python mako 1.3.5 -> 1.3.6 (@github-actions[bot])
- [#31090](https://github.com/apache/superset/pull/31090) chore(🦾): bump python tomlkit 0.12.5 -> 0.13.2 (@github-actions[bot])
- [#31087](https://github.com/apache/superset/pull/31087) chore(🦾): bump python isodate 0.6.1 -> 0.7.2 (@github-actions[bot])
- [#31082](https://github.com/apache/superset/pull/31082) chore(🦾): bump python db-dtypes 1.2.0 -> 1.3.1 (@github-actions[bot])
- [#31081](https://github.com/apache/superset/pull/31081) chore(🦾): bump python trino 0.328.0 -> 0.330.0 (@github-actions[bot])
- [#31089](https://github.com/apache/superset/pull/31089) chore(🦾): bump python certifi 2024.2.2 -> 2024.8.30 (@github-actions[bot])
- [#31088](https://github.com/apache/superset/pull/31088) chore(🦾): bump python pydata-google-auth 1.7.0 -> 1.9.0 (@github-actions[bot])
- [#31086](https://github.com/apache/superset/pull/31086) chore(🦾): bump python pyproject-hooks 1.0.0 -> 1.2.0 (@github-actions[bot])
- [#31085](https://github.com/apache/superset/pull/31085) chore(🦾): bump python sqlalchemy-bigquery 1.11.0 -> 1.12.0 (@github-actions[bot])
- [#31084](https://github.com/apache/superset/pull/31084) chore(🦾): bump python kiwisolver 1.4.5 -> 1.4.7 (@github-actions[bot])
- [#31083](https://github.com/apache/superset/pull/31083) chore(🦾): bump python coverage subpackage(s) (@github-actions[bot])
- [#31077](https://github.com/apache/superset/pull/31077) chore(🦾): bump python cfgv 3.3.1 -> 3.4.0 (@github-actions[bot])
- [#31075](https://github.com/apache/superset/pull/31075) chore(🦾): bump python fonttools 4.51.0 -> 4.55.0 (@github-actions[bot])
- [#31076](https://github.com/apache/superset/pull/31076) chore(🦾): bump python pyasn1-modules 0.4.0 -> 0.4.1 (@github-actions[bot])
- [#31079](https://github.com/apache/superset/pull/31079) chore(🦾): bump python pyhive subpackage(s) (@github-actions[bot])
- [#31078](https://github.com/apache/superset/pull/31078) chore(🦾): bump python google-cloud-core 2.3.2 -> 2.4.1 (@github-actions[bot])
- [#31048](https://github.com/apache/superset/pull/31048) chore(🦾): bump python sqlalchemy-utils subpackage(s) (@github-actions[bot])
- [#31073](https://github.com/apache/superset/pull/31073) chore(🦾): bump python amqp 5.2.0 -> 5.3.1 (@github-actions[bot])
- [#31071](https://github.com/apache/superset/pull/31071) chore(🦾): bump python cachetools 5.3.3 -> 5.5.0 (@github-actions[bot])
- [#31074](https://github.com/apache/superset/pull/31074) chore(🦾): bump python kombu 5.3.7 -> 5.4.2 (@github-actions[bot])
- [#31066](https://github.com/apache/superset/pull/31066) chore(🦾): bump python pyyaml 6.0.1 -> 6.0.2 (@github-actions[bot])
- [#31068](https://github.com/apache/superset/pull/31068) chore(🦾): bump python tqdm 4.66.4 -> 4.67.1 (@github-actions[bot])
- [#31069](https://github.com/apache/superset/pull/31069) chore(🦾): bump python proto-plus 1.22.2 -> 1.25.0 (@github-actions[bot])
- [#31067](https://github.com/apache/superset/pull/31067) chore(🦾): bump python importlib-resources 6.4.0 -> 6.4.5 (@github-actions[bot])
- [#31062](https://github.com/apache/superset/pull/31062) chore(🦾): bump python apispec subpackage(s) (@github-actions[bot])
- [#31056](https://github.com/apache/superset/pull/31056) chore(🦾): bump python deprecated 1.2.14 -> 1.2.15 (@github-actions[bot])
- [#31050](https://github.com/apache/superset/pull/31050) chore(🦾): bump python pre-commit 3.7.1 -> 4.0.1 (@github-actions[bot])
- [#31064](https://github.com/apache/superset/pull/31064) chore(🦾): bump python charset-normalizer 3.3.2 -> 3.4.0 (@github-actions[bot])
- [#31001](https://github.com/apache/superset/pull/31001) chore(🦾): bump python ruff 0.4.5 -> 0.8.0 (@github-actions[bot])
- [#31049](https://github.com/apache/superset/pull/31049) chore(🦾): bump python googleapis-common-protos 1.63.0 -> 1.66.0 (@github-actions[bot])
- [#31046](https://github.com/apache/superset/pull/31046) chore(🦾): bump python cron-descriptor 1.4.3 -> 1.4.5 (@github-actions[bot])
- [#31052](https://github.com/apache/superset/pull/31052) chore(🦾): bump python flask-wtf 1.2.1 -> 1.2.2 (@github-actions[bot])
- [#31044](https://github.com/apache/superset/pull/31044) docs: updated the install process in pypi.mdx (@Rkejji)
- [#31054](https://github.com/apache/superset/pull/31054) chore(🦾): bump python nh3 0.2.17 -> 0.2.18 (@github-actions[bot])
- [#31045](https://github.com/apache/superset/pull/31045) chore(🦾): bump python marshmallow 3.21.2 -> 3.23.1 (@github-actions[bot])
- [#31041](https://github.com/apache/superset/pull/31041) chore(🦾): bump python idna 3.7 -> 3.10 (@github-actions[bot])
- [#31042](https://github.com/apache/superset/pull/31042) chore(🦾): bump python pyjwt 2.8.0 -> 2.10.0 (@github-actions[bot])
- [#31040](https://github.com/apache/superset/pull/31040) chore(🦾): bump python et-xmlfile 1.1.0 -> 2.0.0 & remove pyhive[hive] from requirements/development.in (@github-actions[bot])
- [#30651](https://github.com/apache/superset/pull/30651) chore(legacy-plugin-chart-map-box): replace viewport-mercator-project with @math.gl/web-mercator (@birkskyum)
- [#31004](https://github.com/apache/superset/pull/31004) chore(🦾): bump python pandas subpackage(s) (@github-actions[bot])
- [#31030](https://github.com/apache/superset/pull/31030) chore: Cleanup code related to MetadataBar, fix types (@kgabryje)
- [#31029](https://github.com/apache/superset/pull/31029) chore: Refactor dashboard header to func component (@kgabryje)
- [#30998](https://github.com/apache/superset/pull/30998) chore(🦾): bump python cattrs 23.2.3 -> 24.1.2 (@github-actions[bot])
- [#30867](https://github.com/apache/superset/pull/30867) docs: Update doc about CSV upload (@seiyab)
- [#30972](https://github.com/apache/superset/pull/30972) docs: Embedded sdk (@jpchev)
- [#30981](https://github.com/apache/superset/pull/30981) chore: publish wheels (@dimbleby)
- [#31000](https://github.com/apache/superset/pull/31000) chore(🦾): bump python flask-babel subpackage(s) (@github-actions[bot])
- [#31002](https://github.com/apache/superset/pull/31002) chore(🦾): bump python cffi 1.16.0 -> 1.17.1 (@github-actions[bot])
- [#31006](https://github.com/apache/superset/pull/31006) chore(🦾): bump python numexpr 2.10.0 -> 2.10.1 (@github-actions[bot])
- [#31021](https://github.com/apache/superset/pull/31021) chore: add unit tests for `is_mutating()` (@betodealmeida)
- [#30918](https://github.com/apache/superset/pull/30918) chore(helm): bumping app version to 4.1.1 in helm chart (@lodu)
- [#30948](https://github.com/apache/superset/pull/30948) chore: add performance information to tooltip (@eschutho)
- [#30970](https://github.com/apache/superset/pull/30970) build(deps): bump cross-spawn from 7.0.3 to 7.0.6 in /docs (@dependabot[bot])
- [#30969](https://github.com/apache/superset/pull/30969) build(deps): bump cross-spawn from 7.0.3 to 7.0.6 in /superset-frontend/cypress-base (@dependabot[bot])
- [#30818](https://github.com/apache/superset/pull/30818) chore(Accessibility): Fix accessibility for 'Show x entries' dropdown in tables (@LevisNgigi)
- [#30946](https://github.com/apache/superset/pull/30946) chore(docs): Update list of supported databases to include CrateDB (@amotl)
- [#30915](https://github.com/apache/superset/pull/30915) chore: update change log, UPDATING.md and bug-report.yml for 4.1 release (@sadpandajoe)
- [#29243](https://github.com/apache/superset/pull/29243) chore(deps): Migrate from `crate[sqlalchemy]` to `sqlalchemy-cratedb` (@amotl)
- [#30930](https://github.com/apache/superset/pull/30930) docs: add Free2Move to INTHEWILD.md (@PaoloTerzi)
- [#30925](https://github.com/apache/superset/pull/30925) chore(ci): add tai and michael to helm owners (@villebro)
- [#30730](https://github.com/apache/superset/pull/30730) refactor(input): Migrate Input component to Ant Design 5 (@msyavuz)
- [#30740](https://github.com/apache/superset/pull/30740) refactor(Avatar): Migrate Avatar to Ant Design 5 (@msyavuz)
- [#30806](https://github.com/apache/superset/pull/30806) build(deps): bump remark-gfm from 3.0.1 to 4.0.0 in /superset-frontend (@dependabot[bot])
- [#29545](https://github.com/apache/superset/pull/29545) chore(AntD5): touchup on component imports/exports, theming ListViewCard (@rusackas)
- [#30775](https://github.com/apache/superset/pull/30775) chore: update help text copy on dataset settings (@yousoph)
- [#30792](https://github.com/apache/superset/pull/30792) build(deps): bump @algolia/client-search from 4.24.0 to 5.12.0 in /docs (@dependabot[bot])
- [#30770](https://github.com/apache/superset/pull/30770) docs: make it more clear that GLOBAL_ASYNC_QUERIES is experimental/beta (@mistercrunch)
- [#30883](https://github.com/apache/superset/pull/30883) perf: Prevent redundant calls to getRelevantDataMask (@kgabryje)
- [#30847](https://github.com/apache/superset/pull/30847) chore(GHA): Making the Linkinator STEP non-blocking, rather than the JOB. (@rusackas)
- [#30812](https://github.com/apache/superset/pull/30812) chore(FilterBar): Filter bar accessibility (@alexandrusoare)
- [#30854](https://github.com/apache/superset/pull/30854) chore: Chart context menu permissions cleanup (@kgabryje)
- [#30255](https://github.com/apache/superset/pull/30255) chore(scripts): purge node_modules folder on `npm prune` (@rusackas)
- [#30846](https://github.com/apache/superset/pull/30846) chore(actions): Bump Linkinator in superset-docs-verify.yml (@rusackas)
- [#30797](https://github.com/apache/superset/pull/30797) build(deps): bump @docsearch/react from 3.6.2 to 3.6.3 in /docs (@dependabot[bot])
- [#30796](https://github.com/apache/superset/pull/30796) build(deps): bump @mdx-js/react from 3.0.1 to 3.1.0 in /docs (@dependabot[bot])
- [#30793](https://github.com/apache/superset/pull/30793) build(deps-dev): bump @types/react from 18.3.10 to 18.3.12 in /docs (@dependabot[bot])
- [#30795](https://github.com/apache/superset/pull/30795) build(deps-dev): bump typescript from 5.6.2 to 5.6.3 in /docs (@dependabot[bot])
- [#30799](https://github.com/apache/superset/pull/30799) build(deps): bump @saucelabs/theme-github-codeblock from 0.2.3 to 0.3.0 in /docs (@dependabot[bot])
- [#30824](https://github.com/apache/superset/pull/30824) docs: Update INTHEWILD.md with 2070Health Org (@sanjaynayak007)
- [#30838](https://github.com/apache/superset/pull/30838) chore: Revert "build(deps): bump JustinBeckwith/linkinator-action from 1.10.4 to 1.11.0" (@rusackas)
- [#30832](https://github.com/apache/superset/pull/30832) build(deps-dev): bump webpack from 5.95.0 to 5.96.1 in /docs (@dependabot[bot])
- [#30822](https://github.com/apache/superset/pull/30822) docs: Update INTHEWILD.md (@Habeeb556)
- [#30835](https://github.com/apache/superset/pull/30835) build(deps-dev): bump eslint from 9.11.0 to 9.14.0 in /superset-websocket (@dependabot[bot])
- [#30782](https://github.com/apache/superset/pull/30782) build(deps): bump uuid from 10.0.0 to 11.0.2 in /superset-websocket (@dependabot[bot])
- [#30784](https://github.com/apache/superset/pull/30784) build(deps): bump winston from 3.13.0 to 3.15.0 in /superset-websocket (@dependabot[bot])
- [#30786](https://github.com/apache/superset/pull/30786) build(deps): bump deck.gl from 9.0.28 to 9.0.34 in /superset-frontend/plugins/legacy-preset-chart-deckgl (@dependabot[bot])
- [#30803](https://github.com/apache/superset/pull/30803) build(deps-dev): bump eslint-plugin-react from 7.33.2 to 7.37.2 in /superset-frontend (@dependabot[bot])
- [#30781](https://github.com/apache/superset/pull/30781) build(deps-dev): bump typescript-eslint from 8.8.0 to 8.12.2 in /superset-websocket (@dependabot[bot])
- [#30809](https://github.com/apache/superset/pull/30809) build(deps-dev): bump prettier-plugin-packagejson from 2.5.2 to 2.5.3 in /superset-frontend (@dependabot[bot])
- [#30817](https://github.com/apache/superset/pull/30817) build(deps): bump webpack from 5.80.0 to 5.96.1 in /superset-frontend/cypress-base (@dependabot[bot])
- [#30794](https://github.com/apache/superset/pull/30794) build(deps): bump antd from 5.20.5 to 5.21.6 in /docs (@dependabot[bot])
- [#30811](https://github.com/apache/superset/pull/30811) build(deps): bump @rjsf/validator-ajv8 from 5.19.4 to 5.22.3 in /superset-frontend (@dependabot[bot])
- [#30804](https://github.com/apache/superset/pull/30804) build(deps): bump ace-builds from 1.35.4 to 1.36.3 in /superset-frontend (@dependabot[bot])
- [#30810](https://github.com/apache/superset/pull/30810) build(deps-dev): bump eslint-plugin-testing-library from 6.2.2 to 6.4.0 in /superset-frontend (@dependabot[bot])
- [#30805](https://github.com/apache/superset/pull/30805) build(deps-dev): bump eslint-import-resolver-typescript from 3.6.1 to 3.6.3 in /superset-frontend (@dependabot[bot])
- [#30802](https://github.com/apache/superset/pull/30802) build(deps): bump JustinBeckwith/linkinator-action from 1.10.4 to 1.11.0 (@dependabot[bot])
- [#30758](https://github.com/apache/superset/pull/30758) style(databases-upload-form): update Upload Form cosmetics (@vine-trellis)
- [#30697](https://github.com/apache/superset/pull/30697) refactor: Migrate SliceAdder to typescript (@EnxDev)
- [#30731](https://github.com/apache/superset/pull/30731) refactor(Switch): Upgrade Switch to Ant Design 5 (@alexandrusoare)
- [#30757](https://github.com/apache/superset/pull/30757) docs: Adding link to StarRocks official docs (@rusackas)
- [#30747](https://github.com/apache/superset/pull/30747) docs: Update INTHEWILD.md (@MSTartan)
- [#30753](https://github.com/apache/superset/pull/30753) docs: add Sarathi to users list (@SaiSkandaTNI)
- [#30749](https://github.com/apache/superset/pull/30749) docs: Update INTHEWILD.md with Medic (@1yuv)
- [#30355](https://github.com/apache/superset/pull/30355) chore(fe): replace deprecate aliased Jest matchers with corresponding substituents (@hainenber)
- [#30536](https://github.com/apache/superset/pull/30536) build(deps): bump cookie from 0.6.0 to 0.7.0 in /superset-websocket (@dependabot[bot])
- [#30480](https://github.com/apache/superset/pull/30480) build(deps-dev): bump webpack from 5.94.0 to 5.95.0 in /docs (@dependabot[bot])
- [#30571](https://github.com/apache/superset/pull/30571) build(deps): bump cookie, cookie-parser and express in /superset-websocket/utils/client-ws-app (@dependabot[bot])
- [#30738](https://github.com/apache/superset/pull/30738) docs: rename Twitter to X in the INTHEWILD.md (@wugeer)
- [#30743](https://github.com/apache/superset/pull/30743) docs(templating): Replace "true" with "1 = 1" and explain its purpose (@sfirke)
- [#30709](https://github.com/apache/superset/pull/30709) build(deps-dev): bump http-proxy-middleware from 2.0.6 to 2.0.7 in /superset-frontend (@dependabot[bot])
- [#30654](https://github.com/apache/superset/pull/30654) refactor: Migrate UndoRedoKeyListeners to typescript (@EnxDev)
- [#30653](https://github.com/apache/superset/pull/30653) refactor: Migration publishedStatus to typescript (@EnxDev)
- [#30683](https://github.com/apache/superset/pull/30683) build(deps): bump http-proxy-middleware from 2.0.6 to 2.0.7 in /docs (@dependabot[bot])
- [#30568](https://github.com/apache/superset/pull/30568) refactor: Migrate HeaderActionsDropdown to typescript (@EnxDev)
- [#30655](https://github.com/apache/superset/pull/30655) docs: frontend long build time (@CodeWithEmad)
- [#30662](https://github.com/apache/superset/pull/30662) refactor: Split FastVizSwitcher into multiple files for readability (@kgabryje)
- [#30609](https://github.com/apache/superset/pull/30609) refactor(Dashboard): Native filters form update endpoint (@geido)
- [#30613](https://github.com/apache/superset/pull/30613) chore: Enable suppressing default chart context menu (@kgabryje)
- [#30523](https://github.com/apache/superset/pull/30523) docs: Clarification on which command to use on which Ubuntu version. (@kkovacs)
- [#30599](https://github.com/apache/superset/pull/30599) chore(number-formatter): upgrade pretty-ms to 9.1.0 (@villebro)
- [#30572](https://github.com/apache/superset/pull/30572) build(deps): bump cookie, @applitools/eyes-storybook and express in /superset-frontend (@dependabot[bot])
- [#30357](https://github.com/apache/superset/pull/30357) chore(fe): uplift FE packages to latest version (@hainenber)
- [#30521](https://github.com/apache/superset/pull/30521) chore: enable lint PT009 'use regular assert over self.assert.\*' (@mistercrunch)
- [#28370](https://github.com/apache/superset/pull/28370) refactor: Migration of Chart to TypeScript (@EnxDev)
- [#30528](https://github.com/apache/superset/pull/30528) chore(fe): bump webpack-related packages to v5 (@hainenber)
- [#30526](https://github.com/apache/superset/pull/30526) chore(translations): Slovenian translation update (@dkrat7)
- [#30495](https://github.com/apache/superset/pull/30495) chore: add native filters to Covid Vaccines dashboard (@sadpandajoe)
- [#30463](https://github.com/apache/superset/pull/30463) build(deps-dev): bump typescript from 5.5.4 to 5.6.2 in /superset-websocket (@dependabot[bot])
- [#30472](https://github.com/apache/superset/pull/30472) build(deps): bump express from 4.20.0 to 4.21.0 in /superset-websocket/utils/client-ws-app (@dependabot[bot])
- [#30496](https://github.com/apache/superset/pull/30496) docs: fix broken links in CI (@mistercrunch)
- [#30476](https://github.com/apache/superset/pull/30476) build(deps-dev): bump typescript from 5.5.4 to 5.6.2 in /docs (@dependabot[bot])
- [#30461](https://github.com/apache/superset/pull/30461) build(deps): bump @rjsf/core from 5.19.4 to 5.21.1 in /superset-frontend (@dependabot[bot])
- [#30465](https://github.com/apache/superset/pull/30465) build(deps-dev): bump typescript-eslint from 8.6.0 to 8.8.0 in /superset-websocket (@dependabot[bot])
- [#30466](https://github.com/apache/superset/pull/30466) build(deps-dev): bump @types/node from 22.0.2 to 22.7.4 in /superset-websocket (@dependabot[bot])
- [#30467](https://github.com/apache/superset/pull/30467) build(deps): bump @types/prop-types from 15.7.5 to 15.7.13 in /superset-frontend (@dependabot[bot])
- [#30469](https://github.com/apache/superset/pull/30469) build(deps): bump @types/react-loadable from 5.5.6 to 5.5.11 in /superset-frontend (@dependabot[bot])
- [#30471](https://github.com/apache/superset/pull/30471) build(deps): bump debug from 4.3.6 to 4.3.7 in /superset-websocket/utils/client-ws-app (@dependabot[bot])
- [#30281](https://github.com/apache/superset/pull/30281) refactor(frontend): migrate 6 Enzyme-based tests to RTL, part 2 (@hainenber)
- [#30487](https://github.com/apache/superset/pull/30487) build(deps-dev): bump esbuild-loader from 4.1.0 to 4.2.2 in /superset-frontend (@dependabot[bot])
- [#30460](https://github.com/apache/superset/pull/30460) build(deps-dev): bump eslint-plugin-file-progress from 1.4.0 to 1.5.0 in /superset-frontend (@dependabot[bot])
- [#30459](https://github.com/apache/superset/pull/30459) build(deps-dev): bump @cypress/react from 5.12.5 to 8.0.2 in /superset-frontend (@dependabot[bot])
- [#30464](https://github.com/apache/superset/pull/30464) build(deps-dev): bump @typescript-eslint/eslint-plugin from 8.6.0 to 8.8.0 in /superset-websocket (@dependabot[bot])
- [#30477](https://github.com/apache/superset/pull/30477) build(deps): bump re-resizable from 6.9.11 to 6.10.0 in /superset-frontend (@dependabot[bot])
- [#30473](https://github.com/apache/superset/pull/30473) build(deps-dev): bump webpack-manifest-plugin from 4.1.1 to 5.0.0 in /superset-frontend (@dependabot[bot])
- [#30481](https://github.com/apache/superset/pull/30481) build(deps-dev): bump @types/react from 18.3.5 to 18.3.10 in /docs (@dependabot[bot])
- [#30483](https://github.com/apache/superset/pull/30483) build(deps): bump @docsearch/react from 3.6.1 to 3.6.2 in /docs (@dependabot[bot])
- [#30484](https://github.com/apache/superset/pull/30484) build(deps): bump handlebars from 4.7.7 to 4.7.8 in /superset-frontend (@dependabot[bot])
- [#30485](https://github.com/apache/superset/pull/30485) build(deps-dev): bump @types/yargs from 17.0.32 to 17.0.33 in /superset-frontend (@dependabot[bot])
- [#30445](https://github.com/apache/superset/pull/30445) docs(dashboard): add docs for named and index colors (@villebro)
- [#30410](https://github.com/apache/superset/pull/30410) chore: log warnings for database tables api (@eschutho)
- [#28747](https://github.com/apache/superset/pull/28747) chore: document upper bound for python lib 'holidays' >= 0.26 (@mistercrunch)
- [#30440](https://github.com/apache/superset/pull/30440) chore(Dashboard): Unblock Global Styles (@geido)
- [#30365](https://github.com/apache/superset/pull/30365) chore: add logging for dashboards/get warnings (@eschutho)
- [#30128](https://github.com/apache/superset/pull/30128) chore(View): Remove unnecessary theme view and defer basic styles (@geido)
- [#30407](https://github.com/apache/superset/pull/30407) chore: Merge description and reproduction steps in the issue template (@michael-s-molina)
- [#30305](https://github.com/apache/superset/pull/30305) chore(legacy-plugin-chart-map-box): bump supercluster to v8 (@birkskyum)
- [#30086](https://github.com/apache/superset/pull/30086) build(deps): update @emotion/react requirement from ^11.4.1 to ^11.13.3 in /superset-frontend/packages/superset-ui-demo (@dependabot[bot])
- [#27827](https://github.com/apache/superset/pull/27827) build(deps): bump @emotion/react from 11.4.1 to 11.11.4 in /superset-frontend (@dependabot[bot])
- [#28346](https://github.com/apache/superset/pull/28346) refactor: Migration of AnnotationLayerControl to TypeScript (@EnxDev)
- [#30251](https://github.com/apache/superset/pull/30251) build(deps-dev): bump sinon from 18.0.0 to 18.0.1 in /superset-frontend (@dependabot[bot])
- [#30315](https://github.com/apache/superset/pull/30315) docs: Corrected Dremio connection string (@doernemt)
- [#30352](https://github.com/apache/superset/pull/30352) chore(docs): fix an agreement error in caching docs (@sfirke)
- [#30346](https://github.com/apache/superset/pull/30346) docs: add HANA database logo in README.md (@axuew)
- [#28290](https://github.com/apache/superset/pull/28290) build(deps): update dompurify requirement from ^3.1.0 to ^3.1.2 in /superset-frontend/plugins/legacy-preset-chart-nvd3 (@dependabot[bot])
- [#30089](https://github.com/apache/superset/pull/30089) build(deps-dev): bump @storybook/react-webpack5 from 8.1.11 to 8.2.9 in /superset-frontend/packages/superset-ui-demo (@dependabot[bot])
- [#30359](https://github.com/apache/superset/pull/30359) build(websocket): upgrade ESLint to v9 (@hainenber)
- [#30084](https://github.com/apache/superset/pull/30084) build(deps): bump deck.gl from 9.0.24 to 9.0.28 in /superset-frontend/plugins/legacy-preset-chart-deckgl (@dependabot[bot])
- [#30300](https://github.com/apache/superset/pull/30300) build(deps): bump dompurify from 3.1.0 to 3.1.3 in /superset-frontend (@dependabot[bot])
- [#30247](https://github.com/apache/superset/pull/30247) build(deps): bump path-to-regexp from 1.8.0 to 1.9.0 in /superset-frontend/cypress-base (@dependabot[bot])
- [#30337](https://github.com/apache/superset/pull/30337) docs: sql-templating (@torgge)
- [#30333](https://github.com/apache/superset/pull/30333) docs: Update cache.mdx, add needed space (@varfigstar)
- [#30123](https://github.com/apache/superset/pull/30123) chore: correct a typo (@dl57934)
- [#30262](https://github.com/apache/superset/pull/30262) chore: bump cypress to v 11 (@eschutho)
- [#30313](https://github.com/apache/superset/pull/30313) chore(UPDATING.md): Add item to UPDATING describing translations build flag (@martyngigg)
- [#30227](https://github.com/apache/superset/pull/30227) build(deps): bump express from 4.19.2 to 4.20.0 in /docs (@dependabot[bot])
- [#30032](https://github.com/apache/superset/pull/30032) docs: HTML embedding of charts/dashboards without authentication (@lindner-tj)
- [#30254](https://github.com/apache/superset/pull/30254) style(explore): clarify ambiguously named "sort by" field (@sfirke)
- [#30321](https://github.com/apache/superset/pull/30321) chore(explore): Medium font weight for section headers (@kasiazjc)
- [#30261](https://github.com/apache/superset/pull/30261) chore: remove redundant code (@villebro)
- [#25910](https://github.com/apache/superset/pull/25910) chore(deps): bump dremio deps (@gnought)
- [#30268](https://github.com/apache/superset/pull/30268) docs: Update kubernetes.mdx (@nyandajr)
- [#29771](https://github.com/apache/superset/pull/29771) chore(docker): move mysql os-level deps (GPL) to dev image only (@mistercrunch)
- [#30151](https://github.com/apache/superset/pull/30151) refactor(frontend): migrate 6 tests from Enzyme to RTL (@hainenber)
- [#30253](https://github.com/apache/superset/pull/30253) chore(build): remove extraneous prettier step in superset-frontend CI (@hainenber)
- [#30257](https://github.com/apache/superset/pull/30257) build(ci): make linkinator advisory (@rusackas)
- [#30242](https://github.com/apache/superset/pull/30242) build(deps, deps-dev): upgrade major versions for dependencies of `@superset/embedded-sdk` (@hainenber)
- [#30228](https://github.com/apache/superset/pull/30228) build(deps): bump send and express in /superset-frontend (@dependabot[bot])
- [#30229](https://github.com/apache/superset/pull/30229) build(deps): bump serve-static and express in /superset-frontend (@dependabot[bot])
- [#30232](https://github.com/apache/superset/pull/30232) refactor(explore): Migrate MetricsControl test suite to RTL (@rtexelm)
- [#30226](https://github.com/apache/superset/pull/30226) build(deps): bump serve-static and express in /superset-websocket/utils/client-ws-app (@dependabot[bot])
- [#30225](https://github.com/apache/superset/pull/30225) build(deps): bump send and express in /superset-websocket/utils/client-ws-app (@dependabot[bot])
- [#30091](https://github.com/apache/superset/pull/30091) build(deps): update @babel/runtime requirement from ^7.1.2 to ^7.25.6 in /superset-frontend/packages/superset-ui-core (@dependabot[bot])
- [#25452](https://github.com/apache/superset/pull/25452) chore(frontend): Spelling (@jsoref)
- [#30103](https://github.com/apache/superset/pull/30103) build(deps-dev): update @babel/types requirement from ^7.25.2 to ^7.25.6 in /superset-frontend/plugins/plugin-chart-pivot-table (@dependabot[bot])
- [#30199](https://github.com/apache/superset/pull/30199) chore(docs): Removing dead link from INTHEWILD.md (@rusackas)
- [#30101](https://github.com/apache/superset/pull/30101) build(deps-dev): bump @types/react from 18.3.3 to 18.3.5 in /docs (@dependabot[bot])
- [#30036](https://github.com/apache/superset/pull/30036) build(deps-dev): bump webpack from 5.93.0 to 5.94.0 in /docs (@dependabot[bot])
- [#30179](https://github.com/apache/superset/pull/30179) build(deps): bump antd from 5.20.0 to 5.20.5 in /docs (@dependabot[bot])
- [#30166](https://github.com/apache/superset/pull/30166) build(deps): bump @types/node from 20.12.7 to 22.5.4 in /superset-frontend (@dependabot[bot])
- [#30097](https://github.com/apache/superset/pull/30097) build(deps-dev): bump typescript from 4.9.5 to 5.5.4 in /superset-websocket (@dependabot[bot])
- [#30088](https://github.com/apache/superset/pull/30088) build(deps): bump core-js from 3.37.1 to 3.38.1 in /superset-frontend/packages/superset-ui-demo (@dependabot[bot])
- [#29963](https://github.com/apache/superset/pull/29963) build(dev-deps, deps): upgrade major versions for FE deps (@hainenber)
- [#30167](https://github.com/apache/superset/pull/30167) chore(docs): bump docusaurus from 3.4.0 to 3.5.2 (@villebro)
- [#30094](https://github.com/apache/superset/pull/30094) build(deps): bump ws and @types/ws in /superset-websocket (@dependabot[bot])
- [#30105](https://github.com/apache/superset/pull/30105) build(deps-dev): bump @docusaurus/module-type-aliases from 3.4.0 to 3.5.2 in /docs (@dependabot[bot])
- [#30111](https://github.com/apache/superset/pull/30111) build(deps): bump react-ultimate-pagination and @types/react-ultimate-pagination in /superset-frontend (@dependabot[bot])
- [#30106](https://github.com/apache/superset/pull/30106) build(deps): bump prism-react-renderer from 2.3.1 to 2.4.0 in /docs (@dependabot[bot])
- [#30107](https://github.com/apache/superset/pull/30107) build(deps-dev): bump @docusaurus/tsconfig from 3.4.0 to 3.5.2 in /docs (@dependabot[bot])
- [#30108](https://github.com/apache/superset/pull/30108) build(deps): bump react-svg-pan-zoom from 3.12.1 to 3.13.1 in /docs (@dependabot[bot])
- [#30095](https://github.com/apache/superset/pull/30095) build(deps-dev): bump ts-jest from 29.1.5 to 29.2.5 in /superset-websocket (@dependabot[bot])
- [#30096](https://github.com/apache/superset/pull/30096) build(deps): bump uuid and @types/uuid in /superset-websocket (@dependabot[bot])
- [#30143](https://github.com/apache/superset/pull/30143) build(deps): bump cryptography from 42.0.7 to 42.0.8 (@dependabot[bot])
- [#30118](https://github.com/apache/superset/pull/30118) build(deps-dev): bump prettier-plugin-packagejson from 2.4.10 to 2.5.2 in /superset-frontend (@dependabot[bot])
- [#30127](https://github.com/apache/superset/pull/30127) docs: Fixing missing 'c' in installation guide documentation (@JordanTB)
- [#30155](https://github.com/apache/superset/pull/30155) chore(docs): replace http with https (@villebro)
- [#30072](https://github.com/apache/superset/pull/30072) chore(tests): skip extremely flaky gaq test (@villebro)
- [#30153](https://github.com/apache/superset/pull/30153) chore(docs): update xendit link (@villebro)
- [#30021](https://github.com/apache/superset/pull/30021) chore: accelerate docker compose by skipping frontend build (@mistercrunch)
- [#30090](https://github.com/apache/superset/pull/30090) build(deps): bump aws-actions/amazon-ecs-deploy-task-definition from 1 to 2 (@dependabot[bot])
- [#30037](https://github.com/apache/superset/pull/30037) build(deps-dev): bump webpack from 5.76.0 to 5.94.0 in /superset-embedded-sdk (@dependabot[bot])
- [#30038](https://github.com/apache/superset/pull/30038) build(deps-dev): bump webpack from 5.93.0 to 5.94.0 in /superset-frontend (@dependabot[bot])
- [#30102](https://github.com/apache/superset/pull/30102) build(deps-dev): bump eslint-plugin-react-prefer-function-component from 0.0.7 to 3.3.0 in /superset-frontend (@dependabot[bot])
- [#30117](https://github.com/apache/superset/pull/30117) build(deps): bump d3-time-format and @types/d3-time-format in /superset-frontend (@dependabot[bot])
- [#30116](https://github.com/apache/superset/pull/30116) build(deps-dev): bump eslint-plugin-no-only-tests from 2.4.0 to 3.3.0 in /superset-frontend (@dependabot[bot])
- [#30027](https://github.com/apache/superset/pull/30027) refactor(databases): Create constants.ts, move interface to types.ts (@rtexelm)
- [#30030](https://github.com/apache/superset/pull/30030) chore(docs): docker instructions use `docker compose` instead of the deprecated `docker-compose` (@rusackas)
- [#30057](https://github.com/apache/superset/pull/30057) chore(docs): clean up a few md errors (@villebro)
- [#29586](https://github.com/apache/superset/pull/29586) chore(translations): Arabic translations (@abdilra7eem)
- [#30011](https://github.com/apache/superset/pull/30011) chore(deps): bump core-js (@rusackas)
- [#30007](https://github.com/apache/superset/pull/30007) chore(deps): bump cross-env (@rusackas)
- [#30008](https://github.com/apache/superset/pull/30008) build(deps): bump micromatch from 4.0.4 to 4.0.8 in /superset-frontend/cypress-base (@dependabot[bot])
- [#30009](https://github.com/apache/superset/pull/30009) build(deps): bump micromatch from 4.0.5 to 4.0.8 in /docs (@dependabot[bot])
- [#27832](https://github.com/apache/superset/pull/27832) build(deps): bump remark-gfm from 3.0.1 to 4.0.0 in /superset-frontend/packages/superset-ui-core (@dependabot[bot])
- [#28292](https://github.com/apache/superset/pull/28292) build(deps): bump d3-time from 1.1.0 to 3.1.0 in /superset-frontend/packages/superset-ui-core (@dependabot[bot])
- [#29990](https://github.com/apache/superset/pull/29990) chore(init): adding link to secret key instructions (@rusackas)
- [#29947](https://github.com/apache/superset/pull/29947) build(deps): bump ws and @applitools/eyes-cypress in /superset-frontend/cypress-base (@dependabot[bot])
- [#29988](https://github.com/apache/superset/pull/29988) build(node): Bumping to Node 20 (@rusackas)
- [#25454](https://github.com/apache/superset/pull/25454) chore(tests): Spelling (@jsoref)
- [#29970](https://github.com/apache/superset/pull/29970) docs: improve pre-commit docs and discoverability when CI fails (@mistercrunch)
- [#29964](https://github.com/apache/superset/pull/29964) build(deps-dev): bump eslint-plugin-cypress from 2.11.2 to 3.4.0 in /superset-frontend + corresponding refactor (@hainenber)
- [#29969](https://github.com/apache/superset/pull/29969) chore(antd): straightening out button import paths (@rusackas)
- [#29948](https://github.com/apache/superset/pull/29948) chore(deps): bump micromatch (@rusackas)
- [#29952](https://github.com/apache/superset/pull/29952) chore: add additional code owners to migrations (@sadpandajoe)
- [#29945](https://github.com/apache/superset/pull/29945) build(deps): bump axios from 1.6.8 to 1.7.4 in /docs (@dependabot[bot])
- [#29949](https://github.com/apache/superset/pull/29949) build(deps-dev): bump axios from 1.7.3 to 1.7.4 in /superset-frontend (@dependabot[bot])
- [#29946](https://github.com/apache/superset/pull/29946) build(deps-dev): bump axios from 1.6.0 to 1.7.4 in /superset-embedded-sdk (@dependabot[bot])
- [#29904](https://github.com/apache/superset/pull/29904) chore: Changes the migrations owners (@michael-s-molina)
- [#29868](https://github.com/apache/superset/pull/29868) chore: remove useless GitHub action (@mistercrunch)
- [#29869](https://github.com/apache/superset/pull/29869) chore: remove useless GitHub action required check (@mistercrunch)
- [#29859](https://github.com/apache/superset/pull/29859) chore(deps): bumping underscore via npm override (@rusackas)
- [#29876](https://github.com/apache/superset/pull/29876) chore(docs): reorder fs users (@villebro)
- [#29841](https://github.com/apache/superset/pull/29841) chore(deps): bumping jquery (@rusackas)
- [#29870](https://github.com/apache/superset/pull/29870) docs: add unit to companies list (@amitmiran137)
- [#29652](https://github.com/apache/superset/pull/29652) chore(build): uplift several outdated frontend packages (@hainenber)
- [#29866](https://github.com/apache/superset/pull/29866) chore: pre-matrixify pre-commit check (@mistercrunch)
- [#29844](https://github.com/apache/superset/pull/29844) chore(cleanup): Removing bootstrap (experimental) (@rusackas)
- [#29863](https://github.com/apache/superset/pull/29863) chore: describe timezone issue with alerts and reports scheduler in UPDATING.md (@danielli-ziprecruiter)
- [#29855](https://github.com/apache/superset/pull/29855) perf: Lazy load rehype-raw and react-markdown (@kgabryje)
- [#29788](https://github.com/apache/superset/pull/29788) perf: Remove antd-with-locales import (@kgabryje)
- [#29791](https://github.com/apache/superset/pull/29791) perf: Lazy load moment-timezone (@kgabryje)
- [#29808](https://github.com/apache/superset/pull/29808) build(deps-dev): update @babel/types requirement from ^7.24.5 to ^7.25.2 in /superset-frontend/plugins/plugin-chart-pivot-table (@dependabot[bot])
- [#29838](https://github.com/apache/superset/pull/29838) chore(deps): npm audit fix results (@rusackas)
- [#28294](https://github.com/apache/superset/pull/28294) build(deps): bump react-bootstrap-slider from 2.1.5 to 3.0.0 in /superset-frontend/plugins/legacy-preset-chart-deckgl (@dependabot[bot])
- [#29756](https://github.com/apache/superset/pull/29756) build(deps): bump react-diff-viewer-continued from 3.2.5 to 3.4.0 in /superset-frontend (@dependabot[bot])
- [#29759](https://github.com/apache/superset/pull/29759) build(deps-dev): bump eslint-plugin-file-progress from 1.2.0 to 1.4.0 in /superset-frontend (@dependabot[bot])
- [#29812](https://github.com/apache/superset/pull/29812) build(deps): bump @fontsource/inter from 5.0.19 to 5.0.20 in /superset-frontend (@dependabot[bot])
- [#29813](https://github.com/apache/superset/pull/29813) build(deps): bump chrono-node from 2.7.5 to 2.7.6 in /superset-frontend (@dependabot[bot])
- [#29815](https://github.com/apache/superset/pull/29815) build(deps): bump mustache from 2.3.2 to 4.2.0 in /superset-frontend (@dependabot[bot])
- [#29816](https://github.com/apache/superset/pull/29816) build(deps-dev): bump @types/react-syntax-highlighter from 15.5.11 to 15.5.13 in /superset-frontend (@dependabot[bot])
- [#29820](https://github.com/apache/superset/pull/29820) build(deps-dev): bump style-loader from 3.3.4 to 4.0.0 in /superset-frontend (@dependabot[bot])
- [#29821](https://github.com/apache/superset/pull/29821) build(deps): bump memoize-one from 5.1.1 to 5.2.1 in /superset-frontend (@dependabot[bot])
- [#29809](https://github.com/apache/superset/pull/29809) build(deps-dev): bump @types/jest from 27.0.2 to 29.5.12 in /superset-websocket (@dependabot[bot])
- [#29811](https://github.com/apache/superset/pull/29811) build(deps-dev): bump @types/node from 22.0.0 to 22.0.2 in /superset-websocket (@dependabot[bot])
- [#29758](https://github.com/apache/superset/pull/29758) build(deps): bump rimraf from 3.0.2 to 6.0.1 in /superset-frontend (@dependabot[bot])
- [#29787](https://github.com/apache/superset/pull/29787) perf: Antd icons tree shaking (@kgabryje)
- [#29796](https://github.com/apache/superset/pull/29796) perf: Lazy load React Ace (@kgabryje)
- [#29792](https://github.com/apache/superset/pull/29792) chore: deleting vestigial EMAIL_NOTIFICATIONS (@rusackas)
- [#29673](https://github.com/apache/superset/pull/29673) style: remove uppercase from labels, buttons, tabs to align with design system (@mistercrunch)
- [#29755](https://github.com/apache/superset/pull/29755) build(deps): bump @types/lodash from 4.17.0 to 4.17.7 in /superset-frontend (@dependabot[bot])
- [#29765](https://github.com/apache/superset/pull/29765) build(deps-dev): bump webpack from 5.89.0 to 5.93.0 in /superset-frontend (@dependabot[bot])
- [#29794](https://github.com/apache/superset/pull/29794) chore(deps): bump dayjs to unblock CI. (@rusackas)
- [#29790](https://github.com/apache/superset/pull/29790) chore(docs): remove mention of MariaDB in dev environment setup (@sfirke)
- [#29738](https://github.com/apache/superset/pull/29738) build(deps-dev): bump @types/node from 20.13.0 to 22.0.0 in /superset-websocket (@dependabot[bot])
- [#29748](https://github.com/apache/superset/pull/29748) build(deps): bump @ant-design/icons from 5.3.7 to 5.4.0 in /docs (@dependabot[bot])
- [#29747](https://github.com/apache/superset/pull/29747) build(deps-dev): bump webpack from 5.92.1 to 5.93.0 in /docs (@dependabot[bot])
- [#29427](https://github.com/apache/superset/pull/29427) chore(deps): bump abortcontroller-polyfill from 1.2.1 to 1.7.5 in /superset-frontend (@dependabot[bot])
- [#28820](https://github.com/apache/superset/pull/28820) chore(deps): bump d3-hierarchy from 1.1.9 to 3.1.2 in /superset-frontend (@dependabot[bot])
- [#29740](https://github.com/apache/superset/pull/29740) build(deps-dev): update @types/lodash requirement from ^4.17.6 to ^4.17.7 in /superset-frontend/plugins/plugin-chart-handlebars (@dependabot[bot])
- [#29743](https://github.com/apache/superset/pull/29743) build(deps): update underscore requirement from ^1.13.6 to ^1.13.7 in /superset-frontend/plugins/legacy-preset-chart-deckgl (@dependabot[bot])
- [#29763](https://github.com/apache/superset/pull/29763) build(deps-dev): bump history from 4.10.1 to 5.3.0 in /superset-frontend (@dependabot[bot])
- [#29760](https://github.com/apache/superset/pull/29760) build(deps-dev): bump ts-loader from 7.0.5 to 9.5.1 in /superset-frontend (@dependabot[bot])
- [#28297](https://github.com/apache/superset/pull/28297) build(deps-dev): update @babel/types requirement from ^7.24.0 to ^7.24.5 in /superset-frontend/plugins/plugin-chart-pivot-table (@dependabot[bot])
- [#29767](https://github.com/apache/superset/pull/29767) build(deps): bump fast-xml-parser from 4.2.7 to 4.4.1 in /superset-frontend (@dependabot[bot])
- [#29739](https://github.com/apache/superset/pull/29739) build(deps): bump debug from 4.3.5 to 4.3.6 in /superset-websocket/utils/client-ws-app (@dependabot[bot])
- [#29742](https://github.com/apache/superset/pull/29742) build(deps-dev): bump prettier from 3.2.5 to 3.3.3 in /superset-websocket (@dependabot[bot])
- [#29744](https://github.com/apache/superset/pull/29744) build(deps): bump deck.gl from 9.0.21 to 9.0.24 in /superset-frontend/plugins/legacy-preset-chart-deckgl (@dependabot[bot])
- [#29746](https://github.com/apache/superset/pull/29746) build(deps): bump @types/lodash from 4.17.4 to 4.17.7 in /superset-websocket (@dependabot[bot])
- [#29750](https://github.com/apache/superset/pull/29750) build(deps-dev): bump typescript from 5.5.2 to 5.5.4 in /docs (@dependabot[bot])
- [#29751](https://github.com/apache/superset/pull/29751) build(deps): bump @docsearch/react from 3.6.0 to 3.6.1 in /docs (@dependabot[bot])
- [#29753](https://github.com/apache/superset/pull/29753) build(deps-dev): bump mini-css-extract-plugin from 2.7.6 to 2.9.0 in /superset-frontend (@dependabot[bot])
- [#29754](https://github.com/apache/superset/pull/29754) build(deps-dev): bump @svgr/webpack from 8.0.1 to 8.1.0 in /superset-frontend (@dependabot[bot])
- [#29762](https://github.com/apache/superset/pull/29762) build(deps): bump ace-builds from 1.4.14 to 1.35.4 in /superset-frontend (@dependabot[bot])
- [#29731](https://github.com/apache/superset/pull/29731) chore(build): pin Storybook-related packages to 8.1.11 as further v8+ version requires React 18 (@hainenber)
- [#26557](https://github.com/apache/superset/pull/26557) build(deps-dev): bump thread-loader from 3.0.4 to 4.0.2 in /superset-frontend (@dependabot[bot])

View File

@@ -18,16 +18,19 @@
######################################################################
# Node stage to deal with static asset construction
######################################################################
ARG PY_VER=3.11-slim-bookworm
ARG PY_VER=3.11.13-slim-bookworm
# If BUILDPLATFORM is null, set it to 'amd64' (or leave as is otherwise).
ARG BUILDPLATFORM=${BUILDPLATFORM:-amd64}
# Include translations in the final build
ARG BUILD_TRANSLATIONS="false"
######################################################################
# superset-node-ci used as a base for building frontend assets and CI
######################################################################
FROM --platform=${BUILDPLATFORM} node:20-bullseye-slim AS superset-node-ci
ARG BUILD_TRANSLATIONS="false" # Include translations in the final build
FROM --platform=${BUILDPLATFORM} node:20-bookworm-slim AS superset-node-ci
ARG BUILD_TRANSLATIONS
ENV BUILD_TRANSLATIONS=${BUILD_TRANSLATIONS}
ARG DEV_MODE="false" # Skip frontend build in dev mode
ENV DEV_MODE=${DEV_MODE}
@@ -122,10 +125,13 @@ ENV PATH="/app/.venv/bin:${PATH}"
######################################################################
FROM python-base AS python-translation-compiler
ARG BUILD_TRANSLATIONS
ENV BUILD_TRANSLATIONS=${BUILD_TRANSLATIONS}
# Install Python dependencies using docker/pip-install.sh
COPY requirements/translations.txt requirements/
RUN --mount=type=cache,target=/root/.cache/uv \
/app/docker/pip-install.sh --requires-build-essential -r requirements/translations.txt
. /app/.venv/bin/activate && /app/docker/pip-install.sh --requires-build-essential -r requirements/translations.txt
COPY superset/translations/ /app/translations_mo/
RUN if [ "$BUILD_TRANSLATIONS" = "true" ]; then \
@@ -213,6 +219,10 @@ FROM python-common AS lean
# Install Python dependencies using docker/pip-install.sh
COPY requirements/base.txt requirements/
# Copy superset-core package needed for editable install in base.txt
COPY superset-core superset-core
RUN --mount=type=cache,target=${SUPERSET_HOME}/.cache/uv \
/app/docker/pip-install.sh --requires-build-essential -r requirements/base.txt
# Install the superset package
@@ -235,6 +245,11 @@ RUN /app/docker/apt-install.sh \
# Copy development requirements and install them
COPY requirements/*.txt requirements/
# Copy local packages needed for editable installs in development.txt
COPY superset-core superset-core
COPY superset-extensions-cli superset-extensions-cli
# Install Python dependencies using docker/pip-install.sh
RUN --mount=type=cache,target=${SUPERSET_HOME}/.cache/uv \
/app/docker/pip-install.sh --requires-build-essential -r requirements/development.txt

View File

@@ -30,12 +30,12 @@ RUN apt-get install -y apt-transport-https apt-utils
# Install superset dependencies
# https://superset.apache.org/docs/installation/installing-superset-from-scratch
RUN apt-get install -y build-essential libssl-dev \
libffi-dev python3-dev libsasl2-dev libldap2-dev libxi-dev chromium
libffi-dev python3-dev libsasl2-dev libldap2-dev libxi-dev chromium zstd
# Install nodejs for custom build
# https://nodejs.org/en/download/package-manager/
RUN set -eux; \
curl -sL https://deb.nodesource.com/setup_18.x | bash -; \
curl -sL https://deb.nodesource.com/setup_20.x | bash -; \
apt-get install -y nodejs; \
node --version;
RUN if ! which npm; then apt-get install -y npm; fi
@@ -64,7 +64,7 @@ RUN pip install --upgrade setuptools pip \
RUN flask fab babel-compile --target superset/translations
ENV PATH=/home/superset/superset/bin:$PATH \
PYTHONPATH=/home/superset/superset/:$PYTHONPATH \
PYTHONPATH=/home/superset/superset/ \
SUPERSET_TESTENV=true
COPY from_tarball_entrypoint.sh /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]

View File

@@ -29,13 +29,16 @@ RUN apt-get install -y apt-transport-https apt-utils
# Install superset dependencies
# https://superset.apache.org/docs/installation/installing-superset-from-scratch
RUN apt-get install -y build-essential libssl-dev \
libffi-dev python3-dev libsasl2-dev libldap2-dev libxi-dev chromium
RUN apt-get install -y subversion build-essential libssl-dev \
libffi-dev python3-dev libsasl2-dev libldap2-dev libxi-dev chromium zstd
# Install nodejs for custom build
# https://nodejs.org/en/download/package-manager/
RUN curl -sL https://deb.nodesource.com/setup_16.x | bash - \
&& apt-get install -y nodejs
RUN set -eux; \
curl -sL https://deb.nodesource.com/setup_20.x | bash -; \
apt-get install -y nodejs; \
node --version;
RUN if ! which npm; then apt-get install -y npm; fi
RUN mkdir -p /home/superset
RUN chown superset /home/superset
@@ -46,14 +49,12 @@ ARG VERSION
# Can fetch source from svn or copy tarball from local mounted directory
RUN svn co https://dist.apache.org/repos/dist/dev/superset/$VERSION ./
RUN tar -xvf *.tar.gz
WORKDIR apache-superset-$VERSION
WORKDIR /home/superset/apache-superset-$VERSION/superset-frontend
RUN cd superset-frontend \
&& npm ci \
RUN npm ci \
&& npm run build \
&& rm -rf node_modules
WORKDIR /home/superset/apache-superset-$VERSION
RUN pip install --upgrade setuptools pip \
&& pip install -r requirements/base.txt \
@@ -62,6 +63,6 @@ RUN pip install --upgrade setuptools pip \
RUN flask fab babel-compile --target superset/translations
ENV PATH=/home/superset/superset/bin:$PATH \
PYTHONPATH=/home/superset/superset/:$PYTHONPATH
PYTHONPATH=/home/superset/superset/
COPY from_tarball_entrypoint.sh /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]

View File

@@ -452,7 +452,7 @@ cd ../
# Compile translations for the backend
./scripts/translations/generate_po_files.sh
./scripts/translations/generate_mo_files.sh
# build the python distribution
python -m build

View File

@@ -22,10 +22,11 @@ under the License.
This file documents any backwards-incompatible changes in Superset and
assists people when migrating to a new version.
## Next
## 5.0.0
- [31976](https://github.com/apache/superset/pull/31976) Removed the `DISABLE_LEGACY_DATASOURCE_EDITOR` feature flag. The previous value of the feature flag was `True` and now the feature is permanently removed.
- [31959](https://github.com/apache/superset/pull/32000) Removes CSV_UPLOAD_MAX_SIZE config, use your web server to control file upload size.
- [31959](https://github.com/apache/superset/pull/31959) Removes the following endpoints from data uploads: /api/v1/database/<id>/<file type>_upload and /api/v1/database/<file type>_metadata, in favour of new one (Details on the PR). And simplifies permissions.
- [31959](https://github.com/apache/superset/pull/31959) Removes the following endpoints from data uploads: `/api/v1/database/<id>/<file type>_upload` and `/api/v1/database/<file type>_metadata`, in favour of new one (Details on the PR). And simplifies permissions.
- [31844](https://github.com/apache/superset/pull/31844) The `ALERT_REPORTS_EXECUTE_AS` and `THUMBNAILS_EXECUTE_AS` config parameters have been renamed to `ALERT_REPORTS_EXECUTORS` and `THUMBNAILS_EXECUTORS` respectively. A new config flag `CACHE_WARMUP_EXECUTORS` has also been introduced to be able to control which user is used to execute cache warmup tasks. Finally, the config flag `THUMBNAILS_SELENIUM_USER` has been removed. To use a fixed executor for async tasks, use the new `FixedExecutor` class. See the config and docs for more info on setting up different executor profiles.
- [31894](https://github.com/apache/superset/pull/31894) Domain sharding is deprecated in favor of HTTP2. The `SUPERSET_WEBSERVER_DOMAINS` configuration will be removed in the next major version (6.0)
- [31794](https://github.com/apache/superset/pull/31794) Removed the previously deprecated `DASHBOARD_CROSS_FILTERS` feature flag
@@ -45,9 +46,7 @@ assists people when migrating to a new version.
- [25166](https://github.com/apache/superset/pull/25166) Changed the default configuration of `UPLOAD_FOLDER` from `/app/static/uploads/` to `/static/uploads/`. It also removed the unused `IMG_UPLOAD_FOLDER` and `IMG_UPLOAD_URL` configuration options.
- [30284](https://github.com/apache/superset/pull/30284) Deprecated GLOBAL_ASYNC_QUERIES_REDIS_CONFIG in favor of the new GLOBAL_ASYNC_QUERIES_CACHE_BACKEND configuration. To leverage Redis Sentinel, set CACHE_TYPE to RedisSentinelCache, or use RedisCache for standalone Redis
- [31961](https://github.com/apache/superset/pull/31961) Upgraded React from version 16.13.1 to 17.0.2. If you are using custom frontend extensions or plugins, you may need to update them to be compatible with React 17.
### Potential Downtime
- [31260](https://github.com/apache/superset/pull/31260) Docker images now use `uv pip install` instead of `pip install` to manage the python envrionment. Most docker-based deployments will be affected, whether you derive one of the published images, or have custom bootstrap script that install python libraries (drivers)
## 4.1.0

View File

@@ -50,7 +50,11 @@ fi
#
if [ -f "${REQUIREMENTS_LOCAL}" ]; then
echo "Installing local overrides at ${REQUIREMENTS_LOCAL}"
uv pip install --no-cache-dir -r "${REQUIREMENTS_LOCAL}"
if command -v uv > /dev/null 2>&1; then
uv pip install --no-cache-dir -r "${REQUIREMENTS_LOCAL}"
else
pip install --no-cache-dir -r "${REQUIREMENTS_LOCAL}"
fi
else
echo "Skipping local overrides"
fi

View File

@@ -112,6 +112,12 @@ http {
proxy_set_header Host $host;
}
location /static {
proxy_pass http://host.docker.internal:9000; # Proxy to superset-node
proxy_http_version 1.1;
proxy_set_header Host $host;
}
location / {
proxy_pass http://superset_app;
proxy_set_header Host $host;

View File

@@ -1,16 +1,17 @@
---
title: Kubernetes
title: Kubernetes
hide_title: true
sidebar_position: 2
version: 1
---
import useBaseUrl from "@docusaurus/useBaseUrl";
import useBaseUrl from '@docusaurus/useBaseUrl';
# Installing on Kubernetes
<img src={useBaseUrl("/img/k8s.png" )} width="150" />
<br /><br />
<img src={useBaseUrl('/img/k8s.png')} width="150" />
<br />
<br />
Running Superset on Kubernetes is supported with the provided [Helm](https://helm.sh/) chart
found in the official [Superset helm repository](https://apache.github.io/superset/index.yaml).
@@ -134,7 +135,7 @@ init:
```
:::note
Superset uses [Scarf Gateway](https://about.scarf.sh/scarf-gateway) to collect telemetry data. Knowing the installation counts for different Superset versions informs the project's decisions about patching and long-term support. Scarf purges personally identifiable information (PII) and provides only aggregated statistics.
Superset uses [Scarf Gateway](https://about.scarf.sh/scarf-gateway) to collect telemetry data. Knowing the installation counts for different Superset versions informs the project's decisions about patching and long-term support. Scarf purges personally identifiable information (PII) and provides only aggregated statistics.
To opt-out of this data collection in your Helm-based installation, edit the `repository:` line in your `helm/superset/values.yaml` file, replacing `apachesuperset.docker.scarf.sh/apache/superset` with `apache/superset` to pull the image directly from Docker Hub.
:::
@@ -154,10 +155,11 @@ See [Install Database Drivers](/docs/configuration/databases) for more informati
:::
The following example installs the drivers for BigQuery and Elasticsearch, allowing you to connect to these data sources within your Superset setup:
```yaml
bootstrapScript: |
#!/bin/bash
pip install psycopg2==2.9.6 \
uv pip install psycopg2==2.9.6 \
sqlalchemy-bigquery==1.6.1 \
elasticsearch-dbapi==0.2.5 &&\
if [ ! -f ~/bootstrap ]; then echo "Running Superset with uid {{ .Values.runAsUser }}" > ~/bootstrap; fi
@@ -191,7 +193,7 @@ Those can be passed as key/values either with `extraEnv` or `extraSecretEnv` if
extraEnv:
SMTP_HOST: smtp.gmail.com
SMTP_USER: user@gmail.com
SMTP_PORT: "587"
SMTP_PORT: '587'
SMTP_MAIL_FROM: user@gmail.com
extraSecretEnv:
@@ -352,7 +354,7 @@ supersetCeleryBeat:
extraEnv:
SMTP_HOST: smtp.gmail.com
SMTP_USER: user@gmail.com
SMTP_PORT: "587"
SMTP_PORT: '587'
SMTP_MAIL_FROM: user@gmail.com
extraSecretEnv:

View File

@@ -281,6 +281,49 @@ TALISMAN_CONFIG = {
"content_security_policy": { ...
```
#### Configuring Talisman in Superset
Talisman settings in Superset can be modified using superset_config.py. If you need to adjust security policies, you can override the default configuration.
Example: Overriding Talisman Configuration in superset_config.py for loading images form s3 or other external sources.
```python
TALISMAN_CONFIG = {
"content_security_policy": {
"base-uri": ["'self'"],
"default-src": ["'self'"],
"img-src": [
"'self'",
"blob:",
"data:",
"https://apachesuperset.gateway.scarf.sh",
"https://static.scarf.sh/",
# "https://cdn.brandfolder.io", # Uncomment when SLACK_ENABLE_AVATARS is True # noqa: E501
"ows.terrestris.de",
"aws.s3.com", # Add Your Bucket or external data source
],
"worker-src": ["'self'", "blob:"],
"connect-src": [
"'self'",
"https://api.mapbox.com",
"https://events.mapbox.com",
],
"object-src": "'none'",
"style-src": [
"'self'",
"'unsafe-inline'",
],
"script-src": ["'self'", "'strict-dynamic'"],
},
"content_security_policy_nonce_in": ["script-src"],
"force_https": False,
"session_cookie_secure": False,
}
```
# For more information on setting up Talisman, please refer to
https://superset.apache.org/docs/configuration/networking-settings/#changing-flask-talisman-csp
### Reporting Security Vulnerabilities
Apache Software Foundation takes a rigorous standpoint in annihilating the security issues in its

View File

@@ -137,4 +137,9 @@ export const Databases = [
href: 'https://www.denodo.com/',
imgName: 'denodo.png',
},
{
title: 'TDengine',
href: 'https://www.tdengine.com/',
imgName: 'tdengine.png',
},
];

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

View File

@@ -34,6 +34,8 @@ classifiers = [
"Programming Language :: Python :: 3.11",
]
dependencies = [
# no bounds for apache-superset-core until we have a stable version
"apache-superset-core",
"backoff>=1.8.0",
"celery>=5.3.6, <6.0.0",
"click>=8.0.3",
@@ -44,7 +46,7 @@ dependencies = [
"cryptography>=42.0.4, <44.0.0",
"deprecation>=2.1.0, <2.2.0",
"flask>=2.2.5, <3.0.0",
"flask-appbuilder>=4.5.3, <5.0.0",
"flask-appbuilder>=4.5.5, <5.0.0",
"flask-caching>=2.1.0, <3",
"flask-compress>=1.13, <2.0",
"flask-talisman>=1.0.0, <2.0",
@@ -64,6 +66,8 @@ dependencies = [
"jsonpath-ng>=1.6.1, <2",
"Mako>=1.2.2",
"markdown>=3.0",
# marshmallow>=4 has issues: https://github.com/apache/superset/issues/33162
"marshmallow>=3.0, <4",
"msgpack>=1.0.0, <1.1",
"nh3>=0.2.11, <0.3",
"numpy>1.23.5, <2",
@@ -98,6 +102,7 @@ dependencies = [
"tabulate>=0.8.9, <0.9",
"typing-extensions>=4, <5",
"waitress; sys_platform == 'win32'",
"watchdog>=6.0.0",
"wtforms>=2.3.3, <4",
"wtforms-json",
"xlsxwriter>=3.0.7, <3.1",
@@ -182,6 +187,8 @@ doris = ["pydoris>=1.0.0, <2.0.0"]
oceanbase = ["oceanbase_py>=0.0.1"]
ydb = ["ydb-sqlalchemy>=0.1.2"]
development = [
# no bounds for apache-superset-extensions-cli until a stable version
"apache-superset-extensions-cli",
"docker",
"flask-testing",
"freezegun",
@@ -211,7 +218,7 @@ documentation = "https://superset.apache.org/docs/intro"
combine_as_imports = true
include_trailing_comma = true
line_length = 88
known_first_party = "superset"
known_first_party = "superset, apache-superset-core, apache-superset-extensions-cli"
known_third_party = "alembic, apispec, backoff, celery, click, colorama, cron_descriptor, croniter, cryptography, dateutil, deprecation, flask, flask_appbuilder, flask_babel, flask_caching, flask_compress, flask_jwt_extended, flask_login, flask_migrate, flask_sqlalchemy, flask_talisman, flask_testing, flask_wtf, freezegun, geohash, geopy, holidays, humanize, isodate, jinja2, jwt, markdown, markupsafe, marshmallow, msgpack, nh3, numpy, pandas, parameterized, parsedatetime, pgsanity, polyline, prison, progress, pyarrow, sqlalchemy_bigquery, pyhive, pyparsing, pytest, pytest_mock, pytz, redis, requests, selenium, setuptools, shillelagh, simplejson, slack, sqlalchemy, sqlalchemy_utils, sqlparse, typing_extensions, urllib3, werkzeug, wtforms, wtforms_json, yaml"
multi_line_output = 3
order_by_type = false
@@ -390,3 +397,7 @@ python-geohash = "0"
# TODO REMOVE THESE DEPS FROM CODEBASE
paramiko = "3" # GPL
pyxlsb = "1" # GPL
[tool.uv.sources]
apache-superset-core = { path = "./superset-core", editable = true }
apache-superset-extensions-cli = { path = "./superset-extensions-cli", editable = true }

View File

@@ -1,5 +1,7 @@
# This file was autogenerated by uv via the following command:
# uv pip compile pyproject.toml requirements/base.in -o requirements/base.txt
-e ./superset-core
# via apache-superset (pyproject.toml)
alembic==1.14.0
# via flask-migrate
amqp==5.3.1
@@ -9,7 +11,9 @@ apispec==6.3.0
apsw==3.46.0.0
# via shillelagh
async-timeout==4.0.3
# via -r requirements/base.in
# via
# -r requirements/base.in
# redis
attrs==24.2.0
# via
# cattrs
@@ -94,6 +98,11 @@ email-validator==2.2.0
# via flask-appbuilder
et-xmlfile==2.0.0
# via openpyxl
exceptiongroup==1.3.0
# via
# cattrs
# trio
# trio-websocket
flask==2.3.3
# via
# apache-superset (pyproject.toml)
@@ -108,8 +117,10 @@ flask==2.3.3
# flask-session
# flask-sqlalchemy
# flask-wtf
flask-appbuilder==4.5.3
# via apache-superset (pyproject.toml)
flask-appbuilder==4.5.5
# via
# apache-superset (pyproject.toml)
# apache-superset-core
flask-babel==2.0.0
# via flask-appbuilder
flask-caching==2.3.0
@@ -150,7 +161,7 @@ greenlet==3.0.3
# shillelagh
gunicorn==23.0.0
# via apache-superset (pyproject.toml)
h11==0.14.0
h11==0.16.0
# via wsproto
hashids==1.3.1
# via apache-superset (pyproject.toml)
@@ -203,6 +214,7 @@ markupsafe==3.0.2
# wtforms
marshmallow==3.23.1
# via
# apache-superset (pyproject.toml)
# flask-appbuilder
# marshmallow-sqlalchemy
marshmallow-sqlalchemy==0.28.2
@@ -358,7 +370,7 @@ sqlalchemy-utils==0.38.3
# via
# apache-superset (pyproject.toml)
# flask-appbuilder
sqlglot==26.1.3
sqlglot==26.11.1
# via apache-superset (pyproject.toml)
sqlparse==0.5.2
# via apache-superset (pyproject.toml)
@@ -376,8 +388,11 @@ typing-extensions==4.12.2
# via
# apache-superset (pyproject.toml)
# alembic
# cattrs
# exceptiongroup
# flask-limiter
# limits
# rich
# selenium
# shillelagh
tzdata==2024.2
@@ -398,6 +413,8 @@ vine==5.1.0
# amqp
# celery
# kombu
watchdog==6.0.0
# via apache-superset (pyproject.toml)
wcwidth==0.2.13
# via prompt-toolkit
websocket-client==1.8.0

View File

@@ -17,3 +17,4 @@
# under the License.
#
-e .[development,bigquery,cors,druid,gevent,gsheets,mysql,postgres,presto,prophet,trino,thumbnails]
-e ./superset-extensions-cli[test]

View File

@@ -1,26 +1,38 @@
# This file was autogenerated by uv via the following command:
# uv pip compile requirements/development.in -c requirements/base.txt -o requirements/development.txt
# uv pip compile requirements/development.in -c requirements/base-constraint.txt -o requirements/development.txt
-e .
# via -r requirements/development.in
-e ./superset-core
# via
# apache-superset
# apache-superset-extensions-cli
-e ./superset-extensions-cli
# via
# -r requirements/development.in
# apache-superset
alembic==1.14.0
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# flask-migrate
amqp==5.3.1
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# kombu
apispec==6.3.0
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# flask-appbuilder
apsw==3.46.0.0
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# shillelagh
async-timeout==4.0.3
# via
# -c requirements/base-constraint.txt
# redis
attrs==24.2.0
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# cattrs
# jsonschema
# outcome
@@ -28,69 +40,70 @@ attrs==24.2.0
# trio
babel==2.16.0
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# flask-babel
backoff==2.2.1
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# apache-superset
bcrypt==4.2.1
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# paramiko
billiard==4.2.1
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# celery
blinker==1.9.0
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# flask
bottleneck==1.4.2
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# apache-superset
brotli==1.1.0
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# flask-compress
cachelib==0.9.0
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# flask-caching
# flask-session
cachetools==5.5.0
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# google-auth
cattrs==24.1.2
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# requests-cache
celery==5.4.0
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# apache-superset
certifi==2024.8.30
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# requests
# selenium
cffi==1.17.1
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# cryptography
# pynacl
cfgv==3.4.0
# via pre-commit
charset-normalizer==3.4.0
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# requests
click==8.1.7
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# apache-superset
# apache-superset-extensions-cli
# celery
# click-didyoumean
# click-option-group
@@ -100,25 +113,25 @@ click==8.1.7
# flask-appbuilder
click-didyoumean==0.3.1
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# celery
click-option-group==0.5.6
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# apache-superset
click-plugins==1.1.1
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# celery
click-repl==0.3.0
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# celery
cmdstanpy==1.1.0
# via prophet
colorama==0.4.6
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# apache-superset
# flask-appbuilder
contourpy==1.0.7
@@ -127,15 +140,15 @@ coverage==7.6.8
# via pytest-cov
cron-descriptor==1.4.5
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# apache-superset
croniter==5.0.1
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# apache-superset
cryptography==43.0.3
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# apache-superset
# paramiko
# pyopenssl
@@ -145,37 +158,44 @@ db-dtypes==1.3.1
# via pandas-gbq
defusedxml==0.7.1
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# odfpy
deprecated==1.2.15
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# limits
deprecation==2.1.0
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# apache-superset
distlib==0.3.8
# via virtualenv
dnspython==2.7.0
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# email-validator
docker==7.0.0
# via apache-superset
email-validator==2.2.0
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# flask-appbuilder
et-xmlfile==2.0.0
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# openpyxl
exceptiongroup==1.3.0
# via
# -c requirements/base-constraint.txt
# cattrs
# pytest
# trio
# trio-websocket
filelock==3.12.2
# via virtualenv
flask==2.3.3
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# apache-superset
# flask-appbuilder
# flask-babel
@@ -190,59 +210,60 @@ flask==2.3.3
# flask-sqlalchemy
# flask-testing
# flask-wtf
flask-appbuilder==4.5.3
flask-appbuilder==4.5.5
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# apache-superset
# apache-superset-core
flask-babel==2.0.0
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# flask-appbuilder
flask-caching==2.3.0
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# apache-superset
flask-compress==1.17
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# apache-superset
flask-cors==4.0.0
# via apache-superset
flask-jwt-extended==4.7.1
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# flask-appbuilder
flask-limiter==3.8.0
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# flask-appbuilder
flask-login==0.6.3
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# apache-superset
# flask-appbuilder
flask-migrate==3.1.0
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# apache-superset
flask-session==0.8.0
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# apache-superset
flask-sqlalchemy==2.5.1
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# flask-appbuilder
# flask-migrate
flask-talisman==1.1.0
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# apache-superset
flask-testing==0.8.1
# via apache-superset
flask-wtf==1.2.2
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# apache-superset
# flask-appbuilder
fonttools==4.55.0
@@ -253,11 +274,11 @@ future==1.0.0
# via pyhive
geographiclib==2.0
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# geopy
geopy==2.4.1
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# apache-superset
gevent==24.2.1
# via apache-superset
@@ -270,7 +291,7 @@ google-api-core==2.23.0
# sqlalchemy-bigquery
google-auth==2.36.0
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# google-api-core
# google-auth-oauthlib
# google-cloud-bigquery
@@ -302,7 +323,7 @@ googleapis-common-protos==1.66.0
# grpcio-status
greenlet==3.0.3
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# apache-superset
# gevent
# shillelagh
@@ -315,65 +336,66 @@ grpcio-status==1.60.1
# via google-api-core
gunicorn==23.0.0
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# apache-superset
h11==0.14.0
h11==0.16.0
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# wsproto
hashids==1.3.1
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# apache-superset
holidays==0.25
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# apache-superset
# prophet
humanize==4.11.0
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# apache-superset
identify==2.5.36
# via pre-commit
idna==3.10
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# email-validator
# requests
# trio
importlib-metadata==8.5.0
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# apache-superset
importlib-resources==6.4.5
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# limits
# prophet
iniconfig==2.0.0
# via pytest
isodate==0.7.2
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# apache-superset
itsdangerous==2.2.0
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# flask
# flask-wtf
jinja2==3.1.4
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# apache-superset-extensions-cli
# flask
# flask-babel
jsonpath-ng==1.7.0
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# apache-superset
jsonschema==4.17.3
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# flask-appbuilder
# jsonschema-spec
# openapi-schema-validator
@@ -384,72 +406,73 @@ kiwisolver==1.4.7
# via matplotlib
kombu==5.4.2
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# celery
korean-lunar-calendar==0.3.1
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# holidays
lazy-object-proxy==1.10.0
# via openapi-spec-validator
limits==3.13.0
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# flask-limiter
mako==1.3.6
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# alembic
# apache-superset
markdown==3.7
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# apache-superset
markdown-it-py==3.0.0
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# rich
markupsafe==3.0.2
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# jinja2
# mako
# werkzeug
# wtforms
marshmallow==3.23.1
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# apache-superset
# flask-appbuilder
# marshmallow-sqlalchemy
marshmallow-sqlalchemy==0.28.2
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# flask-appbuilder
matplotlib==3.9.0
# via prophet
mdurl==0.1.2
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# markdown-it-py
msgpack==1.0.8
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# apache-superset
msgspec==0.18.6
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# flask-session
mysqlclient==2.2.6
# via apache-superset
nh3==0.2.19
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# apache-superset
nodeenv==1.8.0
# via pre-commit
numpy==1.26.4
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# apache-superset
# bottleneck
# cmdstanpy
@@ -464,7 +487,7 @@ oauthlib==3.2.2
# via requests-oauthlib
odfpy==1.4.1
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# pandas
openapi-schema-validator==0.4.4
# via openapi-spec-validator
@@ -472,19 +495,19 @@ openapi-spec-validator==0.5.6
# via apache-superset
openpyxl==3.1.5
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# pandas
ordered-set==4.1.0
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# flask-limiter
outcome==1.3.0.post0
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# trio
packaging==24.2
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# apache-superset
# apispec
# db-dtypes
@@ -501,7 +524,7 @@ packaging==24.2
# sqlalchemy-bigquery
pandas==2.0.3
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# apache-superset
# cmdstanpy
# db-dtypes
@@ -513,18 +536,18 @@ parameterized==0.9.0
# via apache-superset
paramiko==3.5.0
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# apache-superset
# sshtunnel
parsedatetime==2.6
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# apache-superset
pathable==0.4.3
# via jsonschema-spec
pgsanity==0.2.9
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# apache-superset
pillow==10.3.0
# via
@@ -532,30 +555,30 @@ pillow==10.3.0
# matplotlib
platformdirs==3.8.1
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# requests-cache
# virtualenv
pluggy==1.5.0
# via pytest
ply==3.11
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# jsonpath-ng
polyline==2.0.2
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# apache-superset
pre-commit==4.0.1
# via apache-superset
prison==0.2.1
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# flask-appbuilder
progress==1.6
# via apache-superset
prompt-toolkit==3.0.48
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# click-repl
prophet==1.1.5
# via apache-superset
@@ -576,24 +599,24 @@ psycopg2-binary==2.9.6
# via apache-superset
pyarrow==14.0.2
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# apache-superset
# db-dtypes
# pandas-gbq
pyasn1==0.6.1
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# pyasn1-modules
# python-ldap
# rsa
pyasn1-modules==0.4.1
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# google-auth
# python-ldap
pycparser==2.22
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# cffi
pydata-google-auth==1.9.0
# via pandas-gbq
@@ -603,7 +626,7 @@ pyfakefs==5.3.5
# via apache-superset
pygments==2.18.0
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# rich
pyhive==0.7.0
# via apache-superset
@@ -611,43 +634,48 @@ pyinstrument==4.4.0
# via apache-superset
pyjwt==2.10.1
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# apache-superset
# flask-appbuilder
# flask-jwt-extended
pynacl==1.5.0
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# paramiko
pyopenssl==24.2.1
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# shillelagh
pyparsing==3.2.0
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# apache-superset
# matplotlib
pyrsistent==0.20.0
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# jsonschema
pysocks==1.7.1
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# urllib3
pytest==7.4.4
# via
# apache-superset
# apache-superset-extensions-cli
# pytest-cov
# pytest-mock
pytest-cov==6.0.0
# via apache-superset
# via
# apache-superset
# apache-superset-extensions-cli
pytest-mock==3.10.0
# via apache-superset
# via
# apache-superset
# apache-superset-extensions-cli
python-dateutil==2.9.0.post0
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# apache-superset
# celery
# croniter
@@ -662,39 +690,39 @@ python-dateutil==2.9.0.post0
# trino
python-dotenv==1.0.1
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# apache-superset
python-geohash==0.8.5
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# apache-superset
python-ldap==3.4.4
# via apache-superset
pytz==2024.2
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# croniter
# flask-babel
# pandas
# trino
pyxlsb==1.0.10
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# pandas
pyyaml==6.0.2
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# apache-superset
# apispec
# jsonschema-spec
# pre-commit
redis==4.6.0
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# apache-superset
requests==2.32.2
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# docker
# google-api-core
# google-cloud-bigquery
@@ -707,7 +735,7 @@ requests==2.32.2
# trino
requests-cache==1.2.0
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# shillelagh
requests-oauthlib==2.0.0
# via google-auth-oauthlib
@@ -715,18 +743,20 @@ rfc3339-validator==0.1.4
# via openapi-schema-validator
rich==13.9.4
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# flask-limiter
rsa==4.9
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# google-auth
ruff==0.8.0
# via apache-superset
selenium==4.27.1
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# apache-superset
semver==3.0.4
# via apache-superset-extensions-cli
setuptools==75.6.0
# via
# nodeenv
@@ -736,19 +766,19 @@ setuptools==75.6.0
# zope-interface
shillelagh==1.2.18
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# apache-superset
shortid==0.1.2
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# apache-superset
simplejson==3.19.3
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# apache-superset
six==1.16.0
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# prison
# python-dateutil
# rfc3339-validator
@@ -756,19 +786,19 @@ six==1.16.0
# wtforms-json
slack-sdk==3.33.4
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# apache-superset
sniffio==1.3.1
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# trio
sortedcontainers==2.4.0
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# trio
sqlalchemy==1.4.54
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# alembic
# apache-superset
# flask-appbuilder
@@ -781,29 +811,34 @@ sqlalchemy-bigquery==1.12.0
# via apache-superset
sqlalchemy-utils==0.38.3
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# apache-superset
# flask-appbuilder
sqlglot==26.1.3
sqlglot==26.11.1
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# apache-superset
sqloxide==0.1.51
# via apache-superset
sqlparse==0.5.2
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# apache-superset
sshtunnel==0.4.0
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# apache-superset
statsd==4.0.1
# via apache-superset
tabulate==0.8.10
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# apache-superset
tomli==2.2.1
# via
# apache-superset-extensions-cli
# coverage
# pytest
tqdm==4.67.1
# via
# cmdstanpy
@@ -812,25 +847,28 @@ trino==0.330.0
# via apache-superset
trio==0.28.0
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# selenium
# trio-websocket
trio-websocket==0.11.1
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# selenium
typing-extensions==4.12.2
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# alembic
# apache-superset
# cattrs
# exceptiongroup
# flask-limiter
# limits
# rich
# selenium
# shillelagh
tzdata==2024.2
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# celery
# kombu
# pandas
@@ -838,69 +876,74 @@ tzlocal==5.2
# via trino
url-normalize==1.4.3
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# requests-cache
urllib3==1.26.18
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# docker
# requests
# requests-cache
# selenium
vine==5.1.0
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# amqp
# celery
# kombu
virtualenv==20.23.1
# via pre-commit
watchdog==6.0.0
# via
# -c requirements/base-constraint.txt
# apache-superset
# apache-superset-extensions-cli
wcwidth==0.2.13
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# prompt-toolkit
websocket-client==1.8.0
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# selenium
werkzeug==3.1.3
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# flask
# flask-appbuilder
# flask-jwt-extended
# flask-login
wrapt==1.17.0
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# deprecated
wsproto==1.2.0
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# trio-websocket
wtforms==3.2.1
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# apache-superset
# flask-appbuilder
# flask-wtf
# wtforms-json
wtforms-json==0.3.5
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# apache-superset
xlrd==2.0.1
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# pandas
xlsxwriter==3.0.9
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# apache-superset
# pandas
zipp==3.21.0
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# importlib-metadata
zope-event==5.0
# via gevent
@@ -908,5 +951,5 @@ zope-interface==5.4.0
# via gevent
zstandard==0.23.0
# via
# -c requirements/base.txt
# -c requirements/base-constraint.txt
# flask-compress

View File

@@ -45,6 +45,11 @@ PATTERNS = {
"docs": [
r"^docs/",
],
"superset-extensions-cli": [
r"^\.github/workflows/superset-extensions-cli\.yml",
r"^superset-extensions-cli/",
r"^superset-core/",
],
}
GITHUB_TOKEN = os.environ.get("GITHUB_TOKEN")
@@ -134,7 +139,7 @@ def main(event_type: str, sha: str, repo: str) -> None:
with open(output_path, "a") as f:
for check, changed in changes_detected.items():
if changed:
print(f"{check}={str(changed).lower()}", file=f)
print(f"{check}=true", file=f)
print(f"Triggering group: {check}")

View File

@@ -24,7 +24,13 @@ ADDITIONAL_ARGS="$@"
# Generate the requirements/base.txt file
uv pip compile pyproject.toml requirements/base.in -o requirements/base.txt $ADDITIONAL_ARGS
# Generate the requirements/development.txt file, making sure requirements/base.txt is a constraint to keep the versions in sync
uv pip compile requirements/development.in -c requirements/base.txt -o requirements/development.txt $ADDITIONAL_ARGS
# Hack to remove "Unnamed requirements are not allowed as constraints" error from base requirements
grep --invert-match "./superset-core" requirements/base.txt > requirements/base-constraint.txt
# Generate the requirements/development.txt file, making sure the base requirements are used as a constraint to keep the versions in sync. Note that `development.txt` is a Superset of `base.txt` where version for the shared libs should match their version.
uv pip compile requirements/development.in -c requirements/base-constraint.txt -o requirements/development.txt $ADDITIONAL_ARGS
# Remove temporary base requirement file
rm requirements/base-constraint.txt
uv pip compile requirements/translations.in -o requirements/translations.txt $ADDITIONAL_ARGS

1
superset-core/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
apache_superset_primitives.egg-info/

View File

@@ -0,0 +1,22 @@
<!--
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.
-->
## Change Log
Changelogs will be added once we have the first stable release.

216
superset-core/LICENSE.txt Normal file
View File

@@ -0,0 +1,216 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed 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.
============================================================================
APACHE SUPERSET SUBCOMPONENTS:
The Apache Superset project contains subcomponents with separate copyright
notices and license terms. Your use of the source code for the these
subcomponents is subject to the terms and conditions of the following
licenses.
========================================================================
Third party SIL Open Font License v1.1 (OFL-1.1)
========================================================================
(SIL OPEN FONT LICENSE Version 1.1) The Inter font family (https://github.com/rsms/inter)
(SIL OPEN FONT LICENSE Version 1.1) The Fira Code font family (https://github.com/tonsky/FiraCode)

113
superset-core/README.md Normal file
View File

@@ -0,0 +1,113 @@
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
# apache-superset-core
[![PyPI version](https://badge.fury.io/py/apache-superset-core.svg)](https://badge.fury.io/py/apache-superset-core)
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
[![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
The official core package for building Apache Superset backend extensions and integrations. This package provides essential building blocks including base classes, API utilities, type definitions, and decorators for both the host application and extensions.
## 📦 Installation
```bash
pip install apache-superset-core
```
## 🏗️ Architecture
The package is organized into logical modules, each providing specific functionality:
- **`api`** - REST API base classes, models access, query utilities, and registration
- **`api.models`** - Access to Superset's database models (datasets, databases, etc.)
- **`api.query`** - Database query utilities and SQL dialect handling
- **`api.rest_api`** - Extension API registration and management
- **`api.types.rest_api`** - REST API base classes and type definitions
## 🚀 Quick Start
### Basic Extension Structure
```python
from flask import request, Response
from flask_appbuilder.api import expose, permission_name, protect, safe
from superset_core.api import models, query, rest_api
from superset_core.api.types.rest_api import RestApi
class DatasetReferencesAPI(RestApi):
"""Example extension API demonstrating core functionality."""
resource_name = "dataset_references"
openapi_spec_tag = "Dataset references"
class_permission_name = "dataset_references"
@expose("/metadata", methods=("POST",))
@protect()
@safe
@permission_name("read")
def metadata(self) -> Response:
"""Get dataset metadata for tables referenced in SQL."""
sql: str = request.json.get("sql")
database_id: int = request.json.get("databaseId")
# Access Superset's models using core APIs
databases = models.get_databases(id=database_id)
if not databases:
return self.response_404()
database = databases[0]
dialect = query.get_sqlglot_dialect(database)
# Access datasets to get owner information
datasets = models.get_datasets()
owners_map = {
dataset.table_name: [
f"{owner.first_name} {owner.last_name}"
for owner in dataset.owners
]
for dataset in datasets
}
# Process SQL and return dataset metadata
return self.response(200, result=owners_map)
# Register the extension API
rest_api.add_extension_api(DatasetReferencesAPI)
```
## 🤝 Contributing
We welcome contributions! Please see the [Contributing Guide](https://github.com/apache/superset/blob/master/CONTRIBUTING.md) for details.
## 📄 License
Licensed under the Apache License, Version 2.0. See [LICENSE](https://github.com/apache/superset/blob/master/LICENSE.txt) for details.
## 🔗 Links
- [Apache Superset](https://superset.apache.org/)
- [Documentation](https://superset.apache.org/docs/)
- [Community](https://superset.apache.org/community/)
- [GitHub Repository](https://github.com/apache/superset)
- [Extension Development Guide](https://superset.apache.org/docs/extensions/)
---
**Note**: This package is currently in release candidate status. APIs may change before the 1.0.0 release. Please check the [changelog](CHANGELOG.md) for breaking changes between versions.

View File

@@ -0,0 +1,63 @@
# 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.
[project]
name = "apache-superset-core"
version = "0.0.1rc2"
description = "Core Python package for building Apache Superset backend extensions and integrations"
readme = "README.md"
authors = [
{ name = "Apache Software Foundation", email = "dev@superset.apache.org" },
]
license = { file="LICENSE.txt" }
requires-python = ">=3.10"
keywords = ["superset", "apache", "analytics", "business-intelligence", "extensions", "visualization"]
classifiers = [
"Development Status :: 3 - Alpha",
"Environment :: Web Environment",
"Intended Audience :: Developers",
"License :: OSI Approved :: Apache Software License",
"Operating System :: OS Independent",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Topic :: Database",
"Topic :: Scientific/Engineering :: Visualization",
"Topic :: Software Development :: Libraries :: Python Modules",
]
dependencies = [
"flask-appbuilder>=4.5.3, <5.0.0",
]
[project.urls]
Homepage = "https://superset.apache.org/"
Documentation = "https://superset.apache.org/docs/"
Repository = "https://github.com/apache/superset"
"Bug Tracker" = "https://github.com/apache/superset/issues"
Changelog = "https://github.com/apache/superset/blob/master/CHANGELOG.md"
[build-system]
requires = ["setuptools>=76.0.0", "wheel"]
build-backend = "setuptools.build_meta"
[tool.setuptools]
package-dir = { "" = "src" }
[tool.setuptools.packages.find]
where = ["src"]

View File

@@ -0,0 +1,16 @@
# 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.

View File

@@ -0,0 +1,24 @@
# 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.
from .types.models import CoreModelsApi
from .types.query import CoreQueryApi
from .types.rest_api import CoreRestApi
models: CoreModelsApi
rest_api: CoreRestApi
query: CoreQueryApi

View File

@@ -0,0 +1,16 @@
# 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.

View File

@@ -0,0 +1,90 @@
# 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.
from abc import ABC, abstractmethod
from typing import Any, Type
from flask_sqlalchemy import BaseQuery
from sqlalchemy.orm import scoped_session
class CoreModelsApi(ABC):
"""
Abstract interface for accessing Superset data models.
This class defines the contract for retrieving SQLAlchemy sessions
and model instances for datasets and databases within Superset.
"""
@staticmethod
@abstractmethod
def get_session() -> scoped_session:
"""
Retrieve the SQLAlchemy session to directly interface with the
Superset models.
:returns: The SQLAlchemy scoped session instance.
"""
...
@staticmethod
@abstractmethod
def get_dataset_model() -> Type[Any]:
"""
Retrieve the Dataset (SqlaTable) SQLAlchemy model.
:returns: The Dataset SQLAlchemy model class.
"""
...
@staticmethod
@abstractmethod
def get_database_model() -> Type[Any]:
"""
Retrieve the Database SQLAlchemy model.
:returns: The Database SQLAlchemy model class.
"""
...
@staticmethod
@abstractmethod
def get_datasets(query: BaseQuery | None = None, **kwargs: Any) -> list[Any]:
"""
Retrieve Dataset (SqlaTable) entities.
:param query: A query with the Dataset model as the primary entity for complex
queries.
:param kwargs: Optional keyword arguments to filter datasets using SQLAlchemy's
`filter_by()`.
:returns: SqlaTable entities.
"""
...
@staticmethod
@abstractmethod
def get_databases(query: BaseQuery | None = None, **kwargs: Any) -> list[Any]:
"""
Retrieve Database entities.
:param query: A query with the Database model as the primary entity for complex
queries.
:param kwargs: Optional keyword arguments to filter databases using SQLAlchemy's
`filter_by()`.
:returns: Database entities.
"""
...

View File

@@ -0,0 +1,41 @@
# 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.
from abc import ABC, abstractmethod
from typing import Any
from sqlglot import Dialects
class CoreQueryApi(ABC):
"""
Abstract interface for query-related operations.
This class defines the contract for database query operations,
including dialect handling and query processing.
"""
@staticmethod
@abstractmethod
def get_sqlglot_dialect(database: Any) -> Dialects:
"""
Get the SQLGlot dialect for the specified database.
:param database: The database instance to get the dialect for.
:returns: The SQLGlot dialect enum corresponding to the database.
"""
...

View File

@@ -0,0 +1,64 @@
# 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.
from abc import ABC, abstractmethod
from typing import Type
from flask_appbuilder.api import BaseApi
class RestApi(BaseApi):
"""
Base REST API class for Superset with browser login support.
This class extends Flask-AppBuilder's BaseApi and enables browser-based
authentication by default.
"""
allow_browser_login = True
class CoreRestApi(ABC):
"""
Abstract interface for managing REST APIs in Superset.
This class defines the contract for adding and managing REST APIs,
including both core APIs and extension APIs.
"""
@staticmethod
@abstractmethod
def add_api(api: Type[RestApi]) -> None:
"""
Add a REST API to the Superset API.
:param api: A REST API instance.
:returns: None.
"""
...
@staticmethod
@abstractmethod
def add_extension_api(api: Type[RestApi]) -> None:
"""
Add an extension REST API to the Superset API.
:param api: An extension REST API instance. These are placed under
the /extensions resource.
:returns: None.
"""
...

View File

@@ -0,0 +1,16 @@
# 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.

View File

@@ -0,0 +1,63 @@
# 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.
from typing import TypedDict
class ModuleFederationConfig(TypedDict):
exposes: dict[str, str]
filename: str
shared: dict[str, str]
remotes: dict[str, str]
class FrontendContributionConfig(TypedDict):
commands: dict[str, list[dict[str, str]]]
views: dict[str, list[dict[str, str]]]
menus: dict[str, list[dict[str, str]]]
class FrontendManifest(TypedDict):
contributions: FrontendContributionConfig
moduleFederation: ModuleFederationConfig
remoteEntry: str
class BackendManifest(TypedDict):
entryPoints: list[str]
class SharedBase(TypedDict, total=False):
id: str
name: str
dependencies: list[str]
description: str
version: str
frontend: FrontendManifest
permissions: list[str]
class Manifest(SharedBase, total=False):
backend: BackendManifest
class BackendMetadata(BackendManifest):
files: list[str]
class Metadata(SharedBase):
backend: BackendMetadata

View File

@@ -0,0 +1,22 @@
<!--
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.
-->
## Change Log
Changelogs will be added once we have the first stable release.

View File

@@ -0,0 +1,216 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed 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.
============================================================================
APACHE SUPERSET SUBCOMPONENTS:
The Apache Superset project contains subcomponents with separate copyright
notices and license terms. Your use of the source code for the these
subcomponents is subject to the terms and conditions of the following
licenses.
========================================================================
Third party SIL Open Font License v1.1 (OFL-1.1)
========================================================================
(SIL OPEN FONT LICENSE Version 1.1) The Inter font family (https://github.com/rsms/inter)
(SIL OPEN FONT LICENSE Version 1.1) The Fira Code font family (https://github.com/tonsky/FiraCode)

View File

@@ -0,0 +1,110 @@
<!--
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.
-->
# apache-superset-extensions-cli
[![PyPI version](https://badge.fury.io/py/apache-superset-extensions-cli.svg)](https://badge.fury.io/py/apache-superset-extensions-cli)
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
[![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
Official command-line interface for building, bundling, and managing Apache Superset extensions. This CLI tool provides developers with everything needed to create, develop, and package extensions for the Superset ecosystem.
## 🚀 Features
- **Extension Scaffolding** - Generate initial folder structure and scaffold new extension projects
- **Development Server** - Automatically rebuild extensions as files change during development
- **Build System** - Build extension assets for production deployment
- **Bundle Packaging** - Package extensions into distributable .supx files
## 📦 Installation
```bash
pip install apache-superset-extensions-cli
```
## 🛠️ Quick Start
### Available Commands
```bash
# Generate initial folder structure and scaffold a new extension project
superset-extensions init <extension-name>
# Automatically rebuild extension as files change during development
superset-extensions dev
# Build extension assets for production
superset-extensions build
# Package extension into a distributable .supx file
superset-extensions bundle
```
## 📋 Extension Structure
The CLI generates extensions with the following structure:
```
extension_name/
├── extension.json # Extension configuration and metadata
├── frontend/ # Frontend code
│ ├── src/ # TypeScript/React source files
│ ├── webpack.config.js # Frontend build configuration
│ ├── tsconfig.json # TypeScript configuration
│ └── package.json # Frontend dependencies
├── backend/ # Backend code
│ ├── src/
│ │ └── dataset_references/ # Python package source
│ ├── tests/ # Backend tests
│ ├── pyproject.toml # Python package configuration
│ └── requirements.txt # Python dependencies
├── dist/ # Built extension files (generated)
│ ├── manifest.json # Generated extension manifest
│ ├── frontend/
│ │ └── dist/ # Built frontend assets
│ │ ├── remoteEntry.*.js # Module federation entry
│ │ └── *.js # Additional frontend bundles
│ └── backend/
│ └── dataset_references/ # Built backend package
│ ├── __init__.py
│ ├── api.py
│ └── entrypoint.py
├── dataset_references-1.0.0.supx # Packaged extension file (generated)
└── README.md # Extension documentation
```
## 🤝 Contributing
We welcome contributions! Please see the [Contributing Guide](https://github.com/apache/superset/blob/master/CONTRIBUTING.md) for details.
## 📄 License
Licensed under the Apache License, Version 2.0. See [LICENSE](https://github.com/apache/superset/blob/master/LICENSE.txt) for details.
## 🔗 Links
- [Apache Superset](https://superset.apache.org/)
- [Extension Development Guide](https://superset.apache.org/docs/extensions/)
- [API Documentation](https://superset.apache.org/docs/api/)
- [GitHub Repository](https://github.com/apache/superset)
- [Community](https://superset.apache.org/community/)
---
**Note**: This package is currently in early development. APIs and commands may change before the 1.0.0 release. Please check the [changelog](CHANGELOG.md) for breaking changes between versions.

View File

@@ -0,0 +1,125 @@
# 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.
[project]
name = "apache-superset-extensions-cli"
version = "0.0.1rc2"
description = "Official command-line interface for building, bundling, and managing Apache Superset extensions"
readme = "README.md"
authors = [
{ name = "Apache Software Foundation", email = "dev@superset.apache.org" },
]
license = { file="LICENSE.txt" }
requires-python = ">=3.10"
keywords = ["superset", "apache", "cli", "extensions", "analytics", "business-intelligence", "development-tools"]
classifiers = [
"Development Status :: 3 - Alpha",
"Environment :: Console",
"Intended Audience :: Developers",
"License :: OSI Approved :: Apache Software License",
"Operating System :: OS Independent",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Topic :: Database",
"Topic :: Scientific/Engineering :: Visualization",
"Topic :: Software Development :: Build Tools",
"Topic :: Software Development :: Libraries :: Python Modules",
"Topic :: System :: Software Distribution",
]
dependencies = [
# no bounds for apache-superset-core until we have a stable version
"apache-superset-core",
"click>=8.0.3",
"jinja2>=3.1.4",
"semver>=3.0.4",
"tomli>=2.2.1; python_version < '3.11'",
"watchdog>=6.0.0",
]
[project.urls]
Homepage = "https://superset.apache.org/"
Documentation = "https://superset.apache.org/docs/"
Repository = "https://github.com/apache/superset"
"Bug Tracker" = "https://github.com/apache/superset/issues"
Changelog = "https://github.com/apache/superset/blob/master/CHANGELOG.md"
[project.optional-dependencies]
test = [
"pytest",
"pytest-cov",
"pytest-mock",
]
[build-system]
requires = ["setuptools>=76.0.0", "wheel"]
build-backend = "setuptools.build_meta"
[tool.setuptools]
package-dir = { "" = "src" }
include-package-data = true
[tool.setuptools.packages.find]
where = ["src"]
[tool.setuptools.package-data]
superset_extensions_cli = ["templates/**/*"]
[project.scripts]
superset-extensions = "superset_extensions_cli.cli:app"
[tool.pytest.ini_options]
testpaths = ["tests"]
python_files = ["test_*.py", "*_test.py"]
python_classes = ["Test*"]
python_functions = ["test_*"]
addopts = [
"--strict-markers",
"--strict-config",
"--verbose",
"--cov=superset_extensions_cli",
"--cov-report=term-missing",
"--cov-report=html:htmlcov"
]
markers = [
"unit: Unit tests",
"integration: Integration tests",
"cli: CLI command tests",
"slow: Slow running tests",
]
[tool.coverage.run]
source = ["src/superset_extensions_cli"]
omit = ["*/tests/*", "*/test_*"]
[tool.coverage.report]
exclude_lines = [
"pragma: no cover",
"def __repr__",
"if self.debug:",
"if settings.DEBUG",
"raise AssertionError",
"raise NotImplementedError",
"if 0:",
"if __name__ == .__main__.:",
"class .*\\bProtocol\\):",
"@(abc\\.)?abstractmethod",
]
[tool.ruff.lint.per-file-ignores]
"src/superset_extensions_cli/*" = ["TID251"]

View File

@@ -0,0 +1,16 @@
# 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.

View File

@@ -0,0 +1,471 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
import json # noqa: TID251
import re
import shutil
import subprocess
import sys
import time
import zipfile
from pathlib import Path
from typing import Any, Callable, cast
import click
import semver
from jinja2 import Environment, FileSystemLoader
from superset_core.extensions.types import Manifest, Metadata
from watchdog.events import FileSystemEventHandler
from watchdog.observers import Observer
from superset_extensions_cli.constants import MIN_NPM_VERSION
from superset_extensions_cli.utils import read_json, read_toml
REMOTE_ENTRY_REGEX = re.compile(r"^remoteEntry\..+\.js$")
FRONTEND_DIST_REGEX = re.compile(r"/frontend/dist")
def validate_npm() -> None:
"""Abort if `npm` is not on PATH."""
if shutil.which("npm") is None:
click.secho(
"❌ npm is not installed or not on your PATH.",
err=True,
fg="red",
)
sys.exit(1)
try:
result = subprocess.run( # noqa: S603
["npm", "-v"], # noqa: S607
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
)
if result.returncode != 0:
click.secho(
f"❌ Failed to run `npm -v`: {result.stderr.strip()}",
err=True,
fg="red",
)
sys.exit(1)
npm_version = result.stdout.strip()
if semver.compare(npm_version, MIN_NPM_VERSION) < 0:
click.secho(
f"❌ npm version {npm_version} is lower than the required {MIN_NPM_VERSION}.", # noqa: E501
err=True,
fg="red",
)
sys.exit(1)
except FileNotFoundError:
click.secho(
"❌ npm was not found when checking its version.",
err=True,
fg="red",
)
sys.exit(1)
def init_frontend_deps(frontend_dir: Path) -> None:
"""
If node_modules is missing under `frontend_dir`, run `npm ci` if package-lock.json
exists, otherwise run `npm i`.
"""
node_modules = frontend_dir / "node_modules"
if not node_modules.exists():
package_lock = frontend_dir / "package-lock.json"
if package_lock.exists():
click.secho("⚙️ node_modules not found, running `npm ci`…", fg="cyan")
npm_command = ["npm", "ci"]
error_msg = "❌ `npm ci` failed. Aborting."
else:
click.secho("⚙️ node_modules not found, running `npm i`…", fg="cyan")
npm_command = ["npm", "i"]
error_msg = "❌ `npm i` failed. Aborting."
validate_npm()
res = subprocess.run( # noqa: S603
npm_command, # noqa: S607
cwd=frontend_dir,
text=True,
)
if res.returncode != 0:
click.secho(error_msg, err=True, fg="red")
sys.exit(1)
click.secho("✅ Dependencies installed", fg="green")
def clean_dist(cwd: Path) -> None:
dist_dir = cwd / "dist"
if dist_dir.exists():
shutil.rmtree(dist_dir)
dist_dir.mkdir(parents=True)
def clean_dist_frontend(cwd: Path) -> None:
frontend_dist = cwd / "dist" / "frontend"
if frontend_dist.exists():
shutil.rmtree(frontend_dist)
def build_manifest(cwd: Path, remote_entry: str | None) -> Manifest:
extension: Metadata = cast(Metadata, read_json(cwd / "extension.json"))
if not extension:
click.secho("❌ extension.json not found.", err=True, fg="red")
sys.exit(1)
manifest: Manifest = {
"id": extension["id"],
"name": extension["name"],
"version": extension["version"],
"permissions": extension["permissions"],
"dependencies": extension.get("dependencies", []),
}
if (
(frontend := extension.get("frontend"))
and (contributions := frontend.get("contributions"))
and (module_federation := frontend.get("moduleFederation"))
and remote_entry
):
manifest["frontend"] = {
"contributions": contributions,
"moduleFederation": module_federation,
"remoteEntry": remote_entry,
}
if entry_points := extension.get("backend", {}).get("entryPoints"):
manifest["backend"] = {"entryPoints": entry_points}
return manifest
def write_manifest(cwd: Path, manifest: Manifest) -> None:
dist_dir = cwd / "dist"
(dist_dir / "manifest.json").write_text(
json.dumps(manifest, indent=2, sort_keys=True)
)
click.secho("✅ Manifest updated", fg="green")
def run_frontend_build(frontend_dir: Path) -> subprocess.CompletedProcess[str]:
click.echo()
click.secho("⚙️ Building frontend assets…", fg="cyan")
return subprocess.run( # noqa: S603
["npm", "run", "build"], # noqa: S607
cwd=frontend_dir,
text=True,
)
def copy_frontend_dist(cwd: Path) -> str:
dist_dir = cwd / "dist"
frontend_dist = cwd / "frontend" / "dist"
remote_entry: str | None = None
for f in frontend_dist.rglob("*"):
if not f.is_file():
continue
if REMOTE_ENTRY_REGEX.match(f.name):
remote_entry = f.name
tgt = dist_dir / f.relative_to(cwd)
tgt.parent.mkdir(parents=True, exist_ok=True)
shutil.copy2(f, tgt)
if not remote_entry:
click.secho("❌ No remote entry file found.", err=True, fg="red")
sys.exit(1)
return remote_entry
def copy_backend_files(cwd: Path) -> None:
dist_dir = cwd / "dist"
extension = read_json(cwd / "extension.json")
if not extension:
click.secho("❌ No extension.json file found.", err=True, fg="red")
sys.exit(1)
for pat in extension.get("backend", {}).get("files", []):
for f in cwd.glob(pat):
if not f.is_file():
continue
tgt = dist_dir / f.relative_to(cwd)
tgt.parent.mkdir(parents=True, exist_ok=True)
shutil.copy2(f, tgt)
def rebuild_frontend(cwd: Path, frontend_dir: Path) -> str | None:
"""Clean and rebuild frontend, return the remoteEntry filename."""
clean_dist_frontend(cwd)
res = run_frontend_build(frontend_dir)
if res.returncode != 0:
click.secho("❌ Frontend build failed", fg="red")
return None
remote_entry = copy_frontend_dist(cwd)
click.secho("✅ Frontend rebuilt", fg="green")
return remote_entry
def rebuild_backend(cwd: Path) -> None:
"""Copy backend files (no manifest update)."""
copy_backend_files(cwd)
click.secho("✅ Backend files synced", fg="green")
class FrontendChangeHandler(FileSystemEventHandler):
def __init__(self, trigger_build: Callable[[], None]):
self.trigger_build = trigger_build
def on_any_event(self, event: Any) -> None:
if FRONTEND_DIST_REGEX.search(event.src_path):
return
click.secho(f"🔁 Frontend change detected: {event.src_path}", fg="yellow")
self.trigger_build()
@click.group(help="CLI for validating and bundling Superset extensions.")
def app() -> None:
pass
@app.command()
def validate() -> None:
validate_npm()
click.secho("✅ Validation successful", fg="green")
@app.command()
@click.pass_context
def build(ctx: click.Context) -> None:
ctx.invoke(validate)
cwd = Path.cwd()
frontend_dir = cwd / "frontend"
backend_dir = cwd / "backend"
clean_dist(cwd)
# Build frontend if it exists
remote_entry = None
if frontend_dir.exists():
init_frontend_deps(frontend_dir)
remote_entry = rebuild_frontend(cwd, frontend_dir)
# Build backend independently if it exists
if backend_dir.exists():
pyproject = read_toml(backend_dir / "pyproject.toml")
if pyproject:
rebuild_backend(cwd)
# Build manifest and write it
manifest = build_manifest(cwd, remote_entry)
write_manifest(cwd, manifest)
click.secho("✅ Full build completed in dist/", fg="green")
@app.command()
@click.option(
"--output",
"-o",
type=click.Path(path_type=Path, dir_okay=True, file_okay=True, writable=True),
help="Optional output path or filename for the bundle.",
)
@click.pass_context
def bundle(ctx: click.Context, output: Path | None) -> None:
ctx.invoke(build)
cwd = Path.cwd()
dist_dir = cwd / "dist"
manifest_path = dist_dir / "manifest.json"
if not manifest_path.exists():
click.secho(
"❌ dist/manifest.json not found. Run `build` first.", err=True, fg="red"
)
sys.exit(1)
manifest = json.loads(manifest_path.read_text())
id_ = manifest["id"]
version = manifest["version"]
default_filename = f"{id_}-{version}.supx"
if output is None:
zip_path = Path(default_filename)
elif output.is_dir():
zip_path = output / default_filename
else:
zip_path = output
try:
with zipfile.ZipFile(zip_path, "w", zipfile.ZIP_DEFLATED) as zipf:
for file in dist_dir.rglob("*"):
if file.is_file():
arcname = file.relative_to(dist_dir)
zipf.write(file, arcname)
except Exception as ex:
click.secho(f"❌ Failed to create bundle: {ex}", err=True, fg="red")
sys.exit(1)
click.secho(f"✅ Bundle created: {zip_path}", fg="green")
@app.command()
@click.pass_context
def dev(ctx: click.Context) -> None:
cwd = Path.cwd()
frontend_dir = cwd / "frontend"
backend_dir = cwd / "backend"
clean_dist(cwd)
# Build frontend if it exists
remote_entry = None
if frontend_dir.exists():
init_frontend_deps(frontend_dir)
remote_entry = rebuild_frontend(cwd, frontend_dir)
# Build backend if it exists
if backend_dir.exists():
rebuild_backend(cwd)
manifest = build_manifest(cwd, remote_entry)
write_manifest(cwd, manifest)
def frontend_watcher() -> None:
if frontend_dir.exists():
if (remote_entry := rebuild_frontend(cwd, frontend_dir)) is not None:
manifest = build_manifest(cwd, remote_entry)
write_manifest(cwd, manifest)
def backend_watcher() -> None:
if backend_dir.exists():
rebuild_backend(cwd)
dist_dir = cwd / "dist"
manifest_path = dist_dir / "manifest.json"
if manifest_path.exists():
manifest = json.loads(manifest_path.read_text())
write_manifest(cwd, manifest)
# Build watch message based on existing directories
watch_dirs = []
if frontend_dir.exists():
watch_dirs.append(str(frontend_dir))
if backend_dir.exists():
watch_dirs.append(str(backend_dir))
if watch_dirs:
click.secho(f"👀 Watching for changes in: {', '.join(watch_dirs)}", fg="green")
else:
click.secho("⚠️ No frontend or backend directories found to watch", fg="yellow")
observer = Observer()
# Only set up watchers for directories that exist
if frontend_dir.exists():
frontend_handler = FrontendChangeHandler(trigger_build=frontend_watcher)
observer.schedule(frontend_handler, str(frontend_dir), recursive=True)
if backend_dir.exists():
backend_handler = FileSystemEventHandler()
backend_handler.on_any_event = lambda event: backend_watcher()
observer.schedule(backend_handler, str(backend_dir), recursive=True)
if watch_dirs:
observer.start()
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
click.secho("\n🛑 Stopping watch mode", fg="blue")
observer.stop()
observer.join()
else:
click.secho("❌ No directories to watch. Exiting.", fg="red")
@app.command()
def init() -> None:
id_ = click.prompt("Extension ID (unique identifier, alphanumeric only)", type=str)
if not re.match(r"^[a-zA-Z0-9_]+$", id_):
click.secho(
"❌ ID must be alphanumeric (letters, digits, underscore).", fg="red"
)
sys.exit(1)
name = click.prompt("Extension name (human-readable display name)", type=str)
version = click.prompt("Initial version", default="0.1.0")
license = click.prompt("License", default="Apache-2.0")
include_frontend = click.confirm("Include frontend?", default=True)
include_backend = click.confirm("Include backend?", default=True)
target_dir = Path.cwd() / id_
if target_dir.exists():
click.secho(f"❌ Directory {target_dir} already exists.", fg="red")
sys.exit(1)
# Set up Jinja environment
templates_dir = Path(__file__).parent / "templates"
env = Environment(loader=FileSystemLoader(templates_dir)) # noqa: S701
ctx = {
"id": id_,
"name": name,
"include_frontend": include_frontend,
"include_backend": include_backend,
"license": license,
"version": version,
}
# Create base directory
target_dir.mkdir()
extension_json = env.get_template("extension.json.j2").render(ctx)
(target_dir / "extension.json").write_text(extension_json)
click.secho("✅ Created extension.json", fg="green")
# Copy frontend template
if include_frontend:
frontend_dir = target_dir / "frontend"
frontend_dir.mkdir()
# package.json
package_json = env.get_template("frontend/package.json.j2").render(ctx)
(frontend_dir / "package.json").write_text(package_json)
click.secho("✅ Created frontend folder structure", fg="green")
# Copy backend template
if include_backend:
backend_dir = target_dir / "backend"
backend_dir.mkdir()
# pyproject.toml
pyproject_toml = env.get_template("backend/pyproject.toml.j2").render(ctx)
(backend_dir / "pyproject.toml").write_text(pyproject_toml)
click.secho("✅ Created backend folder structure", fg="green")
click.secho(
f"🎉 Extension {name} (ID: {id_}) initialized at {target_dir}", fg="cyan"
)
if __name__ == "__main__":
app()

View File

@@ -0,0 +1,19 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
MIN_NPM_VERSION = "10.8.2"

View File

@@ -0,0 +1,4 @@
[project]
name = "{{ id }}"
version = "{{ version }}"
license = "{{ license }}"

View File

@@ -0,0 +1,25 @@
{
"id": "{{ id }}",
"name": "{{ name }}",
"version": "{{ version }}",
"license": "{{ license }}",
{% if include_frontend -%}
"frontend": {
"contributions": {
"commands": [],
"views": [],
"menus": []
},
"moduleFederation": {
"exposes": ["./index"]
}
},
{% endif -%}
{% if include_backend -%}
"backend": {
"entryPoints": ["{{ id }}.entrypoint"],
"files": ["backend/src/{{ id }}/**/*.py"]
},
{% endif -%}
"permissions": []
}

View File

@@ -0,0 +1,34 @@
{
"name": "{{ id }}",
"version": "{{ version }}",
"main": "dist/main.js",
"types": "dist/publicAPI.d.ts",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "webpack serve --mode development",
"build": "webpack --stats-error-details --mode production"
},
"keywords": [],
"private": true,
"author": "",
"license": "{{ license }}",
"description": "",
"peerDependencies": {
"@apache-superset/core": "file:../../../superset-frontend/packages/superset-core",
"react": "^17.0.2",
"react-dom": "^17.0.2"
},
"devDependencies": {
"@babel/preset-react": "^7.26.3",
"@babel/preset-typescript": "^7.26.0",
"@types/react": "^19.0.10",
"copy-webpack-plugin": "^13.0.0",
"install": "^0.13.0",
"npm": "^11.1.0",
"ts-loader": "^9.5.2",
"typescript": "^5.8.2",
"webpack": "^5.98.0",
"webpack-cli": "^6.0.1",
"webpack-dev-server": "^5.2.0"
}
}

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.
import json # noqa: TID251
import sys
from pathlib import Path
from typing import Any
if sys.version_info >= (3, 11):
import tomllib
else:
import tomli as tomllib
def read_toml(path: Path) -> dict[str, Any] | None:
if not path.is_file():
return None
with path.open("rb") as f:
return tomllib.load(f)
def read_json(path: Path) -> dict[str, Any] | None:
path = Path(path)
if not path.is_file():
return None
return json.loads(path.read_text())

View File

@@ -0,0 +1,206 @@
<!--
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.
-->
# 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.
# Superset CLI Tests
This directory contains tests for the superset-extensions-cli package, focusing on the `init` command and other CLI functionality.
## Test Structure
### Core Test Files
- **`test_cli_init.py`**: Comprehensive tests for the `init` command scaffolder
- **`test_templates.py`**: Unit tests for Jinja2 template rendering
- **`conftest.py`**: Pytest fixtures and configuration
- **`utils.py`**: Reusable testing utilities and helpers
### Test Categories
#### Unit Tests (`@pytest.mark.unit`)
- Template rendering functionality
- Individual function testing
- Input validation logic
#### Integration Tests (`@pytest.mark.integration`)
- Complete CLI command workflows
- End-to-end scaffolding processes
#### CLI Tests (`@pytest.mark.cli`)
- Click command interface testing
- User input simulation
- Command output verification
## Testing Approach for Scaffolders/Generators
The tests use these patterns for testing code generators:
### 1. Isolated Environment Testing
```python
@pytest.fixture
def isolated_filesystem(tmp_path):
"""Provide isolated temporary directory for each test."""
```
### 2. Click CLI Testing Framework
```python
from click.testing import CliRunner
runner = CliRunner()
result = runner.invoke(app, ["init"], input="...")
```
### 3. File Structure Validation
```python
from tests.utils import assert_file_structure, assert_directory_structure
assert_file_structure(extension_path, expected_files)
```
### 4. Template Content Verification
```python
from tests.utils import assert_json_content
assert_json_content(json_path, {"name": "expected_value"})
```
### 5. Parametrized Testing
```python
@pytest.mark.parametrize("include_frontend,include_backend", [
(True, True), (True, False), (False, True), (False, False)
])
```
## Key Test Cases
### Init Command Tests
- ✅ Creates extension with both frontend and backend
- ✅ Creates frontend-only extensions
- ✅ Creates backend-only extensions
- ✅ Validates extension naming (alphanumeric + underscore only)
- ✅ Handles existing directory conflicts
- ✅ Verifies generated file content accuracy
- ✅ Tests custom version and license inputs
- ✅ Integration test for complete workflow
### Template Rendering Tests
- ✅ Extension.json template with various configurations
- ✅ Package.json template rendering
- ✅ Pyproject.toml template rendering
- ✅ Template validation with different names/versions/licenses
- ✅ JSON validity verification
- ✅ Whitespace and formatting checks
## Running Tests
### All tests
```bash
pytest
```
### Specific test categories
```bash
pytest -m unit # Unit tests only
pytest -m integration # Integration tests only
pytest -m cli # CLI tests only
```
### With coverage
```bash
pytest --cov=superset_extensions_cli --cov-report=html
```
### Specific test files
```bash
pytest tests/test_cli_init.py
pytest tests/test_templates.py
```
## Reusable Testing Infrastructure
The testing infrastructure is designed for reusability:
### Test Utilities (`tests/utils.py`)
- `assert_file_exists()` / `assert_directory_exists()`
- `assert_file_structure()` / `assert_directory_structure()`
- `assert_json_content()` / `load_json_file()`
- `create_test_extension_structure()` - Helper for expected structures
### Fixtures (`tests/conftest.py`)
- `cli_runner` - Click CLI runner
- `isolated_filesystem` - Temporary directory with cleanup
- `extension_params` - Default extension parameters
- `cli_input_*` - Pre-configured user inputs
This infrastructure can be easily extended for testing additional CLI commands like `build`, `bundle`, `dev`, and `validate`.
## Best Practices Implemented
1. **Isolation**: Each test runs in its own temporary directory
2. **Comprehensive Coverage**: Tests cover happy paths, edge cases, and error conditions
3. **Realistic Testing**: Uses actual Click CLI runner with realistic user input
4. **Content Verification**: Validates both file existence and content accuracy
5. **Template Testing**: Separates template rendering logic from CLI integration
6. **Reusable Components**: Utilities and fixtures designed for extension
7. **Clear Documentation**: Well-documented test cases and helper functions
8. **Type Safety**: Uses modern Python type annotations with `from __future__ import annotations`

View File

@@ -0,0 +1,16 @@
# 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.

View File

@@ -0,0 +1,136 @@
# 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.
from __future__ import annotations
import os
from pathlib import Path
import pytest
from click.testing import CliRunner
@pytest.fixture
def cli_runner():
"""Provide a Click CLI runner for testing commands."""
return CliRunner()
@pytest.fixture
def isolated_filesystem(tmp_path):
"""
Provide an isolated temporary directory and change to it.
This ensures tests don't interfere with each other.
"""
original_cwd = Path.cwd()
os.chdir(tmp_path)
yield tmp_path
os.chdir(original_cwd)
@pytest.fixture
def extension_params():
"""Default parameters for extension creation."""
return {
"id": "test_extension",
"name": "Test Extension",
"version": "0.1.0",
"license": "Apache-2.0",
"include_frontend": True,
"include_backend": True,
}
@pytest.fixture
def cli_input_both():
"""CLI input for creating extension with both frontend and backend."""
return "test_extension\nTest Extension\n0.1.0\nApache-2.0\ny\ny\n"
@pytest.fixture
def cli_input_frontend_only():
"""CLI input for creating extension with frontend only."""
return "test_extension\nTest Extension\n0.1.0\nApache-2.0\ny\nn\n"
@pytest.fixture
def cli_input_backend_only():
"""CLI input for creating extension with backend only."""
return "test_extension\nTest Extension\n0.1.0\nApache-2.0\nn\ny\n"
@pytest.fixture
def cli_input_neither():
"""CLI input for creating extension with neither frontend nor backend."""
return "test_extension\nTest Extension\n0.1.0\nApache-2.0\nn\nn\n"
@pytest.fixture
def extension_setup_for_dev():
"""Set up extension structure for dev testing."""
def _setup(base_path: Path) -> None:
import json
# Create extension.json
extension_json = {
"id": "test_extension",
"name": "Test Extension",
"version": "1.0.0",
"permissions": [],
}
(base_path / "extension.json").write_text(json.dumps(extension_json))
# Create frontend and backend directories
(base_path / "frontend").mkdir()
(base_path / "backend").mkdir()
return _setup
@pytest.fixture
def extension_setup_for_bundling():
"""Set up a complete extension structure ready for bundling."""
def _setup(base_path: Path) -> None:
import json
# Create dist directory with manifest and files
dist_dir = base_path / "dist"
dist_dir.mkdir(parents=True)
# Create manifest.json
manifest = {
"id": "test_extension",
"name": "Test Extension",
"version": "1.0.0",
"permissions": [],
}
(dist_dir / "manifest.json").write_text(json.dumps(manifest))
# Create some frontend files
frontend_dir = dist_dir / "frontend" / "dist"
frontend_dir.mkdir(parents=True)
(frontend_dir / "remoteEntry.abc123.js").write_text("// remote entry")
(frontend_dir / "main.js").write_text("// main js")
# Create some backend files
backend_dir = dist_dir / "backend" / "src" / "test_extension"
backend_dir.mkdir(parents=True)
(backend_dir / "__init__.py").write_text("# init")
return _setup

View File

@@ -0,0 +1,552 @@
# 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.
from __future__ import annotations
import json
from unittest.mock import Mock, patch
import pytest
from superset_extensions_cli.cli import (
app,
build_manifest,
clean_dist,
copy_backend_files,
copy_frontend_dist,
init_frontend_deps,
)
from tests.utils import (
assert_directory_exists,
assert_file_exists,
)
@pytest.fixture
def extension_with_build_structure():
"""Create extension structure suitable for build testing."""
def _create(base_path, include_frontend=True, include_backend=True):
# Create required directories
if include_frontend:
frontend_dir = base_path / "frontend"
frontend_dir.mkdir()
if include_backend:
backend_dir = base_path / "backend"
backend_dir.mkdir()
# Create extension.json
extension_json = {
"id": "test_extension",
"name": "Test Extension",
"version": "1.0.0",
"permissions": [],
}
if include_frontend:
extension_json["frontend"] = {
"contributions": {"commands": []},
"moduleFederation": {"exposes": ["./index"]},
}
if include_backend:
extension_json["backend"] = {"entryPoints": ["test_extension.entrypoint"]}
(base_path / "extension.json").write_text(json.dumps(extension_json))
return {
"frontend_dir": frontend_dir if include_frontend else None,
"backend_dir": backend_dir if include_backend else None,
}
return _create
# Build Command Tests
@pytest.mark.cli
@patch("superset_extensions_cli.cli.validate_npm")
@patch("superset_extensions_cli.cli.init_frontend_deps")
@patch("superset_extensions_cli.cli.rebuild_frontend")
@patch("superset_extensions_cli.cli.rebuild_backend")
@patch("superset_extensions_cli.cli.read_toml")
def test_build_command_success_flow(
mock_read_toml,
mock_rebuild_backend,
mock_rebuild_frontend,
mock_init_frontend_deps,
mock_validate_npm,
cli_runner,
isolated_filesystem,
extension_with_build_structure,
):
"""Test build command success flow."""
# Setup mocks
mock_rebuild_frontend.return_value = "remoteEntry.abc123.js"
mock_read_toml.return_value = {"project": {"name": "test"}}
# Create extension structure
dirs = extension_with_build_structure(isolated_filesystem)
result = cli_runner.invoke(app, ["build"])
assert result.exit_code == 0
assert "✅ Full build completed in dist/" in result.output
# Verify function calls
mock_validate_npm.assert_called_once()
mock_init_frontend_deps.assert_called_once_with(dirs["frontend_dir"])
mock_rebuild_frontend.assert_called_once()
mock_rebuild_backend.assert_called_once()
@pytest.mark.cli
@patch("superset_extensions_cli.cli.validate_npm")
@patch("superset_extensions_cli.cli.init_frontend_deps")
@patch("superset_extensions_cli.cli.rebuild_frontend")
def test_build_command_handles_frontend_build_failure(
mock_rebuild_frontend,
mock_init_frontend_deps,
mock_validate_npm,
cli_runner,
isolated_filesystem,
extension_with_build_structure,
):
"""Test build command handles frontend build failure."""
# Setup mocks
mock_rebuild_frontend.return_value = None # Indicates failure
# Create extension structure
extension_with_build_structure(isolated_filesystem)
result = cli_runner.invoke(app, ["build"])
# Command should complete and create manifest even with frontend failure
assert result.exit_code == 0
assert "✅ Full build completed in dist/" in result.output
# Clean Dist Tests
@pytest.mark.unit
def test_clean_dist_removes_existing_dist_directory(isolated_filesystem):
"""Test clean_dist removes existing dist directory and recreates it."""
# Create dist directory with some content
dist_dir = isolated_filesystem / "dist"
dist_dir.mkdir()
(dist_dir / "some_file.txt").write_text("test content")
(dist_dir / "subdir").mkdir()
clean_dist(isolated_filesystem)
# Should exist but be empty
assert_directory_exists(dist_dir)
assert list(dist_dir.iterdir()) == []
@pytest.mark.unit
def test_clean_dist_creates_dist_directory_if_missing(isolated_filesystem):
"""Test clean_dist creates dist directory when it doesn't exist."""
dist_dir = isolated_filesystem / "dist"
assert not dist_dir.exists()
clean_dist(isolated_filesystem)
assert_directory_exists(dist_dir)
# Frontend Dependencies Tests
@pytest.mark.unit
@patch("subprocess.run")
def test_init_frontend_deps_skips_when_node_modules_exists(
mock_run, isolated_filesystem
):
"""Test init_frontend_deps skips npm ci when node_modules exists."""
frontend_dir = isolated_filesystem / "frontend"
frontend_dir.mkdir()
(frontend_dir / "node_modules").mkdir()
init_frontend_deps(frontend_dir)
# Should not call subprocess.run for npm ci
mock_run.assert_not_called()
@pytest.mark.unit
@patch("subprocess.run")
@patch("superset_extensions_cli.cli.validate_npm")
def test_init_frontend_deps_runs_npm_i_when_missing(
mock_validate_npm, mock_run, isolated_filesystem
):
"""Test init_frontend_deps runs npm ci when node_modules is missing."""
frontend_dir = isolated_filesystem / "frontend"
frontend_dir.mkdir()
# Mock successful npm ci
mock_run.return_value = Mock(returncode=0)
init_frontend_deps(frontend_dir)
# Should validate npm and run npm ci
mock_validate_npm.assert_called_once()
mock_run.assert_called_once_with(["npm", "i"], cwd=frontend_dir, text=True)
@pytest.mark.unit
@patch("subprocess.run")
@patch("superset_extensions_cli.cli.validate_npm")
def test_init_frontend_deps_exits_on_npm_ci_failure(
mock_validate_npm, mock_run, isolated_filesystem
):
"""Test init_frontend_deps exits when npm ci fails."""
frontend_dir = isolated_filesystem / "frontend"
frontend_dir.mkdir()
# Mock failed npm ci
mock_run.return_value = Mock(returncode=1)
with pytest.raises(SystemExit) as exc_info:
init_frontend_deps(frontend_dir)
assert exc_info.value.code == 1
# Build Manifest Tests
@pytest.mark.unit
def test_build_manifest_creates_correct_manifest_structure(isolated_filesystem):
"""Test build_manifest creates correct manifest from extension.json."""
# Create extension.json
extension_data = {
"id": "test_extension",
"name": "Test Extension",
"version": "1.0.0",
"permissions": ["read_data"],
"dependencies": ["some_dep"],
"frontend": {
"contributions": {"commands": ["test_command"]},
"moduleFederation": {"exposes": ["./index"]},
},
"backend": {"entryPoints": ["test_extension.entrypoint"]},
}
extension_json = isolated_filesystem / "extension.json"
extension_json.write_text(json.dumps(extension_data))
manifest = build_manifest(isolated_filesystem, "remoteEntry.abc123.js")
# Verify manifest structure
manifest_dict = dict(manifest)
assert manifest_dict["id"] == "test_extension"
assert manifest_dict["name"] == "Test Extension"
assert manifest_dict["version"] == "1.0.0"
assert manifest_dict["permissions"] == ["read_data"]
assert manifest_dict["dependencies"] == ["some_dep"]
# Verify frontend section
assert "frontend" in manifest
frontend = manifest["frontend"]
assert frontend["contributions"] == {"commands": ["test_command"]}
assert frontend["moduleFederation"] == {"exposes": ["./index"]}
assert frontend["remoteEntry"] == "remoteEntry.abc123.js"
# Verify backend section
assert "backend" in manifest
assert manifest["backend"]["entryPoints"] == ["test_extension.entrypoint"]
@pytest.mark.unit
def test_build_manifest_handles_minimal_extension(isolated_filesystem):
"""Test build_manifest with minimal extension.json (no frontend/backend)."""
extension_data = {
"id": "minimal_extension",
"name": "Minimal Extension",
"version": "0.1.0",
"permissions": [],
}
extension_json = isolated_filesystem / "extension.json"
extension_json.write_text(json.dumps(extension_data))
manifest = build_manifest(isolated_filesystem, None)
manifest_dict = dict(manifest)
assert manifest_dict["id"] == "minimal_extension"
assert manifest_dict["name"] == "Minimal Extension"
assert manifest_dict["version"] == "0.1.0"
assert manifest_dict["permissions"] == []
assert manifest_dict["dependencies"] == [] # Default empty list
assert "frontend" not in manifest
assert "backend" not in manifest
@pytest.mark.unit
def test_build_manifest_exits_when_extension_json_missing(isolated_filesystem):
"""Test build_manifest exits when extension.json is missing."""
with pytest.raises(SystemExit) as exc_info:
build_manifest(isolated_filesystem, "remoteEntry.js")
assert exc_info.value.code == 1
# Frontend Build Tests
@pytest.mark.unit
def test_clean_dist_frontend_removes_frontend_dist(isolated_filesystem):
"""Test clean_dist_frontend removes frontend/dist directory specifically."""
from superset_extensions_cli.cli import clean_dist_frontend
# Create dist/frontend structure
dist_dir = isolated_filesystem / "dist"
dist_dir.mkdir(parents=True)
frontend_dist = dist_dir / "frontend"
frontend_dist.mkdir()
(frontend_dist / "some_file.js").write_text("content")
clean_dist_frontend(isolated_filesystem)
# Frontend dist should be removed, but dist should remain
assert dist_dir.exists()
assert not frontend_dist.exists()
@pytest.mark.unit
def test_clean_dist_frontend_handles_nonexistent_directory(isolated_filesystem):
"""Test clean_dist_frontend handles case where frontend dist doesn't exist."""
from superset_extensions_cli.cli import clean_dist_frontend
# No dist directory exists
clean_dist_frontend(isolated_filesystem)
# Should not raise error
@pytest.mark.unit
def test_run_frontend_build_with_output_messages(isolated_filesystem):
"""Test run_frontend_build produces expected output messages."""
from superset_extensions_cli.cli import run_frontend_build
frontend_dir = isolated_filesystem / "frontend"
frontend_dir.mkdir()
with patch("subprocess.run") as mock_run:
mock_result = Mock(returncode=0)
mock_run.return_value = mock_result
result = run_frontend_build(frontend_dir)
assert result.returncode == 0
mock_run.assert_called_once_with(
["npm", "run", "build"], cwd=frontend_dir, text=True
)
@pytest.mark.unit
@pytest.mark.parametrize(
"return_code,expected_result",
[
(0, "remoteEntry.abc123.js"),
(1, None),
],
)
def test_rebuild_frontend_handles_build_results(
isolated_filesystem, return_code, expected_result
):
"""Test rebuild_frontend handles different build results."""
from superset_extensions_cli.cli import rebuild_frontend
# Create frontend structure
frontend_dir = isolated_filesystem / "frontend"
frontend_dir.mkdir()
if return_code == 0:
# Create frontend/dist with remoteEntry for success case
frontend_dist = frontend_dir / "dist"
frontend_dist.mkdir()
(frontend_dist / "remoteEntry.abc123.js").write_text("content")
# Create dist directory
dist_dir = isolated_filesystem / "dist"
dist_dir.mkdir()
with patch("superset_extensions_cli.cli.run_frontend_build") as mock_build:
mock_build.return_value = Mock(returncode=return_code)
result = rebuild_frontend(isolated_filesystem, frontend_dir)
assert result == expected_result
# Backend Build Tests
@pytest.mark.unit
def test_rebuild_backend_calls_copy_and_shows_message(isolated_filesystem):
"""Test rebuild_backend calls copy_backend_files and shows success message."""
from superset_extensions_cli.cli import rebuild_backend
# Create extension.json
extension_json = {
"id": "test",
"name": "Test Extension",
"version": "1.0.0",
"permissions": [],
}
(isolated_filesystem / "extension.json").write_text(json.dumps(extension_json))
with patch("superset_extensions_cli.cli.copy_backend_files") as mock_copy:
rebuild_backend(isolated_filesystem)
mock_copy.assert_called_once_with(isolated_filesystem)
@pytest.mark.unit
def test_copy_backend_files_skips_non_files(isolated_filesystem):
"""Test copy_backend_files skips directories and non-files."""
# Create backend structure with directory
backend_src = isolated_filesystem / "backend" / "src" / "test_ext"
backend_src.mkdir(parents=True)
(backend_src / "__init__.py").write_text("# init")
# Create a subdirectory (should be skipped)
subdir = backend_src / "subdir"
subdir.mkdir()
# Create extension.json with backend file patterns
extension_data = {
"id": "test_ext",
"name": "Test Extension",
"version": "1.0.0",
"permissions": [],
"backend": {
"files": ["backend/src/test_ext/**/*"] # Will match both files and dirs
},
}
(isolated_filesystem / "extension.json").write_text(json.dumps(extension_data))
# Create dist directory
clean_dist(isolated_filesystem)
copy_backend_files(isolated_filesystem)
# Verify only files were copied, not directories
dist_dir = isolated_filesystem / "dist"
assert_file_exists(dist_dir / "backend" / "src" / "test_ext" / "__init__.py")
# Directory should not be copied as a file
copied_subdir = dist_dir / "backend" / "src" / "test_ext" / "subdir"
# The directory might exist but should be empty since we skip non-files
if copied_subdir.exists():
assert list(copied_subdir.iterdir()) == []
@pytest.mark.unit
def test_copy_backend_files_copies_matched_files(isolated_filesystem):
"""Test copy_backend_files copies files matching patterns from extension.json."""
# Create backend source files
backend_src = isolated_filesystem / "backend" / "src" / "test_ext"
backend_src.mkdir(parents=True)
(backend_src / "__init__.py").write_text("# init")
(backend_src / "main.py").write_text("# main")
# Create extension.json with backend file patterns
extension_data = {
"id": "test_ext",
"name": "Test Extension",
"version": "1.0.0",
"permissions": [],
"backend": {"files": ["backend/src/test_ext/**/*.py"]},
}
(isolated_filesystem / "extension.json").write_text(json.dumps(extension_data))
# Create dist directory
clean_dist(isolated_filesystem)
copy_backend_files(isolated_filesystem)
# Verify files were copied
dist_dir = isolated_filesystem / "dist"
assert_file_exists(dist_dir / "backend" / "src" / "test_ext" / "__init__.py")
assert_file_exists(dist_dir / "backend" / "src" / "test_ext" / "main.py")
@pytest.mark.unit
def test_copy_backend_files_handles_no_backend_config(isolated_filesystem):
"""Test copy_backend_files handles extension.json without backend config."""
extension_data = {
"id": "frontend_only",
"name": "Frontend Only Extension",
"version": "1.0.0",
"permissions": [],
}
(isolated_filesystem / "extension.json").write_text(json.dumps(extension_data))
clean_dist(isolated_filesystem)
# Should not raise error
copy_backend_files(isolated_filesystem)
@pytest.mark.unit
def test_copy_backend_files_exits_when_extension_json_missing(isolated_filesystem):
"""Test copy_backend_files exits when extension.json is missing."""
clean_dist(isolated_filesystem)
with pytest.raises(SystemExit) as exc_info:
copy_backend_files(isolated_filesystem)
assert exc_info.value.code == 1
# Frontend Dist Copy Tests
@pytest.mark.unit
def test_copy_frontend_dist_copies_files_correctly(isolated_filesystem):
"""Test copy_frontend_dist copies frontend build files to dist."""
# Create frontend/dist structure
frontend_dist = isolated_filesystem / "frontend" / "dist"
frontend_dist.mkdir(parents=True)
# Create some files including remoteEntry
(frontend_dist / "remoteEntry.abc123.js").write_text("remote entry content")
(frontend_dist / "main.js").write_text("main js content")
# Create subdirectory with file
assets_dir = frontend_dist / "assets"
assets_dir.mkdir()
(assets_dir / "style.css").write_text("css content")
# Create dist directory
clean_dist(isolated_filesystem)
remote_entry = copy_frontend_dist(isolated_filesystem)
assert remote_entry == "remoteEntry.abc123.js"
# Verify files were copied
dist_dir = isolated_filesystem / "dist"
assert_file_exists(dist_dir / "frontend" / "dist" / "remoteEntry.abc123.js")
assert_file_exists(dist_dir / "frontend" / "dist" / "main.js")
assert_file_exists(dist_dir / "frontend" / "dist" / "assets" / "style.css")
@pytest.mark.unit
def test_copy_frontend_dist_exits_when_no_remote_entry(isolated_filesystem):
"""Test copy_frontend_dist exits when no remoteEntry file found."""
# Create frontend/dist without remoteEntry file
frontend_dist = isolated_filesystem / "frontend" / "dist"
frontend_dist.mkdir(parents=True)
(frontend_dist / "main.js").write_text("main content")
clean_dist(isolated_filesystem)
with pytest.raises(SystemExit) as exc_info:
copy_frontend_dist(isolated_filesystem)
assert exc_info.value.code == 1

View File

@@ -0,0 +1,255 @@
# 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.
from __future__ import annotations
import json
import zipfile
from unittest.mock import patch
import pytest
from superset_extensions_cli.cli import app
from tests.utils import assert_file_exists
# Bundle Command Tests
@pytest.mark.cli
@patch("superset_extensions_cli.cli.build")
def test_bundle_command_creates_zip_with_default_name(
mock_build, cli_runner, isolated_filesystem, extension_setup_for_bundling
):
"""Test bundle command creates zip file with default name."""
# Mock the build command to do nothing (we'll set up dist manually)
mock_build.return_value = None
# Setup extension for bundling (this creates the dist structure)
extension_setup_for_bundling(isolated_filesystem)
result = cli_runner.invoke(app, ["bundle"])
assert result.exit_code == 0
assert "✅ Bundle created: test_extension-1.0.0.supx" in result.output
# Verify zip file was created
zip_path = isolated_filesystem / "test_extension-1.0.0.supx"
assert_file_exists(zip_path)
# Verify zip contents
with zipfile.ZipFile(zip_path, "r") as zipf:
file_list = zipf.namelist()
assert "manifest.json" in file_list
assert "frontend/dist/remoteEntry.abc123.js" in file_list
assert "frontend/dist/main.js" in file_list
assert "backend/src/test_extension/__init__.py" in file_list
@pytest.mark.cli
@patch("superset_extensions_cli.cli.build")
def test_bundle_command_with_custom_output_filename(
mock_build, cli_runner, isolated_filesystem, extension_setup_for_bundling
):
"""Test bundle command with custom output filename."""
# Mock the build command
mock_build.return_value = None
extension_setup_for_bundling(isolated_filesystem)
custom_name = "my_custom_bundle.supx"
result = cli_runner.invoke(app, ["bundle", "--output", custom_name])
assert result.exit_code == 0
assert f"✅ Bundle created: {custom_name}" in result.output
# Verify custom-named zip file was created
zip_path = isolated_filesystem / custom_name
assert_file_exists(zip_path)
@pytest.mark.cli
@patch("superset_extensions_cli.cli.build")
def test_bundle_command_with_output_directory(
mock_build, cli_runner, isolated_filesystem, extension_setup_for_bundling
):
"""Test bundle command with output directory."""
# Mock the build command
mock_build.return_value = None
extension_setup_for_bundling(isolated_filesystem)
# Create output directory
output_dir = isolated_filesystem / "output"
output_dir.mkdir()
result = cli_runner.invoke(app, ["bundle", "--output", str(output_dir)])
assert result.exit_code == 0
# Verify zip file was created in output directory
expected_path = output_dir / "test_extension-1.0.0.supx"
assert_file_exists(expected_path)
assert f"✅ Bundle created: {expected_path}" in result.output
@pytest.mark.cli
@patch("superset_extensions_cli.cli.build")
def test_bundle_command_fails_without_manifest(
mock_build, cli_runner, isolated_filesystem
):
"""Test bundle command fails when manifest.json doesn't exist."""
# Mock build to succeed but not create manifest
mock_build.return_value = None
# Create empty dist directory
(isolated_filesystem / "dist").mkdir()
result = cli_runner.invoke(app, ["bundle"])
assert result.exit_code == 1
assert "dist/manifest.json not found" in result.output
@pytest.mark.cli
@patch("superset_extensions_cli.cli.build")
def test_bundle_command_handles_zip_creation_error(
mock_build, cli_runner, isolated_filesystem, extension_setup_for_bundling
):
"""Test bundle command handles zip file creation errors."""
# Mock the build command
mock_build.return_value = None
extension_setup_for_bundling(isolated_filesystem)
# Try to bundle to an invalid location (directory that doesn't exist)
invalid_path = isolated_filesystem / "nonexistent" / "bundle.supx"
with patch("zipfile.ZipFile", side_effect=OSError("Permission denied")):
result = cli_runner.invoke(app, ["bundle", "--output", str(invalid_path)])
assert result.exit_code == 1
assert "Failed to create bundle" in result.output
@pytest.mark.cli
@patch("superset_extensions_cli.cli.build")
def test_bundle_includes_all_files_recursively(
mock_build, cli_runner, isolated_filesystem
):
"""Test that bundle includes all files from dist directory recursively."""
# Mock the build command
mock_build.return_value = None
# Create complex dist structure
dist_dir = isolated_filesystem / "dist"
dist_dir.mkdir(parents=True)
# Manifest
manifest = {
"id": "complex_extension",
"name": "Complex Extension",
"version": "2.1.0",
"permissions": [],
}
(dist_dir / "manifest.json").write_text(json.dumps(manifest))
# Frontend files with nested structure
frontend_dir = dist_dir / "frontend" / "dist"
frontend_dir.mkdir(parents=True)
(frontend_dir / "remoteEntry.xyz789.js").write_text("// entry")
assets_dir = frontend_dir / "assets"
assets_dir.mkdir()
(assets_dir / "style.css").write_text("/* css */")
(assets_dir / "image.png").write_bytes(b"fake image data")
# Backend files with nested structure
backend_dir = dist_dir / "backend" / "src" / "complex_extension"
backend_dir.mkdir(parents=True)
(backend_dir / "__init__.py").write_text("# init")
(backend_dir / "core.py").write_text("# core")
utils_dir = backend_dir / "utils"
utils_dir.mkdir()
(utils_dir / "helpers.py").write_text("# helpers")
result = cli_runner.invoke(app, ["bundle"])
assert result.exit_code == 0
# Verify zip file and contents
zip_path = isolated_filesystem / "complex_extension-2.1.0.supx"
assert_file_exists(zip_path)
with zipfile.ZipFile(zip_path, "r") as zipf:
file_list = set(zipf.namelist())
# Verify all files are included
expected_files = {
"manifest.json",
"frontend/dist/remoteEntry.xyz789.js",
"frontend/dist/assets/style.css",
"frontend/dist/assets/image.png",
"backend/src/complex_extension/__init__.py",
"backend/src/complex_extension/core.py",
"backend/src/complex_extension/utils/helpers.py",
}
assert expected_files.issubset(
file_list
), f"Missing files: {expected_files - file_list}"
@pytest.mark.cli
@patch("superset_extensions_cli.cli.build")
def test_bundle_command_short_option(
mock_build, cli_runner, isolated_filesystem, extension_setup_for_bundling
):
"""Test bundle command with short -o option."""
# Mock the build command
mock_build.return_value = None
extension_setup_for_bundling(isolated_filesystem)
result = cli_runner.invoke(app, ["bundle", "-o", "short_option.supx"])
assert result.exit_code == 0
assert "✅ Bundle created: short_option.supx" in result.output
assert_file_exists(isolated_filesystem / "short_option.supx")
@pytest.mark.cli
@pytest.mark.parametrize("output_option", ["--output", "-o"])
@patch("superset_extensions_cli.cli.build")
def test_bundle_command_output_options(
mock_build,
output_option,
cli_runner,
isolated_filesystem,
extension_setup_for_bundling,
):
"""Test bundle command with both long and short output options."""
# Mock the build command
mock_build.return_value = None
extension_setup_for_bundling(isolated_filesystem)
filename = f"test_{output_option.replace('-', '')}.supx"
result = cli_runner.invoke(app, ["bundle", output_option, filename])
assert result.exit_code == 0
assert f"✅ Bundle created: {filename}" in result.output
assert_file_exists(isolated_filesystem / filename)

View File

@@ -0,0 +1,238 @@
# 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.
from __future__ import annotations
import json
import threading
import time
from unittest.mock import Mock, patch
import pytest
from superset_extensions_cli.cli import app, FrontendChangeHandler
# Dev Command Tests
@pytest.mark.cli
@patch("superset_extensions_cli.cli.Observer")
@patch("superset_extensions_cli.cli.init_frontend_deps")
@patch("superset_extensions_cli.cli.rebuild_frontend")
@patch("superset_extensions_cli.cli.rebuild_backend")
@patch("superset_extensions_cli.cli.build_manifest")
@patch("superset_extensions_cli.cli.write_manifest")
def test_dev_command_starts_watchers(
mock_write_manifest,
mock_build_manifest,
mock_rebuild_backend,
mock_rebuild_frontend,
mock_init_frontend_deps,
mock_observer_class,
cli_runner,
isolated_filesystem,
extension_setup_for_dev,
):
"""Test dev command starts file watchers."""
# Setup mocks
mock_rebuild_frontend.return_value = "remoteEntry.abc123.js"
mock_build_manifest.return_value = {"name": "test", "version": "1.0.0"}
mock_observer = Mock()
mock_observer_class.return_value = mock_observer
extension_setup_for_dev(isolated_filesystem)
# Run dev command in a thread since it's blocking
def run_dev():
try:
cli_runner.invoke(app, ["dev"], catch_exceptions=False)
except KeyboardInterrupt:
pass
dev_thread = threading.Thread(target=run_dev)
dev_thread.daemon = True
dev_thread.start()
# Let it start up
time.sleep(0.1)
# Verify observer methods were called
mock_observer.schedule.assert_called()
mock_observer.start.assert_called_once()
# Initial setup calls
mock_init_frontend_deps.assert_called_once()
mock_rebuild_frontend.assert_called()
mock_rebuild_backend.assert_called()
mock_build_manifest.assert_called()
mock_write_manifest.assert_called()
@pytest.mark.cli
@patch("superset_extensions_cli.cli.init_frontend_deps")
@patch("superset_extensions_cli.cli.rebuild_frontend")
@patch("superset_extensions_cli.cli.rebuild_backend")
@patch("superset_extensions_cli.cli.build_manifest")
@patch("superset_extensions_cli.cli.write_manifest")
def test_dev_command_initial_build(
mock_write_manifest,
mock_build_manifest,
mock_rebuild_backend,
mock_rebuild_frontend,
mock_init_frontend_deps,
cli_runner,
isolated_filesystem,
extension_setup_for_dev,
):
"""Test dev command performs initial build setup."""
# Setup mocks
mock_rebuild_frontend.return_value = "remoteEntry.abc123.js"
mock_build_manifest.return_value = {"name": "test", "version": "1.0.0"}
extension_setup_for_dev(isolated_filesystem)
with patch("superset_extensions_cli.cli.Observer") as mock_observer_class:
mock_observer = Mock()
mock_observer_class.return_value = mock_observer
with patch("time.sleep", side_effect=KeyboardInterrupt):
try:
cli_runner.invoke(app, ["dev"], catch_exceptions=False)
except KeyboardInterrupt:
pass
# Verify initial build steps
frontend_dir = isolated_filesystem / "frontend"
mock_init_frontend_deps.assert_called_once_with(frontend_dir)
mock_rebuild_frontend.assert_called_once_with(isolated_filesystem, frontend_dir)
mock_rebuild_backend.assert_called_once_with(isolated_filesystem)
# FrontendChangeHandler Tests
@pytest.mark.unit
def test_frontend_change_handler_init():
"""Test FrontendChangeHandler initialization."""
mock_trigger = Mock()
handler = FrontendChangeHandler(trigger_build=mock_trigger)
assert handler.trigger_build == mock_trigger
@pytest.mark.unit
def test_frontend_change_handler_ignores_dist_changes():
"""Test FrontendChangeHandler ignores changes in dist directory."""
mock_trigger = Mock()
handler = FrontendChangeHandler(trigger_build=mock_trigger)
# Create mock event with dist path
mock_event = Mock()
mock_event.src_path = "/path/to/frontend/dist/file.js"
handler.on_any_event(mock_event)
# Should not trigger build for dist changes
mock_trigger.assert_not_called()
@pytest.mark.unit
@pytest.mark.parametrize(
"source_path",
[
"/path/to/frontend/src/component.tsx",
"/path/to/frontend/webpack.config.js",
"/path/to/frontend/package.json",
],
)
def test_frontend_change_handler_triggers_on_source_changes(source_path):
"""Test FrontendChangeHandler triggers build on source changes."""
mock_trigger = Mock()
handler = FrontendChangeHandler(trigger_build=mock_trigger)
# Create mock event with source path
mock_event = Mock()
mock_event.src_path = source_path
handler.on_any_event(mock_event)
# Should trigger build for source changes
mock_trigger.assert_called_once()
# Dev Utility Functions Tests
@pytest.mark.unit
def test_frontend_watcher_function_coverage(isolated_filesystem):
"""Test frontend watcher function for coverage."""
# Create extension.json
extension_json = {
"id": "test_extension",
"name": "Test Extension",
"version": "1.0.0",
"permissions": [],
}
(isolated_filesystem / "extension.json").write_text(json.dumps(extension_json))
# Create dist directory
dist_dir = isolated_filesystem / "dist"
dist_dir.mkdir()
with patch("superset_extensions_cli.cli.rebuild_frontend") as mock_rebuild:
with patch("superset_extensions_cli.cli.build_manifest") as mock_build:
with patch("superset_extensions_cli.cli.write_manifest") as mock_write:
mock_rebuild.return_value = "remoteEntry.abc123.js"
mock_build.return_value = {"name": "test", "version": "1.0.0"}
# Simulate frontend watcher function logic
frontend_dir = isolated_filesystem / "frontend"
frontend_dir.mkdir()
# Actually call the functions to simulate the frontend_watcher
if (
remote_entry := mock_rebuild(isolated_filesystem, frontend_dir)
) is not None:
manifest = mock_build(isolated_filesystem, remote_entry)
mock_write(isolated_filesystem, manifest)
mock_rebuild.assert_called_once_with(isolated_filesystem, frontend_dir)
mock_build.assert_called_once_with(
isolated_filesystem, "remoteEntry.abc123.js"
)
mock_write.assert_called_once_with(
isolated_filesystem, {"name": "test", "version": "1.0.0"}
)
@pytest.mark.unit
def test_backend_watcher_function_coverage(isolated_filesystem):
"""Test backend watcher function for coverage."""
# Create dist directory with manifest
dist_dir = isolated_filesystem / "dist"
dist_dir.mkdir()
manifest_data = {"name": "test", "version": "1.0.0"}
(dist_dir / "manifest.json").write_text(json.dumps(manifest_data))
with patch("superset_extensions_cli.cli.rebuild_backend") as mock_rebuild:
with patch("superset_extensions_cli.cli.write_manifest") as mock_write:
# Simulate backend watcher function
mock_rebuild(isolated_filesystem)
manifest_path = dist_dir / "manifest.json"
if manifest_path.exists():
manifest = json.loads(manifest_path.read_text())
mock_write(isolated_filesystem, manifest)
mock_rebuild.assert_called_once_with(isolated_filesystem)
mock_write.assert_called_once()

View File

@@ -0,0 +1,362 @@
# 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.
from __future__ import annotations
from pathlib import Path
import pytest
from superset_extensions_cli.cli import app
from tests.utils import (
assert_directory_exists,
assert_directory_structure,
assert_file_exists,
assert_file_structure,
assert_json_content,
create_test_extension_structure,
load_json_file,
)
# Init Command Tests
@pytest.mark.cli
def test_init_creates_extension_with_both_frontend_and_backend(
cli_runner, isolated_filesystem, cli_input_both
):
"""Test that init creates a complete extension with both frontend and backend."""
result = cli_runner.invoke(app, ["init"], input=cli_input_both)
assert result.exit_code == 0, f"Command failed with output: {result.output}"
assert (
"🎉 Extension Test Extension (ID: test_extension) initialized" in result.output
)
# Verify directory structure
extension_path = isolated_filesystem / "test_extension"
assert_directory_exists(extension_path, "main extension directory")
expected_structure = create_test_extension_structure(
isolated_filesystem,
"test_extension",
include_frontend=True,
include_backend=True,
)
# Check directories
assert_directory_structure(extension_path, expected_structure["expected_dirs"])
# Check files
assert_file_structure(extension_path, expected_structure["expected_files"])
@pytest.mark.cli
def test_init_creates_extension_with_frontend_only(
cli_runner, isolated_filesystem, cli_input_frontend_only
):
"""Test that init creates extension with only frontend components."""
result = cli_runner.invoke(app, ["init"], input=cli_input_frontend_only)
assert result.exit_code == 0, f"Command failed with output: {result.output}"
extension_path = isolated_filesystem / "test_extension"
assert_directory_exists(extension_path)
# Should have frontend directory and package.json
assert_directory_exists(extension_path / "frontend")
assert_file_exists(extension_path / "frontend" / "package.json")
# Should NOT have backend directory
backend_path = extension_path / "backend"
assert (
not backend_path.exists()
), "Backend directory should not exist for frontend-only extension"
@pytest.mark.cli
def test_init_creates_extension_with_backend_only(
cli_runner, isolated_filesystem, cli_input_backend_only
):
"""Test that init creates extension with only backend components."""
result = cli_runner.invoke(app, ["init"], input=cli_input_backend_only)
assert result.exit_code == 0, f"Command failed with output: {result.output}"
extension_path = isolated_filesystem / "test_extension"
assert_directory_exists(extension_path)
# Should have backend directory and pyproject.toml
assert_directory_exists(extension_path / "backend")
assert_file_exists(extension_path / "backend" / "pyproject.toml")
# Should NOT have frontend directory
frontend_path = extension_path / "frontend"
assert (
not frontend_path.exists()
), "Frontend directory should not exist for backend-only extension"
@pytest.mark.cli
def test_init_creates_extension_with_neither_frontend_nor_backend(
cli_runner, isolated_filesystem, cli_input_neither
):
"""Test that init creates minimal extension with neither frontend nor backend."""
result = cli_runner.invoke(app, ["init"], input=cli_input_neither)
assert result.exit_code == 0, f"Command failed with output: {result.output}"
extension_path = isolated_filesystem / "test_extension"
assert_directory_exists(extension_path)
# Should only have extension.json
assert_file_exists(extension_path / "extension.json")
# Should NOT have frontend or backend directories
assert not (extension_path / "frontend").exists()
assert not (extension_path / "backend").exists()
@pytest.mark.cli
@pytest.mark.parametrize(
"invalid_name,expected_error",
[
("test-extension", "must be alphanumeric"),
("test extension", "must be alphanumeric"),
("test.extension", "must be alphanumeric"),
("test@extension", "must be alphanumeric"),
("", "must be alphanumeric"),
],
)
def test_init_validates_extension_name(
cli_runner, isolated_filesystem, invalid_name, expected_error
):
"""Test that init validates extension names according to regex pattern."""
cli_input = f"{invalid_name}\n0.1.0\nApache-2.0\ny\ny\n"
result = cli_runner.invoke(app, ["init"], input=cli_input)
assert (
result.exit_code == 1
), f"Expected command to fail for invalid name '{invalid_name}'"
assert expected_error in result.output
@pytest.mark.cli
def test_init_accepts_numeric_extension_name(cli_runner, isolated_filesystem):
"""Test that init accepts numeric extension ids like '123'."""
cli_input = "123\n123\n0.1.0\nApache-2.0\ny\ny\n"
result = cli_runner.invoke(app, ["init"], input=cli_input)
assert result.exit_code == 0, f"Numeric id '123' should be valid: {result.output}"
assert Path("123").exists(), "Directory for '123' should be created"
@pytest.mark.cli
@pytest.mark.parametrize(
"valid_id", ["test123", "TestExtension", "test_extension_123", "MyExt_1"]
)
def test_init_with_valid_alphanumeric_names(cli_runner, valid_id):
"""Test that init accepts various valid alphanumeric names."""
with cli_runner.isolated_filesystem():
cli_input = f"{valid_id}\nTest Extension\n0.1.0\nApache-2.0\ny\ny\n"
result = cli_runner.invoke(app, ["init"], input=cli_input)
assert (
result.exit_code == 0
), f"Valid name '{valid_id}' was rejected: {result.output}"
assert Path(valid_id).exists(), f"Directory for '{valid_id}' was not created"
@pytest.mark.cli
def test_init_fails_when_directory_already_exists(
cli_runner, isolated_filesystem, cli_input_both
):
"""Test that init fails gracefully when target directory already exists."""
# Create the directory first
existing_dir = isolated_filesystem / "test_extension"
existing_dir.mkdir()
result = cli_runner.invoke(app, ["init"], input=cli_input_both)
assert result.exit_code == 1, "Command should fail when directory already exists"
assert "already exists" in result.output
@pytest.mark.cli
def test_extension_json_content_is_correct(
cli_runner, isolated_filesystem, cli_input_both
):
"""Test that the generated extension.json has the correct content."""
result = cli_runner.invoke(app, ["init"], input=cli_input_both)
assert result.exit_code == 0
extension_path = isolated_filesystem / "test_extension"
extension_json_path = extension_path / "extension.json"
# Verify the JSON structure and values
assert_json_content(
extension_json_path,
{
"id": "test_extension",
"name": "Test Extension",
"version": "0.1.0",
"license": "Apache-2.0",
"permissions": [],
},
)
# Load and verify more complex nested structures
content = load_json_file(extension_json_path)
# Verify frontend section exists and has correct structure
assert "frontend" in content
frontend = content["frontend"]
assert "contributions" in frontend
assert "moduleFederation" in frontend
assert frontend["contributions"] == {"commands": [], "views": [], "menus": []}
assert frontend["moduleFederation"] == {"exposes": ["./index"]}
# Verify backend section exists and has correct structure
assert "backend" in content
backend = content["backend"]
assert "entryPoints" in backend
assert "files" in backend
assert backend["entryPoints"] == ["test_extension.entrypoint"]
assert backend["files"] == ["backend/src/test_extension/**/*.py"]
@pytest.mark.cli
def test_frontend_package_json_content_is_correct(
cli_runner, isolated_filesystem, cli_input_both
):
"""Test that the generated frontend/package.json has the correct content."""
result = cli_runner.invoke(app, ["init"], input=cli_input_both)
assert result.exit_code == 0
extension_path = isolated_filesystem / "test_extension"
package_json_path = extension_path / "frontend" / "package.json"
# Verify the package.json structure and values
assert_json_content(
package_json_path,
{
"name": "test_extension",
"version": "0.1.0",
"license": "Apache-2.0",
},
)
# Verify more complex structures
content = load_json_file(package_json_path)
assert "scripts" in content
assert "build" in content["scripts"]
assert "peerDependencies" in content
assert "@apache-superset/core" in content["peerDependencies"]
@pytest.mark.cli
def test_backend_pyproject_toml_is_created(
cli_runner, isolated_filesystem, cli_input_both
):
"""Test that the generated backend/pyproject.toml file is created."""
result = cli_runner.invoke(app, ["init"], input=cli_input_both)
assert result.exit_code == 0
extension_path = isolated_filesystem / "test_extension"
pyproject_path = extension_path / "backend" / "pyproject.toml"
assert_file_exists(pyproject_path, "backend pyproject.toml")
# Basic content verification (without parsing TOML for now)
content = pyproject_path.read_text()
assert "test_extension" in content
assert "0.1.0" in content
assert "Apache-2.0" in content
@pytest.mark.cli
def test_init_command_output_messages(cli_runner, isolated_filesystem, cli_input_both):
"""Test that init command produces expected output messages."""
result = cli_runner.invoke(app, ["init"], input=cli_input_both)
assert result.exit_code == 0
output = result.output
# Check for expected success messages
assert "✅ Created extension.json" in output
assert "✅ Created frontend folder structure" in output
assert "✅ Created backend folder structure" in output
assert "🎉 Extension Test Extension (ID: test_extension) initialized" in output
@pytest.mark.cli
def test_init_with_custom_version_and_license(cli_runner, isolated_filesystem):
"""Test init with custom version and license parameters."""
cli_input = "my_extension\nMy Extension\n2.1.0\nMIT\ny\nn\n"
result = cli_runner.invoke(app, ["init"], input=cli_input)
assert result.exit_code == 0
extension_path = isolated_filesystem / "my_extension"
extension_json_path = extension_path / "extension.json"
assert_json_content(
extension_json_path,
{
"id": "my_extension",
"name": "My Extension",
"version": "2.1.0",
"license": "MIT",
},
)
@pytest.mark.integration
@pytest.mark.cli
def test_full_init_workflow_integration(cli_runner, isolated_filesystem):
"""Integration test for the complete init workflow."""
# Test the complete flow with realistic user input
cli_input = "awesome_charts\nAwesome Charts\n1.0.0\nApache-2.0\ny\ny\n"
result = cli_runner.invoke(app, ["init"], input=cli_input)
# Verify success
assert result.exit_code == 0
# Verify complete directory structure
extension_path = isolated_filesystem / "awesome_charts"
expected_structure = create_test_extension_structure(
isolated_filesystem,
"awesome_charts",
include_frontend=True,
include_backend=True,
)
# Comprehensive structure verification
assert_directory_structure(extension_path, expected_structure["expected_dirs"])
assert_file_structure(extension_path, expected_structure["expected_files"])
# Verify all generated files have correct content
extension_json = load_json_file(extension_path / "extension.json")
assert extension_json["id"] == "awesome_charts"
assert extension_json["name"] == "Awesome Charts"
assert extension_json["version"] == "1.0.0"
assert extension_json["license"] == "Apache-2.0"
package_json = load_json_file(extension_path / "frontend" / "package.json")
assert package_json["name"] == "awesome_charts"
pyproject_content = (extension_path / "backend" / "pyproject.toml").read_text()
assert "awesome_charts" in pyproject_content

View File

@@ -0,0 +1,195 @@
# 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.
from __future__ import annotations
from unittest.mock import Mock, patch
import pytest
from superset_extensions_cli.cli import app, validate_npm
# Validate Command Tests
@pytest.mark.cli
def test_validate_command_success(cli_runner):
"""Test validate command succeeds when npm is available and valid."""
with patch("superset_extensions_cli.cli.validate_npm") as mock_validate:
result = cli_runner.invoke(app, ["validate"])
assert result.exit_code == 0
assert "✅ Validation successful" in result.output
mock_validate.assert_called_once()
@pytest.mark.cli
def test_validate_command_calls_npm_validation(cli_runner):
"""Test that validate command calls the npm validation function."""
with patch("superset_extensions_cli.cli.validate_npm") as mock_validate:
cli_runner.invoke(app, ["validate"])
mock_validate.assert_called_once()
# Validate NPM Function Tests
@pytest.mark.unit
@patch("shutil.which")
def test_validate_npm_fails_when_npm_not_on_path(mock_which):
"""Test validate_npm fails when npm is not on PATH."""
mock_which.return_value = None
with pytest.raises(SystemExit) as exc_info:
validate_npm()
assert exc_info.value.code == 1
mock_which.assert_called_once_with("npm")
@pytest.mark.unit
@patch("shutil.which")
@patch("subprocess.run")
def test_validate_npm_fails_when_npm_command_fails(mock_run, mock_which):
"""Test validate_npm fails when npm -v command fails."""
mock_which.return_value = "/usr/bin/npm"
mock_run.return_value = Mock(returncode=1, stderr="Command failed")
with pytest.raises(SystemExit) as exc_info:
validate_npm()
assert exc_info.value.code == 1
@pytest.mark.unit
@patch("shutil.which")
@patch("subprocess.run")
def test_validate_npm_fails_when_version_too_low(mock_run, mock_which):
"""Test validate_npm fails when npm version is below minimum."""
mock_which.return_value = "/usr/bin/npm"
mock_run.return_value = Mock(returncode=0, stdout="9.0.0\n", stderr="")
with pytest.raises(SystemExit) as exc_info:
validate_npm()
assert exc_info.value.code == 1
@pytest.mark.unit
@pytest.mark.parametrize(
"npm_version",
[
"10.8.2", # Exact minimum version
"11.0.0", # Higher version
"10.9.0-alpha.1", # Pre-release version higher than minimum
],
)
@patch("shutil.which")
@patch("subprocess.run")
def test_validate_npm_succeeds_with_valid_versions(mock_run, mock_which, npm_version):
"""Test validate_npm succeeds when npm version is valid."""
mock_which.return_value = "/usr/bin/npm"
mock_run.return_value = Mock(returncode=0, stdout=f"{npm_version}\n", stderr="")
# Should not raise SystemExit
validate_npm()
@pytest.mark.unit
@pytest.mark.parametrize(
"npm_version,should_pass",
[
("10.8.2", True), # Exact minimum version
("10.8.1", False), # Slightly lower version
("10.9.0-alpha.1", True), # Pre-release version higher than minimum
("9.9.9", False), # Much lower version
("11.0.0", True), # Much higher version
],
)
@patch("shutil.which")
@patch("subprocess.run")
def test_validate_npm_version_comparison_edge_cases(
mock_run, mock_which, npm_version, should_pass
):
"""Test npm version comparison with edge cases."""
mock_which.return_value = "/usr/bin/npm"
mock_run.return_value = Mock(returncode=0, stdout=f"{npm_version}\n", stderr="")
if should_pass:
# Should not raise SystemExit
validate_npm()
else:
with pytest.raises(SystemExit):
validate_npm()
@pytest.mark.unit
@patch("shutil.which")
@patch("subprocess.run")
def test_validate_npm_handles_file_not_found_exception(mock_run, mock_which):
"""Test validate_npm handles FileNotFoundError gracefully."""
mock_which.return_value = "/usr/bin/npm"
mock_run.side_effect = FileNotFoundError("Test error")
with pytest.raises(SystemExit) as exc_info:
validate_npm()
assert exc_info.value.code == 1
@pytest.mark.unit
@pytest.mark.parametrize(
"exception_type",
[
OSError,
PermissionError,
],
)
@patch("shutil.which")
@patch("subprocess.run")
def test_validate_npm_does_not_catch_other_subprocess_exceptions(
mock_run, mock_which, exception_type
):
"""Test validate_npm does not catch OSError and PermissionError (they propagate up)."""
mock_which.return_value = "/usr/bin/npm"
mock_run.side_effect = exception_type("Test error")
# These exceptions should propagate up, not be caught
with pytest.raises(exception_type):
validate_npm()
@pytest.mark.unit
@patch("shutil.which")
@patch("subprocess.run")
def test_validate_npm_with_malformed_version_output_raises_error(mock_run, mock_which):
"""Test validate_npm raises ValueError with malformed version output."""
mock_which.return_value = "/usr/bin/npm"
mock_run.return_value = Mock(returncode=0, stdout="not-a-version\n", stderr="")
# semver.compare will raise ValueError for malformed version
with pytest.raises(ValueError):
validate_npm()
@pytest.mark.unit
@patch("shutil.which")
@patch("subprocess.run")
def test_validate_npm_with_empty_version_output_raises_error(mock_run, mock_which):
"""Test validate_npm raises ValueError with empty version output."""
mock_which.return_value = "/usr/bin/npm"
mock_run.return_value = Mock(returncode=0, stdout="", stderr="")
# semver.compare will raise ValueError for empty version
with pytest.raises(ValueError):
validate_npm()

View File

@@ -0,0 +1,331 @@
# 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.
from __future__ import annotations
import json
from pathlib import Path
import pytest
from jinja2 import Environment, FileSystemLoader
@pytest.fixture
def templates_dir():
"""Get the templates directory path."""
return (
Path(__file__).parent.parent / "src" / "superset_extensions_cli" / "templates"
)
@pytest.fixture
def jinja_env(templates_dir):
"""Create a Jinja2 environment for testing templates."""
return Environment(loader=FileSystemLoader(templates_dir))
@pytest.fixture
def template_context():
"""Default template context for testing."""
return {
"id": "test_extension",
"name": "Test Extension",
"version": "0.1.0",
"license": "Apache-2.0",
"include_frontend": True,
"include_backend": True,
}
# Extension JSON Template Tests
@pytest.mark.unit
def test_extension_json_template_renders_with_both_frontend_and_backend(
jinja_env, template_context
):
"""Test extension.json template renders correctly with both frontend and backend."""
template = jinja_env.get_template("extension.json.j2")
rendered = template.render(template_context)
# Parse the rendered JSON to ensure it's valid
parsed = json.loads(rendered)
# Verify basic fields
assert parsed["id"] == "test_extension"
assert parsed["name"] == "Test Extension"
assert parsed["version"] == "0.1.0"
assert parsed["license"] == "Apache-2.0"
assert parsed["permissions"] == []
# Verify frontend section exists
assert "frontend" in parsed
frontend = parsed["frontend"]
assert "contributions" in frontend
assert "moduleFederation" in frontend
assert frontend["contributions"] == {"commands": [], "views": [], "menus": []}
assert frontend["moduleFederation"] == {"exposes": ["./index"]}
# Verify backend section exists
assert "backend" in parsed
backend = parsed["backend"]
assert backend["entryPoints"] == ["test_extension.entrypoint"]
assert backend["files"] == ["backend/src/test_extension/**/*.py"]
@pytest.mark.unit
@pytest.mark.parametrize(
"include_frontend,include_backend,expected_sections",
[
(True, False, ["frontend"]),
(False, True, ["backend"]),
(False, False, []),
],
)
def test_extension_json_template_renders_with_different_configurations(
jinja_env, template_context, include_frontend, include_backend, expected_sections
):
"""Test extension.json template renders correctly with different configurations."""
template_context["include_frontend"] = include_frontend
template_context["include_backend"] = include_backend
template = jinja_env.get_template("extension.json.j2")
rendered = template.render(template_context)
parsed = json.loads(rendered)
# Check for expected sections
for section in expected_sections:
assert section in parsed, f"Expected section '{section}' not found"
# Check that unexpected sections are not present
all_sections = ["frontend", "backend"]
for section in all_sections:
if section not in expected_sections:
assert section not in parsed, f"Unexpected section '{section}' found"
# Frontend Package JSON Template Tests
@pytest.mark.unit
def test_frontend_package_json_template_renders_correctly(jinja_env, template_context):
"""Test frontend/package.json template renders correctly."""
template = jinja_env.get_template("frontend/package.json.j2")
rendered = template.render(template_context)
parsed = json.loads(rendered)
# Verify basic package info
assert parsed["name"] == "test_extension"
assert parsed["version"] == "0.1.0"
assert parsed["license"] == "Apache-2.0"
assert parsed["private"] is True
# Verify scripts section
assert "scripts" in parsed
scripts = parsed["scripts"]
assert "start" in scripts
assert "build" in scripts
assert "webpack" in scripts["build"]
# Verify dependencies
assert "peerDependencies" in parsed
peer_deps = parsed["peerDependencies"]
assert "@apache-superset/core" in peer_deps
assert "react" in peer_deps
assert "react-dom" in peer_deps
# Verify dev dependencies
assert "devDependencies" in parsed
dev_deps = parsed["devDependencies"]
assert "webpack" in dev_deps
assert "typescript" in dev_deps
# Backend Pyproject TOML Template Tests
@pytest.mark.unit
def test_backend_pyproject_toml_template_renders_correctly(jinja_env, template_context):
"""Test backend/pyproject.toml template renders correctly."""
template = jinja_env.get_template("backend/pyproject.toml.j2")
rendered = template.render(template_context)
# Basic content verification (without full TOML parsing)
assert "test_extension" in rendered
assert "0.1.0" in rendered
assert "Apache-2.0" in rendered
# Template Rendering with Different Parameters Tests
@pytest.mark.unit
@pytest.mark.parametrize(
"id_,name",
[
("simple_extension", "Simple Extension"),
("MyExtension123", "My Extension 123"),
("complex_extension_name_123", "Complex Extension Name 123"),
("ext", "Ext"),
],
)
def test_template_rendering_with_different_ids(jinja_env, id_, name):
"""Test templates render correctly with various extension ids/names."""
context = {
"id": id_,
"name": name,
"version": "1.0.0",
"license": "MIT",
"include_frontend": True,
"include_backend": True,
}
# Test extension.json template
template = jinja_env.get_template("extension.json.j2")
rendered = template.render(context)
parsed = json.loads(rendered)
assert parsed["id"] == id_
assert parsed["name"] == name
assert parsed["backend"]["entryPoints"] == [f"{id_}.entrypoint"]
assert parsed["backend"]["files"] == [f"backend/src/{id_}/**/*.py"]
# Test package.json template
template = jinja_env.get_template("frontend/package.json.j2")
rendered = template.render(context)
parsed = json.loads(rendered)
assert parsed["name"] == id_
# Test pyproject.toml template
template = jinja_env.get_template("backend/pyproject.toml.j2")
rendered = template.render(context)
assert id_ in rendered
@pytest.mark.unit
@pytest.mark.parametrize("version", ["0.1.0", "1.0.0", "2.1.3-alpha", "10.20.30"])
def test_template_rendering_with_different_versions(jinja_env, version):
"""Test templates render correctly with various version formats."""
context = {
"id": "test_ext",
"name": "Test Extension",
"version": version,
"license": "Apache-2.0",
"include_frontend": True,
"include_backend": False,
}
template = jinja_env.get_template("extension.json.j2")
rendered = template.render(context)
parsed = json.loads(rendered)
assert parsed["version"] == version
@pytest.mark.unit
@pytest.mark.parametrize(
"license_type",
[
"Apache-2.0",
"MIT",
"BSD-3-Clause",
"GPL-3.0",
"Custom License",
],
)
def test_template_rendering_with_different_licenses(jinja_env, license_type):
"""Test templates render correctly with various license types."""
context = {
"id": "test_ext",
"name": "Test Extension",
"version": "1.0.0",
"license": license_type,
"include_frontend": True,
"include_backend": True,
}
# Test extension.json template
template = jinja_env.get_template("extension.json.j2")
rendered = template.render(context)
parsed = json.loads(rendered)
assert parsed["license"] == license_type
# Test package.json template
template = jinja_env.get_template("frontend/package.json.j2")
rendered = template.render(context)
parsed = json.loads(rendered)
assert parsed["license"] == license_type
# Template Validation Tests
@pytest.mark.unit
@pytest.mark.parametrize(
"template_name", ["extension.json.j2", "frontend/package.json.j2"]
)
def test_templates_produce_valid_json(jinja_env, template_context, template_name):
"""Test that all JSON templates produce valid JSON output."""
template = jinja_env.get_template(template_name)
rendered = template.render(template_context)
# This will raise an exception if the JSON is invalid
try:
json.loads(rendered)
except json.JSONDecodeError as e:
pytest.fail(f"Template {template_name} produced invalid JSON: {e}")
@pytest.mark.unit
def test_template_whitespace_handling(jinja_env, template_context):
"""Test that templates handle whitespace correctly and produce clean output."""
template = jinja_env.get_template("extension.json.j2")
rendered = template.render(template_context)
# Should not have excessive empty lines
lines = rendered.split("\n")
empty_line_count = sum(1 for line in lines if line.strip() == "")
# Some empty lines are OK for formatting, but not excessive
assert (
empty_line_count < len(lines) / 2
), "Too many empty lines in rendered template"
# Should be properly formatted JSON
parsed = json.loads(rendered)
# Re-serialize to check it's valid structure
json.dumps(parsed, indent=2)
@pytest.mark.unit
def test_template_context_edge_cases(jinja_env):
"""Test template rendering with edge case contexts."""
# Test with minimal context
minimal_context = {
"id": "minimal",
"name": "Minimal",
"version": "1.0.0",
"license": "MIT",
"include_frontend": False,
"include_backend": False,
}
template = jinja_env.get_template("extension.json.j2")
rendered = template.render(minimal_context)
parsed = json.loads(rendered)
# Should still be valid JSON with basic fields
assert parsed["id"] == "minimal"
assert parsed["name"] == "Minimal"
assert "frontend" not in parsed
assert "backend" not in parsed

View File

@@ -0,0 +1,271 @@
# 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.
from __future__ import annotations
import json
import pytest
from superset_extensions_cli.utils import read_json, read_toml
# Read JSON Tests
@pytest.mark.unit
def test_read_json_with_valid_file(isolated_filesystem):
"""Test read_json with valid JSON file."""
json_data = {"name": "test", "version": "1.0.0"}
json_file = isolated_filesystem / "test.json"
json_file.write_text(json.dumps(json_data))
result = read_json(json_file)
assert result == json_data
@pytest.mark.unit
def test_read_json_with_nonexistent_file(isolated_filesystem):
"""Test read_json returns None when file doesn't exist."""
nonexistent_file = isolated_filesystem / "nonexistent.json"
result = read_json(nonexistent_file)
assert result is None
@pytest.mark.unit
def test_read_json_with_invalid_json(isolated_filesystem):
"""Test read_json with invalid JSON content."""
invalid_json_file = isolated_filesystem / "invalid.json"
invalid_json_file.write_text("{ invalid json content")
with pytest.raises(json.JSONDecodeError):
read_json(invalid_json_file)
@pytest.mark.unit
def test_read_json_with_directory_instead_of_file(isolated_filesystem):
"""Test read_json returns None when path is a directory."""
directory = isolated_filesystem / "test_dir"
directory.mkdir()
result = read_json(directory)
assert result is None
@pytest.mark.unit
@pytest.mark.parametrize(
"json_content,expected",
[
({"simple": "value"}, {"simple": "value"}),
({"nested": {"key": "value"}}, {"nested": {"key": "value"}}),
({"array": [1, 2, 3]}, {"array": [1, 2, 3]}),
({}, {}), # Empty JSON object
],
)
def test_read_json_with_various_valid_content(
isolated_filesystem, json_content, expected
):
"""Test read_json with various valid JSON content types."""
json_file = isolated_filesystem / "test.json"
json_file.write_text(json.dumps(json_content))
result = read_json(json_file)
assert result == expected
# Read TOML Tests
@pytest.mark.unit
def test_read_toml_with_valid_file(isolated_filesystem):
"""Test read_toml with valid TOML file."""
toml_content = '[project]\nname = "test"\nversion = "1.0.0"'
toml_file = isolated_filesystem / "pyproject.toml"
toml_file.write_text(toml_content)
result = read_toml(toml_file)
assert result is not None
assert result["project"]["name"] == "test"
assert result["project"]["version"] == "1.0.0"
@pytest.mark.unit
def test_read_toml_with_nonexistent_file(isolated_filesystem):
"""Test read_toml returns None when file doesn't exist."""
nonexistent_file = isolated_filesystem / "nonexistent.toml"
result = read_toml(nonexistent_file)
assert result is None
@pytest.mark.unit
def test_read_toml_with_directory_instead_of_file(isolated_filesystem):
"""Test read_toml returns None when path is a directory."""
directory = isolated_filesystem / "test_dir"
directory.mkdir()
result = read_toml(directory)
assert result is None
@pytest.mark.unit
def test_read_toml_with_invalid_toml(isolated_filesystem):
"""Test read_toml with invalid TOML content."""
invalid_toml_file = isolated_filesystem / "invalid.toml"
invalid_toml_file.write_text("[ invalid toml content")
with pytest.raises(Exception): # tomli raises various exceptions for invalid TOML
read_toml(invalid_toml_file)
@pytest.mark.unit
@pytest.mark.parametrize(
"toml_content,expected_keys",
[
('[project]\nname = "test"', ["project"]),
('[build-system]\nrequires = ["setuptools"]', ["build-system"]),
(
'[project]\nname = "test"\n[build-system]\nrequires = ["setuptools"]',
["project", "build-system"],
),
],
)
def test_read_toml_with_various_valid_content(
isolated_filesystem, toml_content, expected_keys
):
"""Test read_toml with various valid TOML content types."""
toml_file = isolated_filesystem / "test.toml"
toml_file.write_text(toml_content)
result = read_toml(toml_file)
assert result is not None
for key in expected_keys:
assert key in result
@pytest.mark.unit
def test_read_toml_with_complex_structure(isolated_filesystem):
"""Test read_toml with complex TOML structure."""
complex_toml = """
[project]
name = "my-package"
version = "1.0.0"
authors = [
{name = "Author Name", email = "author@example.com"}
]
[project.dependencies]
requests = "^2.25.0"
[build-system]
requires = ["setuptools", "wheel"]
build-backend = "setuptools.build_meta"
"""
toml_file = isolated_filesystem / "complex.toml"
toml_file.write_text(complex_toml)
result = read_toml(toml_file)
assert result is not None
assert result["project"]["name"] == "my-package"
assert result["project"]["version"] == "1.0.0"
assert len(result["project"]["authors"]) == 1
assert result["project"]["authors"][0]["name"] == "Author Name"
assert result["build-system"]["requires"] == ["setuptools", "wheel"]
@pytest.mark.unit
def test_read_toml_with_empty_file(isolated_filesystem):
"""Test read_toml with empty TOML file."""
toml_file = isolated_filesystem / "empty.toml"
toml_file.write_text("")
result = read_toml(toml_file)
assert result == {}
@pytest.mark.unit
@pytest.mark.parametrize(
"invalid_content",
[
"[ invalid section",
"key = ",
"key = unquoted string",
"[section\nkey = value",
],
)
def test_read_toml_with_various_invalid_content(isolated_filesystem, invalid_content):
"""Test read_toml with various types of invalid TOML content."""
toml_file = isolated_filesystem / "invalid.toml"
toml_file.write_text(invalid_content)
with pytest.raises(Exception): # Various TOML parsing exceptions
read_toml(toml_file)
# File System Edge Cases
@pytest.mark.unit
def test_read_json_with_permission_denied(isolated_filesystem):
"""Test read_json behavior when file permissions are denied."""
json_file = isolated_filesystem / "restricted.json"
json_file.write_text('{"test": "value"}')
# This test may not work on all systems, so we'll skip it if chmod doesn't work
try:
json_file.chmod(0o000) # No permissions
result = read_json(json_file)
# If we get here without exception, the file was still readable
# This is system-dependent behavior
assert result is None or result == {"test": "value"}
except (OSError, PermissionError):
# Expected on some systems
pass
finally:
# Restore permissions for cleanup
try:
json_file.chmod(0o644)
except (OSError, PermissionError):
pass
@pytest.mark.unit
def test_read_toml_with_permission_denied(isolated_filesystem):
"""Test read_toml behavior when file permissions are denied."""
toml_file = isolated_filesystem / "restricted.toml"
toml_file.write_text('[test]\nkey = "value"')
# This test may not work on all systems, so we'll skip it if chmod doesn't work
try:
toml_file.chmod(0o000) # No permissions
result = read_toml(toml_file)
# If we get here without exception, the file was still readable
# This is system-dependent behavior
assert result is None or "test" in result
except (OSError, PermissionError):
# Expected on some systems
pass
finally:
# Restore permissions for cleanup
try:
toml_file.chmod(0o644)
except (OSError, PermissionError):
pass

View File

@@ -0,0 +1,211 @@
# 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.
from __future__ import annotations
import json
from pathlib import Path
from typing import Any
def assert_file_exists(path: Path, description: str = "") -> None:
"""
Assert that a file exists with a descriptive error message.
Args:
path: Path to the file that should exist
description: Optional description for better error messages
"""
desc_msg = f" ({description})" if description else ""
assert path.exists(), f"Expected file {path}{desc_msg} to exist, but it doesn't"
assert path.is_file(), f"Expected {path}{desc_msg} to be a file, but it's not"
def assert_directory_exists(path: Path, description: str = "") -> None:
"""
Assert that a directory exists with a descriptive error message.
Args:
path: Path to the directory that should exist
description: Optional description for better error messages
"""
desc_msg = f" ({description})" if description else ""
assert (
path.exists()
), f"Expected directory {path}{desc_msg} to exist, but it doesn't"
assert path.is_dir(), f"Expected {path}{desc_msg} to be a directory, but it's not"
def assert_file_structure(base_path: Path, expected_files: list[str]) -> None:
"""
Assert that all expected files exist under the base path.
Args:
base_path: Base directory path
expected_files: List of relative file paths that should exist
"""
for file_path in expected_files:
full_path = base_path / file_path
assert_file_exists(full_path, "part of expected structure")
def assert_directory_structure(base_path: Path, expected_dirs: list[str]) -> None:
"""
Assert that all expected directories exist under the base path.
Args:
base_path: Base directory path
expected_dirs: List of relative directory paths that should exist
"""
for dir_path in expected_dirs:
full_path = base_path / dir_path
assert_directory_exists(full_path, "part of expected structure")
def get_directory_tree(path: Path, ignore: set[str] | None = None) -> set[str]:
"""
Get all files and directories under a path as relative string paths.
Args:
path: Base path to scan
ignore: Set of file/directory names to ignore
Returns:
Set of relative path strings
"""
ignore = ignore or {".DS_Store", "__pycache__", ".pytest_cache"}
tree: set[str] = set()
if not path.exists():
return tree
for item in path.rglob("*"):
if any(ignored in item.parts for ignored in ignore):
continue
relative = item.relative_to(path)
tree.add(str(relative))
return tree
def load_json_file(path: Path) -> dict[str, Any]:
"""
Load and parse a JSON file.
Args:
path: Path to the JSON file
Returns:
Parsed JSON content
Raises:
AssertionError: If file doesn't exist or isn't valid JSON
"""
assert_file_exists(path, "JSON file")
try:
content = json.loads(path.read_text())
return content
except json.JSONDecodeError as e:
raise AssertionError(f"File {path} contains invalid JSON: {e}")
def assert_json_content(path: Path, expected_values: dict[str, Any]) -> None:
"""
Assert that a JSON file contains expected key-value pairs.
Args:
path: Path to the JSON file
expected_values: Dictionary of expected key-value pairs
"""
content = load_json_file(path)
for key, expected_value in expected_values.items():
assert key in content, f"Expected key '{key}' not found in {path}"
actual_value = content[key]
assert (
actual_value == expected_value
), f"Expected {key}='{expected_value}' but got '{actual_value}' in {path}"
def assert_file_contains(path: Path, text: str) -> None:
"""
Assert that a file contains specific text.
Args:
path: Path to the file
text: Text that should be present in the file
"""
assert_file_exists(path, "text file")
content = path.read_text()
assert text in content, f"Expected text '{text}' not found in {path}"
def assert_file_content_matches(path: Path, expected_content: str) -> None:
"""
Assert that a file's content exactly matches expected content.
Args:
path: Path to the file
expected_content: Expected file content
"""
assert_file_exists(path, "content file")
actual_content = path.read_text()
assert actual_content == expected_content, (
f"File content mismatch in {path}\n"
f"Expected:\n{expected_content}\n"
f"Actual:\n{actual_content}"
)
def create_test_extension_structure(
base_path: Path,
id_: str,
include_frontend: bool = True,
include_backend: bool = True,
) -> dict[str, Any]:
"""
Helper to create expected extension structure for testing.
Args:
base_path: Base path where extension should be created
id_: Unique identifier for extension
name: Extension name
include_frontend: Whether frontend should be included
include_backend: Whether backend should be included
Returns:
Dictionary with expected paths and metadata
"""
extension_path = base_path / id_
expected_files = ["extension.json"]
expected_dirs: list[str] = []
if include_frontend:
expected_dirs.append("frontend")
expected_files.append("frontend/package.json")
if include_backend:
expected_dirs.append("backend")
expected_files.append("backend/pyproject.toml")
expected = {
"extension_path": extension_path,
"expected_files": expected_files,
"expected_dirs": expected_dirs,
}
return expected

View File

@@ -46,6 +46,7 @@ module.exports = {
plugins: [
'lodash',
'@babel/plugin-syntax-dynamic-import',
'@babel/plugin-transform-export-namespace-from',
['@babel/plugin-proposal-class-properties', { loose: true }],
['@babel/plugin-proposal-optional-chaining', { loose: true }],
['@babel/plugin-proposal-private-methods', { loose: true }],
@@ -89,6 +90,7 @@ module.exports = {
plugins: [
'babel-plugin-dynamic-import-node',
'@babel/plugin-transform-modules-commonjs',
'@babel/plugin-transform-export-namespace-from',
],
},
// build instrumented code for testing code coverage with Cypress

View File

@@ -511,29 +511,29 @@ describe('Drill by modal', () => {
it('Line chart', () => {
testEchart('echarts_timeseries_line', 'Line Chart', [
[70, 93],
[70, 93],
[85, 93],
[85, 93],
]);
});
it('Area Chart', () => {
testEchart('echarts_area', 'Area Chart', [
[70, 93],
[70, 93],
[85, 93],
[85, 93],
]);
});
it('Scatter Chart', () => {
testEchart('echarts_timeseries_scatter', 'Scatter Chart', [
[70, 93],
[70, 93],
[85, 93],
[85, 93],
]);
});
it('Bar Chart', () => {
testEchart('echarts_timeseries_bar', 'Bar Chart', [
[70, 94],
[362, 68],
[85, 94],
[490, 68],
]);
});
@@ -566,22 +566,22 @@ describe('Drill by modal', () => {
it('Generic Chart', () => {
testEchart('echarts_timeseries', 'Generic Chart', [
[70, 93],
[70, 93],
[85, 93],
[85, 93],
]);
});
it('Smooth Line Chart', () => {
testEchart('echarts_timeseries_smooth', 'Smooth Line Chart', [
[70, 93],
[70, 93],
[85, 93],
[85, 93],
]);
});
it('Step Line Chart', () => {
testEchart('echarts_timeseries_step', 'Step Line Chart', [
[70, 93],
[70, 93],
[85, 93],
[85, 93],
]);
});
@@ -617,8 +617,8 @@ describe('Drill by modal', () => {
cy.get('[data-test-viz-type="mixed_timeseries"] canvas').then($canvas => {
// click 'boy'
cy.wrap($canvas).scrollIntoView();
cy.wrap($canvas).trigger('mouseover', 70, 93);
cy.wrap($canvas).rightclick(70, 93);
cy.wrap($canvas).trigger('mouseover', 85, 93);
cy.wrap($canvas).rightclick(85, 93);
drillBy('name').then(intercepted => {
const { queries } = intercepted.request.body;
@@ -651,8 +651,8 @@ describe('Drill by modal', () => {
cy.get(`[data-test="drill-by-chart"] canvas`).then($canvas => {
// click second query
cy.wrap($canvas).scrollIntoView();
cy.wrap($canvas).trigger('mouseover', 246, 114);
cy.wrap($canvas).rightclick(246, 114);
cy.wrap($canvas).trigger('mouseover', 261, 114);
cy.wrap($canvas).rightclick(261, 114);
drillBy('ds').then(intercepted => {
const { queries } = intercepted.request.body;

View File

@@ -96,24 +96,24 @@ function testTimeChart(vizType: string) {
cy.get(`[data-test-viz-type='${vizType}'] canvas`).then($canvas => {
cy.wrap($canvas).scrollIntoView();
cy.wrap($canvas).trigger('mousemove', 70, 93);
cy.wrap($canvas).rightclick(70, 93);
cy.wrap($canvas).trigger('mousemove', 85, 93);
cy.wrap($canvas).rightclick(85, 93);
drillToDetailBy('Drill to detail by 1965');
cy.getBySel('filter-val').should('contain', '1965');
closeModal();
cy.wrap($canvas).scrollIntoView();
cy.wrap($canvas).trigger('mousemove', 70, 93);
cy.wrap($canvas).rightclick(70, 93);
cy.wrap($canvas).trigger('mousemove', 85, 93);
cy.wrap($canvas).rightclick(85, 93);
drillToDetailBy('Drill to detail by boy');
cy.getBySel('filter-val').should('contain', 'boy');
closeModal();
cy.wrap($canvas).scrollIntoView();
cy.wrap($canvas).trigger('mousemove', 70, 93);
cy.wrap($canvas).rightclick(70, 93);
cy.wrap($canvas).trigger('mousemove', 85, 93);
cy.wrap($canvas).rightclick(85, 93);
drillToDetailBy('Drill to detail by all');
cy.getBySel('filter-val').first().should('contain', '1965');
@@ -435,7 +435,7 @@ describe('Drill to detail modal', () => {
SUPPORTED_TIER2_CHARTS.forEach(waitForChartLoad);
});
describe('Modal actions', () => {
describe.only('Modal actions', () => {
it('clears filters', () => {
interceptSamples();
@@ -443,7 +443,7 @@ describe('Drill to detail modal', () => {
cy.get("[data-test-viz-type='box_plot'] canvas").then($canvas => {
const canvasWidth = $canvas.width() || 0;
const canvasHeight = $canvas.height() || 0;
const canvasCenterX = canvasWidth / 3;
const canvasCenterX = canvasWidth / 3 + 15;
const canvasCenterY = (canvasHeight * 5) / 6;
cy.wrap($canvas).scrollIntoView();

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