Compare commits
39 Commits
chore/ci/s
...
4.1.0rc2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8f93ad7068 | ||
|
|
cced1c5a4e | ||
|
|
c332eebc37 | ||
|
|
106d755931 | ||
|
|
ef31710c2b | ||
|
|
6a5c293a04 | ||
|
|
86bfb2ade6 | ||
|
|
f8ed0cec74 | ||
|
|
b70c5e1d9d | ||
|
|
f4b201857e | ||
|
|
16385322db | ||
|
|
9677fa97ff | ||
|
|
16295b086a | ||
|
|
afe580bb8a | ||
|
|
d102b45692 | ||
|
|
c0c6486e70 | ||
|
|
a2d8590f0a | ||
|
|
bfb6ff3394 | ||
|
|
8ea94916d9 | ||
|
|
642de0ad63 | ||
|
|
6954db023c | ||
|
|
eca7c57083 | ||
|
|
4dca9bceed | ||
|
|
7219310267 | ||
|
|
77ade18107 | ||
|
|
bca2366d5a | ||
|
|
de2eedd16f | ||
|
|
0f1663b2ec | ||
|
|
604fe27ed1 | ||
|
|
3d7f6dae90 | ||
|
|
a8c6bb5b52 | ||
|
|
30fbfa1b14 | ||
|
|
3e297d130e | ||
|
|
dc754e2d26 | ||
|
|
f59fb6f780 | ||
|
|
fea187a36a | ||
|
|
a9ba3b325f | ||
|
|
c8008e6225 | ||
|
|
4369967732 |
@@ -43,3 +43,4 @@ under the License.
|
||||
- [4.0.0](./CHANGELOG/4.0.0.md)
|
||||
- [4.0.1](./CHANGELOG/4.0.1.md)
|
||||
- [4.0.2](./CHANGELOG/4.0.2.md)
|
||||
- [4.1.0](./CHANGELOG/4.1.0.md)
|
||||
|
||||
901
CHANGELOG/4.1.0.md
Normal file
@@ -0,0 +1,901 @@
|
||||
<!--
|
||||
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
|
||||
|
||||
### 4.1 (Thu Aug 22 14:46:26 2024 -0300)
|
||||
|
||||
**Database Migrations**
|
||||
|
||||
- [#29625](https://github.com/apache/superset/pull/29625) fix: try to prevent deadlocks when running upgrade (@sadpandajoe)
|
||||
- [#29906](https://github.com/apache/superset/pull/29906) fix: Error when downgrading add_catalog_perm_to_tables migration (@michael-s-molina)
|
||||
- [#29799](https://github.com/apache/superset/pull/29799) fix: Downgrade of revision 678eefb4ab44 throws error (@michael-s-molina)
|
||||
- [#29166](https://github.com/apache/superset/pull/29166) chore: enable ruff lint rule TRY201 and B904 to improve `raise` stack traces (@mistercrunch)
|
||||
- [#28838](https://github.com/apache/superset/pull/28838) fix: Update downgrade path for migration to remove sl_tables (@sadpandajoe)
|
||||
- [#28704](https://github.com/apache/superset/pull/28704) chore: remove sl_ tables (@mistercrunch)
|
||||
- [#28482](https://github.com/apache/superset/pull/28482) fix: Update migration logic in #27119 (@john-bodley)
|
||||
- [#28556](https://github.com/apache/superset/pull/28556) fix: db migration revision (@justinpark)
|
||||
- [#28416](https://github.com/apache/superset/pull/28416) feat: add support for catalogs (@betodealmeida)
|
||||
- [#27718](https://github.com/apache/superset/pull/27718) refactor(plugins): BigNumber Time Comparison with existing time_offset API (@Antonio-RiveroMartnez)
|
||||
- [#26327](https://github.com/apache/superset/pull/26327) feat: Customizable email subject name (@puridach-w)
|
||||
- [#28422](https://github.com/apache/superset/pull/28422) fix: Update migration logic in #27119 (@john-bodley)
|
||||
- [#28394](https://github.com/apache/superset/pull/28394) feat: catalog support for Databricks native (@betodealmeida)
|
||||
- [#28361](https://github.com/apache/superset/pull/28361) chore: fix master build by merging alembic migration heads (@mistercrunch)
|
||||
- [#27392](https://github.com/apache/superset/pull/27392) fix: Missing sql_editor_id index (@justinpark)
|
||||
- [#28317](https://github.com/apache/superset/pull/28317) feat(SIP-95): permissions for catalogs (@betodealmeida)
|
||||
- [#28192](https://github.com/apache/superset/pull/28192) feat: new Columnar upload form and API (@dpgaspar)
|
||||
- [#28267](https://github.com/apache/superset/pull/28267) chore: enable ruff's isort equivalent (@mistercrunch)
|
||||
- [#28122](https://github.com/apache/superset/pull/28122) feat(SIP-95): new endpoint for table metadata (@betodealmeida)
|
||||
- [#28158](https://github.com/apache/superset/pull/28158) chore: set up ruff as a new linter/formatter (@mistercrunch)
|
||||
- [#28105](https://github.com/apache/superset/pull/28105) feat: new Excel upload form and API (@dpgaspar)
|
||||
- [#28106](https://github.com/apache/superset/pull/28106) fix: db migrations on downgrade (@dpgaspar)
|
||||
- [#27849](https://github.com/apache/superset/pull/27849) feat: Slack Avatar integration (@mistercrunch)
|
||||
- [#27840](https://github.com/apache/superset/pull/27840) feat: new CSV upload form and API (@dpgaspar)
|
||||
- [#27631](https://github.com/apache/superset/pull/27631) feat(SIP-85): OAuth2 for databases (@betodealmeida)
|
||||
- [#27351](https://github.com/apache/superset/pull/27351) fix: Migration for single metric in Big Number with Time Comparison (@kgabryje)
|
||||
|
||||
**Features**
|
||||
|
||||
- [#29088](https://github.com/apache/superset/pull/29088) feat(alert/report): Added optional CC and BCC fields for email notifi… (@nsivarajan)
|
||||
- [#29264](https://github.com/apache/superset/pull/29264) feat: add slackv2 notification (@eschutho)
|
||||
- [#29584](https://github.com/apache/superset/pull/29584) feat(frontend/hooks): replace 3rd-party BroadcastChannel with native Web API equivalence (@hainenber)
|
||||
- [#29590](https://github.com/apache/superset/pull/29590) feat: custom values to sandbox iframe (@dacopan)
|
||||
- [#29419](https://github.com/apache/superset/pull/29419) feat(build): uplift Lerna + replace insecure shortid with nanoid + uplift Yeoman-related packages + ESM-ize generator-superset (@hainenber)
|
||||
- [#29225](https://github.com/apache/superset/pull/29225) feat: add connector for CouchbaseDB (@ayush33143314)
|
||||
- [#29408](https://github.com/apache/superset/pull/29408) feat(build): uplift Storybook to v8 (@hainenber)
|
||||
- [#29496](https://github.com/apache/superset/pull/29496) feat(database): Add OceanBase support (@yuanoOo)
|
||||
- [#29384](https://github.com/apache/superset/pull/29384) feat: add support to NOT LIKE operator (@dacopan)
|
||||
- [#29498](https://github.com/apache/superset/pull/29498) feat: Enable customizing the docker admin password (@c-w)
|
||||
- [#29187](https://github.com/apache/superset/pull/29187) feat(dashboard): add API endpoints for generating and downloading screenshots (@eulloa10)
|
||||
- [#27221](https://github.com/apache/superset/pull/27221) feat(CLI command): Apache Superset "Factory Reset" CLI command #27207 (@mknadh)
|
||||
- [#29328](https://github.com/apache/superset/pull/29328) feat: Add Ant Design 5 Theme (@geido)
|
||||
- [#29351](https://github.com/apache/superset/pull/29351) feat(e2e): implementing Cypress Dashboard on `master` branch merges (@rusackas)
|
||||
- [#29361](https://github.com/apache/superset/pull/29361) feat: Adds chart IDs option to migrate-viz (@michael-s-molina)
|
||||
- [#29329](https://github.com/apache/superset/pull/29329) feat: Adds the ECharts Sankey chart (@michael-s-molina)
|
||||
- [#29118](https://github.com/apache/superset/pull/29118) feat(build): uplift `Jest` to v29 (@hainenber)
|
||||
- [#29231](https://github.com/apache/superset/pull/29231) feat: add new SQLLAB_FORCE_RUN_ASYNC feature flag (@mistercrunch)
|
||||
- [#29123](https://github.com/apache/superset/pull/29123) feat(dashboard): Enables pivot table download option at dashboard level (@adimyth)
|
||||
- [#27962](https://github.com/apache/superset/pull/27962) feat: Dashboard tabs api endpoint (@fisjac)
|
||||
- [#29242](https://github.com/apache/superset/pull/29242) feat: Improves the Drill By feature (@michael-s-molina)
|
||||
- [#28057](https://github.com/apache/superset/pull/28057) feat(table): Table with Time Comparison (@Antonio-RiveroMartnez)
|
||||
- [#29241](https://github.com/apache/superset/pull/29241) feat: Support a dynamic minimum interval for alerts and reports (@Vitor-Avila)
|
||||
- [#29164](https://github.com/apache/superset/pull/29164) feat(trino): Add functionality to upload data (@john-bodley)
|
||||
- [#28774](https://github.com/apache/superset/pull/28774) feat(echarts-pie): add string template support for labels (@hexcafe)
|
||||
- [#24263](https://github.com/apache/superset/pull/24263) feat(formatters): Add custom d3-time-format locale (@matheusbsilva)
|
||||
- [#29109](https://github.com/apache/superset/pull/29109) feat: OAuth2 client initial work (@betodealmeida)
|
||||
- [#28637](https://github.com/apache/superset/pull/28637) feat: add Current time-range options for time filter (@pranav1699)
|
||||
- [#28780](https://github.com/apache/superset/pull/28780) feat: Adds Histogram chart migration logic (@michael-s-molina)
|
||||
- [#28762](https://github.com/apache/superset/pull/28762) feat(helm): allow removal of Node & Worker replicas for custom HPA solutions (@hanslemm)
|
||||
- [#28789](https://github.com/apache/superset/pull/28789) feat: Adds the Featured Charts dashboard (@michael-s-molina)
|
||||
- [#28652](https://github.com/apache/superset/pull/28652) feat: Adds the ECharts Histogram chart (@michael-s-molina)
|
||||
- [#28770](https://github.com/apache/superset/pull/28770) feat: impersonate with email prefix (@betodealmeida)
|
||||
- [#28483](https://github.com/apache/superset/pull/28483) feat: bake translations as part of the build processes (@mistercrunch)
|
||||
- [#27851](https://github.com/apache/superset/pull/27851) feat(reports): allowing the email mutator to update recipients (@SkinnyPigeon)
|
||||
- [#28597](https://github.com/apache/superset/pull/28597) feat: add Nightingale chart support for echarts pie chart (@hexcafe)
|
||||
- [#28602](https://github.com/apache/superset/pull/28602) feat: Adds Bar chart migration logic (@michael-s-molina)
|
||||
- [#28521](https://github.com/apache/superset/pull/28521) feat: unpack payload into log function (@mistercrunch)
|
||||
- [#28629](https://github.com/apache/superset/pull/28629) feat: Data Zoom scrolls using the mouse (mark II) (@hughhhh)
|
||||
- [#28265](https://github.com/apache/superset/pull/28265) feat(maps): Adding ALL the countries to the Country Map plugin! 🌎 (@rusackas)
|
||||
- [#27857](https://github.com/apache/superset/pull/27857) feat(dashboard): Add metadata bar to the header (@justinpark)
|
||||
- [#28425](https://github.com/apache/superset/pull/28425) feat: clarify that 'Text' supports markdown (@mistercrunch)
|
||||
- [#27995](https://github.com/apache/superset/pull/27995) feat(explore): Color scheme groups, new color schemes (@kgabryje)
|
||||
- [#28376](https://github.com/apache/superset/pull/28376) feat(SIP-95): catalogs in SQL Lab and datasets (@betodealmeida)
|
||||
- [#28176](https://github.com/apache/superset/pull/28176) feat(reports): Set a minimum interval for each report's execution (@Vitor-Avila)
|
||||
- [#27950](https://github.com/apache/superset/pull/27950) feat: Utility function to render chart tooltips (@michael-s-molina)
|
||||
- [#28345](https://github.com/apache/superset/pull/28345) feat(docs): uplift Docusaurus to v3 (@hainenber)
|
||||
- [#28282](https://github.com/apache/superset/pull/28282) feat: accelerate webpack builds with filesystem cache (@mistercrunch)
|
||||
- [#28035](https://github.com/apache/superset/pull/28035) feat: Add Czech Republic country map. (@martinspudich)
|
||||
- [#27933](https://github.com/apache/superset/pull/27933) feat(country-map): Adds Philippines regional map and updates/cleans existing Philippines provincial map (@jdruii)
|
||||
- [#28169](https://github.com/apache/superset/pull/28169) feat(translations): Traditional Chinese translation files added (@bestlong)
|
||||
- [#24449](https://github.com/apache/superset/pull/24449) feat: custom refresh frequency (@Abhishek-kumar-samsung)
|
||||
- [#27943](https://github.com/apache/superset/pull/27943) feat: improve event logging for queries + refactor (@mistercrunch)
|
||||
- [#28107](https://github.com/apache/superset/pull/28107) feat: label PR with release tags (@mistercrunch)
|
||||
- [#28063](https://github.com/apache/superset/pull/28063) feat(SIP-95): new endpoint for extra table metadata (@betodealmeida)
|
||||
- [#27908](https://github.com/apache/superset/pull/27908) feat(dbview): Add token request button to DuckDB and MotherDuck database modal (@guenp)
|
||||
- [#27953](https://github.com/apache/superset/pull/27953) feat: optimize docker-compose up for faster boot time (@mistercrunch)
|
||||
- [#27969](https://github.com/apache/superset/pull/27969) feat: add option to disable rendering of html in sql lab and table chart (@soniagtm)
|
||||
- [#27773](https://github.com/apache/superset/pull/27773) feat(alert report tabs): adding feature flag (@fisjac)
|
||||
- [#27863](https://github.com/apache/superset/pull/27863) feat: GHA to bump python packages using supersetbot (@mistercrunch)
|
||||
- [#27788](https://github.com/apache/superset/pull/27788) feat(explore): Clear temporal filter value (@kgabryje)
|
||||
- [#26138](https://github.com/apache/superset/pull/26138) feat(accessibility): add tabbing to chart menu in dashboard (@eschutho)
|
||||
- [#27708](https://github.com/apache/superset/pull/27708) feat(viz picker): Remove some tags, refactor Recommended section (@kgabryje)
|
||||
- [#27647](https://github.com/apache/superset/pull/27647) feat: move supersetbot out of repo (@mistercrunch)
|
||||
- [#27859](https://github.com/apache/superset/pull/27859) feat: setup a pyproject.toml (@mistercrunch)
|
||||
- [#27847](https://github.com/apache/superset/pull/27847) feat(db): Adding DB_SQLA_URI_VALIDATOR (@craig-rueda)
|
||||
- [#27771](https://github.com/apache/superset/pull/27771) feat: Adds Heatmap chart migration logic (@michael-s-molina)
|
||||
- [#27665](https://github.com/apache/superset/pull/27665) feat(db_engine): Add custom_user_agent when connecting to MotherDuck (@guenp)
|
||||
- [#25353](https://github.com/apache/superset/pull/25353) feat: Adds the ECharts Heatmap chart (@michael-s-molina)
|
||||
- [#27615](https://github.com/apache/superset/pull/27615) feat: use the local supersetbot (@mistercrunch)
|
||||
- [#27582](https://github.com/apache/superset/pull/27582) feat(jinja): metric macro (@Vitor-Avila)
|
||||
- [#27497](https://github.com/apache/superset/pull/27497) feat(alerts-reports): adding pdf filetype to email and slack reports (@fisjac)
|
||||
- [#27522](https://github.com/apache/superset/pull/27522) feat: support for KQL in `SQLScript` (@betodealmeida)
|
||||
- [#27589](https://github.com/apache/superset/pull/27589) feat(bar_chart): Stacked Bar chart with Time comparison in separated stacks (@Antonio-RiveroMartnez)
|
||||
- [#27536](https://github.com/apache/superset/pull/27536) feat: Adds option to disable drill to detail per database (@michael-s-molina)
|
||||
- [#27571](https://github.com/apache/superset/pull/27571) feat(supersetbot): label PRs and issues with author's public org (@mistercrunch)
|
||||
- [#27542](https://github.com/apache/superset/pull/27542) feat(maps): Add Italy regions code to the map generator notebook (@iskenderulgen)
|
||||
- [#27524](https://github.com/apache/superset/pull/27524) feat(plugins): add color options for big number with time comparison (@lilykuang)
|
||||
- [#27455](https://github.com/apache/superset/pull/27455) feat: Add Turkey's regions to country map visualization (@iskenderulgen)
|
||||
- [#27046](https://github.com/apache/superset/pull/27046) feat(supersetbot): introduce `supersetbot` as its own npm package, CLI and comment-operated bot (@mistercrunch)
|
||||
- [#27255](https://github.com/apache/superset/pull/27255) feat: show more information when loading chart (@betodealmeida)
|
||||
- [#27434](https://github.com/apache/superset/pull/27434) feat: docker-compose to work off repo Dockerfile (@mistercrunch)
|
||||
- [#27244](https://github.com/apache/superset/pull/27244) feat(translations): Turkish translation files added (@coteli)
|
||||
- [#27372](https://github.com/apache/superset/pull/27372) feat: Add repo activity stats to README.md (@rusackas)
|
||||
- [#27375](https://github.com/apache/superset/pull/27375) feat: Responsive UI for Big Number with Time Comparison (@kgabryje)
|
||||
- [#27370](https://github.com/apache/superset/pull/27370) feat: support to fetch multiple date time in time_range endpoint (@zhaoyongjie)
|
||||
- [#27368](https://github.com/apache/superset/pull/27368) feat: datediff in datetime_parser (@zhaoyongjie)
|
||||
- [#24408](https://github.com/apache/superset/pull/24408) feat(embedded-sdk): Add 'urlParams' option to pass query parameters to embedded dashboard (@grvoicu)
|
||||
- [#27298](https://github.com/apache/superset/pull/27298) feat(logs context): Adding dashboard id to logs context (@Vitor-Avila)
|
||||
- [#27197](https://github.com/apache/superset/pull/27197) feat(jinja): current_user_email macro (@Vitor-Avila)
|
||||
- [#27146](https://github.com/apache/superset/pull/27146) feat(ci): no more docker builds on PR-related events (@mistercrunch)
|
||||
- [#27193](https://github.com/apache/superset/pull/27193) feat: Use standardized controls in Big Number with Time Comparison (@kgabryje)
|
||||
- [#27176](https://github.com/apache/superset/pull/27176) feat(docs): Adds an "Edit this page on GitHub" button to docs pages (@rusackas)
|
||||
- [#27163](https://github.com/apache/superset/pull/27163) feat(helm): optionally set pod disruption budgets (@pradasouvanlasy)
|
||||
- [#27162](https://github.com/apache/superset/pull/27162) feat(adt): add 403 to api response status codes (@anirudh-hegde)
|
||||
|
||||
**Fixes**
|
||||
|
||||
- [#29993](https://github.com/apache/superset/pull/29993) fix: Duplicated example dataset (@michael-s-molina)
|
||||
- [#29981](https://github.com/apache/superset/pull/29981) fix: trino thread app missing full context (@dpgaspar)
|
||||
- [#29978](https://github.com/apache/superset/pull/29978) fix(sqllab): flaky json explore modal due to shallow equality checks for extra data (@justinpark)
|
||||
- [#29830](https://github.com/apache/superset/pull/29830) fix(ci): remove unused "type: ignore" comment to unblock precommit check in CI (@hainenber)
|
||||
- [#29956](https://github.com/apache/superset/pull/29956) fix(sqllab): Add abort call on query refresh timeout (@justinpark)
|
||||
- [#29860](https://github.com/apache/superset/pull/29860) fix: upgrade_catalog_perms and downgrade_catalog_perms implementation (@michael-s-molina)
|
||||
- [#29953](https://github.com/apache/superset/pull/29953) fix(embedded): Remove CSRF requirement for dashboard download API (@Vitor-Avila)
|
||||
- [#29672](https://github.com/apache/superset/pull/29672) fix(explore): missing column autocomplete in custom SQL (@justinpark)
|
||||
- [#29840](https://github.com/apache/superset/pull/29840) fix: handle empty catalog when DB supports them (@betodealmeida)
|
||||
- [#29287](https://github.com/apache/superset/pull/29287) fix: Add user filtering to changed_by. Fixes #27986 (@marre)
|
||||
- [#29921](https://github.com/apache/superset/pull/29921) fix: add imports back to celery file (@sadpandajoe)
|
||||
- [#29894](https://github.com/apache/superset/pull/29894) fix(Embedded): Deleting Embedded Dashboards does not commit the transaction (@geido)
|
||||
- [#29862](https://github.com/apache/superset/pull/29862) fix: update celery config imports (@mistercrunch)
|
||||
- [#29846](https://github.com/apache/superset/pull/29846) fix: load slack channels earlier (@eschutho)
|
||||
- [#29805](https://github.com/apache/superset/pull/29805) fix: bump packages to unblock ci (@eschutho)
|
||||
- [#29802](https://github.com/apache/superset/pull/29802) fix: create permissions on DB import (@betodealmeida)
|
||||
- [#29780](https://github.com/apache/superset/pull/29780) fix: catalog upgrade/downgrade (@betodealmeida)
|
||||
- [#29776](https://github.com/apache/superset/pull/29776) fix(Dashboard): Copying a Dashboard does not commit the transaction (@geido)
|
||||
- [#29721](https://github.com/apache/superset/pull/29721) fix: pass slack recipients correctly (@eschutho)
|
||||
- [#29681](https://github.com/apache/superset/pull/29681) fix(Database): Refresh catalogs on db update returns database error (@geido)
|
||||
- [#29669](https://github.com/apache/superset/pull/29669) fix: Use default custom time range time without timezone (@kgabryje)
|
||||
- [#29667](https://github.com/apache/superset/pull/29667) fix: Dashboard editable title weird behavior when adding spaces (@kgabryje)
|
||||
- [#29648](https://github.com/apache/superset/pull/29648) fix: Layout of native filters modal with lengthy columns (@michael-s-molina)
|
||||
- [#29647](https://github.com/apache/superset/pull/29647) fix: Loading of native filter column (@michael-s-molina)
|
||||
- [#29643](https://github.com/apache/superset/pull/29643) fix: Required native filter message wrongfully appearing (@michael-s-molina)
|
||||
- [#29638](https://github.com/apache/superset/pull/29638) fix(sqllab): prev shema/table options remained on fail (@justinpark)
|
||||
- [#29567](https://github.com/apache/superset/pull/29567) fix: Add Japanese Translations (@avintonOfficial)
|
||||
- [#29607](https://github.com/apache/superset/pull/29607) fix(sqllab): Show warning message when deprecated db is selected (@justinpark)
|
||||
- [#29610](https://github.com/apache/superset/pull/29610) fix: sort schemas when uploading data (@betodealmeida)
|
||||
- [#29604](https://github.com/apache/superset/pull/29604) fix: schemas for upload API (@betodealmeida)
|
||||
- [#28496](https://github.com/apache/superset/pull/28496) fix(docs): fix broken indexed link from Google search (@sfirke)
|
||||
- [#29587](https://github.com/apache/superset/pull/29587) fix(storybook): fix broken Storybook stories during development (@hainenber)
|
||||
- [#29581](https://github.com/apache/superset/pull/29581) fix: catalog permission check (@betodealmeida)
|
||||
- [#29579](https://github.com/apache/superset/pull/29579) fix: small fixes to the catalog migration (@betodealmeida)
|
||||
- [#29566](https://github.com/apache/superset/pull/29566) fix: Trino `get_columns` (@betodealmeida)
|
||||
- [#29576](https://github.com/apache/superset/pull/29576) fix(dataset import): Support catalog field during dataset import (@Vitor-Avila)
|
||||
- [#29549](https://github.com/apache/superset/pull/29549) fix: make catalog migration lenient (@betodealmeida)
|
||||
- [#29412](https://github.com/apache/superset/pull/29412) fix(Tags filter): Filter assets by tag ID (@Vitor-Avila)
|
||||
- [#29548](https://github.com/apache/superset/pull/29548) fix: babel_update script crash (@CodeWithEmad)
|
||||
- [#29530](https://github.com/apache/superset/pull/29530) fix: prevent guest users from changing columns (@betodealmeida)
|
||||
- [#29538](https://github.com/apache/superset/pull/29538) fix(websocket): add error handling (@harshit2283)
|
||||
- [#29330](https://github.com/apache/superset/pull/29330) fix: refactor view error handling into a separate module (@mistercrunch)
|
||||
- [#29525](https://github.com/apache/superset/pull/29525) fix: Table time comparison breaking after form data update (@kgabryje)
|
||||
- [#29520](https://github.com/apache/superset/pull/29520) fix(plugins): Big Number with Time Comparison (@Antonio-RiveroMartnez)
|
||||
- [#29517](https://github.com/apache/superset/pull/29517) fix(plugins): Fix dashboard filter for Table and Big Number with Time Comparison (@Antonio-RiveroMartnez)
|
||||
- [#29454](https://github.com/apache/superset/pull/29454) fix: add more disallowed pg functions (@dpgaspar)
|
||||
- [#29470](https://github.com/apache/superset/pull/29470) fix: remove info from datasource access error (@dpgaspar)
|
||||
- [#28364](https://github.com/apache/superset/pull/28364) fix: Enable explore button on SQL Lab view when connected to Apache Pinot as a database (@soumitra-st)
|
||||
- [#29456](https://github.com/apache/superset/pull/29456) fix: Dashboard hangs when initial filters cannot be loaded (@michael-s-molina)
|
||||
- [#29461](https://github.com/apache/superset/pull/29461) fix: OAuth2 in async DBs (@betodealmeida)
|
||||
- [#29446](https://github.com/apache/superset/pull/29446) fix: re-add missing code from PR #28132 (@sadpandajoe)
|
||||
- [#29451](https://github.com/apache/superset/pull/29451) fix(metastore-cache): import dao in methods (@villebro)
|
||||
- [#29420](https://github.com/apache/superset/pull/29420) fix: SQL label missing for non-group-by queries (@hexcafe)
|
||||
- [#29392](https://github.com/apache/superset/pull/29392) fix(readme): changing video from mp4 to webm format (@rusackas)
|
||||
- [#29368](https://github.com/apache/superset/pull/29368) fix(tox): Address issue with generative environment variables (@john-bodley)
|
||||
- [#29367](https://github.com/apache/superset/pull/29367) fix(explore): don't respect y-axis formatting (@justinpark)
|
||||
- [#29321](https://github.com/apache/superset/pull/29321) fix(Query): Parse html string error responses to avoid displaying raw HTML as error message (@rtexelm)
|
||||
- [#27777](https://github.com/apache/superset/pull/27777) fix: default logging (@jessie-ross)
|
||||
- [#29352](https://github.com/apache/superset/pull/29352) fix(tests): Ensure fixture is invoked (@john-bodley)
|
||||
- [#29345](https://github.com/apache/superset/pull/29345) fix(revert 27883): Excess padding in horizontal Bar charts (@michael-s-molina)
|
||||
- [#14817](https://github.com/apache/superset/pull/14817) fix: actually write changes on "superset import-datasources" (@regisb)
|
||||
- [#29349](https://github.com/apache/superset/pull/29349) fix(explore): restored hidden field values has discarded (@justinpark)
|
||||
- [#29346](https://github.com/apache/superset/pull/29346) fix: Cannot delete empty column inside a tab using the dashboard editor (@michael-s-molina)
|
||||
- [#29314](https://github.com/apache/superset/pull/29314) fix: Remove recursive repr call (@jessie-ross)
|
||||
- [#28753](https://github.com/apache/superset/pull/28753) fix: don't strip SQL comments in Explore - 2nd try (@mistercrunch)
|
||||
- [#28429](https://github.com/apache/superset/pull/28429) fix(ui): Disable ability to export data when user does not have the correct permission (@edjannoo)
|
||||
- [#27439](https://github.com/apache/superset/pull/27439) fix(Dashboard): Color inconsistency on refreshes and conflicts (@geido)
|
||||
- [#29286](https://github.com/apache/superset/pull/29286) fix(key-value): use flush instead of commit (@villebro)
|
||||
- [#29301](https://github.com/apache/superset/pull/29301) fix(metastore-cache): prune before add (@villebro)
|
||||
- [#29279](https://github.com/apache/superset/pull/29279) fix(sqllab): excessive API calls for schemas (@justinpark)
|
||||
- [#29278](https://github.com/apache/superset/pull/29278) fix(sqllab): invalid empty state on switch tab (@justinpark)
|
||||
- [#29291](https://github.com/apache/superset/pull/29291) fix: filters not updating with force update when caching is enabled (@ka-weihe)
|
||||
- [#28744](https://github.com/apache/superset/pull/28744) fix(permalink): adding anchor to dashboard permalink generation (@fisjac)
|
||||
- [#29257](https://github.com/apache/superset/pull/29257) fix: Catalog with restricted permissions produces an error during database connection (@geido)
|
||||
- [#29260](https://github.com/apache/superset/pull/29260) fix: Custom SQL filter control (@michael-s-molina)
|
||||
- [#29248](https://github.com/apache/superset/pull/29248) fix(sqllab): Do not strip comments when executing SQL statements (@john-bodley)
|
||||
- [#29234](https://github.com/apache/superset/pull/29234) fix(Explore): Keep necessary form data to allow query mode switching (@rtexelm)
|
||||
- [#28755](https://github.com/apache/superset/pull/28755) fix: Workaround for Pandas.DataFrame.to_csv bug (@john-bodley)
|
||||
- [#29230](https://github.com/apache/superset/pull/29230) fix(sqllab): run previous state query (@justinpark)
|
||||
- [#29229](https://github.com/apache/superset/pull/29229) fix: Improving handling for tag relationship when deleting assets v2 (@Vitor-Avila)
|
||||
- [#29170](https://github.com/apache/superset/pull/29170) fix(maps): Load indian map borders correctly (Restores #24927 fixes) (@PushpenderSaini0)
|
||||
- [#29117](https://github.com/apache/superset/pull/29117) fix: Improving handling for tag relationship when deleting assets (@Vitor-Avila)
|
||||
- [#29119](https://github.com/apache/superset/pull/29119) fix(mixed-timeseries-plugin): Second query stacks stacked on top of first query series (@kgabryje)
|
||||
- [#29110](https://github.com/apache/superset/pull/29110) fix: CI failture due to Default React import (@justinpark)
|
||||
- [#29091](https://github.com/apache/superset/pull/29091) fix(helm): Set priorityClassName to pods (superset, celeryBeat, celeryBeatFlower, celeryBeatWorker, celeryBeatWebsocket, jobs) (@sabyrzhan)
|
||||
- [#28932](https://github.com/apache/superset/pull/28932) fix(embedded): add missing GUEST_TOKEN_HEADER_NAME to bootstrap data (@hexcafe)
|
||||
- [#29098](https://github.com/apache/superset/pull/29098) fix: Cypress CI process while opening PR from a fork (@mistercrunch)
|
||||
- [#28572](https://github.com/apache/superset/pull/28572) fix(i18n): improved Russian translation (@goldjee)
|
||||
- [#29084](https://github.com/apache/superset/pull/29084) fix: Remove BASE_AXIS from pre-query (@john-bodley)
|
||||
- [#29081](https://github.com/apache/superset/pull/29081) fix(explore): Drill to detail truncates int64 IDs (@justinpark)
|
||||
- [#29089](https://github.com/apache/superset/pull/29089) fix: CI errors as the result of removing React imports (@michael-s-molina)
|
||||
- [#27017](https://github.com/apache/superset/pull/27017) fix(embedded-sdk): add accessible title to iframe (@bhaugeea)
|
||||
- [#28797](https://github.com/apache/superset/pull/28797) fix: use channel id with new slack api for file uploads (@eschutho)
|
||||
- [#28771](https://github.com/apache/superset/pull/28771) fix(Mixed Chart Filter Control): Allow delete condition for `adhoc_filters_b` (@rtexelm)
|
||||
- [#28783](https://github.com/apache/superset/pull/28783) fix: use upload v2 for slack (@eschutho)
|
||||
- [#28772](https://github.com/apache/superset/pull/28772) fix(dashboard): unable to resize due to the overlapped droptarget (@justinpark)
|
||||
- [#28750](https://github.com/apache/superset/pull/28750) fix: do not close database modal on mask click (@eschutho)
|
||||
- [#28745](https://github.com/apache/superset/pull/28745) fix(reports): Update the element class to wait for when taking a screenshot (@Vitor-Avila)
|
||||
- [#28749](https://github.com/apache/superset/pull/28749) fix(sqllab): Sort db selector options by the API order (@justinpark)
|
||||
- [#28765](https://github.com/apache/superset/pull/28765) fix(docs): fix url typo to fix a broken image (@rusackas)
|
||||
- [#28639](https://github.com/apache/superset/pull/28639) fix: adds the ability to disallow SQL functions per engine (@dpgaspar)
|
||||
- [#28609](https://github.com/apache/superset/pull/28609) fix: dashboard performance (@dpgaspar)
|
||||
- [#28653](https://github.com/apache/superset/pull/28653) fix: Handling of column types for Presto, Trino, et al. (@john-bodley)
|
||||
- [#28633](https://github.com/apache/superset/pull/28633) fix(ci): restrict issue comments to members or owners (@dpgaspar)
|
||||
- [#28613](https://github.com/apache/superset/pull/28613) fix: revert fix(presto preview): re-enable schema previsualization for Trino/Presto table/schemas" (@john-bodley)
|
||||
- [#28568](https://github.com/apache/superset/pull/28568) fix: add listener to repaint on visibility change for canvas (@eschutho)
|
||||
- [#28566](https://github.com/apache/superset/pull/28566) fix: Fixes workflow Applitools Cypress (@geido)
|
||||
- [#28349](https://github.com/apache/superset/pull/28349) fix: Add back description column to saved queries #12431 (@imancrsrk)
|
||||
- [#28567](https://github.com/apache/superset/pull/28567) fix: Revert "fix: don't strip SQL comments in Explore (#28363)" (@michael-s-molina)
|
||||
- [#28497](https://github.com/apache/superset/pull/28497) fix: Correction translation (@aehanno)
|
||||
- [#28555](https://github.com/apache/superset/pull/28555) fix(explore): hide a control wrapped with StashFormDataContainer correctly (@justinpark)
|
||||
- [#28487](https://github.com/apache/superset/pull/28487) fix(i18n): Adding and modifying Japanese translations (@aikawa-ohno)
|
||||
- [#28550](https://github.com/apache/superset/pull/28550) fix(Dashboard): Prevent scroll when hovering filters (@geido)
|
||||
- [#28423](https://github.com/apache/superset/pull/28423) fix: move to slack-sdk files_upload_v2 (@mistercrunch)
|
||||
- [#28486](https://github.com/apache/superset/pull/28486) fix: utf-16 json encoder support (@eyalezer)
|
||||
- [#28512](https://github.com/apache/superset/pull/28512) fix: improve df to records performance (@dpgaspar)
|
||||
- [#28507](https://github.com/apache/superset/pull/28507) fix(dashboard): invalid drop item on a tab (@justinpark)
|
||||
- [#28432](https://github.com/apache/superset/pull/28432) fix: Time shifts calculation for ECharts plugins (@michael-s-molina)
|
||||
- [#28144](https://github.com/apache/superset/pull/28144) fix: bump sqlparse to 0.5.0 (@dpgaspar)
|
||||
- [#26782](https://github.com/apache/superset/pull/26782) fix(presto preview): re-enable schema previsualization for Trino/Presto table/schemas (@brouberol)
|
||||
- [#28451](https://github.com/apache/superset/pull/28451) fix: jwt extended broken by flask bump (@dpgaspar)
|
||||
- [#28409](https://github.com/apache/superset/pull/28409) fix(ar-modal): updateNotificationSettings not updating state (@fisjac)
|
||||
- [#28457](https://github.com/apache/superset/pull/28457) fix: Color scheme control crashing when dashboardId present (@kgabryje)
|
||||
- [#28442](https://github.com/apache/superset/pull/28442) fix(ci): fix failed `docker-build` CI job (@hainenber)
|
||||
- [#28433](https://github.com/apache/superset/pull/28433) fix(docs): add missing link to meta-cross-db feature flag docs (@sfirke)
|
||||
- [#28395](https://github.com/apache/superset/pull/28395) fix(dashboard): Change class name on last Droppable in a column (@rtexelm)
|
||||
- [#28419](https://github.com/apache/superset/pull/28419) fix: run some CI tests against previous python version (@mistercrunch)
|
||||
- [#28415](https://github.com/apache/superset/pull/28415) fix(SIP-95): missing catalog cache key (@justinpark)
|
||||
- [#28418](https://github.com/apache/superset/pull/28418) fix: set supersetbot orglabel to always succeed (@mistercrunch)
|
||||
- [#28412](https://github.com/apache/superset/pull/28412) fix(docs): fix typo in development.mdx (@eschutho)
|
||||
- [#28410](https://github.com/apache/superset/pull/28410) fix: pass catalog when estimating query cost (@betodealmeida)
|
||||
- [#28413](https://github.com/apache/superset/pull/28413) fix: table autocomplete should pass catalog (@betodealmeida)
|
||||
- [#28408](https://github.com/apache/superset/pull/28408) fix: export/import catalogs (@betodealmeida)
|
||||
- [#28396](https://github.com/apache/superset/pull/28396) fix: type annotation breaking on py3.9 (@dpgaspar)
|
||||
- [#28397](https://github.com/apache/superset/pull/28397) fix: tests on database, dataset, saved_queries apis (@dpgaspar)
|
||||
- [#28312](https://github.com/apache/superset/pull/28312) fix(explore): hide advanced analytics for non temporal xaxis (@justinpark)
|
||||
- [#28389](https://github.com/apache/superset/pull/28389) fix: update links to reference docs listing Superset issue codes (@jonaschn)
|
||||
- [#28368](https://github.com/apache/superset/pull/28368) fix: Contribution percentages for ECharts plugins (@michael-s-molina)
|
||||
- [#28386](https://github.com/apache/superset/pull/28386) fix: Scroll to top when selecting a global dashboard tab (@michael-s-molina)
|
||||
- [#28384](https://github.com/apache/superset/pull/28384) fix: Revert "chore(build): uplift `webpack`-related packages to v5 (#28342)" (@kgabryje)
|
||||
- [#28363](https://github.com/apache/superset/pull/28363) fix: don't strip SQL comments in Explore (@mistercrunch)
|
||||
- [#28341](https://github.com/apache/superset/pull/28341) fix: Remedy logic for UpdateDatasetCommand uniqueness check (@john-bodley)
|
||||
- [#28334](https://github.com/apache/superset/pull/28334) fix: Small tweaks for Line and Area chart migrations (ECharts) (@michael-s-molina)
|
||||
- [#28266](https://github.com/apache/superset/pull/28266) fix: use pessimistic json encoder in SQL Lab (@mistercrunch)
|
||||
- [#28343](https://github.com/apache/superset/pull/28343) fix(ci): correct input type for `allow-dependencies-licenses` in Dependency Review GH action (@hainenber)
|
||||
- [#28340](https://github.com/apache/superset/pull/28340) fix: database logos look stretched (@mistercrunch)
|
||||
- [#28333](https://github.com/apache/superset/pull/28333) fix(website): links corrected (@frankzimper)
|
||||
- [#28113](https://github.com/apache/superset/pull/28113) fix: Rename legacy line and area charts (@john-bodley)
|
||||
- [#28279](https://github.com/apache/superset/pull/28279) fix(sql_parse): Ignore USE SQL keyword when determining SELECT statement (@john-bodley)
|
||||
- [#28319](https://github.com/apache/superset/pull/28319) fix(docs): prevent browser to download the entire video in first page load + fix empty `controls` attribute (@hainenber)
|
||||
- [#28322](https://github.com/apache/superset/pull/28322) fix(sql_parse): Add Apache Spark to SQLGlot dialect mapping (@john-bodley)
|
||||
- [#28205](https://github.com/apache/superset/pull/28205) fix: all_database_access should enable access to all datasets/charts/dashboards (@mistercrunch)
|
||||
- [#28269](https://github.com/apache/superset/pull/28269) fix(explore): cannot reorder dnd of Metrics (@justinpark)
|
||||
- [#28283](https://github.com/apache/superset/pull/28283) fix: silence docker-compose useless warnings (@mistercrunch)
|
||||
- [#28271](https://github.com/apache/superset/pull/28271) fix: % replace in `values_for_column` (@betodealmeida)
|
||||
- [#28277](https://github.com/apache/superset/pull/28277) fix(ci): adding codecov token (@rusackas)
|
||||
- [#28225](https://github.com/apache/superset/pull/28225) fix(Dev-Server): Edit ChartPropsConfig reexport to be a type object (@rtexelm)
|
||||
- [#28232](https://github.com/apache/superset/pull/28232) fix(Webpack dev-sever warnings): Add ignoreWarning to webpack config for @data-ui error (@rtexelm)
|
||||
- [#28242](https://github.com/apache/superset/pull/28242) fix(dashboard): unable to drop tabs in columns (@justinpark)
|
||||
- [#28229](https://github.com/apache/superset/pull/28229) fix(Webpack dev-server build warning): Create false value alias for `moment-with-locales` (@rtexelm)
|
||||
- [#28241](https://github.com/apache/superset/pull/28241) fix(explore): temporal column mixin (@justinpark)
|
||||
- [#28156](https://github.com/apache/superset/pull/28156) fix(sqllab): invalid css scope for ace editor autocomplete (@justinpark)
|
||||
- [#28222](https://github.com/apache/superset/pull/28222) fix: Dremio alias (@betodealmeida)
|
||||
- [#28152](https://github.com/apache/superset/pull/28152) fix(sql_parse): Provide more lenient logic when extracting latest[_sub]_partition (@john-bodley)
|
||||
- [#28226](https://github.com/apache/superset/pull/28226) fix(maps): adds Crimea back to Ukraine 🇺🇦 (@rusackas)
|
||||
- [#28197](https://github.com/apache/superset/pull/28197) fix: Remove deprecated ignoreTestFiles from Applitools Cypress (@geido)
|
||||
- [#28189](https://github.com/apache/superset/pull/28189) fix(docs): ERD docs fail on master (@mistercrunch)
|
||||
- [#27554](https://github.com/apache/superset/pull/27554) fix(AlertsReports): making log retention "None" option valid (@fisjac)
|
||||
- [#28117](https://github.com/apache/superset/pull/28117) fix(sql_parse): Support Jinja format() filter when extracting latest[_sub]_partition (@john-bodley)
|
||||
- [#27195](https://github.com/apache/superset/pull/27195) fix: Upgrade eyes-cypress to latest (@geido)
|
||||
- [#28061](https://github.com/apache/superset/pull/28061) fix: switch off dependabot for pip/python (@mistercrunch)
|
||||
- [#28054](https://github.com/apache/superset/pull/28054) fix(Dashboard): Support "Edit chart" click on a new window (@geido)
|
||||
- [#28036](https://github.com/apache/superset/pull/28036) fix: Dynamic filter does not show all values on blur/clear events (@michael-s-molina)
|
||||
- [#28018](https://github.com/apache/superset/pull/28018) fix: bump client side chart timeouts to use the SUPERSET_WEBSERVER_TIMEOUT (@eschutho)
|
||||
- [#28039](https://github.com/apache/superset/pull/28039) fix: support docker/.env-local for docker-compose (@mistercrunch)
|
||||
- [#28017](https://github.com/apache/superset/pull/28017) fix: Select is accepting unknown pasted values when `allowNewOptions` is false (@michael-s-molina)
|
||||
- [#27996](https://github.com/apache/superset/pull/27996) fix: Incorrect onChange value when an unloaded value is pasted into AsyncSelect (@michael-s-molina)
|
||||
- [#27934](https://github.com/apache/superset/pull/27934) fix(time_offset): improved LIMIT-handling in advanced analytics (@Antonio-RiveroMartnez)
|
||||
- [#27992](https://github.com/apache/superset/pull/27992) fix(docs): add missing code formatting, fix broken link (@sfirke)
|
||||
- [#27941](https://github.com/apache/superset/pull/27941) fix(drillby): Enable DrillBy in charts w/o filters (dimensions) (@sowo)
|
||||
- [#27994](https://github.com/apache/superset/pull/27994) fix(superset-frontend): remove unused `@superset-ui/plugin-chart-period-over-period-kpi` package (@corocoto)
|
||||
- [#27239](https://github.com/apache/superset/pull/27239) fix(alerts/reports): removing duplicate notification method options (@fisjac)
|
||||
- [#27974](https://github.com/apache/superset/pull/27974) fix(node): bump node version in nvmrc files (@rusackas)
|
||||
- [#27963](https://github.com/apache/superset/pull/27963) fix(asf): removing google hosted analytics and fonts (@rusackas)
|
||||
- [#27968](https://github.com/apache/superset/pull/27968) fix(Dashboard): Add aria-label to filters and search forms (@geido)
|
||||
- [#27955](https://github.com/apache/superset/pull/27955) fix(node): missed one bump from node 16 to 18. (@rusackas)
|
||||
- [#27701](https://github.com/apache/superset/pull/27701) fix: useTruncation infinite loop, reenable dashboard cross links on ChartList (@kgabryje)
|
||||
- [#27904](https://github.com/apache/superset/pull/27904) fix: improve change detection for GHAs (@mistercrunch)
|
||||
- [#27942](https://github.com/apache/superset/pull/27942) fix(docs): CSP mods to re-enable Algolia search (@rusackas)
|
||||
- [#27926](https://github.com/apache/superset/pull/27926) fix: Locale sent to frontend (@michael-s-molina)
|
||||
- [#27925](https://github.com/apache/superset/pull/27925) fix: docker-release GHA fails with pathspec error (@mistercrunch)
|
||||
- [#27922](https://github.com/apache/superset/pull/27922) fix: fix-zh-translation-2 (@listeng)
|
||||
- [#25407](https://github.com/apache/superset/pull/25407) fix(frontend): allow "constructor" property in response data (@SpencerTorres)
|
||||
- [#27912](https://github.com/apache/superset/pull/27912) fix(docs): restoring search capability with new public key (@rusackas)
|
||||
- [#27919](https://github.com/apache/superset/pull/27919) fix: add mariadb engine spec same as MySQL (@dpgaspar)
|
||||
- [#27593](https://github.com/apache/superset/pull/27593) fix(Dashboard): Add border to row when hovering HoverMenu in edit mode (@rtexelm)
|
||||
- [#27794](https://github.com/apache/superset/pull/27794) fix: corrects some inaccuracies zh translation (@listeng)
|
||||
- [#27889](https://github.com/apache/superset/pull/27889) fix(pylint): Address errors/warnings introduced by #27867 (@john-bodley)
|
||||
- [#27883](https://github.com/apache/superset/pull/27883) fix(bar-chart): change legend padding for horizontal orientation (@lilykuang)
|
||||
- [#27861](https://github.com/apache/superset/pull/27861) fix: run pip-compile-multi --no-upgrade (@mistercrunch)
|
||||
- [#27860](https://github.com/apache/superset/pull/27860) fix: GHA update-monorepo-lockfiles (@mistercrunch)
|
||||
- [#27700](https://github.com/apache/superset/pull/27700) fix: row limits & row count labels are confusing (@mistercrunch)
|
||||
- [#27855](https://github.com/apache/superset/pull/27855) fix: pkg-config dependency in Dockerfile (@mistercrunch)
|
||||
- [#27845](https://github.com/apache/superset/pull/27845) fix(dashboard): missing null check in error extra (@justinpark)
|
||||
- [#27846](https://github.com/apache/superset/pull/27846) fix: alembic's 'superset db migrate' fails with CompileError (@mistercrunch)
|
||||
- [#27785](https://github.com/apache/superset/pull/27785) fix: Select's storybook (@michael-s-molina)
|
||||
- [#27710](https://github.com/apache/superset/pull/27710) fix: Pylint errors on master (@michael-s-molina)
|
||||
- [#27714](https://github.com/apache/superset/pull/27714) fix: Revert "chore: bump pylint (#27711)" (@michael-s-molina)
|
||||
- [#27611](https://github.com/apache/superset/pull/27611) fix(dashboard,css): center align 'waiting on database' (@mistercrunch)
|
||||
- [#27608](https://github.com/apache/superset/pull/27608) fix(docker): error around missing requirements/base.txt (@mistercrunch)
|
||||
- [#27595](https://github.com/apache/superset/pull/27595) fix: skip another Hive test (@betodealmeida)
|
||||
- [#27523](https://github.com/apache/superset/pull/27523) fix: Hive integration test (@betodealmeida)
|
||||
- [#27541](https://github.com/apache/superset/pull/27541) fix: typo in configuring-superset.mdx (@armando-fandango)
|
||||
- [#27502](https://github.com/apache/superset/pull/27502) fix(big-number-chart): number format is not applying to percentage number of the time comparison (@lilykuang)
|
||||
- [#27515](https://github.com/apache/superset/pull/27515) fix: master build 4th attempt (@mistercrunch)
|
||||
- [#27514](https://github.com/apache/superset/pull/27514) fix: another attempt at fixing docker master builds (@mistercrunch)
|
||||
- [#27507](https://github.com/apache/superset/pull/27507) fix: master docker build is broken (@mistercrunch)
|
||||
- [#27503](https://github.com/apache/superset/pull/27503) fix: docker builds in master fail (@mistercrunch)
|
||||
- [#27209](https://github.com/apache/superset/pull/27209) fix: Allow only dttm columns in comparison filter in Period over Period chart (@kgabryje)
|
||||
- [#27312](https://github.com/apache/superset/pull/27312) fix(docs): just a missing backtick (@rusackas)
|
||||
- [#27303](https://github.com/apache/superset/pull/27303) fix(ci): check file changes for python should include the scripts folders (@dpgaspar)
|
||||
- [#27296](https://github.com/apache/superset/pull/27296) fix: Revert "chore: Replace deprecated command with environment file (#240… (@eschutho)
|
||||
- [#27282](https://github.com/apache/superset/pull/27282) fix(ci): docker builds don't work from remote forks (@mistercrunch)
|
||||
- [#27280](https://github.com/apache/superset/pull/27280) fix(docs): more CSP tweaks (@rusackas)
|
||||
- [#27279](https://github.com/apache/superset/pull/27279) fix(docs): more csp tweaks (@rusackas)
|
||||
- [#27278](https://github.com/apache/superset/pull/27278) fix(docs): even more CSP adjustments... (@rusackas)
|
||||
- [#27277](https://github.com/apache/superset/pull/27277) fix(docs): Even more access in CSP policies! (@rusackas)
|
||||
- [#27275](https://github.com/apache/superset/pull/27275) fix(docs): More CSP touchups (@rusackas)
|
||||
- [#27274](https://github.com/apache/superset/pull/27274) fix(docs): removing meta tag CSP, poking more holes in htaccess (@rusackas)
|
||||
- [#27261](https://github.com/apache/superset/pull/27261) fix: docker CI job doesn't trigger on master (@mistercrunch)
|
||||
- [#27259](https://github.com/apache/superset/pull/27259) fix(docs site): CSP changes, take 2 (@rusackas)
|
||||
- [#27256](https://github.com/apache/superset/pull/27256) fix(docs site): Opening up CSP for 3rd party frame content. (@rusackas)
|
||||
- [#27203](https://github.com/apache/superset/pull/27203) fix(plugin-chart-period-over-period-kpi): Blank chart when switching from BigNumberTotal (@kgabryje)
|
||||
- [#27179](https://github.com/apache/superset/pull/27179) fix: docker-compose point to master tag (@dpgaspar)
|
||||
- [#27168](https://github.com/apache/superset/pull/27168) fix: CSRF exempt unit_tests (@dpgaspar)
|
||||
|
||||
**Others**
|
||||
|
||||
- [#29936](https://github.com/apache/superset/pull/29936) chore: Allow auto pruning of the query table (@michael-s-molina)
|
||||
- [#29893](https://github.com/apache/superset/pull/29893) chore: Logs the duration of migrations execution (@michael-s-molina)
|
||||
- [#29262](https://github.com/apache/superset/pull/29262) chore: Add the 4.1 release notes (@sadpandajoe)
|
||||
- [#29666](https://github.com/apache/superset/pull/29666) refactor(ProgressBar): Upgrade ProgressBar to Antd 5 (@geido)
|
||||
- [#29631](https://github.com/apache/superset/pull/29631) docs: fix query typo in creating-your-first-dashboard.mdx (@Jaswanth-Sriram-Veturi)
|
||||
- [#29650](https://github.com/apache/superset/pull/29650) chore: add catalog_access to OBJECT_SPEC_PERMISSIONS (@betodealmeida)
|
||||
- [#29594](https://github.com/apache/superset/pull/29594) refactor: Remove dead code from the Word Cloud plugin (@michael-s-molina)
|
||||
- [#29637](https://github.com/apache/superset/pull/29637) chore: Adds 4.1.0 RC1 daa to CHANGELOG.md and UPDATING.md (@sadpandajoe)
|
||||
- [#29272](https://github.com/apache/superset/pull/29272) refactor(Dashboard): Fetch dashboard screenshot via dedicated endpoint (@geido)
|
||||
- [#29593](https://github.com/apache/superset/pull/29593) refactor(Tag): Upgrade Tag and TagsList to Ant Design 5 (@geido)
|
||||
- [#29612](https://github.com/apache/superset/pull/29612) docs: fix code comment explaining local override (@oscep)
|
||||
- [#29602](https://github.com/apache/superset/pull/29602) chore: Clear redux localStorage on logout (@geido)
|
||||
- [#29600](https://github.com/apache/superset/pull/29600) chore: Updates CHANGELOG.md with 4.0.2 data (@michael-s-molina)
|
||||
- [#28124](https://github.com/apache/superset/pull/28124) docs(Database): Clarify host value expected when running in docker (@Carmageddon)
|
||||
- [#28481](https://github.com/apache/superset/pull/28481) chore(docs): create architecture page (@sfirke)
|
||||
- [#29603](https://github.com/apache/superset/pull/29603) docs(contributing): removing old blog post link (@rusackas)
|
||||
- [#29599](https://github.com/apache/superset/pull/29599) docs: update CVEs for 4.0.2 (@dpgaspar)
|
||||
- [#29552](https://github.com/apache/superset/pull/29552) chore: cleanup documentation (@CodeWithEmad)
|
||||
- [#29487](https://github.com/apache/superset/pull/29487) docs: Added Keycloak auth configuration (@lindner-tj)
|
||||
- [#29436](https://github.com/apache/superset/pull/29436) chore(deps): bump deck.gl from 8.9.22 to 9.0.20 in /superset-frontend (@dependabot[bot])
|
||||
- [#29537](https://github.com/apache/superset/pull/29537) docs(intro): Add OceanBase to the Supported Databases section of readme.md. (@yuanoOo)
|
||||
- [#29437](https://github.com/apache/superset/pull/29437) chore(deps): bump regenerator-runtime from 0.13.11 to 0.14.1 in /superset-frontend (@dependabot[bot])
|
||||
- [#29529](https://github.com/apache/superset/pull/29529) chore(deps): bump deck.gl from 8.9.22 to 9.0.21 in /superset-frontend (@dependabot[bot])
|
||||
- [#29510](https://github.com/apache/superset/pull/29510) docs: Add frontend dependency installation steps (@CodeWithEmad)
|
||||
- [#29124](https://github.com/apache/superset/pull/29124) refactor: Upgrade Badge component to Ant Design 5 (@geido)
|
||||
- [#29414](https://github.com/apache/superset/pull/29414) chore(build): sync Jest version across plugins (@hainenber)
|
||||
- [#29486](https://github.com/apache/superset/pull/29486) docs: Add Vasu and Jamie to the Users List (@vasu-ram)
|
||||
- [#29511](https://github.com/apache/superset/pull/29511) docs: cleanup markdown warnings (@CodeWithEmad)
|
||||
- [#29389](https://github.com/apache/superset/pull/29389) refactor: Upgrade Card to Ant Design 5 (@geido)
|
||||
- [#29493](https://github.com/apache/superset/pull/29493) chore(Home): Avoid firing API requests when a custom Home is used (@Vitor-Avila)
|
||||
- [#29459](https://github.com/apache/superset/pull/29459) chore(utils): Support select_columns with getUserOwnedObjects and split recentActivityObjs (@Vitor-Avila)
|
||||
- [#29476](https://github.com/apache/superset/pull/29476) chore: run babel_update.sh to update po files (@mistercrunch)
|
||||
- [#29377](https://github.com/apache/superset/pull/29377) chore(i18n): Translated charts and filters into Russian (@goldjee)
|
||||
- [#29468](https://github.com/apache/superset/pull/29468) docs(docker compose): fix step 4 list formatting (@easontm)
|
||||
- [#29426](https://github.com/apache/superset/pull/29426) chore(deps): bump deck.gl from 9.0.12 to 9.0.20 in /superset-frontend/plugins/legacy-preset-chart-deckgl (@dependabot[bot])
|
||||
- [#29425](https://github.com/apache/superset/pull/29425) chore(deps-dev): update @types/lodash requirement from ^4.17.4 to ^4.17.6 in /superset-frontend/plugins/plugin-chart-handlebars (@dependabot[bot])
|
||||
- [#29434](https://github.com/apache/superset/pull/29434) chore(deps): bump actions/checkout from 2 to 4 (@dependabot[bot])
|
||||
- [#29429](https://github.com/apache/superset/pull/29429) chore(deps-dev): bump webpack from 5.91.0 to 5.92.1 in /docs (@dependabot[bot])
|
||||
- [#29428](https://github.com/apache/superset/pull/29428) chore(deps): bump @algolia/client-search from 4.23.3 to 4.24.0 in /docs (@dependabot[bot])
|
||||
- [#29439](https://github.com/apache/superset/pull/29439) chore(deps): bump react-markdown from 8.0.3 to 8.0.7 in /superset-frontend (@dependabot[bot])
|
||||
- [#29447](https://github.com/apache/superset/pull/29447) chore: move all GHAs to ubuntu-22.04 (@mistercrunch)
|
||||
- [#29442](https://github.com/apache/superset/pull/29442) chore: Added 10Web to the list of organizations that use Apache Superset (@saghatelian)
|
||||
- [#29344](https://github.com/apache/superset/pull/29344) chore(key-value): convert command to dao (@villebro)
|
||||
- [#29423](https://github.com/apache/superset/pull/29423) chore(deps-dev): bump ts-jest from 29.1.2 to 29.1.5 in /superset-websocket (@dependabot[bot])
|
||||
- [#29435](https://github.com/apache/superset/pull/29435) chore(deps-dev): bump eslint-import-resolver-typescript from 2.5.0 to 3.6.1 in /superset-frontend (@dependabot[bot])
|
||||
- [#29433](https://github.com/apache/superset/pull/29433) chore(deps): bump rehype-raw from 6.1.1 to 7.0.0 in /superset-frontend (@dependabot[bot])
|
||||
- [#29432](https://github.com/apache/superset/pull/29432) chore(deps-dev): bump typescript from 5.4.5 to 5.5.2 in /docs (@dependabot[bot])
|
||||
- [#29431](https://github.com/apache/superset/pull/29431) chore(deps): bump stream from 0.0.2 to 0.0.3 in /docs (@dependabot[bot])
|
||||
- [#29413](https://github.com/apache/superset/pull/29413) docs: Update INTHEWILD.md with Aveti Learning (@TheShubhendra)
|
||||
- [#29399](https://github.com/apache/superset/pull/29399) docs: update INTHEWILD.md with bluquist (@ari-jane)
|
||||
- [#29405](https://github.com/apache/superset/pull/29405) chore(frontend): remove obsolete ESLint rules in tests (@hainenber)
|
||||
- [#24969](https://github.com/apache/superset/pull/24969) chore(dao/command): Add transaction decorator to try to enforce "unit of work" (@john-bodley)
|
||||
- [#29380](https://github.com/apache/superset/pull/29380) refactor(src/explore/comp/controls/metricControl): migrate Enzyme test to RTL syntax (@hainenber)
|
||||
- [#29400](https://github.com/apache/superset/pull/29400) docs: fix typos (@jansule)
|
||||
- [#28816](https://github.com/apache/superset/pull/28816) chore(deps): bump scroll-into-view-if-needed from 2.2.28 to 3.1.0 in /superset-frontend (@dependabot[bot])
|
||||
- [#29391](https://github.com/apache/superset/pull/29391) chore(Table): Add aria-label to Table page size selector (@geido)
|
||||
- [#29390](https://github.com/apache/superset/pull/29390) docs: fix typo in docker compose doc (@jansule)
|
||||
- [#29388](https://github.com/apache/superset/pull/29388) ci: remove update repo on issue comment (@dpgaspar)
|
||||
- [#29386](https://github.com/apache/superset/pull/29386) chore(tests): Remove unnecessary mock (@john-bodley)
|
||||
- [#29381](https://github.com/apache/superset/pull/29381) chore(security): Clean up session/commit logic (@john-bodley)
|
||||
- [#29371](https://github.com/apache/superset/pull/29371) chore(ci): Start Celery worker as a background process (@john-bodley)
|
||||
- [#29366](https://github.com/apache/superset/pull/29366) chore(tests): Mark TestConnectionDatabaseCommand as non-test related (@john-bodley)
|
||||
- [#29353](https://github.com/apache/superset/pull/29353) refactor(Homepage): Migrate Home.test to RTL (@rtexelm)
|
||||
- [#29356](https://github.com/apache/superset/pull/29356) chore(tests): Fix MySQL logic (@john-bodley)
|
||||
- [#29355](https://github.com/apache/superset/pull/29355) chore(tests): Cleanup Celery tests (@john-bodley)
|
||||
- [#29360](https://github.com/apache/superset/pull/29360) chore: Rename Totals to Summary in table chart (@michael-s-molina)
|
||||
- [#29337](https://github.com/apache/superset/pull/29337) docs: Update INTHEWILD.md with Bluesquare (@madewulf)
|
||||
- [#29327](https://github.com/apache/superset/pull/29327) chore(e2e): simplify Cypress record key usage (@rusackas)
|
||||
- [#29325](https://github.com/apache/superset/pull/29325) refactor: Adds the sort_by_metric control to sharedControls (@michael-s-molina)
|
||||
- [#29313](https://github.com/apache/superset/pull/29313) docs: update CVEs fixed on 4.0.1 and 3.1.3 (@dpgaspar)
|
||||
- [#28296](https://github.com/apache/superset/pull/28296) build(deps): bump deck.gl from 9.0.6 to 9.0.12 in /superset-frontend/plugins/legacy-preset-chart-deckgl (@dependabot[bot])
|
||||
- [#29319](https://github.com/apache/superset/pull/29319) chore(e2e): more instructions for manual test runs. (@rusackas)
|
||||
- [#28201](https://github.com/apache/superset/pull/28201) chore(applitools): making tests more static for consistent testing (@rusackas)
|
||||
- [#29302](https://github.com/apache/superset/pull/29302) chore(distributed-lock): refactor tests (@villebro)
|
||||
- [#29308](https://github.com/apache/superset/pull/29308) build(deps-dev): bump ws from 7.5.7 to 7.5.10 in /superset-embedded-sdk (@dependabot[bot])
|
||||
- [#29296](https://github.com/apache/superset/pull/29296) chore(e2e): using updated repo secret, new Cypress project id (@rusackas)
|
||||
- [#29300](https://github.com/apache/superset/pull/29300) docs: add Agoda to users list (@oBoMBaYo)
|
||||
- [#29285](https://github.com/apache/superset/pull/29285) chore: use json codec for key value lock (@villebro)
|
||||
- [#29277](https://github.com/apache/superset/pull/29277) chore: make flask-talisman work with test config (@mistercrunch)
|
||||
- [#29273](https://github.com/apache/superset/pull/29273) docs: remove comment header in README.md (@mistercrunch)
|
||||
- [#29275](https://github.com/apache/superset/pull/29275) build(deps): bump ws from 7.5.9 to 7.5.10 in /docs (@dependabot[bot])
|
||||
- [#29276](https://github.com/apache/superset/pull/29276) build(deps): bump ws from 8.17.0 to 8.17.1 in /superset-websocket (@dependabot[bot])
|
||||
- [#29274](https://github.com/apache/superset/pull/29274) chore: trigger CI jobs on all release-related branches (@mistercrunch)
|
||||
- [#29247](https://github.com/apache/superset/pull/29247) chore: translate strings to French (@eschutho)
|
||||
- [#29233](https://github.com/apache/superset/pull/29233) refactor(sqllab): nonblocking delete query editor (@justinpark)
|
||||
- [#29249](https://github.com/apache/superset/pull/29249) test(Explorer): Fix minor errors in ExploreViewContainer syntax, add tests (@rtexelm)
|
||||
- [#28876](https://github.com/apache/superset/pull/28876) chore(sqllab): Add logging for actions (@justinpark)
|
||||
- [#29245](https://github.com/apache/superset/pull/29245) test(storybook): fix component stories (@msyavuz)
|
||||
- [#29235](https://github.com/apache/superset/pull/29235) chore: Remove the need for explicit bubble up of certain exceptions (@john-bodley)
|
||||
- [#28628](https://github.com/apache/superset/pull/28628) chore: Set isolation level to READ COMMITTED for testing et al. (@john-bodley)
|
||||
- [#29108](https://github.com/apache/superset/pull/29108) refactor(sqllab): nonblocking switch query editor (@justinpark)
|
||||
- [#29232](https://github.com/apache/superset/pull/29232) build(deps-dev): bump braces from 3.0.2 to 3.0.3 in /superset-embedded-sdk (@dependabot[bot])
|
||||
- [#29226](https://github.com/apache/superset/pull/29226) chore(intros): Update INTHEWILD.md (@RIS3cz)
|
||||
- [#29167](https://github.com/apache/superset/pull/29167) build(deps-dev): bump braces from 3.0.2 to 3.0.3 in /superset-websocket (@dependabot[bot])
|
||||
- [#28836](https://github.com/apache/superset/pull/28836) chore(deps): bump distributions from 1.1.0 to 2.2.0 in /superset-frontend (@dependabot[bot])
|
||||
- [#29168](https://github.com/apache/superset/pull/29168) build(deps): bump braces from 3.0.2 to 3.0.3 in /superset-frontend/cypress-base (@dependabot[bot])
|
||||
- [#29169](https://github.com/apache/superset/pull/29169) build(deps): bump braces from 3.0.2 to 3.0.3 in /docs (@dependabot[bot])
|
||||
- [#28295](https://github.com/apache/superset/pull/28295) build(deps): update urijs requirement from ^1.19.8 to ^1.19.11 in /superset-frontend/plugins/legacy-preset-chart-deckgl (@dependabot[bot])
|
||||
- [#29160](https://github.com/apache/superset/pull/29160) chore: `s/MockFixture/MockerFixture/g` (@betodealmeida)
|
||||
- [#29142](https://github.com/apache/superset/pull/29142) docs: Add Analytics Aura to INTHEWILD (@visharavana)
|
||||
- [#29104](https://github.com/apache/superset/pull/29104) docs: Add Gavagai to INTHEWILD (@ninaviereckel)
|
||||
- [#28786](https://github.com/apache/superset/pull/28786) refactor: Removes the export of QueryFormData (@EnxDev)
|
||||
- [#28641](https://github.com/apache/superset/pull/28641) chore: change security error level (@eschutho)
|
||||
- [#29093](https://github.com/apache/superset/pull/29093) docs: various adjustments across the docs (@mholthausen)
|
||||
- [#29077](https://github.com/apache/superset/pull/29077) chore: only use cypress.io when triggered manually (@mistercrunch)
|
||||
- [#28571](https://github.com/apache/superset/pull/28571) chore: remove React 16.4's obsolete React imports (@hainenber)
|
||||
- [#28795](https://github.com/apache/superset/pull/28795) refactor(sqllab): nonblocking new query editor (@justinpark)
|
||||
- [#28822](https://github.com/apache/superset/pull/28822) chore(deps-dev): update @types/lodash requirement from ^4.17.0 to ^4.17.4 in /superset-frontend/plugins/plugin-chart-handlebars (@dependabot[bot])
|
||||
- [#28814](https://github.com/apache/superset/pull/28814) chore(deps): bump core-js from 3.8.3 to 3.37.1 in /superset-frontend (@dependabot[bot])
|
||||
- [#28812](https://github.com/apache/superset/pull/28812) chore(deps): bump @types/lodash from 4.17.0 to 4.17.4 in /superset-websocket (@dependabot[bot])
|
||||
- [#28811](https://github.com/apache/superset/pull/28811) chore(deps): bump react-intersection-observer from 9.8.2 to 9.10.2 in /superset-frontend (@dependabot[bot])
|
||||
- [#28808](https://github.com/apache/superset/pull/28808) chore(deps): bump @types/json-bigint from 1.0.1 to 1.0.4 in /superset-frontend (@dependabot[bot])
|
||||
- [#28801](https://github.com/apache/superset/pull/28801) chore(deps-dev): bump @docusaurus/tsconfig from 3.3.2 to 3.4.0 in /docs (@dependabot[bot])
|
||||
- [#28799](https://github.com/apache/superset/pull/28799) chore(deps): bump @ant-design/icons from 5.3.6 to 5.3.7 in /docs (@dependabot[bot])
|
||||
- [#28802](https://github.com/apache/superset/pull/28802) chore(deps-dev): bump @types/react from 18.3.1 to 18.3.3 in /docs (@dependabot[bot])
|
||||
- [#28805](https://github.com/apache/superset/pull/28805) chore(deps): bump swagger-ui-react from 5.17.5 to 5.17.14 in /docs (@dependabot[bot])
|
||||
- [#28806](https://github.com/apache/superset/pull/28806) chore(deps-dev): bump @docusaurus/module-type-aliases from 3.2.1 to 3.4.0 in /docs (@dependabot[bot])
|
||||
- [#28809](https://github.com/apache/superset/pull/28809) chore(deps-dev): bump @types/node from 20.12.7 to 20.13.0 in /superset-websocket (@dependabot[bot])
|
||||
- [#28817](https://github.com/apache/superset/pull/28817) chore(deps-dev): bump @hot-loader/react-dom from 16.13.0 to 16.14.0 in /superset-frontend (@dependabot[bot])
|
||||
- [#28827](https://github.com/apache/superset/pull/28827) chore(deps-dev): bump exports-loader from 0.7.0 to 5.0.0 in /superset-frontend (@dependabot[bot])
|
||||
- [#28826](https://github.com/apache/superset/pull/28826) chore(deps-dev): bump imports-loader from 3.1.1 to 5.0.0 in /superset-frontend (@dependabot[bot])
|
||||
- [#28824](https://github.com/apache/superset/pull/28824) chore(deps): bump react-window and @types/react-window in /superset-frontend (@dependabot[bot])
|
||||
- [#28823](https://github.com/apache/superset/pull/28823) chore(deps): bump debug from 4.3.4 to 4.3.5 in /superset-websocket/utils/client-ws-app (@dependabot[bot])
|
||||
- [#28773](https://github.com/apache/superset/pull/28773) chore: make docker-compose use less memory (@mistercrunch)
|
||||
- [#28654](https://github.com/apache/superset/pull/28654) chore(revert): "add listener to repaint on visibility change for canvas" (@eschutho)
|
||||
- [#28752](https://github.com/apache/superset/pull/28752) chore: remove duplicate code in `SqlaTable` (@betodealmeida)
|
||||
- [#28710](https://github.com/apache/superset/pull/28710) chore: updated Dutch translations (@Seboeb)
|
||||
- [#28471](https://github.com/apache/superset/pull/28471) chore(🦾): bump python celery 5.3.6 -> 5.4.0 (@github-actions[bot])
|
||||
- [#28742](https://github.com/apache/superset/pull/28742) chore(deps): bump pug from 3.0.2 to 3.0.3 in /superset-websocket/utils/client-ws-app (@dependabot[bot])
|
||||
- [#28716](https://github.com/apache/superset/pull/28716) chore(🦾): bump python importlib-resources 5.12.0 -> 6.4.0 (@github-actions[bot])
|
||||
- [#28718](https://github.com/apache/superset/pull/28718) chore(🦾): bump python zipp 3.18.2 -> 3.19.0 (@github-actions[bot])
|
||||
- [#28719](https://github.com/apache/superset/pull/28719) chore(🦾): bump python cachetools 5.3.2 -> 5.3.3 (@github-actions[bot])
|
||||
- [#28720](https://github.com/apache/superset/pull/28720) chore(🦾): bump python markdown-it-py 2.2.0 -> 3.0.0 (@github-actions[bot])
|
||||
- [#28721](https://github.com/apache/superset/pull/28721) chore(🦾): bump python slack-sdk 3.21.3 -> 3.27.2 (@github-actions[bot])
|
||||
- [#28727](https://github.com/apache/superset/pull/28727) chore(🦾): bump python prompt-toolkit 3.0.38 -> 3.0.44 (@github-actions[bot])
|
||||
- [#28729](https://github.com/apache/superset/pull/28729) chore(🦾): bump python attrs 23.1.0 -> 23.2.0 (@github-actions[bot])
|
||||
- [#28730](https://github.com/apache/superset/pull/28730) chore(🦾): bump python apsw 3.45.3.0 -> 3.46.0.0 (@github-actions[bot])
|
||||
- [#28731](https://github.com/apache/superset/pull/28731) chore(🦾): bump python pytz 2021.3 -> 2024.1 (@github-actions[bot])
|
||||
- [#28570](https://github.com/apache/superset/pull/28570) chore(tags): Handle tagging as part of asset update call (@Vitor-Avila)
|
||||
- [#28722](https://github.com/apache/superset/pull/28722) chore(🦾): bump python wrapt 1.15.0 -> 1.16.0 (@github-actions[bot])
|
||||
- [#28717](https://github.com/apache/superset/pull/28717) chore(🦾): bump python limits 3.4.0 -> 3.12.0 (@github-actions[bot])
|
||||
- [#28723](https://github.com/apache/superset/pull/28723) chore(🦾): bump python mako 1.3.3 -> 1.3.5 (@github-actions[bot])
|
||||
- [#28724](https://github.com/apache/superset/pull/28724) chore(🦾): bump python marshmallow-sqlalchemy 0.23.1 -> 0.28.2 (@github-actions[bot])
|
||||
- [#28725](https://github.com/apache/superset/pull/28725) chore(🦾): bump python wcwidth 0.2.5 -> 0.2.13 (@github-actions[bot])
|
||||
- [#28726](https://github.com/apache/superset/pull/28726) chore(🦾): bump python pyasn1 0.5.1 -> 0.6.0 (@github-actions[bot])
|
||||
- [#28732](https://github.com/apache/superset/pull/28732) chore(🦾): bump python google-auth 2.27.0 -> 2.29.0 (@github-actions[bot])
|
||||
- [#28733](https://github.com/apache/superset/pull/28733) chore(🦾): bump python certifi 2023.7.22 -> 2024.2.2 (@github-actions[bot])
|
||||
- [#28679](https://github.com/apache/superset/pull/28679) chore(🦾): bump python boto3 1.26.130 -> 1.34.112 (@github-actions[bot])
|
||||
- [#28703](https://github.com/apache/superset/pull/28703) chore: remove ipython from development dependencies (@mistercrunch)
|
||||
- [#28661](https://github.com/apache/superset/pull/28661) chore(🦾): bump python stack-data 0.6.2 -> 0.6.3 (@github-actions[bot])
|
||||
- [#28663](https://github.com/apache/superset/pull/28663) chore(🦾): bump python googleapis-common-protos 1.59.0 -> 1.63.0 (@github-actions[bot])
|
||||
- [#28669](https://github.com/apache/superset/pull/28669) chore(🦾): bump python ruff 0.4.4 -> 0.4.5 (@github-actions[bot])
|
||||
- [#28674](https://github.com/apache/superset/pull/28674) chore(🦾): bump python matplotlib 3.7.1 -> 3.9.0 (@github-actions[bot])
|
||||
- [#28696](https://github.com/apache/superset/pull/28696) chore(docs): address common docker compose error message in Quickstart (@sfirke)
|
||||
- [#28681](https://github.com/apache/superset/pull/28681) chore(🦾): bump python requests-oauthlib 1.3.1 -> 2.0.0 (@github-actions[bot])
|
||||
- [#28670](https://github.com/apache/superset/pull/28670) chore(🦾): bump python flask-limiter 3.3.1 -> 3.7.0 (@github-actions[bot])
|
||||
- [#28655](https://github.com/apache/superset/pull/28655) chore(🦾): bump python marshmallow 3.19.0 -> 3.21.2 (@github-actions[bot])
|
||||
- [#28590](https://github.com/apache/superset/pull/28590) chore(🦾): bump python bcrypt 4.0.1 -> 4.1.3 (@github-actions[bot])
|
||||
- [#28657](https://github.com/apache/superset/pull/28657) chore(🦾): bump python bottleneck 1.3.7 -> 1.3.8 (@github-actions[bot])
|
||||
- [#28658](https://github.com/apache/superset/pull/28658) chore(🦾): bump python cattrs 23.2.1 -> 23.2.3 (@github-actions[bot])
|
||||
- [#28659](https://github.com/apache/superset/pull/28659) chore(🦾): bump python typing-extensions 4.11.0 -> 4.12.0 (@github-actions[bot])
|
||||
- [#28660](https://github.com/apache/superset/pull/28660) chore(🦾): bump python wheel 0.40.0 -> 0.43.0 (@github-actions[bot])
|
||||
- [#28662](https://github.com/apache/superset/pull/28662) chore(🦾): bump python pexpect 4.8.0 -> 4.9.0 (@github-actions[bot])
|
||||
- [#28665](https://github.com/apache/superset/pull/28665) chore(🦾): bump python traitlets 5.9.0 -> 5.14.3 (@github-actions[bot])
|
||||
- [#28666](https://github.com/apache/superset/pull/28666) chore(🦾): bump python freezegun 1.4.0 -> 1.5.1 (@github-actions[bot])
|
||||
- [#28668](https://github.com/apache/superset/pull/28668) chore(🦾): bump python babel 2.9.1 -> 2.15.0 (@github-actions[bot])
|
||||
- [#28672](https://github.com/apache/superset/pull/28672) chore(🦾): bump python pyproject-api 1.5.2 -> 1.6.1 (@github-actions[bot])
|
||||
- [#28671](https://github.com/apache/superset/pull/28671) chore(🦾): bump python click-repl 0.2.0 -> 0.3.0 (@github-actions[bot])
|
||||
- [#28675](https://github.com/apache/superset/pull/28675) chore(🦾): bump python kombu 5.3.4 -> 5.3.7 (@github-actions[bot])
|
||||
- [#28676](https://github.com/apache/superset/pull/28676) chore(🦾): bump python cffi 1.15.1 -> 1.16.0 (@github-actions[bot])
|
||||
- [#28677](https://github.com/apache/superset/pull/28677) chore(🦾): bump python click-didyoumean 0.3.0 -> 0.3.1 (@github-actions[bot])
|
||||
- [#28680](https://github.com/apache/superset/pull/28680) chore(🦾): bump python identify 2.5.24 -> 2.5.36 (@github-actions[bot])
|
||||
- [#28682](https://github.com/apache/superset/pull/28682) chore(🦾): bump python pydruid 0.6.6 -> 0.6.9 (@github-actions[bot])
|
||||
- [#28683](https://github.com/apache/superset/pull/28683) chore(🦾): bump python kiwisolver 1.4.4 -> 1.4.5 (@github-actions[bot])
|
||||
- [#28684](https://github.com/apache/superset/pull/28684) chore(🦾): bump python requests 2.31.0 -> 2.32.2 (@github-actions[bot])
|
||||
- [#28574](https://github.com/apache/superset/pull/28574) chore(🦾): bump python dnspython 2.1.0 -> 2.6.1 (@github-actions[bot])
|
||||
- [#28573](https://github.com/apache/superset/pull/28573) chore(🦾): bump python rich 13.3.4 -> 13.7.1 (@github-actions[bot])
|
||||
- [#28535](https://github.com/apache/superset/pull/28535) chore(🦾): bump python pygments 2.15.0 -> 2.18.0 (@github-actions[bot])
|
||||
- [#28580](https://github.com/apache/superset/pull/28580) chore(🦾): bump python deprecated 1.2.13 -> 1.2.14 (@github-actions[bot])
|
||||
- [#28526](https://github.com/apache/superset/pull/28526) chore(🦾): bump python tzlocal 4.3 -> 5.2 (@github-actions[bot])
|
||||
- [#28533](https://github.com/apache/superset/pull/28533) chore(🦾): bump python lazy-object-proxy 1.9.0 -> 1.10.0 (@github-actions[bot])
|
||||
- [#28527](https://github.com/apache/superset/pull/28527) chore(🦾): bump python jsonlines 3.1.0 -> 4.0.0 (@github-actions[bot])
|
||||
- [#28576](https://github.com/apache/superset/pull/28576) chore(🦾): bump python flask-babel 1.0.0 -> 2.0.0 (@github-actions[bot])
|
||||
- [#28577](https://github.com/apache/superset/pull/28577) chore(🦾): bump python tqdm 4.65.0 -> 4.66.4 (@github-actions[bot])
|
||||
- [#28578](https://github.com/apache/superset/pull/28578) chore(🦾): bump python parso 0.8.3 -> 0.8.4 (@github-actions[bot])
|
||||
- [#28579](https://github.com/apache/superset/pull/28579) chore(🦾): bump python tzdata 2023.3 -> 2024.1 (@github-actions[bot])
|
||||
- [#28581](https://github.com/apache/superset/pull/28581) chore(🦾): bump python ijson 3.2.0.post0 -> 3.2.3 (@github-actions[bot])
|
||||
- [#28582](https://github.com/apache/superset/pull/28582) chore(🦾): bump python apsw 3.42.0.1 -> 3.45.3.0 (@github-actions[bot])
|
||||
- [#28583](https://github.com/apache/superset/pull/28583) chore(🦾): bump python distlib 0.3.6 -> 0.3.8 (@github-actions[bot])
|
||||
- [#28585](https://github.com/apache/superset/pull/28585) chore(🦾): bump python pycparser 2.20 -> 2.22 (@github-actions[bot])
|
||||
- [#28589](https://github.com/apache/superset/pull/28589) chore(🦾): bump python idna 3.2 -> 3.7 (@github-actions[bot])
|
||||
- [#28586](https://github.com/apache/superset/pull/28586) chore(🦾): bump python pre-commit 3.7.0 -> 3.7.1 (@github-actions[bot])
|
||||
- [#28587](https://github.com/apache/superset/pull/28587) chore(🦾): bump python sqlalchemy-bigquery 1.10.0 -> 1.11.0 (@github-actions[bot])
|
||||
- [#28588](https://github.com/apache/superset/pull/28588) chore(🦾): bump python google-resumable-media 2.5.0 -> 2.7.0 (@github-actions[bot])
|
||||
- [#28591](https://github.com/apache/superset/pull/28591) chore(🦾): bump python zipp 3.18.1 -> 3.18.2 (@github-actions[bot])
|
||||
- [#28593](https://github.com/apache/superset/pull/28593) chore(🦾): bump python pip-tools 7.3.0 -> 7.4.1 (@github-actions[bot])
|
||||
- [#28584](https://github.com/apache/superset/pull/28584) chore(🦾): bump python ruff 0.4.0 -> 0.4.4 (@github-actions[bot])
|
||||
- [#28540](https://github.com/apache/superset/pull/28540) chore(🦾): bump python tomlkit 0.11.8 -> 0.12.5 (@github-actions[bot])
|
||||
- [#28541](https://github.com/apache/superset/pull/28541) chore(🦾): bump python db-dtypes 1.1.1 -> 1.2.0 (@github-actions[bot])
|
||||
- [#28563](https://github.com/apache/superset/pull/28563) refactor(superset-ui-core): Migrate ChartFrame to RTL (@rtexelm)
|
||||
- [#28522](https://github.com/apache/superset/pull/28522) refactor: Migration of json utilities from core (@eyalezer)
|
||||
- [#28532](https://github.com/apache/superset/pull/28532) chore(🦾): bump python nodeenv 1.7.0 -> 1.8.0 (@github-actions[bot])
|
||||
- [#28537](https://github.com/apache/superset/pull/28537) chore(🦾): bump python numba 0.57.1 -> 0.59.1 (@github-actions[bot])
|
||||
- [#28539](https://github.com/apache/superset/pull/28539) chore(🦾): bump python dill 0.3.6 -> 0.3.8 (@github-actions[bot])
|
||||
- [#28531](https://github.com/apache/superset/pull/28531) chore(🦾): bump python charset-normalizer 3.2.0 -> 3.3.2 (@github-actions[bot])
|
||||
- [#28530](https://github.com/apache/superset/pull/28530) chore(🦾): bump python jsonschema-spec 0.1.4 -> 0.1.6 (@github-actions[bot])
|
||||
- [#28474](https://github.com/apache/superset/pull/28474) chore(🦾): bump python croniter 2.0.3 -> 2.0.5 (@github-actions[bot])
|
||||
- [#28536](https://github.com/apache/superset/pull/28536) chore(🦾): bump python amqp 5.1.1 -> 5.2.0 (@github-actions[bot])
|
||||
- [#28544](https://github.com/apache/superset/pull/28544) chore(🦾): bump python flask-jwt-extended 4.5.3 -> 4.6.0 (@github-actions[bot])
|
||||
- [#28542](https://github.com/apache/superset/pull/28542) chore(🦾): bump python requests-cache 1.1.1 -> 1.2.0 (@github-actions[bot])
|
||||
- [#28528](https://github.com/apache/superset/pull/28528) chore(🦾): bump python zope-event 4.5.0 -> 5.0 (@github-actions[bot])
|
||||
- [#28545](https://github.com/apache/superset/pull/28545) chore(🦾): bump python pyasn1-modules 0.3.0 -> 0.4.0 (@github-actions[bot])
|
||||
- [#28500](https://github.com/apache/superset/pull/28500) chore(🦾): bump python fonttools 4.43.0 -> 4.51.0 (@github-actions[bot])
|
||||
- [#28503](https://github.com/apache/superset/pull/28503) chore(🦾): bump python email-validator 1.1.3 -> 2.1.1 (@github-actions[bot])
|
||||
- [#28506](https://github.com/apache/superset/pull/28506) chore(🦾): bump python numexpr 2.9.0 -> 2.10.0 (@github-actions[bot])
|
||||
- [#28508](https://github.com/apache/superset/pull/28508) chore(docker): Reduce image size and update GECKODRIVER_VERSION ,FIRE… (@alekseyolg)
|
||||
- [#28499](https://github.com/apache/superset/pull/28499) docs: creating a redirect for a legacy link about pre-commit hook (@rusackas)
|
||||
- [#28520](https://github.com/apache/superset/pull/28520) chore: Adds setActiveTabs back (@michael-s-molina)
|
||||
- [#27951](https://github.com/apache/superset/pull/27951) chore(docs): updating alerts & reports documentation WEBDRIVER_BASEURL settings for docker compose (@fisjac)
|
||||
- [#28435](https://github.com/apache/superset/pull/28435) chore(D2D): Add granular permission for dashboard drilling operations (@Vitor-Avila)
|
||||
- [#28399](https://github.com/apache/superset/pull/28399) chore: deprecate old Dashboard endpoints (@dpgaspar)
|
||||
- [#28492](https://github.com/apache/superset/pull/28492) chore: deprecate multiple old APIs (@dpgaspar)
|
||||
- [#28490](https://github.com/apache/superset/pull/28490) chore: bump gunicorn to 22.0.0 (@dpgaspar)
|
||||
- [#28498](https://github.com/apache/superset/pull/28498) chore: Don't mark Helm releases as latest (@michael-s-molina)
|
||||
- [#28046](https://github.com/apache/superset/pull/28046) refactor: Migrate saveModalActions to TypeScript (@EnxDev)
|
||||
- [#28484](https://github.com/apache/superset/pull/28484) chore: remove lost file (@betodealmeida)
|
||||
- [#28309](https://github.com/apache/superset/pull/28309) build(deps): bump ejs from 3.1.8 to 3.1.10 in /superset-frontend (@dependabot[bot])
|
||||
- [#28467](https://github.com/apache/superset/pull/28467) chore(🦾): bump python redis subpackage(s) (@github-actions[bot])
|
||||
- [#28469](https://github.com/apache/superset/pull/28469) chore(🦾): bump python flask-compress 1.14 -> 1.15 (@github-actions[bot])
|
||||
- [#28453](https://github.com/apache/superset/pull/28453) chore: deprecate old Dataset related endpoints (@dpgaspar)
|
||||
- [#28479](https://github.com/apache/superset/pull/28479) chore(🦾): bump python geopy subpackage(s) (@github-actions[bot])
|
||||
- [#28468](https://github.com/apache/superset/pull/28468) chore(🦾): bump python cryptography 42.0.5 -> 42.0.7 (@github-actions[bot])
|
||||
- [#28472](https://github.com/apache/superset/pull/28472) chore(🦾): bump python flask-session subpackage(s) (@github-actions[bot])
|
||||
- [#28465](https://github.com/apache/superset/pull/28465) chore(🦾): bump python flask-migrate subpackage(s) (@github-actions[bot])
|
||||
- [#28464](https://github.com/apache/superset/pull/28464) chore(🦾): bump python markdown subpackage(s) (@github-actions[bot])
|
||||
- [#28463](https://github.com/apache/superset/pull/28463) chore(🦾): bump python flask-caching 2.1.0 -> 2.3.0 (@github-actions[bot])
|
||||
- [#28436](https://github.com/apache/superset/pull/28436) chore(models): Adding encrypted field checks (@craig-rueda)
|
||||
- [#28456](https://github.com/apache/superset/pull/28456) chore(helm): bumping app version to 4.0.1 in helm chart (@lodu)
|
||||
- [#28452](https://github.com/apache/superset/pull/28452) chore: Updates CHANGELOG.md with 4.0.1 data (@michael-s-molina)
|
||||
- [#28404](https://github.com/apache/superset/pull/28404) chore: deprecate old Database endpoints (@dpgaspar)
|
||||
- [#28421](https://github.com/apache/superset/pull/28421) chore(🦾): bump python werkzeug 3.0.1 -> 3.0.3 (@mistercrunch)
|
||||
- [#28430](https://github.com/apache/superset/pull/28430) chore(docs): fix two broken Docusaurus redirect links (@sfirke)
|
||||
- [#28379](https://github.com/apache/superset/pull/28379) chore(build): fix issue that prevent `eslint` displaying type-check report during build (@hainenber)
|
||||
- [#28393](https://github.com/apache/superset/pull/28393) chore(Databricks): New Databricks driver (@Vitor-Avila)
|
||||
- [#28406](https://github.com/apache/superset/pull/28406) chore: unit tests for `catalog_access` (@betodealmeida)
|
||||
- [#28398](https://github.com/apache/superset/pull/28398) chore: Updates CHANGELOG.md with 3.1.3 data (@michael-s-molina)
|
||||
- [#28358](https://github.com/apache/superset/pull/28358) chore: add a github "action-validator" in CI (@mistercrunch)
|
||||
- [#28387](https://github.com/apache/superset/pull/28387) chore: remove and deprecate old CSS templates endpoints (@dpgaspar)
|
||||
- [#28342](https://github.com/apache/superset/pull/28342) chore(build): uplift `webpack`-related packages to v5 (@hainenber)
|
||||
- [#28373](https://github.com/apache/superset/pull/28373) docs: update CVE list (@dpgaspar)
|
||||
- [#28359](https://github.com/apache/superset/pull/28359) refactor(superset-ui-core): Migrate FallbackComponent.test to RTL (@rtexelm)
|
||||
- [#28360](https://github.com/apache/superset/pull/28360) docs: clarifying that config.SQL_QUERY_MUTATOR does not affect cache (@mistercrunch)
|
||||
- [#28362](https://github.com/apache/superset/pull/28362) build(deps): bump swagger-ui-react from 5.17.2 to 5.17.5 in /docs (@dependabot[bot])
|
||||
- [#28344](https://github.com/apache/superset/pull/28344) docs(intro): embed overview video into README.md (@hainenber)
|
||||
- [#28335](https://github.com/apache/superset/pull/28335) chore: Add Apache Spark Jinja template processor (@john-bodley)
|
||||
- [#28285](https://github.com/apache/superset/pull/28285) docs: various improvements across the docs (@mistercrunch)
|
||||
- [#28288](https://github.com/apache/superset/pull/28288) build(deps): bump ws from 8.16.0 to 8.17.0 in /superset-websocket (@dependabot[bot])
|
||||
- [#23730](https://github.com/apache/superset/pull/23730) docs: add npm publish steps to release/readme (@lilykuang)
|
||||
- [#28308](https://github.com/apache/superset/pull/28308) refactor(helm): Allow chart operators to exclude the creation of the secret manifest (@asaf400)
|
||||
- [#28321](https://github.com/apache/superset/pull/28321) chore(dev): remove obsolete image reference to `superset-websocket` + fix minor typo (@hainenber)
|
||||
- [#28311](https://github.com/apache/superset/pull/28311) chore: Move #26288 from "Database Migration" to "Other" (@john-bodley)
|
||||
- [#28154](https://github.com/apache/superset/pull/28154) chore(commands): Remove unnecessary commit (@john-bodley)
|
||||
- [#28298](https://github.com/apache/superset/pull/28298) build(deps): bump markdown-to-jsx from 7.4.1 to 7.4.7 in /superset-frontend (@dependabot[bot])
|
||||
- [#28301](https://github.com/apache/superset/pull/28301) build(deps): bump clsx from 2.1.0 to 2.1.1 in /docs (@dependabot[bot])
|
||||
- [#28306](https://github.com/apache/superset/pull/28306) build(deps-dev): bump eslint-plugin-testing-library from 6.2.0 to 6.2.2 in /superset-frontend (@dependabot[bot])
|
||||
- [#28246](https://github.com/apache/superset/pull/28246) chore: clean up DB create command (@betodealmeida)
|
||||
- [#28284](https://github.com/apache/superset/pull/28284) chore(docs): video now hosted by ASF instead of GitHub (@rusackas)
|
||||
- [#28281](https://github.com/apache/superset/pull/28281) docs: merge database config under Configuration section (@mistercrunch)
|
||||
- [#28278](https://github.com/apache/superset/pull/28278) chore: allow codecov to detect SHA (@mistercrunch)
|
||||
- [#28276](https://github.com/apache/superset/pull/28276) chore: use depth=1 for cloning (@rantoniuk)
|
||||
- [#28163](https://github.com/apache/superset/pull/28163) docs(intro): embed overview video into Intro document (@hainenber)
|
||||
- [#28275](https://github.com/apache/superset/pull/28275) docs(upgrading): clarify upgrade process (@SaTae66)
|
||||
- [#28187](https://github.com/apache/superset/pull/28187) chore(superset-ui-core and NoResultsComponent): Migrate to RTL, add RTL modules to the ui-core (@rtexelm)
|
||||
- [#27891](https://github.com/apache/superset/pull/27891) chore(AlteredSliceTag): Migrate to functional (@rtexelm)
|
||||
- [#28247](https://github.com/apache/superset/pull/28247) docs: set up redirects (@mistercrunch)
|
||||
- [#28240](https://github.com/apache/superset/pull/28240) build(deps): bump polished from 3.7.2 to 4.3.1 in /superset-frontend (@dependabot[bot])
|
||||
- [#27003](https://github.com/apache/superset/pull/27003) docs(maps): jupyter notebook now auto-updates docs site (@rusackas)
|
||||
- [#28220](https://github.com/apache/superset/pull/28220) docs: reorganize the CONTRIBUTING section (@mistercrunch)
|
||||
- [#28243](https://github.com/apache/superset/pull/28243) chore(docs): Move ::: onto its own line to fix caution formatting (@sfirke)
|
||||
- [#28236](https://github.com/apache/superset/pull/28236) chore(docs): add closing ::: to caution tag (@sfirke)
|
||||
- [#28237](https://github.com/apache/superset/pull/28237) chore(docs): reorder pages in the Configuring Superset section (@sfirke)
|
||||
- [#28153](https://github.com/apache/superset/pull/28153) chore: Add custom keywords for SQL Lab autocomplete (@justinpark)
|
||||
- [#28223](https://github.com/apache/superset/pull/28223) chore(plugin-chart-country-map): fix broken urls (@villebro)
|
||||
- [#28217](https://github.com/apache/superset/pull/28217) docs: update README.md to avoid 404 issue (@schuberng)
|
||||
- [#28137](https://github.com/apache/superset/pull/28137) chore: add pylint to pre-commit hook (@mistercrunch)
|
||||
- [#28161](https://github.com/apache/superset/pull/28161) docs: Refactor Documentation Structure (@artofcomputing)
|
||||
- [#28159](https://github.com/apache/superset/pull/28159) chore(tests): Remove unnecessary/problematic app contexts (@john-bodley)
|
||||
- [#28130](https://github.com/apache/superset/pull/28130) docs: add dynamic entity-relationship diagram to docs (@mistercrunch)
|
||||
- [#27831](https://github.com/apache/superset/pull/27831) build(deps): update @types/fetch-mock requirement from ^7.3.3 to ^7.3.8 in /superset-frontend/packages/superset-ui-core (@dependabot[bot])
|
||||
- [#28177](https://github.com/apache/superset/pull/28177) build(deps): bump gh-pages from 3.2.3 to 5.0.0 in /superset-frontend (@dependabot[bot])
|
||||
- [#28134](https://github.com/apache/superset/pull/28134) chore: clean up console upon firing up the CLI (@mistercrunch)
|
||||
- [#28135](https://github.com/apache/superset/pull/28135) chore: get websocket service to start in docker-compose (@mistercrunch)
|
||||
- [#28164](https://github.com/apache/superset/pull/28164) chore: refactor file upload commands (@dpgaspar)
|
||||
- [#28019](https://github.com/apache/superset/pull/28019) chore: change deprecation versions post 4.0 (@eschutho)
|
||||
- [#28129](https://github.com/apache/superset/pull/28129) chore(translations): add Arabic translations stub (@OmarIthawi)
|
||||
- [#28031](https://github.com/apache/superset/pull/28031) chore(translations): fix translations order (@lscheibel)
|
||||
- [#28082](https://github.com/apache/superset/pull/28082) build(deps): bump match-sorter from 6.3.3 to 6.3.4 in /superset-frontend (@dependabot[bot])
|
||||
- [#28085](https://github.com/apache/superset/pull/28085) build(deps): bump react-virtualized-auto-sizer from 1.0.7 to 1.0.24 in /superset-frontend (@dependabot[bot])
|
||||
- [#28069](https://github.com/apache/superset/pull/28069) build(deps): update underscore requirement from ^1.12.1 to ^1.13.6 in /superset-frontend/plugins/legacy-preset-chart-deckgl (@dependabot[bot])
|
||||
- [#28075](https://github.com/apache/superset/pull/28075) build(deps): update prop-types requirement from ^15.6.0 to ^15.8.1 in /superset-frontend/plugins/legacy-preset-chart-deckgl (@dependabot[bot])
|
||||
- [#28068](https://github.com/apache/superset/pull/28068) build(deps-dev): bump fs-extra from 10.1.0 to 11.2.0 in /superset-frontend/packages/generator-superset (@dependabot[bot])
|
||||
- [#28083](https://github.com/apache/superset/pull/28083) build(deps): bump @types/node from 18.0.0 to 20.12.7 in /superset-frontend (@dependabot[bot])
|
||||
- [#28071](https://github.com/apache/superset/pull/28071) build(deps): update xss requirement from ^1.0.10 to ^1.0.15 in /superset-frontend/plugins/legacy-preset-chart-deckgl (@dependabot[bot])
|
||||
- [#27965](https://github.com/apache/superset/pull/27965) build(deps): bump deck.gl from 8.8.27 to 9.0.6 in /superset-frontend/plugins/legacy-preset-chart-deckgl (@dependabot[bot])
|
||||
- [#28131](https://github.com/apache/superset/pull/28131) docs: Updated quick start page. Docker compose command had a typo (@jonedmiston)
|
||||
- [#26746](https://github.com/apache/superset/pull/26746) build(deps): bump chrono-node from 2.2.6 to 2.7.5 in /superset-frontend (@dependabot[bot])
|
||||
- [#26896](https://github.com/apache/superset/pull/26896) build(deps): bump d3-interpolate and @types/d3-interpolate in /superset-frontend (@dependabot[bot])
|
||||
- [#26564](https://github.com/apache/superset/pull/26564) build(deps-dev): bump babel-plugin-jsx-remove-data-test-id from 2.1.3 to 3.0.0 in /superset-frontend (@dependabot[bot])
|
||||
- [#26563](https://github.com/apache/superset/pull/26563) build(deps-dev): bump @types/js-levenshtein from 1.1.0 to 1.1.3 in /superset-frontend (@dependabot[bot])
|
||||
- [#28080](https://github.com/apache/superset/pull/28080) build(deps-dev): bump @docusaurus/module-type-aliases from 3.2.0 to 3.2.1 in /docs (@dependabot[bot])
|
||||
- [#28084](https://github.com/apache/superset/pull/28084) build(deps-dev): bump @applitools/eyes-storybook from 3.46.0 to 3.49.0 in /superset-frontend (@dependabot[bot])
|
||||
- [#28086](https://github.com/apache/superset/pull/28086) build(deps-dev): bump eslint-plugin-storybook from 0.6.15 to 0.8.0 in /superset-frontend (@dependabot[bot])
|
||||
- [#28089](https://github.com/apache/superset/pull/28089) build(deps-dev): bump jsdom from 20.0.0 to 24.0.0 in /superset-frontend (@dependabot[bot])
|
||||
- [#28088](https://github.com/apache/superset/pull/28088) build(deps-dev): bump esbuild-loader from 4.0.3 to 4.1.0 in /superset-frontend (@dependabot[bot])
|
||||
- [#28067](https://github.com/apache/superset/pull/28067) build(deps): bump @types/d3-scale from 2.2.10 to 4.0.8 in /superset-frontend/plugins/plugin-chart-word-cloud (@dependabot[bot])
|
||||
- [#27340](https://github.com/apache/superset/pull/27340) build(deps): bump azure/setup-helm from 3 to 4 (@dependabot[bot])
|
||||
- [#28070](https://github.com/apache/superset/pull/28070) build(deps-dev): bump @types/node from 20.12.4 to 20.12.7 in /superset-websocket (@dependabot[bot])
|
||||
- [#28065](https://github.com/apache/superset/pull/28065) build(deps): update dompurify requirement from ^3.0.11 to ^3.1.0 in /superset-frontend/plugins/legacy-preset-chart-nvd3 (@dependabot[bot])
|
||||
- [#28066](https://github.com/apache/superset/pull/28066) build(deps): update @types/lodash requirement from ^4.14.149 to ^4.17.0 in /superset-frontend/packages/superset-ui-core (@dependabot[bot])
|
||||
- [#26602](https://github.com/apache/superset/pull/26602) refactor: add "button" role to clickable UI elements for improved accessibility (@eulloa10)
|
||||
- [#28127](https://github.com/apache/superset/pull/28127) chore(Dashboard): Improve accessibility chart descriptions (@geido)
|
||||
- [#28081](https://github.com/apache/superset/pull/28081) build(deps): bump react-intersection-observer from 9.6.0 to 9.8.2 in /superset-frontend (@dependabot[bot])
|
||||
- [#28090](https://github.com/apache/superset/pull/28090) build(deps-dev): bump babel-loader from 8.3.0 to 9.1.3 in /superset-frontend (@dependabot[bot])
|
||||
- [#28092](https://github.com/apache/superset/pull/28092) build(deps-dev): bump @types/react-gravatar from 2.6.8 to 2.6.14 in /superset-frontend (@dependabot[bot])
|
||||
- [#28102](https://github.com/apache/superset/pull/28102) docs: small fixes and update of README screenshots (@artofcomputing)
|
||||
- [#28059](https://github.com/apache/superset/pull/28059) chore(Dashboard): Improve Table accessibility (@geido)
|
||||
- [#28099](https://github.com/apache/superset/pull/28099) chore(asf): setting website staging server to point at superset-site's lfs branch (@rusackas)
|
||||
- [#28016](https://github.com/apache/superset/pull/28016) chore(docs): splitting out "stable" feature flags by intent (config vs feature dev) (@rusackas)
|
||||
- [#28077](https://github.com/apache/superset/pull/28077) build(deps): bump @algolia/client-search from 4.23.2 to 4.23.3 in /docs (@dependabot[bot])
|
||||
- [#28074](https://github.com/apache/superset/pull/28074) build(deps-dev): bump typescript from 5.4.3 to 5.4.5 in /docs (@dependabot[bot])
|
||||
- [#28048](https://github.com/apache/superset/pull/28048) chore(asf): disable calendar display by default, click to show (@rusackas)
|
||||
- [#27921](https://github.com/apache/superset/pull/27921) docs: add more warnings for default secrets and docker-compose (@dpgaspar)
|
||||
- [#28064](https://github.com/apache/superset/pull/28064) chore(csp): nix bugherd, add githubusercontent (@rusackas)
|
||||
- [#27998](https://github.com/apache/superset/pull/27998) docs: move mp4 video to superset-site/tree/lfs (@mistercrunch)
|
||||
- [#27978](https://github.com/apache/superset/pull/27978) chore(ASF): adds DOAP file and bumping apache-rat (@rusackas)
|
||||
- [#28041](https://github.com/apache/superset/pull/28041) chore: Updates release related assets (@michael-s-molina)
|
||||
- [#28045](https://github.com/apache/superset/pull/28045) chore(docs): disable bugherd for now (@rusackas)
|
||||
- [#28028](https://github.com/apache/superset/pull/28028) chore: stabilize MySQL tests by aligning isolation levels (@mistercrunch)
|
||||
- [#27884](https://github.com/apache/superset/pull/27884) chore: consolidate the Superset python package metadata (@mistercrunch)
|
||||
- [#28040](https://github.com/apache/superset/pull/28040) docs: Updated NOTICE to 2024 (@esivakumar26)
|
||||
- [#28015](https://github.com/apache/superset/pull/28015) chore(Dashboard): Accessibility filters Popover (@geido)
|
||||
- [#27999](https://github.com/apache/superset/pull/27999) chore: Revert "chore(ci): make pre-commit step faster by skipping superset install" (@mistercrunch)
|
||||
- [#28012](https://github.com/apache/superset/pull/28012) refactor: rename get_sqla_engine_with_context (@betodealmeida)
|
||||
- [#27980](https://github.com/apache/superset/pull/27980) chore: remove no-op.yml as it's not needed anymore (@mistercrunch)
|
||||
- [#27979](https://github.com/apache/superset/pull/27979) chore(ci): make pre-commit step faster by skipping superset install (@mistercrunch)
|
||||
- [#27956](https://github.com/apache/superset/pull/27956) docs: deploy docs when merging to master (@mistercrunch)
|
||||
- [#27906](https://github.com/apache/superset/pull/27906) chore: [proposal] de-matrix python-version in GHAs (@mistercrunch)
|
||||
- [#27976](https://github.com/apache/superset/pull/27976) chore(docs): remove seemingly unused unpkg domain from CSPs (@rusackas)
|
||||
- [#27977](https://github.com/apache/superset/pull/27977) chore(docs): removing Superset Community Newsletter archive (@rusackas)
|
||||
- [#27975](https://github.com/apache/superset/pull/27975) chore(docs): adding ASF Privacy Link. (@rusackas)
|
||||
- [#27954](https://github.com/apache/superset/pull/27954) docs(k8s): making it clear users MUST update secrets for prod instances. (@rusackas)
|
||||
- [#27810](https://github.com/apache/superset/pull/27810) build(deps-dev): update @types/mapbox__geojson-extent requirement from ^1.0.0 to ^1.0.3 in /superset-frontend/plugins/legacy-preset-chart-deckgl (@dependabot[bot])
|
||||
- [#27946](https://github.com/apache/superset/pull/27946) chore(helm): bumping app version to 4.0.0 in helm chart (@lodu)
|
||||
- [#27149](https://github.com/apache/superset/pull/27149) chore(tests): Remove ineffectual login (@john-bodley)
|
||||
- [#27937](https://github.com/apache/superset/pull/27937) chore: Adds 4.0.0 data to CHANGELOG.md and UPDATING.md (@michael-s-molina)
|
||||
- [#27932](https://github.com/apache/superset/pull/27932) docs: fix broken OS Dependencies link in CONTRIBUTING.md (@bgreenlee)
|
||||
- [#27717](https://github.com/apache/superset/pull/27717) chore(explore): Hide non-droppable metric and column list (@justinpark)
|
||||
- [#27880](https://github.com/apache/superset/pull/27880) chore(OAuth2): refactor for custom OAuth2 clients (@betodealmeida)
|
||||
- [#27915](https://github.com/apache/superset/pull/27915) chore(helm): Bumping app version to 3.1.2 in helm chart (@joshkoeneHawking)
|
||||
- [#27334](https://github.com/apache/superset/pull/27334) build(deps-dev): update @babel/types requirement from ^7.23.9 to ^7.24.0 in /superset-frontend/plugins/plugin-chart-pivot-table (@dependabot[bot])
|
||||
- [#27321](https://github.com/apache/superset/pull/27321) build(deps-dev): bump fork-ts-checker-webpack-plugin from 5.2.1 to 9.0.2 in /superset-frontend/packages/superset-ui-demo (@dependabot[bot])
|
||||
- [#27322](https://github.com/apache/superset/pull/27322) build(deps): bump memoize-one from 5.2.1 to 6.0.0 in /superset-frontend/packages/superset-ui-demo (@dependabot[bot])
|
||||
- [#27319](https://github.com/apache/superset/pull/27319) build(deps): update @types/d3-time requirement from ^3.0.0 to ^3.0.3 in /superset-frontend/packages/superset-ui-core (@dependabot[bot])
|
||||
- [#27903](https://github.com/apache/superset/pull/27903) docs: replace broken david badges with libraries.io (@10xLaCroixDrinker)
|
||||
- [#27725](https://github.com/apache/superset/pull/27725) chore(sqllab): Do not strip comments when executing SQL statements (@john-bodley)
|
||||
- [#27888](https://github.com/apache/superset/pull/27888) build(deps-dev): bump @types/node from 20.11.24 to 20.12.4 in /superset-websocket (@dependabot[bot])
|
||||
- [#27805](https://github.com/apache/superset/pull/27805) build(deps): bump @types/lodash from 4.14.202 to 4.17.0 in /superset-websocket (@dependabot[bot])
|
||||
- [#27887](https://github.com/apache/superset/pull/27887) build(deps): bump fetch-retry from 4.1.1 to 6.0.0 in /superset-frontend (@dependabot[bot])
|
||||
- [#27772](https://github.com/apache/superset/pull/27772) chore: Cleanup table access check naming (@john-bodley)
|
||||
- [#27804](https://github.com/apache/superset/pull/27804) build(deps): bump winston from 3.11.0 to 3.13.0 in /superset-websocket (@dependabot[bot])
|
||||
- [#27800](https://github.com/apache/superset/pull/27800) build(deps-dev): update @types/lodash requirement from ^4.14.202 to ^4.17.0 in /superset-frontend/plugins/plugin-chart-handlebars (@dependabot[bot])
|
||||
- [#27318](https://github.com/apache/superset/pull/27318) build(deps): update lodash requirement from ^4.17.15 to ^4.17.21 in /superset-frontend/plugins/legacy-preset-chart-deckgl (@dependabot[bot])
|
||||
- [#27317](https://github.com/apache/superset/pull/27317) build(deps): bump bootstrap-slider from 10.6.2 to 11.0.2 in /superset-frontend/plugins/legacy-preset-chart-deckgl (@dependabot[bot])
|
||||
- [#26975](https://github.com/apache/superset/pull/26975) build(deps-dev): update @types/jest requirement from ^29.5.11 to ^29.5.12 in /superset-frontend/plugins/plugin-chart-pivot-table (@dependabot[bot])
|
||||
- [#27833](https://github.com/apache/superset/pull/27833) build(deps): update @types/react-table requirement from ^7.7.19 to ^7.7.20 in /superset-frontend/plugins/plugin-chart-table (@dependabot[bot])
|
||||
- [#27813](https://github.com/apache/superset/pull/27813) build(deps): bump @docsearch/react from 3.5.2 to 3.6.0 in /docs (@dependabot[bot])
|
||||
- [#27864](https://github.com/apache/superset/pull/27864) chore(🦾): bump python pytest 7.3.1 -> 7.4.4 (@github-actions[bot])
|
||||
- [#27343](https://github.com/apache/superset/pull/27343) build(deps-dev): bump @types/underscore from 1.11.6 to 1.11.15 in /superset-frontend (@dependabot[bot])
|
||||
- [#27852](https://github.com/apache/superset/pull/27852) refactor: Move fetchTimeRange to core package (@kgabryje)
|
||||
- [#27843](https://github.com/apache/superset/pull/27843) chore: Default to engine specification regarding using wildcard (@john-bodley)
|
||||
- [#27878](https://github.com/apache/superset/pull/27878) chore: Updates CHANGELOG.md with 3.1.2 data (@michael-s-molina)
|
||||
- [#27867](https://github.com/apache/superset/pull/27867) chore(🦾): bump python pylint 2.17.7 -> 3.1.0 (@github-actions[bot])
|
||||
- [#27836](https://github.com/apache/superset/pull/27836) build(deps-dev): bump @types/redux-mock-store from 1.0.2 to 1.0.6 in /superset-frontend (@dependabot[bot])
|
||||
- [#27858](https://github.com/apache/superset/pull/27858) chore(sql_parse): Provide more meaningful SQLGlot errors (@john-bodley)
|
||||
- [#27824](https://github.com/apache/superset/pull/27824) build(deps): bump @algolia/client-search from 4.22.1 to 4.23.2 in /docs (@dependabot[bot])
|
||||
- [#27816](https://github.com/apache/superset/pull/27816) build(deps): bump dompurify from 2.4.9 to 3.0.11 in /superset-frontend/plugins/legacy-preset-chart-nvd3 (@dependabot[bot])
|
||||
- [#27874](https://github.com/apache/superset/pull/27874) chore(🦾): bump python pyfakefs 5.2.2 -> 5.3.5 (@github-actions[bot])
|
||||
- [#27872](https://github.com/apache/superset/pull/27872) chore(🦾): bump python grpcio 1.60.1 -> 1.62.1 (@github-actions[bot])
|
||||
- [#27868](https://github.com/apache/superset/pull/27868) chore(🦾): bump python google-cloud-bigquery 3.20.0 -> 3.20.1 (@github-actions[bot])
|
||||
- [#27866](https://github.com/apache/superset/pull/27866) chore(🦾): bump python pytest-cov 4.0.0 -> 5.0.0 (@github-actions[bot])
|
||||
- [#27871](https://github.com/apache/superset/pull/27871) chore(🦾): bump python sqloxide 0.1.33 -> 0.1.43 (@github-actions[bot])
|
||||
- [#27875](https://github.com/apache/superset/pull/27875) chore(🦾): bump python sqlglot 23.2.0 -> 23.6.3 (@github-actions[bot])
|
||||
- [#27870](https://github.com/apache/superset/pull/27870) chore(🦾): bump python docker 6.1.1 -> 7.0.0 (@github-actions[bot])
|
||||
- [#27869](https://github.com/apache/superset/pull/27869) chore(🦾): bump python freezegun 1.2.2 -> 1.4.0 (@github-actions[bot])
|
||||
- [#27873](https://github.com/apache/superset/pull/27873) chore(🦾): bump python pillow 10.2.0 -> 10.3.0 (@github-actions[bot])
|
||||
- [#27865](https://github.com/apache/superset/pull/27865) chore(🦾): bump python pre-commit 3.3.3 -> 3.7.0 (@github-actions[bot])
|
||||
- [#27791](https://github.com/apache/superset/pull/27791) docs: small cleanup (@artofcomputing)
|
||||
- [#27835](https://github.com/apache/superset/pull/27835) build(deps): update xss requirement from ^1.0.14 to ^1.0.15 in /superset-frontend/plugins/plugin-chart-table (@dependabot[bot])
|
||||
- [#27808](https://github.com/apache/superset/pull/27808) build(deps-dev): bump react-test-renderer from 16.9.0 to 16.14.0 in /superset-frontend (@dependabot[bot])
|
||||
- [#27819](https://github.com/apache/superset/pull/27819) build(deps): bump @ant-design/icons from 5.3.1 to 5.3.6 in /docs (@dependabot[bot])
|
||||
- [#27842](https://github.com/apache/superset/pull/27842) chore(sql_parse): Strip leading/trailing whitespace in Jinja macro extraction (@john-bodley)
|
||||
- [#27198](https://github.com/apache/superset/pull/27198) chore(node): bumping Superset to Node 18 (@rusackas)
|
||||
- [#27814](https://github.com/apache/superset/pull/27814) build(deps-dev): bump typescript from 5.3.3 to 5.4.3 in /docs (@dependabot[bot])
|
||||
- [#27818](https://github.com/apache/superset/pull/27818) build(deps-dev): bump @docusaurus/module-type-aliases from 3.1.1 to 3.2.0 in /docs (@dependabot[bot])
|
||||
- [#27823](https://github.com/apache/superset/pull/27823) build(deps-dev): bump @tsconfig/docusaurus from 2.0.2 to 2.0.3 in /docs (@dependabot[bot])
|
||||
- [#24112](https://github.com/apache/superset/pull/24112) chore: Bump to Python3.10 (@EugeneTorap)
|
||||
- [#27802](https://github.com/apache/superset/pull/27802) build(deps): bump actions/github-script from 5 to 7 (@dependabot[bot])
|
||||
- [#27751](https://github.com/apache/superset/pull/27751) chore(🦾): bump python flask-session 0.5.0 -> 0.8.0 (@github-actions[bot])
|
||||
- [#27757](https://github.com/apache/superset/pull/27757) chore(🦾): bump python simplejson 3.17.3 -> 3.19.2 (@github-actions[bot])
|
||||
- [#27839](https://github.com/apache/superset/pull/27839) chore: Updates translation owners (@michael-s-molina)
|
||||
- [#27754](https://github.com/apache/superset/pull/27754) chore(🦾): bump python thrift 0.16.0 -> 0.20.0 (@github-actions[bot])
|
||||
- [#27612](https://github.com/apache/superset/pull/27612) docs: simplify the Quickstart guide (@mistercrunch)
|
||||
- [#27750](https://github.com/apache/superset/pull/27750) chore(🦾): bump python pandas-gbq 0.19.1 -> 0.22.0 (@github-actions[bot])
|
||||
- [#27747](https://github.com/apache/superset/pull/27747) chore(🦾): bump python xlsxwriter 3.0.7 -> 3.0.9 (@github-actions[bot])
|
||||
- [#27758](https://github.com/apache/superset/pull/27758) chore(🦾): bump python google-cloud-bigquery 3.10.0 -> 3.20.0 (@github-actions[bot])
|
||||
- [#27759](https://github.com/apache/superset/pull/27759) chore(🦾): bump python python-dotenv 0.19.0 -> 1.0.1 (@github-actions[bot])
|
||||
- [#27748](https://github.com/apache/superset/pull/27748) chore(🦾): bump python flask-cors 3.0.10 -> 4.0.0 (@github-actions[bot])
|
||||
- [#27746](https://github.com/apache/superset/pull/27746) chore(🦾): bump python cron-descriptor 1.2.24 -> 1.4.3 (@github-actions[bot])
|
||||
- [#27749](https://github.com/apache/superset/pull/27749) chore(🦾): bump python sqlglot 23.0.2 -> 23.2.0 (@github-actions[bot])
|
||||
- [#27756](https://github.com/apache/superset/pull/27756) chore(🦾): bump python humanize 3.11.0 -> 4.9.0 (@github-actions[bot])
|
||||
- [#27755](https://github.com/apache/superset/pull/27755) chore(🦾): bump python flask-talisman 1.0.0 -> 1.1.0 (@github-actions[bot])
|
||||
- [#27753](https://github.com/apache/superset/pull/27753) chore(🦾): bump python packaging 23.1 -> 23.2 (@github-actions[bot])
|
||||
- [#27752](https://github.com/apache/superset/pull/27752) chore(🦾): bump python google-cloud-bigquery 3.10.0 -> 3.20.0 (@github-actions[bot])
|
||||
- [#27728](https://github.com/apache/superset/pull/27728) chore(🦾): bump python gevent 23.9.1 -> 24.2.1 (@github-actions[bot])
|
||||
- [#27740](https://github.com/apache/superset/pull/27740) chore(🦾): bump python flask-compress 1.13 -> 1.14 (@github-actions[bot])
|
||||
- [#27729](https://github.com/apache/superset/pull/27729) chore(🦾): bump python mysqlclient 2.1.0 -> 2.2.4 (@github-actions[bot])
|
||||
- [#27727](https://github.com/apache/superset/pull/27727) chore(🦾): bump python sqlalchemy-bigquery 1.6.1 -> 1.10.0 (@github-actions[bot])
|
||||
- [#27732](https://github.com/apache/superset/pull/27732) chore(🦾): bump python tableschema 1.20.2 -> 1.20.10 (@github-actions[bot])
|
||||
- [#27733](https://github.com/apache/superset/pull/27733) chore(🦾): bump python tabulate 0.8.9 -> 0.8.10 (@github-actions[bot])
|
||||
- [#27735](https://github.com/apache/superset/pull/27735) chore(🦾): bump python mako 1.2.4 -> 1.3.2 (@github-actions[bot])
|
||||
- [#27736](https://github.com/apache/superset/pull/27736) chore(🦾): bump python python-dateutil 2.8.2 -> 2.9.0.post0 (@github-actions[bot])
|
||||
- [#27737](https://github.com/apache/superset/pull/27737) chore(🦾): bump python pyjwt 2.4.0 -> 2.8.0 (@github-actions[bot])
|
||||
- [#27741](https://github.com/apache/superset/pull/27741) chore(🦾): bump python click-option-group 0.5.5 -> 0.5.6 (@github-actions[bot])
|
||||
- [#27742](https://github.com/apache/superset/pull/27742) chore(🦾): bump python typing-extensions 4.4.0 -> 4.10.0 (@github-actions[bot])
|
||||
- [#27726](https://github.com/apache/superset/pull/27726) chore(🦾): bump python playwright 1.41.2 -> 1.42.0 (@github-actions[bot])
|
||||
- [#27731](https://github.com/apache/superset/pull/27731) chore(🦾): bump python pydruid 0.6.5 -> 0.6.6 (@github-actions[bot])
|
||||
- [#27730](https://github.com/apache/superset/pull/27730) chore(🦾): bump python thrift 0.16.0 -> 0.20.0 (@github-actions[bot])
|
||||
- [#27695](https://github.com/apache/superset/pull/27695) chore(🦾): bump python "sqlalchemy==1.4.52" (@github-actions[bot])
|
||||
- [#27687](https://github.com/apache/superset/pull/27687) chore(🦾): bump python "nh3==0.2.17" (@github-actions[bot])
|
||||
- [#27680](https://github.com/apache/superset/pull/27680) chore(🦾): bump python "isodate==0.6.1" (@github-actions[bot])
|
||||
- [#27711](https://github.com/apache/superset/pull/27711) chore: bump pylint (@betodealmeida)
|
||||
- [#27696](https://github.com/apache/superset/pull/27696) chore(🦾): bump python "msgpack==1.0.8" (@github-actions[bot])
|
||||
- [#27688](https://github.com/apache/superset/pull/27688) chore(🦾): bump python "wtforms==3.1.2" (@github-actions[bot])
|
||||
- [#27634](https://github.com/apache/superset/pull/27634) other: Add TechAuditBI to supersetbot metadata.js (@TechAuditBI)
|
||||
- [#27699](https://github.com/apache/superset/pull/27699) chore(🦾): bump python "geopy==2.4.1" (@github-actions[bot])
|
||||
- [#27698](https://github.com/apache/superset/pull/27698) chore(🦾): bump python "backoff==2.2.1" (@github-actions[bot])
|
||||
- [#27692](https://github.com/apache/superset/pull/27692) chore(🦾): bump python "pyparsing==3.1.2" (@github-actions[bot])
|
||||
- [#27693](https://github.com/apache/superset/pull/27693) chore(🦾): bump python "croniter==2.0.3" (@github-actions[bot])
|
||||
- [#27682](https://github.com/apache/superset/pull/27682) chore(🦾): bump python "click==8.1.7" (@github-actions[bot])
|
||||
- [#27681](https://github.com/apache/superset/pull/27681) chore(🦾): bump python "polyline==2.0.2" (@github-actions[bot])
|
||||
- [#27684](https://github.com/apache/superset/pull/27684) chore(🦾): bump python "pyarrow==14.0.2" (@github-actions[bot])
|
||||
- [#27657](https://github.com/apache/superset/pull/27657) chore(🤖): bump python "flask==2.3.3" (@mistercrunch)
|
||||
- [#27655](https://github.com/apache/superset/pull/27655) chore(🤖): bump python "sqlalchemy==1.4.52" (@mistercrunch)
|
||||
- [#27641](https://github.com/apache/superset/pull/27641) chore: fix master builds + bump python library "cryptography" (@mistercrunch)
|
||||
- [#27650](https://github.com/apache/superset/pull/27650) chore(🤖): bump python "alembic==1.13.1" (@github-actions[bot])
|
||||
- [#27653](https://github.com/apache/superset/pull/27653) build(deps-dev): bump express from 4.17.3 to 4.19.2 in /superset-frontend (@dependabot[bot])
|
||||
- [#27651](https://github.com/apache/superset/pull/27651) build(deps): bump express from 4.18.3 to 4.19.2 in /superset-websocket/utils/client-ws-app (@dependabot[bot])
|
||||
- [#27652](https://github.com/apache/superset/pull/27652) build(deps): bump express from 4.18.2 to 4.19.2 in /docs (@dependabot[bot])
|
||||
- [#27649](https://github.com/apache/superset/pull/27649) chore(🤖): bump python "markdown==3.6" (@github-actions[bot])
|
||||
- [#27498](https://github.com/apache/superset/pull/27498) refactor: Migrate CssEditor to typescript (@EnxDev)
|
||||
- [#27422](https://github.com/apache/superset/pull/27422) test(Migration to RTL): Refactor ActivityTable.test.tsx from Enzyme to RTL (@rtexelm)
|
||||
- [#27626](https://github.com/apache/superset/pull/27626) build(deps-dev): bump webpack from 5.90.1 to 5.91.0 in /docs (@dependabot[bot])
|
||||
- [#25540](https://github.com/apache/superset/pull/25540) chore: replace "dashboard" -> "report" in chart email report modal (@sfirke)
|
||||
- [#27596](https://github.com/apache/superset/pull/27596) docs: updates list of countries in country-map-tools.mdx (@jbat)
|
||||
- [#27609](https://github.com/apache/superset/pull/27609) build(deps): bump webpack-dev-middleware from 5.3.1 to 5.3.4 in /docs (@dependabot[bot])
|
||||
- [#27309](https://github.com/apache/superset/pull/27309) refactor: Migrate CopyToClipboard to typescript (@EnxDev)
|
||||
- [#27579](https://github.com/apache/superset/pull/27579) chore(docs): clarifying doc comments about LOGO_TARGET_PATH (@rusackas)
|
||||
- [#27572](https://github.com/apache/superset/pull/27572) chore(examples): organizing example chart yaml files into dashboard folders (@rusackas)
|
||||
- [#27610](https://github.com/apache/superset/pull/27610) build(deps-dev): bump webpack-dev-middleware from 5.3.3 to 5.3.4 in /superset-frontend (@dependabot[bot])
|
||||
- [#27540](https://github.com/apache/superset/pull/27540) docs: make k8s top item in Installation section (@mistercrunch)
|
||||
- [#27574](https://github.com/apache/superset/pull/27574) chore: Update required jobs in .asf.yml (@john-bodley)
|
||||
- [#27569](https://github.com/apache/superset/pull/27569) chore(helm): Bumping app version to 3.1.1 in helm chart (@craig-rueda)
|
||||
- [#27505](https://github.com/apache/superset/pull/27505) chore: 2nd try - simplify python dependencies (@mistercrunch)
|
||||
- [#27533](https://github.com/apache/superset/pull/27533) chore(docs): fix last broken Slack join link in docs (@sfirke)
|
||||
- [#27518](https://github.com/apache/superset/pull/27518) build(deps-dev): bump follow-redirects from 1.15.4 to 1.15.6 in /superset-frontend (@dependabot[bot])
|
||||
- [#27516](https://github.com/apache/superset/pull/27516) build(deps-dev): bump follow-redirects from 1.15.4 to 1.15.6 in /superset-embedded-sdk (@dependabot[bot])
|
||||
- [#27517](https://github.com/apache/superset/pull/27517) build(deps): bump follow-redirects from 1.15.4 to 1.15.6 in /docs (@dependabot[bot])
|
||||
- [#27520](https://github.com/apache/superset/pull/27520) chore: add annotations to `sql_parse.py` (@betodealmeida)
|
||||
- [#27486](https://github.com/apache/superset/pull/27486) chore(docs): relocating the edit page button a tad. (@rusackas)
|
||||
- [#26767](https://github.com/apache/superset/pull/26767) chore: improve SQL parsing (@betodealmeida)
|
||||
- [#27480](https://github.com/apache/superset/pull/27480) chore: Add an extension for Home submenu (@kgabryje)
|
||||
- [#27429](https://github.com/apache/superset/pull/27429) test(Migration to RTL): Refactor ChartTable.test.tsx from Enzyme to RTL (@rtexelm)
|
||||
- [#27469](https://github.com/apache/superset/pull/27469) chore: add unit test for `values_for_column` (@betodealmeida)
|
||||
- [#27327](https://github.com/apache/superset/pull/27327) build(deps-dev): bump eslint from 8.56.0 to 8.57.0 in /superset-websocket (@dependabot[bot])
|
||||
- [#27326](https://github.com/apache/superset/pull/27326) build(deps-dev): bump @types/node from 20.11.16 to 20.11.24 in /superset-websocket (@dependabot[bot])
|
||||
- [#27347](https://github.com/apache/superset/pull/27347) build(deps): bump @storybook/types from 7.6.13 to 7.6.17 in /superset-frontend (@dependabot[bot])
|
||||
- [#27405](https://github.com/apache/superset/pull/27405) chore: upgrade setuptools/pip in Dockerfile (@mistercrunch)
|
||||
- [#27290](https://github.com/apache/superset/pull/27290) docs(import_datasources): Remove legacy documentation and update current use (@ddxv)
|
||||
- [#27325](https://github.com/apache/superset/pull/27325) build(deps-dev): bump @types/jsonwebtoken from 9.0.5 to 9.0.6 in /superset-websocket (@dependabot[bot])
|
||||
- [#27324](https://github.com/apache/superset/pull/27324) build(deps-dev): bump @typescript-eslint/eslint-plugin from 5.61.0 to 5.62.0 in /superset-websocket (@dependabot[bot])
|
||||
- [#27328](https://github.com/apache/superset/pull/27328) build(deps-dev): bump prettier from 3.2.4 to 3.2.5 in /superset-websocket (@dependabot[bot])
|
||||
- [#27342](https://github.com/apache/superset/pull/27342) build(deps): bump react-lines-ellipsis from 0.15.0 to 0.15.4 in /superset-frontend (@dependabot[bot])
|
||||
- [#27337](https://github.com/apache/superset/pull/27337) build(deps): bump express from 4.18.2 to 4.18.3 in /superset-websocket/utils/client-ws-app (@dependabot[bot])
|
||||
- [#27331](https://github.com/apache/superset/pull/27331) build(deps): bump @ant-design/icons from 5.3.0 to 5.3.1 in /docs (@dependabot[bot])
|
||||
- [#27356](https://github.com/apache/superset/pull/27356) chore(docs): remove filterbox section from Exploring docs page (@sfirke)
|
||||
- [#27250](https://github.com/apache/superset/pull/27250) chore: update redis to >= 4.6.0 (@nigzak)
|
||||
- [#27304](https://github.com/apache/superset/pull/27304) chore: Replace deprecated command with environment file (@jongwooo)
|
||||
- [#27297](https://github.com/apache/superset/pull/27297) chore(ci): run unit tests on script changes (@eschutho)
|
||||
- [#27287](https://github.com/apache/superset/pull/27287) docs: update CVEs for 3.0.4 and 3.1.1 (@dpgaspar)
|
||||
- [#27219](https://github.com/apache/superset/pull/27219) build(deps): bump re-resizable from 6.6.1 to 6.9.11 in /superset-frontend (@justinpark)
|
||||
- [#27264](https://github.com/apache/superset/pull/27264) build(deps): bump es5-ext from 0.10.53 to 0.10.63 in /docs (@dependabot[bot])
|
||||
- [#24063](https://github.com/apache/superset/pull/24063) chore: Replace deprecated command with environment file (@jongwooo)
|
||||
- [#26932](https://github.com/apache/superset/pull/26932) build(deps): bump @ant-design/icons from 4.7.0 to 5.3.0 in /docs (@dependabot[bot])
|
||||
- [#27145](https://github.com/apache/superset/pull/27145) refactor(plugins): Time Comparison Utils (@Antonio-RiveroMartnez)
|
||||
- [#26732](https://github.com/apache/superset/pull/26732) build(deps-dev): bump prettier from 3.0.3 to 3.2.4 in /superset-websocket (@dependabot[bot])
|
||||
- [#26765](https://github.com/apache/superset/pull/26765) perf(export): export generates unnecessary files content (@Always-prog)
|
||||
- [#27180](https://github.com/apache/superset/pull/27180) build(deps): bump ip from 1.1.8 to 1.1.9 in /superset-frontend/cypress-base (@dependabot[bot])
|
||||
- [#27175](https://github.com/apache/superset/pull/27175) chore(docs): change 'install from scratch' to 'install from PyPI' (@sfirke)
|
||||
- [#27178](https://github.com/apache/superset/pull/27178) build(deps-dev): bump ip from 2.0.0 to 2.0.1 in /superset-frontend (@dependabot[bot])
|
||||
- [#27147](https://github.com/apache/superset/pull/27147) chore: Remove obsolete actor (@john-bodley)
|
||||
- [#27170](https://github.com/apache/superset/pull/27170) chore: Updates CHANGELOG.md with 3.1.1 data (@michael-s-molina)
|
||||
131
RELEASING/release-notes-4-1/README.md
Normal file
@@ -0,0 +1,131 @@
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
# Release Notes for Superset 4.1.0
|
||||
|
||||
Superset 4.1.0 brings a range of new features and quality of life improvements. This release is a minor version, meaning it doesn't include any breaking changes to ensure a seamless transition for our users. Here are some of the highlights of this release.
|
||||
|
||||
### Big Number With Time Period Updates
|
||||
|
||||
We released a [Big Number with Time Period Comparison](https://github.com/apache/superset/pull/26908) chart as part of Superset 4.0. With the latest update, there are now [color options](https://github.com/apache/superset/pull/27524) for comparisons. The chart now also uses [standardize controls](https://github.com/apache/superset/pull/27193) such that when switching charts will maintain the selected metrics. To enable the new chart, you'll need to enable the `CHART_PLUGINS_EXPERIMENTAL` feature flag.
|
||||
|
||||
<div>
|
||||
<image src="media/big_number_chart.png" alt="Image" width="100%">
|
||||
</div>
|
||||
|
||||
### Table with Time Comparison
|
||||
Added functionality to do [table time comparisons](https://github.com/apache/superset/pull/28057) behind the `CHART_PLUGINS_EXPERIMENTAL` feature flag. This will help improve and facilitate efficient data analysis.
|
||||
|
||||
<div>
|
||||
<image src="media/table_with_time.png" alt="Image" width="100%">
|
||||
</div>
|
||||
|
||||
### New ECharts Versions
|
||||
|
||||
The new ECharts [Heatmap](https://github.com/apache/superset/pull/25353) has been added. Compared to the legacy Heatmap, it has more accurate percentage calculations, server side sorting to respect row limits, and a more interactive legend control that allows selecting a subset of values.
|
||||
|
||||
<div>
|
||||
<image src="media/heatmap.png" alt="Image" width="100%">
|
||||
</div>
|
||||
|
||||
We also added a new ECharts [Histogram](https://github.com/apache/superset/pull/28652) chart. The new chart will help visualize patterns, clusters, and outliers in the data and provides insights into its shape, central tendency, and spread.
|
||||
|
||||
<div>
|
||||
<image src="media/histogram.png" alt="Image" width="100%">
|
||||
</div>
|
||||
|
||||
A new Echarts [Sankey](https://github.com/apache/superset/pull/29329) chart now exists. The chart visually tracks the movement and transformation of values across system stages.
|
||||
|
||||
<div>
|
||||
<image src="media/sankey.png" alt="Image" width="100%">
|
||||
</div>
|
||||
|
||||
You can use the CLI command to migrate Area, Bubble, Line, Sankey, [Heatmap](https://github.com/apache/superset/pull/27771), and [Histogram](https://github.com/apache/superset/pull/28780) chart types but we'll add more as the ECharts migrations continue. Note that migrations for deprecated charts may be forced in upcoming major versions when the code is removed. Running migrations earlier will allow you to de-risk future upgrades while improving user experience.
|
||||
|
||||
```bash
|
||||
Usage: superset viz-migrations [OPTIONS] COMMAND [ARGS]...
|
||||
|
||||
Migrates a viz from one type to another.
|
||||
|
||||
Commands:
|
||||
downgrade Downgrades a viz to the previous version.
|
||||
upgrade Upgrade a viz to the latest version.
|
||||
```
|
||||
|
||||
Note: When migrating dashboards from one Superset instance to another (using import/export features or the Superset CLI), or restoring a backup of prior charts and dashboards, Superset will apply the existing migrations that are used during version upgrades. This will ensure that your charts and dashboards are using the latest and greatest charts that Superset officially supports. For any migration issues, feel free to [open a new issue](https://github.com/apache/superset/issues/new?assignees=&labels=bug&projects=&template=bug-report.yml) in the repo.
|
||||
|
||||
### Improved Upload Forms
|
||||
|
||||
We've made design changes to the [CSV](https://github.com/apache/superset/pull/27840), [Excel](https://github.com/apache/superset/pull/28105), and [Columnar](https://github.com/apache/superset/pull/28192
|
||||
) upload modals to improve user experience and to be more performant. The new designs has the following goals:
|
||||
|
||||
- Improved error handling.
|
||||
- Better backend parameter validation.
|
||||
- More aligned with our other modal dialogs
|
||||
|
||||
#### CSV
|
||||
<div>
|
||||
<img src="media/csv_modal_1.png" alt="Image" width="25%">
|
||||
<img src="media/csv_modal_2.png" alt="Image" width="25%">
|
||||
<img src="media/csv_modal_3.png" alt="Image" width="25%">
|
||||
<img src="media/csv_modal_4.png" alt="Image" width="25%">
|
||||
</div>
|
||||
|
||||
#### Excel
|
||||
<div>
|
||||
<img src="media/excel_modal_1.png" alt="Image" width="25%">
|
||||
<img src="media/excel_modal_2.png" alt="Image" width="25%">
|
||||
<img src="media/excel_modal_3.png" alt="Image" width="25%">
|
||||
<img src="media/excel_modal_4.png" alt="Image" width="25%">
|
||||
</div>
|
||||
|
||||
#### Columnar
|
||||
<div>
|
||||
<img src="media/columnar_modal_1.png" alt="Image" width="33%">
|
||||
<img src="media/columnar_modal_2.png" alt="Image" width="33%">
|
||||
<img src="media/columnar_modal_3.png" alt="Image" width="33%">
|
||||
</div>
|
||||
|
||||
|
||||
### OAuth2 For Databases
|
||||
|
||||
You now have the ability to enable [OAuth2](https://github.com/apache/superset/pull/27631) for databases like BigQuery, Snowflake, Dremio, Databricks, Google Sheets, etc. When enabled, it will allow users to connect to Oauth2 enabled databases with their own credentials.
|
||||
|
||||
### Catalog Support For Databases
|
||||
|
||||
Added support for the [catalog heirachy](https://github.com/apache/superset/pull/28317) for databases that support it, such as [BigQuery (projects), Databricks, Presto, Snowflake, and Trino](https://github.com/apache/superset/pull/28416). Once enabled, users will see catalogs when selecting tables in [SQL Lab, datasets](https://github.com/apache/superset/pull/28376), and when setting up Data Access Roles
|
||||
|
||||
### Slack Upload Files V2 API Updates
|
||||
As part of [[SIP-138] Proposal for Slack file upload V2 integration for Alerts and Reports](https://github.com/apache/superset/issues/29263) we now have support for Slack file upload files v2 API call. This feature is behind the feature flag `ALERT_REPORT_SLACK_V2` and also changes the Slack channel to a selector. You may also need to add the following scopes (`channels:read`, `group:read`) to your Slack bot to work.
|
||||
|
||||
<div>
|
||||
<image src="media/slack_modal.png" alt="Image" width="100%">
|
||||
</div>
|
||||
|
||||
### Total and Percentages In Tooltips For ECharts
|
||||
|
||||
Users can now see both the [total and percentage in tooltips](https://github.com/apache/superset/pull/27950) for ECharts.
|
||||
|
||||
<div>
|
||||
<image src="media/tooltips.png" alt="Image" width="100%">
|
||||
</div>
|
||||
|
||||
### Additional Metadata Bar To Dashboards
|
||||
|
||||
There is now a [metadata bar](https://github.com/apache/superset/pull/27857) added to the header of dashboards. This will now show viewers of the dashboard both the owners and last modified time of the dashboard.
|
||||
BIN
RELEASING/release-notes-4-1/media/big_number_chart.png
Normal file
|
After Width: | Height: | Size: 110 KiB |
BIN
RELEASING/release-notes-4-1/media/columnar_modal_1.png
Normal file
|
After Width: | Height: | Size: 59 KiB |
BIN
RELEASING/release-notes-4-1/media/columnar_modal_2.png
Normal file
|
After Width: | Height: | Size: 44 KiB |
BIN
RELEASING/release-notes-4-1/media/columnar_modal_3.png
Normal file
|
After Width: | Height: | Size: 49 KiB |
BIN
RELEASING/release-notes-4-1/media/csv_modal_1.png
Normal file
|
After Width: | Height: | Size: 66 KiB |
BIN
RELEASING/release-notes-4-1/media/csv_modal_2.png
Normal file
|
After Width: | Height: | Size: 73 KiB |
BIN
RELEASING/release-notes-4-1/media/csv_modal_3.png
Normal file
|
After Width: | Height: | Size: 55 KiB |
BIN
RELEASING/release-notes-4-1/media/csv_modal_4.png
Normal file
|
After Width: | Height: | Size: 49 KiB |
BIN
RELEASING/release-notes-4-1/media/excel_modal_1.png
Normal file
|
After Width: | Height: | Size: 68 KiB |
BIN
RELEASING/release-notes-4-1/media/excel_modal_2.png
Normal file
|
After Width: | Height: | Size: 59 KiB |
BIN
RELEASING/release-notes-4-1/media/excel_modal_3.png
Normal file
|
After Width: | Height: | Size: 53 KiB |
BIN
RELEASING/release-notes-4-1/media/excel_modal_4.png
Normal file
|
After Width: | Height: | Size: 49 KiB |
BIN
RELEASING/release-notes-4-1/media/heatmap.png
Normal file
|
After Width: | Height: | Size: 132 KiB |
BIN
RELEASING/release-notes-4-1/media/histogram.png
Normal file
|
After Width: | Height: | Size: 510 KiB |
BIN
RELEASING/release-notes-4-1/media/sankey.png
Normal file
|
After Width: | Height: | Size: 617 KiB |
BIN
RELEASING/release-notes-4-1/media/slack_modal.png
Normal file
|
After Width: | Height: | Size: 64 KiB |
BIN
RELEASING/release-notes-4-1/media/table_with_time.png
Normal file
|
After Width: | Height: | Size: 168 KiB |
BIN
RELEASING/release-notes-4-1/media/tooltips.png
Normal file
|
After Width: | Height: | Size: 363 KiB |
@@ -22,7 +22,7 @@ under the License.
|
||||
This file documents any backwards-incompatible changes in Superset and
|
||||
assists people when migrating to a new version.
|
||||
|
||||
## Next
|
||||
## 4.1.0
|
||||
|
||||
- [29274](https://github.com/apache/superset/pull/29274): We made it easier to trigger CI on your
|
||||
forks, whether they are public or private. Simply push to a branch that fits `[0-9].[0-9]*` and
|
||||
|
||||
@@ -74,7 +74,12 @@ DATA_CACHE_CONFIG = CACHE_CONFIG
|
||||
|
||||
class CeleryConfig:
|
||||
broker_url = f"redis://{REDIS_HOST}:{REDIS_PORT}/{REDIS_CELERY_DB}"
|
||||
imports = ("superset.sql_lab",)
|
||||
imports = (
|
||||
"superset.sql_lab",
|
||||
"superset.tasks.scheduler",
|
||||
"superset.tasks.thumbnails",
|
||||
"superset.tasks.cache",
|
||||
)
|
||||
result_backend = f"redis://{REDIS_HOST}:{REDIS_PORT}/{REDIS_RESULTS_DB}"
|
||||
worker_prefetch_multiplier = 1
|
||||
task_acks_late = False
|
||||
|
||||
@@ -106,7 +106,7 @@ You can also certify metrics if you'd like for your team in this view.
|
||||
|
||||
2. Virtual calculated columns: you can write SQL queries that
|
||||
customize the appearance and behavior
|
||||
of a specific column (e.g. `CAST(recovery_rate) as float`).
|
||||
of a specific column (e.g. `CAST(recovery_rate as float)`).
|
||||
Aggregate functions aren't allowed in calculated columns.
|
||||
|
||||
<img src={useBaseUrl("/img/tutorial/tutorial_calculated_column.png" )} />
|
||||
|
||||
@@ -230,6 +230,7 @@ module = "tests.*"
|
||||
check_untyped_defs = false
|
||||
disallow_untyped_calls = false
|
||||
disallow_untyped_defs = false
|
||||
disable_error_code = "annotation-unchecked"
|
||||
|
||||
[tool.tox]
|
||||
legacy_tox_ini = """
|
||||
|
||||
@@ -52,7 +52,7 @@ GITHUB_TOKEN = os.environ.get("GITHUB_TOKEN")
|
||||
def fetch_files_github_api(url: str): # type: ignore
|
||||
"""Fetches data using GitHub API."""
|
||||
req = Request(url)
|
||||
req.add_header("Authorization", f"token {GITHUB_TOKEN}")
|
||||
req.add_header("Authorization", f"Bearer {GITHUB_TOKEN}")
|
||||
req.add_header("Accept", "application/vnd.github.v3+json")
|
||||
|
||||
print(f"Fetching from {url}")
|
||||
|
||||
@@ -53,6 +53,9 @@ function test_init() {
|
||||
echo Superset init
|
||||
echo --------------------
|
||||
superset init
|
||||
echo Load test users
|
||||
echo --------------------
|
||||
superset load-test-users
|
||||
}
|
||||
|
||||
#
|
||||
|
||||
2861
superset-frontend/package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "superset",
|
||||
"version": "0.0.0-dev",
|
||||
"version": "4.1.0",
|
||||
"description": "Superset is a data exploration platform designed to be visual, intuitive, and interactive.",
|
||||
"keywords": [
|
||||
"big",
|
||||
@@ -155,6 +155,7 @@
|
||||
"moment-timezone": "^0.5.44",
|
||||
"mousetrap": "^1.6.5",
|
||||
"mustache": "^2.2.1",
|
||||
"nanoid": "^5.0.7",
|
||||
"polished": "^4.3.1",
|
||||
"prop-types": "^15.7.2",
|
||||
"query-string": "^6.13.7",
|
||||
@@ -197,7 +198,6 @@
|
||||
"rimraf": "^3.0.2",
|
||||
"rison": "^0.1.1",
|
||||
"scroll-into-view-if-needed": "^3.1.0",
|
||||
"nanoid": "^5.0.7",
|
||||
"tinycolor2": "^1.4.2",
|
||||
"urijs": "^1.19.8",
|
||||
"use-event-callback": "^0.1.0",
|
||||
@@ -206,7 +206,7 @@
|
||||
"yargs": "^17.7.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@applitools/eyes-storybook": "^3.49.0",
|
||||
"@applitools/eyes-storybook": "^3.50.7",
|
||||
"@babel/cli": "^7.22.6",
|
||||
"@babel/compat-data": "^7.22.6",
|
||||
"@babel/core": "^7.23.9",
|
||||
@@ -226,6 +226,7 @@
|
||||
"@emotion/jest": "^11.11.0",
|
||||
"@hot-loader/react-dom": "^16.14.0",
|
||||
"@istanbuljs/nyc-config-typescript": "^1.0.1",
|
||||
"@mihkeleidast/storybook-addon-source": "^1.0.1",
|
||||
"@storybook/addon-actions": "^8.1.11",
|
||||
"@storybook/addon-controls": "^8.1.11",
|
||||
"@storybook/addon-essentials": "^8.1.11",
|
||||
@@ -338,7 +339,6 @@
|
||||
"source-map-support": "^0.5.21",
|
||||
"speed-measure-webpack-plugin": "^1.5.0",
|
||||
"storybook": "^8.1.11",
|
||||
"@mihkeleidast/storybook-addon-source": "^1.0.1",
|
||||
"style-loader": "^3.3.4",
|
||||
"thread-loader": "^3.0.4",
|
||||
"transform-loader": "^0.2.4",
|
||||
@@ -361,7 +361,9 @@
|
||||
"d3-color": "^3.1.0",
|
||||
"yosay": {
|
||||
"ansi-regex": "^4.1.1"
|
||||
}
|
||||
},
|
||||
"puppeteer": "^22.4.1",
|
||||
"@types/react": "^16.9.53"
|
||||
},
|
||||
"readme": "ERROR: No README data found!",
|
||||
"scarfSettings": {
|
||||
|
||||
@@ -39,14 +39,14 @@ export const ISO8601_AND_CONSTANT = RegExp(
|
||||
);
|
||||
const DATETIME_CONSTANT = ['now', 'today'];
|
||||
const SEVEN_DAYS_AGO = new Date();
|
||||
SEVEN_DAYS_AGO.setUTCHours(0, 0, 0, 0);
|
||||
SEVEN_DAYS_AGO.setHours(0, 0, 0, 0);
|
||||
|
||||
const MIDNIGHT = new Date();
|
||||
MIDNIGHT.setUTCHours(0, 0, 0, 0);
|
||||
MIDNIGHT.setHours(0, 0, 0, 0);
|
||||
|
||||
const defaultCustomRange: CustomRangeType = {
|
||||
sinceDatetime: SEVEN_DAYS_AGO.setUTCDate(
|
||||
SEVEN_DAYS_AGO.getUTCDate() - 7,
|
||||
sinceDatetime: SEVEN_DAYS_AGO.setDate(
|
||||
SEVEN_DAYS_AGO.getDate() - 7,
|
||||
).toString(),
|
||||
sinceMode: 'relative',
|
||||
sinceGrain: 'day',
|
||||
|
||||
@@ -151,14 +151,14 @@ describe('customTimeRangeDecode', () => {
|
||||
it('7) default', () => {
|
||||
const SEVEN_DAYS_AGO = new Date();
|
||||
const MIDNIGHT = new Date();
|
||||
SEVEN_DAYS_AGO.setUTCHours(0, 0, 0, 0);
|
||||
MIDNIGHT.setUTCHours(0, 0, 0, 0);
|
||||
SEVEN_DAYS_AGO.setHours(0, 0, 0, 0);
|
||||
MIDNIGHT.setHours(0, 0, 0, 0);
|
||||
expect(
|
||||
customTimeRangeDecode('now : DATEADD(DATETIME("TODAY"), -7, day)'),
|
||||
).toEqual({
|
||||
customRange: {
|
||||
sinceDatetime: SEVEN_DAYS_AGO.setUTCDate(
|
||||
SEVEN_DAYS_AGO.getUTCDate() - 7,
|
||||
sinceDatetime: SEVEN_DAYS_AGO.setDate(
|
||||
SEVEN_DAYS_AGO.getDate() - 7,
|
||||
).toString(),
|
||||
sinceMode: 'relative',
|
||||
sinceGrain: 'day',
|
||||
@@ -176,18 +176,18 @@ describe('customTimeRangeDecode', () => {
|
||||
|
||||
it('8) relative : relative return default', () => {
|
||||
const SEVEN_DAYS_AGO = new Date();
|
||||
SEVEN_DAYS_AGO.setUTCHours(0, 0, 0, 0);
|
||||
SEVEN_DAYS_AGO.setHours(0, 0, 0, 0);
|
||||
|
||||
const MIDNIGHT = new Date();
|
||||
MIDNIGHT.setUTCHours(0, 0, 0, 0);
|
||||
MIDNIGHT.setHours(0, 0, 0, 0);
|
||||
expect(
|
||||
customTimeRangeDecode(
|
||||
'DATEADD(DATETIME("2021-01-26T00:00:00"), -55, day) : DATEADD(DATETIME("2021-01-27T00:00:00"), 7, day)',
|
||||
),
|
||||
).toEqual({
|
||||
customRange: {
|
||||
sinceDatetime: SEVEN_DAYS_AGO.setUTCDate(
|
||||
SEVEN_DAYS_AGO.getUTCDate() - 7,
|
||||
sinceDatetime: SEVEN_DAYS_AGO.setDate(
|
||||
SEVEN_DAYS_AGO.getDate() - 7,
|
||||
).toString(),
|
||||
sinceMode: 'relative',
|
||||
sinceGrain: 'day',
|
||||
|
||||
@@ -17,26 +17,12 @@
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { SuperChart, getChartTransformPropsRegistry } from '@superset-ui/core';
|
||||
import {
|
||||
WordCloudChartPlugin,
|
||||
LegacyWordCloudChartPlugin,
|
||||
WordCloudTransformProps,
|
||||
} from '@superset-ui/plugin-chart-word-cloud';
|
||||
import { SuperChart } from '@superset-ui/core';
|
||||
import { WordCloudChartPlugin } from '@superset-ui/plugin-chart-word-cloud';
|
||||
import { withResizableChartDemo } from '../../../shared/components/ResizableChartDemo';
|
||||
import data from './data';
|
||||
|
||||
new WordCloudChartPlugin().configure({ key: 'word-cloud2' }).register();
|
||||
new LegacyWordCloudChartPlugin()
|
||||
.configure({ key: 'legacy-word-cloud2' })
|
||||
.register();
|
||||
|
||||
// Enable the new WordCloud Props to show case its full features
|
||||
// if the control panel is updated to be able to pass formData in the new format.
|
||||
getChartTransformPropsRegistry().registerValue(
|
||||
'word-cloud2',
|
||||
WordCloudTransformProps,
|
||||
);
|
||||
|
||||
export default {
|
||||
title: 'Chart Plugins/plugin-chart-word-cloud',
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
@@ -18,7 +18,5 @@
|
||||
*/
|
||||
|
||||
export { default as WordCloudChartPlugin } from './plugin';
|
||||
export { default as WordCloudTransformProps } from './plugin/transformProps';
|
||||
export { default as LegacyWordCloudChartPlugin } from './legacyPlugin';
|
||||
export * from './types';
|
||||
export { default as configureEncodable } from './configureEncodable';
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { t, ChartMetadata, ChartPlugin } from '@superset-ui/core';
|
||||
import transformProps from './transformProps';
|
||||
import buildQuery from '../plugin/buildQuery';
|
||||
import thumbnail from '../images/thumbnail.png';
|
||||
import { LegacyWordCloudFormData } from './types';
|
||||
|
||||
const metadata = new ChartMetadata({
|
||||
credits: ['https://github.com/jasondavies/d3-cloud'],
|
||||
description: '',
|
||||
name: t('Word Cloud'),
|
||||
thumbnail,
|
||||
useLegacyApi: true,
|
||||
});
|
||||
|
||||
export default class LegacyWordCloudChartPlugin extends ChartPlugin<LegacyWordCloudFormData> {
|
||||
constructor() {
|
||||
super({
|
||||
buildQuery,
|
||||
loadChart: () => import('../chart/WordCloud'),
|
||||
metadata,
|
||||
transformProps,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { ChartProps, getColumnLabel } from '@superset-ui/core';
|
||||
import { WordCloudProps, WordCloudEncoding } from '../chart/WordCloud';
|
||||
import { LegacyWordCloudFormData } from './types';
|
||||
|
||||
function getMetricLabel(
|
||||
metric: LegacyWordCloudFormData['metric'],
|
||||
): string | undefined {
|
||||
if (typeof metric === 'string' || typeof metric === 'undefined') {
|
||||
return metric;
|
||||
}
|
||||
if (Array.isArray(metric)) {
|
||||
return metric.length > 0 ? getMetricLabel(metric[0]) : undefined;
|
||||
}
|
||||
|
||||
return metric.label;
|
||||
}
|
||||
|
||||
export default function transformProps(chartProps: ChartProps): WordCloudProps {
|
||||
const { width, height, formData, queriesData } = chartProps;
|
||||
const {
|
||||
colorScheme,
|
||||
metric,
|
||||
rotation,
|
||||
series,
|
||||
sizeFrom = 0,
|
||||
sizeTo,
|
||||
sliceId,
|
||||
} = formData as LegacyWordCloudFormData;
|
||||
|
||||
const metricLabel = getMetricLabel(metric);
|
||||
const seriesLabel = getColumnLabel(series);
|
||||
|
||||
const encoding: Partial<WordCloudEncoding> = {
|
||||
color: {
|
||||
field: seriesLabel,
|
||||
scale: {
|
||||
scheme: colorScheme,
|
||||
},
|
||||
type: 'nominal',
|
||||
},
|
||||
fontSize:
|
||||
typeof metricLabel === 'undefined'
|
||||
? undefined
|
||||
: {
|
||||
field: metricLabel,
|
||||
scale: {
|
||||
range: [sizeFrom, sizeTo],
|
||||
zero: true,
|
||||
},
|
||||
type: 'quantitative',
|
||||
},
|
||||
text: {
|
||||
field: seriesLabel,
|
||||
},
|
||||
};
|
||||
|
||||
return {
|
||||
data: queriesData[0].data,
|
||||
encoding,
|
||||
height,
|
||||
rotation,
|
||||
width,
|
||||
sliceId,
|
||||
colorScheme,
|
||||
};
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { QueryFormColumn, QueryFormData } from '@superset-ui/core';
|
||||
import { RotationType } from '../chart/WordCloud';
|
||||
|
||||
export type LegacyWordCloudFormData = QueryFormData & {
|
||||
colorScheme: string;
|
||||
rotation?: RotationType;
|
||||
series: QueryFormColumn;
|
||||
sizeFrom?: number;
|
||||
sizeTo: number;
|
||||
};
|
||||
@@ -18,7 +18,7 @@
|
||||
*/
|
||||
|
||||
import { t, ChartMetadata, ChartPlugin } from '@superset-ui/core';
|
||||
import transformProps from '../legacyPlugin/transformProps';
|
||||
import transformProps from './transformProps';
|
||||
import buildQuery from './buildQuery';
|
||||
import { WordCloudFormData } from '../types';
|
||||
import thumbnail from '../images/thumbnail.png';
|
||||
|
||||
@@ -17,14 +17,61 @@
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { ChartProps } from '@superset-ui/core';
|
||||
import { WordCloudProps } from '../chart/WordCloud';
|
||||
import { ChartProps, getColumnLabel } from '@superset-ui/core';
|
||||
import { WordCloudProps, WordCloudEncoding } from '../chart/WordCloud';
|
||||
import { WordCloudFormData } from '../types';
|
||||
|
||||
function getMetricLabel(
|
||||
metric: WordCloudFormData['metric'],
|
||||
): string | undefined {
|
||||
if (typeof metric === 'string' || typeof metric === 'undefined') {
|
||||
return metric;
|
||||
}
|
||||
if (Array.isArray(metric)) {
|
||||
return metric.length > 0 ? getMetricLabel(metric[0]) : undefined;
|
||||
}
|
||||
|
||||
return metric.label;
|
||||
}
|
||||
|
||||
export default function transformProps(chartProps: ChartProps): WordCloudProps {
|
||||
const { width, height, formData, queriesData } = chartProps;
|
||||
const { encoding, rotation, sliceId, colorScheme } =
|
||||
formData as WordCloudFormData;
|
||||
const {
|
||||
colorScheme,
|
||||
metric,
|
||||
rotation,
|
||||
series,
|
||||
sizeFrom = 0,
|
||||
sizeTo,
|
||||
sliceId,
|
||||
} = formData as WordCloudFormData;
|
||||
|
||||
const metricLabel = getMetricLabel(metric);
|
||||
const seriesLabel = getColumnLabel(series);
|
||||
|
||||
const encoding: Partial<WordCloudEncoding> = {
|
||||
color: {
|
||||
field: seriesLabel,
|
||||
scale: {
|
||||
scheme: colorScheme,
|
||||
},
|
||||
type: 'nominal',
|
||||
},
|
||||
fontSize:
|
||||
typeof metricLabel === 'undefined'
|
||||
? undefined
|
||||
: {
|
||||
field: metricLabel,
|
||||
scale: {
|
||||
range: [sizeFrom, sizeTo],
|
||||
zero: true,
|
||||
},
|
||||
type: 'quantitative',
|
||||
},
|
||||
text: {
|
||||
field: seriesLabel,
|
||||
},
|
||||
};
|
||||
|
||||
return {
|
||||
data: queriesData[0].data,
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { WordCloudFormData } from '../../src';
|
||||
import buildQuery from '../../src/plugin/buildQuery';
|
||||
import { WordCloudFormData } from '../src';
|
||||
import buildQuery from '../src/plugin/buildQuery';
|
||||
|
||||
describe('WordCloud buildQuery', () => {
|
||||
const formData: WordCloudFormData = {
|
||||
@@ -1,75 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { ChartProps, supersetTheme } from '@superset-ui/core';
|
||||
import transformProps from '../../src/legacyPlugin/transformProps';
|
||||
|
||||
describe('WordCloud transformProps', () => {
|
||||
const formData = {
|
||||
colorScheme: 'bnbColors',
|
||||
datasource: '3__table',
|
||||
granularity_sqla: 'ds',
|
||||
metric: 'sum__num',
|
||||
rotation: 'square',
|
||||
series: 'name',
|
||||
sizeFrom: 10,
|
||||
sizeTo: 70,
|
||||
};
|
||||
const chartProps = new ChartProps({
|
||||
formData,
|
||||
width: 800,
|
||||
height: 600,
|
||||
queriesData: [
|
||||
{
|
||||
data: [{ name: 'Hulk', sum__num: 1 }],
|
||||
},
|
||||
],
|
||||
theme: supersetTheme,
|
||||
});
|
||||
|
||||
it('should transform chart props for word cloud viz', () => {
|
||||
expect(transformProps(chartProps)).toEqual({
|
||||
width: 800,
|
||||
height: 600,
|
||||
encoding: {
|
||||
color: {
|
||||
field: 'name',
|
||||
scale: {
|
||||
scheme: 'bnbColors',
|
||||
},
|
||||
type: 'nominal',
|
||||
},
|
||||
fontSize: {
|
||||
field: 'sum__num',
|
||||
scale: {
|
||||
range: [10, 70],
|
||||
zero: true,
|
||||
},
|
||||
type: 'quantitative',
|
||||
},
|
||||
text: {
|
||||
field: 'name',
|
||||
},
|
||||
},
|
||||
rotation: 'square',
|
||||
colorScheme: 'bnbColors',
|
||||
data: [{ name: 'Hulk', sum__num: 1 }],
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -77,7 +77,7 @@ export function useKeywords(
|
||||
// skipFetch is used to prevent re-evaluating memoized keywords
|
||||
// due to updated api results by skip flag
|
||||
const skipFetch = hasFetchedKeywords && skip;
|
||||
const { data: schemaOptions } = useSchemasQueryState(
|
||||
const { currentData: schemaOptions } = useSchemasQueryState(
|
||||
{
|
||||
dbId,
|
||||
catalog: catalog || undefined,
|
||||
@@ -85,7 +85,7 @@ export function useKeywords(
|
||||
},
|
||||
{ skip: skipFetch || !dbId },
|
||||
);
|
||||
const { data: tableData } = useTablesQueryState(
|
||||
const { currentData: tableData } = useTablesQueryState(
|
||||
{
|
||||
dbId,
|
||||
catalog,
|
||||
@@ -95,7 +95,7 @@ export function useKeywords(
|
||||
{ skip: skipFetch || !dbId || !schema },
|
||||
);
|
||||
|
||||
const { data: functionNames, isError } = useDatabaseFunctionsQuery(
|
||||
const { currentData: functionNames, isError } = useDatabaseFunctionsQuery(
|
||||
{ dbId },
|
||||
{ skip: skipFetch || !dbId },
|
||||
);
|
||||
|
||||
@@ -76,28 +76,35 @@ function QueryAutoRefresh({
|
||||
last_updated_ms: queriesLastUpdate - QUERY_UPDATE_BUFFER_MS,
|
||||
});
|
||||
|
||||
const controller = new AbortController();
|
||||
pendingRequestRef.current = true;
|
||||
SupersetClient.get({
|
||||
endpoint: `/api/v1/query/updated_since?q=${params}`,
|
||||
timeout: QUERY_TIMEOUT_LIMIT,
|
||||
parseMethod: 'json-bigint',
|
||||
signal: controller.signal,
|
||||
})
|
||||
.then(({ json }) => {
|
||||
if (json) {
|
||||
const jsonPayload = json as { result?: QueryResponse[] };
|
||||
if (jsonPayload?.result?.length) {
|
||||
const queries =
|
||||
jsonPayload?.result?.reduce((acc, current) => {
|
||||
acc[current.id] = current;
|
||||
return acc;
|
||||
}, {}) ?? {};
|
||||
jsonPayload?.result?.reduce(
|
||||
(acc: Record<string, QueryResponse>, current) => {
|
||||
acc[current.id] = current;
|
||||
return acc;
|
||||
},
|
||||
{},
|
||||
) ?? {};
|
||||
dispatch(refreshQueries(queries));
|
||||
} else {
|
||||
dispatch(clearInactiveQueries(QUERY_UPDATE_FREQ));
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(() => {})
|
||||
.catch(() => {
|
||||
controller.abort();
|
||||
})
|
||||
.finally(() => {
|
||||
pendingRequestRef.current = false;
|
||||
});
|
||||
|
||||
@@ -70,7 +70,11 @@ const QueryHistory = ({
|
||||
({ sqlLab: { queries } }: SqlLabRootState) => queries,
|
||||
shallowEqual,
|
||||
);
|
||||
const { data, isLoading, isFetching } = useEditorQueriesQuery(
|
||||
const {
|
||||
currentData: data,
|
||||
isLoading,
|
||||
isFetching,
|
||||
} = useEditorQueriesQuery(
|
||||
{ editorId: `${queryEditorId}`, pageIndex },
|
||||
{
|
||||
skip: !isFeatureEnabled(FeatureFlag.SqllabBackendPersistence),
|
||||
|
||||
@@ -47,7 +47,14 @@ beforeEach(() => {
|
||||
count: 0,
|
||||
result: [],
|
||||
});
|
||||
fetchMock.get('glob:*/api/v1/database/*/schemas/?*', {
|
||||
fetchMock.get('glob:*/api/v1/database/3/schemas/?*', {
|
||||
error: 'Unauthorized',
|
||||
});
|
||||
fetchMock.get('glob:*/api/v1/database/1/schemas/?*', {
|
||||
count: 2,
|
||||
result: ['main', 'db1_schema', 'db1_schema2'],
|
||||
});
|
||||
fetchMock.get('glob:*/api/v1/database/2/schemas/?*', {
|
||||
count: 2,
|
||||
result: ['main', 'new_schema'],
|
||||
});
|
||||
@@ -198,7 +205,7 @@ test('should toggle the table when the header is clicked', async () => {
|
||||
);
|
||||
});
|
||||
|
||||
test('When changing database the table list must be updated', async () => {
|
||||
test('When changing database the schema and table list must be updated', async () => {
|
||||
const { rerender } = await renderAndWait(mockedProps, undefined, {
|
||||
...initialState,
|
||||
sqlLab: {
|
||||
@@ -245,6 +252,32 @@ test('When changing database the table list must be updated', async () => {
|
||||
expect(updatedDbSelector[0]).toBeInTheDocument();
|
||||
const updatedTableSelector = await screen.findAllByText(/new_table/i);
|
||||
expect(updatedTableSelector[0]).toBeInTheDocument();
|
||||
|
||||
const select = screen.getByRole('combobox', {
|
||||
name: 'Select schema or type to search schemas',
|
||||
});
|
||||
userEvent.click(select);
|
||||
expect(
|
||||
await screen.findByRole('option', { name: 'main' }),
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
await screen.findByRole('option', { name: 'new_schema' }),
|
||||
).toBeInTheDocument();
|
||||
rerender(
|
||||
<SqlEditorLeftBar
|
||||
{...mockedProps}
|
||||
database={{
|
||||
id: 3,
|
||||
database_name: 'unauth_db',
|
||||
backend: 'minervasql',
|
||||
}}
|
||||
queryEditorId={extraQueryEditor1.id}
|
||||
/>,
|
||||
);
|
||||
userEvent.click(select);
|
||||
expect(
|
||||
await screen.findByText('No compatible schema found'),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('ignore schema api when current schema is deprecated', async () => {
|
||||
|
||||
@@ -105,7 +105,7 @@ const TableElement = ({ table, ...props }: TableElementProps) => {
|
||||
const theme = useTheme();
|
||||
const dispatch = useDispatch();
|
||||
const {
|
||||
data: tableMetadata,
|
||||
currentData: tableMetadata,
|
||||
isSuccess: isMetadataSuccess,
|
||||
isLoading: isMetadataLoading,
|
||||
isError: hasMetadataError,
|
||||
@@ -119,7 +119,7 @@ const TableElement = ({ table, ...props }: TableElementProps) => {
|
||||
{ skip: !expanded },
|
||||
);
|
||||
const {
|
||||
data: tableExtendedMetadata,
|
||||
currentData: tableExtendedMetadata,
|
||||
isSuccess: isExtraMetadataSuccess,
|
||||
isLoading: isExtraMetadataLoading,
|
||||
isError: hasExtendedMetadataError,
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
* under the License.
|
||||
*/
|
||||
import { normalizeTimestamp, QueryState, t } from '@superset-ui/core';
|
||||
import { isEqual, omit } from 'lodash';
|
||||
import { shallowEqual } from 'react-redux';
|
||||
import * as actions from '../actions/sqlLab';
|
||||
import { now } from '../../utils/dates';
|
||||
import {
|
||||
@@ -696,7 +698,17 @@ export default function sqlLabReducer(state = {}, action) {
|
||||
? prevState
|
||||
: currentState,
|
||||
};
|
||||
change = true;
|
||||
if (
|
||||
shallowEqual(
|
||||
omit(newQueries[id], ['extra']),
|
||||
omit(state.queries[id], ['extra']),
|
||||
) &&
|
||||
isEqual(newQueries[id].extra, state.queries[id].extra)
|
||||
) {
|
||||
newQueries[id] = state.queries[id];
|
||||
} else {
|
||||
change = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
if (!change) {
|
||||
|
||||
@@ -449,6 +449,35 @@ describe('sqlLabReducer', () => {
|
||||
expect(newState.queries.abcd.endDttm).toBe(Number(endDttmInStr));
|
||||
expect(newState.queriesLastUpdate).toBe(CHANGED_ON_TIMESTAMP);
|
||||
});
|
||||
it('should skip refreshing queries when polling contains existing results', () => {
|
||||
const completedQuery = {
|
||||
...query,
|
||||
extra: {
|
||||
columns: [],
|
||||
progress: null,
|
||||
},
|
||||
};
|
||||
newState = sqlLabReducer(
|
||||
{
|
||||
...newState,
|
||||
queries: { abcd: query, def: completedQuery },
|
||||
},
|
||||
actions.refreshQueries({
|
||||
abcd: {
|
||||
...query,
|
||||
},
|
||||
def: {
|
||||
...completedQuery,
|
||||
extra: {
|
||||
columns: [],
|
||||
progress: null,
|
||||
},
|
||||
},
|
||||
}),
|
||||
);
|
||||
expect(newState.queries.abcd).toBe(query);
|
||||
expect(newState.queries.def).toBe(completedQuery);
|
||||
});
|
||||
it('should refresh queries when polling returns empty', () => {
|
||||
newState = sqlLabReducer(newState, actions.refreshQueries({}));
|
||||
});
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* 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 { render, screen } from 'spec/helpers/testing-library';
|
||||
import Tooltip, { getTooltipHTML } from './Tooltip';
|
||||
|
||||
test('should render a tooltip', () => {
|
||||
const expected = {
|
||||
title: 'tooltip title',
|
||||
icon: <div>icon</div>,
|
||||
body: <div>body</div>,
|
||||
meta: 'meta',
|
||||
footer: <div>footer</div>,
|
||||
};
|
||||
render(<Tooltip {...expected} />);
|
||||
expect(screen.getByText(expected.title)).toBeInTheDocument();
|
||||
expect(screen.getByText(expected.meta)).toBeInTheDocument();
|
||||
expect(screen.getByText('icon')).toBeInTheDocument();
|
||||
expect(screen.getByText('body')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('returns the tooltip HTML', () => {
|
||||
const html = getTooltipHTML({
|
||||
title: 'tooltip title',
|
||||
icon: <div>icon</div>,
|
||||
body: <div>body</div>,
|
||||
meta: 'meta',
|
||||
footer: <div>footer</div>,
|
||||
});
|
||||
expect(html).toContain('tooltip title');
|
||||
});
|
||||
57
superset-frontend/src/components/AsyncAceEditor/Tooltip.tsx
Normal file
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* 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 { renderToStaticMarkup } from 'react-dom/server';
|
||||
import { Tag } from 'src/components';
|
||||
|
||||
type Props = {
|
||||
title: string;
|
||||
icon?: React.ReactNode;
|
||||
body?: React.ReactNode;
|
||||
meta?: string;
|
||||
footer?: React.ReactNode;
|
||||
};
|
||||
|
||||
export const Tooltip: React.FC<Props> = ({
|
||||
title,
|
||||
icon,
|
||||
body,
|
||||
meta,
|
||||
footer,
|
||||
}) => (
|
||||
<div className="tooltip-detail">
|
||||
<div className="tooltip-detail-head">
|
||||
<div className="tooltip-detail-title">
|
||||
{icon}
|
||||
{title}
|
||||
</div>
|
||||
{meta && (
|
||||
<span className="tooltip-detail-meta">
|
||||
<Tag color="default">{meta}</Tag>
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
{body && <div className="tooltip-detail-body">{body ?? title}</div>}
|
||||
{footer && <div className="tooltip-detail-footer">{footer}</div>}
|
||||
</div>
|
||||
);
|
||||
|
||||
export const getTooltipHTML = (props: Props) =>
|
||||
`${renderToStaticMarkup(<Tooltip {...props} />)}`;
|
||||
|
||||
export default Tooltip;
|
||||
@@ -32,6 +32,10 @@ import AsyncEsmComponent, {
|
||||
} from 'src/components/AsyncEsmComponent';
|
||||
import useEffectEvent from 'src/hooks/useEffectEvent';
|
||||
import cssWorkerUrl from 'ace-builds/src-noconflict/worker-css';
|
||||
import { useTheme, css } from '@superset-ui/core';
|
||||
import { Global } from '@emotion/react';
|
||||
|
||||
export { getTooltipHTML } from './Tooltip';
|
||||
|
||||
config.setModuleUrl('ace/mode/css_worker', cssWorkerUrl);
|
||||
|
||||
@@ -135,6 +139,7 @@ export default function AsyncAceEditor(
|
||||
},
|
||||
ref,
|
||||
) {
|
||||
const supersetTheme = useTheme();
|
||||
const langTools = acequire('ace/ext/language_tools');
|
||||
const setCompleters = useEffectEvent(
|
||||
(keywords: AceCompleterKeyword[]) => {
|
||||
@@ -167,15 +172,66 @@ export default function AsyncAceEditor(
|
||||
}, [keywords, setCompleters]);
|
||||
|
||||
return (
|
||||
<ReactAceEditor
|
||||
ref={ref}
|
||||
mode={mode}
|
||||
theme={theme}
|
||||
tabSize={tabSize}
|
||||
defaultValue={defaultValue}
|
||||
setOptions={{ fontFamily }}
|
||||
{...props}
|
||||
/>
|
||||
<>
|
||||
<Global
|
||||
styles={css`
|
||||
.ace_tooltip {
|
||||
margin-left: ${supersetTheme.gridUnit * 2}px;
|
||||
padding: 0px;
|
||||
border: 1px solid ${supersetTheme.colors.grayscale.light1};
|
||||
}
|
||||
|
||||
& .tooltip-detail {
|
||||
background-color: ${supersetTheme.colors.grayscale.light5};
|
||||
white-space: pre-wrap;
|
||||
word-break: break-all;
|
||||
min-width: ${supersetTheme.gridUnit * 50}px;
|
||||
max-width: ${supersetTheme.gridUnit * 100}px;
|
||||
& .tooltip-detail-head {
|
||||
background-color: ${supersetTheme.colors.grayscale.light4};
|
||||
color: ${supersetTheme.colors.grayscale.dark1};
|
||||
display: flex;
|
||||
column-gap: ${supersetTheme.gridUnit}px;
|
||||
align-items: baseline;
|
||||
justify-content: space-between;
|
||||
}
|
||||
& .tooltip-detail-title {
|
||||
display: flex;
|
||||
column-gap: ${supersetTheme.gridUnit}px;
|
||||
}
|
||||
& .tooltip-detail-body {
|
||||
word-break: break-word;
|
||||
}
|
||||
& .tooltip-detail-head,
|
||||
& .tooltip-detail-body {
|
||||
padding: ${supersetTheme.gridUnit}px
|
||||
${supersetTheme.gridUnit * 2}px;
|
||||
}
|
||||
& .tooltip-detail-footer {
|
||||
border-top: 1px ${supersetTheme.colors.grayscale.light2}
|
||||
solid;
|
||||
padding: 0 ${supersetTheme.gridUnit * 2}px;
|
||||
color: ${supersetTheme.colors.grayscale.dark1};
|
||||
font-size: ${supersetTheme.typography.sizes.xs}px;
|
||||
}
|
||||
& .tooltip-detail-meta {
|
||||
& > .ant-tag {
|
||||
margin-right: 0px;
|
||||
}
|
||||
}
|
||||
}
|
||||
`}
|
||||
/>
|
||||
<ReactAceEditor
|
||||
ref={ref}
|
||||
mode={mode}
|
||||
theme={theme}
|
||||
tabSize={tabSize}
|
||||
defaultValue={defaultValue}
|
||||
setOptions={{ fontFamily }}
|
||||
{...props}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -272,7 +272,6 @@ test('should display options in order of the api response', async () => {
|
||||
});
|
||||
|
||||
test('Should fetch the search keyword when total count exceeds initial options', async () => {
|
||||
fetchMock.reset();
|
||||
fetchMock.get(
|
||||
databaseApiRoute,
|
||||
{
|
||||
@@ -365,7 +364,7 @@ test('Sends the correct schema when changing the schema', async () => {
|
||||
});
|
||||
await waitFor(() => expect(fetchMock.calls(databaseApiRoute).length).toBe(1));
|
||||
rerender(<DatabaseSelector {...props} />);
|
||||
expect(props.onSchemaChange).toBeCalledTimes(0);
|
||||
expect(props.onSchemaChange).toHaveBeenCalledTimes(0);
|
||||
const select = screen.getByRole('combobox', {
|
||||
name: 'Select schema or type to search schemas',
|
||||
});
|
||||
@@ -376,5 +375,5 @@ test('Sends the correct schema when changing the schema', async () => {
|
||||
await waitFor(() =>
|
||||
expect(props.onSchemaChange).toHaveBeenCalledWith('information_schema'),
|
||||
);
|
||||
expect(props.onSchemaChange).toBeCalledTimes(1);
|
||||
expect(props.onSchemaChange).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
@@ -260,7 +260,7 @@ export default function DatabaseSelector({
|
||||
}
|
||||
|
||||
const {
|
||||
data: schemaData,
|
||||
currentData: schemaData,
|
||||
isFetching: loadingSchemas,
|
||||
refetch: refetchSchemas,
|
||||
} = useSchemas({
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
import {
|
||||
ChangeEvent,
|
||||
KeyboardEvent,
|
||||
memo,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useLayoutEffect,
|
||||
@@ -72,144 +73,154 @@ const titleStyles = (theme: SupersetTheme) => css`
|
||||
position: absolute;
|
||||
left: -9999px;
|
||||
display: inline-block;
|
||||
white-space: pre;
|
||||
}
|
||||
`;
|
||||
|
||||
export const DynamicEditableTitle = ({
|
||||
title,
|
||||
placeholder,
|
||||
onSave,
|
||||
canEdit,
|
||||
label,
|
||||
}: DynamicEditableTitleProps) => {
|
||||
const [isEditing, setIsEditing] = useState(false);
|
||||
const [currentTitle, setCurrentTitle] = useState(title || '');
|
||||
const contentRef = useRef<HTMLInputElement>(null);
|
||||
const [showTooltip, setShowTooltip] = useState(false);
|
||||
export const DynamicEditableTitle = memo(
|
||||
({
|
||||
title,
|
||||
placeholder,
|
||||
onSave,
|
||||
canEdit,
|
||||
label,
|
||||
}: DynamicEditableTitleProps) => {
|
||||
const [isEditing, setIsEditing] = useState(false);
|
||||
const [currentTitle, setCurrentTitle] = useState(title || '');
|
||||
const contentRef = useRef<HTMLInputElement>(null);
|
||||
const [showTooltip, setShowTooltip] = useState(false);
|
||||
|
||||
const { width: inputWidth, ref: sizerRef } = useResizeDetector();
|
||||
const { width: containerWidth, ref: containerRef } = useResizeDetector({
|
||||
refreshMode: 'debounce',
|
||||
});
|
||||
const { width: inputWidth, ref: sizerRef } = useResizeDetector();
|
||||
const { width: containerWidth, ref: containerRef } = useResizeDetector({
|
||||
refreshMode: 'debounce',
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
setCurrentTitle(title);
|
||||
}, [title]);
|
||||
useEffect(() => {
|
||||
setCurrentTitle(title);
|
||||
}, [title]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isEditing && contentRef?.current) {
|
||||
contentRef.current.focus();
|
||||
// move cursor and scroll to the end
|
||||
if (contentRef.current.setSelectionRange) {
|
||||
const { length } = contentRef.current.value;
|
||||
contentRef.current.setSelectionRange(length, length);
|
||||
contentRef.current.scrollLeft = contentRef.current.scrollWidth;
|
||||
useEffect(() => {
|
||||
if (isEditing && contentRef?.current) {
|
||||
contentRef.current.focus();
|
||||
// move cursor and scroll to the end
|
||||
if (contentRef.current.setSelectionRange) {
|
||||
const { length } = contentRef.current.value;
|
||||
contentRef.current.setSelectionRange(length, length);
|
||||
contentRef.current.scrollLeft = contentRef.current.scrollWidth;
|
||||
}
|
||||
}
|
||||
}
|
||||
}, [isEditing]);
|
||||
}, [isEditing]);
|
||||
|
||||
// a trick to make the input grow when user types text
|
||||
// we make additional span component, place it somewhere out of view and copy input
|
||||
// then we can measure the width of that span to resize the input element
|
||||
useLayoutEffect(() => {
|
||||
if (sizerRef?.current) {
|
||||
sizerRef.current.textContent = currentTitle || placeholder;
|
||||
}
|
||||
}, [currentTitle, placeholder, sizerRef]);
|
||||
// a trick to make the input grow when user types text
|
||||
// we make additional span component, place it somewhere out of view and copy input
|
||||
// then we can measure the width of that span to resize the input element
|
||||
useLayoutEffect(() => {
|
||||
if (sizerRef?.current) {
|
||||
sizerRef.current.textContent = currentTitle || placeholder;
|
||||
}
|
||||
}, [currentTitle, placeholder, sizerRef]);
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
contentRef.current &&
|
||||
contentRef.current.scrollWidth > contentRef.current.clientWidth
|
||||
) {
|
||||
setShowTooltip(true);
|
||||
} else {
|
||||
setShowTooltip(false);
|
||||
}
|
||||
}, [inputWidth, containerWidth]);
|
||||
useEffect(() => {
|
||||
if (
|
||||
contentRef.current &&
|
||||
contentRef.current.scrollWidth > contentRef.current.clientWidth
|
||||
) {
|
||||
setShowTooltip(true);
|
||||
} else {
|
||||
setShowTooltip(false);
|
||||
}
|
||||
}, [inputWidth, containerWidth]);
|
||||
|
||||
const handleClick = useCallback(() => {
|
||||
if (!canEdit || isEditing) {
|
||||
return;
|
||||
}
|
||||
setIsEditing(true);
|
||||
}, [canEdit, isEditing]);
|
||||
|
||||
const handleBlur = useCallback(() => {
|
||||
if (!canEdit) {
|
||||
return;
|
||||
}
|
||||
const formattedTitle = currentTitle.trim();
|
||||
setCurrentTitle(formattedTitle);
|
||||
if (title !== formattedTitle) {
|
||||
onSave(formattedTitle);
|
||||
}
|
||||
setIsEditing(false);
|
||||
}, [canEdit, currentTitle, onSave, title]);
|
||||
|
||||
const handleChange = useCallback(
|
||||
(ev: ChangeEvent<HTMLInputElement>) => {
|
||||
if (!canEdit || !isEditing) {
|
||||
const handleClick = useCallback(() => {
|
||||
if (!canEdit || isEditing) {
|
||||
return;
|
||||
}
|
||||
setCurrentTitle(ev.target.value);
|
||||
},
|
||||
[canEdit, isEditing],
|
||||
);
|
||||
setIsEditing(true);
|
||||
}, [canEdit, isEditing]);
|
||||
|
||||
const handleKeyPress = useCallback(
|
||||
(ev: KeyboardEvent<HTMLInputElement>) => {
|
||||
const handleBlur = useCallback(() => {
|
||||
if (!canEdit) {
|
||||
return;
|
||||
}
|
||||
if (ev.key === 'Enter') {
|
||||
ev.preventDefault();
|
||||
contentRef.current?.blur();
|
||||
const formattedTitle = currentTitle.trim();
|
||||
setCurrentTitle(formattedTitle);
|
||||
if (title !== formattedTitle) {
|
||||
onSave(formattedTitle);
|
||||
}
|
||||
},
|
||||
[canEdit],
|
||||
);
|
||||
setIsEditing(false);
|
||||
}, [canEdit, currentTitle, onSave, title]);
|
||||
|
||||
return (
|
||||
<div css={titleStyles} ref={containerRef}>
|
||||
<Tooltip
|
||||
id="title-tooltip"
|
||||
title={showTooltip && currentTitle && !isEditing ? currentTitle : null}
|
||||
>
|
||||
{canEdit ? (
|
||||
<input
|
||||
data-test="editable-title-input"
|
||||
className="dynamic-title-input"
|
||||
aria-label={label ?? t('Title')}
|
||||
ref={contentRef}
|
||||
onChange={handleChange}
|
||||
onBlur={handleBlur}
|
||||
onClick={handleClick}
|
||||
onKeyPress={handleKeyPress}
|
||||
placeholder={placeholder}
|
||||
value={currentTitle}
|
||||
css={css`
|
||||
cursor: ${isEditing ? 'text' : 'pointer'};
|
||||
const handleChange = useCallback(
|
||||
(ev: ChangeEvent<HTMLInputElement>) => {
|
||||
if (!canEdit || !isEditing) {
|
||||
return;
|
||||
}
|
||||
setCurrentTitle(ev.target.value);
|
||||
},
|
||||
[canEdit, isEditing],
|
||||
);
|
||||
|
||||
${inputWidth &&
|
||||
inputWidth > 0 &&
|
||||
css`
|
||||
width: ${inputWidth + 1}px;
|
||||
const handleKeyPress = useCallback(
|
||||
(ev: KeyboardEvent<HTMLInputElement>) => {
|
||||
if (!canEdit) {
|
||||
return;
|
||||
}
|
||||
if (ev.key === 'Enter') {
|
||||
ev.preventDefault();
|
||||
contentRef.current?.blur();
|
||||
}
|
||||
},
|
||||
[canEdit],
|
||||
);
|
||||
|
||||
return (
|
||||
<div css={titleStyles} ref={containerRef}>
|
||||
<Tooltip
|
||||
id="title-tooltip"
|
||||
title={
|
||||
showTooltip && currentTitle && !isEditing ? currentTitle : null
|
||||
}
|
||||
>
|
||||
{canEdit ? (
|
||||
<input
|
||||
data-test="editable-title-input"
|
||||
className="dynamic-title-input"
|
||||
aria-label={label ?? t('Title')}
|
||||
ref={contentRef}
|
||||
onChange={handleChange}
|
||||
onBlur={handleBlur}
|
||||
onClick={handleClick}
|
||||
onKeyPress={handleKeyPress}
|
||||
placeholder={placeholder}
|
||||
value={currentTitle}
|
||||
css={css`
|
||||
cursor: ${isEditing ? 'text' : 'pointer'};
|
||||
|
||||
${inputWidth &&
|
||||
inputWidth > 0 &&
|
||||
css`
|
||||
width: ${inputWidth + 1}px;
|
||||
`}
|
||||
`}
|
||||
`}
|
||||
/>
|
||||
) : (
|
||||
<span
|
||||
className="dynamic-title"
|
||||
aria-label={label ?? t('Title')}
|
||||
ref={contentRef}
|
||||
data-test="editable-title"
|
||||
>
|
||||
{currentTitle}
|
||||
</span>
|
||||
)}
|
||||
</Tooltip>
|
||||
<span ref={sizerRef} className="input-sizer" aria-hidden tabIndex={-1} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
/>
|
||||
) : (
|
||||
<span
|
||||
className="dynamic-title"
|
||||
aria-label={label ?? t('Title')}
|
||||
ref={contentRef}
|
||||
data-test="editable-title"
|
||||
>
|
||||
{currentTitle}
|
||||
</span>
|
||||
)}
|
||||
</Tooltip>
|
||||
<span
|
||||
ref={sizerRef}
|
||||
className="input-sizer"
|
||||
aria-hidden
|
||||
tabIndex={-1}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { AntdThemeProvider } from 'src/components/AntdThemeProvider';
|
||||
import ProgressBar, { ProgressBarProps } from '.';
|
||||
|
||||
export default {
|
||||
@@ -24,32 +25,39 @@ export default {
|
||||
};
|
||||
|
||||
export const InteractiveProgressBar = (args: ProgressBarProps) => (
|
||||
<ProgressBar {...args} />
|
||||
<AntdThemeProvider>
|
||||
<ProgressBar {...args} type="line" />
|
||||
</AntdThemeProvider>
|
||||
);
|
||||
|
||||
InteractiveProgressBar.args = {
|
||||
export const InteractiveProgressCircle = (args: ProgressBarProps) => (
|
||||
<AntdThemeProvider>
|
||||
<ProgressBar {...args} type="circle" />
|
||||
</AntdThemeProvider>
|
||||
);
|
||||
|
||||
export const InteractiveProgressDashboard = (args: ProgressBarProps) => (
|
||||
<AntdThemeProvider>
|
||||
<ProgressBar {...args} type="dashboard" />
|
||||
</AntdThemeProvider>
|
||||
);
|
||||
|
||||
const commonArgs = {
|
||||
striped: true,
|
||||
percent: 90,
|
||||
showInfo: true,
|
||||
status: 'normal',
|
||||
strokeColor: '#FF0000',
|
||||
trailColor: '#000',
|
||||
strokeLinecap: 'round',
|
||||
type: 'line',
|
||||
};
|
||||
|
||||
InteractiveProgressBar.argTypes = {
|
||||
status: {
|
||||
control: {
|
||||
type: 'select',
|
||||
},
|
||||
options: ['normal', 'success', 'exception', 'active'],
|
||||
},
|
||||
const commonArgTypes = {
|
||||
strokeLinecap: {
|
||||
control: {
|
||||
type: 'select',
|
||||
},
|
||||
options: ['round', 'square'],
|
||||
options: ['round', 'butt', 'square'],
|
||||
},
|
||||
type: {
|
||||
control: {
|
||||
@@ -58,3 +66,26 @@ InteractiveProgressBar.argTypes = {
|
||||
options: ['line', 'circle', 'dashboard'],
|
||||
},
|
||||
};
|
||||
|
||||
InteractiveProgressBar.args = {
|
||||
...commonArgs,
|
||||
status: 'normal',
|
||||
};
|
||||
|
||||
InteractiveProgressBar.argTypes = {
|
||||
...commonArgTypes,
|
||||
status: {
|
||||
control: {
|
||||
type: 'select',
|
||||
},
|
||||
options: ['normal', 'success', 'exception', 'active'],
|
||||
},
|
||||
};
|
||||
|
||||
InteractiveProgressCircle.args = commonArgs;
|
||||
|
||||
InteractiveProgressCircle.argTypes = commonArgTypes;
|
||||
|
||||
InteractiveProgressDashboard.args = commonArgs;
|
||||
|
||||
InteractiveProgressDashboard.argTypes = commonArgTypes;
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
* under the License.
|
||||
*/
|
||||
import { styled } from '@superset-ui/core';
|
||||
import { Progress as AntdProgress } from 'antd';
|
||||
import { ProgressProps } from 'antd/lib/progress/progress';
|
||||
import { Progress as AntdProgress } from 'antd-v5';
|
||||
import { ProgressProps } from 'antd-v5/lib/progress/progress';
|
||||
|
||||
export interface ProgressBarProps extends ProgressProps {
|
||||
striped?: boolean;
|
||||
@@ -28,18 +28,11 @@ export interface ProgressBarProps extends ProgressProps {
|
||||
const ProgressBar = styled(({ striped, ...props }: ProgressBarProps) => (
|
||||
<AntdProgress data-test="progress-bar" {...props} />
|
||||
))`
|
||||
line-height: 0;
|
||||
position: static;
|
||||
.ant-progress-inner {
|
||||
.antd5-progress-inner {
|
||||
position: static;
|
||||
}
|
||||
.ant-progress-outer {
|
||||
${({ percent }) => !percent && `display: none;`}
|
||||
}
|
||||
.ant-progress-text {
|
||||
font-size: ${({ theme }) => theme.typography.sizes.s}px;
|
||||
}
|
||||
.ant-progress-bg {
|
||||
.antd5-progress-bg {
|
||||
position: static;
|
||||
${({ striped }) =>
|
||||
striped &&
|
||||
|
||||
@@ -188,7 +188,7 @@ const TableSelector: FunctionComponent<TableSelectorProps> = ({
|
||||
SelectValue | undefined
|
||||
>(undefined);
|
||||
const {
|
||||
data,
|
||||
currentData: data,
|
||||
isFetching: loadingTables,
|
||||
refetch,
|
||||
} = useTables({
|
||||
|
||||
@@ -675,31 +675,33 @@ const DashboardBuilder: FC<DashboardBuilderProps> = () => {
|
||||
editMode={editMode}
|
||||
marginLeft={dashboardContentMarginLeft}
|
||||
>
|
||||
{missingInitialFilters.length > 0 ? (
|
||||
<div
|
||||
css={css`
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex: 1;
|
||||
& div {
|
||||
width: 500px;
|
||||
}
|
||||
`}
|
||||
>
|
||||
<BasicErrorAlert
|
||||
title={t('Unable to load dashboard')}
|
||||
body={t(
|
||||
`The following filters have the 'Select first filter value by default'
|
||||
{showDashboard ? (
|
||||
missingInitialFilters.length > 0 ? (
|
||||
<div
|
||||
css={css`
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex: 1;
|
||||
& div {
|
||||
width: 500px;
|
||||
}
|
||||
`}
|
||||
>
|
||||
<BasicErrorAlert
|
||||
title={t('Unable to load dashboard')}
|
||||
body={t(
|
||||
`The following filters have the 'Select first filter value by default'
|
||||
option checked and could not be loaded, which is preventing the dashboard
|
||||
from rendering: %s`,
|
||||
missingInitialFilters.join(', '),
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
) : showDashboard ? (
|
||||
<DashboardContainer topLevelTabs={topLevelTabs} />
|
||||
missingInitialFilters.join(', '),
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<DashboardContainer topLevelTabs={topLevelTabs} />
|
||||
)
|
||||
) : (
|
||||
<Loading />
|
||||
)}
|
||||
|
||||
@@ -56,6 +56,7 @@ export function ColumnSelect({
|
||||
mode,
|
||||
}: ColumnSelectProps) {
|
||||
const [columns, setColumns] = useState<Column[]>();
|
||||
const [loading, setLoading] = useState(false);
|
||||
const { addDangerToast } = useToasts();
|
||||
const resetColumnField = useCallback(() => {
|
||||
form.setFields([
|
||||
@@ -87,9 +88,11 @@ export function ColumnSelect({
|
||||
|
||||
useChangeEffect(datasetId, previous => {
|
||||
if (previous != null) {
|
||||
setColumns([]);
|
||||
resetColumnField();
|
||||
}
|
||||
if (datasetId != null) {
|
||||
setLoading(true);
|
||||
cachedSupersetGet({
|
||||
endpoint: `/api/v1/dataset/${datasetId}?q=${rison.encode({
|
||||
columns: [
|
||||
@@ -98,26 +101,30 @@ export function ColumnSelect({
|
||||
'columns.type_generic',
|
||||
],
|
||||
})}`,
|
||||
}).then(
|
||||
({ json: { result } }) => {
|
||||
const lookupValue = Array.isArray(value) ? value : [value];
|
||||
const valueExists = result.columns.some(
|
||||
(column: Column) => lookupValue?.includes(column.column_name),
|
||||
);
|
||||
if (!valueExists) {
|
||||
resetColumnField();
|
||||
}
|
||||
setColumns(result.columns);
|
||||
},
|
||||
async badResponse => {
|
||||
const { error, message } = await getClientErrorObject(badResponse);
|
||||
let errorText = message || error || t('An error has occurred');
|
||||
if (message === 'Forbidden') {
|
||||
errorText = t('You do not have permission to edit this dashboard');
|
||||
}
|
||||
addDangerToast(errorText);
|
||||
},
|
||||
);
|
||||
})
|
||||
.then(
|
||||
({ json: { result } }) => {
|
||||
const lookupValue = Array.isArray(value) ? value : [value];
|
||||
const valueExists = result.columns.some(
|
||||
(column: Column) => lookupValue?.includes(column.column_name),
|
||||
);
|
||||
if (!valueExists) {
|
||||
resetColumnField();
|
||||
}
|
||||
setColumns(result.columns);
|
||||
},
|
||||
async badResponse => {
|
||||
const { error, message } = await getClientErrorObject(badResponse);
|
||||
let errorText = message || error || t('An error has occurred');
|
||||
if (message === 'Forbidden') {
|
||||
errorText = t(
|
||||
'You do not have permission to edit this dashboard',
|
||||
);
|
||||
}
|
||||
addDangerToast(errorText);
|
||||
},
|
||||
)
|
||||
.finally(() => setLoading(false));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -126,6 +133,7 @@ export function ColumnSelect({
|
||||
mode={mode}
|
||||
value={mode === 'multiple' ? value || [] : value}
|
||||
ariaLabel={t('Column select')}
|
||||
loading={loading}
|
||||
onChange={onChange}
|
||||
options={options}
|
||||
placeholder={t('Select a column')}
|
||||
|
||||
@@ -34,6 +34,7 @@ describe('FilterScope', () => {
|
||||
const save = jest.fn();
|
||||
let form: FormInstance<NativeFiltersForm>;
|
||||
const mockedProps = {
|
||||
expanded: false,
|
||||
filterId: 'DefaultFilterId',
|
||||
dependencies: [],
|
||||
setErroredFilters: jest.fn(),
|
||||
|
||||
@@ -105,6 +105,8 @@ import {
|
||||
import { FILTER_SUPPORTED_TYPES, INPUT_WIDTH } from './constants';
|
||||
import DependencyList from './DependencyList';
|
||||
|
||||
const FORM_ITEM_WIDTH = 260;
|
||||
|
||||
const TabPane = styled(Tabs.TabPane)`
|
||||
padding: ${({ theme }) => theme.gridUnit * 4}px 0px;
|
||||
`;
|
||||
@@ -136,8 +138,8 @@ const controlsOrder: ControlKey[] = [
|
||||
'inverseSelection',
|
||||
];
|
||||
|
||||
export const StyledFormItem = styled(FormItem)`
|
||||
width: 49%;
|
||||
export const StyledFormItem = styled(FormItem)<{ expanded: boolean }>`
|
||||
width: ${({ expanded }) => (expanded ? '49%' : `${FORM_ITEM_WIDTH}px`)};
|
||||
margin-bottom: ${({ theme }) => theme.gridUnit * 4}px;
|
||||
|
||||
& .ant-form-item-label {
|
||||
@@ -149,10 +151,10 @@ export const StyledFormItem = styled(FormItem)`
|
||||
}
|
||||
`;
|
||||
|
||||
export const StyledRowFormItem = styled(FormItem)`
|
||||
export const StyledRowFormItem = styled(FormItem)<{ expanded: boolean }>`
|
||||
margin-bottom: 0;
|
||||
padding-bottom: 0;
|
||||
min-width: 50%;
|
||||
min-width: ${({ expanded }) => (expanded ? '50%' : `${FORM_ITEM_WIDTH}px`)};
|
||||
|
||||
& .ant-form-item-label {
|
||||
padding-bottom: 0;
|
||||
@@ -167,8 +169,8 @@ export const StyledRowFormItem = styled(FormItem)`
|
||||
}
|
||||
`;
|
||||
|
||||
export const StyledRowSubFormItem = styled(FormItem)`
|
||||
min-width: 50%;
|
||||
export const StyledRowSubFormItem = styled(FormItem)<{ expanded: boolean }>`
|
||||
min-width: ${({ expanded }) => (expanded ? '50%' : `${FORM_ITEM_WIDTH}px`)};
|
||||
|
||||
& .ant-form-item-label {
|
||||
padding-bottom: 0;
|
||||
@@ -264,9 +266,9 @@ const StyledAsterisk = styled.span`
|
||||
}
|
||||
`;
|
||||
|
||||
const FilterTypeInfo = styled.div`
|
||||
${({ theme }) => `
|
||||
width: 49%;
|
||||
const FilterTypeInfo = styled.div<{ expanded: boolean }>`
|
||||
${({ theme, expanded }) => `
|
||||
width: ${expanded ? '49%' : `${FORM_ITEM_WIDTH}px`};
|
||||
font-size: ${theme.typography.sizes.s}px;
|
||||
color: ${theme.colors.grayscale.light1};
|
||||
margin:
|
||||
@@ -300,6 +302,7 @@ export const FilterPanels = {
|
||||
};
|
||||
|
||||
export interface FiltersConfigFormProps {
|
||||
expanded: boolean;
|
||||
filterId: string;
|
||||
filterToEdit?: Filter;
|
||||
removedFilters: Record<string, FilterRemoval>;
|
||||
@@ -334,6 +337,7 @@ const FILTER_TYPE_NAME_MAPPING = {
|
||||
*/
|
||||
const FiltersConfigForm = (
|
||||
{
|
||||
expanded,
|
||||
filterId,
|
||||
filterToEdit,
|
||||
removedFilters,
|
||||
@@ -376,7 +380,7 @@ const FiltersConfigForm = (
|
||||
const nativeFilterVizTypes = Object.entries(nativeFilterItems)
|
||||
// @ts-ignore
|
||||
.filter(([, { value }]) => value.behaviors?.includes(Behavior.NativeFilter))
|
||||
.map(([key]) => key);
|
||||
.map(([key]) => key as keyof typeof FILTER_SUPPORTED_TYPES);
|
||||
|
||||
const loadedDatasets = useSelector<RootState, DatasourcesState>(
|
||||
({ datasources }) => datasources,
|
||||
@@ -411,6 +415,7 @@ const FiltersConfigForm = (
|
||||
|
||||
const { controlItems = {}, mainControlItems = {} } = formFilter
|
||||
? getControlItemsMap({
|
||||
expanded,
|
||||
datasetId,
|
||||
disabled: false,
|
||||
forceUpdate,
|
||||
@@ -760,6 +765,7 @@ const FiltersConfigForm = (
|
||||
|
||||
const timeColumn = (
|
||||
<StyledRowFormItem
|
||||
expanded={expanded}
|
||||
name={['filters', filterId, 'granularity_sqla']}
|
||||
label={
|
||||
<>
|
||||
@@ -807,6 +813,7 @@ const FiltersConfigForm = (
|
||||
>
|
||||
<StyledContainer>
|
||||
<StyledFormItem
|
||||
expanded={expanded}
|
||||
name={['filters', filterId, 'type']}
|
||||
hidden
|
||||
initialValue={NativeFilterType.NativeFilter}
|
||||
@@ -814,6 +821,7 @@ const FiltersConfigForm = (
|
||||
<Input />
|
||||
</StyledFormItem>
|
||||
<StyledFormItem
|
||||
expanded={expanded}
|
||||
name={['filters', filterId, 'name']}
|
||||
label={<StyledLabel>{t('Filter name')}</StyledLabel>}
|
||||
initialValue={filterToEdit?.name}
|
||||
@@ -822,6 +830,7 @@ const FiltersConfigForm = (
|
||||
<Input {...getFiltersConfigModalTestId('name-input')} />
|
||||
</StyledFormItem>
|
||||
<StyledFormItem
|
||||
expanded={expanded}
|
||||
name={['filters', filterId, 'filterType']}
|
||||
rules={[{ required: !isRemoved, message: t('Name is required') }]}
|
||||
initialValue={filterToEdit?.filterType || 'filter_select'}
|
||||
@@ -867,7 +876,7 @@ const FiltersConfigForm = (
|
||||
</StyledFormItem>
|
||||
</StyledContainer>
|
||||
{formFilter?.filterType === 'filter_time' && (
|
||||
<FilterTypeInfo>
|
||||
<FilterTypeInfo expanded={expanded}>
|
||||
{t(`Dashboard time range filters apply to temporal columns defined in
|
||||
the filter section of each chart. Add temporal columns to the chart
|
||||
filters to have this dashboard filter impact those charts.`)}
|
||||
@@ -877,6 +886,7 @@ const FiltersConfigForm = (
|
||||
<StyledRowContainer>
|
||||
{showDataset ? (
|
||||
<StyledFormItem
|
||||
expanded={expanded}
|
||||
name={['filters', filterId, 'dataset']}
|
||||
label={<StyledLabel>{t('Dataset')}</StyledLabel>}
|
||||
initialValue={
|
||||
@@ -915,7 +925,10 @@ const FiltersConfigForm = (
|
||||
/>
|
||||
</StyledFormItem>
|
||||
) : (
|
||||
<StyledFormItem label={<StyledLabel>{t('Dataset')}</StyledLabel>}>
|
||||
<StyledFormItem
|
||||
expanded={expanded}
|
||||
label={<StyledLabel>{t('Dataset')}</StyledLabel>}
|
||||
>
|
||||
<Loading position="inline-centered" />
|
||||
</StyledFormItem>
|
||||
)}
|
||||
@@ -941,6 +954,7 @@ const FiltersConfigForm = (
|
||||
>
|
||||
{canDependOnOtherFilters && hasAvailableFilters && (
|
||||
<StyledRowFormItem
|
||||
expanded={expanded}
|
||||
name={['filters', filterId, 'dependencies']}
|
||||
initialValue={dependencies}
|
||||
>
|
||||
@@ -981,6 +995,7 @@ const FiltersConfigForm = (
|
||||
}}
|
||||
>
|
||||
<StyledRowSubFormItem
|
||||
expanded={expanded}
|
||||
name={['filters', filterId, 'adhoc_filters']}
|
||||
css={{ width: INPUT_WIDTH }}
|
||||
initialValue={filterToEdit?.adhoc_filters}
|
||||
@@ -1016,6 +1031,7 @@ const FiltersConfigForm = (
|
||||
</StyledRowSubFormItem>
|
||||
{showTimeRangePicker && (
|
||||
<StyledRowFormItem
|
||||
expanded={expanded}
|
||||
name={['filters', filterId, 'time_range']}
|
||||
label={<StyledLabel>{t('Time range')}</StyledLabel>}
|
||||
initialValue={
|
||||
@@ -1057,6 +1073,7 @@ const FiltersConfigForm = (
|
||||
}}
|
||||
>
|
||||
<StyledRowFormItem
|
||||
expanded={expanded}
|
||||
name={[
|
||||
'filters',
|
||||
filterId,
|
||||
@@ -1077,6 +1094,7 @@ const FiltersConfigForm = (
|
||||
</StyledRowFormItem>
|
||||
{hasMetrics && (
|
||||
<StyledRowSubFormItem
|
||||
expanded={expanded}
|
||||
name={['filters', filterId, 'sortMetric']}
|
||||
initialValue={filterToEdit?.sortMetric}
|
||||
label={
|
||||
@@ -1126,6 +1144,7 @@ const FiltersConfigForm = (
|
||||
}}
|
||||
>
|
||||
<StyledRowFormItem
|
||||
expanded={expanded}
|
||||
name={[
|
||||
'filters',
|
||||
filterId,
|
||||
@@ -1164,6 +1183,7 @@ const FiltersConfigForm = (
|
||||
key={`${filterId}-${FilterPanels.settings.key}`}
|
||||
>
|
||||
<StyledFormItem
|
||||
expanded={expanded}
|
||||
name={['filters', filterId, 'description']}
|
||||
initialValue={filterToEdit?.description}
|
||||
label={<StyledLabel>{t('Description')}</StyledLabel>}
|
||||
@@ -1194,6 +1214,7 @@ const FiltersConfigForm = (
|
||||
>
|
||||
{!isRemoved && (
|
||||
<StyledRowSubFormItem
|
||||
expanded={expanded}
|
||||
name={['filters', filterId, 'defaultDataMask']}
|
||||
initialValue={initialDefaultValue}
|
||||
data-test="default-input"
|
||||
|
||||
@@ -64,6 +64,7 @@ const filterMock: Filter = {
|
||||
};
|
||||
|
||||
const createProps: () => ControlItemsProps = () => ({
|
||||
expanded: false,
|
||||
datasetId: 1,
|
||||
disabled: false,
|
||||
forceUpdate: jest.fn(),
|
||||
|
||||
@@ -44,6 +44,7 @@ import {
|
||||
import { ColumnSelect } from './ColumnSelect';
|
||||
|
||||
export interface ControlItemsProps {
|
||||
expanded: boolean;
|
||||
datasetId: number;
|
||||
disabled: boolean;
|
||||
forceUpdate: Function;
|
||||
@@ -60,6 +61,7 @@ const CleanFormItem = styled(FormItem)`
|
||||
`;
|
||||
|
||||
export default function getControlItemsMap({
|
||||
expanded,
|
||||
datasetId,
|
||||
disabled,
|
||||
forceUpdate,
|
||||
@@ -104,6 +106,7 @@ export default function getControlItemsMap({
|
||||
}
|
||||
/>
|
||||
<StyledFormItem
|
||||
expanded={expanded}
|
||||
// don't show the column select unless we have a dataset
|
||||
name={['filters', filterId, 'column']}
|
||||
initialValue={initColumn}
|
||||
@@ -174,6 +177,7 @@ export default function getControlItemsMap({
|
||||
}
|
||||
>
|
||||
<StyledRowFormItem
|
||||
expanded={expanded}
|
||||
key={controlItem.name}
|
||||
name={['filters', filterId, 'controlValues', controlItem.name]}
|
||||
initialValue={initialValue}
|
||||
|
||||
@@ -581,6 +581,7 @@ function FiltersConfigModal({
|
||||
/>
|
||||
) : (
|
||||
<FiltersConfigForm
|
||||
expanded={expanded}
|
||||
ref={configFormRef}
|
||||
form={form}
|
||||
filterId={id}
|
||||
@@ -613,6 +614,7 @@ function FiltersConfigModal({
|
||||
validateDependencies,
|
||||
getDependencySuggestion,
|
||||
handleActiveFilterPanelChange,
|
||||
expanded,
|
||||
],
|
||||
);
|
||||
|
||||
|
||||
@@ -41,8 +41,10 @@ import Button from 'src/components/Button';
|
||||
import { Select } from 'src/components';
|
||||
|
||||
import { Form, FormItem } from 'src/components/Form';
|
||||
import sqlKeywords from 'src/SqlLab/utils/sqlKeywords';
|
||||
import { SQLEditor } from 'src/components/AsyncAceEditor';
|
||||
import { EmptyStateSmall } from 'src/components/EmptyState';
|
||||
import { getColumnKeywords } from 'src/explore/controlUtils/getColumnKeywords';
|
||||
import { StyledColumnOption } from 'src/explore/components/optionRenderers';
|
||||
import {
|
||||
POPOVER_INITIAL_HEIGHT,
|
||||
@@ -287,6 +289,10 @@ const ColumnSelectPopover = ({
|
||||
|
||||
const savedExpressionsLabel = t('Saved expressions');
|
||||
const simpleColumnsLabel = t('Column');
|
||||
const keywords = useMemo(
|
||||
() => sqlKeywords.concat(getColumnKeywords(columns)),
|
||||
[columns],
|
||||
);
|
||||
|
||||
return (
|
||||
<Form layout="vertical" id="metrics-edit-popover">
|
||||
@@ -451,6 +457,7 @@ const ColumnSelectPopover = ({
|
||||
className="filter-sql-editor"
|
||||
wrapEnabled
|
||||
ref={sqlEditorRef}
|
||||
keywords={keywords}
|
||||
/>
|
||||
</Tabs.TabPane>
|
||||
</Tabs>
|
||||
|
||||
@@ -48,6 +48,7 @@ import { DndItemType } from '../../DndItemType';
|
||||
import DatasourcePanelDragOption from '../../DatasourcePanel/DatasourcePanelDragOption';
|
||||
|
||||
jest.mock('src/components/AsyncAceEditor', () => ({
|
||||
...jest.requireActual('src/components/AsyncAceEditor'),
|
||||
SQLEditor: (props: AsyncAceEditorProps) => (
|
||||
<div data-test="react-ace">{props.value}</div>
|
||||
),
|
||||
|
||||
@@ -23,6 +23,7 @@ import { styled, t } from '@superset-ui/core';
|
||||
import { SQLEditor } from 'src/components/AsyncAceEditor';
|
||||
import sqlKeywords from 'src/SqlLab/utils/sqlKeywords';
|
||||
|
||||
import { getColumnKeywords } from 'src/explore/controlUtils/getColumnKeywords';
|
||||
import adhocMetricType from 'src/explore/components/controls/MetricControl/adhocMetricType';
|
||||
import columnType from 'src/explore/components/controls/FilterControl/columnType';
|
||||
import AdhocFilter from 'src/explore/components/controls/FilterControl/AdhocFilter';
|
||||
@@ -91,19 +92,7 @@ export default class AdhocFilterEditPopoverSqlTabContent extends Component {
|
||||
const { adhocFilter, height, options } = this.props;
|
||||
|
||||
const keywords = sqlKeywords.concat(
|
||||
options
|
||||
.map(option => {
|
||||
if (option.column_name) {
|
||||
return {
|
||||
name: option.column_name,
|
||||
value: option.column_name,
|
||||
score: 50,
|
||||
meta: 'option',
|
||||
};
|
||||
}
|
||||
return null;
|
||||
})
|
||||
.filter(Boolean),
|
||||
getColumnKeywords(options.filter(option => option.column_name)),
|
||||
);
|
||||
const selectOptions = Object.values(Clauses).map(clause => ({
|
||||
label: clause,
|
||||
|
||||
@@ -49,6 +49,7 @@ import {
|
||||
StyledMetricOption,
|
||||
StyledColumnOption,
|
||||
} from 'src/explore/components/optionRenderers';
|
||||
import { getColumnKeywords } from 'src/explore/controlUtils/getColumnKeywords';
|
||||
|
||||
const propTypes = {
|
||||
onChange: PropTypes.func.isRequired,
|
||||
@@ -304,14 +305,7 @@ export default class AdhocMetricEditPopover extends PureComponent {
|
||||
...popoverProps
|
||||
} = this.props;
|
||||
const { adhocMetric, savedMetric } = this.state;
|
||||
const keywords = sqlKeywords.concat(
|
||||
columns.map(column => ({
|
||||
name: column.column_name,
|
||||
value: column.column_name,
|
||||
score: 50,
|
||||
meta: 'column',
|
||||
})),
|
||||
);
|
||||
const keywords = sqlKeywords.concat(getColumnKeywords(columns));
|
||||
|
||||
const columnValue =
|
||||
(adhocMetric.column && adhocMetric.column.column_name) ||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/*
|
||||
/**
|
||||
* 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
|
||||
@@ -17,13 +17,22 @@
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { WordCloudChartPlugin, LegacyWordCloudChartPlugin } from '../src';
|
||||
import { getColumnKeywords } from './getColumnKeywords';
|
||||
|
||||
describe('plugin-chart-word-cloud', () => {
|
||||
it('exports WordCloudChartPlugin', () => {
|
||||
expect(WordCloudChartPlugin).toBeDefined();
|
||||
});
|
||||
it('exports LegacyWordCloudChartPlugin', () => {
|
||||
expect(LegacyWordCloudChartPlugin).toBeDefined();
|
||||
test('returns HTML for a column tooltip', () => {
|
||||
const expected = {
|
||||
column_name: 'test column1',
|
||||
verbose_name: null,
|
||||
is_certified: false,
|
||||
certified_by: null,
|
||||
description: 'test description',
|
||||
type: 'VARCHAR',
|
||||
};
|
||||
expect(getColumnKeywords([expected])).toContainEqual({
|
||||
name: expected.column_name,
|
||||
value: expected.column_name,
|
||||
docHTML: expect.stringContaining(expected.description),
|
||||
score: 50,
|
||||
meta: 'column',
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* 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 { ColumnMeta } from '@superset-ui/chart-controls';
|
||||
import { t } from '@superset-ui/core';
|
||||
import { getTooltipHTML } from 'src/components/AsyncAceEditor';
|
||||
import { COLUMN_AUTOCOMPLETE_SCORE } from 'src/SqlLab/constants';
|
||||
|
||||
export function getColumnKeywords(columns: ColumnMeta[]) {
|
||||
return columns.map(
|
||||
({
|
||||
column_name,
|
||||
verbose_name,
|
||||
is_certified,
|
||||
certified_by,
|
||||
description,
|
||||
type,
|
||||
}) => ({
|
||||
name: verbose_name || column_name,
|
||||
value: column_name,
|
||||
docHTML: getTooltipHTML({
|
||||
title: column_name,
|
||||
meta: type ? `column: ${type}` : 'column',
|
||||
body: `${description ?? ''}`,
|
||||
footer: is_certified ? (
|
||||
<>{t('Certified by %s', certified_by)}</>
|
||||
) : undefined,
|
||||
}),
|
||||
score: COLUMN_AUTOCOMPLETE_SCORE,
|
||||
meta: 'column',
|
||||
}),
|
||||
);
|
||||
}
|
||||
@@ -98,6 +98,7 @@ export interface AlertReportModalProps {
|
||||
const DEFAULT_WORKING_TIMEOUT = 3600;
|
||||
const DEFAULT_CRON_VALUE = '0 0 * * *'; // every day
|
||||
const DEFAULT_RETENTION = 90;
|
||||
const EMAIL_REGEX = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
|
||||
|
||||
const DEFAULT_NOTIFICATION_METHODS: NotificationMethodOption[] = [
|
||||
NotificationMethodOption.Email,
|
||||
@@ -372,6 +373,7 @@ export const TRANSLATIONS = {
|
||||
WORKING_TIMEOUT_ERROR_TEXT: t('working timeout'),
|
||||
RECIPIENTS_ERROR_TEXT: t('recipients'),
|
||||
EMAIL_SUBJECT_ERROR_TEXT: t('email subject'),
|
||||
EMAIL_VALIDATION_ERROR_TEXT: t('invalid email'),
|
||||
ERROR_TOOLTIP_MESSAGE: t(
|
||||
'Not all required fields are complete. Please provide the following:',
|
||||
),
|
||||
@@ -621,6 +623,8 @@ const AlertReportModal: FunctionComponent<AlertReportModalProps> = ({
|
||||
recipients.push({
|
||||
recipient_config_json: {
|
||||
target: setting.recipients,
|
||||
ccTarget: setting.cc,
|
||||
bccTarget: setting.bcc,
|
||||
},
|
||||
type: setting.method,
|
||||
});
|
||||
@@ -1014,6 +1018,31 @@ const AlertReportModal: FunctionComponent<AlertReportModalProps> = ({
|
||||
return hasInfo;
|
||||
};
|
||||
|
||||
const checkEmailFormat = () => {
|
||||
if (!notificationSettings.length) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const validateEmails = (emails: string): boolean => {
|
||||
if (!emails) return true; // No emails to validate
|
||||
return emails
|
||||
.split(/[,;]/)
|
||||
.every(email => EMAIL_REGEX.test(email.trim()));
|
||||
};
|
||||
|
||||
// Use array method to check conditions
|
||||
return notificationSettings.every(setting => {
|
||||
if (!!setting.method && setting.method === 'Email') {
|
||||
return (
|
||||
(!setting.recipients?.length || validateEmails(setting.recipients)) &&
|
||||
(!setting.cc || validateEmails(setting.cc)) &&
|
||||
(!setting.bcc || validateEmails(setting.bcc))
|
||||
);
|
||||
}
|
||||
return true; // Non-Email methods are considered valid
|
||||
});
|
||||
};
|
||||
|
||||
const validateGeneralSection = () => {
|
||||
const errors = [];
|
||||
if (!currentAlert?.name?.length) {
|
||||
@@ -1069,13 +1098,24 @@ const AlertReportModal: FunctionComponent<AlertReportModalProps> = ({
|
||||
};
|
||||
|
||||
const validateNotificationSection = () => {
|
||||
const errors = [];
|
||||
const hasErrors = !checkNotificationSettings();
|
||||
const errors = hasErrors ? [TRANSLATIONS.RECIPIENTS_ERROR_TEXT] : [];
|
||||
|
||||
if (hasErrors) {
|
||||
errors.push(TRANSLATIONS.RECIPIENTS_ERROR_TEXT);
|
||||
} else {
|
||||
// Check for email format errors
|
||||
const hasValidationErrors = !checkEmailFormat();
|
||||
if (hasValidationErrors) {
|
||||
errors.push(TRANSLATIONS.EMAIL_VALIDATION_ERROR_TEXT);
|
||||
}
|
||||
}
|
||||
|
||||
if (emailError) {
|
||||
errors.push(TRANSLATIONS.EMAIL_SUBJECT_ERROR_TEXT);
|
||||
}
|
||||
|
||||
// Update validation status with combined errors
|
||||
updateValidationStatus(Sections.Notification, errors);
|
||||
};
|
||||
|
||||
@@ -1132,6 +1172,8 @@ const AlertReportModal: FunctionComponent<AlertReportModalProps> = ({
|
||||
setNotificationSettings([
|
||||
{
|
||||
recipients: '',
|
||||
cc: '',
|
||||
bcc: '',
|
||||
options: allowedNotificationMethods,
|
||||
method: NotificationMethodOption.Email,
|
||||
},
|
||||
@@ -1153,6 +1195,8 @@ const AlertReportModal: FunctionComponent<AlertReportModalProps> = ({
|
||||
// @ts-ignore: Type not assignable
|
||||
recipients: config.target || setting.recipient_config_json,
|
||||
options: allowedNotificationMethods,
|
||||
cc: config.ccTarget || '',
|
||||
bcc: config.bccTarget || '',
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
@@ -16,9 +16,21 @@
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { fireEvent, render, screen } from 'spec/helpers/testing-library';
|
||||
import {
|
||||
cleanup,
|
||||
fireEvent,
|
||||
render,
|
||||
screen,
|
||||
waitFor,
|
||||
} from 'spec/helpers/testing-library';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
|
||||
import {
|
||||
FeatureFlag,
|
||||
JsonResponse,
|
||||
SupersetClient,
|
||||
TextResponse,
|
||||
} from '@superset-ui/core';
|
||||
import { NotificationMethod, mapSlackValues } from './NotificationMethod';
|
||||
import { NotificationMethodOption, NotificationSetting } from '../types';
|
||||
|
||||
@@ -43,6 +55,7 @@ const mockDefaultSubject = 'Default Subject';
|
||||
describe('NotificationMethod', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
cleanup();
|
||||
});
|
||||
|
||||
it('should render the component', () => {
|
||||
@@ -80,8 +93,8 @@ describe('NotificationMethod', () => {
|
||||
/>,
|
||||
);
|
||||
|
||||
const deleteButton = screen.getByRole('button');
|
||||
userEvent.click(deleteButton);
|
||||
const deleteButton = document.querySelector('.delete-button');
|
||||
if (deleteButton) userEvent.click(deleteButton);
|
||||
|
||||
expect(mockOnRemove).toHaveBeenCalledWith(1);
|
||||
});
|
||||
@@ -180,4 +193,291 @@ describe('NotificationMethod', () => {
|
||||
{ label: 'User Two', value: 'user2' },
|
||||
]);
|
||||
});
|
||||
it('should render CC and BCC fields when method is Email and visibility flags are true', () => {
|
||||
const defaultProps = {
|
||||
setting: {
|
||||
method: NotificationMethodOption.Email,
|
||||
recipients: 'recipient1@example.com, recipient2@example.com',
|
||||
cc: 'cc1@example.com',
|
||||
bcc: 'bcc1@example.com',
|
||||
options: [
|
||||
NotificationMethodOption.Email,
|
||||
NotificationMethodOption.Slack,
|
||||
],
|
||||
},
|
||||
index: 0,
|
||||
onUpdate: jest.fn(),
|
||||
onRemove: jest.fn(),
|
||||
onInputChange: jest.fn(),
|
||||
email_subject: 'Test Subject',
|
||||
defaultSubject: 'Default Subject',
|
||||
setErrorSubject: jest.fn(),
|
||||
};
|
||||
|
||||
const { getByTestId } = render(<NotificationMethod {...defaultProps} />);
|
||||
|
||||
// Check if CC and BCC fields are rendered
|
||||
expect(getByTestId('cc')).toBeInTheDocument();
|
||||
expect(getByTestId('bcc')).toBeInTheDocument();
|
||||
});
|
||||
it('should render CC and BCC fields with correct values when method is Email', () => {
|
||||
const defaultProps = {
|
||||
setting: {
|
||||
method: NotificationMethodOption.Email,
|
||||
recipients: 'recipient1@example.com, recipient2@example.com',
|
||||
cc: 'cc1@example.com',
|
||||
bcc: 'bcc1@example.com',
|
||||
options: [
|
||||
NotificationMethodOption.Email,
|
||||
NotificationMethodOption.Slack,
|
||||
],
|
||||
},
|
||||
index: 0,
|
||||
onUpdate: jest.fn(),
|
||||
onRemove: jest.fn(),
|
||||
onInputChange: jest.fn(),
|
||||
email_subject: 'Test Subject',
|
||||
defaultSubject: 'Default Subject',
|
||||
setErrorSubject: jest.fn(),
|
||||
};
|
||||
|
||||
const { getByTestId } = render(<NotificationMethod {...defaultProps} />);
|
||||
|
||||
// Check if CC and BCC fields are rendered with correct values
|
||||
expect(getByTestId('cc')).toHaveValue('cc1@example.com');
|
||||
expect(getByTestId('bcc')).toHaveValue('bcc1@example.com');
|
||||
});
|
||||
it('should not render CC and BCC fields when method is not Email', () => {
|
||||
const defaultProps = {
|
||||
setting: {
|
||||
method: NotificationMethodOption.Slack,
|
||||
recipients: 'recipient1@example.com, recipient2@example.com',
|
||||
cc: 'cc1@example.com',
|
||||
bcc: 'bcc1@example.com',
|
||||
options: [
|
||||
NotificationMethodOption.Email,
|
||||
NotificationMethodOption.Slack,
|
||||
],
|
||||
},
|
||||
index: 0,
|
||||
onUpdate: jest.fn(),
|
||||
onRemove: jest.fn(),
|
||||
onInputChange: jest.fn(),
|
||||
email_subject: 'Test Subject',
|
||||
defaultSubject: 'Default Subject',
|
||||
setErrorSubject: jest.fn(),
|
||||
};
|
||||
|
||||
const { queryByTestId } = render(<NotificationMethod {...defaultProps} />);
|
||||
|
||||
// Check if CC and BCC fields are not rendered
|
||||
expect(queryByTestId('cc')).not.toBeInTheDocument();
|
||||
expect(queryByTestId('bcc')).not.toBeInTheDocument();
|
||||
});
|
||||
// Handle empty recipients list gracefully
|
||||
it('should handle empty recipients list gracefully', () => {
|
||||
const defaultProps = {
|
||||
setting: {
|
||||
method: NotificationMethodOption.Email,
|
||||
recipients: '',
|
||||
cc: '',
|
||||
bcc: '',
|
||||
options: [
|
||||
NotificationMethodOption.Email,
|
||||
NotificationMethodOption.Slack,
|
||||
],
|
||||
},
|
||||
index: 0,
|
||||
onUpdate: jest.fn(),
|
||||
onRemove: jest.fn(),
|
||||
onInputChange: jest.fn(),
|
||||
email_subject: 'Test Subject',
|
||||
defaultSubject: 'Default Subject',
|
||||
setErrorSubject: jest.fn(),
|
||||
};
|
||||
|
||||
const { queryByTestId } = render(<NotificationMethod {...defaultProps} />);
|
||||
|
||||
// Check if CC and BCC fields are not rendered
|
||||
expect(queryByTestId('cc')).not.toBeInTheDocument();
|
||||
expect(queryByTestId('bcc')).not.toBeInTheDocument();
|
||||
});
|
||||
it('shows the right combo when ff is false', async () => {
|
||||
/* should show the div with "Recipients are separated by"
|
||||
when FeatureFlag.AlertReportSlackV2 is false and fetchSlackChannels errors
|
||||
*/
|
||||
// Mock the feature flag to be false
|
||||
window.featureFlags = { [FeatureFlag.AlertReportSlackV2]: false };
|
||||
|
||||
// Mock the SupersetClient.get to simulate an error
|
||||
jest.spyOn(SupersetClient, 'get').mockImplementation(() => {
|
||||
throw new Error('Error fetching Slack channels');
|
||||
});
|
||||
|
||||
render(
|
||||
<NotificationMethod
|
||||
setting={{
|
||||
...mockSetting,
|
||||
method: NotificationMethodOption.Slack,
|
||||
}}
|
||||
index={0}
|
||||
onUpdate={mockOnUpdate}
|
||||
onRemove={mockOnRemove}
|
||||
onInputChange={mockOnInputChange}
|
||||
email_subject={mockEmailSubject}
|
||||
defaultSubject={mockDefaultSubject}
|
||||
setErrorSubject={mockSetErrorSubject}
|
||||
/>,
|
||||
);
|
||||
|
||||
// Wait for the component to handle the error and render the expected div
|
||||
await waitFor(() => {
|
||||
expect(
|
||||
screen.getByText('Recipients are separated by "," or ";"'),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
it('shows the textbox when the fetch fails', async () => {
|
||||
/* should show the div with "Recipients are separated by"
|
||||
when FeatureFlag.AlertReportSlackV2 is true and fetchSlackChannels errors
|
||||
*/
|
||||
|
||||
// Mock the feature flag to be false
|
||||
window.featureFlags = { [FeatureFlag.AlertReportSlackV2]: false };
|
||||
|
||||
// Mock the SupersetClient.get to simulate an error
|
||||
jest.spyOn(SupersetClient, 'get').mockImplementation(() => {
|
||||
throw new Error('Error fetching Slack channels');
|
||||
});
|
||||
|
||||
render(
|
||||
<NotificationMethod
|
||||
setting={{
|
||||
...mockSetting,
|
||||
method: NotificationMethodOption.Slack,
|
||||
}}
|
||||
index={0}
|
||||
onUpdate={mockOnUpdate}
|
||||
onRemove={mockOnRemove}
|
||||
onInputChange={mockOnInputChange}
|
||||
email_subject={mockEmailSubject}
|
||||
defaultSubject={mockDefaultSubject}
|
||||
setErrorSubject={mockSetErrorSubject}
|
||||
/>,
|
||||
);
|
||||
|
||||
// Wait for the component to handle the error and render the expected div
|
||||
await waitFor(() => {
|
||||
expect(
|
||||
screen.getByText('Recipients are separated by "," or ";"'),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
it('shows the dropdown when ff is true and slackChannels succeed', async () => {
|
||||
/* should show the Select channels dropdown
|
||||
when FeatureFlag.AlertReportSlackV2 is true and fetchSlackChannels succeeds
|
||||
*/
|
||||
// Mock the feature flag to be false
|
||||
window.featureFlags = { [FeatureFlag.AlertReportSlackV2]: true };
|
||||
|
||||
// Mock the SupersetClient.get to simulate an error
|
||||
jest
|
||||
.spyOn(SupersetClient, 'get')
|
||||
.mockImplementation(
|
||||
() =>
|
||||
Promise.resolve({ json: { result: [] } }) as unknown as Promise<
|
||||
Response | JsonResponse | TextResponse
|
||||
>,
|
||||
);
|
||||
|
||||
render(
|
||||
<NotificationMethod
|
||||
setting={{
|
||||
...mockSetting,
|
||||
method: NotificationMethodOption.SlackV2,
|
||||
recipients: 'slack-channel',
|
||||
}}
|
||||
index={0}
|
||||
onUpdate={mockOnUpdate}
|
||||
onRemove={mockOnRemove}
|
||||
onInputChange={mockOnInputChange}
|
||||
email_subject={mockEmailSubject}
|
||||
defaultSubject={mockDefaultSubject}
|
||||
setErrorSubject={mockSetErrorSubject}
|
||||
/>,
|
||||
);
|
||||
|
||||
// Wait for the component to handle the error and render the expected div
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTitle('Slack')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
it('shows the textarea when ff is true and slackChannels fail', async () => {
|
||||
/* should show the Select channels dropdown
|
||||
when FeatureFlag.AlertReportSlackV2 is true and fetchSlackChannels succeeds
|
||||
*/
|
||||
// Mock the feature flag to be false
|
||||
window.featureFlags = { [FeatureFlag.AlertReportSlackV2]: true };
|
||||
|
||||
// Mock the SupersetClient.get to simulate an error
|
||||
jest.spyOn(SupersetClient, 'get').mockImplementation(() => {
|
||||
throw new Error('Error fetching Slack channels');
|
||||
});
|
||||
|
||||
render(
|
||||
<NotificationMethod
|
||||
setting={{
|
||||
...mockSetting,
|
||||
method: NotificationMethodOption.Slack,
|
||||
recipients: 'slack-channel',
|
||||
}}
|
||||
index={0}
|
||||
onUpdate={mockOnUpdate}
|
||||
onRemove={mockOnRemove}
|
||||
onInputChange={mockOnInputChange}
|
||||
email_subject={mockEmailSubject}
|
||||
defaultSubject={mockDefaultSubject}
|
||||
setErrorSubject={mockSetErrorSubject}
|
||||
/>,
|
||||
);
|
||||
|
||||
// Wait for the component to handle the error and render the expected div
|
||||
expect(
|
||||
screen.getByText('Recipients are separated by "," or ";"'),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
it('shows the textarea when ff is true and slackChannels fail and slack is selected', async () => {
|
||||
/* should show the Select channels dropdown
|
||||
when FeatureFlag.AlertReportSlackV2 is true and fetchSlackChannels succeeds
|
||||
*/
|
||||
// Mock the feature flag to be false
|
||||
window.featureFlags = { [FeatureFlag.AlertReportSlackV2]: true };
|
||||
|
||||
// Mock the SupersetClient.get to simulate an error
|
||||
jest.spyOn(SupersetClient, 'get').mockImplementation(() => {
|
||||
throw new Error('Error fetching Slack channels');
|
||||
});
|
||||
|
||||
render(
|
||||
<NotificationMethod
|
||||
setting={{
|
||||
...mockSetting,
|
||||
method: NotificationMethodOption.Slack,
|
||||
recipients: 'slack-channel',
|
||||
}}
|
||||
index={0}
|
||||
onUpdate={mockOnUpdate}
|
||||
onRemove={mockOnRemove}
|
||||
onInputChange={mockOnInputChange}
|
||||
email_subject={mockEmailSubject}
|
||||
defaultSubject={mockDefaultSubject}
|
||||
setErrorSubject={mockSetErrorSubject}
|
||||
/>,
|
||||
);
|
||||
|
||||
// Wait for the component to handle the error and render the expected div
|
||||
expect(
|
||||
screen.getByText('Recipients are separated by "," or ";"'),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -44,34 +44,75 @@ import {
|
||||
import { StyledInputContainer } from '../AlertReportModal';
|
||||
|
||||
const StyledNotificationMethod = styled.div`
|
||||
margin-bottom: 10px;
|
||||
${({ theme }) => `
|
||||
margin-bottom: ${theme.gridUnit * 3}px;
|
||||
|
||||
.input-container {
|
||||
textarea {
|
||||
height: auto;
|
||||
}
|
||||
.input-container {
|
||||
textarea {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
&.error {
|
||||
input {
|
||||
border-color: ${({ theme }) => theme.colors.error.base};
|
||||
&.error {
|
||||
input {
|
||||
border-color: ${theme.colors.error.base};
|
||||
}
|
||||
}
|
||||
|
||||
.helper {
|
||||
margin-top: ${theme.gridUnit * 2}px;
|
||||
font-size: ${theme.typography.sizes.s}px;
|
||||
color: ${theme.colors.grayscale.base};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.inline-container {
|
||||
margin-bottom: 10px;
|
||||
.inline-container {
|
||||
margin-bottom: ${theme.gridUnit * 2}px;
|
||||
|
||||
> div {
|
||||
margin: 0;
|
||||
> div {
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
.delete-button {
|
||||
margin-left: ${theme.gridUnit * 2}px;
|
||||
padding-top: ${theme.gridUnit}px;
|
||||
}
|
||||
}
|
||||
|
||||
.delete-button {
|
||||
margin-left: 10px;
|
||||
padding-top: 3px;
|
||||
.ghost-button {
|
||||
color: ${theme.colors.primary.dark1};
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
font-size: ${theme.typography.sizes.s}px;
|
||||
cursor: pointer;
|
||||
margin-top: ${theme.gridUnit}px;
|
||||
|
||||
.icon {
|
||||
width: ${theme.gridUnit * 3}px;
|
||||
height: ${theme.gridUnit * 3}px;
|
||||
font-size: ${theme.typography.sizes.s}px;
|
||||
margin-right: ${theme.gridUnit}px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ghost-button + .ghost-button {
|
||||
margin-left: ${theme.gridUnit * 4}px;
|
||||
}
|
||||
|
||||
.ghost-button:first-child[style*='none'] + .ghost-button {
|
||||
margin-left: 0px; /* Remove margin when the first button is hidden */
|
||||
}
|
||||
`}
|
||||
`;
|
||||
|
||||
const TRANSLATIONS = {
|
||||
EMAIL_CC_NAME: t('CC recipients'),
|
||||
EMAIL_BCC_NAME: t('BCC recipients'),
|
||||
EMAIL_SUBJECT_NAME: t('Email subject name (optional)'),
|
||||
EMAIL_SUBJECT_ERROR_TEXT: t(
|
||||
'Please enter valid text. Spaces alone are not permitted.',
|
||||
),
|
||||
};
|
||||
|
||||
interface NotificationMethodProps {
|
||||
setting?: NotificationSetting | null;
|
||||
index: number;
|
||||
@@ -85,13 +126,6 @@ interface NotificationMethodProps {
|
||||
setErrorSubject: (hasError: boolean) => void;
|
||||
}
|
||||
|
||||
const TRANSLATIONS = {
|
||||
EMAIL_SUBJECT_NAME: t('Email subject name (optional)'),
|
||||
EMAIL_SUBJECT_ERROR_TEXT: t(
|
||||
'Please enter valid text. Spaces alone are not permitted.',
|
||||
),
|
||||
};
|
||||
|
||||
export const mapSlackValues = ({
|
||||
method,
|
||||
recipientValue,
|
||||
@@ -164,7 +198,7 @@ export const NotificationMethod: FunctionComponent<NotificationMethodProps> = ({
|
||||
defaultSubject,
|
||||
setErrorSubject,
|
||||
}) => {
|
||||
const { method, recipients, options } = setting || {};
|
||||
const { method, recipients, cc, bcc, options } = setting || {};
|
||||
const [recipientValue, setRecipientValue] = useState<string>(
|
||||
recipients || '',
|
||||
);
|
||||
@@ -172,7 +206,13 @@ export const NotificationMethod: FunctionComponent<NotificationMethodProps> = ({
|
||||
{ label: string; value: string }[]
|
||||
>([]);
|
||||
const [error, setError] = useState(false);
|
||||
const [ccVisible, setCcVisible] = useState<boolean>(!!cc);
|
||||
const [bccVisible, setBccVisible] = useState<boolean>(!!bcc);
|
||||
const [ccValue, setCcValue] = useState<string>(cc || '');
|
||||
const [bccValue, setBccValue] = useState<string>(bcc || '');
|
||||
const theme = useTheme();
|
||||
const [methodOptionsLoading, setMethodOptionsLoading] =
|
||||
useState<boolean>(true);
|
||||
const [slackOptions, setSlackOptions] = useState<SlackOptionsType>([
|
||||
{
|
||||
label: '',
|
||||
@@ -188,11 +228,16 @@ export const NotificationMethod: FunctionComponent<NotificationMethodProps> = ({
|
||||
}) => {
|
||||
// Since we're swapping the method, reset the recipients
|
||||
setRecipientValue('');
|
||||
setCcValue('');
|
||||
setBccValue('');
|
||||
|
||||
if (onUpdate && setting) {
|
||||
const updatedSetting = {
|
||||
...setting,
|
||||
method: selected.value,
|
||||
recipients: '',
|
||||
cc: '',
|
||||
bcc: '',
|
||||
};
|
||||
|
||||
onUpdate(index, updatedSetting);
|
||||
@@ -214,51 +259,47 @@ export const NotificationMethod: FunctionComponent<NotificationMethodProps> = ({
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
method &&
|
||||
[
|
||||
NotificationMethodOption.Slack,
|
||||
NotificationMethodOption.SlackV2,
|
||||
].includes(method) &&
|
||||
!slackOptions[0]?.options.length
|
||||
) {
|
||||
if (!slackOptions[0]?.options.length) {
|
||||
fetchSlackChannels({ types: ['public_channel', 'private_channel'] })
|
||||
.then(({ json }) => {
|
||||
const { result } = json;
|
||||
|
||||
const options: SlackOptionsType = mapChannelsToOptions(result);
|
||||
|
||||
setSlackOptions(options);
|
||||
|
||||
if (isFeatureEnabled(FeatureFlag.AlertReportSlackV2)) {
|
||||
// map existing ids to names for display
|
||||
// for edit mode, map existing ids to names for display if slack v2
|
||||
// or names to ids if slack v1
|
||||
const [publicOptions, privateOptions] = options;
|
||||
|
||||
setSlackRecipients(
|
||||
mapSlackValues({
|
||||
method,
|
||||
recipientValue,
|
||||
slackOptions: [
|
||||
...publicOptions.options,
|
||||
...privateOptions.options,
|
||||
],
|
||||
}),
|
||||
);
|
||||
if (method === NotificationMethodOption.Slack) {
|
||||
onMethodChange({
|
||||
label: NotificationMethodOption.Slack,
|
||||
value: NotificationMethodOption.SlackV2,
|
||||
});
|
||||
if (
|
||||
method &&
|
||||
[
|
||||
NotificationMethodOption.SlackV2,
|
||||
NotificationMethodOption.Slack,
|
||||
].includes(method)
|
||||
) {
|
||||
setSlackRecipients(
|
||||
mapSlackValues({
|
||||
method,
|
||||
recipientValue,
|
||||
slackOptions: [
|
||||
...publicOptions.options,
|
||||
...privateOptions.options,
|
||||
],
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
.catch(e => {
|
||||
// Fallback to slack v1 if slack v2 is not compatible
|
||||
setUseSlackV1(true);
|
||||
})
|
||||
.finally(() => {
|
||||
setMethodOptionsLoading(false);
|
||||
});
|
||||
}
|
||||
}, [method]);
|
||||
}, []);
|
||||
|
||||
const methodOptions = useMemo(
|
||||
() =>
|
||||
@@ -280,7 +321,7 @@ export const NotificationMethod: FunctionComponent<NotificationMethodProps> = ({
|
||||
: method,
|
||||
value: method,
|
||||
})),
|
||||
[options],
|
||||
[options, useSlackV1],
|
||||
);
|
||||
|
||||
if (!setting) {
|
||||
@@ -333,11 +374,49 @@ export const NotificationMethod: FunctionComponent<NotificationMethodProps> = ({
|
||||
}
|
||||
};
|
||||
|
||||
const onCcChange = (event: React.ChangeEvent<HTMLTextAreaElement>) => {
|
||||
const { target } = event;
|
||||
|
||||
setCcValue(target.value);
|
||||
|
||||
if (onUpdate) {
|
||||
const updatedSetting = {
|
||||
...setting,
|
||||
cc: target.value,
|
||||
};
|
||||
|
||||
onUpdate(index, updatedSetting);
|
||||
}
|
||||
};
|
||||
|
||||
const onBccChange = (event: React.ChangeEvent<HTMLTextAreaElement>) => {
|
||||
const { target } = event;
|
||||
|
||||
setBccValue(target.value);
|
||||
|
||||
if (onUpdate) {
|
||||
const updatedSetting = {
|
||||
...setting,
|
||||
bcc: target.value,
|
||||
};
|
||||
|
||||
onUpdate(index, updatedSetting);
|
||||
}
|
||||
};
|
||||
|
||||
// Set recipients
|
||||
if (!!recipients && recipientValue !== recipients) {
|
||||
setRecipientValue(recipients);
|
||||
}
|
||||
|
||||
if (!!cc && ccValue !== cc) {
|
||||
setCcValue(cc);
|
||||
}
|
||||
|
||||
if (!!bcc && bccValue !== bcc) {
|
||||
setBccValue(bcc);
|
||||
}
|
||||
|
||||
return (
|
||||
<StyledNotificationMethod>
|
||||
<div className="inline-container">
|
||||
@@ -353,8 +432,10 @@ export const NotificationMethod: FunctionComponent<NotificationMethodProps> = ({
|
||||
options={methodOptions}
|
||||
showSearch
|
||||
value={methodOptions.find(option => option.value === method)}
|
||||
loading={methodOptionsLoading}
|
||||
/>
|
||||
{index !== 0 && !!onRemove ? (
|
||||
// eslint-disable-next-line jsx-a11y/control-has-associated-label
|
||||
<span
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
@@ -418,14 +499,16 @@ export const NotificationMethod: FunctionComponent<NotificationMethodProps> = ({
|
||||
<>
|
||||
<div className="input-container">
|
||||
<textarea
|
||||
name="recipients"
|
||||
name="To"
|
||||
data-test="recipients"
|
||||
value={recipientValue}
|
||||
onChange={onRecipientsChange}
|
||||
/>
|
||||
</div>
|
||||
<div className="helper">
|
||||
{t('Recipients are separated by "," or ";"')}
|
||||
<div className="input-container">
|
||||
<div className="helper">
|
||||
{t('Recipients are separated by "," or ";"')}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
@@ -446,6 +529,75 @@ export const NotificationMethod: FunctionComponent<NotificationMethodProps> = ({
|
||||
</div>
|
||||
</StyledInputContainer>
|
||||
</div>
|
||||
{method === NotificationMethodOption.Email && (
|
||||
<StyledInputContainer>
|
||||
{/* Render "CC" input field if ccVisible is true */}
|
||||
{ccVisible && (
|
||||
<>
|
||||
<div className="control-label">
|
||||
{TRANSLATIONS.EMAIL_CC_NAME}
|
||||
</div>
|
||||
<div className="input-container">
|
||||
<textarea
|
||||
name="CC"
|
||||
data-test="cc"
|
||||
value={ccValue}
|
||||
onChange={onCcChange}
|
||||
/>
|
||||
</div>
|
||||
<div className="input-container">
|
||||
<div className="helper">
|
||||
{t('Recipients are separated by "," or ";"')}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{/* Render "BCC" input field if bccVisible is true */}
|
||||
{bccVisible && (
|
||||
<>
|
||||
<div className="control-label">
|
||||
{TRANSLATIONS.EMAIL_BCC_NAME}
|
||||
</div>
|
||||
<div className="input-container">
|
||||
<textarea
|
||||
name="BCC"
|
||||
data-test="bcc"
|
||||
value={bccValue}
|
||||
onChange={onBccChange}
|
||||
/>
|
||||
</div>
|
||||
<div className="input-container">
|
||||
<div className="helper">
|
||||
{t('Recipients are separated by "," or ";"')}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{/* New buttons container */}
|
||||
<div className="ghost-button">
|
||||
<span
|
||||
className="ghost-button"
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
onClick={() => setCcVisible(true)}
|
||||
style={{ display: ccVisible ? 'none' : 'inline-flex' }}
|
||||
>
|
||||
<Icons.Email className="icon" />
|
||||
{t('Add CC Recipients')}
|
||||
</span>
|
||||
<span
|
||||
className="ghost-button"
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
onClick={() => setBccVisible(true)}
|
||||
style={{ display: bccVisible ? 'none' : 'inline-flex' }}
|
||||
>
|
||||
<Icons.Email className="icon" />
|
||||
{t('Add BCC Recipients')}
|
||||
</span>
|
||||
</div>
|
||||
</StyledInputContainer>
|
||||
)}
|
||||
</>
|
||||
) : null}
|
||||
</StyledNotificationMethod>
|
||||
|
||||
@@ -50,6 +50,8 @@ export enum NotificationMethodOption {
|
||||
export type NotificationSetting = {
|
||||
method?: NotificationMethodOption;
|
||||
recipients: string;
|
||||
cc?: string;
|
||||
bcc?: string;
|
||||
options: NotificationMethodOption[];
|
||||
};
|
||||
|
||||
@@ -63,6 +65,8 @@ export type SlackChannel = {
|
||||
export type Recipient = {
|
||||
recipient_config_json: {
|
||||
target: string;
|
||||
ccTarget?: string;
|
||||
bccTarget?: string;
|
||||
};
|
||||
type: NotificationMethodOption;
|
||||
};
|
||||
|
||||
@@ -73,6 +73,8 @@ interface ReportProps {
|
||||
show: boolean;
|
||||
userId: number;
|
||||
userEmail: string;
|
||||
ccEmail: string;
|
||||
bccEmail: string;
|
||||
chart?: ChartState;
|
||||
chartName?: string;
|
||||
dashboardId?: number;
|
||||
@@ -109,6 +111,8 @@ function ReportModal({
|
||||
chart,
|
||||
userId,
|
||||
userEmail,
|
||||
ccEmail,
|
||||
bccEmail,
|
||||
creationMethod,
|
||||
dashboardName,
|
||||
chartName,
|
||||
@@ -184,7 +188,11 @@ function ReportModal({
|
||||
owners: [userId],
|
||||
recipients: [
|
||||
{
|
||||
recipient_config_json: { target: userEmail },
|
||||
recipient_config_json: {
|
||||
target: userEmail,
|
||||
ccTarget: ccEmail,
|
||||
bccTarget: bccEmail,
|
||||
},
|
||||
type: 'Email',
|
||||
},
|
||||
],
|
||||
|
||||
@@ -46,7 +46,14 @@ export interface ReportObject {
|
||||
name: string;
|
||||
owners: number[];
|
||||
recipients: [
|
||||
{ recipient_config_json: { target: string }; type: ReportRecipientType },
|
||||
{
|
||||
recipient_config_json: {
|
||||
target: string;
|
||||
ccTarget: string;
|
||||
bccTarget: string;
|
||||
};
|
||||
type: ReportRecipientType;
|
||||
},
|
||||
];
|
||||
report_format: string;
|
||||
timezone: string;
|
||||
|
||||
@@ -69,7 +69,7 @@ export type InitialState = {
|
||||
}[];
|
||||
};
|
||||
|
||||
const queryValidationApi = api.injectEndpoints({
|
||||
const initialStateApi = api.injectEndpoints({
|
||||
endpoints: builder => ({
|
||||
sqlLabInitialState: builder.query<InitialState, void>({
|
||||
providesTags: ['SqlLabInitialState'],
|
||||
@@ -83,4 +83,4 @@ const queryValidationApi = api.injectEndpoints({
|
||||
});
|
||||
|
||||
export const { useSqlLabInitialStateQuery: useSqlLabInitialState } =
|
||||
queryValidationApi;
|
||||
initialStateApi;
|
||||
|
||||
@@ -152,7 +152,7 @@ export const {
|
||||
export function useTables(options: Params) {
|
||||
const { dbId, catalog, schema, onSuccess, onError } = options || {};
|
||||
const isMountedRef = useRef(false);
|
||||
const { data: schemaOptions, isFetching } = useSchemas({
|
||||
const { currentData: schemaOptions, isFetching } = useSchemas({
|
||||
dbId,
|
||||
catalog: catalog || undefined,
|
||||
});
|
||||
@@ -203,13 +203,13 @@ export function useTables(options: Params) {
|
||||
isSuccess,
|
||||
isError,
|
||||
isFetching,
|
||||
data,
|
||||
currentData,
|
||||
error,
|
||||
originalArgs,
|
||||
} = result;
|
||||
if (!originalArgs?.forceRefresh && requestId && !isFetching) {
|
||||
if (isSuccess && data) {
|
||||
handleOnSuccess(data, false);
|
||||
if (isSuccess && currentData) {
|
||||
handleOnSuccess(currentData, false);
|
||||
}
|
||||
if (isError) {
|
||||
handleOnError(error as Response);
|
||||
|
||||
@@ -64,6 +64,11 @@ const baseConfig: ThemeConfig = {
|
||||
borderRadiusSM: supersetTheme.gridUnit / 2,
|
||||
defaultBg: supersetTheme.colors.grayscale.light4,
|
||||
},
|
||||
Progress: {
|
||||
fontSize: supersetTheme.typography.sizes.s,
|
||||
colorText: supersetTheme.colors.text.label,
|
||||
remainingColor: supersetTheme.colors.grayscale.light4,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -32,6 +32,10 @@ class Datasource(Schema):
|
||||
datasource_name = fields.String(
|
||||
metadata={"description": datasource_name_description},
|
||||
)
|
||||
catalog = fields.String(
|
||||
allow_none=True,
|
||||
metadata={"description": "Datasource catalog"},
|
||||
)
|
||||
schema = fields.String(
|
||||
metadata={"description": "Datasource schema"},
|
||||
)
|
||||
|
||||
@@ -269,10 +269,12 @@ class ChartRestApi(BaseSupersetModelRestApi):
|
||||
base_related_field_filters = {
|
||||
"owners": [["id", BaseFilterRelatedUsers, lambda: []]],
|
||||
"created_by": [["id", BaseFilterRelatedUsers, lambda: []]],
|
||||
"changed_by": [["id", BaseFilterRelatedUsers, lambda: []]],
|
||||
}
|
||||
related_field_filters = {
|
||||
"owners": RelatedFieldFilter("first_name", FilterRelatedOwners),
|
||||
"created_by": RelatedFieldFilter("first_name", FilterRelatedOwners),
|
||||
"changed_by": RelatedFieldFilter("first_name", FilterRelatedOwners),
|
||||
}
|
||||
|
||||
allowed_rel_fields = {"owners", "created_by", "changed_by"}
|
||||
|
||||
53
superset/commands/dashboard/copy.py
Normal file
@@ -0,0 +1,53 @@
|
||||
# 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 logging
|
||||
from functools import partial
|
||||
from typing import Any
|
||||
|
||||
from superset import is_feature_enabled, security_manager
|
||||
from superset.commands.base import BaseCommand
|
||||
from superset.commands.dashboard.exceptions import (
|
||||
DashboardCopyError,
|
||||
DashboardForbiddenError,
|
||||
DashboardInvalidError,
|
||||
)
|
||||
from superset.daos.dashboard import DashboardDAO
|
||||
from superset.models.dashboard import Dashboard
|
||||
from superset.utils.decorators import on_error, transaction
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class CopyDashboardCommand(BaseCommand):
|
||||
def __init__(self, original_dash: Dashboard, data: dict[str, Any]) -> None:
|
||||
self._original_dash = original_dash
|
||||
self._properties = data.copy()
|
||||
|
||||
@transaction(on_error=partial(on_error, reraise=DashboardCopyError))
|
||||
def run(self) -> Dashboard:
|
||||
self.validate()
|
||||
return DashboardDAO.copy_dashboard(self._original_dash, self._properties)
|
||||
|
||||
def validate(self) -> None:
|
||||
if not self._properties.get("dashboard_title") or not self._properties.get(
|
||||
"json_metadata"
|
||||
):
|
||||
raise DashboardInvalidError()
|
||||
if is_feature_enabled("DASHBOARD_RBAC") and not security_manager.is_owner(
|
||||
self._original_dash
|
||||
):
|
||||
raise DashboardForbiddenError()
|
||||
@@ -23,12 +23,13 @@ from flask_babel import lazy_gettext as _
|
||||
from superset import security_manager
|
||||
from superset.commands.base import BaseCommand
|
||||
from superset.commands.dashboard.exceptions import (
|
||||
DashboardDeleteEmbeddedFailedError,
|
||||
DashboardDeleteFailedError,
|
||||
DashboardDeleteFailedReportsExistError,
|
||||
DashboardForbiddenError,
|
||||
DashboardNotFoundError,
|
||||
)
|
||||
from superset.daos.dashboard import DashboardDAO
|
||||
from superset.daos.dashboard import DashboardDAO, EmbeddedDashboardDAO
|
||||
from superset.daos.report import ReportScheduleDAO
|
||||
from superset.exceptions import SupersetSecurityException
|
||||
from superset.models.dashboard import Dashboard
|
||||
@@ -37,6 +38,19 @@ from superset.utils.decorators import on_error, transaction
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class DeleteEmbeddedDashboardCommand(BaseCommand):
|
||||
def __init__(self, dashboard: Dashboard):
|
||||
self._dashboard = dashboard
|
||||
|
||||
@transaction(on_error=partial(on_error, reraise=DashboardDeleteEmbeddedFailedError))
|
||||
def run(self) -> None:
|
||||
self.validate()
|
||||
return EmbeddedDashboardDAO.delete(self._dashboard.embedded)
|
||||
|
||||
def validate(self) -> None:
|
||||
pass
|
||||
|
||||
|
||||
class DeleteDashboardCommand(BaseCommand):
|
||||
def __init__(self, model_ids: list[int]):
|
||||
self._model_ids = model_ids
|
||||
|
||||
@@ -62,6 +62,10 @@ class DashboardDeleteFailedError(DeleteFailedError):
|
||||
message = _("Dashboard could not be deleted.")
|
||||
|
||||
|
||||
class DashboardDeleteEmbeddedFailedError(DeleteFailedError):
|
||||
message = _("Embedded dashboard could not be deleted.")
|
||||
|
||||
|
||||
class DashboardDeleteFailedReportsExistError(DashboardDeleteFailedError):
|
||||
message = _("There are associated alerts or reports")
|
||||
|
||||
@@ -76,3 +80,7 @@ class DashboardImportError(ImportFailedError):
|
||||
|
||||
class DashboardAccessDeniedError(ForbiddenError):
|
||||
message = _("You don't have access to this dashboard.")
|
||||
|
||||
|
||||
class DashboardCopyError(CommandInvalidError):
|
||||
message = _("Dashboard cannot be copied due to invalid parameters.")
|
||||
|
||||
@@ -41,6 +41,7 @@ from superset.commands.database.ssh_tunnel.exceptions import (
|
||||
from superset.commands.database.test_connection import TestConnectionDatabaseCommand
|
||||
from superset.daos.database import DatabaseDAO
|
||||
from superset.databases.ssh_tunnel.models import SSHTunnel
|
||||
from superset.db_engine_specs.base import GenericDBException
|
||||
from superset.exceptions import SupersetErrorsException
|
||||
from superset.extensions import event_logger, security_manager
|
||||
from superset.models.core import Database
|
||||
@@ -118,7 +119,7 @@ class CreateDatabaseCommand(BaseCommand):
|
||||
for catalog in catalogs:
|
||||
try:
|
||||
self.add_schema_permissions(database, catalog, ssh_tunnel)
|
||||
except Exception: # pylint: disable=broad-except
|
||||
except GenericDBException: # pylint: disable=broad-except
|
||||
logger.warning("Error processing catalog '%s'", catalog)
|
||||
continue
|
||||
except (
|
||||
|
||||
@@ -62,14 +62,55 @@ def import_database(
|
||||
config["extra"] = json.dumps(config["extra"])
|
||||
|
||||
# Before it gets removed in import_from_dict
|
||||
ssh_tunnel = config.pop("ssh_tunnel", None)
|
||||
ssh_tunnel_config = config.pop("ssh_tunnel", None)
|
||||
|
||||
database = Database.import_from_dict(config, recursive=False)
|
||||
if database.id is None:
|
||||
db.session.flush()
|
||||
|
||||
if ssh_tunnel:
|
||||
ssh_tunnel["database_id"] = database.id
|
||||
SSHTunnel.import_from_dict(ssh_tunnel, recursive=False)
|
||||
if ssh_tunnel_config:
|
||||
ssh_tunnel_config["database_id"] = database.id
|
||||
ssh_tunnel = SSHTunnel.import_from_dict(ssh_tunnel_config, recursive=False)
|
||||
else:
|
||||
ssh_tunnel = None
|
||||
|
||||
# TODO (betodealmeida): we should use the `CreateDatabaseCommand` for imports
|
||||
add_permissions(database, ssh_tunnel)
|
||||
|
||||
return database
|
||||
|
||||
|
||||
def add_permissions(database: Database, ssh_tunnel: SSHTunnel) -> None:
|
||||
"""
|
||||
Add DAR for catalogs and schemas.
|
||||
"""
|
||||
if database.db_engine_spec.supports_catalog:
|
||||
catalogs = database.get_all_catalog_names(
|
||||
cache=False,
|
||||
ssh_tunnel=ssh_tunnel,
|
||||
)
|
||||
for catalog in catalogs:
|
||||
security_manager.add_permission_view_menu(
|
||||
"catalog_access",
|
||||
security_manager.get_catalog_perm(
|
||||
database.database_name,
|
||||
catalog,
|
||||
),
|
||||
)
|
||||
else:
|
||||
catalogs = [None]
|
||||
|
||||
for catalog in catalogs:
|
||||
for schema in database.get_all_schema_names(
|
||||
catalog=catalog,
|
||||
cache=False,
|
||||
ssh_tunnel=ssh_tunnel,
|
||||
):
|
||||
security_manager.add_permission_view_menu(
|
||||
"schema_access",
|
||||
security_manager.get_schema_perm(
|
||||
database.database_name,
|
||||
catalog,
|
||||
schema,
|
||||
),
|
||||
)
|
||||
|
||||
@@ -41,6 +41,7 @@ from superset.commands.database.ssh_tunnel.update import UpdateSSHTunnelCommand
|
||||
from superset.daos.database import DatabaseDAO
|
||||
from superset.daos.dataset import DatasetDAO
|
||||
from superset.databases.ssh_tunnel.models import SSHTunnel
|
||||
from superset.db_engine_specs.base import GenericDBException
|
||||
from superset.models.core import Database
|
||||
from superset.utils.decorators import on_error, transaction
|
||||
|
||||
@@ -80,6 +81,7 @@ class UpdateDatabaseCommand(BaseCommand):
|
||||
database.set_sqlalchemy_uri(database.sqlalchemy_uri)
|
||||
ssh_tunnel = self._handle_ssh_tunnel(database)
|
||||
self._refresh_catalogs(database, original_database_name, ssh_tunnel)
|
||||
|
||||
return database
|
||||
|
||||
def _handle_ssh_tunnel(self, database: Database) -> SSHTunnel | None:
|
||||
@@ -115,17 +117,13 @@ class UpdateDatabaseCommand(BaseCommand):
|
||||
) -> set[str]:
|
||||
"""
|
||||
Helper method to load catalogs.
|
||||
|
||||
This method captures a generic exception, since errors could potentially come
|
||||
from any of the 50+ database drivers we support.
|
||||
"""
|
||||
|
||||
try:
|
||||
return database.get_all_catalog_names(
|
||||
force=True,
|
||||
ssh_tunnel=ssh_tunnel,
|
||||
)
|
||||
except Exception as ex:
|
||||
except GenericDBException as ex:
|
||||
raise DatabaseConnectionFailedError() from ex
|
||||
|
||||
def _get_schema_names(
|
||||
@@ -136,18 +134,14 @@ class UpdateDatabaseCommand(BaseCommand):
|
||||
) -> set[str]:
|
||||
"""
|
||||
Helper method to load schemas.
|
||||
|
||||
This method captures a generic exception, since errors could potentially come
|
||||
from any of the 50+ database drivers we support.
|
||||
"""
|
||||
|
||||
try:
|
||||
return database.get_all_schema_names(
|
||||
force=True,
|
||||
catalog=catalog,
|
||||
ssh_tunnel=ssh_tunnel,
|
||||
)
|
||||
except Exception as ex:
|
||||
except GenericDBException as ex:
|
||||
raise DatabaseConnectionFailedError() from ex
|
||||
|
||||
def _refresh_catalogs(
|
||||
@@ -166,36 +160,43 @@ class UpdateDatabaseCommand(BaseCommand):
|
||||
)
|
||||
|
||||
for catalog in catalogs:
|
||||
schemas = self._get_schema_names(database, catalog, ssh_tunnel)
|
||||
try:
|
||||
schemas = self._get_schema_names(database, catalog, ssh_tunnel)
|
||||
|
||||
if catalog:
|
||||
perm = security_manager.get_catalog_perm(
|
||||
original_database_name,
|
||||
catalog,
|
||||
)
|
||||
existing_pvm = security_manager.find_permission_view_menu(
|
||||
"catalog_access",
|
||||
perm,
|
||||
)
|
||||
if not existing_pvm:
|
||||
# new catalog
|
||||
security_manager.add_permission_view_menu(
|
||||
"catalog_access",
|
||||
security_manager.get_catalog_perm(
|
||||
database.database_name,
|
||||
catalog,
|
||||
),
|
||||
if catalog:
|
||||
perm = security_manager.get_catalog_perm(
|
||||
original_database_name,
|
||||
catalog,
|
||||
)
|
||||
for schema in schemas:
|
||||
existing_pvm = security_manager.find_permission_view_menu(
|
||||
"catalog_access",
|
||||
perm,
|
||||
)
|
||||
if not existing_pvm:
|
||||
# new catalog
|
||||
security_manager.add_permission_view_menu(
|
||||
"schema_access",
|
||||
security_manager.get_schema_perm(
|
||||
"catalog_access",
|
||||
security_manager.get_catalog_perm(
|
||||
database.database_name,
|
||||
catalog,
|
||||
schema,
|
||||
),
|
||||
)
|
||||
for schema in schemas:
|
||||
security_manager.add_permission_view_menu(
|
||||
"schema_access",
|
||||
security_manager.get_schema_perm(
|
||||
database.database_name,
|
||||
catalog,
|
||||
schema,
|
||||
),
|
||||
)
|
||||
continue
|
||||
except DatabaseConnectionFailedError:
|
||||
# more than one catalog, move to next
|
||||
if catalog:
|
||||
logger.warning("Error processing catalog %s", catalog)
|
||||
continue
|
||||
raise
|
||||
|
||||
# add possible new schemas in catalog
|
||||
self._refresh_schemas(
|
||||
@@ -248,7 +249,7 @@ class UpdateDatabaseCommand(BaseCommand):
|
||||
catalog: str | None,
|
||||
schemas: set[str],
|
||||
) -> None:
|
||||
new_name = security_manager.get_catalog_perm(
|
||||
new_catalog_perm_name = security_manager.get_catalog_perm(
|
||||
database.database_name,
|
||||
catalog,
|
||||
)
|
||||
@@ -264,10 +265,10 @@ class UpdateDatabaseCommand(BaseCommand):
|
||||
perm,
|
||||
)
|
||||
if existing_pvm:
|
||||
existing_pvm.view_menu.name = new_name
|
||||
existing_pvm.view_menu.name = new_catalog_perm_name
|
||||
|
||||
for schema in schemas:
|
||||
new_name = security_manager.get_schema_perm(
|
||||
new_schema_perm_name = security_manager.get_schema_perm(
|
||||
database.database_name,
|
||||
catalog,
|
||||
schema,
|
||||
@@ -284,7 +285,7 @@ class UpdateDatabaseCommand(BaseCommand):
|
||||
perm,
|
||||
)
|
||||
if existing_pvm:
|
||||
existing_pvm.view_menu.name = new_name
|
||||
existing_pvm.view_menu.name = new_schema_perm_name
|
||||
|
||||
# rename permissions on datasets and charts
|
||||
for dataset in DatabaseDAO.get_datasets(
|
||||
@@ -292,9 +293,11 @@ class UpdateDatabaseCommand(BaseCommand):
|
||||
catalog=catalog,
|
||||
schema=schema,
|
||||
):
|
||||
dataset.schema_perm = new_name
|
||||
dataset.catalog_perm = new_catalog_perm_name
|
||||
dataset.schema_perm = new_schema_perm_name
|
||||
for chart in DatasetDAO.get_related_objects(dataset.id)["charts"]:
|
||||
chart.schema_perm = new_name
|
||||
chart.catalog_perm = new_catalog_perm_name
|
||||
chart.schema_perm = new_schema_perm_name
|
||||
|
||||
def validate(self) -> None:
|
||||
if database_name := self._properties.get("database_name"):
|
||||
|
||||
@@ -54,23 +54,28 @@ class CreateDatasetCommand(CreateMixin, BaseCommand):
|
||||
def validate(self) -> None:
|
||||
exceptions: list[ValidationError] = []
|
||||
database_id = self._properties["database"]
|
||||
schema = self._properties.get("schema")
|
||||
catalog = self._properties.get("catalog")
|
||||
schema = self._properties.get("schema")
|
||||
table_name = self._properties["table_name"]
|
||||
sql = self._properties.get("sql")
|
||||
owner_ids: Optional[list[int]] = self._properties.get("owners")
|
||||
|
||||
table = Table(self._properties["table_name"], schema, catalog)
|
||||
|
||||
# Validate uniqueness
|
||||
if not DatasetDAO.validate_uniqueness(database_id, table):
|
||||
exceptions.append(DatasetExistsValidationError(table))
|
||||
|
||||
# Validate/Populate database
|
||||
database = DatasetDAO.get_database_by_id(database_id)
|
||||
if not database:
|
||||
exceptions.append(DatabaseNotFoundValidationError())
|
||||
self._properties["database"] = database
|
||||
|
||||
# Validate uniqueness
|
||||
if database:
|
||||
if not catalog:
|
||||
catalog = self._properties["catalog"] = database.get_default_catalog()
|
||||
|
||||
table = Table(table_name, schema, catalog)
|
||||
|
||||
if not DatasetDAO.validate_uniqueness(database, table):
|
||||
exceptions.append(DatasetExistsValidationError(table))
|
||||
|
||||
# Validate table exists on dataset if sql is not provided
|
||||
# This should be validated when the dataset is physical
|
||||
if (
|
||||
|
||||
@@ -166,7 +166,7 @@ def import_dataset(
|
||||
|
||||
try:
|
||||
table_exists = dataset.database.has_table(
|
||||
Table(dataset.table_name, dataset.schema),
|
||||
Table(dataset.table_name, dataset.schema, dataset.catalog),
|
||||
)
|
||||
except Exception: # pylint: disable=broad-except
|
||||
# MySQL doesn't play nice with GSheets table names
|
||||
|
||||
@@ -79,10 +79,12 @@ class UpdateDatasetCommand(UpdateMixin, BaseCommand):
|
||||
def validate(self) -> None:
|
||||
exceptions: list[ValidationError] = []
|
||||
owner_ids: Optional[list[int]] = self._properties.get("owners")
|
||||
|
||||
# Validate/populate model exists
|
||||
self._model = DatasetDAO.find_by_id(self._model_id)
|
||||
if not self._model:
|
||||
raise DatasetNotFoundError()
|
||||
|
||||
# Check ownership
|
||||
try:
|
||||
security_manager.raise_for_ownership(self._model)
|
||||
@@ -91,22 +93,30 @@ class UpdateDatasetCommand(UpdateMixin, BaseCommand):
|
||||
|
||||
database_id = self._properties.get("database")
|
||||
|
||||
catalog = self._properties.get("catalog")
|
||||
if not catalog:
|
||||
catalog = self._properties["catalog"] = (
|
||||
self._model.database.get_default_catalog()
|
||||
)
|
||||
|
||||
table = Table(
|
||||
self._properties.get("table_name"), # type: ignore
|
||||
self._properties.get("schema"),
|
||||
self._properties.get("catalog"),
|
||||
catalog,
|
||||
)
|
||||
|
||||
# Validate uniqueness
|
||||
if not DatasetDAO.validate_update_uniqueness(
|
||||
self._model.database_id,
|
||||
self._model.database,
|
||||
table,
|
||||
self._model_id,
|
||||
):
|
||||
exceptions.append(DatasetExistsValidationError(table))
|
||||
|
||||
# Validate/Populate database not allowed to change
|
||||
if database_id and database_id != self._model:
|
||||
exceptions.append(DatabaseChangeValidationError())
|
||||
|
||||
# Validate/Populate owner
|
||||
try:
|
||||
owners = self.compute_owners(
|
||||
@@ -116,6 +126,7 @@ class UpdateDatasetCommand(UpdateMixin, BaseCommand):
|
||||
self._properties["owners"] = owners
|
||||
except ValidationError as ex:
|
||||
exceptions.append(ex)
|
||||
|
||||
# Validate columns
|
||||
if columns := self._properties.get("columns"):
|
||||
self._validate_columns(columns, exceptions)
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
import logging
|
||||
from copy import deepcopy
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Any, Optional, Union
|
||||
from uuid import UUID
|
||||
@@ -67,6 +66,7 @@ from superset.reports.notifications import create_notification
|
||||
from superset.reports.notifications.base import NotificationContent
|
||||
from superset.reports.notifications.exceptions import (
|
||||
NotificationError,
|
||||
NotificationParamException,
|
||||
SlackV1NotificationError,
|
||||
)
|
||||
from superset.tasks.utils import get_executor
|
||||
@@ -132,15 +132,13 @@ class BaseReportState:
|
||||
V2 uses ids instead of names for channels.
|
||||
"""
|
||||
try:
|
||||
updated_recipients = []
|
||||
for recipient in self._report_schedule.recipients:
|
||||
recipient_copy = deepcopy(recipient)
|
||||
if recipient_copy.type == ReportRecipientType.SLACK:
|
||||
recipient_copy.type = ReportRecipientType.SLACKV2
|
||||
slack_recipients = json.loads(recipient_copy.recipient_config_json)
|
||||
if recipient.type == ReportRecipientType.SLACK:
|
||||
recipient.type = ReportRecipientType.SLACKV2
|
||||
slack_recipients = json.loads(recipient.recipient_config_json)
|
||||
# we need to ensure that existing reports can also fetch
|
||||
# ids from private channels
|
||||
recipient_copy.recipient_config_json = json.dumps(
|
||||
recipient.recipient_config_json = json.dumps(
|
||||
{
|
||||
"target": get_channels_with_search(
|
||||
slack_recipients["target"],
|
||||
@@ -151,9 +149,6 @@ class BaseReportState:
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
updated_recipients.append(recipient_copy)
|
||||
db.session.commit() # pylint: disable=consider-using-transaction
|
||||
except Exception as ex:
|
||||
logger.warning(
|
||||
"Failed to update slack recipients to v2: %s", str(ex), exc_info=True
|
||||
@@ -367,6 +362,7 @@ class BaseReportState:
|
||||
chart_id = None
|
||||
dashboard_id = None
|
||||
report_source = None
|
||||
slack_channels = None
|
||||
if self._report_schedule.chart:
|
||||
report_source = ReportSourceFormat.CHART
|
||||
chart_id = self._report_schedule.chart_id
|
||||
@@ -374,6 +370,14 @@ class BaseReportState:
|
||||
report_source = ReportSourceFormat.DASHBOARD
|
||||
dashboard_id = self._report_schedule.dashboard_id
|
||||
|
||||
if self._report_schedule.recipients:
|
||||
slack_channels = [
|
||||
recipient.recipient_config_json
|
||||
for recipient in self._report_schedule.recipients
|
||||
if recipient.type
|
||||
in [ReportRecipientType.SLACK, ReportRecipientType.SLACKV2]
|
||||
]
|
||||
|
||||
log_data: HeaderDataType = {
|
||||
"notification_type": self._report_schedule.type,
|
||||
"notification_source": report_source,
|
||||
@@ -381,6 +385,7 @@ class BaseReportState:
|
||||
"chart_id": chart_id,
|
||||
"dashboard_id": dashboard_id,
|
||||
"owners": self._report_schedule.owners,
|
||||
"slack_channels": slack_channels,
|
||||
}
|
||||
return log_data
|
||||
|
||||
@@ -486,7 +491,7 @@ class BaseReportState:
|
||||
recipient.type = ReportRecipientType.SLACKV2
|
||||
notification = create_notification(recipient, notification_content)
|
||||
notification.send()
|
||||
except UpdateFailedError as err:
|
||||
except (UpdateFailedError, NotificationParamException) as err:
|
||||
# log the error but keep processing the report with SlackV1
|
||||
logger.warning(
|
||||
"Failed to update slack recipients to v2: %s", str(err)
|
||||
|
||||
109
superset/commands/sql_lab/query.py
Normal file
@@ -0,0 +1,109 @@
|
||||
# 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 logging
|
||||
import time
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
import sqlalchemy as sa
|
||||
|
||||
from superset import db
|
||||
from superset.commands.base import BaseCommand
|
||||
from superset.models.sql_lab import Query
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# pylint: disable=consider-using-transaction
|
||||
class QueryPruneCommand(BaseCommand):
|
||||
"""
|
||||
Command to prune the query table by deleting rows older than the specified retention period.
|
||||
|
||||
This command deletes records from the `Query` table that have not been changed within the
|
||||
specified number of days. It helps in maintaining the database by removing outdated entries
|
||||
and freeing up space.
|
||||
|
||||
Attributes:
|
||||
retention_period_days (int): The number of days for which records should be retained.
|
||||
Records older than this period will be deleted.
|
||||
"""
|
||||
|
||||
def __init__(self, retention_period_days: int):
|
||||
"""
|
||||
:param retention_period_days: Number of days to keep in the query table
|
||||
"""
|
||||
self.retention_period_days = retention_period_days
|
||||
|
||||
def run(self) -> None:
|
||||
"""
|
||||
Executes the prune command
|
||||
"""
|
||||
batch_size = 999 # SQLite has a IN clause limit of 999
|
||||
total_deleted = 0
|
||||
start_time = time.time()
|
||||
|
||||
# Select all IDs that need to be deleted
|
||||
ids_to_delete = (
|
||||
db.session.execute(
|
||||
sa.select(Query.id).where(
|
||||
Query.changed_on
|
||||
< datetime.now() - timedelta(days=self.retention_period_days)
|
||||
)
|
||||
)
|
||||
.scalars()
|
||||
.all()
|
||||
)
|
||||
|
||||
total_rows = len(ids_to_delete)
|
||||
|
||||
logger.info("Total rows to be deleted: %s", total_rows)
|
||||
|
||||
next_logging_threshold = 1
|
||||
|
||||
# Iterate over the IDs in batches
|
||||
for i in range(0, total_rows, batch_size):
|
||||
batch_ids = ids_to_delete[i : i + batch_size]
|
||||
|
||||
# Delete the selected batch using IN clause
|
||||
result = db.session.execute(sa.delete(Query).where(Query.id.in_(batch_ids)))
|
||||
|
||||
# Update the total number of deleted records
|
||||
total_deleted += result.rowcount
|
||||
|
||||
# Explicitly commit the transaction given that if an error occurs, we want to ensure that the
|
||||
# records that have been deleted so far are committed
|
||||
db.session.commit()
|
||||
|
||||
# Log the number of deleted records every 1% increase in progress
|
||||
percentage_complete = (total_deleted / total_rows) * 100
|
||||
if percentage_complete >= next_logging_threshold:
|
||||
logger.info(
|
||||
"Deleted %s rows from the query table older than %s days (%d%% complete)",
|
||||
total_deleted,
|
||||
self.retention_period_days,
|
||||
percentage_complete,
|
||||
)
|
||||
next_logging_threshold += 1
|
||||
|
||||
elapsed_time = time.time() - start_time
|
||||
minutes, seconds = divmod(elapsed_time, 60)
|
||||
formatted_time = f"{int(minutes):02}:{int(seconds):02}"
|
||||
logger.info(
|
||||
"Pruning complete: %s rows deleted in %s", total_deleted, formatted_time
|
||||
)
|
||||
|
||||
def validate(self) -> None:
|
||||
pass
|
||||
@@ -258,6 +258,7 @@ WTF_CSRF_EXEMPT_LIST = [
|
||||
"superset.views.core.log",
|
||||
"superset.views.core.explore_json",
|
||||
"superset.charts.data.api.data",
|
||||
"superset.dashboards.api.cache_dashboard_screenshot",
|
||||
]
|
||||
|
||||
# Whether to run the web server in debug mode or not
|
||||
@@ -975,7 +976,12 @@ CELERY_BEAT_SCHEDULER_EXPIRES = timedelta(weeks=1)
|
||||
|
||||
class CeleryConfig: # pylint: disable=too-few-public-methods
|
||||
broker_url = "sqla+sqlite:///celerydb.sqlite"
|
||||
imports = ("superset.sql_lab", "superset.tasks.scheduler")
|
||||
imports = (
|
||||
"superset.sql_lab",
|
||||
"superset.tasks.scheduler",
|
||||
"superset.tasks.thumbnails",
|
||||
"superset.tasks.cache",
|
||||
)
|
||||
result_backend = "db+sqlite:///celery_results.sqlite"
|
||||
worker_prefetch_multiplier = 1
|
||||
task_acks_late = False
|
||||
@@ -994,6 +1000,12 @@ class CeleryConfig: # pylint: disable=too-few-public-methods
|
||||
"task": "reports.prune_log",
|
||||
"schedule": crontab(minute=0, hour=0),
|
||||
},
|
||||
# Uncomment to enable pruning of the query table
|
||||
# "prune_query": {
|
||||
# "task": "prune_query",
|
||||
# "schedule": crontab(minute=0, hour=0, day_of_month=1),
|
||||
# "options": {"retention_period_days": 180},
|
||||
# },
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -461,9 +461,11 @@ class BaseDatasource(AuditMixinNullable, ImportExportMixin): # pylint: disable=
|
||||
)
|
||||
else:
|
||||
_columns = [
|
||||
utils.get_column_name(column_)
|
||||
if utils.is_adhoc_column(column_)
|
||||
else column_
|
||||
(
|
||||
utils.get_column_name(column_)
|
||||
if utils.is_adhoc_column(column_)
|
||||
else column_
|
||||
)
|
||||
for column_param in COLUMN_FORM_DATA_PARAMS
|
||||
for column_ in utils.as_list(form_data.get(column_param) or [])
|
||||
]
|
||||
@@ -1963,7 +1965,7 @@ class SqlaTable(
|
||||
if self.has_extra_cache_key_calls(query_obj):
|
||||
sqla_query = self.get_sqla_query(**query_obj)
|
||||
extra_cache_keys += sqla_query.extra_cache_keys
|
||||
return extra_cache_keys
|
||||
return list(set(extra_cache_keys))
|
||||
|
||||
@property
|
||||
def quote_identifier(self) -> Callable[[str], str]:
|
||||
|
||||
@@ -35,7 +35,12 @@ from superset.css_templates.schemas import (
|
||||
)
|
||||
from superset.extensions import event_logger
|
||||
from superset.models.core import CssTemplate
|
||||
from superset.views.base_api import BaseSupersetModelRestApi, statsd_metrics
|
||||
from superset.views.base_api import (
|
||||
BaseSupersetModelRestApi,
|
||||
RelatedFieldFilter,
|
||||
statsd_metrics,
|
||||
)
|
||||
from superset.views.filters import BaseFilterRelatedUsers, FilterRelatedOwners
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -91,6 +96,13 @@ class CssTemplateRestApi(BaseSupersetModelRestApi):
|
||||
openapi_spec_tag = "CSS Templates"
|
||||
openapi_spec_methods = openapi_spec_methods_override
|
||||
|
||||
related_field_filters = {
|
||||
"changed_by": RelatedFieldFilter("first_name", FilterRelatedOwners),
|
||||
}
|
||||
base_related_field_filters = {
|
||||
"changed_by": [["id", BaseFilterRelatedUsers, lambda: []]],
|
||||
}
|
||||
|
||||
@expose("/", methods=("DELETE",))
|
||||
@protect()
|
||||
@safe
|
||||
|
||||
@@ -84,15 +84,19 @@ class DatasetDAO(BaseDAO[SqlaTable]):
|
||||
|
||||
@staticmethod
|
||||
def validate_uniqueness(
|
||||
database_id: int,
|
||||
database: Database,
|
||||
table: Table,
|
||||
dataset_id: int | None = None,
|
||||
) -> bool:
|
||||
# The catalog might not be set even if the database supports catalogs, in case
|
||||
# multi-catalog is disabled.
|
||||
catalog = table.catalog or database.get_default_catalog()
|
||||
|
||||
dataset_query = db.session.query(SqlaTable).filter(
|
||||
SqlaTable.table_name == table.table,
|
||||
SqlaTable.schema == table.schema,
|
||||
SqlaTable.catalog == table.catalog,
|
||||
SqlaTable.database_id == database_id,
|
||||
SqlaTable.catalog == catalog,
|
||||
SqlaTable.database_id == database.id,
|
||||
)
|
||||
|
||||
if dataset_id:
|
||||
@@ -103,15 +107,19 @@ class DatasetDAO(BaseDAO[SqlaTable]):
|
||||
|
||||
@staticmethod
|
||||
def validate_update_uniqueness(
|
||||
database_id: int,
|
||||
database: Database,
|
||||
table: Table,
|
||||
dataset_id: int,
|
||||
) -> bool:
|
||||
# The catalog might not be set even if the database supports catalogs, in case
|
||||
# multi-catalog is disabled.
|
||||
catalog = table.catalog or database.get_default_catalog()
|
||||
|
||||
dataset_query = db.session.query(SqlaTable).filter(
|
||||
SqlaTable.table_name == table.table,
|
||||
SqlaTable.database_id == database_id,
|
||||
SqlaTable.database_id == database.id,
|
||||
SqlaTable.schema == table.schema,
|
||||
SqlaTable.catalog == table.catalog,
|
||||
SqlaTable.catalog == catalog,
|
||||
SqlaTable.id != dataset_id,
|
||||
)
|
||||
return not db.session.query(dataset_query.exists()).scalar()
|
||||
|
||||
@@ -34,10 +34,15 @@ from werkzeug.wsgi import FileWrapper
|
||||
|
||||
from superset import db, is_feature_enabled, thumbnail_cache
|
||||
from superset.charts.schemas import ChartEntityResponseSchema
|
||||
from superset.commands.dashboard.copy import CopyDashboardCommand
|
||||
from superset.commands.dashboard.create import CreateDashboardCommand
|
||||
from superset.commands.dashboard.delete import DeleteDashboardCommand
|
||||
from superset.commands.dashboard.delete import (
|
||||
DeleteDashboardCommand,
|
||||
DeleteEmbeddedDashboardCommand,
|
||||
)
|
||||
from superset.commands.dashboard.exceptions import (
|
||||
DashboardAccessDeniedError,
|
||||
DashboardCopyError,
|
||||
DashboardCreateFailedError,
|
||||
DashboardDeleteFailedError,
|
||||
DashboardForbiddenError,
|
||||
@@ -271,6 +276,7 @@ class DashboardRestApi(BaseSupersetModelRestApi):
|
||||
base_related_field_filters = {
|
||||
"owners": [["id", BaseFilterRelatedUsers, lambda: []]],
|
||||
"created_by": [["id", BaseFilterRelatedUsers, lambda: []]],
|
||||
"changed_by": [["id", BaseFilterRelatedUsers, lambda: []]],
|
||||
"roles": [["id", BaseFilterRelatedRoles, lambda: []]],
|
||||
}
|
||||
|
||||
@@ -278,6 +284,7 @@ class DashboardRestApi(BaseSupersetModelRestApi):
|
||||
"owners": RelatedFieldFilter("first_name", FilterRelatedOwners),
|
||||
"roles": RelatedFieldFilter("name", FilterRelatedRoles),
|
||||
"created_by": RelatedFieldFilter("first_name", FilterRelatedOwners),
|
||||
"changed_by": RelatedFieldFilter("first_name", FilterRelatedOwners),
|
||||
}
|
||||
allowed_rel_fields = {"owners", "roles", "created_by", "changed_by"}
|
||||
|
||||
@@ -1545,7 +1552,7 @@ class DashboardRestApi(BaseSupersetModelRestApi):
|
||||
500:
|
||||
$ref: '#/components/responses/500'
|
||||
"""
|
||||
EmbeddedDashboardDAO.delete(dashboard.embedded)
|
||||
DeleteEmbeddedDashboardCommand(dashboard).run()
|
||||
return self.response(200, message="OK")
|
||||
|
||||
@expose("/<id_or_slug>/copy/", methods=("POST",))
|
||||
@@ -1604,9 +1611,11 @@ class DashboardRestApi(BaseSupersetModelRestApi):
|
||||
return self.response_400(message=error.messages)
|
||||
|
||||
try:
|
||||
dash = DashboardDAO.copy_dashboard(original_dash, data)
|
||||
dash = CopyDashboardCommand(original_dash, data).run()
|
||||
except DashboardForbiddenError:
|
||||
return self.response_403()
|
||||
except DashboardCopyError:
|
||||
return self.response_400()
|
||||
|
||||
return self.response(
|
||||
200,
|
||||
|
||||
@@ -125,11 +125,13 @@ from superset.utils.oauth2 import decode_oauth2_state
|
||||
from superset.utils.ssh_tunnel import mask_password_info
|
||||
from superset.views.base_api import (
|
||||
BaseSupersetModelRestApi,
|
||||
RelatedFieldFilter,
|
||||
requires_form_data,
|
||||
requires_json,
|
||||
statsd_metrics,
|
||||
)
|
||||
from superset.views.error_handling import json_error_response
|
||||
from superset.views.filters import BaseFilterRelatedUsers, FilterRelatedOwners
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -304,6 +306,13 @@ class DatabaseRestApi(BaseSupersetModelRestApi):
|
||||
openapi_spec_methods = openapi_spec_methods_override
|
||||
""" Overrides GET methods OpenApi descriptions """
|
||||
|
||||
related_field_filters = {
|
||||
"changed_by": RelatedFieldFilter("first_name", FilterRelatedOwners),
|
||||
}
|
||||
base_related_field_filters = {
|
||||
"changed_by": [["id", BaseFilterRelatedUsers, lambda: []]],
|
||||
}
|
||||
|
||||
@expose("/<int:pk>/connection", methods=("GET",))
|
||||
@protect()
|
||||
@safe
|
||||
@@ -1150,7 +1159,7 @@ class DatabaseRestApi(BaseSupersetModelRestApi):
|
||||
self.incr_stats("init", self.select_star.__name__)
|
||||
try:
|
||||
result = database.select_star(
|
||||
Table(table_name, schema_name),
|
||||
Table(table_name, schema_name, database.get_default_catalog()),
|
||||
latest_partition=True,
|
||||
)
|
||||
except NoSuchTableError:
|
||||
|
||||
@@ -242,10 +242,12 @@ class DatasetRestApi(BaseSupersetModelRestApi):
|
||||
|
||||
base_related_field_filters = {
|
||||
"owners": [["id", BaseFilterRelatedUsers, lambda: []]],
|
||||
"changed_by": [["id", BaseFilterRelatedUsers, lambda: []]],
|
||||
"database": [["id", DatabaseFilter, lambda: []]],
|
||||
}
|
||||
related_field_filters = {
|
||||
"owners": RelatedFieldFilter("first_name", FilterRelatedOwners),
|
||||
"changed_by": RelatedFieldFilter("first_name", FilterRelatedOwners),
|
||||
"database": "database_name",
|
||||
}
|
||||
search_filters = {
|
||||
|
||||
@@ -92,6 +92,12 @@ ColumnTypeMapping = tuple[
|
||||
|
||||
logger = logging.getLogger()
|
||||
|
||||
# When connecting to a database it's hard to catch specific exceptions, since we support
|
||||
# more than 50 different database drivers. Usually the try/except block will catch the
|
||||
# generic `Exception` class, which requires a pylint disablee comment. To make it clear
|
||||
# that we know this is a necessary evil we create an alias, and catch it instead.
|
||||
GenericDBException = Exception
|
||||
|
||||
|
||||
def convert_inspector_columns(cols: list[SQLAColumnType]) -> list[ResultSetColumnType]:
|
||||
result_set_columns: list[ResultSetColumnType] = []
|
||||
@@ -406,7 +412,8 @@ class BaseEngineSpec: # pylint: disable=too-many-public-methods
|
||||
#
|
||||
# When this is changed to true in a DB engine spec it MUST support the
|
||||
# `get_default_catalog` and `get_catalog_names` methods. In addition, you MUST write
|
||||
# a database migration updating any existing schema permissions.
|
||||
# a database migration updating any existing schema permissions using the helper
|
||||
# `upgrade_catalog_perms`.
|
||||
supports_catalog = False
|
||||
|
||||
# Can the catalog be changed on a per-query basis?
|
||||
|
||||