mirror of
https://github.com/apache/superset.git
synced 2026-06-21 15:39:18 +00:00
Compare commits
118 Commits
enxdev/ref
...
fix-radar
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6b7394e789 | ||
|
|
5a8eab3b25 | ||
|
|
15969fdf94 | ||
|
|
9b15e04bc4 | ||
|
|
fd947a097d | ||
|
|
e1383d3821 | ||
|
|
c131205ff1 | ||
|
|
b6df88a134 | ||
|
|
629b137bb0 | ||
|
|
db959a6463 | ||
|
|
4041150660 | ||
|
|
bcb43327b1 | ||
|
|
63c8bbf3eb | ||
|
|
24b1666273 | ||
|
|
86b795cd36 | ||
|
|
bc0bf94680 | ||
|
|
f5d64176f6 | ||
|
|
4f0020d0df | ||
|
|
c83eda9551 | ||
|
|
a36e636a58 | ||
|
|
f5d3627468 | ||
|
|
8eeed49547 | ||
|
|
00933a27af | ||
|
|
2bc33beec4 | ||
|
|
e1c1de1b94 | ||
|
|
26743dfcee | ||
|
|
8b0bda3bad | ||
|
|
a8a6254ea2 | ||
|
|
be4bc3dec5 | ||
|
|
6e02d19b0d | ||
|
|
662f0fa8f4 | ||
|
|
56bf17f879 | ||
|
|
b92909d621 | ||
|
|
8f35a3ec8c | ||
|
|
a4a092794a | ||
|
|
174750c9dd | ||
|
|
f2c0686346 | ||
|
|
c2afae51cb | ||
|
|
6e1d1ad18b | ||
|
|
ab22bb1878 | ||
|
|
e0ed652ed8 | ||
|
|
103fedaf92 | ||
|
|
50fe7483ae | ||
|
|
37f626f5e2 | ||
|
|
b1693f625a | ||
|
|
f0dc1e7527 | ||
|
|
6c7f089ebb | ||
|
|
68a81c3989 | ||
|
|
5222f940cc | ||
|
|
45ea11c1b6 | ||
|
|
b624919d2f | ||
|
|
b5cb5f4525 | ||
|
|
4a70065e5f | ||
|
|
7d77dc4fd2 | ||
|
|
6f69c84d10 | ||
|
|
6b96b37c38 | ||
|
|
b7435f84f0 | ||
|
|
7bc349c3c3 | ||
|
|
fd4e45aafc | ||
|
|
b339d7ad20 | ||
|
|
cedd186c21 | ||
|
|
c6c9114b40 | ||
|
|
f4a05a5ffd | ||
|
|
a82f916a71 | ||
|
|
ff0529c932 | ||
|
|
c0f83a7467 | ||
|
|
9bb3a5782d | ||
|
|
5ec710efc6 | ||
|
|
5866f3ec83 | ||
|
|
01801e3c36 | ||
|
|
d319543377 | ||
|
|
5392bafe28 | ||
|
|
89ce7ba0b0 | ||
|
|
376a1f49d3 | ||
|
|
6042ea8f28 | ||
|
|
78efb62781 | ||
|
|
e9d5079986 | ||
|
|
c6e0abbe13 | ||
|
|
4f166a03f5 | ||
|
|
29b62f7c0a | ||
|
|
09ee3e2a1d | ||
|
|
121e424a7f | ||
|
|
66c1a6a875 | ||
|
|
b26c373f4d | ||
|
|
4dd318ca68 | ||
|
|
ce6d5f5551 | ||
|
|
9e3052968b | ||
|
|
3f1ef2a283 | ||
|
|
bc3e19d0a2 | ||
|
|
850801f510 | ||
|
|
710af87faf | ||
|
|
6612343f33 | ||
|
|
c399295a4e | ||
|
|
e34644d983 | ||
|
|
cc0097c87a | ||
|
|
d71e655a4b | ||
|
|
99e69c32ee | ||
|
|
a2c164a77d | ||
|
|
78d2a584b7 | ||
|
|
f0c8c12c1a | ||
|
|
34cd741e9b | ||
|
|
1684ddc7e6 | ||
|
|
e35145c816 | ||
|
|
4adf44a43c | ||
|
|
cd5a94305c | ||
|
|
b4602aaf28 | ||
|
|
3e69ba1384 | ||
|
|
41bf215367 | ||
|
|
06deaebe19 | ||
|
|
6a13ab8920 | ||
|
|
f1a222d356 | ||
|
|
a87bedf31a | ||
|
|
890b6079b9 | ||
|
|
9c62456487 | ||
|
|
414cdbf83a | ||
|
|
df06bdf33b | ||
|
|
449f51aed5 | ||
|
|
c9e2c7037e |
@@ -17,6 +17,12 @@
|
||||
|
||||
# https://cwiki.apache.org/confluence/display/INFRA/.asf.yaml+features+for+git+repositories
|
||||
---
|
||||
notifications:
|
||||
commits: commits@superset.apache.org
|
||||
issues: notifications@superset.apache.org
|
||||
pullrequests: notifications@superset.apache.org
|
||||
discussions: notifications@superset.apache.org
|
||||
|
||||
github:
|
||||
del_branch_on_merge: true
|
||||
description: "Apache Superset is a Data Visualization and Data Exploration Platform"
|
||||
@@ -48,6 +54,8 @@ github:
|
||||
projects: true
|
||||
# Enable wiki for documentation
|
||||
wiki: true
|
||||
# Enable discussions
|
||||
discussions: true
|
||||
|
||||
enabled_merge_buttons:
|
||||
squash: true
|
||||
|
||||
2
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
2
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
@@ -41,7 +41,7 @@ body:
|
||||
label: Superset version
|
||||
options:
|
||||
- master / latest-dev
|
||||
- "4.1.1"
|
||||
- "4.1.2"
|
||||
- "4.0.2"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -107,6 +107,7 @@ ghostdriver.log
|
||||
testCSV.csv
|
||||
.terser-plugin-cache/
|
||||
apache-superset-*.tar.gz*
|
||||
apache_superset-*.tar.gz*
|
||||
release.json
|
||||
|
||||
# Translation-related files
|
||||
|
||||
@@ -57,7 +57,7 @@ repos:
|
||||
hooks:
|
||||
- id: prettier
|
||||
additional_dependencies:
|
||||
- prettier@3.3.3
|
||||
- prettier@3.5.3
|
||||
args: ["--ignore-path=./superset-frontend/.prettierignore"]
|
||||
files: "superset-frontend"
|
||||
- repo: local
|
||||
|
||||
50
CHANGELOG/4.1.1.md
Normal file
50
CHANGELOG/4.1.1.md
Normal file
@@ -0,0 +1,50 @@
|
||||
<!--
|
||||
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 (Fri Nov 15 22:13:57 2024 +0530)
|
||||
|
||||
**Database Migrations**
|
||||
|
||||
**Features**
|
||||
|
||||
**Fixes**
|
||||
|
||||
- [#30886](https://github.com/apache/superset/pull/30886) fix: blocks UI elements on right side (@samarsrivastav)
|
||||
- [#30859](https://github.com/apache/superset/pull/30859) fix(package.json): Pin luxon version to unblock master (@geido)
|
||||
- [#30588](https://github.com/apache/superset/pull/30588) fix(explore): column data type tooltip format (@mistercrunch)
|
||||
- [#29911](https://github.com/apache/superset/pull/29911) fix: Rename database from 'couchbasedb' to 'couchbase' in documentation and db_engine_specs (@ayush-couchbase)
|
||||
- [#30828](https://github.com/apache/superset/pull/30828) fix(TimezoneSelector): Failing unit tests due to timezone change (@geido)
|
||||
- [#30875](https://github.com/apache/superset/pull/30875) fix: don't show metadata for embedded dashboards (@sadpandajoe)
|
||||
- [#30851](https://github.com/apache/superset/pull/30851) fix: Graph chart colors (@michael-s-molina)
|
||||
- [#29867](https://github.com/apache/superset/pull/29867) fix(capitalization): Capitalizing a button. (@rusackas)
|
||||
- [#29782](https://github.com/apache/superset/pull/29782) fix(translations): Translate embedded errors (@rusackas)
|
||||
- [#29772](https://github.com/apache/superset/pull/29772) fix: Fixing incomplete string escaping. (@rusackas)
|
||||
- [#29725](https://github.com/apache/superset/pull/29725) fix(frontend/docker, ci): fix borked Docker build due to Lerna v8 uplift (@hainenber)
|
||||
|
||||
**Others**
|
||||
|
||||
- [#30576](https://github.com/apache/superset/pull/30576) chore: add link to Superset when report error (@eschutho)
|
||||
- [#29786](https://github.com/apache/superset/pull/29786) refactor(Slider): Upgrade Slider to Antd 5 (@geido)
|
||||
- [#29674](https://github.com/apache/superset/pull/29674) refactor(ChartCreation): Migrate tests to RTL (@rtexelm)
|
||||
- [#29843](https://github.com/apache/superset/pull/29843) refactor(controls): Migrate AdhocMetricOption.test to RTL (@rtexelm)
|
||||
- [#29845](https://github.com/apache/superset/pull/29845) refactor(controls): Migrate MetricDefinitionValue.test to RTL (@rtexelm)
|
||||
- [#28424](https://github.com/apache/superset/pull/28424) docs: Check markdown files for bad links using linkinator (@rusackas)
|
||||
- [#29768](https://github.com/apache/superset/pull/29768) docs(contributing): fix broken link to translations sub-section (@sfirke)
|
||||
83
CHANGELOG/4.1.2.md
Normal file
83
CHANGELOG/4.1.2.md
Normal file
@@ -0,0 +1,83 @@
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
-->
|
||||
|
||||
## Change Log
|
||||
|
||||
### 4.1.2 (Fri Mar 7 13:28:05 2025 -0800)
|
||||
|
||||
**Database Migrations**
|
||||
|
||||
- [#32538](https://github.com/apache/superset/pull/32538) fix(migrations): Handle comparator None in old time comparison migration (@Antonio-RiveroMartnez)
|
||||
- [#32155](https://github.com/apache/superset/pull/32155) fix(migrations): Handle no params in time comparison migration (@Antonio-RiveroMartnez)
|
||||
- [#31185](https://github.com/apache/superset/pull/31185) fix: check for column before adding in migrations (@betodealmeida)
|
||||
|
||||
**Features**
|
||||
|
||||
- [#29974](https://github.com/apache/superset/pull/29974) feat(sqllab): Adds refresh button to table metadata in SQL Lab (@Usiel)
|
||||
|
||||
**Fixes**
|
||||
|
||||
- [#32515](https://github.com/apache/superset/pull/32515) fix(sqllab): Allow clear on schema and catalog (@justinpark)
|
||||
- [#32500](https://github.com/apache/superset/pull/32500) fix: dashboard, chart and dataset import validation (@dpgaspar)
|
||||
- [#31353](https://github.com/apache/superset/pull/31353) fix(sqllab): duplicate error message (@betodealmeida)
|
||||
- [#31407](https://github.com/apache/superset/pull/31407) fix: Big Number side cut fixed (@fardin-developer)
|
||||
- [#31480](https://github.com/apache/superset/pull/31480) fix(sunburst): Use metric label from verbose map (@gerbermichi)
|
||||
- [#31427](https://github.com/apache/superset/pull/31427) fix(tags): clean up bulk create api and schema (@villebro)
|
||||
- [#31334](https://github.com/apache/superset/pull/31334) fix(docs): add custom editUrl path for intro page (@dwgrossberg)
|
||||
- [#31353](https://github.com/apache/superset/pull/31353) fix(sqllab): duplicate error message (@betodealmeida)
|
||||
- [#31323](https://github.com/apache/superset/pull/31323) fix: Use clickhouse sqlglot dialect for YDB (@vgvoleg)
|
||||
- [#31198](https://github.com/apache/superset/pull/31198) fix: add more clickhouse disallowed functions on config (@dpgaspar)
|
||||
- [#31194](https://github.com/apache/superset/pull/31194) fix(embedded): Hide anchor links in embedded mode (@Vitor-Avila)
|
||||
- [#31960](https://github.com/apache/superset/pull/31960) fix(sqllab): Missing allowHTML props in ResultTableExtension (@justinpark)
|
||||
- [#31332](https://github.com/apache/superset/pull/31332) fix: prevent multiple pvm errors on migration (@eschutho)
|
||||
- [#31437](https://github.com/apache/superset/pull/31437) fix(database import): Gracefully handle error to get catalog schemas (@Vitor-Avila)
|
||||
- [#31173](https://github.com/apache/superset/pull/31173) fix: cache-warmup fails (@nsivarajan)
|
||||
- [#30442](https://github.com/apache/superset/pull/30442) fix(fe/src/dashboard): optional chaining for possibly nullable parent attribute in LayoutItem type (@hainenber)
|
||||
- [#31639](https://github.com/apache/superset/pull/31639) fix(sqllab): unable to update saved queries (@DamianPendrak)
|
||||
- [#29898](https://github.com/apache/superset/pull/29898) fix: parse pandas pivot null values (@eschutho)
|
||||
- [#31414](https://github.com/apache/superset/pull/31414) fix(Pivot Table): Fix column width to respect currency config (@Vitor-Avila)
|
||||
- [#31335](https://github.com/apache/superset/pull/31335) fix(histogram): axis margin padding consistent with other graphs (@tatiana-cherne)
|
||||
- [#31301](https://github.com/apache/superset/pull/31301) fix(AllEntitiesTable): show Tags (@alexandrusoare)
|
||||
- [#31329](https://github.com/apache/superset/pull/31329) fix: pass string to `process_template` (@betodealmeida)
|
||||
- [#31341](https://github.com/apache/superset/pull/31341) fix(pinot): remove query aliases from SELECT and ORDER BY clauses in Pinot (@yuribogomolov)
|
||||
- [#31308](https://github.com/apache/superset/pull/31308) fix: annotations on horizontal bar chart (@DamianPendrak)
|
||||
- [#31294](https://github.com/apache/superset/pull/31294) fix(sqllab): Remove update_saved_query_exec_info to reduce lag (@justinpark)
|
||||
- [#30897](https://github.com/apache/superset/pull/30897) fix: Exception handling for SQL Lab views (@michael-s-molina)
|
||||
- [#31199](https://github.com/apache/superset/pull/31199) fix(Databricks): Escape catalog and schema names in pre-queries (@Vitor-Avila)
|
||||
- [#31265](https://github.com/apache/superset/pull/31265) fix(trino): db session error in handle cursor (@justinpark)
|
||||
- [#31024](https://github.com/apache/superset/pull/31024) fix(dataset): use sqlglot for DML check (@betodealmeida)
|
||||
- [#29885](https://github.com/apache/superset/pull/29885) fix: add mutator to get_columns_description (@eschutho)
|
||||
- [#30821](https://github.com/apache/superset/pull/30821) fix: x axis title disappears when editing bar chart (@DamianPendrak)
|
||||
- [#31181](https://github.com/apache/superset/pull/31181) fix: Time-series Line Chart Display unnecessary total (@michael-s-molina)
|
||||
- [#31163](https://github.com/apache/superset/pull/31163) fix(Dashboard): Backward compatible shared_label_colors field (@geido)
|
||||
- [#31156](https://github.com/apache/superset/pull/31156) fix: check orderby (@betodealmeida)
|
||||
- [#31154](https://github.com/apache/superset/pull/31154) fix: Remove unwanted commit on Trino's handle_cursor (@michael-s-molina)
|
||||
- [#31151](https://github.com/apache/superset/pull/31151) fix: Revert "feat(trino): Add functionality to upload data (#29164)" (@michael-s-molina)
|
||||
- [#31031](https://github.com/apache/superset/pull/31031) fix(Dashboard): Ensure shared label colors are updated (@geido)
|
||||
- [#30967](https://github.com/apache/superset/pull/30967) fix(release validation): scripts now support RSA and EDDSA keys. (@rusackas)
|
||||
- [#30881](https://github.com/apache/superset/pull/30881) fix(Dashboard): Native & Cross-Filters Scoping Performance (@geido)
|
||||
- [#30887](https://github.com/apache/superset/pull/30887) fix(imports): import query_context for imports with charts (@lindenh)
|
||||
- [#31008](https://github.com/apache/superset/pull/31008) fix(explore): verified props is not updated (@justinpark)
|
||||
- [#30646](https://github.com/apache/superset/pull/30646) fix(Dashboard): Retain colors when color scheme not set (@geido)
|
||||
- [#30962](https://github.com/apache/superset/pull/30962) fix(Dashboard): Exclude edit param in async screenshot (@geido)
|
||||
|
||||
**Others**
|
||||
|
||||
- [#32043](https://github.com/apache/superset/pull/32043) chore: Skip the creation of secondary perms during catalog migrations (@Vitor-Avila)
|
||||
- [#30865](https://github.com/apache/superset/pull/30865) docs: Updating 4.1 Release Notes (@yousoph)
|
||||
20
README.md
20
README.md
@@ -20,11 +20,11 @@ under the License.
|
||||
# Superset
|
||||
|
||||
[](https://opensource.org/license/apache-2-0)
|
||||
[](https://github.com/apache/superset/tree/latest)
|
||||
[](https://github.com/apache/superset/actions)
|
||||
[](https://badge.fury.io/py/apache-superset)
|
||||
[](https://github.com/apache/superset/releases/latest)
|
||||
[](https://github.com/apache/superset/actions)
|
||||
[](https://badge.fury.io/py/apache_superset)
|
||||
[](https://codecov.io/github/apache/superset)
|
||||
[](https://pypi.python.org/pypi/apache-superset)
|
||||
[](https://pypi.python.org/pypi/apache_superset)
|
||||
[](http://bit.ly/join-superset-slack)
|
||||
[](https://superset.apache.org)
|
||||
|
||||
@@ -72,9 +72,10 @@ Superset provides:
|
||||
## Screenshots & Gifs
|
||||
|
||||
**Video Overview**
|
||||
<!-- File hosted here https://github.com/apache/superset-site/raw/lfs/superset-video-4k.mp4 -->
|
||||
[superset-video-1080p.webm](https://github.com/user-attachments/assets/b37388f7-a971-409c-96a7-90c4e31322e6)
|
||||
|
||||
<!-- File hosted here https://github.com/apache/superset-site/raw/lfs/superset-video-4k.mp4 -->
|
||||
|
||||
[superset-video-1080p.webm](https://github.com/user-attachments/assets/b37388f7-a971-409c-96a7-90c4e31322e6)
|
||||
|
||||
<br/>
|
||||
|
||||
@@ -156,7 +157,7 @@ Try out Superset's [quickstart](https://superset.apache.org/docs/quickstart/) gu
|
||||
and please read our [Slack Community Guidelines](https://github.com/apache/superset/blob/master/CODE_OF_CONDUCT.md#slack-community-guidelines)
|
||||
- [Join our dev@superset.apache.org Mailing list](https://lists.apache.org/list.html?dev@superset.apache.org). To join, simply send an email to [dev-subscribe@superset.apache.org](mailto:dev-subscribe@superset.apache.org)
|
||||
- If you want to help troubleshoot GitHub Issues involving the numerous database drivers that Superset supports, please consider adding your name and the databases you have access to on the [Superset Database Familiarity Rolodex](https://docs.google.com/spreadsheets/d/1U1qxiLvOX0kBTUGME1AHHi6Ywel6ECF8xk_Qy-V9R8c/edit#gid=0)
|
||||
- Join Superset's Town Hall and [Operational Model](https://preset.io/blog/the-superset-operational-model-wants-you/) recurring meetings. Meeting info is available on the [Superset Community Calendar](https://superset.apache.org/community)
|
||||
- Join Superset's Town Hall and [Operational Model](https://preset.io/blog/the-superset-operational-model-wants-you/) recurring meetings. Meeting info is available on the [Superset Community Calendar](https://superset.apache.org/community)
|
||||
|
||||
## Contributor Guide
|
||||
|
||||
@@ -184,14 +185,16 @@ Understanding the Superset Points of View
|
||||
- [Building New Database Connectors](https://preset.io/blog/building-database-connector/)
|
||||
- [Create Your First Dashboard](https://superset.apache.org/docs/using-superset/creating-your-first-dashboard/)
|
||||
- [Comprehensive Tutorial for Contributing Code to Apache Superset
|
||||
](https://preset.io/blog/tutorial-contributing-code-to-apache-superset/)
|
||||
](https://preset.io/blog/tutorial-contributing-code-to-apache-superset/)
|
||||
- [Resources to master Superset by Preset](https://preset.io/resources/)
|
||||
|
||||
- Deploying Superset
|
||||
|
||||
- [Official Docker image](https://hub.docker.com/r/apache/superset)
|
||||
- [Helm Chart](https://github.com/apache/superset/tree/master/helm/superset)
|
||||
|
||||
- Recordings of Past [Superset Community Events](https://preset.io/events)
|
||||
|
||||
- [Mixed Time Series Charts](https://preset.io/events/mixed-time-series-visualization-in-superset-workshop/)
|
||||
- [How the Bing Team Customized Superset for the Internal Self-Serve Data & Analytics Platform](https://preset.io/events/how-the-bing-team-heavily-customized-superset-for-their-internal-data/)
|
||||
- [Live Demo: Visualizing MongoDB and Pinot Data using Trino](https://preset.io/events/2021-04-13-visualizing-mongodb-and-pinot-data-using-trino/)
|
||||
@@ -199,6 +202,7 @@ Understanding the Superset Points of View
|
||||
- [Building a Database Connector for Superset](https://preset.io/events/2021-02-16-building-a-database-connector-for-superset/)
|
||||
|
||||
- Visualizations
|
||||
|
||||
- [Creating Viz Plugins](https://superset.apache.org/docs/contributing/creating-viz-plugins/)
|
||||
- [Managing and Deploying Custom Viz Plugins](https://medium.com/nmc-techblog/apache-superset-manage-custom-viz-plugins-in-production-9fde1a708e55)
|
||||
- [Why Apache Superset is Betting on Apache ECharts](https://preset.io/blog/2021-4-1-why-echarts/)
|
||||
|
||||
@@ -20,7 +20,7 @@ RUN useradd --user-group --create-home --no-log-init --shell /bin/bash superset
|
||||
|
||||
# Configure environment
|
||||
ENV LANG=C.UTF-8 \
|
||||
LC_ALL=C.UTF-8
|
||||
LC_ALL=C.UTF-8
|
||||
|
||||
RUN apt-get update -y
|
||||
|
||||
@@ -30,14 +30,14 @@ RUN apt-get install -y apt-transport-https apt-utils
|
||||
# Install superset dependencies
|
||||
# https://superset.apache.org/docs/installation/installing-superset-from-scratch
|
||||
RUN apt-get install -y build-essential libssl-dev \
|
||||
libffi-dev python3-dev libsasl2-dev libldap2-dev libxi-dev chromium zstd
|
||||
libffi-dev python3-dev libsasl2-dev libldap2-dev libxi-dev chromium zstd
|
||||
|
||||
# Install nodejs for custom build
|
||||
# https://nodejs.org/en/download/package-manager/
|
||||
RUN set -eux; \
|
||||
curl -sL https://deb.nodesource.com/setup_20.x | bash -; \
|
||||
apt-get install -y nodejs; \
|
||||
node --version;
|
||||
curl -sL https://deb.nodesource.com/setup_20.x | bash -; \
|
||||
apt-get install -y nodejs; \
|
||||
node --version;
|
||||
RUN if ! which npm; then apt-get install -y npm; fi
|
||||
|
||||
RUN mkdir -p /home/superset
|
||||
@@ -50,21 +50,21 @@ ARG SUPERSET_RELEASE_RC_TARBALL
|
||||
# Can fetch source from svn or copy tarball from local mounted directory
|
||||
COPY $SUPERSET_RELEASE_RC_TARBALL ./
|
||||
RUN tar -xvf *.tar.gz
|
||||
WORKDIR /home/superset/apache-superset-$VERSION/superset-frontend
|
||||
WORKDIR /home/superset/apache_superset-$VERSION/superset-frontend
|
||||
|
||||
RUN npm ci \
|
||||
&& npm run build \
|
||||
&& rm -rf node_modules
|
||||
&& npm run build \
|
||||
&& rm -rf node_modules
|
||||
|
||||
WORKDIR /home/superset/apache-superset-$VERSION
|
||||
WORKDIR /home/superset/apache_superset-$VERSION
|
||||
RUN pip install --upgrade setuptools pip \
|
||||
&& pip install -r requirements/base.txt \
|
||||
&& pip install --no-cache-dir .
|
||||
&& pip install -r requirements/base.txt \
|
||||
&& pip install --no-cache-dir .
|
||||
|
||||
RUN flask fab babel-compile --target superset/translations
|
||||
|
||||
ENV PATH=/home/superset/superset/bin:$PATH \
|
||||
PYTHONPATH=/home/superset/superset/ \
|
||||
SUPERSET_TESTENV=true
|
||||
PYTHONPATH=/home/superset/superset/ \
|
||||
SUPERSET_TESTENV=true
|
||||
COPY from_tarball_entrypoint.sh /entrypoint.sh
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
|
||||
@@ -20,7 +20,7 @@ RUN useradd --user-group --create-home --no-log-init --shell /bin/bash superset
|
||||
|
||||
# Configure environment
|
||||
ENV LANG=C.UTF-8 \
|
||||
LC_ALL=C.UTF-8
|
||||
LC_ALL=C.UTF-8
|
||||
|
||||
RUN apt-get update -y
|
||||
|
||||
@@ -30,14 +30,14 @@ RUN apt-get install -y apt-transport-https apt-utils
|
||||
# Install superset dependencies
|
||||
# https://superset.apache.org/docs/installation/installing-superset-from-scratch
|
||||
RUN apt-get install -y subversion build-essential libssl-dev \
|
||||
libffi-dev python3-dev libsasl2-dev libldap2-dev libxi-dev chromium zstd
|
||||
libffi-dev python3-dev libsasl2-dev libldap2-dev libxi-dev chromium zstd
|
||||
|
||||
# Install nodejs for custom build
|
||||
# https://nodejs.org/en/download/package-manager/
|
||||
RUN set -eux; \
|
||||
curl -sL https://deb.nodesource.com/setup_20.x | bash -; \
|
||||
apt-get install -y nodejs; \
|
||||
node --version;
|
||||
curl -sL https://deb.nodesource.com/setup_20.x | bash -; \
|
||||
apt-get install -y nodejs; \
|
||||
node --version;
|
||||
RUN if ! which npm; then apt-get install -y npm; fi
|
||||
|
||||
RUN mkdir -p /home/superset
|
||||
@@ -49,20 +49,20 @@ ARG VERSION
|
||||
# Can fetch source from svn or copy tarball from local mounted directory
|
||||
RUN svn co https://dist.apache.org/repos/dist/dev/superset/$VERSION ./
|
||||
RUN tar -xvf *.tar.gz
|
||||
WORKDIR /home/superset/apache-superset-$VERSION/superset-frontend
|
||||
WORKDIR /home/superset/apache_superset-$VERSION/superset-frontend
|
||||
|
||||
RUN npm ci \
|
||||
&& npm run build \
|
||||
&& rm -rf node_modules
|
||||
&& npm run build \
|
||||
&& rm -rf node_modules
|
||||
|
||||
WORKDIR /home/superset/apache-superset-$VERSION
|
||||
WORKDIR /home/superset/apache_superset-$VERSION
|
||||
RUN pip install --upgrade setuptools pip \
|
||||
&& pip install -r requirements/base.txt \
|
||||
&& pip install --no-cache-dir .
|
||||
&& pip install -r requirements/base.txt \
|
||||
&& pip install --no-cache-dir .
|
||||
|
||||
RUN flask fab babel-compile --target superset/translations
|
||||
|
||||
ENV PATH=/home/superset/superset/bin:$PATH \
|
||||
PYTHONPATH=/home/superset/superset/
|
||||
PYTHONPATH=/home/superset/superset/
|
||||
COPY from_tarball_entrypoint.sh /entrypoint.sh
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
|
||||
@@ -123,10 +123,10 @@ SUPERSET_RC=1
|
||||
SUPERSET_GITHUB_BRANCH=1.5
|
||||
SUPERSET_PGP_FULLNAME=villebro@apache.org
|
||||
SUPERSET_VERSION_RC=1.5.1rc1
|
||||
SUPERSET_RELEASE=apache-superset-1.5.1
|
||||
SUPERSET_RELEASE_RC=apache-superset-1.5.1rc1
|
||||
SUPERSET_RELEASE_TARBALL=apache-superset-1.5.1-source.tar.gz
|
||||
SUPERSET_RELEASE_RC_TARBALL=apache-superset-1.5.1rc1-source.tar.gz
|
||||
SUPERSET_RELEASE=apache_superset-1.5.1
|
||||
SUPERSET_RELEASE_RC=apache_superset-1.5.1rc1
|
||||
SUPERSET_RELEASE_TARBALL=apache_superset-1.5.1-source.tar.gz
|
||||
SUPERSET_RELEASE_RC_TARBALL=apache_superset-1.5.1rc1-source.tar.gz
|
||||
SUPERSET_TMP_ASF_SITE_PATH=/tmp/incubator-superset-site-1.5.1
|
||||
-------------------------------
|
||||
```
|
||||
@@ -380,7 +380,7 @@ Official instructions:
|
||||
https://www.apache.org/info/verification.html
|
||||
|
||||
We now have a handy script for anyone validating a release to use. The core of it is in this very folder, `verify_release.py`. Just make sure you have all three release files in the same directory (`{some version}.tar.gz`, `{some version}.tar.gz.asc` and `{some version}tar.gz.sha512`). Then you can pass this script the path to the `.gz` file like so:
|
||||
`python verify_release.py ~/path/tp/apache-superset-{version/candidate}-source.tar.gz`
|
||||
`python verify_release.py ~/path/tp/apache_superset-{version/candidate}-source.tar.gz`
|
||||
|
||||
If all goes well, you will see this result in your terminal:
|
||||
|
||||
@@ -470,7 +470,7 @@ while requesting access to push packages.
|
||||
|
||||
```bash
|
||||
twine upload dist/apache_superset-${SUPERSET_VERSION}-py3-none-any.whl
|
||||
twine upload dist/apache-superset-${SUPERSET_VERSION}.tar.gz
|
||||
twine upload dist/apache_superset-${SUPERSET_VERSION}.tar.gz
|
||||
```
|
||||
|
||||
Set your username to `__token__`
|
||||
|
||||
@@ -31,7 +31,7 @@ The official source release:
|
||||
https://downloads.apache.org/{{ project_module }}/{{ version }}
|
||||
|
||||
The PyPI package:
|
||||
https://pypi.org/project/apache-superset/{{ version }}
|
||||
https://pypi.org/project/apache_superset/{{ version }}
|
||||
|
||||
The CHANGELOG for the release:
|
||||
https://github.com/apache/{{ project_module }}/blob/{{ version }}/CHANGELOG/{{ version }}.md
|
||||
|
||||
@@ -32,7 +32,7 @@ else
|
||||
SUPERSET_VERSION="${1}"
|
||||
SUPERSET_RC="${2}"
|
||||
SUPERSET_PGP_FULLNAME="${3}"
|
||||
SUPERSET_RELEASE_RC_TARBALL="apache-superset-${SUPERSET_VERSION_RC}-source.tar.gz"
|
||||
SUPERSET_RELEASE_RC_TARBALL="apache_superset-${SUPERSET_VERSION_RC}-source.tar.gz"
|
||||
fi
|
||||
|
||||
SUPERSET_VERSION_RC="${SUPERSET_VERSION}rc${SUPERSET_RC}"
|
||||
|
||||
@@ -22,7 +22,7 @@ if [ -z "${SUPERSET_VERSION_RC}" ] || [ -z "${SUPERSET_SVN_DEV_PATH}" ] || [ -z
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SUPERSET_RELEASE_RC=apache-superset-"${SUPERSET_VERSION_RC}"
|
||||
SUPERSET_RELEASE_RC=apache_superset-"${SUPERSET_VERSION_RC}"
|
||||
SUPERSET_RELEASE_RC_TARBALL="${SUPERSET_RELEASE_RC}"-source.tar.gz
|
||||
SUPERSET_RELEASE_RC_BASE_PATH="${SUPERSET_SVN_DEV_PATH}"/"${SUPERSET_VERSION_RC}"
|
||||
SUPERSET_RELEASE_RC_TARBALL_PATH="${SUPERSET_RELEASE_RC_BASE_PATH}"/"${SUPERSET_RELEASE_RC_TARBALL}"
|
||||
|
||||
@@ -50,8 +50,8 @@ else
|
||||
export SUPERSET_GITHUB_BRANCH="${VERSION_MAJOR}.${VERSION_MINOR}"
|
||||
export SUPERSET_PGP_FULLNAME="${2}"
|
||||
export SUPERSET_VERSION_RC="${SUPERSET_VERSION}rc${VERSION_RC}"
|
||||
export SUPERSET_RELEASE=apache-superset-"${SUPERSET_VERSION}"
|
||||
export SUPERSET_RELEASE_RC=apache-superset-"${SUPERSET_VERSION_RC}"
|
||||
export SUPERSET_RELEASE=apache_superset-"${SUPERSET_VERSION}"
|
||||
export SUPERSET_RELEASE_RC=apache_superset-"${SUPERSET_VERSION_RC}"
|
||||
export SUPERSET_RELEASE_TARBALL="${SUPERSET_RELEASE}"-source.tar.gz
|
||||
export SUPERSET_RELEASE_RC_TARBALL="${SUPERSET_RELEASE_RC}"-source.tar.gz
|
||||
export SUPERSET_TMP_ASF_SITE_PATH="/tmp/incubator-superset-site-${SUPERSET_VERSION}"
|
||||
|
||||
@@ -27,7 +27,7 @@ if [ -z "${SUPERSET_SVN_DEV_PATH}" ]; then
|
||||
fi
|
||||
|
||||
if [[ -n ${1} ]] && [[ ${1} == "local" ]]; then
|
||||
SUPERSET_RELEASE_RC=apache-superset-"${SUPERSET_VERSION_RC}"
|
||||
SUPERSET_RELEASE_RC=apache_superset-"${SUPERSET_VERSION_RC}"
|
||||
SUPERSET_RELEASE_RC_TARBALL="${SUPERSET_RELEASE_RC}"-source.tar.gz
|
||||
SUPERSET_TARBALL_PATH="${SUPERSET_SVN_DEV_PATH}"/${SUPERSET_VERSION_RC}/${SUPERSET_RELEASE_RC_TARBALL}
|
||||
SUPERSET_TMP_TARBALL_FILENAME=_tmp_"${SUPERSET_VERSION_RC}".tar.gz
|
||||
|
||||
@@ -38,7 +38,7 @@ get_pip_command() {
|
||||
PYTHON=$(get_python_command)
|
||||
PIP=$(get_pip_command)
|
||||
|
||||
# Get the release directory's path. If you unzip an Apache release and just run the npm script to validate the release, this will be a file name like `apache-superset-x.x.xrcx-source.tar.gz`
|
||||
# Get the release directory's path. If you unzip an Apache release and just run the npm script to validate the release, this will be a file name like `apache_superset-x.x.xrcx-source.tar.gz`
|
||||
RELEASE_ZIP_PATH="../../$(basename "$(dirname "$(pwd)")")-source.tar.gz"
|
||||
|
||||
# Install dependencies from requirements.txt if the file exists
|
||||
|
||||
@@ -114,6 +114,7 @@ Join our growing community!
|
||||
- [Ona](https://ona.io) [@pld]
|
||||
- [Orange](https://www.orange.com) [@icsu]
|
||||
- [Oslandia](https://oslandia.com)
|
||||
- [Oxylabs](https://oxylabs.io/) [@rytis-ulys]
|
||||
- [Peak AI](https://www.peak.ai/) [@azhar22k]
|
||||
- [PeopleDoc](https://www.people-doc.com) [@rodo]
|
||||
- [PlaidCloud](https://www.plaidcloud.com)
|
||||
@@ -136,6 +137,7 @@ Join our growing community!
|
||||
- [Virtuoso QA](https://www.virtuosoqa.com)
|
||||
- [Whale](https://whale.im)
|
||||
- [Windsor.ai](https://www.windsor.ai/) [@octaviancorlade]
|
||||
- [WinWin Network马上赢](https://brandct.cn/) [@wenbinye]
|
||||
- [Zeta](https://www.zeta.tech/) [@shaikidris]
|
||||
|
||||
### Media & Entertainment
|
||||
|
||||
@@ -33,12 +33,10 @@ assists people when migrating to a new version.
|
||||
- [31794](https://github.com/apache/superset/pull/31794) Removed the previously deprecated `DASHBOARD_CROSS_FILTERS` feature flag
|
||||
- [31774](https://github.com/apache/superset/pull/31774): Fixes the spelling of the `USE-ANALAGOUS-COLORS` feature flag. Please update any scripts/configuration item to use the new/corrected `USE-ANALOGOUS-COLORS` flag spelling.
|
||||
- [31582](https://github.com/apache/superset/pull/31582) Removed the legacy Area, Bar, Event Flow, Heatmap, Histogram, Line, Sankey, and Sankey Loop charts. They were all automatically migrated to their ECharts counterparts with the exception of the Event Flow and Sankey Loop charts which were removed as they were not actively maintained and not widely used. If you were using the Event Flow or Sankey Loop charts, you will need to find an alternative solution.
|
||||
- [31198](https://github.com/apache/superset/pull/31198) Disallows by default the use of the following ClickHouse functions: "version", "currentDatabase", "hostName".
|
||||
- [29798](https://github.com/apache/superset/pull/29798) Since 3.1.0, the intial schedule for an alert or report was mistakenly offset by the specified timezone's relation to UTC. The initial schedule should now begin at the correct time.
|
||||
- [30021](https://github.com/apache/superset/pull/30021) The `dev` layer in our Dockerfile no long includes firefox binaries, only Chromium to reduce bloat/docker-build-time.
|
||||
- [30099](https://github.com/apache/superset/pull/30099) Translations are no longer included in the default docker image builds. If your environment requires translations, you'll want to set the docker build arg `BUILD_TRANSACTION=true`.
|
||||
- [31262](https://github.com/apache/superset/pull/31262) NOTE: deprecated `pylint` in favor of `ruff` as our only python linter. Only affect development workflows positively (not the release itself). It should cover most important rules, be much faster, but some things linting rules that were enforced before may not be enforce in the exact same way as before.
|
||||
- [31173](https://github.com/apache/superset/pull/31173) Modified `fetch_csrf_token` to align with HTTP standards, particularly regarding how cookies are handled. If you encounter any issues related to CSRF functionality, please report them as a new issue and reference this PR for context.
|
||||
- [31413](https://github.com/apache/superset/pull/31413) Enable the DATE_FORMAT_IN_EMAIL_SUBJECT feature flag to allow users to specify a date format for the email subject, which will then be replaced with the actual date.
|
||||
- [31385](https://github.com/apache/superset/pull/31385) Significant docker refactor, reducing access levels for the `superset` user, streamlining layer building, ...
|
||||
- [31503](https://github.com/apache/superset/pull/31503) Deprecating python 3.9.x support, 3.11 is now the recommended version and 3.10 is still supported over the Superset 5.0 lifecycle.
|
||||
@@ -48,9 +46,15 @@ assists people when migrating to a new version.
|
||||
- [30284](https://github.com/apache/superset/pull/30284) Deprecated GLOBAL_ASYNC_QUERIES_REDIS_CONFIG in favor of the new GLOBAL_ASYNC_QUERIES_CACHE_BACKEND configuration. To leverage Redis Sentinel, set CACHE_TYPE to RedisSentinelCache, or use RedisCache for standalone Redis
|
||||
- [31961](https://github.com/apache/superset/pull/31961) Upgraded React from version 16.13.1 to 17.0.2. If you are using custom frontend extensions or plugins, you may need to update them to be compatible with React 17.
|
||||
- [31260](https://github.com/apache/superset/pull/31260) Docker images now use `uv pip install` instead of `pip install` to manage the python envrionment. Most docker-based deployments will be affected, whether you derive one of the published images, or have custom bootstrap script that install python libraries (drivers)
|
||||
- [32432](https://github.com/apache/superset/pull/31260) Moves the List Roles FAB view to the frontend and requires `FAB_ADD_SECURITY_API` to be enabled in the configuration and `superset init` to be executed.
|
||||
|
||||
### Potential Downtime
|
||||
|
||||
## 4.1.2
|
||||
|
||||
- [31198](https://github.com/apache/superset/pull/31198) Disallows by default the use of the following ClickHouse functions: "version", "currentDatabase", "hostName".
|
||||
- [31173](https://github.com/apache/superset/pull/31173) Modified `fetch_csrf_token` to align with HTTP standards, particularly regarding how cookies are handled. If you encounter any issues related to CSRF functionality, please report them as a new issue and reference this PR for context.
|
||||
|
||||
## 4.1.0
|
||||
|
||||
- [29274](https://github.com/apache/superset/pull/29274): We made it easier to trigger CI on your
|
||||
|
||||
@@ -62,7 +62,6 @@ MAPBOX_API_KEY=''
|
||||
|
||||
# Make sure you set this to a unique secure random value on production
|
||||
SUPERSET_SECRET_KEY=TEST_NON_DEV_SECRET
|
||||
|
||||
ENABLE_PLAYWRIGHT=false
|
||||
PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true
|
||||
BUILD_SUPERSET_FRONTEND_IN_DOCKER=true
|
||||
|
||||
@@ -72,7 +72,7 @@ are compatible with Superset.
|
||||
| [PostgreSQL](/docs/configuration/databases#postgres) | `pip install psycopg2` | `postgresql://<UserName>:<DBPassword>@<Database Host>/<Database Name>` |
|
||||
| [Presto](/docs/configuration/databases#presto) | `pip install pyhive` | `presto://{username}:{password}@{hostname}:{port}/{database}` |
|
||||
| [Rockset](/docs/configuration/databases#rockset) | `pip install rockset-sqlalchemy` | `rockset://<api_key>:@<api_server>` |
|
||||
| [SAP Hana](/docs/configuration/databases#hana) | `pip install hdbcli sqlalchemy-hana` or `pip install apache-superset[hana]` | `hana://{username}:{password}@{host}:{port}` |
|
||||
| [SAP Hana](/docs/configuration/databases#hana) | `pip install hdbcli sqlalchemy-hana` or `pip install apache_superset[hana]` | `hana://{username}:{password}@{host}:{port}` |
|
||||
| [StarRocks](/docs/configuration/databases#starrocks) | `pip install starrocks` | `starrocks://<User>:<Password>@<Host>:<Port>/<Catalog>.<Database>` |
|
||||
| [Snowflake](/docs/configuration/databases#snowflake) | `pip install snowflake-sqlalchemy` | `snowflake://{user}:{password}@{account}.{region}/{database}?role={role}&warehouse={warehouse}` |
|
||||
| SQLite | No additional library needed | `sqlite://path/to/file.db?check_same_thread=false` |
|
||||
|
||||
@@ -11,7 +11,7 @@ version: 1
|
||||
To configure CORS, or cross-origin resource sharing, the following dependency must be installed:
|
||||
|
||||
```python
|
||||
pip install apache-superset[cors]
|
||||
pip install apache_superset[cors]
|
||||
```
|
||||
|
||||
The following keys in `superset_config.py` can be specified to configure CORS:
|
||||
|
||||
@@ -220,6 +220,36 @@ cache key by adding the following parameter to your Jinja code:
|
||||
{{ current_user_email(add_to_cache_keys=False) }}
|
||||
```
|
||||
|
||||
**Current User Roles**
|
||||
|
||||
The `{{ current_user_roles() }}` macro returns an array of roles for the logged in user.
|
||||
|
||||
If you have caching enabled in your Superset configuration, then by default the roles value will be used
|
||||
by Superset when calculating the cache key. A cache key is a unique identifier that determines if there's a
|
||||
cache hit in the future and Superset can retrieve cached data.
|
||||
|
||||
You can disable the inclusion of the roles value in the calculation of the
|
||||
cache key by adding the following parameter to your Jinja code:
|
||||
|
||||
```python
|
||||
{{ current_user_roles(add_to_cache_keys=False) }}
|
||||
```
|
||||
|
||||
You can json-stringify the array by adding `|tojson` to your Jinja code:
|
||||
```python
|
||||
{{ current_user_roles()|tojson }}
|
||||
```
|
||||
|
||||
You can use the `|where_in` filter to use your roles in a SQL statement. For example, if `current_user_roles()` returns `['admin', 'viewer']`, the following template:
|
||||
```python
|
||||
SELECT * FROM users WHERE role IN {{ current_user_roles()|where_in }}
|
||||
```
|
||||
|
||||
Will be rendered as:
|
||||
```sql
|
||||
SELECT * FROM users WHERE role IN ('admin', 'viewer')
|
||||
```
|
||||
|
||||
**Custom URL Parameters**
|
||||
|
||||
The `{{ url_param('custom_variable') }}` macro lets you define arbitrary URL
|
||||
@@ -461,3 +491,37 @@ This macro avoids copy/paste, allowing users to centralize the metric definition
|
||||
|
||||
The `dataset_id` parameter is optional, and if not provided Superset will use the current dataset from context (for example, when using this macro in the Chart Builder, by default the `macro_key` will be searched in the dataset powering the chart).
|
||||
The parameter can be used in SQL Lab, or when fetching a metric from another dataset.
|
||||
|
||||
## Available Filters
|
||||
|
||||
Superset supports [builtin filters from the Jinja2 templating package](https://jinja.palletsprojects.com/en/stable/templates/#builtin-filters). Custom filters have also been implemented:
|
||||
|
||||
**Where In**
|
||||
Parses a list into a SQL-compatible statement. This is useful with macros that return an array (for example the `filter_values` macro):
|
||||
|
||||
```
|
||||
Dashboard filter with "First", "Second" and "Third" options selected
|
||||
{{ filter_values('column') }} => ["First", "Second", "Third"]
|
||||
{{ filter_values('column')|where_in }} => ('First', 'Second', 'Third')
|
||||
```
|
||||
|
||||
By default, this filter returns `()` (as a string) in case the value is null. The `default_to_none` parameter can be se to `True` to return null in this case:
|
||||
|
||||
```
|
||||
Dashboard filter without any value applied
|
||||
{{ filter_values('column') }} => ()
|
||||
{{ filter_values('column')|where_in(default_to_none=True) }} => None
|
||||
```
|
||||
|
||||
**To Datetime**
|
||||
|
||||
Loads a string as a `datetime` object. This is useful when performing date operations. For example:
|
||||
```
|
||||
{% set from_expr = get_time_filter("dttm", strftime="%Y-%m-%d").from_expr %}
|
||||
{% set to_expr = get_time_filter("dttm", strftime="%Y-%m-%d").to_expr %}
|
||||
{% if (to_expr|to_datetime(format="%Y-%m-%d") - from_expr|to_datetime(format="%Y-%m-%d")).days > 100 %}
|
||||
do something
|
||||
{% else %}
|
||||
do something else
|
||||
{% endif %}
|
||||
```
|
||||
|
||||
@@ -26,9 +26,9 @@ More references:
|
||||
Here's a list of repositories that contain Superset-related packages:
|
||||
|
||||
- [apache/superset](https://github.com/apache/superset)
|
||||
is the main repository containing the `apache-superset` Python package
|
||||
is the main repository containing the `apache_superset` Python package
|
||||
distributed on
|
||||
[pypi](https://pypi.org/project/apache-superset/). This repository
|
||||
[pypi](https://pypi.org/project/apache_superset/). This repository
|
||||
also includes Superset's main TypeScript/JavaScript bundles and react apps under
|
||||
the [superset-frontend](https://github.com/apache/superset/tree/master/superset-frontend)
|
||||
folder.
|
||||
|
||||
@@ -12,7 +12,7 @@ import useBaseUrl from "@docusaurus/useBaseUrl";
|
||||
<img src={useBaseUrl("/img/pypi.png" )} width="150" />
|
||||
<br /><br />
|
||||
|
||||
This page describes how to install Superset using the `apache-superset` package [published on PyPI](https://pypi.org/project/apache-superset/).
|
||||
This page describes how to install Superset using the `apache_superset` package [published on PyPI](https://pypi.org/project/apache_superset/).
|
||||
|
||||
## OS Dependencies
|
||||
|
||||
@@ -124,10 +124,10 @@ command line.
|
||||
|
||||
### Installing and Initializing Superset
|
||||
|
||||
First, start by installing `apache-superset`:
|
||||
First, start by installing `apache_superset`:
|
||||
|
||||
```bash
|
||||
pip install apache-superset
|
||||
pip install apache_superset
|
||||
```
|
||||
|
||||
Then, define mandatory configurations, SECRET_KEY and FLASK_APP:
|
||||
|
||||
@@ -32,7 +32,7 @@ docker compose up
|
||||
To upgrade superset in a native installation, run the following commands:
|
||||
|
||||
```bash
|
||||
pip install apache-superset --upgrade
|
||||
pip install apache_superset --upgrade
|
||||
```
|
||||
|
||||
## Upgrading the Metadata Database
|
||||
|
||||
@@ -280,6 +280,49 @@ TALISMAN_CONFIG = {
|
||||
"content_security_policy": { ...
|
||||
```
|
||||
|
||||
#### Configuring Talisman in Superset
|
||||
|
||||
Talisman settings in Superset can be modified using superset_config.py. If you need to adjust security policies, you can override the default configuration.
|
||||
|
||||
Example: Overriding Talisman Configuration in superset_config.py for loading images form s3 or other external sources.
|
||||
|
||||
```python
|
||||
TALISMAN_CONFIG = {
|
||||
"content_security_policy": {
|
||||
"base-uri": ["'self'"],
|
||||
"default-src": ["'self'"],
|
||||
"img-src": [
|
||||
"'self'",
|
||||
"blob:",
|
||||
"data:",
|
||||
"https://apachesuperset.gateway.scarf.sh",
|
||||
"https://static.scarf.sh/",
|
||||
# "https://cdn.brandfolder.io", # Uncomment when SLACK_ENABLE_AVATARS is True # noqa: E501
|
||||
"ows.terrestris.de",
|
||||
"aws.s3.com", # Add Your Bucket or external data source
|
||||
],
|
||||
"worker-src": ["'self'", "blob:"],
|
||||
"connect-src": [
|
||||
"'self'",
|
||||
"https://api.mapbox.com",
|
||||
"https://events.mapbox.com",
|
||||
],
|
||||
"object-src": "'none'",
|
||||
"style-src": [
|
||||
"'self'",
|
||||
"'unsafe-inline'",
|
||||
],
|
||||
"script-src": ["'self'", "'strict-dynamic'"],
|
||||
},
|
||||
"content_security_policy_nonce_in": ["script-src"],
|
||||
"force_https": False,
|
||||
"session_cookie_secure": False,
|
||||
}
|
||||
```
|
||||
|
||||
# For more information on setting up Talisman, please refer to
|
||||
https://superset.apache.org/docs/configuration/networking-settings/#changing-flask-talisman-csp
|
||||
|
||||
### Reporting Security Vulnerabilities
|
||||
|
||||
Apache Software Foundation takes a rigorous standpoint in annihilating the security issues in its
|
||||
|
||||
@@ -12,8 +12,12 @@ import useBaseUrl from "@docusaurus/useBaseUrl";
|
||||
This section is focused on documentation for end-users who will be using Superset
|
||||
for the data analysis and exploration workflow
|
||||
(data analysts, business analysts, data
|
||||
scientists, etc). In addition to this site, [Preset.io](http://preset.io/) maintains an updated set of end-user
|
||||
scientists, etc).
|
||||
|
||||
:::tip
|
||||
In addition to this site, [Preset.io](http://preset.io/) maintains an updated set of end-user
|
||||
documentation at [docs.preset.io](https://docs.preset.io/).
|
||||
:::
|
||||
|
||||
This tutorial targets someone who wants to create charts and dashboards in Superset. We’ll show you
|
||||
how to connect Superset to a new database and configure a table in that database for analysis.
|
||||
@@ -175,23 +179,36 @@ into a position you like onto the underlying grid.
|
||||
|
||||
Congrats! You’ve successfully linked, analyzed, and visualized data in Superset. There are a wealth
|
||||
of other table configuration and visualization options, so please start exploring and creating
|
||||
slices and dashboards of your own
|
||||
|
||||
ֿ
|
||||
slices and dashboards of your own.
|
||||
|
||||
### Manage access to Dashboards
|
||||
|
||||
Access to dashboards is managed via owners (users that have edit permissions to the dashboard)
|
||||
Access to dashboards is managed via owners (users that have edit permissions to the dashboard).
|
||||
|
||||
Non-owner users access can be managed two different ways:
|
||||
Non-owner users access can be managed in two different ways. The dashboard needs to be published to be visible to other users.
|
||||
|
||||
1. Dataset permissions - if you add to the relevant role permissions to datasets it automatically grants implicit access to all dashboards that uses those permitted datasets
|
||||
2. Dashboard roles - if you enable **DASHBOARD_RBAC** [feature flag](/docs/configuration/configuring-superset#feature-flags) then you be able to manage which roles can access the dashboard
|
||||
1. Dataset permissions - if you add to the relevant role permissions to datasets it automatically grants implicit access to all dashboards that uses those permitted datasets.
|
||||
2. Dashboard roles - if you enable [**DASHBOARD_RBAC** feature flag](/docs/configuration/configuring-superset#feature-flags) then you will be able to manage which roles can access the dashboard
|
||||
- Granting a role access to a dashboard will bypass dataset level checks. Having dashboard access implicitly grants read access to all the featured charts in the dashboard, and thereby also all the associated datasets.
|
||||
- If no roles are specified for a dashboard, regular **Dataset permissions** will apply.
|
||||
|
||||
<img src={useBaseUrl("/img/tutorial/tutorial_dashboard_access.png" )} />
|
||||
|
||||
### Publishing a Dashboard
|
||||
|
||||
If you would like to make your dashboard available to other users, click on the `Draft` button next to the
|
||||
title of your dashboard.
|
||||
|
||||
<img src={useBaseUrl("/img/tutorial/publish_button_dashboard.png" )} />
|
||||
|
||||
:::warning
|
||||
Draft dashboards are only visible to the dashboard owners and admins. Published dashboards are visible to all users with access to the underlying datasets or if RBAC is enabled, to the roles that have been granted access to the dashboard.
|
||||
:::
|
||||
|
||||
### Mark a Dashboard as Favorite
|
||||
|
||||
You can mark a dashboard as a favorite by clicking on the star icon next to the title of your dashboard. This makes it easier to find it in the list of dashboards or on the home page.
|
||||
|
||||
### Customizing dashboard
|
||||
|
||||
The following URL parameters can be used to modify how the dashboard is rendered:
|
||||
|
||||
@@ -339,20 +339,19 @@ const config: Config = {
|
||||
async: true,
|
||||
'data-website-id': 'c6a8a8b8-3127-48f9-97a7-51e9e10d20d0',
|
||||
'data-project-name': 'Apache Superset',
|
||||
'data-project-color': '#1AA1C2',
|
||||
'data-project-color': '#FFFFFF',
|
||||
'data-project-logo':
|
||||
'https://images.seeklogo.com/logo-png/50/2/superset-icon-logo-png_seeklogo-500354.png',
|
||||
'data-modal-override-open-id': 'ask-ai-input',
|
||||
'data-modal-override-open-class': 'search-input',
|
||||
'data-modal-open-by-default': 'true',
|
||||
'data-modal-disclaimer':
|
||||
'This is a custom LLM for Apache Superset with access to all [documentation](superset.apache.org/docs/intro/), [GitHub Open Issues, PRs and READMEs](github.com/apache/superset). Companies deploy assistants like this ([built by kapa.ai](https://kapa.ai)) on docs via [website widget](https://docs.kapa.ai/integrations/website-widget) (Docker, Reddit), in [support forms](https://docs.kapa.ai/integrations/support-form-deflector) for ticket deflection (Monday.com, Mapbox), or as [Slack bots](https://docs.kapa.ai/integrations/slack-bot) with private sources.',
|
||||
'data-modal-example-questions':
|
||||
'How do I use Docker Compose?,How to run Supersets on kubernetes?',
|
||||
'data-button-text-color': '#FFFFFF',
|
||||
'data-modal-header-bg-color': '#1AA1C2',
|
||||
'data-modal-title-color': '#FFFFFF',
|
||||
'data-modal-title': 'Superset Ask AI',
|
||||
'How do I install Superset?,How can I contribute to Superset?',
|
||||
'data-button-text-color': 'rgb(81,166,197)',
|
||||
'data-modal-header-bg-color': '#ffffff',
|
||||
'data-modal-title-color': 'rgb(81,166,197)',
|
||||
'data-modal-title': 'Apache Superset AI',
|
||||
'data-modal-disclaimer-text-color': '#000000',
|
||||
'data-consent-required': 'true',
|
||||
'data-consent-screen-disclaimer':
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
"@emotion/styled": "^10.0.27",
|
||||
"@saucelabs/theme-github-codeblock": "^0.3.0",
|
||||
"@superset-ui/style": "^0.14.23",
|
||||
"antd": "^5.24.2",
|
||||
"antd": "^5.24.5",
|
||||
"docusaurus-plugin-less": "^2.0.2",
|
||||
"less": "^4.2.2",
|
||||
"less-loader": "^11.0.0",
|
||||
@@ -34,7 +34,7 @@
|
||||
"react-dom": "^18.3.1",
|
||||
"react-github-btn": "^1.4.0",
|
||||
"react-svg-pan-zoom": "^3.13.1",
|
||||
"swagger-ui-react": "^5.20.0"
|
||||
"swagger-ui-react": "^5.20.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@docusaurus/module-type-aliases": "^3.7.0",
|
||||
@@ -43,7 +43,7 @@
|
||||
"@typescript-eslint/eslint-plugin": "^5.0.0",
|
||||
"@typescript-eslint/parser": "^5.0.0",
|
||||
"eslint": "^8.0.0",
|
||||
"eslint-config-prettier": "^10.0.2",
|
||||
"eslint-config-prettier": "^10.1.1",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"eslint-plugin-react": "^7.0.0",
|
||||
"prettier": "^2.0.0",
|
||||
|
||||
@@ -58,7 +58,6 @@ ul.dropdown__menu svg {
|
||||
--ifm-code-font-size: 95%;
|
||||
--ifm-menu-link-padding-vertical: 12px;
|
||||
--doc-sidebar-width: 350px !important;
|
||||
--ifm-navbar-height: none;
|
||||
--ifm-font-family-base: Roboto;
|
||||
--ifm-footer-background-color: #173036;
|
||||
--ifm-footer-color: #87939a;
|
||||
|
||||
2
docs/static/.htaccess
vendored
2
docs/static/.htaccess
vendored
@@ -22,7 +22,7 @@ RewriteRule ^(.*)$ https://superset.apache.org/$1 [R,L]
|
||||
RewriteCond %{HTTP_HOST} ^superset.incubator.apache.org$ [NC]
|
||||
RewriteRule ^(.*)$ https://superset.apache.org/$1 [R=301,L]
|
||||
|
||||
Header set Content-Security-Policy "default-src data: blob: 'self' *.apache.org *.githubusercontent.com *.scarf.sh *.googleapis.com *.github.com *.algolia.net *.algolianet.com 'unsafe-inline' 'unsafe-eval'; frame-src *; frame-ancestors 'self' *.google.com https://sidebar.bugherd.com; form-action 'self'; worker-src blob:; img-src 'self' blob: data: https:; font-src 'self'; object-src 'none'"
|
||||
Header set Content-Security-Policy "default-src data: blob: 'self' *.apache.org widget.kapa.ai *.githubusercontent.com *.scarf.sh *.googleapis.com *.google.com *.run.app *.gstatic.com *.github.com *.algolia.net *.algolianet.com 'unsafe-inline' 'unsafe-eval'; frame-src *; frame-ancestors 'self' *.google.com https://sidebar.bugherd.com; form-action 'self'; worker-src blob:; img-src 'self' blob: data: https:; font-src 'self'; object-src 'none'"
|
||||
|
||||
# REDIRECTS
|
||||
|
||||
|
||||
BIN
docs/static/img/tutorial/publish_button_dashboard.png
vendored
Normal file
BIN
docs/static/img/tutorial/publish_button_dashboard.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 84 KiB |
2
docs/static/resources/openapi.json
vendored
2
docs/static/resources/openapi.json
vendored
@@ -18736,7 +18736,7 @@
|
||||
{
|
||||
"description": "Table name",
|
||||
"in": "query",
|
||||
"name": "table",
|
||||
"name": "name",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
|
||||
457
docs/yarn.lock
457
docs/yarn.lock
@@ -1366,10 +1366,10 @@
|
||||
resolved "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz"
|
||||
integrity sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==
|
||||
|
||||
"@babel/runtime-corejs3@^7.20.7", "@babel/runtime-corejs3@^7.22.15", "@babel/runtime-corejs3@^7.22.6", "@babel/runtime-corejs3@^7.26.7":
|
||||
version "7.26.10"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.26.10.tgz#5a3185ca2813f8de8ae68622572086edf5cf51f2"
|
||||
integrity sha512-uITFQYO68pMEYR46AHgQoyBg7KPPJDAbGn4jUTIRgCFJIp88MIBUianVOplhZDEec07bp9zIyr4Kp0FCyQzmWg==
|
||||
"@babel/runtime-corejs3@^7.20.7", "@babel/runtime-corejs3@^7.22.15", "@babel/runtime-corejs3@^7.22.6", "@babel/runtime-corejs3@^7.26.10":
|
||||
version "7.27.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.27.0.tgz#c766df350ec7a2caf3ed64e3659b100954589413"
|
||||
integrity sha512-UWjX6t+v+0ckwZ50Y5ShZLnlk95pP5MyW/pon9tiYzl3+18pkTHTFNTKr7rQbfRXPkowt2QAn30o1b6oswszew==
|
||||
dependencies:
|
||||
core-js-pure "^3.30.2"
|
||||
regenerator-runtime "^0.14.0"
|
||||
@@ -2491,7 +2491,34 @@
|
||||
ramda-adjunct "^5.0.0"
|
||||
unraw "^3.0.0"
|
||||
|
||||
"@swagger-api/apidom-core@>=1.0.0-beta.12 <1.0.0-rc.0", "@swagger-api/apidom-core@^1.0.0-beta.12", "@swagger-api/apidom-core@^1.0.0-beta.3":
|
||||
"@swagger-api/apidom-ast@^1.0.0-beta.30":
|
||||
version "1.0.0-beta.30"
|
||||
resolved "https://registry.yarnpkg.com/@swagger-api/apidom-ast/-/apidom-ast-1.0.0-beta.30.tgz#88c25259a4a0b8fd9fa2106634089a927fd1d2d9"
|
||||
integrity sha512-5Wj3zdt0dxS9ERVk4qSuqDIsMQ8dP2vop8b494OpJ/O2W261yCV39Z+vN+PqeJ2NiKDRMlJ+QoQ1uVfKwEo8Kg==
|
||||
dependencies:
|
||||
"@babel/runtime-corejs3" "^7.26.10"
|
||||
"@swagger-api/apidom-error" "^1.0.0-beta.30"
|
||||
"@types/ramda" "~0.30.0"
|
||||
ramda "~0.30.0"
|
||||
ramda-adjunct "^5.0.0"
|
||||
unraw "^3.0.0"
|
||||
|
||||
"@swagger-api/apidom-core@>=1.0.0-beta.13 <1.0.0-rc.0", "@swagger-api/apidom-core@^1.0.0-beta.30":
|
||||
version "1.0.0-beta.30"
|
||||
resolved "https://registry.yarnpkg.com/@swagger-api/apidom-core/-/apidom-core-1.0.0-beta.30.tgz#e0f52d343c109304878e5bf119a9fc297f5a09dc"
|
||||
integrity sha512-pDnUhXIKKUvmeezQfwKLL05rkOH1L7ueiy5ja5ob9y2w4r+HXDID7qHtDGeRxKZoIt4E3Sd1K37OjcE9fNcknQ==
|
||||
dependencies:
|
||||
"@babel/runtime-corejs3" "^7.26.10"
|
||||
"@swagger-api/apidom-ast" "^1.0.0-beta.30"
|
||||
"@swagger-api/apidom-error" "^1.0.0-beta.30"
|
||||
"@types/ramda" "~0.30.0"
|
||||
minim "~0.23.8"
|
||||
ramda "~0.30.0"
|
||||
ramda-adjunct "^5.0.0"
|
||||
short-unique-id "^5.0.2"
|
||||
ts-mixer "^6.0.3"
|
||||
|
||||
"@swagger-api/apidom-core@^1.0.0-beta.12", "@swagger-api/apidom-core@^1.0.0-beta.3":
|
||||
version "1.0.0-beta.12"
|
||||
resolved "https://registry.npmjs.org/@swagger-api/apidom-core/-/apidom-core-1.0.0-beta.12.tgz"
|
||||
integrity sha512-CAr6aSk9l9ZJUneHpmwk4Br0NZhFLy2QRHoPmr2pWMlAn+0YC4eRYtwOEB8PVsCmP83D4MiXU5zi6cOZyV/cVw==
|
||||
@@ -2506,14 +2533,33 @@
|
||||
short-unique-id "^5.0.2"
|
||||
ts-mixer "^6.0.3"
|
||||
|
||||
"@swagger-api/apidom-error@>=1.0.0-beta.12 <1.0.0-rc.0", "@swagger-api/apidom-error@^1.0.0-beta.12", "@swagger-api/apidom-error@^1.0.0-beta.3", "@swagger-api/apidom-error@^1.0.0-beta.3 <1.0.0-rc.0":
|
||||
"@swagger-api/apidom-error@>=1.0.0-beta.13 <1.0.0-rc.0", "@swagger-api/apidom-error@^1.0.0-beta.30":
|
||||
version "1.0.0-beta.30"
|
||||
resolved "https://registry.yarnpkg.com/@swagger-api/apidom-error/-/apidom-error-1.0.0-beta.30.tgz#97fdc0eedc9cb28f8f76b29933b7e0b8f784740e"
|
||||
integrity sha512-hVDx0kUF1DTyaEXwmsF3wpJClEfnH0pxjEubqtvHpjjeTMgZzmKc5azbYtvgBX3uUpGHyQZyG/O9g94/wIhhMA==
|
||||
dependencies:
|
||||
"@babel/runtime-corejs3" "^7.20.7"
|
||||
|
||||
"@swagger-api/apidom-error@^1.0.0-beta.12", "@swagger-api/apidom-error@^1.0.0-beta.3", "@swagger-api/apidom-error@^1.0.0-beta.3 <1.0.0-rc.0":
|
||||
version "1.0.0-beta.12"
|
||||
resolved "https://registry.npmjs.org/@swagger-api/apidom-error/-/apidom-error-1.0.0-beta.12.tgz"
|
||||
integrity sha512-p74a/8GgitGIYvjD5WmROEHv2bGCnDKug3QpJvC5+g36ErZQp428+fK5hhfKQuCo0rjD2fZvs27S17Zh8y0zFw==
|
||||
dependencies:
|
||||
"@babel/runtime-corejs3" "^7.20.7"
|
||||
|
||||
"@swagger-api/apidom-json-pointer@>=1.0.0-beta.12 <1.0.0-rc.0", "@swagger-api/apidom-json-pointer@^1.0.0-beta.12", "@swagger-api/apidom-json-pointer@^1.0.0-beta.3 <1.0.0-rc.0":
|
||||
"@swagger-api/apidom-json-pointer@>=1.0.0-beta.13 <1.0.0-rc.0", "@swagger-api/apidom-json-pointer@^1.0.0-beta.30":
|
||||
version "1.0.0-beta.30"
|
||||
resolved "https://registry.yarnpkg.com/@swagger-api/apidom-json-pointer/-/apidom-json-pointer-1.0.0-beta.30.tgz#7dc9d17190924bd848661961b85569e854cffdee"
|
||||
integrity sha512-G+BDNXU/ARJCbJiFq1A6dh6pNDDp1J0jPfKeIHjsD8aZoRdpJC0F3F7onm8TjQm2cnvAi4B7vPOKzjWrYN1VWw==
|
||||
dependencies:
|
||||
"@babel/runtime-corejs3" "^7.26.10"
|
||||
"@swagger-api/apidom-core" "^1.0.0-beta.30"
|
||||
"@swagger-api/apidom-error" "^1.0.0-beta.30"
|
||||
"@types/ramda" "~0.30.0"
|
||||
ramda "~0.30.0"
|
||||
ramda-adjunct "^5.0.0"
|
||||
|
||||
"@swagger-api/apidom-json-pointer@^1.0.0-beta.12", "@swagger-api/apidom-json-pointer@^1.0.0-beta.3 <1.0.0-rc.0":
|
||||
version "1.0.0-beta.12"
|
||||
resolved "https://registry.npmjs.org/@swagger-api/apidom-json-pointer/-/apidom-json-pointer-1.0.0-beta.12.tgz"
|
||||
integrity sha512-JuCqMVfDSWJ7JcdPjYgGjNlqjmKQwxuQh7uKKBLTpNccmXYT+x7WemPuzcWjVVHDd5plw8yQ0YvaU0HlqjS1mA==
|
||||
@@ -2539,6 +2585,19 @@
|
||||
ramda-adjunct "^5.0.0"
|
||||
ts-mixer "^6.0.3"
|
||||
|
||||
"@swagger-api/apidom-ns-arazzo-1@^1.0.0-beta.3 <1.0.0-rc.0", "@swagger-api/apidom-ns-arazzo-1@^1.0.0-beta.30":
|
||||
version "1.0.0-beta.30"
|
||||
resolved "https://registry.yarnpkg.com/@swagger-api/apidom-ns-arazzo-1/-/apidom-ns-arazzo-1-1.0.0-beta.30.tgz#3f2f8a9ed5d2c8c10157981231afd6032e20b6b9"
|
||||
integrity sha512-HpszcpuDlSOXWruHzasR64L8640VHVDuy8xXJrhx1iBu+gDHriOM8gbh8jQgWST91H0smtPeTG9WV1/h6frhRw==
|
||||
dependencies:
|
||||
"@babel/runtime-corejs3" "^7.26.10"
|
||||
"@swagger-api/apidom-core" "^1.0.0-beta.30"
|
||||
"@swagger-api/apidom-ns-json-schema-2020-12" "^1.0.0-beta.30"
|
||||
"@types/ramda" "~0.30.0"
|
||||
ramda "~0.30.0"
|
||||
ramda-adjunct "^5.0.0"
|
||||
ts-mixer "^6.0.3"
|
||||
|
||||
"@swagger-api/apidom-ns-asyncapi-2@^1.0.0-beta.3", "@swagger-api/apidom-ns-asyncapi-2@^1.0.0-beta.3 <1.0.0-rc.0":
|
||||
version "1.0.0-beta.3"
|
||||
resolved "https://registry.npmjs.org/@swagger-api/apidom-ns-asyncapi-2/-/apidom-ns-asyncapi-2-1.0.0-beta.3.tgz"
|
||||
@@ -2566,6 +2625,20 @@
|
||||
ramda-adjunct "^5.0.0"
|
||||
ts-mixer "^6.0.4"
|
||||
|
||||
"@swagger-api/apidom-ns-json-schema-2019-09@^1.0.0-beta.30":
|
||||
version "1.0.0-beta.30"
|
||||
resolved "https://registry.yarnpkg.com/@swagger-api/apidom-ns-json-schema-2019-09/-/apidom-ns-json-schema-2019-09-1.0.0-beta.30.tgz#2467cc1d780f7a20442b8892d77dd9a25147031c"
|
||||
integrity sha512-HZL76SJaUDmL1GuFcev23UX1vVuxSHIED3vvKso+k3KWNfVWZJrr7GX1ELJx84fWW8g3b5S5+nyz5q1ApT084A==
|
||||
dependencies:
|
||||
"@babel/runtime-corejs3" "^7.26.10"
|
||||
"@swagger-api/apidom-core" "^1.0.0-beta.30"
|
||||
"@swagger-api/apidom-error" "^1.0.0-beta.30"
|
||||
"@swagger-api/apidom-ns-json-schema-draft-7" "^1.0.0-beta.30"
|
||||
"@types/ramda" "~0.30.0"
|
||||
ramda "~0.30.0"
|
||||
ramda-adjunct "^5.0.0"
|
||||
ts-mixer "^6.0.4"
|
||||
|
||||
"@swagger-api/apidom-ns-json-schema-2020-12@^1.0.0-beta.12":
|
||||
version "1.0.0-beta.12"
|
||||
resolved "https://registry.npmjs.org/@swagger-api/apidom-ns-json-schema-2020-12/-/apidom-ns-json-schema-2020-12-1.0.0-beta.12.tgz"
|
||||
@@ -2580,6 +2653,20 @@
|
||||
ramda-adjunct "^5.0.0"
|
||||
ts-mixer "^6.0.4"
|
||||
|
||||
"@swagger-api/apidom-ns-json-schema-2020-12@^1.0.0-beta.30":
|
||||
version "1.0.0-beta.30"
|
||||
resolved "https://registry.yarnpkg.com/@swagger-api/apidom-ns-json-schema-2020-12/-/apidom-ns-json-schema-2020-12-1.0.0-beta.30.tgz#7247885d81a7639b695687d1912cb1c66ea5897c"
|
||||
integrity sha512-D2adAcu/ISoBe0zRbcX0HyaDvWoMhmaL8iPR4pvjLY7soB2tCR4uLEzAkqPa2zaOKBRA2ziF74aNKrKbM5sX8w==
|
||||
dependencies:
|
||||
"@babel/runtime-corejs3" "^7.26.10"
|
||||
"@swagger-api/apidom-core" "^1.0.0-beta.30"
|
||||
"@swagger-api/apidom-error" "^1.0.0-beta.30"
|
||||
"@swagger-api/apidom-ns-json-schema-2019-09" "^1.0.0-beta.30"
|
||||
"@types/ramda" "~0.30.0"
|
||||
ramda "~0.30.0"
|
||||
ramda-adjunct "^5.0.0"
|
||||
ts-mixer "^6.0.4"
|
||||
|
||||
"@swagger-api/apidom-ns-json-schema-draft-4@^1.0.0-beta.12", "@swagger-api/apidom-ns-json-schema-draft-4@^1.0.0-beta.3":
|
||||
version "1.0.0-beta.12"
|
||||
resolved "https://registry.npmjs.org/@swagger-api/apidom-ns-json-schema-draft-4/-/apidom-ns-json-schema-draft-4-1.0.0-beta.12.tgz"
|
||||
@@ -2593,6 +2680,19 @@
|
||||
ramda-adjunct "^5.0.0"
|
||||
ts-mixer "^6.0.4"
|
||||
|
||||
"@swagger-api/apidom-ns-json-schema-draft-4@^1.0.0-beta.30":
|
||||
version "1.0.0-beta.30"
|
||||
resolved "https://registry.yarnpkg.com/@swagger-api/apidom-ns-json-schema-draft-4/-/apidom-ns-json-schema-draft-4-1.0.0-beta.30.tgz#c87a9d2c92236098e78948594fdf3b24d1f77d07"
|
||||
integrity sha512-u5YMIw/g74Z59wPBFS2A2LaheC+EEqRcbpUQOApTvb6zjW+xWxbCuKV1ypzIaVDDPIry8e3mpwjjXLj1mvad5w==
|
||||
dependencies:
|
||||
"@babel/runtime-corejs3" "^7.26.10"
|
||||
"@swagger-api/apidom-ast" "^1.0.0-beta.30"
|
||||
"@swagger-api/apidom-core" "^1.0.0-beta.30"
|
||||
"@types/ramda" "~0.30.0"
|
||||
ramda "~0.30.0"
|
||||
ramda-adjunct "^5.0.0"
|
||||
ts-mixer "^6.0.4"
|
||||
|
||||
"@swagger-api/apidom-ns-json-schema-draft-6@^1.0.0-beta.12":
|
||||
version "1.0.0-beta.12"
|
||||
resolved "https://registry.npmjs.org/@swagger-api/apidom-ns-json-schema-draft-6/-/apidom-ns-json-schema-draft-6-1.0.0-beta.12.tgz"
|
||||
@@ -2607,6 +2707,20 @@
|
||||
ramda-adjunct "^5.0.0"
|
||||
ts-mixer "^6.0.4"
|
||||
|
||||
"@swagger-api/apidom-ns-json-schema-draft-6@^1.0.0-beta.30":
|
||||
version "1.0.0-beta.30"
|
||||
resolved "https://registry.yarnpkg.com/@swagger-api/apidom-ns-json-schema-draft-6/-/apidom-ns-json-schema-draft-6-1.0.0-beta.30.tgz#980bce110261b9554bdea19bf3ac01d0e1d43c07"
|
||||
integrity sha512-/Mp11+tBKTN6XnpOiQo/cKnqmvfJhdCniHCK6Bg8wpCI3dMi+nSSpIYgWEPVQfNsLtf/PaYegrtYY56W4UzNRw==
|
||||
dependencies:
|
||||
"@babel/runtime-corejs3" "^7.26.10"
|
||||
"@swagger-api/apidom-core" "^1.0.0-beta.30"
|
||||
"@swagger-api/apidom-error" "^1.0.0-beta.30"
|
||||
"@swagger-api/apidom-ns-json-schema-draft-4" "^1.0.0-beta.30"
|
||||
"@types/ramda" "~0.30.0"
|
||||
ramda "~0.30.0"
|
||||
ramda-adjunct "^5.0.0"
|
||||
ts-mixer "^6.0.4"
|
||||
|
||||
"@swagger-api/apidom-ns-json-schema-draft-7@^1.0.0-beta.12", "@swagger-api/apidom-ns-json-schema-draft-7@^1.0.0-beta.3":
|
||||
version "1.0.0-beta.12"
|
||||
resolved "https://registry.npmjs.org/@swagger-api/apidom-ns-json-schema-draft-7/-/apidom-ns-json-schema-draft-7-1.0.0-beta.12.tgz"
|
||||
@@ -2621,6 +2735,20 @@
|
||||
ramda-adjunct "^5.0.0"
|
||||
ts-mixer "^6.0.4"
|
||||
|
||||
"@swagger-api/apidom-ns-json-schema-draft-7@^1.0.0-beta.30":
|
||||
version "1.0.0-beta.30"
|
||||
resolved "https://registry.yarnpkg.com/@swagger-api/apidom-ns-json-schema-draft-7/-/apidom-ns-json-schema-draft-7-1.0.0-beta.30.tgz#a1a665ff33f71679085f60ea444b46c257b2650e"
|
||||
integrity sha512-6sZ0LLYnEz9KXtt9xTRSc0EORBl5Fj3LUbfabUjqLQZGldsJWU+3TTQ4XtzFFHlan7z2WYyALKP7iP+b60XbPg==
|
||||
dependencies:
|
||||
"@babel/runtime-corejs3" "^7.26.10"
|
||||
"@swagger-api/apidom-core" "^1.0.0-beta.30"
|
||||
"@swagger-api/apidom-error" "^1.0.0-beta.30"
|
||||
"@swagger-api/apidom-ns-json-schema-draft-6" "^1.0.0-beta.30"
|
||||
"@types/ramda" "~0.30.0"
|
||||
ramda "~0.30.0"
|
||||
ramda-adjunct "^5.0.0"
|
||||
ts-mixer "^6.0.4"
|
||||
|
||||
"@swagger-api/apidom-ns-openapi-2@^1.0.0-beta.3", "@swagger-api/apidom-ns-openapi-2@^1.0.0-beta.3 <1.0.0-rc.0":
|
||||
version "1.0.0-beta.3"
|
||||
resolved "https://registry.npmjs.org/@swagger-api/apidom-ns-openapi-2/-/apidom-ns-openapi-2-1.0.0-beta.3.tgz"
|
||||
@@ -2649,7 +2777,37 @@
|
||||
ramda-adjunct "^5.0.0"
|
||||
ts-mixer "^6.0.3"
|
||||
|
||||
"@swagger-api/apidom-ns-openapi-3-1@>=1.0.0-beta.12 <1.0.0-rc.0", "@swagger-api/apidom-ns-openapi-3-1@^1.0.0-beta.3", "@swagger-api/apidom-ns-openapi-3-1@^1.0.0-beta.3 <1.0.0-rc.0":
|
||||
"@swagger-api/apidom-ns-openapi-3-0@^1.0.0-beta.30":
|
||||
version "1.0.0-beta.30"
|
||||
resolved "https://registry.yarnpkg.com/@swagger-api/apidom-ns-openapi-3-0/-/apidom-ns-openapi-3-0-1.0.0-beta.30.tgz#611709a24279435a9cf8f98552b6fba3991da031"
|
||||
integrity sha512-7bz6kCgjStTKGGI4wBP2ho574lyfjH5EDPPuXhkwmAG2mOn9MZezlQhsbdo3B+vbi/58mqQb2XCoB4aeP1F+GQ==
|
||||
dependencies:
|
||||
"@babel/runtime-corejs3" "^7.26.10"
|
||||
"@swagger-api/apidom-core" "^1.0.0-beta.30"
|
||||
"@swagger-api/apidom-error" "^1.0.0-beta.30"
|
||||
"@swagger-api/apidom-ns-json-schema-draft-4" "^1.0.0-beta.30"
|
||||
"@types/ramda" "~0.30.0"
|
||||
ramda "~0.30.0"
|
||||
ramda-adjunct "^5.0.0"
|
||||
ts-mixer "^6.0.3"
|
||||
|
||||
"@swagger-api/apidom-ns-openapi-3-1@>=1.0.0-beta.13 <1.0.0-rc.0":
|
||||
version "1.0.0-beta.30"
|
||||
resolved "https://registry.yarnpkg.com/@swagger-api/apidom-ns-openapi-3-1/-/apidom-ns-openapi-3-1-1.0.0-beta.30.tgz#a43fe94c57ec576c8b4a5ebeb7c2a35683ebf84b"
|
||||
integrity sha512-pq2jxSp0I6xnGzyAiEXWYMuurp8H7TlOQ6Ijr/XX54gNmaIK+yQ3HXc7S6FZx+B2kQx03Tb8Y8O7L7J7YnmFiA==
|
||||
dependencies:
|
||||
"@babel/runtime-corejs3" "^7.26.10"
|
||||
"@swagger-api/apidom-ast" "^1.0.0-beta.30"
|
||||
"@swagger-api/apidom-core" "^1.0.0-beta.30"
|
||||
"@swagger-api/apidom-json-pointer" "^1.0.0-beta.30"
|
||||
"@swagger-api/apidom-ns-json-schema-2020-12" "^1.0.0-beta.30"
|
||||
"@swagger-api/apidom-ns-openapi-3-0" "^1.0.0-beta.30"
|
||||
"@types/ramda" "~0.30.0"
|
||||
ramda "~0.30.0"
|
||||
ramda-adjunct "^5.0.0"
|
||||
ts-mixer "^6.0.3"
|
||||
|
||||
"@swagger-api/apidom-ns-openapi-3-1@^1.0.0-beta.3", "@swagger-api/apidom-ns-openapi-3-1@^1.0.0-beta.3 <1.0.0-rc.0":
|
||||
version "1.0.0-beta.12"
|
||||
resolved "https://registry.npmjs.org/@swagger-api/apidom-ns-openapi-3-1/-/apidom-ns-openapi-3-1-1.0.0-beta.12.tgz"
|
||||
integrity sha512-IayaLSawWo5rAyM2nRY6faTfK8cJQ+mGGR94NOmsjcUQw9IljY9uX7PXj3izOdFlXFYjgR1P+mIhuuXyDuw4qg==
|
||||
@@ -2665,19 +2823,6 @@
|
||||
ramda-adjunct "^5.0.0"
|
||||
ts-mixer "^6.0.3"
|
||||
|
||||
"@swagger-api/apidom-ns-workflows-1@^1.0.0-beta.3", "@swagger-api/apidom-ns-workflows-1@^1.0.0-beta.3 <1.0.0-rc.0":
|
||||
version "1.0.0-beta.3"
|
||||
resolved "https://registry.npmjs.org/@swagger-api/apidom-ns-workflows-1/-/apidom-ns-workflows-1-1.0.0-beta.3.tgz"
|
||||
integrity sha512-+7i8CZAC+TypSYuxTtwXH2qIyQC1ATn8r+1pW4NWCs4F2Yr4K2gGG4ZmOE6ckNa+Q53yyx+Spt7xhLfZDJZp/w==
|
||||
dependencies:
|
||||
"@babel/runtime-corejs3" "^7.20.7"
|
||||
"@swagger-api/apidom-core" "^1.0.0-beta.3"
|
||||
"@swagger-api/apidom-ns-openapi-3-1" "^1.0.0-beta.3"
|
||||
"@types/ramda" "~0.30.0"
|
||||
ramda "~0.30.0"
|
||||
ramda-adjunct "^5.0.0"
|
||||
ts-mixer "^6.0.3"
|
||||
|
||||
"@swagger-api/apidom-parser-adapter-api-design-systems-json@^1.0.0-beta.3 <1.0.0-rc.0":
|
||||
version "1.0.0-beta.3"
|
||||
resolved "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-api-design-systems-json/-/apidom-parser-adapter-api-design-systems-json-1.0.0-beta.3.tgz"
|
||||
@@ -2704,6 +2849,32 @@
|
||||
ramda "~0.30.0"
|
||||
ramda-adjunct "^5.0.0"
|
||||
|
||||
"@swagger-api/apidom-parser-adapter-arazzo-json-1@^1.0.0-beta.3 <1.0.0-rc.0":
|
||||
version "1.0.0-beta.30"
|
||||
resolved "https://registry.yarnpkg.com/@swagger-api/apidom-parser-adapter-arazzo-json-1/-/apidom-parser-adapter-arazzo-json-1-1.0.0-beta.30.tgz#3250aa29e0b423bfdf59fd355c8927a6588ee5e2"
|
||||
integrity sha512-SZajkrTJ7c1I9CI3gnsdHZCQFSIyQ2H/lkWDjA/drZkRcfbR1CTbR2q0BGGlV5Y+nFHBxjRNpPbYbZrqh0WV4w==
|
||||
dependencies:
|
||||
"@babel/runtime-corejs3" "^7.26.10"
|
||||
"@swagger-api/apidom-core" "^1.0.0-beta.30"
|
||||
"@swagger-api/apidom-ns-arazzo-1" "^1.0.0-beta.30"
|
||||
"@swagger-api/apidom-parser-adapter-json" "^1.0.0-beta.30"
|
||||
"@types/ramda" "~0.30.0"
|
||||
ramda "~0.30.0"
|
||||
ramda-adjunct "^5.0.0"
|
||||
|
||||
"@swagger-api/apidom-parser-adapter-arazzo-yaml-1@^1.0.0-beta.3 <1.0.0-rc.0":
|
||||
version "1.0.0-beta.30"
|
||||
resolved "https://registry.yarnpkg.com/@swagger-api/apidom-parser-adapter-arazzo-yaml-1/-/apidom-parser-adapter-arazzo-yaml-1-1.0.0-beta.30.tgz#54ab0622a73d8ecc3190a3f1d07c4b994903536a"
|
||||
integrity sha512-T+N1ix+V5IpOWMFcamQRI50830JayD1gifnRm+mVeWJKMzp+xm08bnO8NiR9LQ2SKJZ6FWYM38oG2tAt0Lwxcg==
|
||||
dependencies:
|
||||
"@babel/runtime-corejs3" "^7.26.10"
|
||||
"@swagger-api/apidom-core" "^1.0.0-beta.30"
|
||||
"@swagger-api/apidom-ns-arazzo-1" "^1.0.0-beta.30"
|
||||
"@swagger-api/apidom-parser-adapter-yaml-1-2" "^1.0.0-beta.30"
|
||||
"@types/ramda" "~0.30.0"
|
||||
ramda "~0.30.0"
|
||||
ramda-adjunct "^5.0.0"
|
||||
|
||||
"@swagger-api/apidom-parser-adapter-asyncapi-json-2@^1.0.0-beta.3 <1.0.0-rc.0":
|
||||
version "1.0.0-beta.3"
|
||||
resolved "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-asyncapi-json-2/-/apidom-parser-adapter-asyncapi-json-2-1.0.0-beta.3.tgz"
|
||||
@@ -2746,6 +2917,22 @@
|
||||
tree-sitter-json "=0.24.8"
|
||||
web-tree-sitter "=0.24.3"
|
||||
|
||||
"@swagger-api/apidom-parser-adapter-json@^1.0.0-beta.30":
|
||||
version "1.0.0-beta.30"
|
||||
resolved "https://registry.yarnpkg.com/@swagger-api/apidom-parser-adapter-json/-/apidom-parser-adapter-json-1.0.0-beta.30.tgz#2febfadd7e3e4ca755fcf954d44a01ee9e66e2ab"
|
||||
integrity sha512-cciT19OOXafwBnXe9KFVwUGEVu4Zrvb4k12TYNlNqzVg1xA9pBc3Ywq5EgHIhiiQOLY3fILr0fr6B36N6irN2Q==
|
||||
dependencies:
|
||||
"@babel/runtime-corejs3" "^7.26.10"
|
||||
"@swagger-api/apidom-ast" "^1.0.0-beta.30"
|
||||
"@swagger-api/apidom-core" "^1.0.0-beta.30"
|
||||
"@swagger-api/apidom-error" "^1.0.0-beta.30"
|
||||
"@types/ramda" "~0.30.0"
|
||||
ramda "~0.30.0"
|
||||
ramda-adjunct "^5.0.0"
|
||||
tree-sitter "=0.22.1"
|
||||
tree-sitter-json "=0.24.8"
|
||||
web-tree-sitter "=0.24.5"
|
||||
|
||||
"@swagger-api/apidom-parser-adapter-openapi-json-2@^1.0.0-beta.3 <1.0.0-rc.0":
|
||||
version "1.0.0-beta.3"
|
||||
resolved "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-openapi-json-2/-/apidom-parser-adapter-openapi-json-2-1.0.0-beta.3.tgz"
|
||||
@@ -2824,32 +3011,6 @@
|
||||
ramda "~0.30.0"
|
||||
ramda-adjunct "^5.0.0"
|
||||
|
||||
"@swagger-api/apidom-parser-adapter-workflows-json-1@^1.0.0-beta.3 <1.0.0-rc.0":
|
||||
version "1.0.0-beta.3"
|
||||
resolved "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-workflows-json-1/-/apidom-parser-adapter-workflows-json-1-1.0.0-beta.3.tgz"
|
||||
integrity sha512-OsKz09YcfQfTbiNZueTLHBrn7umnMjtuN0ZzuNiBs5txaLS196grpzyTiG+4UJ1zIWvjvZmLZEbQqbKZ9qTw8A==
|
||||
dependencies:
|
||||
"@babel/runtime-corejs3" "^7.20.7"
|
||||
"@swagger-api/apidom-core" "^1.0.0-beta.3"
|
||||
"@swagger-api/apidom-ns-workflows-1" "^1.0.0-beta.3"
|
||||
"@swagger-api/apidom-parser-adapter-json" "^1.0.0-beta.3"
|
||||
"@types/ramda" "~0.30.0"
|
||||
ramda "~0.30.0"
|
||||
ramda-adjunct "^5.0.0"
|
||||
|
||||
"@swagger-api/apidom-parser-adapter-workflows-yaml-1@^1.0.0-beta.3 <1.0.0-rc.0":
|
||||
version "1.0.0-beta.3"
|
||||
resolved "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-workflows-yaml-1/-/apidom-parser-adapter-workflows-yaml-1-1.0.0-beta.3.tgz"
|
||||
integrity sha512-IifK3T6UtqBkIoHOQe6QRGpFU9LFqmJ5T1JzbWnVX+gazoVE+N9ZkFWQfb9pKCaCfAwPVp+vai6bQ2eUsGh4CA==
|
||||
dependencies:
|
||||
"@babel/runtime-corejs3" "^7.20.7"
|
||||
"@swagger-api/apidom-core" "^1.0.0-beta.3"
|
||||
"@swagger-api/apidom-ns-workflows-1" "^1.0.0-beta.3"
|
||||
"@swagger-api/apidom-parser-adapter-yaml-1-2" "^1.0.0-beta.3"
|
||||
"@types/ramda" "~0.30.0"
|
||||
ramda "~0.30.0"
|
||||
ramda-adjunct "^5.0.0"
|
||||
|
||||
"@swagger-api/apidom-parser-adapter-yaml-1-2@^1.0.0-beta.3", "@swagger-api/apidom-parser-adapter-yaml-1-2@^1.0.0-beta.3 <1.0.0-rc.0":
|
||||
version "1.0.0-beta.3"
|
||||
resolved "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-yaml-1-2/-/apidom-parser-adapter-yaml-1-2-1.0.0-beta.3.tgz"
|
||||
@@ -2866,15 +3027,31 @@
|
||||
tree-sitter "=0.21.1"
|
||||
web-tree-sitter "=0.24.3"
|
||||
|
||||
"@swagger-api/apidom-reference@>=1.0.0-beta.12 <1.0.0-rc.0":
|
||||
version "1.0.0-beta.12"
|
||||
resolved "https://registry.npmjs.org/@swagger-api/apidom-reference/-/apidom-reference-1.0.0-beta.12.tgz"
|
||||
integrity sha512-4A5dvra9NCsl9Dp3x3UyNV3tyTl1LJwvNowaLfMuY5r8jtQLzkcCW+CLPyP2Y64qeT30sklZp7/M3VVd6jKPOg==
|
||||
"@swagger-api/apidom-parser-adapter-yaml-1-2@^1.0.0-beta.30":
|
||||
version "1.0.0-beta.30"
|
||||
resolved "https://registry.yarnpkg.com/@swagger-api/apidom-parser-adapter-yaml-1-2/-/apidom-parser-adapter-yaml-1-2-1.0.0-beta.30.tgz#b48d0f8093d976f97dbc86a51fa86f84dfec8f5a"
|
||||
integrity sha512-NRmQehyw4gbDzeBAl0zjyPqj4e/jNYgqnRLcOsxTKpWODud8RHBqEvju/M6iET6ru0o+A9265efFzqR9hiE0LA==
|
||||
dependencies:
|
||||
"@babel/runtime-corejs3" "^7.20.7"
|
||||
"@swagger-api/apidom-core" "^1.0.0-beta.12"
|
||||
"@babel/runtime-corejs3" "^7.26.10"
|
||||
"@swagger-api/apidom-ast" "^1.0.0-beta.30"
|
||||
"@swagger-api/apidom-core" "^1.0.0-beta.30"
|
||||
"@swagger-api/apidom-error" "^1.0.0-beta.30"
|
||||
"@tree-sitter-grammars/tree-sitter-yaml" "=0.7.0"
|
||||
"@types/ramda" "~0.30.0"
|
||||
axios "^1.7.4"
|
||||
ramda "~0.30.0"
|
||||
ramda-adjunct "^5.0.0"
|
||||
tree-sitter "=0.22.1"
|
||||
web-tree-sitter "=0.24.5"
|
||||
|
||||
"@swagger-api/apidom-reference@>=1.0.0-beta.13 <1.0.0-rc.0":
|
||||
version "1.0.0-beta.30"
|
||||
resolved "https://registry.yarnpkg.com/@swagger-api/apidom-reference/-/apidom-reference-1.0.0-beta.30.tgz#231f80df4060a88391ecd7cece6c71cc9ae60544"
|
||||
integrity sha512-l1MpLMlmaX+y2hra5EadfR37sAMzmEz1wZomVcnw7vJEFlLQo3WwOdFvpQemPCZ9IJHUs+5zhZ++w7z60uKpSw==
|
||||
dependencies:
|
||||
"@babel/runtime-corejs3" "^7.26.10"
|
||||
"@swagger-api/apidom-core" "^1.0.0-beta.30"
|
||||
"@types/ramda" "~0.30.0"
|
||||
axios "^1.8.2"
|
||||
minimatch "^7.4.3"
|
||||
process "^0.11.10"
|
||||
ramda "~0.30.0"
|
||||
@@ -2882,13 +3059,15 @@
|
||||
optionalDependencies:
|
||||
"@swagger-api/apidom-error" "^1.0.0-beta.3 <1.0.0-rc.0"
|
||||
"@swagger-api/apidom-json-pointer" "^1.0.0-beta.3 <1.0.0-rc.0"
|
||||
"@swagger-api/apidom-ns-arazzo-1" "^1.0.0-beta.3 <1.0.0-rc.0"
|
||||
"@swagger-api/apidom-ns-asyncapi-2" "^1.0.0-beta.3 <1.0.0-rc.0"
|
||||
"@swagger-api/apidom-ns-openapi-2" "^1.0.0-beta.3 <1.0.0-rc.0"
|
||||
"@swagger-api/apidom-ns-openapi-3-0" "^1.0.0-beta.3 <1.0.0-rc.0"
|
||||
"@swagger-api/apidom-ns-openapi-3-1" "^1.0.0-beta.3 <1.0.0-rc.0"
|
||||
"@swagger-api/apidom-ns-workflows-1" "^1.0.0-beta.3 <1.0.0-rc.0"
|
||||
"@swagger-api/apidom-parser-adapter-api-design-systems-json" "^1.0.0-beta.3 <1.0.0-rc.0"
|
||||
"@swagger-api/apidom-parser-adapter-api-design-systems-yaml" "^1.0.0-beta.3 <1.0.0-rc.0"
|
||||
"@swagger-api/apidom-parser-adapter-arazzo-json-1" "^1.0.0-beta.3 <1.0.0-rc.0"
|
||||
"@swagger-api/apidom-parser-adapter-arazzo-yaml-1" "^1.0.0-beta.3 <1.0.0-rc.0"
|
||||
"@swagger-api/apidom-parser-adapter-asyncapi-json-2" "^1.0.0-beta.3 <1.0.0-rc.0"
|
||||
"@swagger-api/apidom-parser-adapter-asyncapi-yaml-2" "^1.0.0-beta.3 <1.0.0-rc.0"
|
||||
"@swagger-api/apidom-parser-adapter-json" "^1.0.0-beta.3 <1.0.0-rc.0"
|
||||
@@ -2898,8 +3077,6 @@
|
||||
"@swagger-api/apidom-parser-adapter-openapi-yaml-2" "^1.0.0-beta.3 <1.0.0-rc.0"
|
||||
"@swagger-api/apidom-parser-adapter-openapi-yaml-3-0" "^1.0.0-beta.3 <1.0.0-rc.0"
|
||||
"@swagger-api/apidom-parser-adapter-openapi-yaml-3-1" "^1.0.0-beta.3 <1.0.0-rc.0"
|
||||
"@swagger-api/apidom-parser-adapter-workflows-json-1" "^1.0.0-beta.3 <1.0.0-rc.0"
|
||||
"@swagger-api/apidom-parser-adapter-workflows-yaml-1" "^1.0.0-beta.3 <1.0.0-rc.0"
|
||||
"@swagger-api/apidom-parser-adapter-yaml-1-2" "^1.0.0-beta.3 <1.0.0-rc.0"
|
||||
|
||||
"@swaggerexpert/cookie@^2.0.2":
|
||||
@@ -2924,6 +3101,14 @@
|
||||
node-addon-api "^8.0.0"
|
||||
node-gyp-build "^4.8.0"
|
||||
|
||||
"@tree-sitter-grammars/tree-sitter-yaml@=0.7.0":
|
||||
version "0.7.0"
|
||||
resolved "https://registry.yarnpkg.com/@tree-sitter-grammars/tree-sitter-yaml/-/tree-sitter-yaml-0.7.0.tgz#83995463cdeed8bb9ad2cdcbeb4d4aed9472411f"
|
||||
integrity sha512-GOMIK3IaDvECD0eZEhAsLl03RMtM1E8StxuGMn6PpMKFg7jyQ+jSzxJZ4Jmc/tYitah9/AECt8o4tlRQ5yEZQg==
|
||||
dependencies:
|
||||
node-addon-api "^8.3.0"
|
||||
node-gyp-build "^4.8.4"
|
||||
|
||||
"@trysound/sax@0.2.0":
|
||||
version "0.2.0"
|
||||
resolved "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz"
|
||||
@@ -3668,10 +3853,10 @@ ansi-styles@^6.1.0:
|
||||
resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz"
|
||||
integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==
|
||||
|
||||
antd@^5.24.2:
|
||||
version "5.24.2"
|
||||
resolved "https://registry.yarnpkg.com/antd/-/antd-5.24.2.tgz#df28583b68279821096234920584dadea6f9b283"
|
||||
integrity sha512-7Z9HsE3ZIK3sE/WuUqii3w7Gl1IJuRL21sDUTtkN95JS5KhRYP8ISv7m/HxsJ3Mn/yxgojBCgLPJ212+Dn+aPw==
|
||||
antd@^5.24.5:
|
||||
version "5.24.5"
|
||||
resolved "https://registry.yarnpkg.com/antd/-/antd-5.24.5.tgz#b0976a113163888d1477f9e666c3c23352b098e9"
|
||||
integrity sha512-1lAv/G+9ewQanyoAo3JumQmIlVxwo5QwWGb6QCHYc40Cq0NxC/EzITcjsgq1PSaTUpLkKq8A2l7Fjtu47vqQBg==
|
||||
dependencies:
|
||||
"@ant-design/colors" "^7.2.0"
|
||||
"@ant-design/cssinjs" "^1.23.0"
|
||||
@@ -3688,22 +3873,22 @@ antd@^5.24.2:
|
||||
classnames "^2.5.1"
|
||||
copy-to-clipboard "^3.3.3"
|
||||
dayjs "^1.11.11"
|
||||
rc-cascader "~3.33.0"
|
||||
rc-cascader "~3.33.1"
|
||||
rc-checkbox "~3.5.0"
|
||||
rc-collapse "~3.9.0"
|
||||
rc-dialog "~9.6.0"
|
||||
rc-drawer "~7.2.0"
|
||||
rc-dropdown "~4.2.1"
|
||||
rc-field-form "~2.7.0"
|
||||
rc-image "~7.11.0"
|
||||
rc-input "~1.7.2"
|
||||
rc-image "~7.11.1"
|
||||
rc-input "~1.7.3"
|
||||
rc-input-number "~9.4.0"
|
||||
rc-mentions "~2.19.1"
|
||||
rc-menu "~9.16.1"
|
||||
rc-motion "^2.9.5"
|
||||
rc-notification "~5.6.3"
|
||||
rc-pagination "~5.1.0"
|
||||
rc-picker "~4.11.2"
|
||||
rc-picker "~4.11.3"
|
||||
rc-progress "~4.0.0"
|
||||
rc-rate "~2.13.1"
|
||||
rc-resize-observer "^1.4.3"
|
||||
@@ -3712,11 +3897,11 @@ antd@^5.24.2:
|
||||
rc-slider "~11.1.8"
|
||||
rc-steps "~6.0.1"
|
||||
rc-switch "~4.1.0"
|
||||
rc-table "~7.50.3"
|
||||
rc-table "~7.50.4"
|
||||
rc-tabs "~15.5.1"
|
||||
rc-textarea "~1.9.0"
|
||||
rc-tooltip "~6.4.0"
|
||||
rc-tree "~5.13.0"
|
||||
rc-tree "~5.13.1"
|
||||
rc-tree-select "~5.27.0"
|
||||
rc-upload "~4.8.1"
|
||||
rc-util "^5.44.4"
|
||||
@@ -3885,10 +4070,10 @@ available-typed-arrays@^1.0.7:
|
||||
dependencies:
|
||||
possible-typed-array-names "^1.0.0"
|
||||
|
||||
axios@^1.7.4:
|
||||
version "1.8.2"
|
||||
resolved "https://registry.yarnpkg.com/axios/-/axios-1.8.2.tgz#fabe06e241dfe83071d4edfbcaa7b1c3a40f7979"
|
||||
integrity sha512-ls4GYBm5aig9vWx8AWDSGLpnpDQRtWAfrjU+EuytuODrFBkqesN2RkOQCBzrA1RQNHw1SmRMSDDDSwzNAYQ6Rg==
|
||||
axios@^1.8.2:
|
||||
version "1.8.4"
|
||||
resolved "https://registry.yarnpkg.com/axios/-/axios-1.8.4.tgz#78990bb4bc63d2cae072952d374835950a82f447"
|
||||
integrity sha512-eBSYY4Y68NNlHbHBMdeDmKNtDgXWhQsJcGqzO3iLUM0GraQFSS9cVgPX5I9b3lbdFKyYoAEGAZF1DwhTaljNAw==
|
||||
dependencies:
|
||||
follow-redirects "^1.15.6"
|
||||
form-data "^4.0.0"
|
||||
@@ -5349,10 +5534,10 @@ escape-string-regexp@^5.0.0:
|
||||
resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz"
|
||||
integrity sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==
|
||||
|
||||
eslint-config-prettier@^10.0.2:
|
||||
version "10.0.2"
|
||||
resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-10.0.2.tgz#47444de8aa104ce82c2f91ad2a5e96b62c01e20d"
|
||||
integrity sha512-1105/17ZIMjmCOJOPNfVdbXafLCLj3hPmkmB7dLgt7XsQ/zkxSuDerE/xgO3RxoHysR1N1whmquY0lSn2O0VLg==
|
||||
eslint-config-prettier@^10.1.1:
|
||||
version "10.1.1"
|
||||
resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-10.1.1.tgz#cf0ff6e5c4e7e15f129f1f1ce2a5ecba92dec132"
|
||||
integrity sha512-4EQQr6wXwS+ZJSzaR5ZCrYgLxqvUjdXctaEtBqHcbkW944B1NQyO4qpdHQbXBONfwxXdkAY81HH4+LUfrg+zPw==
|
||||
|
||||
eslint-plugin-prettier@^4.0.0:
|
||||
version "4.2.1"
|
||||
@@ -5520,12 +5705,11 @@ estree-util-to-js@^2.0.0:
|
||||
source-map "^0.7.0"
|
||||
|
||||
estree-util-value-to-estree@^3.0.1:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.npmjs.org/estree-util-value-to-estree/-/estree-util-value-to-estree-3.1.1.tgz"
|
||||
integrity sha512-5mvUrF2suuv5f5cGDnDphIy4/gW86z82kl5qG6mM9z04SEQI4FB5Apmaw/TGEf3l55nLtMs5s51dmhUzvAHQCA==
|
||||
version "3.3.3"
|
||||
resolved "https://registry.yarnpkg.com/estree-util-value-to-estree/-/estree-util-value-to-estree-3.3.3.tgz#800b03a551b466dd77ed2c574b042a9992546cf2"
|
||||
integrity sha512-Db+m1WSD4+mUO7UgMeKkAwdbfNWwIxLt48XF2oFU9emPfXkIu+k5/nlOj313v7wqtAPo0f9REhUvznFrPkG8CQ==
|
||||
dependencies:
|
||||
"@types/estree" "^1.0.0"
|
||||
is-plain-obj "^4.0.0"
|
||||
|
||||
estree-util-visit@^2.0.0:
|
||||
version "2.0.0"
|
||||
@@ -8256,6 +8440,11 @@ node-addon-api@^8.0.0, node-addon-api@^8.2.2:
|
||||
resolved "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.3.0.tgz"
|
||||
integrity sha512-8VOpLHFrOQlAH+qA0ZzuGRlALRA6/LVh8QJldbrC4DY0hXoMP0l4Acq8TzFC018HztWiRqyCEj2aTWY2UvnJUg==
|
||||
|
||||
node-addon-api@^8.2.1, node-addon-api@^8.3.0:
|
||||
version "8.3.1"
|
||||
resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-8.3.1.tgz#53bc8a4f8dbde3de787b9828059da94ba9fd4eed"
|
||||
integrity sha512-lytcDEdxKjGJPTLEfW4mYMigRezMlyJY8W4wxJK8zE533Jlb8L8dRuObJFWg2P+AuOIxoCgKF+2Oq4d4Zd0OUA==
|
||||
|
||||
node-domexception@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz"
|
||||
@@ -8284,7 +8473,7 @@ node-forge@^1:
|
||||
resolved "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz"
|
||||
integrity sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==
|
||||
|
||||
node-gyp-build@^4.8.0, node-gyp-build@^4.8.2:
|
||||
node-gyp-build@^4.8.0, node-gyp-build@^4.8.2, node-gyp-build@^4.8.4:
|
||||
version "4.8.4"
|
||||
resolved "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz"
|
||||
integrity sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==
|
||||
@@ -8424,16 +8613,16 @@ open@^8.0.9, open@^8.4.0:
|
||||
is-docker "^2.1.1"
|
||||
is-wsl "^2.2.0"
|
||||
|
||||
openapi-path-templating@^2.0.1:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.npmjs.org/openapi-path-templating/-/openapi-path-templating-2.1.0.tgz"
|
||||
integrity sha512-fLs5eJmLyU8wPRz+JSH5uLE7TE4Ohg6VHOtj0C0AlD3GTCCcw2LgKW6MSN1A8ZBKHEg2O4/d02knmVU1nvGAKQ==
|
||||
openapi-path-templating@^2.2.1:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/openapi-path-templating/-/openapi-path-templating-2.2.1.tgz#57026767530667096d33d7362382a93d75d497f6"
|
||||
integrity sha512-eN14VrDvl/YyGxxrkGOHkVkWEoPyhyeydOUrbvjoz8K5eIGgELASwN1eqFOJ2CTQMGCy2EntOK1KdtJ8ZMekcg==
|
||||
dependencies:
|
||||
apg-lite "^1.0.4"
|
||||
|
||||
openapi-server-url-templating@^1.2.0:
|
||||
openapi-server-url-templating@^1.3.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.npmjs.org/openapi-server-url-templating/-/openapi-server-url-templating-1.3.0.tgz"
|
||||
resolved "https://registry.yarnpkg.com/openapi-server-url-templating/-/openapi-server-url-templating-1.3.0.tgz#80bc6ea5209a3c4fe9d359673ba51635676e2503"
|
||||
integrity sha512-DPlCms3KKEbjVQb0spV6Awfn6UWNheuG/+folQPzh/wUaKwuqvj8zt5gagD7qoyxtE03cIiKPgLFS3Q8Bz00uQ==
|
||||
dependencies:
|
||||
apg-lite "^1.0.4"
|
||||
@@ -9180,6 +9369,11 @@ ramda-adjunct@^5.0.0:
|
||||
resolved "https://registry.npmjs.org/ramda-adjunct/-/ramda-adjunct-5.0.0.tgz"
|
||||
integrity sha512-iEehjqp/ZGjYZybZByDaDu27c+79SE7rKDcySLdmjAwKWkz6jNhvGgZwzUGaMsij8Llp9+1N1Gy0drpAq8ZSyA==
|
||||
|
||||
ramda-adjunct@^5.1.0:
|
||||
version "5.1.0"
|
||||
resolved "https://registry.yarnpkg.com/ramda-adjunct/-/ramda-adjunct-5.1.0.tgz#c1281100922b03e74b1535cb9c966628697c5cc1"
|
||||
integrity sha512-8qCpl2vZBXEJyNbi4zqcgdfHtcdsWjOGbiNSEnEBrM6Y0OKOT8UxJbIVGm1TIcjaSu2MxaWcgtsNlKlCk7o7qg==
|
||||
|
||||
ramda@^0.30.1, ramda@~0.30.0:
|
||||
version "0.30.1"
|
||||
resolved "https://registry.npmjs.org/ramda/-/ramda-0.30.1.tgz"
|
||||
@@ -9220,10 +9414,10 @@ raw-body@2.5.2:
|
||||
iconv-lite "0.4.24"
|
||||
unpipe "1.0.0"
|
||||
|
||||
rc-cascader@~3.33.0:
|
||||
version "3.33.0"
|
||||
resolved "https://registry.npmjs.org/rc-cascader/-/rc-cascader-3.33.0.tgz"
|
||||
integrity sha512-JvZrMbKBXIbEDmpIORxqvedY/bck6hGbs3hxdWT8eS9wSQ1P7//lGxbyKjOSyQiVBbgzNWriSe6HoMcZO/+0rQ==
|
||||
rc-cascader@~3.33.1:
|
||||
version "3.33.1"
|
||||
resolved "https://registry.yarnpkg.com/rc-cascader/-/rc-cascader-3.33.1.tgz#19e01462ef5ef51b723c1f562c7b9cde4691e7ee"
|
||||
integrity sha512-Kyl4EJ7ZfCBuidmZVieegcbFw0RcU5bHHSbtEdmuLYd0fYHCAiYKZ6zon7fWAVyC6rWWOOib0XKdTSf7ElC9rg==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.25.7"
|
||||
classnames "^2.3.1"
|
||||
@@ -9291,10 +9485,10 @@ rc-field-form@~2.7.0:
|
||||
"@rc-component/async-validator" "^5.0.3"
|
||||
rc-util "^5.32.2"
|
||||
|
||||
rc-image@~7.11.0:
|
||||
version "7.11.0"
|
||||
resolved "https://registry.npmjs.org/rc-image/-/rc-image-7.11.0.tgz"
|
||||
integrity sha512-aZkTEZXqeqfPZtnSdNUnKQA0N/3MbgR7nUnZ+/4MfSFWPFHZau4p5r5ShaI0KPEMnNjv4kijSCFq/9wtJpwykw==
|
||||
rc-image@~7.11.1:
|
||||
version "7.11.1"
|
||||
resolved "https://registry.yarnpkg.com/rc-image/-/rc-image-7.11.1.tgz#3ab290708dc053d3681de94186522e4e594f6772"
|
||||
integrity sha512-XuoWx4KUXg7hNy5mRTy1i8c8p3K8boWg6UajbHpDXS5AlRVucNfTi5YxTtPBTBzegxAZpvuLfh3emXFt6ybUdA==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.11.2"
|
||||
"@rc-component/portal" "^1.0.2"
|
||||
@@ -9314,10 +9508,10 @@ rc-input-number@~9.4.0:
|
||||
rc-input "~1.7.1"
|
||||
rc-util "^5.40.1"
|
||||
|
||||
rc-input@~1.7.1, rc-input@~1.7.2:
|
||||
version "1.7.2"
|
||||
resolved "https://registry.npmjs.org/rc-input/-/rc-input-1.7.2.tgz"
|
||||
integrity sha512-g3nYONnl4edWj2FfVoxsU3Ec4XTE+Hb39Kfh2MFxMZjp/0gGyPUgy/v7ZhS27ZxUFNkuIDYXm9PJsLyJbtg86A==
|
||||
rc-input@~1.7.1, rc-input@~1.7.3:
|
||||
version "1.7.3"
|
||||
resolved "https://registry.yarnpkg.com/rc-input/-/rc-input-1.7.3.tgz#cb334a17b93ce985bceb243b4c111a5ed641e0e3"
|
||||
integrity sha512-A5w4egJq8+4JzlQ55FfQjDnPvOaAbzwC3VLOAdOytyek3TboSOP9qxN+Gifup+shVXfvecBLBbWBpWxmk02SWQ==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.11.1"
|
||||
classnames "^2.2.1"
|
||||
@@ -9386,7 +9580,7 @@ rc-pagination@~5.1.0:
|
||||
classnames "^2.3.2"
|
||||
rc-util "^5.38.0"
|
||||
|
||||
rc-picker@~4.11.2:
|
||||
rc-picker@~4.11.3:
|
||||
version "4.11.3"
|
||||
resolved "https://registry.yarnpkg.com/rc-picker/-/rc-picker-4.11.3.tgz#7e7e3ad83aa461c284b8391c697492d1c34d2cb8"
|
||||
integrity sha512-MJ5teb7FlNE0NFHTncxXQ62Y5lytq6sh5nUw0iH8OkHL/TjARSEvSHpr940pWgjGANpjCwyMdvsEV55l5tYNSg==
|
||||
@@ -9476,10 +9670,10 @@ rc-switch@~4.1.0:
|
||||
classnames "^2.2.1"
|
||||
rc-util "^5.30.0"
|
||||
|
||||
rc-table@~7.50.3:
|
||||
version "7.50.3"
|
||||
resolved "https://registry.npmjs.org/rc-table/-/rc-table-7.50.3.tgz"
|
||||
integrity sha512-Z4/zNCzjv7f/XzPRecb+vJU0DJKdsYt4YRkDzNl4G05m7JmxrKGYC2KqN1Ew6jw2zJq7cxVv3z39qyZOHMuf7A==
|
||||
rc-table@~7.50.4:
|
||||
version "7.50.4"
|
||||
resolved "https://registry.yarnpkg.com/rc-table/-/rc-table-7.50.4.tgz#687b5bf76d1a94168f75481cbc83be9442010432"
|
||||
integrity sha512-Y+YuncnQqoS5e7yHvfvlv8BmCvwDYDX/2VixTBEhkMDk9itS9aBINp4nhzXFKiBP/frG4w0pS9d9Rgisl0T1Bw==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.10.1"
|
||||
"@rc-component/context" "^1.4.0"
|
||||
@@ -9533,10 +9727,10 @@ rc-tree-select@~5.27.0:
|
||||
rc-tree "~5.13.0"
|
||||
rc-util "^5.43.0"
|
||||
|
||||
rc-tree@~5.13.0:
|
||||
version "5.13.0"
|
||||
resolved "https://registry.npmjs.org/rc-tree/-/rc-tree-5.13.0.tgz"
|
||||
integrity sha512-2+lFvoVRnvHQ1trlpXMOWtF8BUgF+3TiipG72uOfhpL5CUdXCk931kvDdUkTL/IZVtNEDQKwEEmJbAYJSA5NnA==
|
||||
rc-tree@~5.13.0, rc-tree@~5.13.1:
|
||||
version "5.13.1"
|
||||
resolved "https://registry.yarnpkg.com/rc-tree/-/rc-tree-5.13.1.tgz#f36a33a94a1282f4b09685216c01487089748910"
|
||||
integrity sha512-FNhIefhftobCdUJshO7M8uZTA9F4OPGVXqGfZkkD/5soDeOhwO06T/aKTrg0WD8gRg/pyfq+ql3aMymLHCTC4A==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.10.1"
|
||||
classnames "2.x"
|
||||
@@ -10866,18 +11060,18 @@ svgo@^3.0.2, svgo@^3.2.0:
|
||||
csso "^5.0.5"
|
||||
picocolors "^1.0.0"
|
||||
|
||||
swagger-client@^3.34.1:
|
||||
version "3.34.1"
|
||||
resolved "https://registry.yarnpkg.com/swagger-client/-/swagger-client-3.34.1.tgz#e61e8120fe80addc3563e0ec5147a9ca71b6e7f4"
|
||||
integrity sha512-aqk315C959936kijVpR28Q07eugElW9vp77a57hdFlQDF8Kuln7SeB1MwXnTCOQEM6/pIWYN00QlvIEwHqQkqw==
|
||||
swagger-client@^3.34.4:
|
||||
version "3.34.4"
|
||||
resolved "https://registry.yarnpkg.com/swagger-client/-/swagger-client-3.34.4.tgz#034cb241af39b988ca10c39e7add2596c480075d"
|
||||
integrity sha512-Qvtu8DtARAx5GwefA0eV1WRLa4Q9bhczrtNAsiBMOx3HkxAOczy1APQhrcblJdLys0xEGQ4xYizYFXfIL9BhpA==
|
||||
dependencies:
|
||||
"@babel/runtime-corejs3" "^7.22.15"
|
||||
"@scarf/scarf" "=1.4.0"
|
||||
"@swagger-api/apidom-core" ">=1.0.0-beta.12 <1.0.0-rc.0"
|
||||
"@swagger-api/apidom-error" ">=1.0.0-beta.12 <1.0.0-rc.0"
|
||||
"@swagger-api/apidom-json-pointer" ">=1.0.0-beta.12 <1.0.0-rc.0"
|
||||
"@swagger-api/apidom-ns-openapi-3-1" ">=1.0.0-beta.12 <1.0.0-rc.0"
|
||||
"@swagger-api/apidom-reference" ">=1.0.0-beta.12 <1.0.0-rc.0"
|
||||
"@swagger-api/apidom-core" ">=1.0.0-beta.13 <1.0.0-rc.0"
|
||||
"@swagger-api/apidom-error" ">=1.0.0-beta.13 <1.0.0-rc.0"
|
||||
"@swagger-api/apidom-json-pointer" ">=1.0.0-beta.13 <1.0.0-rc.0"
|
||||
"@swagger-api/apidom-ns-openapi-3-1" ">=1.0.0-beta.13 <1.0.0-rc.0"
|
||||
"@swagger-api/apidom-reference" ">=1.0.0-beta.13 <1.0.0-rc.0"
|
||||
"@swaggerexpert/cookie" "^2.0.2"
|
||||
deepmerge "~4.3.0"
|
||||
fast-json-patch "^3.0.0-1"
|
||||
@@ -10885,17 +11079,17 @@ swagger-client@^3.34.1:
|
||||
neotraverse "=0.6.18"
|
||||
node-abort-controller "^3.1.1"
|
||||
node-fetch-commonjs "^3.3.2"
|
||||
openapi-path-templating "^2.0.1"
|
||||
openapi-server-url-templating "^1.2.0"
|
||||
openapi-path-templating "^2.2.1"
|
||||
openapi-server-url-templating "^1.3.0"
|
||||
ramda "^0.30.1"
|
||||
ramda-adjunct "^5.0.0"
|
||||
ramda-adjunct "^5.1.0"
|
||||
|
||||
swagger-ui-react@^5.20.0:
|
||||
version "5.20.0"
|
||||
resolved "https://registry.yarnpkg.com/swagger-ui-react/-/swagger-ui-react-5.20.0.tgz#46b7d65feefad6490e80a4c9f102e44c407c902a"
|
||||
integrity sha512-txC3j+aPi6KOV7OxJvCdmeosg1oPmPdtOH2Ny3kogRCSwj9y7FF0IHv5KWhjmOaUvQa+9+XiYiw+NGQvi88pSg==
|
||||
swagger-ui-react@^5.20.2:
|
||||
version "5.20.2"
|
||||
resolved "https://registry.yarnpkg.com/swagger-ui-react/-/swagger-ui-react-5.20.2.tgz#eb9f8de2e6c916661d8033d43119f6e105ab87da"
|
||||
integrity sha512-6ifaFjT02yBv1kjEivIMWxQpI7r8O7D/oA8u1JiwhTkom0dOk85lTExao5Dj5ztS6dBg6i1zm+ILhH94fF9g8Q==
|
||||
dependencies:
|
||||
"@babel/runtime-corejs3" "^7.26.7"
|
||||
"@babel/runtime-corejs3" "^7.26.10"
|
||||
"@scarf/scarf" "=1.4.0"
|
||||
base64-js "^1.5.1"
|
||||
classnames "^2.5.1"
|
||||
@@ -10923,7 +11117,7 @@ swagger-ui-react@^5.20.0:
|
||||
reselect "^5.1.1"
|
||||
serialize-error "^8.1.0"
|
||||
sha.js "^2.4.11"
|
||||
swagger-client "^3.34.1"
|
||||
swagger-client "^3.34.4"
|
||||
url-parse "^1.5.10"
|
||||
xml "=1.0.1"
|
||||
xml-but-prettier "^1.0.1"
|
||||
@@ -11043,6 +11237,14 @@ tree-sitter@=0.21.1:
|
||||
node-addon-api "^8.0.0"
|
||||
node-gyp-build "^4.8.0"
|
||||
|
||||
tree-sitter@=0.22.1:
|
||||
version "0.22.1"
|
||||
resolved "https://registry.yarnpkg.com/tree-sitter/-/tree-sitter-0.22.1.tgz#5a5296fc0898b21443657e071b050c95c0d7afbd"
|
||||
integrity sha512-gRO+jk2ljxZlIn20QRskIvpLCMtzuLl5T0BY6L9uvPYD17uUrxlxWkvYCiVqED2q2q7CVtY52Uex4WcYo2FEXw==
|
||||
dependencies:
|
||||
node-addon-api "^8.2.1"
|
||||
node-gyp-build "^4.8.2"
|
||||
|
||||
trim-lines@^3.0.0:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz"
|
||||
@@ -11452,6 +11654,11 @@ web-tree-sitter@=0.24.3:
|
||||
resolved "https://registry.npmjs.org/web-tree-sitter/-/web-tree-sitter-0.24.3.tgz"
|
||||
integrity sha512-uR9YNewr1S2EzPKE+y39nAwaTyobBaZRG/IsfkB/OT4v0lXtNj5WjtHKgn2h7eOYUWIZh5rK9Px7tI6S9CRKdA==
|
||||
|
||||
web-tree-sitter@=0.24.5:
|
||||
version "0.24.5"
|
||||
resolved "https://registry.yarnpkg.com/web-tree-sitter/-/web-tree-sitter-0.24.5.tgz#16cea449da63012f23ca7b83bd32817dd0520400"
|
||||
integrity sha512-+J/2VSHN8J47gQUAvF8KDadrfz6uFYVjxoxbKWDoXVsH2u7yLdarCnIURnrMA6uSRkgX3SdmqM5BOoQjPdSh5w==
|
||||
|
||||
webpack-bundle-analyzer@^4.9.0:
|
||||
version "4.10.2"
|
||||
resolved "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.10.2.tgz"
|
||||
|
||||
@@ -5,5 +5,5 @@ dependencies:
|
||||
- name: redis
|
||||
repository: oci://registry-1.docker.io/bitnamicharts
|
||||
version: 17.9.4
|
||||
digest: sha256:9588e2a9f15d875a95763ed7da8e92b5b48a8d13cbacd66b775eacba3e8cebcd
|
||||
generated: "2024-12-29T12:19:15.365763+09:00"
|
||||
digest: sha256:c6290bb7e8ce9c694c06b3f5e9b9d01401943b0943c515d3a7a3a8dc1e6492ea
|
||||
generated: "2025-03-16T00:52:41.47139769+09:00"
|
||||
|
||||
@@ -29,7 +29,7 @@ maintainers:
|
||||
- name: craig-rueda
|
||||
email: craig@craigrueda.com
|
||||
url: https://github.com/craig-rueda
|
||||
version: 0.14.0
|
||||
version: 0.14.1
|
||||
dependencies:
|
||||
- name: postgresql
|
||||
version: 13.4.4
|
||||
|
||||
@@ -23,7 +23,7 @@ NOTE: This file is generated by helm-docs: https://github.com/norwoodj/helm-docs
|
||||
|
||||
# superset
|
||||
|
||||

|
||||

|
||||
|
||||
Apache Superset is a modern, enterprise-ready business intelligence web application
|
||||
|
||||
|
||||
@@ -812,7 +812,7 @@ postgresql:
|
||||
database: superset
|
||||
|
||||
image:
|
||||
tag: "14.6.0-debian-11-r13"
|
||||
tag: "14.17.0-debian-12-r3"
|
||||
|
||||
## PostgreSQL Primary parameters
|
||||
primary:
|
||||
|
||||
BIN
null_byte.csv
BIN
null_byte.csv
Binary file not shown.
|
@@ -20,7 +20,7 @@ requires = ["setuptools>=40.9.0", "wheel"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "apache-superset"
|
||||
name = "apache_superset"
|
||||
description = "A modern, enterprise-ready business intelligence web application"
|
||||
readme = "README.md"
|
||||
dynamic = ["version", "scripts", "entry-points"]
|
||||
@@ -44,7 +44,7 @@ dependencies = [
|
||||
"cryptography>=42.0.4, <45.0.0",
|
||||
"deprecation>=2.1.0, <2.2.0",
|
||||
"flask>=2.2.5, <3.0.0",
|
||||
"flask-appbuilder>=4.6.0, <5.0.0",
|
||||
"flask-appbuilder>=4.6.1, <5.0.0",
|
||||
"flask-caching>=2.1.0, <3",
|
||||
"flask-compress>=1.13, <2.0",
|
||||
"flask-talisman>=1.0.0, <2.0",
|
||||
|
||||
@@ -23,3 +23,13 @@ numexpr>=2.9.0
|
||||
# 5.0.0 has a sensitive deprecation used in other libs
|
||||
# -> https://github.com/aio-libs/async-timeout/blob/master/CHANGES.rst#500-2024-10-31
|
||||
async_timeout>=4.0.0,<5.0.0
|
||||
|
||||
# Known issue with 6.7.0 breaking a unit test, probably easy to fix, but will require
|
||||
# a bit of attention to bump.
|
||||
apispec>=6.0.0,<6.7.0
|
||||
|
||||
# 1.4.1 appears to use much more memory, where the python test suite runs out of memory
|
||||
# causing CI to fail. 1.4.0 is the last version that works.
|
||||
# https://marshmallow-sqlalchemy.readthedocs.io/en/latest/changelog.html#id3
|
||||
# Opened this issue https://github.com/marshmallow-code/marshmallow-sqlalchemy/issues/665
|
||||
marshmallow-sqlalchemy>=1.3.0,<1.4.1
|
||||
|
||||
@@ -4,22 +4,25 @@ alembic==1.15.1
|
||||
# via flask-migrate
|
||||
amqp==5.3.1
|
||||
# via kombu
|
||||
apispec==6.3.0
|
||||
# via flask-appbuilder
|
||||
apsw==3.46.0.0
|
||||
apispec==6.6.1
|
||||
# via
|
||||
# -r requirements/base.in
|
||||
# flask-appbuilder
|
||||
apsw==3.49.1.0
|
||||
# via shillelagh
|
||||
async-timeout==4.0.3
|
||||
# via
|
||||
# -r requirements/base.in
|
||||
# redis
|
||||
attrs==24.2.0
|
||||
attrs==25.3.0
|
||||
# via
|
||||
# cattrs
|
||||
# jsonschema
|
||||
# outcome
|
||||
# referencing
|
||||
# requests-cache
|
||||
# trio
|
||||
babel==2.16.0
|
||||
babel==2.17.0
|
||||
# via flask-babel
|
||||
backoff==2.2.1
|
||||
# via apache-superset (pyproject.toml)
|
||||
@@ -37,13 +40,13 @@ cachelib==0.13.0
|
||||
# via
|
||||
# flask-caching
|
||||
# flask-session
|
||||
cachetools==5.5.0
|
||||
cachetools==5.5.2
|
||||
# via google-auth
|
||||
cattrs==24.1.2
|
||||
# via requests-cache
|
||||
celery==5.4.0
|
||||
# via apache-superset (pyproject.toml)
|
||||
certifi==2024.8.30
|
||||
certifi==2025.1.31
|
||||
# via
|
||||
# requests
|
||||
# selenium
|
||||
@@ -51,7 +54,7 @@ cffi==1.17.1
|
||||
# via
|
||||
# cryptography
|
||||
# pynacl
|
||||
charset-normalizer==3.4.0
|
||||
charset-normalizer==3.4.1
|
||||
# via requests
|
||||
click==8.1.8
|
||||
# via
|
||||
@@ -65,7 +68,7 @@ click==8.1.8
|
||||
# flask-appbuilder
|
||||
click-didyoumean==0.3.1
|
||||
# via celery
|
||||
click-option-group==0.5.6
|
||||
click-option-group==0.5.7
|
||||
# via apache-superset (pyproject.toml)
|
||||
click-plugins==1.1.1
|
||||
# via celery
|
||||
@@ -86,7 +89,7 @@ cryptography==44.0.2
|
||||
# pyopenssl
|
||||
defusedxml==0.7.1
|
||||
# via odfpy
|
||||
deprecated==1.2.15
|
||||
deprecated==1.2.18
|
||||
# via limits
|
||||
deprecation==2.1.0
|
||||
# via apache-superset (pyproject.toml)
|
||||
@@ -115,7 +118,7 @@ flask==2.3.3
|
||||
# flask-session
|
||||
# flask-sqlalchemy
|
||||
# flask-wtf
|
||||
flask-appbuilder==4.6.0
|
||||
flask-appbuilder==4.6.1
|
||||
# via apache-superset (pyproject.toml)
|
||||
flask-babel==2.0.0
|
||||
# via flask-appbuilder
|
||||
@@ -125,7 +128,7 @@ flask-compress==1.17
|
||||
# via apache-superset (pyproject.toml)
|
||||
flask-jwt-extended==4.7.1
|
||||
# via flask-appbuilder
|
||||
flask-limiter==3.8.0
|
||||
flask-limiter==3.12
|
||||
# via flask-appbuilder
|
||||
flask-login==0.6.3
|
||||
# via
|
||||
@@ -149,13 +152,12 @@ geographiclib==2.0
|
||||
# via geopy
|
||||
geopy==2.4.1
|
||||
# via apache-superset (pyproject.toml)
|
||||
google-auth==2.36.0
|
||||
google-auth==2.38.0
|
||||
# via shillelagh
|
||||
greenlet==3.1.1
|
||||
# via
|
||||
# apache-superset (pyproject.toml)
|
||||
# shillelagh
|
||||
# sqlalchemy
|
||||
gunicorn==23.0.0
|
||||
# via apache-superset (pyproject.toml)
|
||||
h11==0.14.0
|
||||
@@ -164,7 +166,7 @@ hashids==1.3.1
|
||||
# via apache-superset (pyproject.toml)
|
||||
holidays==0.25
|
||||
# via apache-superset (pyproject.toml)
|
||||
humanize==4.12.1
|
||||
humanize==4.12.2
|
||||
# via apache-superset (pyproject.toml)
|
||||
idna==3.10
|
||||
# via
|
||||
@@ -173,8 +175,6 @@ idna==3.10
|
||||
# trio
|
||||
importlib-metadata==8.6.1
|
||||
# via apache-superset (pyproject.toml)
|
||||
importlib-resources==6.4.5
|
||||
# via limits
|
||||
isodate==0.7.2
|
||||
# via apache-superset (pyproject.toml)
|
||||
itsdangerous==2.2.0
|
||||
@@ -187,13 +187,15 @@ jinja2==3.1.6
|
||||
# flask-babel
|
||||
jsonpath-ng==1.7.0
|
||||
# via apache-superset (pyproject.toml)
|
||||
jsonschema==4.17.3
|
||||
jsonschema==4.23.0
|
||||
# via flask-appbuilder
|
||||
kombu==5.4.2
|
||||
jsonschema-specifications==2024.10.1
|
||||
# via jsonschema
|
||||
kombu==5.5.0
|
||||
# via celery
|
||||
korean-lunar-calendar==0.3.1
|
||||
# via holidays
|
||||
limits==3.13.0
|
||||
limits==4.4.1
|
||||
# via flask-limiter
|
||||
mako==1.3.9
|
||||
# via
|
||||
@@ -209,12 +211,14 @@ markupsafe==3.0.2
|
||||
# mako
|
||||
# werkzeug
|
||||
# wtforms
|
||||
marshmallow==3.23.1
|
||||
marshmallow==3.26.1
|
||||
# via
|
||||
# flask-appbuilder
|
||||
# marshmallow-sqlalchemy
|
||||
marshmallow-sqlalchemy==0.28.2
|
||||
# via flask-appbuilder
|
||||
marshmallow-sqlalchemy==1.4.0
|
||||
# via
|
||||
# -r requirements/base.in
|
||||
# flask-appbuilder
|
||||
mdurl==0.1.2
|
||||
# via markdown-it-py
|
||||
msgpack==1.0.8
|
||||
@@ -248,7 +252,6 @@ packaging==24.2
|
||||
# gunicorn
|
||||
# limits
|
||||
# marshmallow
|
||||
# marshmallow-sqlalchemy
|
||||
# shillelagh
|
||||
pandas==2.0.3
|
||||
# via apache-superset (pyproject.toml)
|
||||
@@ -260,7 +263,7 @@ parsedatetime==2.6
|
||||
# via apache-superset (pyproject.toml)
|
||||
pgsanity==0.2.9
|
||||
# via apache-superset (pyproject.toml)
|
||||
platformdirs==3.9.1
|
||||
platformdirs==4.3.7
|
||||
# via requests-cache
|
||||
ply==3.11
|
||||
# via jsonpath-ng
|
||||
@@ -280,7 +283,7 @@ pyasn1-modules==0.4.1
|
||||
# via google-auth
|
||||
pycparser==2.22
|
||||
# via cffi
|
||||
pygments==2.18.0
|
||||
pygments==2.19.1
|
||||
# via rich
|
||||
pyjwt==2.10.1
|
||||
# via
|
||||
@@ -291,10 +294,8 @@ pynacl==1.5.0
|
||||
# via paramiko
|
||||
pyopenssl==25.0.0
|
||||
# via shillelagh
|
||||
pyparsing==3.2.1
|
||||
pyparsing==3.2.2
|
||||
# via apache-superset (pyproject.toml)
|
||||
pyrsistent==0.20.0
|
||||
# via jsonschema
|
||||
pysocks==1.7.1
|
||||
# via urllib3
|
||||
python-dateutil==2.9.0.post0
|
||||
@@ -323,19 +324,27 @@ pyyaml==6.0.2
|
||||
# apispec
|
||||
redis==4.6.0
|
||||
# via apache-superset (pyproject.toml)
|
||||
requests==2.32.2
|
||||
referencing==0.36.2
|
||||
# via
|
||||
# jsonschema
|
||||
# jsonschema-specifications
|
||||
requests==2.32.3
|
||||
# via
|
||||
# requests-cache
|
||||
# shillelagh
|
||||
requests-cache==1.2.0
|
||||
requests-cache==1.2.1
|
||||
# via shillelagh
|
||||
rich==13.9.4
|
||||
# via flask-limiter
|
||||
rpds-py==0.23.1
|
||||
# via
|
||||
# jsonschema
|
||||
# referencing
|
||||
rsa==4.9
|
||||
# via google-auth
|
||||
selenium==4.27.1
|
||||
# via apache-superset (pyproject.toml)
|
||||
shillelagh==1.2.18
|
||||
shillelagh==1.3.5
|
||||
# via apache-superset (pyproject.toml)
|
||||
simplejson==3.20.1
|
||||
# via apache-superset (pyproject.toml)
|
||||
@@ -345,7 +354,7 @@ six==1.17.0
|
||||
# python-dateutil
|
||||
# url-normalize
|
||||
# wtforms-json
|
||||
slack-sdk==3.34.0
|
||||
slack-sdk==3.35.0
|
||||
# via apache-superset (pyproject.toml)
|
||||
sniffio==1.3.1
|
||||
# via trio
|
||||
@@ -364,7 +373,7 @@ sqlalchemy-utils==0.38.3
|
||||
# via
|
||||
# apache-superset (pyproject.toml)
|
||||
# flask-appbuilder
|
||||
sqlglot==26.1.3
|
||||
sqlglot==26.11.1
|
||||
# via apache-superset (pyproject.toml)
|
||||
sqlparse==0.5.3
|
||||
# via apache-superset (pyproject.toml)
|
||||
@@ -383,9 +392,9 @@ typing-extensions==4.12.2
|
||||
# apache-superset (pyproject.toml)
|
||||
# alembic
|
||||
# cattrs
|
||||
# flask-limiter
|
||||
# limits
|
||||
# pyopenssl
|
||||
# referencing
|
||||
# rich
|
||||
# selenium
|
||||
# shillelagh
|
||||
@@ -418,7 +427,7 @@ werkzeug==3.1.3
|
||||
# flask-appbuilder
|
||||
# flask-jwt-extended
|
||||
# flask-login
|
||||
wrapt==1.17.0
|
||||
wrapt==1.17.2
|
||||
# via deprecated
|
||||
wsproto==1.2.0
|
||||
# via trio-websocket
|
||||
|
||||
@@ -10,11 +10,11 @@ amqp==5.3.1
|
||||
# via
|
||||
# -c requirements/base.txt
|
||||
# kombu
|
||||
apispec==6.3.0
|
||||
apispec==6.6.1
|
||||
# via
|
||||
# -c requirements/base.txt
|
||||
# flask-appbuilder
|
||||
apsw==3.46.0.0
|
||||
apsw==3.49.1.0
|
||||
# via
|
||||
# -c requirements/base.txt
|
||||
# shillelagh
|
||||
@@ -22,15 +22,16 @@ async-timeout==4.0.3
|
||||
# via
|
||||
# -c requirements/base.txt
|
||||
# redis
|
||||
attrs==24.2.0
|
||||
attrs==25.3.0
|
||||
# via
|
||||
# -c requirements/base.txt
|
||||
# cattrs
|
||||
# jsonschema
|
||||
# outcome
|
||||
# referencing
|
||||
# requests-cache
|
||||
# trio
|
||||
babel==2.16.0
|
||||
babel==2.17.0
|
||||
# via
|
||||
# -c requirements/base.txt
|
||||
# flask-babel
|
||||
@@ -63,7 +64,7 @@ cachelib==0.13.0
|
||||
# -c requirements/base.txt
|
||||
# flask-caching
|
||||
# flask-session
|
||||
cachetools==5.5.0
|
||||
cachetools==5.5.2
|
||||
# via
|
||||
# -c requirements/base.txt
|
||||
# google-auth
|
||||
@@ -75,7 +76,7 @@ celery==5.4.0
|
||||
# via
|
||||
# -c requirements/base.txt
|
||||
# apache-superset
|
||||
certifi==2024.8.30
|
||||
certifi==2025.1.31
|
||||
# via
|
||||
# -c requirements/base.txt
|
||||
# requests
|
||||
@@ -87,7 +88,7 @@ cffi==1.17.1
|
||||
# pynacl
|
||||
cfgv==3.4.0
|
||||
# via pre-commit
|
||||
charset-normalizer==3.4.0
|
||||
charset-normalizer==3.4.1
|
||||
# via
|
||||
# -c requirements/base.txt
|
||||
# requests
|
||||
@@ -106,7 +107,7 @@ click-didyoumean==0.3.1
|
||||
# via
|
||||
# -c requirements/base.txt
|
||||
# celery
|
||||
click-option-group==0.5.6
|
||||
click-option-group==0.5.7
|
||||
# via
|
||||
# -c requirements/base.txt
|
||||
# apache-superset
|
||||
@@ -151,7 +152,7 @@ defusedxml==0.7.1
|
||||
# via
|
||||
# -c requirements/base.txt
|
||||
# odfpy
|
||||
deprecated==1.2.15
|
||||
deprecated==1.2.18
|
||||
# via
|
||||
# -c requirements/base.txt
|
||||
# limits
|
||||
@@ -201,7 +202,7 @@ flask==2.3.3
|
||||
# flask-sqlalchemy
|
||||
# flask-testing
|
||||
# flask-wtf
|
||||
flask-appbuilder==4.6.0
|
||||
flask-appbuilder==4.6.1
|
||||
# via
|
||||
# -c requirements/base.txt
|
||||
# apache-superset
|
||||
@@ -223,7 +224,7 @@ flask-jwt-extended==4.7.1
|
||||
# via
|
||||
# -c requirements/base.txt
|
||||
# flask-appbuilder
|
||||
flask-limiter==3.8.0
|
||||
flask-limiter==3.12
|
||||
# via
|
||||
# -c requirements/base.txt
|
||||
# flask-appbuilder
|
||||
@@ -279,7 +280,7 @@ google-api-core==2.23.0
|
||||
# google-cloud-core
|
||||
# pandas-gbq
|
||||
# sqlalchemy-bigquery
|
||||
google-auth==2.36.0
|
||||
google-auth==2.38.0
|
||||
# via
|
||||
# -c requirements/base.txt
|
||||
# google-api-core
|
||||
@@ -317,8 +318,7 @@ greenlet==3.1.1
|
||||
# apache-superset
|
||||
# gevent
|
||||
# shillelagh
|
||||
# sqlalchemy
|
||||
grpcio==1.68.0
|
||||
grpcio==1.71.0
|
||||
# via
|
||||
# apache-superset
|
||||
# google-api-core
|
||||
@@ -342,7 +342,7 @@ holidays==0.25
|
||||
# -c requirements/base.txt
|
||||
# apache-superset
|
||||
# prophet
|
||||
humanize==4.12.1
|
||||
humanize==4.12.2
|
||||
# via
|
||||
# -c requirements/base.txt
|
||||
# apache-superset
|
||||
@@ -358,11 +358,8 @@ importlib-metadata==8.6.1
|
||||
# via
|
||||
# -c requirements/base.txt
|
||||
# apache-superset
|
||||
importlib-resources==6.4.5
|
||||
# via
|
||||
# -c requirements/base.txt
|
||||
# limits
|
||||
# prophet
|
||||
importlib-resources==6.5.2
|
||||
# via prophet
|
||||
iniconfig==2.0.0
|
||||
# via pytest
|
||||
isodate==0.7.2
|
||||
@@ -383,18 +380,22 @@ jsonpath-ng==1.7.0
|
||||
# via
|
||||
# -c requirements/base.txt
|
||||
# apache-superset
|
||||
jsonschema==4.17.3
|
||||
jsonschema==4.23.0
|
||||
# via
|
||||
# -c requirements/base.txt
|
||||
# flask-appbuilder
|
||||
# jsonschema-spec
|
||||
# openapi-schema-validator
|
||||
# openapi-spec-validator
|
||||
jsonschema-spec==0.1.6
|
||||
jsonschema-path==0.3.4
|
||||
# via openapi-spec-validator
|
||||
jsonschema-specifications==2024.10.1
|
||||
# via
|
||||
# -c requirements/base.txt
|
||||
# jsonschema
|
||||
# openapi-schema-validator
|
||||
kiwisolver==1.4.7
|
||||
# via matplotlib
|
||||
kombu==5.4.2
|
||||
kombu==5.5.0
|
||||
# via
|
||||
# -c requirements/base.txt
|
||||
# celery
|
||||
@@ -404,7 +405,7 @@ korean-lunar-calendar==0.3.1
|
||||
# holidays
|
||||
lazy-object-proxy==1.10.0
|
||||
# via openapi-spec-validator
|
||||
limits==3.13.0
|
||||
limits==4.4.1
|
||||
# via
|
||||
# -c requirements/base.txt
|
||||
# flask-limiter
|
||||
@@ -428,12 +429,12 @@ markupsafe==3.0.2
|
||||
# mako
|
||||
# werkzeug
|
||||
# wtforms
|
||||
marshmallow==3.23.1
|
||||
marshmallow==3.26.1
|
||||
# via
|
||||
# -c requirements/base.txt
|
||||
# flask-appbuilder
|
||||
# marshmallow-sqlalchemy
|
||||
marshmallow-sqlalchemy==0.28.2
|
||||
marshmallow-sqlalchemy==1.4.0
|
||||
# via
|
||||
# -c requirements/base.txt
|
||||
# flask-appbuilder
|
||||
@@ -478,9 +479,9 @@ odfpy==1.4.1
|
||||
# via
|
||||
# -c requirements/base.txt
|
||||
# pandas
|
||||
openapi-schema-validator==0.4.4
|
||||
openapi-schema-validator==0.6.3
|
||||
# via openapi-spec-validator
|
||||
openapi-spec-validator==0.5.6
|
||||
openapi-spec-validator==0.7.1
|
||||
# via apache-superset
|
||||
openpyxl==3.1.5
|
||||
# via
|
||||
@@ -506,7 +507,6 @@ packaging==24.2
|
||||
# gunicorn
|
||||
# limits
|
||||
# marshmallow
|
||||
# marshmallow-sqlalchemy
|
||||
# matplotlib
|
||||
# pytest
|
||||
# shillelagh
|
||||
@@ -533,7 +533,7 @@ parsedatetime==2.6
|
||||
# -c requirements/base.txt
|
||||
# apache-superset
|
||||
pathable==0.4.3
|
||||
# via jsonschema-spec
|
||||
# via jsonschema-path
|
||||
pgsanity==0.2.9
|
||||
# via
|
||||
# -c requirements/base.txt
|
||||
@@ -542,7 +542,7 @@ pillow==10.3.0
|
||||
# via
|
||||
# apache-superset
|
||||
# matplotlib
|
||||
platformdirs==3.9.1
|
||||
platformdirs==4.3.7
|
||||
# via
|
||||
# -c requirements/base.txt
|
||||
# requests-cache
|
||||
@@ -613,7 +613,7 @@ pydruid==0.6.9
|
||||
# via apache-superset
|
||||
pyfakefs==5.3.5
|
||||
# via apache-superset
|
||||
pygments==2.18.0
|
||||
pygments==2.19.1
|
||||
# via
|
||||
# -c requirements/base.txt
|
||||
# rich
|
||||
@@ -635,15 +635,11 @@ pyopenssl==25.0.0
|
||||
# via
|
||||
# -c requirements/base.txt
|
||||
# shillelagh
|
||||
pyparsing==3.2.1
|
||||
pyparsing==3.2.2
|
||||
# via
|
||||
# -c requirements/base.txt
|
||||
# apache-superset
|
||||
# matplotlib
|
||||
pyrsistent==0.20.0
|
||||
# via
|
||||
# -c requirements/base.txt
|
||||
# jsonschema
|
||||
pysocks==1.7.1
|
||||
# via
|
||||
# -c requirements/base.txt
|
||||
@@ -698,26 +694,32 @@ pyyaml==6.0.2
|
||||
# -c requirements/base.txt
|
||||
# apache-superset
|
||||
# apispec
|
||||
# jsonschema-spec
|
||||
# jsonschema-path
|
||||
# pre-commit
|
||||
redis==4.6.0
|
||||
# via
|
||||
# -c requirements/base.txt
|
||||
# apache-superset
|
||||
requests==2.32.2
|
||||
referencing==0.36.2
|
||||
# via
|
||||
# -c requirements/base.txt
|
||||
# jsonschema
|
||||
# jsonschema-path
|
||||
# jsonschema-specifications
|
||||
requests==2.32.3
|
||||
# via
|
||||
# -c requirements/base.txt
|
||||
# docker
|
||||
# google-api-core
|
||||
# google-cloud-bigquery
|
||||
# jsonschema-spec
|
||||
# jsonschema-path
|
||||
# pydruid
|
||||
# pyhive
|
||||
# requests-cache
|
||||
# requests-oauthlib
|
||||
# shillelagh
|
||||
# trino
|
||||
requests-cache==1.2.0
|
||||
requests-cache==1.2.1
|
||||
# via
|
||||
# -c requirements/base.txt
|
||||
# shillelagh
|
||||
@@ -729,6 +731,11 @@ rich==13.9.4
|
||||
# via
|
||||
# -c requirements/base.txt
|
||||
# flask-limiter
|
||||
rpds-py==0.23.1
|
||||
# via
|
||||
# -c requirements/base.txt
|
||||
# jsonschema
|
||||
# referencing
|
||||
rsa==4.9
|
||||
# via
|
||||
# -c requirements/base.txt
|
||||
@@ -746,7 +753,7 @@ setuptools==75.6.0
|
||||
# pydata-google-auth
|
||||
# zope-event
|
||||
# zope-interface
|
||||
shillelagh==1.2.18
|
||||
shillelagh==1.3.5
|
||||
# via
|
||||
# -c requirements/base.txt
|
||||
# apache-superset
|
||||
@@ -762,7 +769,7 @@ six==1.17.0
|
||||
# rfc3339-validator
|
||||
# url-normalize
|
||||
# wtforms-json
|
||||
slack-sdk==3.34.0
|
||||
slack-sdk==3.35.0
|
||||
# via
|
||||
# -c requirements/base.txt
|
||||
# apache-superset
|
||||
@@ -792,7 +799,7 @@ sqlalchemy-utils==0.38.3
|
||||
# -c requirements/base.txt
|
||||
# apache-superset
|
||||
# flask-appbuilder
|
||||
sqlglot==26.1.3
|
||||
sqlglot==26.11.1
|
||||
# via
|
||||
# -c requirements/base.txt
|
||||
# apache-superset
|
||||
@@ -837,9 +844,9 @@ typing-extensions==4.12.2
|
||||
# alembic
|
||||
# apache-superset
|
||||
# cattrs
|
||||
# flask-limiter
|
||||
# limits
|
||||
# pyopenssl
|
||||
# referencing
|
||||
# rich
|
||||
# selenium
|
||||
# shillelagh
|
||||
@@ -885,7 +892,7 @@ werkzeug==3.1.3
|
||||
# flask-appbuilder
|
||||
# flask-jwt-extended
|
||||
# flask-login
|
||||
wrapt==1.17.0
|
||||
wrapt==1.17.2
|
||||
# via
|
||||
# -c requirements/base.txt
|
||||
# deprecated
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# This file was autogenerated by uv via the following command:
|
||||
# uv pip compile requirements/translations.in -o requirements/translations.txt
|
||||
babel==2.16.0
|
||||
babel==2.17.0
|
||||
# via -r requirements/translations.in
|
||||
|
||||
1
setup.py
1
setup.py
@@ -52,6 +52,7 @@ with open(VERSION_INFO_FILE, "w") as version_file:
|
||||
version_string = version_string.replace("-dev", ".dev0")
|
||||
|
||||
setup(
|
||||
name="apache_superset",
|
||||
version=version_string,
|
||||
packages=find_packages(),
|
||||
include_package_data=True,
|
||||
|
||||
@@ -60,7 +60,9 @@ embedDashboard({
|
||||
}
|
||||
},
|
||||
// optional additional iframe sandbox attributes
|
||||
iframeSandboxExtras: ['allow-top-navigation', 'allow-popups-to-escape-sandbox']
|
||||
iframeSandboxExtras: ['allow-top-navigation', 'allow-popups-to-escape-sandbox'],
|
||||
// optional config to enforce a particular referrerPolicy
|
||||
referrerPolicy: "same-origin"
|
||||
});
|
||||
```
|
||||
|
||||
@@ -146,3 +148,11 @@ To pass additional sandbox attributes you can use `iframeSandboxExtras`:
|
||||
// optional additional iframe sandbox attributes
|
||||
iframeSandboxExtras: ['allow-top-navigation', 'allow-popups-to-escape-sandbox']
|
||||
```
|
||||
|
||||
### Enforcing a ReferrerPolicy on the request triggered by the iframe
|
||||
|
||||
By default, the Embedded SDK creates an `iframe` element without a `referrerPolicy` value enforced. This means that a policy defined for `iframe` elements at the host app level would reflect to it.
|
||||
|
||||
This can be an issue as during the embedded enablement for a dashboard it's possible to specify which domain(s) are allowed to embed the dashboard, and this validation happens throuth the `Referrer` header. That said, in case the hosting app has a more restrictive policy that would omit this header, this validation would fail.
|
||||
|
||||
Use the `referrerPolicy` parameter in the `embedDashboard` method to specify [a particular policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Referrer-Policy) that works for your implementation.
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
import {
|
||||
DASHBOARD_UI_FILTER_CONFIG_URL_PARAM_KEY,
|
||||
IFRAME_COMMS_MESSAGE_TYPE
|
||||
IFRAME_COMMS_MESSAGE_TYPE,
|
||||
} from './const';
|
||||
|
||||
// We can swap this out for the actual switchboard package once it gets published
|
||||
@@ -34,48 +34,62 @@ import { getGuestTokenRefreshTiming } from './guestTokenRefresh';
|
||||
export type GuestTokenFetchFn = () => Promise<string>;
|
||||
|
||||
export type UiConfigType = {
|
||||
hideTitle?: boolean
|
||||
hideTab?: boolean
|
||||
hideChartControls?: boolean
|
||||
hideTitle?: boolean;
|
||||
hideTab?: boolean;
|
||||
hideChartControls?: boolean;
|
||||
emitDataMasks?: boolean;
|
||||
filters?: {
|
||||
[key: string]: boolean | undefined
|
||||
visible?: boolean
|
||||
expanded?: boolean
|
||||
}
|
||||
[key: string]: boolean | undefined;
|
||||
visible?: boolean;
|
||||
expanded?: boolean;
|
||||
};
|
||||
urlParams?: {
|
||||
[key: string]: any
|
||||
}
|
||||
}
|
||||
[key: string]: any;
|
||||
};
|
||||
};
|
||||
|
||||
export type EmbedDashboardParams = {
|
||||
/** The id provided by the embed configuration UI in Superset */
|
||||
id: string
|
||||
id: string;
|
||||
/** The domain where Superset can be located, with protocol, such as: https://superset.example.com */
|
||||
supersetDomain: string
|
||||
supersetDomain: string;
|
||||
/** The html element within which to mount the iframe */
|
||||
mountPoint: HTMLElement
|
||||
mountPoint: HTMLElement;
|
||||
/** A function to fetch a guest token from the Host App's backend server */
|
||||
fetchGuestToken: GuestTokenFetchFn
|
||||
fetchGuestToken: GuestTokenFetchFn;
|
||||
/** The dashboard UI config: hideTitle, hideTab, hideChartControls, filters.visible, filters.expanded **/
|
||||
dashboardUiConfig?: UiConfigType
|
||||
dashboardUiConfig?: UiConfigType;
|
||||
/** Are we in debug mode? */
|
||||
debug?: boolean
|
||||
debug?: boolean;
|
||||
/** The iframe title attribute */
|
||||
iframeTitle?: string
|
||||
iframeTitle?: string;
|
||||
/** additional iframe sandbox attributes ex (allow-top-navigation, allow-popups-to-escape-sandbox) **/
|
||||
iframeSandboxExtras?: string[]
|
||||
}
|
||||
iframeSandboxExtras?: string[];
|
||||
/** force a specific refererPolicy to be used in the iframe request **/
|
||||
referrerPolicy?: ReferrerPolicy;
|
||||
};
|
||||
|
||||
export type Size = {
|
||||
width: number, height: number
|
||||
}
|
||||
width: number;
|
||||
height: number;
|
||||
};
|
||||
|
||||
export type ObserveDataMaskCallbackFn = (
|
||||
dataMask: Record<string, any> & {
|
||||
crossFiltersChanged: boolean;
|
||||
nativeFiltersChanged: boolean;
|
||||
},
|
||||
) => void;
|
||||
export type EmbeddedDashboard = {
|
||||
getScrollSize: () => Promise<Size>
|
||||
unmount: () => void
|
||||
getDashboardPermalink: (anchor: string) => Promise<string>
|
||||
getActiveTabs: () => Promise<string[]>
|
||||
}
|
||||
getScrollSize: () => Promise<Size>;
|
||||
unmount: () => void;
|
||||
getDashboardPermalink: (anchor: string) => Promise<string>;
|
||||
getActiveTabs: () => Promise<string[]>;
|
||||
observeDataMask: (
|
||||
callbackFn: ObserveDataMaskCallbackFn,
|
||||
) => void;
|
||||
getDataMask: () => Record<string, any>;
|
||||
};
|
||||
|
||||
/**
|
||||
* Embeds a Superset dashboard into the page using an iframe.
|
||||
@@ -87,8 +101,9 @@ export async function embedDashboard({
|
||||
fetchGuestToken,
|
||||
dashboardUiConfig,
|
||||
debug = false,
|
||||
iframeTitle = "Embedded Dashboard",
|
||||
iframeSandboxExtras = []
|
||||
iframeTitle = 'Embedded Dashboard',
|
||||
iframeSandboxExtras = [],
|
||||
referrerPolicy,
|
||||
}: EmbedDashboardParams): Promise<EmbeddedDashboard> {
|
||||
function log(...info: unknown[]) {
|
||||
if (debug) {
|
||||
@@ -98,50 +113,69 @@ export async function embedDashboard({
|
||||
|
||||
log('embedding');
|
||||
|
||||
if (supersetDomain.endsWith("/")) {
|
||||
if (supersetDomain.endsWith('/')) {
|
||||
supersetDomain = supersetDomain.slice(0, -1);
|
||||
}
|
||||
|
||||
function calculateConfig() {
|
||||
let configNumber = 0
|
||||
if(dashboardUiConfig) {
|
||||
if(dashboardUiConfig.hideTitle) {
|
||||
configNumber += 1
|
||||
let configNumber = 0;
|
||||
if (dashboardUiConfig) {
|
||||
if (dashboardUiConfig.hideTitle) {
|
||||
configNumber += 1;
|
||||
}
|
||||
if(dashboardUiConfig.hideTab) {
|
||||
configNumber += 2
|
||||
if (dashboardUiConfig.hideTab) {
|
||||
configNumber += 2;
|
||||
}
|
||||
if(dashboardUiConfig.hideChartControls) {
|
||||
configNumber += 8
|
||||
if (dashboardUiConfig.hideChartControls) {
|
||||
configNumber += 8;
|
||||
}
|
||||
if (dashboardUiConfig.emitDataMasks) {
|
||||
configNumber += 16;
|
||||
}
|
||||
}
|
||||
return configNumber
|
||||
return configNumber;
|
||||
}
|
||||
|
||||
async function mountIframe(): Promise<Switchboard> {
|
||||
return new Promise(resolve => {
|
||||
const iframe = document.createElement('iframe');
|
||||
const dashboardConfigUrlParams = dashboardUiConfig ? {uiConfig: `${calculateConfig()}`} : undefined;
|
||||
const filterConfig = dashboardUiConfig?.filters || {}
|
||||
const filterConfigKeys = Object.keys(filterConfig)
|
||||
const filterConfigUrlParams = Object.fromEntries(filterConfigKeys.map(
|
||||
key => [DASHBOARD_UI_FILTER_CONFIG_URL_PARAM_KEY[key], filterConfig[key]]))
|
||||
const dashboardConfigUrlParams = dashboardUiConfig
|
||||
? { uiConfig: `${calculateConfig()}` }
|
||||
: undefined;
|
||||
const filterConfig = dashboardUiConfig?.filters || {};
|
||||
const filterConfigKeys = Object.keys(filterConfig);
|
||||
const filterConfigUrlParams = Object.fromEntries(
|
||||
filterConfigKeys.map(key => [
|
||||
DASHBOARD_UI_FILTER_CONFIG_URL_PARAM_KEY[key],
|
||||
filterConfig[key],
|
||||
]),
|
||||
);
|
||||
|
||||
// Allow url query parameters from dashboardUiConfig.urlParams to override the ones from filterConfig
|
||||
const urlParams = {...dashboardConfigUrlParams, ...filterConfigUrlParams, ...dashboardUiConfig?.urlParams}
|
||||
const urlParamsString = Object.keys(urlParams).length ? '?' + new URLSearchParams(urlParams).toString() : ''
|
||||
const urlParams = {
|
||||
...dashboardConfigUrlParams,
|
||||
...filterConfigUrlParams,
|
||||
...dashboardUiConfig?.urlParams,
|
||||
};
|
||||
const urlParamsString = Object.keys(urlParams).length
|
||||
? '?' + new URLSearchParams(urlParams).toString()
|
||||
: '';
|
||||
|
||||
// set up the iframe's sandbox configuration
|
||||
iframe.sandbox.add("allow-same-origin"); // needed for postMessage to work
|
||||
iframe.sandbox.add("allow-scripts"); // obviously the iframe needs scripts
|
||||
iframe.sandbox.add("allow-presentation"); // for fullscreen charts
|
||||
iframe.sandbox.add("allow-downloads"); // for downloading charts as image
|
||||
iframe.sandbox.add("allow-forms"); // for forms to submit
|
||||
iframe.sandbox.add("allow-popups"); // for exporting charts as csv
|
||||
iframe.sandbox.add('allow-same-origin'); // needed for postMessage to work
|
||||
iframe.sandbox.add('allow-scripts'); // obviously the iframe needs scripts
|
||||
iframe.sandbox.add('allow-presentation'); // for fullscreen charts
|
||||
iframe.sandbox.add('allow-downloads'); // for downloading charts as image
|
||||
iframe.sandbox.add('allow-forms'); // for forms to submit
|
||||
iframe.sandbox.add('allow-popups'); // for exporting charts as csv
|
||||
// additional sandbox props
|
||||
iframeSandboxExtras.forEach((key: string) => {
|
||||
iframe.sandbox.add(key);
|
||||
});
|
||||
// force a specific refererPolicy to be used in the iframe request
|
||||
if (referrerPolicy) {
|
||||
iframe.referrerPolicy = referrerPolicy;
|
||||
}
|
||||
|
||||
// add the event listener before setting src, to be 100% sure that we capture the load event
|
||||
iframe.addEventListener('load', () => {
|
||||
@@ -155,20 +189,26 @@ export async function embedDashboard({
|
||||
// See https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage
|
||||
// we know the content window isn't null because we are in the load event handler.
|
||||
iframe.contentWindow!.postMessage(
|
||||
{ type: IFRAME_COMMS_MESSAGE_TYPE, handshake: "port transfer" },
|
||||
{ type: IFRAME_COMMS_MESSAGE_TYPE, handshake: 'port transfer' },
|
||||
supersetDomain,
|
||||
[theirPort],
|
||||
)
|
||||
);
|
||||
log('sent message channel to the iframe');
|
||||
|
||||
// return our port from the promise
|
||||
resolve(new Switchboard({ port: ourPort, name: 'superset-embedded-sdk', debug }));
|
||||
resolve(
|
||||
new Switchboard({
|
||||
port: ourPort,
|
||||
name: 'superset-embedded-sdk',
|
||||
debug,
|
||||
}),
|
||||
);
|
||||
});
|
||||
iframe.src = `${supersetDomain}/embedded/${id}${urlParamsString}`;
|
||||
iframe.title = iframeTitle;
|
||||
//@ts-ignore
|
||||
mountPoint.replaceChildren(iframe);
|
||||
log('placed the iframe')
|
||||
log('placed the iframe');
|
||||
});
|
||||
}
|
||||
|
||||
@@ -197,12 +237,21 @@ export async function embedDashboard({
|
||||
const getScrollSize = () => ourPort.get<Size>('getScrollSize');
|
||||
const getDashboardPermalink = (anchor: string) =>
|
||||
ourPort.get<string>('getDashboardPermalink', { anchor });
|
||||
const getActiveTabs = () => ourPort.get<string[]>('getActiveTabs')
|
||||
const getActiveTabs = () => ourPort.get<string[]>('getActiveTabs');
|
||||
const getDataMask = () => ourPort.get<Record<string, any>>('getDataMask');
|
||||
const observeDataMask = (
|
||||
callbackFn: ObserveDataMaskCallbackFn,
|
||||
) => {
|
||||
ourPort.start();
|
||||
ourPort.defineMethod('observeDataMask', callbackFn);
|
||||
};
|
||||
|
||||
return {
|
||||
getScrollSize,
|
||||
unmount,
|
||||
getDashboardPermalink,
|
||||
getActiveTabs,
|
||||
observeDataMask,
|
||||
getDataMask,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -36,6 +36,45 @@ if (process.env.NODE_ENV === 'production') {
|
||||
];
|
||||
}
|
||||
|
||||
const restrictedImportsRules = {
|
||||
'no-design-icons': {
|
||||
name: '@ant-design/icons',
|
||||
message:
|
||||
'Avoid importing icons directly from @ant-design/icons. Use the src/components/Icons component instead.',
|
||||
},
|
||||
'no-moment': {
|
||||
name: 'moment',
|
||||
message:
|
||||
'Please use the dayjs library instead of moment.js. See https://day.js.org',
|
||||
},
|
||||
'no-lodash-memoize': {
|
||||
name: 'lodash/memoize',
|
||||
message: 'Lodash Memoize is unsafe! Please use memoize-one instead',
|
||||
},
|
||||
'no-testing-library-react': {
|
||||
name: '@testing-library/react',
|
||||
message: 'Please use spec/helpers/testing-library instead',
|
||||
},
|
||||
'no-testing-library-react-dom-utils': {
|
||||
name: '@testing-library/react-dom-utils',
|
||||
message: 'Please use spec/helpers/testing-library instead',
|
||||
},
|
||||
'no-antd': {
|
||||
name: 'antd',
|
||||
message: 'Please import Ant components from the index of src/components',
|
||||
},
|
||||
'no-antd-v5': {
|
||||
name: 'antd-v5',
|
||||
message: 'Please import Ant v5 components from the index of src/components',
|
||||
},
|
||||
'no-superset-theme': {
|
||||
name: '@superset-ui/core',
|
||||
importNames: ['supersetTheme'],
|
||||
message:
|
||||
'Please use the theme directly from the ThemeProvider rather than importing supersetTheme.',
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
extends: [
|
||||
'airbnb',
|
||||
@@ -74,6 +113,7 @@ module.exports = {
|
||||
'file-progress',
|
||||
'lodash',
|
||||
'theme-colors',
|
||||
'icons',
|
||||
'i18n-strings',
|
||||
'react-prefer-function-component',
|
||||
'prettier',
|
||||
@@ -200,6 +240,13 @@ module.exports = {
|
||||
message: 'Wildcard imports are not allowed',
|
||||
},
|
||||
],
|
||||
'no-restricted-imports': [
|
||||
'error',
|
||||
{
|
||||
paths: Object.values(restrictedImportsRules).filter(Boolean),
|
||||
patterns: ['antd/*'],
|
||||
},
|
||||
],
|
||||
},
|
||||
settings: {
|
||||
'import/resolver': {
|
||||
@@ -210,6 +257,51 @@ module.exports = {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['packages/**'],
|
||||
rules: {
|
||||
'no-restricted-imports': [
|
||||
'error',
|
||||
{
|
||||
paths: [
|
||||
restrictedImportsRules['no-moment'],
|
||||
restrictedImportsRules['no-lodash-memoize'],
|
||||
restrictedImportsRules['no-superset-theme'],
|
||||
],
|
||||
patterns: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['plugins/**'],
|
||||
rules: {
|
||||
'no-restricted-imports': [
|
||||
'error',
|
||||
{
|
||||
paths: [
|
||||
restrictedImportsRules['no-moment'],
|
||||
restrictedImportsRules['no-lodash-memoize'],
|
||||
],
|
||||
patterns: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['src/components/**', 'src/theme/**'],
|
||||
rules: {
|
||||
'no-restricted-imports': [
|
||||
'error',
|
||||
{
|
||||
paths: Object.values(restrictedImportsRules).filter(
|
||||
r => r.name !== 'antd-v5',
|
||||
),
|
||||
patterns: ['antd/*'],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
files: [
|
||||
'*.test.ts',
|
||||
@@ -267,6 +359,7 @@ module.exports = {
|
||||
'Default React import is not required due to automatic JSX runtime in React 16.4',
|
||||
},
|
||||
],
|
||||
'no-restricted-imports': 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -284,6 +377,7 @@ module.exports = {
|
||||
],
|
||||
rules: {
|
||||
'theme-colors/no-literal-colors': 0,
|
||||
'icons/no-fa-icons-usage': 0,
|
||||
'i18n-strings/no-template-vars': 0,
|
||||
'no-restricted-imports': 0,
|
||||
'react/no-void-elements': 0,
|
||||
@@ -292,6 +386,7 @@ module.exports = {
|
||||
],
|
||||
rules: {
|
||||
'theme-colors/no-literal-colors': 'error',
|
||||
'icons/no-fa-icons-usage': 'error',
|
||||
'i18n-strings/no-template-vars': ['error', true],
|
||||
camelcase: [
|
||||
'error',
|
||||
@@ -330,42 +425,6 @@ module.exports = {
|
||||
'no-nested-ternary': 0,
|
||||
'no-prototype-builtins': 0,
|
||||
'no-restricted-properties': 0,
|
||||
'no-restricted-imports': [
|
||||
'error',
|
||||
{
|
||||
paths: [
|
||||
{
|
||||
name: 'antd',
|
||||
message:
|
||||
'Please import Ant components from the index of src/components',
|
||||
},
|
||||
{
|
||||
name: 'antd-v5',
|
||||
message:
|
||||
'Please import Ant v5 components from the index of src/components',
|
||||
},
|
||||
{
|
||||
name: '@superset-ui/core',
|
||||
importNames: ['supersetTheme'],
|
||||
message:
|
||||
'Please use the theme directly from the ThemeProvider rather than importing supersetTheme.',
|
||||
},
|
||||
{
|
||||
name: 'lodash/memoize',
|
||||
message: 'Lodash Memoize is unsafe! Please use memoize-one instead',
|
||||
},
|
||||
{
|
||||
name: '@testing-library/react',
|
||||
message: 'Please use spec/helpers/testing-library instead',
|
||||
},
|
||||
{
|
||||
name: '@testing-library/react-dom-utils',
|
||||
message: 'Please use spec/helpers/testing-library instead',
|
||||
},
|
||||
],
|
||||
patterns: ['antd/*'],
|
||||
},
|
||||
],
|
||||
'no-shadow': 0, // re-enable up for discussion
|
||||
'padded-blocks': 0,
|
||||
'prefer-arrow-callback': 0,
|
||||
@@ -406,6 +465,13 @@ module.exports = {
|
||||
'no-promise-executor-return': 0,
|
||||
'react/no-unused-class-component-methods': 0,
|
||||
'react/react-in-jsx-scope': 0,
|
||||
'no-restricted-imports': [
|
||||
'error',
|
||||
{
|
||||
paths: Object.values(restrictedImportsRules).filter(Boolean),
|
||||
patterns: ['antd/*'],
|
||||
},
|
||||
],
|
||||
},
|
||||
ignorePatterns,
|
||||
};
|
||||
|
||||
@@ -28,7 +28,7 @@ describe('charts list view', () => {
|
||||
});
|
||||
|
||||
it('should load the Charts list', () => {
|
||||
cy.get('[aria-label="list-view"]').click();
|
||||
cy.get('[aria-label="unordered-list"]').click();
|
||||
cy.eyesOpen({
|
||||
testName: 'Charts list-view',
|
||||
});
|
||||
@@ -36,7 +36,7 @@ describe('charts list view', () => {
|
||||
});
|
||||
|
||||
it('should load the Charts card list', () => {
|
||||
cy.get('[aria-label="card-view"]').click();
|
||||
cy.get('[aria-label="appstore"]').click();
|
||||
cy.eyesOpen({
|
||||
testName: 'Charts card-view',
|
||||
});
|
||||
|
||||
@@ -28,7 +28,7 @@ describe('dashboard list view', () => {
|
||||
});
|
||||
|
||||
it('should load the Dashboards list', () => {
|
||||
cy.get('[aria-label="list-view"]').click();
|
||||
cy.get('[aria-label="unordered-list"]').click();
|
||||
cy.eyesOpen({
|
||||
testName: 'Dashboards list-view',
|
||||
});
|
||||
@@ -36,7 +36,7 @@ describe('dashboard list view', () => {
|
||||
});
|
||||
|
||||
it('should load the Dashboards card list', () => {
|
||||
cy.get('[aria-label="card-view"]').click();
|
||||
cy.get('[aria-label="appstore"]').click();
|
||||
cy.eyesOpen({
|
||||
testName: 'Dashboards card-view',
|
||||
});
|
||||
|
||||
@@ -35,12 +35,12 @@ function orderAlphabetical() {
|
||||
}
|
||||
|
||||
function openProperties() {
|
||||
cy.get('[aria-label="more-vert"]').eq(1).click();
|
||||
cy.get('[aria-label="more"]').eq(1).click();
|
||||
cy.getBySel('chart-list-edit-option').click();
|
||||
}
|
||||
|
||||
function openMenu() {
|
||||
cy.get('[aria-label="more-vert"]').eq(1).click();
|
||||
cy.get('[aria-label="more"]').eq(1).click();
|
||||
}
|
||||
|
||||
function confirmDelete() {
|
||||
@@ -263,7 +263,7 @@ describe('Charts list', () => {
|
||||
// deletes in list-view
|
||||
setGridMode('list');
|
||||
cy.getBySel('table-row').eq(1).contains('2 - Sample chart');
|
||||
cy.getBySel('trash').eq(1).click();
|
||||
cy.getBySel('delete').eq(1).click();
|
||||
confirmDelete();
|
||||
cy.wait('@delete');
|
||||
cy.getBySel('table-row').eq(1).should('not.contain', '2 - Sample chart');
|
||||
|
||||
@@ -62,7 +62,7 @@ describe.skip('Dashboard top-level controls', () => {
|
||||
// should allow force refresh
|
||||
WORLD_HEALTH_CHARTS.forEach(waitForChartLoad);
|
||||
getChartAliasesBySpec(WORLD_HEALTH_CHARTS).then(aliases => {
|
||||
cy.get('[aria-label="more-horiz"]').click();
|
||||
cy.get('[aria-label="ellipsis"]').click();
|
||||
cy.get('[data-test="refresh-dashboard-menu-item"]').should(
|
||||
'not.have.class',
|
||||
'antd5-dropdown-menu-item-disabled',
|
||||
@@ -91,7 +91,7 @@ describe.skip('Dashboard top-level controls', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
cy.get('[aria-label="more-horiz"]').click();
|
||||
cy.get('[aria-label="ellipsis"]').click();
|
||||
cy.get('[data-test="refresh-dashboard-menu-item"]').and(
|
||||
'not.have.class',
|
||||
'antd5-dropdown-menu-item-disabled',
|
||||
|
||||
@@ -24,21 +24,44 @@ describe('Dashboard actions', () => {
|
||||
cy.createSampleDashboards([0]);
|
||||
cy.visit(SAMPLE_DASHBOARD_1);
|
||||
});
|
||||
|
||||
it('should allow to favorite/unfavorite dashboard', () => {
|
||||
interceptFav();
|
||||
interceptUnfav();
|
||||
|
||||
// Find and click StarOutlined (adds to favorites)
|
||||
cy.getBySel('dashboard-header-container')
|
||||
.find("[aria-label='favorite-unselected']")
|
||||
.find("[aria-label='unstarred']")
|
||||
.as('starIconOutlined')
|
||||
.should('exist')
|
||||
.click();
|
||||
|
||||
cy.wait('@select');
|
||||
|
||||
// After clicking, StarFilled should appear
|
||||
cy.getBySel('dashboard-header-container')
|
||||
.find("[aria-label='favorite-selected']")
|
||||
.click();
|
||||
.find("[aria-label='starred']")
|
||||
.as('starIconFilled')
|
||||
.should('exist');
|
||||
|
||||
// Verify the color of the filled star (gold)
|
||||
cy.get('@starIconFilled')
|
||||
.should('have.css', 'color')
|
||||
.and('eq', 'rgb(252, 199, 0)');
|
||||
|
||||
// Click on StarFilled (removes from favorites)
|
||||
cy.get('@starIconFilled').click();
|
||||
|
||||
cy.wait('@unselect');
|
||||
|
||||
// After clicking, StarOutlined should reappear
|
||||
cy.getBySel('dashboard-header-container')
|
||||
.find("[aria-label='favorite-selected']")
|
||||
.should('not.exist');
|
||||
.find("[aria-label='unstarred']")
|
||||
.as('starIconOutlinedAfter')
|
||||
.should('exist');
|
||||
|
||||
// Verify the color of the outlined star (gray)
|
||||
cy.get('@starIconOutlinedAfter')
|
||||
.should('have.css', 'color')
|
||||
.and('eq', 'rgb(178, 178, 178)');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -510,29 +510,29 @@ describe('Drill by modal', () => {
|
||||
|
||||
it('Line chart', () => {
|
||||
testEchart('echarts_timeseries_line', 'Line Chart', [
|
||||
[70, 93],
|
||||
[70, 93],
|
||||
[85, 93],
|
||||
[85, 93],
|
||||
]);
|
||||
});
|
||||
|
||||
it('Area Chart', () => {
|
||||
testEchart('echarts_area', 'Area Chart', [
|
||||
[70, 93],
|
||||
[70, 93],
|
||||
[85, 93],
|
||||
[85, 93],
|
||||
]);
|
||||
});
|
||||
|
||||
it('Scatter Chart', () => {
|
||||
testEchart('echarts_timeseries_scatter', 'Scatter Chart', [
|
||||
[70, 93],
|
||||
[70, 93],
|
||||
[85, 93],
|
||||
[85, 93],
|
||||
]);
|
||||
});
|
||||
|
||||
it('Bar Chart', () => {
|
||||
testEchart('echarts_timeseries_bar', 'Bar Chart', [
|
||||
[70, 94],
|
||||
[362, 68],
|
||||
[85, 94],
|
||||
[490, 68],
|
||||
]);
|
||||
});
|
||||
|
||||
@@ -565,22 +565,22 @@ describe('Drill by modal', () => {
|
||||
|
||||
it('Generic Chart', () => {
|
||||
testEchart('echarts_timeseries', 'Generic Chart', [
|
||||
[70, 93],
|
||||
[70, 93],
|
||||
[85, 93],
|
||||
[85, 93],
|
||||
]);
|
||||
});
|
||||
|
||||
it('Smooth Line Chart', () => {
|
||||
testEchart('echarts_timeseries_smooth', 'Smooth Line Chart', [
|
||||
[70, 93],
|
||||
[70, 93],
|
||||
[85, 93],
|
||||
[85, 93],
|
||||
]);
|
||||
});
|
||||
|
||||
it('Step Line Chart', () => {
|
||||
testEchart('echarts_timeseries_step', 'Step Line Chart', [
|
||||
[70, 93],
|
||||
[70, 93],
|
||||
[85, 93],
|
||||
[85, 93],
|
||||
]);
|
||||
});
|
||||
|
||||
@@ -616,8 +616,8 @@ describe('Drill by modal', () => {
|
||||
cy.get('[data-test-viz-type="mixed_timeseries"] canvas').then($canvas => {
|
||||
// click 'boy'
|
||||
cy.wrap($canvas).scrollIntoView();
|
||||
cy.wrap($canvas).trigger('mouseover', 70, 93);
|
||||
cy.wrap($canvas).rightclick(70, 93);
|
||||
cy.wrap($canvas).trigger('mouseover', 85, 93);
|
||||
cy.wrap($canvas).rightclick(85, 93);
|
||||
|
||||
drillBy('name').then(intercepted => {
|
||||
const { queries } = intercepted.request.body;
|
||||
@@ -650,8 +650,8 @@ describe('Drill by modal', () => {
|
||||
cy.get(`[data-test="drill-by-chart"] canvas`).then($canvas => {
|
||||
// click second query
|
||||
cy.wrap($canvas).scrollIntoView();
|
||||
cy.wrap($canvas).trigger('mouseover', 246, 114);
|
||||
cy.wrap($canvas).rightclick(246, 114);
|
||||
cy.wrap($canvas).trigger('mouseover', 261, 114);
|
||||
cy.wrap($canvas).rightclick(261, 114);
|
||||
|
||||
drillBy('ds').then(intercepted => {
|
||||
const { queries } = intercepted.request.body;
|
||||
|
||||
@@ -95,24 +95,24 @@ function testTimeChart(vizType: string) {
|
||||
|
||||
cy.get(`[data-test-viz-type='${vizType}'] canvas`).then($canvas => {
|
||||
cy.wrap($canvas).scrollIntoView();
|
||||
cy.wrap($canvas).trigger('mousemove', 70, 93);
|
||||
cy.wrap($canvas).rightclick(70, 93);
|
||||
cy.wrap($canvas).trigger('mousemove', 85, 93);
|
||||
cy.wrap($canvas).rightclick(85, 93);
|
||||
|
||||
drillToDetailBy('Drill to detail by 1965');
|
||||
cy.getBySel('filter-val').should('contain', '1965');
|
||||
closeModal();
|
||||
|
||||
cy.wrap($canvas).scrollIntoView();
|
||||
cy.wrap($canvas).trigger('mousemove', 70, 93);
|
||||
cy.wrap($canvas).rightclick(70, 93);
|
||||
cy.wrap($canvas).trigger('mousemove', 85, 93);
|
||||
cy.wrap($canvas).rightclick(85, 93);
|
||||
|
||||
drillToDetailBy('Drill to detail by boy');
|
||||
cy.getBySel('filter-val').should('contain', 'boy');
|
||||
closeModal();
|
||||
|
||||
cy.wrap($canvas).scrollIntoView();
|
||||
cy.wrap($canvas).trigger('mousemove', 70, 93);
|
||||
cy.wrap($canvas).rightclick(70, 93);
|
||||
cy.wrap($canvas).trigger('mousemove', 85, 93);
|
||||
cy.wrap($canvas).rightclick(85, 93);
|
||||
|
||||
drillToDetailBy('Drill to detail by all');
|
||||
cy.getBySel('filter-val').first().should('contain', '1965');
|
||||
@@ -151,7 +151,7 @@ describe('Drill to detail modal', () => {
|
||||
cy.on('uncaught:exception', () => false);
|
||||
cy.wait('@samples');
|
||||
// reload
|
||||
cy.get("[aria-label='reload']").click();
|
||||
cy.get("[aria-label='Reload']").click();
|
||||
cy.wait('@samples');
|
||||
// make sure it started back from first page
|
||||
cy.get('.ant-pagination-item-active').should('contain', '1');
|
||||
@@ -442,7 +442,7 @@ describe('Drill to detail modal', () => {
|
||||
cy.get("[data-test-viz-type='box_plot'] canvas").then($canvas => {
|
||||
const canvasWidth = $canvas.width() || 0;
|
||||
const canvasHeight = $canvas.height() || 0;
|
||||
const canvasCenterX = canvasWidth / 3;
|
||||
const canvasCenterX = canvasWidth / 3 + 15;
|
||||
const canvasCenterY = (canvasHeight * 5) / 6;
|
||||
|
||||
cy.wrap($canvas).scrollIntoView();
|
||||
|
||||
@@ -32,12 +32,12 @@ function orderAlphabetical() {
|
||||
}
|
||||
|
||||
function openProperties() {
|
||||
cy.get('[aria-label="more-vert"]').first().click();
|
||||
cy.get('[aria-label="more"]').first().click();
|
||||
cy.getBySel('dashboard-card-option-edit-button').click();
|
||||
}
|
||||
|
||||
function openMenu() {
|
||||
cy.get('[aria-label="more-vert"]').first().click();
|
||||
cy.get('[aria-label="more"]').first().click();
|
||||
}
|
||||
|
||||
function confirmDelete(bulk = false) {
|
||||
@@ -158,17 +158,14 @@ describe('Dashboards list', () => {
|
||||
cy.getBySel('styled-card').first().contains('1 - Sample dashboard');
|
||||
cy.getBySel('styled-card')
|
||||
.first()
|
||||
.find("[aria-label='favorite-unselected']")
|
||||
.find("[aria-label='unstarred']")
|
||||
.click();
|
||||
cy.wait('@select');
|
||||
cy.getBySel('styled-card')
|
||||
.first()
|
||||
.find("[aria-label='favorite-selected']")
|
||||
.click();
|
||||
cy.getBySel('styled-card').first().find("[aria-label='starred']").click();
|
||||
cy.wait('@unselect');
|
||||
cy.getBySel('styled-card')
|
||||
.first()
|
||||
.find("[aria-label='favorite-selected']")
|
||||
.find("[aria-label='starred']")
|
||||
.should('not.exist');
|
||||
});
|
||||
|
||||
|
||||
@@ -171,7 +171,7 @@ export const sqlLabView = {
|
||||
header: '[role=columnheader]',
|
||||
table: '.QueryTable',
|
||||
row: dataTestLocator('table-row'),
|
||||
failureMarkIcon: '[aria-label=x-small]',
|
||||
failureMarkIcon: '[aria-label=close]',
|
||||
successMarkIcon: '[aria-label=check]',
|
||||
},
|
||||
};
|
||||
@@ -252,7 +252,7 @@ export const datasetsList = {
|
||||
aceTextInput: '.ace_text-input',
|
||||
sourceSQLInput: '.ace_content',
|
||||
sourceVirtualSQLRadio: ':nth-child(2) > .ant-radio > .ant-radio-inner',
|
||||
sourcePadlock: '[aria-label=lock-locked]',
|
||||
sourcePadlock: '[aria-label=lock]',
|
||||
legacy: {
|
||||
panel: '.panel-body',
|
||||
sqlInput: '#sql',
|
||||
@@ -275,8 +275,8 @@ export const chartListView = {
|
||||
bulkSelect: dataTestLocator('bulk-select'),
|
||||
},
|
||||
header: {
|
||||
cardView: '[aria-label="card-view"]',
|
||||
listView: '[aria-label="list-view"]',
|
||||
cardView: '[aria-label="appstore"]',
|
||||
listView: '[aria-label="unordered-list"]',
|
||||
sort: '[class="ant-select-selection-search-input"][aria-label="Sort"]',
|
||||
sortRecentlyModifiedMenuOption: '[label="Recently modified"]',
|
||||
sortAlphabeticalMenuOption: '[label="Alphabetical"]',
|
||||
@@ -286,8 +286,6 @@ export const chartListView = {
|
||||
card: dataTestLocator('styled-card'),
|
||||
cardCover: '[class="antd5-card-cover"]',
|
||||
cardImage: '[class="gradient-container"]',
|
||||
selectedStarIcon: "[aria-label='favorite-selected']",
|
||||
unselectedStarIcon: "[aria-label='favorite-unselected']",
|
||||
starIcon: dataTestLocator('fave-unfave-icon'),
|
||||
},
|
||||
deleteModal: {
|
||||
@@ -330,7 +328,7 @@ export const nativeFilters = {
|
||||
filterItemsContainer: dataTestLocator('filter-title-container'),
|
||||
tabsContainer: '[class="ant-tabs-nav-list"]',
|
||||
tab: '.ant-tabs-tab',
|
||||
removeTab: '[aria-label="trash"]',
|
||||
removeTab: '[aria-label="delete"]',
|
||||
},
|
||||
addFilter: dataTestLocator('add-filter-button'),
|
||||
defaultValueCheck: '.ant-checkbox-checked',
|
||||
@@ -375,7 +373,7 @@ export const nativeFilters = {
|
||||
listItemNotActive: '[class="ant-tabs-tab ant-tabs-tab-with-remove"]',
|
||||
listItemActive:
|
||||
'[class="ant-tabs-tab ant-tabs-tab-with-remove ant-tabs-tab-active"]',
|
||||
removeIcon: '[aria-label="trash"]',
|
||||
removeIcon: '[aria-label="delete"]',
|
||||
},
|
||||
filterItem: dataTestLocator('form-item-value'),
|
||||
filterItemDropdown: '.ant-select-selection-search',
|
||||
@@ -402,8 +400,8 @@ export const dashboardListView = {
|
||||
card: dataTestLocator('styled-card'),
|
||||
cardCover: '[class="antd5-card-cover"]',
|
||||
cardImage: '[class="gradient-container"]',
|
||||
selectedStarIcon: "[aria-label='favorite-selected']",
|
||||
unselectedStarIcon: "[aria-label='favorite-unselected']",
|
||||
selectedStarIcon: "[aria-label='star']",
|
||||
unselectedStarIcon: "[aria-label='star']",
|
||||
starIcon: dataTestLocator('fave-unfave-icon'),
|
||||
},
|
||||
deleteModal: {
|
||||
@@ -412,8 +410,8 @@ export const dashboardListView = {
|
||||
},
|
||||
table: {
|
||||
starIcon: dataTestLocator('fave-unfave-icon'),
|
||||
selectedStarIcon: "[aria-label='favorite-selected']",
|
||||
unselectedStarIcon: "[aria-label='favorite-unselected']",
|
||||
selectedStarIcon: "[aria-label='star']",
|
||||
unselectedStarIcon: "[aria-label='star']",
|
||||
bulkSelect: {
|
||||
checkboxOff: '[aria-label="checkbox-off"]',
|
||||
checkboxOn: '[aria-label="checkbox-on"]',
|
||||
@@ -438,8 +436,8 @@ export const dashboardListView = {
|
||||
importButton: dataTestLocator('modal-confirm-button'),
|
||||
},
|
||||
header: {
|
||||
cardView: '[aria-label="card-view"]',
|
||||
listView: '[aria-label="list-view"]',
|
||||
cardView: '[aria-label="appstore"]',
|
||||
listView: '[aria-label="unordered-list"]',
|
||||
sort: dataTestLocator('sort-header'),
|
||||
sortDropdown: '.Select__menu',
|
||||
statusFilterInput: `${dataTestLocator(
|
||||
@@ -503,7 +501,7 @@ export const exploreView = {
|
||||
optionField: dataTestLocator('option-label'),
|
||||
fieldInput: '.Select__control input',
|
||||
removeFieldValue: dataTestLocator('remove-control-button'),
|
||||
addFieldValue: '[aria-label="plus-small"]',
|
||||
addFieldValue: '[aria-label="plus"]',
|
||||
vizType: dataTestLocator('visualization-type'),
|
||||
runButton: dataTestLocator('run-query-button'),
|
||||
saveQuery: dataTestLocator('query-save-button'),
|
||||
|
||||
@@ -25,8 +25,14 @@ export interface ChartSpec {
|
||||
viz: string;
|
||||
}
|
||||
|
||||
const viewTypeIcons = {
|
||||
card: 'appstore',
|
||||
list: 'unordered-list',
|
||||
};
|
||||
|
||||
export function setGridMode(type: 'card' | 'list') {
|
||||
cy.get(`[aria-label="${type}-view"]`).click();
|
||||
const icon = viewTypeIcons[type];
|
||||
cy.get(`[aria-label="${icon}"]`).click();
|
||||
}
|
||||
|
||||
export function toggleBulkSelect() {
|
||||
|
||||
68
superset-frontend/eslint-rules/eslint-plugin-icons/index.js
Normal file
68
superset-frontend/eslint-rules/eslint-plugin-icons/index.js
Normal file
@@ -0,0 +1,68 @@
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Rule to warn about direct imports from @ant-design/icons
|
||||
* @author Apache
|
||||
*/
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('eslint').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
rules: {
|
||||
'no-fa-icons-usage': {
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description:
|
||||
'Disallow the usage of FontAwesome icons in the codebase',
|
||||
category: 'Best Practices',
|
||||
},
|
||||
schema: [],
|
||||
},
|
||||
create(context) {
|
||||
return {
|
||||
// Check for JSX elements with class names containing "fa"
|
||||
JSXElement(node) {
|
||||
if (
|
||||
node.openingElement &&
|
||||
node.openingElement.name.name === 'i' &&
|
||||
node.openingElement.attributes &&
|
||||
node.openingElement.attributes.some(
|
||||
attr =>
|
||||
attr.name &&
|
||||
attr.name.name === 'className' &&
|
||||
/fa fa-/.test(attr.value.value),
|
||||
)
|
||||
) {
|
||||
context.report({
|
||||
node,
|
||||
message:
|
||||
'FontAwesome icons should not be used. Use the src/components/Icons component instead.',
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Test file for the no-fa-icons-usage rule
|
||||
* @author Apache
|
||||
*/
|
||||
|
||||
const { RuleTester } = require('eslint');
|
||||
const plugin = require('.');
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Tests
|
||||
//------------------------------------------------------------------------------
|
||||
const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } });
|
||||
const rule = plugin.rules['no-fa-icons-usage'];
|
||||
|
||||
const errors = [
|
||||
{
|
||||
message:
|
||||
'FontAwesome icons should not be used. Use the src/components/Icons component instead.',
|
||||
},
|
||||
];
|
||||
|
||||
ruleTester.run('no-fa-icons-usage', rule, {
|
||||
valid: ['<Icons.Database />', '<Icons.Search />'],
|
||||
invalid: [
|
||||
{
|
||||
code: '<i className="fa fa-database"></i>',
|
||||
errors,
|
||||
},
|
||||
{
|
||||
code: '<i className="fa fa-search"></i>',
|
||||
errors,
|
||||
},
|
||||
{
|
||||
code: '<i className="fa fa-home"></i>',
|
||||
errors,
|
||||
},
|
||||
{
|
||||
code: '<i className="fa fa-arrow-right"></i>',
|
||||
errors,
|
||||
},
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "eslint-plugin-icons",
|
||||
"version": "1.0.0",
|
||||
"description": "Warns about direct usage of Ant Design icons",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [],
|
||||
"license": "Apache-2.0",
|
||||
"author": "Apache",
|
||||
"dependencies": {},
|
||||
"peerDependencies": {
|
||||
"eslint": ">=0.8.0"
|
||||
}
|
||||
}
|
||||
83
superset-frontend/package-lock.json
generated
83
superset-frontend/package-lock.json
generated
@@ -152,7 +152,7 @@
|
||||
"devDependencies": {
|
||||
"@applitools/eyes-storybook": "^3.50.9",
|
||||
"@babel/cli": "^7.22.6",
|
||||
"@babel/compat-data": "^7.22.6",
|
||||
"@babel/compat-data": "^7.26.8",
|
||||
"@babel/core": "^7.26.0",
|
||||
"@babel/eslint-parser": "^7.25.9",
|
||||
"@babel/node": "^7.22.6",
|
||||
@@ -234,7 +234,7 @@
|
||||
"copy-webpack-plugin": "^12.0.2",
|
||||
"cross-env": "^7.0.3",
|
||||
"css-loader": "^7.1.2",
|
||||
"css-minimizer-webpack-plugin": "^7.0.0",
|
||||
"css-minimizer-webpack-plugin": "^7.0.2",
|
||||
"enzyme": "^3.11.0",
|
||||
"enzyme-matchers": "^7.1.2",
|
||||
"eslint": "^8.56.0",
|
||||
@@ -243,6 +243,7 @@
|
||||
"eslint-import-resolver-typescript": "^3.7.0",
|
||||
"eslint-plugin-cypress": "^3.6.0",
|
||||
"eslint-plugin-file-progress": "^1.5.0",
|
||||
"eslint-plugin-icons": "file:eslint-rules/eslint-plugin-icons",
|
||||
"eslint-plugin-import": "^2.24.2",
|
||||
"eslint-plugin-jest": "^27.8.0",
|
||||
"eslint-plugin-jest-dom": "^5.5.0",
|
||||
@@ -272,7 +273,7 @@
|
||||
"mini-css-extract-plugin": "^2.9.0",
|
||||
"open-cli": "^8.0.0",
|
||||
"po2json": "^0.4.5",
|
||||
"prettier": "3.3.3",
|
||||
"prettier": "3.5.3",
|
||||
"prettier-plugin-packagejson": "^2.5.3",
|
||||
"process": "^0.11.10",
|
||||
"react-resizable": "^3.0.5",
|
||||
@@ -317,6 +318,14 @@
|
||||
"eslint": ">=0.8.0"
|
||||
}
|
||||
},
|
||||
"eslint-rules/eslint-plugin-icons": {
|
||||
"version": "1.0.0",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"peerDependencies": {
|
||||
"eslint": ">=0.8.0"
|
||||
}
|
||||
},
|
||||
"eslint-rules/eslint-plugin-theme-colors": {
|
||||
"version": "1.0.0",
|
||||
"dev": true,
|
||||
@@ -1151,9 +1160,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/compat-data": {
|
||||
"version": "7.26.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.5.tgz",
|
||||
"integrity": "sha512-XvcZi1KWf88RVbF9wn8MN6tYFloU5qX8KjuF3E1PVBmJ9eypXfs4GRiJwLuTZL0iSnJUKn1BFPa5BPZZJyFzPg==",
|
||||
"version": "7.26.8",
|
||||
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.8.tgz",
|
||||
"integrity": "sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -3244,9 +3253,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/runtime": {
|
||||
"version": "7.26.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.0.tgz",
|
||||
"integrity": "sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==",
|
||||
"version": "7.26.10",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.10.tgz",
|
||||
"integrity": "sha512-2WJMeRQPHKSPemqk/awGrAiuFfzBmOIPXKizAsVhWH9YJqLZ0H+HS4c8loHGgW6utJ3E/ejXQUsiGaQy2NZ9Fw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"regenerator-runtime": "^0.14.0"
|
||||
@@ -17353,9 +17362,9 @@
|
||||
"license": "CC-BY-4.0"
|
||||
},
|
||||
"node_modules/canvg": {
|
||||
"version": "3.0.10",
|
||||
"resolved": "https://registry.npmjs.org/canvg/-/canvg-3.0.10.tgz",
|
||||
"integrity": "sha512-qwR2FRNO9NlzTeKIPIKpnTY6fqwuYSequ8Ru8c0YkYU7U0oW+hLUvWadLvAu1Rl72OMNiFhoLu4f8eUjQ7l/+Q==",
|
||||
"version": "3.0.11",
|
||||
"resolved": "https://registry.npmjs.org/canvg/-/canvg-3.0.11.tgz",
|
||||
"integrity": "sha512-5ON+q7jCTgMp9cjpu4Jo6XbvfYwSB2Ow3kzHKfIyJfaCAOHLbdKPQqGKgfED/R5B+3TFFfe8pegYA+b423SRyA==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
@@ -18979,16 +18988,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/css-minimizer-webpack-plugin": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-7.0.0.tgz",
|
||||
"integrity": "sha512-niy66jxsQHqO+EYbhPuIhqRQ1mNcNVUHrMnkzzir9kFOERJUaQDDRhh7dKDz33kBpkWMF9M8Vx0QlDbc5AHOsw==",
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-7.0.2.tgz",
|
||||
"integrity": "sha512-nBRWZtI77PBZQgcXMNqiIXVshiQOVLGSf2qX/WZfG8IQfMbeHUMXaBWQmiiSTmPJUflQxHjZjzAmuyO7tpL2Jg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@jridgewell/trace-mapping": "^0.3.25",
|
||||
"cssnano": "^7.0.1",
|
||||
"cssnano": "^7.0.4",
|
||||
"jest-worker": "^29.7.0",
|
||||
"postcss": "^8.4.38",
|
||||
"postcss": "^8.4.40",
|
||||
"schema-utils": "^4.2.0",
|
||||
"serialize-javascript": "^6.0.2"
|
||||
},
|
||||
@@ -20646,6 +20655,16 @@
|
||||
"url": "https://github.com/fb55/domhandler?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/dompurify": {
|
||||
"version": "3.2.4",
|
||||
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.4.tgz",
|
||||
"integrity": "sha512-ysFSFEDVduQpyhzAob/kkuJjf5zWkZD8/A9ywSp1byueyuCfHamrCBa14/Oc2iiB0e51B+NpxSl5gmzn+Ms/mg==",
|
||||
"license": "(MPL-2.0 OR Apache-2.0)",
|
||||
"optional": true,
|
||||
"optionalDependencies": {
|
||||
"@types/trusted-types": "^2.0.7"
|
||||
}
|
||||
},
|
||||
"node_modules/domutils": {
|
||||
"version": "3.2.2",
|
||||
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz",
|
||||
@@ -21906,6 +21925,10 @@
|
||||
"resolved": "eslint-rules/eslint-plugin-i18n-strings",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/eslint-plugin-icons": {
|
||||
"resolved": "eslint-rules/eslint-plugin-icons",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/eslint-plugin-import": {
|
||||
"version": "2.31.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.31.0.tgz",
|
||||
@@ -30329,30 +30352,23 @@
|
||||
}
|
||||
},
|
||||
"node_modules/jspdf": {
|
||||
"version": "2.5.2",
|
||||
"resolved": "https://registry.npmjs.org/jspdf/-/jspdf-2.5.2.tgz",
|
||||
"integrity": "sha512-myeX9c+p7znDWPk0eTrujCzNjT+CXdXyk7YmJq5nD5V7uLLKmSXnlQ/Jn/kuo3X09Op70Apm0rQSnFWyGK8uEQ==",
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/jspdf/-/jspdf-3.0.1.tgz",
|
||||
"integrity": "sha512-qaGIxqxetdoNnFQQXxTKUD9/Z7AloLaw94fFsOiJMxbfYdBbrBuhWmbzI8TVjrw7s3jBY1PFHofBKMV/wZPapg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.23.2",
|
||||
"@babel/runtime": "^7.26.7",
|
||||
"atob": "^2.1.2",
|
||||
"btoa": "^1.2.1",
|
||||
"fflate": "^0.8.1"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"canvg": "^3.0.6",
|
||||
"canvg": "^3.0.11",
|
||||
"core-js": "^3.6.0",
|
||||
"dompurify": "^2.5.4",
|
||||
"dompurify": "^3.2.4",
|
||||
"html2canvas": "^1.0.0-rc.5"
|
||||
}
|
||||
},
|
||||
"node_modules/jspdf/node_modules/dompurify": {
|
||||
"version": "2.5.8",
|
||||
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.5.8.tgz",
|
||||
"integrity": "sha512-o1vSNgrmYMQObbSSvF/1brBYEQPHhV1+gsmrusO7/GXtp1T9rCS8cXFqVxK/9crT1jA6Ccv+5MTSjBNqr7Sovw==",
|
||||
"license": "(MPL-2.0 OR Apache-2.0)",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/jsprim": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-2.0.2.tgz",
|
||||
@@ -37462,9 +37478,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/prettier": {
|
||||
"version": "3.3.3",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz",
|
||||
"integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==",
|
||||
"version": "3.5.3",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz",
|
||||
"integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
@@ -50711,6 +50727,7 @@
|
||||
"version": "0.20.3",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@types/react-redux": "^7.1.10",
|
||||
"d3-array": "^1.2.0",
|
||||
"dayjs": "^1.11.13",
|
||||
"lodash": "^4.17.21"
|
||||
|
||||
@@ -219,7 +219,7 @@
|
||||
"devDependencies": {
|
||||
"@applitools/eyes-storybook": "^3.50.9",
|
||||
"@babel/cli": "^7.22.6",
|
||||
"@babel/compat-data": "^7.22.6",
|
||||
"@babel/compat-data": "^7.26.8",
|
||||
"@babel/core": "^7.26.0",
|
||||
"@babel/eslint-parser": "^7.25.9",
|
||||
"@babel/node": "^7.22.6",
|
||||
@@ -301,7 +301,7 @@
|
||||
"copy-webpack-plugin": "^12.0.2",
|
||||
"cross-env": "^7.0.3",
|
||||
"css-loader": "^7.1.2",
|
||||
"css-minimizer-webpack-plugin": "^7.0.0",
|
||||
"css-minimizer-webpack-plugin": "^7.0.2",
|
||||
"enzyme": "^3.11.0",
|
||||
"enzyme-matchers": "^7.1.2",
|
||||
"eslint": "^8.56.0",
|
||||
@@ -310,6 +310,7 @@
|
||||
"eslint-import-resolver-typescript": "^3.7.0",
|
||||
"eslint-plugin-cypress": "^3.6.0",
|
||||
"eslint-plugin-file-progress": "^1.5.0",
|
||||
"eslint-plugin-icons": "file:eslint-rules/eslint-plugin-icons",
|
||||
"eslint-plugin-import": "^2.24.2",
|
||||
"eslint-plugin-jest": "^27.8.0",
|
||||
"eslint-plugin-jest-dom": "^5.5.0",
|
||||
@@ -339,7 +340,7 @@
|
||||
"mini-css-extract-plugin": "^2.9.0",
|
||||
"open-cli": "^8.0.0",
|
||||
"po2json": "^0.4.5",
|
||||
"prettier": "3.3.3",
|
||||
"prettier": "3.5.3",
|
||||
"prettier-plugin-packagejson": "^2.5.3",
|
||||
"process": "^0.11.10",
|
||||
"react-resizable": "^3.0.5",
|
||||
@@ -372,7 +373,8 @@
|
||||
"core-js": "^3.38.1",
|
||||
"d3-color": "^3.1.0",
|
||||
"puppeteer": "^22.4.1",
|
||||
"underscore": "^1.13.7"
|
||||
"underscore": "^1.13.7",
|
||||
"jspdf": "^3.0.1"
|
||||
},
|
||||
"readme": "ERROR: No README data found!",
|
||||
"scarfSettings": {
|
||||
|
||||
@@ -19,12 +19,14 @@
|
||||
*/
|
||||
import { ReactNode } from 'react';
|
||||
import { css, GenericDataType, styled, t } from '@superset-ui/core';
|
||||
import { ClockCircleOutlined, QuestionOutlined } from '@ant-design/icons';
|
||||
// TODO: move all icons to superset-ui/core
|
||||
import FunctionSvg from './type-icons/field_derived.svg';
|
||||
import BooleanSvg from './type-icons/field_boolean.svg';
|
||||
import StringSvg from './type-icons/field_abc.svg';
|
||||
import NumSvg from './type-icons/field_num.svg';
|
||||
import {
|
||||
ClockCircleOutlined,
|
||||
QuestionOutlined,
|
||||
FunctionOutlined,
|
||||
FieldBinaryOutlined,
|
||||
FieldStringOutlined,
|
||||
NumberOutlined,
|
||||
} from '@ant-design/icons';
|
||||
|
||||
export type ColumnLabelExtendedType = 'expression' | '';
|
||||
|
||||
@@ -56,13 +58,13 @@ export function ColumnTypeLabel({ type }: ColumnTypeLabelProps) {
|
||||
);
|
||||
|
||||
if (type === '' || type === 'expression') {
|
||||
typeIcon = <FunctionSvg aria-label={t('function type icon')} />;
|
||||
typeIcon = <FunctionOutlined aria-label={t('function type icon')} />;
|
||||
} else if (type === GenericDataType.String) {
|
||||
typeIcon = <StringSvg aria-label={t('string type icon')} />;
|
||||
typeIcon = <FieldStringOutlined aria-label={t('string type icon')} />;
|
||||
} else if (type === GenericDataType.Numeric) {
|
||||
typeIcon = <NumSvg aria-label={t('numeric type icon')} />;
|
||||
typeIcon = <NumberOutlined aria-label={t('numeric type icon')} />;
|
||||
} else if (type === GenericDataType.Boolean) {
|
||||
typeIcon = <BooleanSvg aria-label={t('boolean type icon')} />;
|
||||
typeIcon = <FieldBinaryOutlined aria-label={t('boolean type icon')} />;
|
||||
} else if (type === GenericDataType.Temporal) {
|
||||
typeIcon = <ClockCircleOutlined aria-label={t('temporal type icon')} />;
|
||||
}
|
||||
|
||||
@@ -105,6 +105,8 @@ export function ControlHeader({
|
||||
{warning && (
|
||||
<span>
|
||||
<Tooltip id="error-tooltip" placement="top" title={warning}>
|
||||
{/* TODO: Remove fa-icon */}
|
||||
{/* eslint-disable-next-line icons/no-fa-icons-usage */}
|
||||
<i className="fa fa-exclamation-circle text-warning" />
|
||||
</Tooltip>{' '}
|
||||
</span>
|
||||
@@ -112,6 +114,8 @@ export function ControlHeader({
|
||||
{danger && (
|
||||
<span>
|
||||
<Tooltip id="error-tooltip" placement="top" title={danger}>
|
||||
{/* TODO: Remove fa-icon */}
|
||||
{/* eslint-disable-next-line icons/no-fa-icons-usage */}
|
||||
<i className="fa fa-exclamation-circle text-danger" />
|
||||
</Tooltip>{' '}
|
||||
</span>
|
||||
@@ -123,6 +127,8 @@ export function ControlHeader({
|
||||
placement="top"
|
||||
title={validationErrors.join(' ')}
|
||||
>
|
||||
{/* TODO: Remove fa-icon */}
|
||||
{/* eslint-disable-next-line icons/no-fa-icons-usage */}
|
||||
<i className="fa fa-exclamation-circle text-danger" />
|
||||
</Tooltip>{' '}
|
||||
</span>
|
||||
|
||||
@@ -16,11 +16,13 @@
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { styled } from '@superset-ui/core';
|
||||
import { styled, css } from '@superset-ui/core';
|
||||
|
||||
export const ControlSubSectionHeader = styled.div`
|
||||
font-weight: ${({ theme }) => theme.typography.weights.bold};
|
||||
font-size: ${({ theme }) => theme.typography.sizes.s};
|
||||
margin-bottom: ${({ theme }) => theme.gridUnit}px;
|
||||
${({ theme }) => css`
|
||||
font-weight: ${theme.typography.weights.bold};
|
||||
font-size: ${theme.typography.sizes.s};
|
||||
margin-bottom: ${theme.gridUnit}px;
|
||||
`}
|
||||
`;
|
||||
export default ControlSubSectionHeader;
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* 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 limitationsxw
|
||||
* under the License.
|
||||
*/
|
||||
import {
|
||||
getMetricLabel,
|
||||
ensureIsArray,
|
||||
PostProcessingAggregation,
|
||||
QueryFormData,
|
||||
Aggregates,
|
||||
} from '@superset-ui/core';
|
||||
import { PostProcessingFactory } from './types';
|
||||
|
||||
export const aggregationOperator: PostProcessingFactory<
|
||||
PostProcessingAggregation
|
||||
> = (formData: QueryFormData, queryObject) => {
|
||||
const { aggregation = 'LAST_VALUE' } = formData;
|
||||
|
||||
if (aggregation === 'LAST_VALUE') {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const metrics = ensureIsArray(queryObject.metrics);
|
||||
if (metrics.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const aggregates: Aggregates = {};
|
||||
metrics.forEach(metric => {
|
||||
const metricLabel = getMetricLabel(metric);
|
||||
aggregates[metricLabel] = {
|
||||
operator: aggregation,
|
||||
column: metricLabel,
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
operation: 'aggregate',
|
||||
options: {
|
||||
groupby: [],
|
||||
aggregates,
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -21,6 +21,7 @@ export { rollingWindowOperator } from './rollingWindowOperator';
|
||||
export { timeCompareOperator } from './timeCompareOperator';
|
||||
export { timeComparePivotOperator } from './timeComparePivotOperator';
|
||||
export { sortOperator } from './sortOperator';
|
||||
export { aggregationOperator } from './aggregateOperator';
|
||||
export { histogramOperator } from './histogramOperator';
|
||||
export { pivotOperator } from './pivotOperator';
|
||||
export { resampleOperator } from './resampleOperator';
|
||||
|
||||
@@ -84,7 +84,7 @@ export const titleControls: ControlPanelSectionConfig = {
|
||||
clearable: true,
|
||||
label: t('Y Axis Title Margin'),
|
||||
renderTrigger: true,
|
||||
default: TITLE_MARGIN_OPTIONS[0],
|
||||
default: TITLE_MARGIN_OPTIONS[1],
|
||||
choices: formatSelectOptions(TITLE_MARGIN_OPTIONS),
|
||||
description: t('Changing this control takes effect instantly'),
|
||||
},
|
||||
|
||||
@@ -61,6 +61,32 @@ const xAxisSortVisibility = ({ controls }: { controls: ControlStateMapping }) =>
|
||||
ensureIsArray(controls?.groupby?.value).length === 0 &&
|
||||
ensureIsArray(controls?.metrics?.value).length === 1;
|
||||
|
||||
// TODO: Expand this aggregation options list to include all backend-supported aggregations.
|
||||
// TODO: Migrate existing chart types (Pivot Table, etc.) to use this shared control.
|
||||
export const aggregationControl = {
|
||||
name: 'aggregation',
|
||||
config: {
|
||||
type: 'SelectControl',
|
||||
label: t('Aggregation Method'),
|
||||
default: 'LAST_VALUE',
|
||||
clearable: false,
|
||||
renderTrigger: false,
|
||||
choices: [
|
||||
['LAST_VALUE', t('Last Value')],
|
||||
['sum', t('Total (Sum)')],
|
||||
['mean', t('Average (Mean)')],
|
||||
['min', t('Minimum')],
|
||||
['max', t('Maximum')],
|
||||
['median', t('Median')],
|
||||
],
|
||||
description: t('Select an aggregation method to apply to the metric.'),
|
||||
provideFormDataToProps: true,
|
||||
mapStateToProps: ({ form_data }: ControlPanelState) => ({
|
||||
value: form_data.aggregation || 'LAST_VALUE',
|
||||
}),
|
||||
},
|
||||
};
|
||||
|
||||
const xAxisMultiSortVisibility = ({
|
||||
controls,
|
||||
}: {
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
export { default as sharedControls } from './sharedControls';
|
||||
// React control components
|
||||
export { default as sharedControlComponents } from './components';
|
||||
export { aggregationControl } from './customControls';
|
||||
export * from './components';
|
||||
export * from './customControls';
|
||||
export * from './mixins';
|
||||
|
||||
@@ -78,6 +78,7 @@ export const D3_TIME_FORMAT_OPTIONS: [string, string][] = [
|
||||
[SMART_DATE_ID, t('Adaptive formatting')],
|
||||
['%d/%m/%Y', '%d/%m/%Y | 14/01/2019'],
|
||||
['%m/%d/%Y', '%m/%d/%Y | 01/14/2019'],
|
||||
['%d.%m.%Y', '%d.%m.%Y | 14.01.2019'],
|
||||
['%Y-%m-%d', '%Y-%m-%d | 2019-01-14'],
|
||||
['%Y-%m-%d %H:%M:%S', '%Y-%m-%d %H:%M:%S | 2019-01-14 01:32:10'],
|
||||
['%d-%m-%Y %H:%M:%S', '%d-%m-%Y %H:%M:%S | 14-01-2019 01:32:10'],
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
/**
|
||||
* 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 { QueryObject, SqlaFormData, VizType } from '@superset-ui/core';
|
||||
import { aggregationOperator } from '@superset-ui/chart-controls';
|
||||
|
||||
describe('aggregationOperator', () => {
|
||||
const formData: SqlaFormData = {
|
||||
metrics: [
|
||||
'count(*)',
|
||||
{ label: 'sum(val)', expressionType: 'SQL', sqlExpression: 'sum(val)' },
|
||||
],
|
||||
time_range: '2015 : 2016',
|
||||
granularity: 'month',
|
||||
datasource: 'foo',
|
||||
viz_type: VizType.Table,
|
||||
};
|
||||
|
||||
const queryObject: QueryObject = {
|
||||
metrics: [
|
||||
'count(*)',
|
||||
{ label: 'sum(val)', expressionType: 'SQL', sqlExpression: 'sum(val)' },
|
||||
],
|
||||
time_range: '2015 : 2016',
|
||||
granularity: 'month',
|
||||
};
|
||||
|
||||
test('should return undefined for LAST_VALUE aggregation', () => {
|
||||
const formDataWithLastValue = {
|
||||
...formData,
|
||||
aggregation: 'LAST_VALUE',
|
||||
};
|
||||
|
||||
expect(
|
||||
aggregationOperator(formDataWithLastValue, queryObject),
|
||||
).toBeUndefined();
|
||||
});
|
||||
|
||||
test('should return undefined when metrics is empty', () => {
|
||||
const queryObjectWithoutMetrics = {
|
||||
...queryObject,
|
||||
metrics: [],
|
||||
};
|
||||
|
||||
const formDataWithSum = {
|
||||
...formData,
|
||||
aggregation: 'sum',
|
||||
};
|
||||
|
||||
expect(
|
||||
aggregationOperator(formDataWithSum, queryObjectWithoutMetrics),
|
||||
).toBeUndefined();
|
||||
});
|
||||
|
||||
test('should apply sum aggregation to all metrics', () => {
|
||||
const formDataWithSum = {
|
||||
...formData,
|
||||
aggregation: 'sum',
|
||||
};
|
||||
|
||||
expect(aggregationOperator(formDataWithSum, queryObject)).toEqual({
|
||||
operation: 'aggregate',
|
||||
options: {
|
||||
groupby: [],
|
||||
aggregates: {
|
||||
'count(*)': {
|
||||
operator: 'sum',
|
||||
column: 'count(*)',
|
||||
},
|
||||
'sum(val)': {
|
||||
operator: 'sum',
|
||||
column: 'sum(val)',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test('should apply mean aggregation to all metrics', () => {
|
||||
const formDataWithMean = {
|
||||
...formData,
|
||||
aggregation: 'mean',
|
||||
};
|
||||
|
||||
expect(aggregationOperator(formDataWithMean, queryObject)).toEqual({
|
||||
operation: 'aggregate',
|
||||
options: {
|
||||
groupby: [],
|
||||
aggregates: {
|
||||
'count(*)': {
|
||||
operator: 'mean',
|
||||
column: 'count(*)',
|
||||
},
|
||||
'sum(val)': {
|
||||
operator: 'mean',
|
||||
column: 'sum(val)',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test('should use default aggregation when not specified', () => {
|
||||
expect(aggregationOperator(formData, queryObject)).toBeUndefined();
|
||||
});
|
||||
});
|
||||
@@ -54,7 +54,7 @@ const queryObject: QueryObject = {
|
||||
},
|
||||
},
|
||||
{
|
||||
operation: 'aggregation',
|
||||
operation: 'aggregate',
|
||||
options: {
|
||||
groupby: ['col1'],
|
||||
aggregates: {},
|
||||
|
||||
@@ -67,7 +67,7 @@ export interface Aggregates {
|
||||
export type DefaultPostProcessing = undefined;
|
||||
|
||||
interface _PostProcessingAggregation {
|
||||
operation: 'aggregation';
|
||||
operation: 'aggregate';
|
||||
options: {
|
||||
groupby: string[];
|
||||
aggregates: Aggregates;
|
||||
@@ -271,7 +271,7 @@ export type PostProcessingRule =
|
||||
export function isPostProcessingAggregation(
|
||||
rule?: PostProcessingRule,
|
||||
): rule is PostProcessingAggregation {
|
||||
return rule?.operation === 'aggregation';
|
||||
return rule?.operation === 'aggregate';
|
||||
}
|
||||
|
||||
export function isPostProcessingBoxplot(
|
||||
|
||||
@@ -61,7 +61,7 @@ const AGGREGATES_OPTION: Aggregates = {
|
||||
};
|
||||
|
||||
const AGGREGATE_RULE: PostProcessingAggregation = {
|
||||
operation: 'aggregation',
|
||||
operation: 'aggregate',
|
||||
options: {
|
||||
groupby: ['foo'],
|
||||
aggregates: AGGREGATES_OPTION,
|
||||
|
||||
@@ -63,6 +63,11 @@ const form_data = {
|
||||
header_font_size: 60,
|
||||
subheader_font_size: 26,
|
||||
comparison_color_enabled: true,
|
||||
column_config: {
|
||||
name: {
|
||||
visible: true,
|
||||
},
|
||||
},
|
||||
extra_form_data: {},
|
||||
force: false,
|
||||
result_format: 'json',
|
||||
@@ -142,7 +147,7 @@ describe('getComparisonInfo', () => {
|
||||
expect(resultFormData.adhoc_filters?.[0]).toEqual(expectedFilters[0]);
|
||||
});
|
||||
|
||||
it('If adhoc_filter is undefrined the code wont break', () => {
|
||||
it('If adhoc_filter is undefined the code wont break', () => {
|
||||
const resultFormData = getComparisonInfo(
|
||||
{
|
||||
...form_data,
|
||||
@@ -175,4 +180,21 @@ describe('getComparisonInfo', () => {
|
||||
expect(resultFormData.adhoc_filters?.length).toEqual(1);
|
||||
expect(resultFormData.adhoc_filters).toEqual(expectedFilters);
|
||||
});
|
||||
|
||||
it('Updates comparison display values when toggled', () => {
|
||||
const resultFormData = getComparisonInfo(
|
||||
{
|
||||
...form_data,
|
||||
column_config: {
|
||||
name: {
|
||||
visible: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
ComparisonTimeRangeType.Year,
|
||||
{},
|
||||
);
|
||||
|
||||
expect(resultFormData.column_config.name.visible).toEqual(false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -24,9 +24,10 @@
|
||||
"lib"
|
||||
],
|
||||
"dependencies": {
|
||||
"@types/react-redux": "^7.1.34",
|
||||
"d3-array": "^1.2.0",
|
||||
"lodash": "^4.17.21",
|
||||
"dayjs": "^1.11.13"
|
||||
"dayjs": "^1.11.13",
|
||||
"lodash": "^4.17.21"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@superset-ui/chart-controls": "*",
|
||||
|
||||
@@ -200,16 +200,19 @@ export default function PopKPI(props: PopKPIProps) {
|
||||
symbol: '#',
|
||||
value: prevNumber,
|
||||
tooltipText: t('Data for %s', comparisonRange || 'previous range'),
|
||||
columnKey: 'Previous value',
|
||||
},
|
||||
{
|
||||
symbol: '△',
|
||||
value: valueDifference,
|
||||
tooltipText: t('Value difference between the time periods'),
|
||||
columnKey: 'Delta',
|
||||
},
|
||||
{
|
||||
symbol: '%',
|
||||
value: percentDifferenceFormattedString,
|
||||
tooltipText: t('Percentage difference between the time periods'),
|
||||
columnKey: 'Percent change',
|
||||
},
|
||||
],
|
||||
[
|
||||
@@ -220,6 +223,10 @@ export default function PopKPI(props: PopKPIProps) {
|
||||
],
|
||||
);
|
||||
|
||||
const visibleSymbols = SYMBOLS_WITH_VALUES.filter(
|
||||
symbol => props.columnConfig?.[symbol.columnKey]?.visible !== false,
|
||||
);
|
||||
|
||||
const { isOverflowing, symbolContainerRef, wrapperRef } =
|
||||
useOverflowDetection(flexGap);
|
||||
|
||||
@@ -244,51 +251,53 @@ export default function PopKPI(props: PopKPIProps) {
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div
|
||||
css={[
|
||||
css`
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
gap: ${flexGap}px;
|
||||
min-width: 0;
|
||||
flex-shrink: 1;
|
||||
`,
|
||||
isOverflowing
|
||||
? css`
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
width: fit-content;
|
||||
`
|
||||
: css`
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
`,
|
||||
]}
|
||||
ref={symbolContainerRef}
|
||||
>
|
||||
{SYMBOLS_WITH_VALUES.map((symbol_with_value, index) => (
|
||||
<ComparisonValue
|
||||
key={`comparison-symbol-${symbol_with_value.symbol}`}
|
||||
subheaderFontSize={subheaderFontSize}
|
||||
>
|
||||
<Tooltip
|
||||
id="tooltip"
|
||||
placement="top"
|
||||
title={symbol_with_value.tooltipText}
|
||||
{visibleSymbols.length > 0 && (
|
||||
<div
|
||||
css={[
|
||||
css`
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
gap: ${flexGap}px;
|
||||
min-width: 0;
|
||||
flex-shrink: 1;
|
||||
`,
|
||||
isOverflowing
|
||||
? css`
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
width: fit-content;
|
||||
`
|
||||
: css`
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
`,
|
||||
]}
|
||||
ref={symbolContainerRef}
|
||||
>
|
||||
{visibleSymbols.map((symbol_with_value, index) => (
|
||||
<ComparisonValue
|
||||
key={`comparison-symbol-${symbol_with_value.symbol}`}
|
||||
subheaderFontSize={subheaderFontSize}
|
||||
>
|
||||
<SymbolWrapper
|
||||
backgroundColor={
|
||||
index > 0 ? backgroundColor : defaultBackgroundColor
|
||||
}
|
||||
textColor={index > 0 ? textColor : defaultTextColor}
|
||||
<Tooltip
|
||||
id="tooltip"
|
||||
placement="top"
|
||||
title={symbol_with_value.tooltipText}
|
||||
>
|
||||
{symbol_with_value.symbol}
|
||||
</SymbolWrapper>
|
||||
{symbol_with_value.value}
|
||||
</Tooltip>
|
||||
</ComparisonValue>
|
||||
))}
|
||||
</div>
|
||||
<SymbolWrapper
|
||||
backgroundColor={
|
||||
index > 0 ? backgroundColor : defaultBackgroundColor
|
||||
}
|
||||
textColor={index > 0 ? textColor : defaultTextColor}
|
||||
>
|
||||
{symbol_with_value.symbol}
|
||||
</SymbolWrapper>
|
||||
{symbol_with_value.value}
|
||||
</Tooltip>
|
||||
</ComparisonValue>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</NumbersContainer>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { t } from '@superset-ui/core';
|
||||
import { t, GenericDataType } from '@superset-ui/core';
|
||||
import {
|
||||
ControlPanelConfig,
|
||||
getStandardizedControls,
|
||||
@@ -106,6 +106,42 @@ const config: ControlPanelConfig = {
|
||||
},
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
name: 'column_config',
|
||||
config: {
|
||||
type: 'ColumnConfigControl',
|
||||
label: t('Customize columns'),
|
||||
description: t('Further customize how to display each column'),
|
||||
width: 400,
|
||||
height: 320,
|
||||
renderTrigger: true,
|
||||
configFormLayout: {
|
||||
[GenericDataType.Numeric]: [
|
||||
{
|
||||
tab: t('General'),
|
||||
children: [['visible']],
|
||||
},
|
||||
],
|
||||
},
|
||||
shouldMapStateToProps() {
|
||||
return true;
|
||||
},
|
||||
mapStateToProps(explore, _, chart) {
|
||||
return {
|
||||
columnsPropsObject: {
|
||||
colnames: ['Previous value', 'Delta', 'Percent change'],
|
||||
coltypes: [
|
||||
GenericDataType.Numeric,
|
||||
GenericDataType.Numeric,
|
||||
GenericDataType.Numeric,
|
||||
],
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
sections.timeComparisonControls({
|
||||
|
||||
@@ -89,6 +89,7 @@ export default function transformProps(chartProps: ChartProps) {
|
||||
comparisonColorScheme,
|
||||
comparisonColorEnabled,
|
||||
percentDifferenceFormat,
|
||||
columnConfig,
|
||||
} = formData;
|
||||
const { data: dataA = [] } = queriesData[0];
|
||||
const data = dataA;
|
||||
@@ -193,5 +194,6 @@ export default function transformProps(chartProps: ChartProps) {
|
||||
startDateOffset,
|
||||
shift: timeComparison,
|
||||
dashboardTimeRange: formData?.extraFormData?.time_range,
|
||||
columnConfig,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -33,6 +33,10 @@ export interface PopKPIStylesProps {
|
||||
comparisonColorEnabled: boolean;
|
||||
}
|
||||
|
||||
export type TableColumnConfig = {
|
||||
visible?: boolean;
|
||||
};
|
||||
|
||||
interface PopKPICustomizeProps {
|
||||
headerText: string;
|
||||
}
|
||||
@@ -66,6 +70,7 @@ export type PopKPIProps = PopKPIStylesProps &
|
||||
startDateOffset?: string;
|
||||
shift: string;
|
||||
dashboardTimeRange?: string;
|
||||
columnConfig?: Record<string, TableColumnConfig>;
|
||||
};
|
||||
|
||||
export enum ColorSchemeEnum {
|
||||
|
||||
@@ -24,6 +24,7 @@ import {
|
||||
QueryFormData,
|
||||
} from '@superset-ui/core';
|
||||
import {
|
||||
aggregationOperator,
|
||||
flattenOperator,
|
||||
pivotOperator,
|
||||
resampleOperator,
|
||||
@@ -47,5 +48,19 @@ export default function buildQuery(formData: QueryFormData) {
|
||||
flattenOperator(formData, baseQueryObject),
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
...baseQueryObject,
|
||||
columns: [
|
||||
...(isXAxisSet(formData)
|
||||
? ensureIsArray(getXAxisColumn(formData))
|
||||
: []),
|
||||
],
|
||||
...(isXAxisSet(formData) ? {} : { is_timeseries: true }),
|
||||
post_processing: [
|
||||
pivotOperator(formData, baseQueryObject),
|
||||
aggregationOperator(formData, baseQueryObject),
|
||||
],
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
*/
|
||||
import { SMART_DATE_ID, t } from '@superset-ui/core';
|
||||
import {
|
||||
aggregationControl,
|
||||
ControlPanelConfig,
|
||||
ControlSubSectionHeader,
|
||||
D3_FORMAT_DOCS,
|
||||
@@ -35,6 +36,7 @@ const config: ControlPanelConfig = {
|
||||
controlSetRows: [
|
||||
['x_axis'],
|
||||
['time_grain_sqla'],
|
||||
[aggregationControl],
|
||||
['metric'],
|
||||
['adhoc_filters'],
|
||||
],
|
||||
|
||||
@@ -66,6 +66,7 @@ export default function transformProps(
|
||||
metric = 'value',
|
||||
showTimestamp,
|
||||
showTrendLine,
|
||||
aggregation,
|
||||
startYAxisAtZero,
|
||||
subheader = '',
|
||||
subheaderFontSize,
|
||||
@@ -82,6 +83,15 @@ export default function transformProps(
|
||||
from_dttm: fromDatetime,
|
||||
to_dttm: toDatetime,
|
||||
} = queriesData[0];
|
||||
|
||||
const aggregatedQueryData = queriesData.length > 1 ? queriesData[1] : null;
|
||||
|
||||
const hasAggregatedData =
|
||||
aggregatedQueryData?.data &&
|
||||
aggregatedQueryData.data.length > 0 &&
|
||||
aggregation !== 'LAST_VALUE';
|
||||
|
||||
const aggregatedData = hasAggregatedData ? aggregatedQueryData.data[0] : null;
|
||||
const refs: Refs = {};
|
||||
const metricName = getMetricLabel(metric);
|
||||
const compareLag = Number(compareLag_) || 0;
|
||||
@@ -95,18 +105,39 @@ export default function transformProps(
|
||||
let percentChange = 0;
|
||||
let bigNumber = data.length === 0 ? null : data[0][metricName];
|
||||
let timestamp = data.length === 0 ? null : data[0][xAxisLabel];
|
||||
let bigNumberFallback;
|
||||
|
||||
const metricColtypeIndex = colnames.findIndex(name => name === metricName);
|
||||
const metricColtype =
|
||||
metricColtypeIndex > -1 ? coltypes[metricColtypeIndex] : null;
|
||||
let bigNumberFallback = null;
|
||||
let sortedData: [number | null, number | null][] = [];
|
||||
|
||||
if (data.length > 0) {
|
||||
const sortedData = (data as BigNumberDatum[])
|
||||
.map(d => [d[xAxisLabel], parseMetricValue(d[metricName])])
|
||||
sortedData = (data as BigNumberDatum[])
|
||||
.map(
|
||||
d =>
|
||||
[d[xAxisLabel], parseMetricValue(d[metricName])] as [
|
||||
number | null,
|
||||
number | null,
|
||||
],
|
||||
)
|
||||
// sort in time descending order
|
||||
.sort((a, b) => (a[0] !== null && b[0] !== null ? b[0] - a[0] : 0));
|
||||
}
|
||||
if (hasAggregatedData && aggregatedData) {
|
||||
if (
|
||||
aggregatedData[metricName] !== null &&
|
||||
aggregatedData[metricName] !== undefined
|
||||
) {
|
||||
bigNumber = aggregatedData[metricName];
|
||||
} else {
|
||||
const metricKeys = Object.keys(aggregatedData).filter(
|
||||
key =>
|
||||
key !== xAxisLabel &&
|
||||
aggregatedData[key] !== null &&
|
||||
typeof aggregatedData[key] === 'number',
|
||||
);
|
||||
bigNumber = metricKeys.length > 0 ? aggregatedData[metricKeys[0]] : null;
|
||||
}
|
||||
|
||||
timestamp = sortedData.length > 0 ? sortedData[0][0] : null;
|
||||
} else if (sortedData.length > 0) {
|
||||
bigNumber = sortedData[0][1];
|
||||
timestamp = sortedData[0][0];
|
||||
|
||||
@@ -115,25 +146,28 @@ export default function transformProps(
|
||||
bigNumber = bigNumberFallback ? bigNumberFallback[1] : null;
|
||||
timestamp = bigNumberFallback ? bigNumberFallback[0] : null;
|
||||
}
|
||||
}
|
||||
|
||||
if (compareLag > 0) {
|
||||
const compareIndex = compareLag;
|
||||
if (compareIndex < sortedData.length) {
|
||||
const compareValue = sortedData[compareIndex][1];
|
||||
// compare values must both be non-nulls
|
||||
if (bigNumber !== null && compareValue !== null) {
|
||||
percentChange = compareValue
|
||||
? (bigNumber - compareValue) / Math.abs(compareValue)
|
||||
: 0;
|
||||
formattedSubheader = `${formatPercentChange(
|
||||
percentChange,
|
||||
)} ${compareSuffix}`;
|
||||
}
|
||||
if (compareLag > 0 && sortedData.length > 0) {
|
||||
const compareIndex = compareLag;
|
||||
if (compareIndex < sortedData.length) {
|
||||
const compareValue = sortedData[compareIndex][1];
|
||||
// compare values must both be non-nulls
|
||||
if (bigNumber !== null && compareValue !== null) {
|
||||
percentChange = compareValue
|
||||
? (Number(bigNumber) - compareValue) / Math.abs(compareValue)
|
||||
: 0;
|
||||
formattedSubheader = `${formatPercentChange(
|
||||
percentChange,
|
||||
)} ${compareSuffix}`;
|
||||
}
|
||||
}
|
||||
sortedData.reverse();
|
||||
}
|
||||
|
||||
if (data.length > 0) {
|
||||
const reversedData = [...sortedData].reverse();
|
||||
// @ts-ignore
|
||||
trendLineData = showTrendLine ? sortedData : undefined;
|
||||
trendLineData = showTrendLine ? reversedData : undefined;
|
||||
}
|
||||
|
||||
let className = '';
|
||||
@@ -143,6 +177,10 @@ export default function transformProps(
|
||||
className = 'negative';
|
||||
}
|
||||
|
||||
const metricColtypeIndex = colnames.findIndex(name => name === metricName);
|
||||
const metricColtype =
|
||||
metricColtypeIndex > -1 ? coltypes[metricColtypeIndex] : null;
|
||||
|
||||
let metricEntry: Metric | undefined;
|
||||
if (chartProps.datasource?.metrics) {
|
||||
metricEntry = chartProps.datasource.metrics.find(
|
||||
|
||||
@@ -201,7 +201,7 @@ export default function transformProps(chartProps: EchartsBubbleChartProps) {
|
||||
name: bubbleXAxisTitle,
|
||||
nameLocation: 'middle',
|
||||
nameTextStyle: {
|
||||
fontWight: 'bolder',
|
||||
fontWeight: 'bolder',
|
||||
},
|
||||
nameGap: convertInteger(xAxisTitleMargin),
|
||||
type: xAxisType,
|
||||
@@ -219,7 +219,7 @@ export default function transformProps(chartProps: EchartsBubbleChartProps) {
|
||||
name: bubbleYAxisTitle,
|
||||
nameLocation: 'middle',
|
||||
nameTextStyle: {
|
||||
fontWight: 'bolder',
|
||||
fontWeight: 'bolder',
|
||||
},
|
||||
nameGap: convertInteger(yAxisTitleMargin),
|
||||
min: yAxisMin,
|
||||
|
||||
@@ -122,7 +122,7 @@ function createAxisTitleControl(axis: 'x' | 'y'): ControlSetRow[] {
|
||||
clearable: true,
|
||||
label: t('AXIS TITLE MARGIN'),
|
||||
renderTrigger: true,
|
||||
default: sections.TITLE_MARGIN_OPTIONS[0],
|
||||
default: sections.TITLE_MARGIN_OPTIONS[1],
|
||||
choices: formatSelectOptions(sections.TITLE_MARGIN_OPTIONS),
|
||||
description: t('Changing this control takes effect instantly'),
|
||||
visibility: ({ controls }: ControlPanelsContainerProps) =>
|
||||
|
||||
@@ -89,9 +89,9 @@ const controlPanel: ControlPanelConfig = {
|
||||
{
|
||||
name: 'metric',
|
||||
config: {
|
||||
...optionalEntity,
|
||||
type: 'DndMetricSelect',
|
||||
label: t('Metric'),
|
||||
...sharedControls.metric,
|
||||
clearable: true,
|
||||
validators: [],
|
||||
description: t('Metric for node values'),
|
||||
},
|
||||
},
|
||||
|
||||
@@ -27,8 +27,10 @@ import {
|
||||
Ref,
|
||||
} from 'react';
|
||||
|
||||
import { useSelector } from 'react-redux';
|
||||
|
||||
import { styled } from '@superset-ui/core';
|
||||
import { use, init, EChartsType } from 'echarts/core';
|
||||
import { use, init, EChartsType, registerLocale } from 'echarts/core';
|
||||
import {
|
||||
SankeyChart,
|
||||
PieChart,
|
||||
@@ -60,6 +62,15 @@ import {
|
||||
} from 'echarts/components';
|
||||
import { LabelLayout } from 'echarts/features';
|
||||
import { EchartsHandler, EchartsProps, EchartsStylesProps } from '../types';
|
||||
import { DEFAULT_LOCALE } from '../constants';
|
||||
|
||||
// Define this interface here to avoid creating a dependency back to superset-frontend,
|
||||
// TODO: to move the type to @superset-ui/core
|
||||
interface ExplorePageState {
|
||||
common: {
|
||||
locale: string;
|
||||
};
|
||||
}
|
||||
|
||||
const Styles = styled.div<EchartsStylesProps>`
|
||||
height: ${({ height }) => height};
|
||||
@@ -123,24 +134,52 @@ function Echart(
|
||||
getEchartInstance: () => chartRef.current,
|
||||
}));
|
||||
|
||||
const locale = useSelector(
|
||||
(state: ExplorePageState) => state?.common?.locale ?? DEFAULT_LOCALE,
|
||||
).toUpperCase();
|
||||
|
||||
const handleSizeChange = useCallback(
|
||||
({ width, height }: { width: number; height: number }) => {
|
||||
if (chartRef.current) {
|
||||
chartRef.current.resize({ width, height });
|
||||
}
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!divRef.current) return;
|
||||
if (!chartRef.current) {
|
||||
chartRef.current = init(divRef.current);
|
||||
}
|
||||
const loadLocaleAndInitChart = async () => {
|
||||
if (!divRef.current) return;
|
||||
|
||||
Object.entries(eventHandlers || {}).forEach(([name, handler]) => {
|
||||
chartRef.current?.off(name);
|
||||
chartRef.current?.on(name, handler);
|
||||
});
|
||||
const lang = await import(`echarts/lib/i18n/lang${locale}`).catch(e => {
|
||||
console.error(`Locale ${locale} not supported in ECharts`, e);
|
||||
});
|
||||
if (lang?.default) {
|
||||
registerLocale(locale, lang.default);
|
||||
}
|
||||
|
||||
Object.entries(zrEventHandlers || {}).forEach(([name, handler]) => {
|
||||
chartRef.current?.getZr().off(name);
|
||||
chartRef.current?.getZr().on(name, handler);
|
||||
});
|
||||
if (!chartRef.current) {
|
||||
chartRef.current = init(divRef.current, null, { locale });
|
||||
}
|
||||
|
||||
chartRef.current.setOption(echartOptions, true);
|
||||
}, [echartOptions, eventHandlers, zrEventHandlers]);
|
||||
Object.entries(eventHandlers || {}).forEach(([name, handler]) => {
|
||||
chartRef.current?.off(name);
|
||||
chartRef.current?.on(name, handler);
|
||||
});
|
||||
|
||||
Object.entries(zrEventHandlers || {}).forEach(([name, handler]) => {
|
||||
chartRef.current?.getZr().off(name);
|
||||
chartRef.current?.getZr().on(name, handler);
|
||||
});
|
||||
|
||||
chartRef.current.setOption(echartOptions, true);
|
||||
|
||||
// did mount
|
||||
handleSizeChange({ width, height });
|
||||
};
|
||||
|
||||
loadLocaleAndInitChart();
|
||||
}, [echartOptions, eventHandlers, zrEventHandlers, locale]);
|
||||
|
||||
// highlighting
|
||||
useEffect(() => {
|
||||
@@ -158,22 +197,7 @@ function Echart(
|
||||
});
|
||||
}
|
||||
previousSelection.current = currentSelection;
|
||||
}, [currentSelection]);
|
||||
|
||||
const handleSizeChange = useCallback(
|
||||
({ width, height }: { width: number; height: number }) => {
|
||||
if (chartRef.current) {
|
||||
chartRef.current.resize({ width, height });
|
||||
}
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
// did mount
|
||||
useEffect(() => {
|
||||
handleSizeChange({ width, height });
|
||||
return () => chartRef.current?.dispose();
|
||||
}, []);
|
||||
}, [currentSelection, chartRef.current]);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
handleSizeChange({ width, height });
|
||||
|
||||
@@ -121,3 +121,5 @@ export const TOOLTIP_POINTER_MARGIN = 10;
|
||||
// If no satisfactory position can be found, how far away
|
||||
// from the edge of the window should the tooltip be kept
|
||||
export const TOOLTIP_OVERFLOW_MARGIN = 5;
|
||||
|
||||
export const DEFAULT_LOCALE = 'en';
|
||||
|
||||
@@ -156,9 +156,15 @@ export function sortAndFilterSeries(
|
||||
case SortSeriesType.Avg:
|
||||
aggregator = name => ({ name, value: meanBy(rows, name) });
|
||||
break;
|
||||
default:
|
||||
aggregator = name => ({ name, value: name.toLowerCase() });
|
||||
break;
|
||||
default: {
|
||||
const collator = new Intl.Collator(undefined, {
|
||||
numeric: true,
|
||||
sensitivity: 'base',
|
||||
});
|
||||
return seriesNames.sort((a, b) =>
|
||||
sortSeriesAscending ? collator.compare(a, b) : collator.compare(b, a),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const sortedValues = seriesNames.map(aggregator);
|
||||
|
||||
@@ -186,3 +186,188 @@ describe('BigNumberWithTrendline', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('BigNumberWithTrendline - Aggregation Tests', () => {
|
||||
const baseProps = {
|
||||
width: 800,
|
||||
height: 600,
|
||||
formData: {
|
||||
colorPicker: { r: 0, g: 0, b: 0, a: 1 },
|
||||
metric: 'metric',
|
||||
aggregation: 'LAST_VALUE',
|
||||
},
|
||||
queriesData: [
|
||||
{
|
||||
data: [
|
||||
{ __timestamp: 1607558400000, metric: 10 },
|
||||
{ __timestamp: 1607558500000, metric: 30 },
|
||||
{ __timestamp: 1607558600000, metric: 50 },
|
||||
{ __timestamp: 1607558700000, metric: 60 },
|
||||
],
|
||||
colnames: ['__timestamp', 'metric'],
|
||||
coltypes: ['TIMESTAMP', 'BIGINT'],
|
||||
},
|
||||
],
|
||||
hooks: {},
|
||||
filterState: {},
|
||||
datasource: {
|
||||
columnFormats: {},
|
||||
currencyFormats: {},
|
||||
},
|
||||
rawDatasource: {},
|
||||
rawFormData: {},
|
||||
theme: {
|
||||
colors: {
|
||||
grayscale: {
|
||||
light5: '#fafafa',
|
||||
},
|
||||
},
|
||||
},
|
||||
} as unknown as BigNumberWithTrendlineChartProps;
|
||||
|
||||
const propsWithEvenData = {
|
||||
...baseProps,
|
||||
queriesData: [
|
||||
{
|
||||
data: [
|
||||
{ __timestamp: 1607558400000, metric: 10 },
|
||||
{ __timestamp: 1607558500000, metric: 20 },
|
||||
{ __timestamp: 1607558600000, metric: 30 },
|
||||
{ __timestamp: 1607558700000, metric: 40 },
|
||||
],
|
||||
colnames: ['__timestamp', 'metric'],
|
||||
coltypes: ['TIMESTAMP', 'BIGINT'],
|
||||
},
|
||||
],
|
||||
} as unknown as BigNumberWithTrendlineChartProps;
|
||||
|
||||
it('should correctly calculate SUM', () => {
|
||||
const props = {
|
||||
...baseProps,
|
||||
formData: { ...baseProps.formData, aggregation: 'sum' },
|
||||
queriesData: [
|
||||
baseProps.queriesData[0],
|
||||
{
|
||||
data: [{ metric: 150 }],
|
||||
colnames: ['metric'],
|
||||
coltypes: ['BIGINT'],
|
||||
},
|
||||
],
|
||||
} as unknown as BigNumberWithTrendlineChartProps;
|
||||
|
||||
const transformed = transformProps(props);
|
||||
expect(transformed.bigNumber).toStrictEqual(150);
|
||||
});
|
||||
|
||||
it('should correctly calculate AVG', () => {
|
||||
const props = {
|
||||
...baseProps,
|
||||
formData: { ...baseProps.formData, aggregation: 'mean' },
|
||||
queriesData: [
|
||||
baseProps.queriesData[0],
|
||||
{
|
||||
data: [{ metric: 37.5 }],
|
||||
colnames: ['metric'],
|
||||
coltypes: ['BIGINT'],
|
||||
},
|
||||
],
|
||||
} as unknown as BigNumberWithTrendlineChartProps;
|
||||
|
||||
const transformed = transformProps(props);
|
||||
expect(transformed.bigNumber).toStrictEqual(37.5);
|
||||
});
|
||||
|
||||
it('should correctly calculate MIN', () => {
|
||||
const props = {
|
||||
...baseProps,
|
||||
formData: { ...baseProps.formData, aggregation: 'min' },
|
||||
queriesData: [
|
||||
baseProps.queriesData[0],
|
||||
{
|
||||
data: [{ metric: 10 }],
|
||||
colnames: ['metric'],
|
||||
coltypes: ['BIGINT'],
|
||||
},
|
||||
],
|
||||
} as unknown as BigNumberWithTrendlineChartProps;
|
||||
|
||||
const transformed = transformProps(props);
|
||||
expect(transformed.bigNumber).toStrictEqual(10);
|
||||
});
|
||||
|
||||
it('should correctly calculate MAX', () => {
|
||||
const props = {
|
||||
...baseProps,
|
||||
formData: { ...baseProps.formData, aggregation: 'max' },
|
||||
queriesData: [
|
||||
baseProps.queriesData[0],
|
||||
{
|
||||
data: [{ metric: 60 }],
|
||||
colnames: ['metric'],
|
||||
coltypes: ['BIGINT'],
|
||||
},
|
||||
],
|
||||
} as unknown as BigNumberWithTrendlineChartProps;
|
||||
|
||||
const transformed = transformProps(props);
|
||||
expect(transformed.bigNumber).toStrictEqual(60);
|
||||
});
|
||||
|
||||
it('should correctly calculate MEDIAN (odd count)', () => {
|
||||
const oddCountProps = {
|
||||
...baseProps,
|
||||
queriesData: [
|
||||
{
|
||||
data: [
|
||||
{ __timestamp: 1607558300000, metric: 10 },
|
||||
{ __timestamp: 1607558400000, metric: 20 },
|
||||
{ __timestamp: 1607558500000, metric: 30 },
|
||||
{ __timestamp: 1607558600000, metric: 40 },
|
||||
{ __timestamp: 1607558700000, metric: 50 },
|
||||
],
|
||||
colnames: ['__timestamp', 'metric'],
|
||||
coltypes: ['TIMESTAMP', 'BIGINT'],
|
||||
},
|
||||
],
|
||||
} as unknown as BigNumberWithTrendlineChartProps;
|
||||
|
||||
const props = {
|
||||
...oddCountProps,
|
||||
formData: { ...oddCountProps.formData, aggregation: 'median' },
|
||||
queriesData: [
|
||||
oddCountProps.queriesData[0],
|
||||
{
|
||||
data: [{ metric: 30 }],
|
||||
colnames: ['metric'],
|
||||
coltypes: ['BIGINT'],
|
||||
},
|
||||
],
|
||||
} as unknown as BigNumberWithTrendlineChartProps;
|
||||
|
||||
const transformed = transformProps(props);
|
||||
expect(transformed.bigNumber).toStrictEqual(30);
|
||||
});
|
||||
|
||||
it('should correctly calculate MEDIAN (even count)', () => {
|
||||
const props = {
|
||||
...propsWithEvenData,
|
||||
formData: { ...propsWithEvenData.formData, aggregation: 'median' },
|
||||
queriesData: [
|
||||
propsWithEvenData.queriesData[0],
|
||||
{
|
||||
data: [{ metric: 25 }],
|
||||
colnames: ['metric'],
|
||||
coltypes: ['BIGINT'],
|
||||
},
|
||||
],
|
||||
} as unknown as BigNumberWithTrendlineChartProps;
|
||||
|
||||
const transformed = transformProps(props);
|
||||
expect(transformed.bigNumber).toStrictEqual(25);
|
||||
});
|
||||
|
||||
it('should return the LAST_VALUE correctly', () => {
|
||||
const transformed = transformProps(baseProps);
|
||||
expect(transformed.bigNumber).toStrictEqual(10);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -67,6 +67,39 @@ const sortData: DataRecord[] = [
|
||||
{ my_x_axis: null, x: 4, y: 3, z: 7 },
|
||||
];
|
||||
|
||||
const sortDataWithNumbers: DataRecord[] = [
|
||||
{
|
||||
my_x_axis: 'my_axis',
|
||||
'9. September': 6,
|
||||
6: 1,
|
||||
'11. November': 8,
|
||||
8: 2,
|
||||
'10. October': 1,
|
||||
10: 4,
|
||||
'3. March': 2,
|
||||
'8. August': 6,
|
||||
2: 1,
|
||||
12: 3,
|
||||
9: 1,
|
||||
'1. January': 1,
|
||||
'4. April': 12,
|
||||
'2. February': 9,
|
||||
5: 4,
|
||||
3: 1,
|
||||
11: 2,
|
||||
'12. December': 4,
|
||||
1: 7,
|
||||
'6. June': 1,
|
||||
4: 5,
|
||||
7: 2,
|
||||
c: 0,
|
||||
'7. July': 2,
|
||||
d: 0,
|
||||
'5. May': 4,
|
||||
a: 1,
|
||||
},
|
||||
];
|
||||
|
||||
const totalStackedValues = [3, 15, 14];
|
||||
|
||||
test('sortRows by name ascending', () => {
|
||||
@@ -288,6 +321,84 @@ test('sortAndFilterSeries by name descending', () => {
|
||||
sortAndFilterSeries(sortData, 'my_x_axis', [], SortSeriesType.Name, false),
|
||||
).toEqual(['z', 'y', 'x']);
|
||||
});
|
||||
test('sortAndFilterSeries by name with numbers asc', () => {
|
||||
expect(
|
||||
sortAndFilterSeries(
|
||||
sortDataWithNumbers,
|
||||
'my_x_axis',
|
||||
[],
|
||||
SortSeriesType.Name,
|
||||
true,
|
||||
),
|
||||
).toEqual([
|
||||
'1',
|
||||
'1. January',
|
||||
'2',
|
||||
'2. February',
|
||||
'3',
|
||||
'3. March',
|
||||
'4',
|
||||
'4. April',
|
||||
'5',
|
||||
'5. May',
|
||||
'6',
|
||||
'6. June',
|
||||
'7',
|
||||
'7. July',
|
||||
'8',
|
||||
'8. August',
|
||||
'9',
|
||||
'9. September',
|
||||
'10',
|
||||
'10. October',
|
||||
'11',
|
||||
'11. November',
|
||||
'12',
|
||||
'12. December',
|
||||
'a',
|
||||
'c',
|
||||
'd',
|
||||
]);
|
||||
});
|
||||
test('sortAndFilterSeries by name with numbers desc', () => {
|
||||
expect(
|
||||
sortAndFilterSeries(
|
||||
sortDataWithNumbers,
|
||||
'my_x_axis',
|
||||
[],
|
||||
SortSeriesType.Name,
|
||||
false,
|
||||
),
|
||||
).toEqual([
|
||||
'd',
|
||||
'c',
|
||||
'a',
|
||||
'12. December',
|
||||
'12',
|
||||
'11. November',
|
||||
'11',
|
||||
'10. October',
|
||||
'10',
|
||||
'9. September',
|
||||
'9',
|
||||
'8. August',
|
||||
'8',
|
||||
'7. July',
|
||||
'7',
|
||||
'6. June',
|
||||
'6',
|
||||
'5. May',
|
||||
'5',
|
||||
'4. April',
|
||||
'4',
|
||||
'3. March',
|
||||
'3',
|
||||
'2. February',
|
||||
'2',
|
||||
'1. January',
|
||||
'1',
|
||||
]);
|
||||
});
|
||||
|
||||
describe('extractSeries', () => {
|
||||
it('should generate a valid ECharts timeseries series object', () => {
|
||||
|
||||
@@ -51,7 +51,6 @@ const Styles = styled.div<PivotTableStylesProps>`
|
||||
width: ${
|
||||
typeof width === 'string' ? parseInt(width, 10) : width - margin * 2
|
||||
}px;
|
||||
white-space: nowrap;
|
||||
`}
|
||||
`;
|
||||
|
||||
|
||||
@@ -605,6 +605,8 @@ export default function TableChart<D extends DataRecord = DataRecord>(
|
||||
// Calculate the number of placeholder columns needed before the current header
|
||||
const startPosition = value[0];
|
||||
const colSpan = value.length;
|
||||
// Retrieve the originalLabel from the first column in this group
|
||||
const originalLabel = columnsMeta[value[0]]?.originalLabel || key;
|
||||
|
||||
// Add placeholder <th> for columns before this header
|
||||
for (let i = currentColumnIndex; i < startPosition; i += 1) {
|
||||
@@ -620,7 +622,7 @@ export default function TableChart<D extends DataRecord = DataRecord>(
|
||||
// Add the current header <th>
|
||||
headers.push(
|
||||
<th key={`header-${key}`} colSpan={colSpan} style={{ borderBottom: 0 }}>
|
||||
{key}
|
||||
{originalLabel}
|
||||
<span
|
||||
css={css`
|
||||
float: right;
|
||||
@@ -975,7 +977,7 @@ export default function TableChart<D extends DataRecord = DataRecord>(
|
||||
),
|
||||
Footer: totals ? (
|
||||
i === 0 ? (
|
||||
<th>
|
||||
<th key={`footer-summary-${i}`}>
|
||||
<div
|
||||
css={css`
|
||||
display: flex;
|
||||
@@ -997,7 +999,7 @@ export default function TableChart<D extends DataRecord = DataRecord>(
|
||||
</div>
|
||||
</th>
|
||||
) : (
|
||||
<td style={sharedStyle}>
|
||||
<td key={`footer-total-${i}`} style={sharedStyle}>
|
||||
<strong>{formatColumnValue(column, totals[key])[1]}</strong>
|
||||
</td>
|
||||
)
|
||||
|
||||
@@ -198,11 +198,6 @@ const buildQuery: BuildQuery<TableChartFormData> = (
|
||||
(ownState.currentPage ?? 0) * (ownState.pageSize ?? 0);
|
||||
}
|
||||
|
||||
if (!temporalColumn) {
|
||||
// This query is not using temporal column, so it doesn't need time grain
|
||||
extras.time_grain_sqla = undefined;
|
||||
}
|
||||
|
||||
let queryObject = {
|
||||
...baseQueryObject,
|
||||
columns,
|
||||
|
||||
@@ -486,8 +486,9 @@ const config: ControlPanelConfig = {
|
||||
return true;
|
||||
},
|
||||
mapStateToProps(explore, _, chart) {
|
||||
const timeComparisonStatus =
|
||||
!!explore?.controls?.time_compare?.value;
|
||||
const timeComparisonStatus = !isEmpty(
|
||||
explore?.controls?.time_compare?.value,
|
||||
);
|
||||
|
||||
const { colnames: _colnames, coltypes: _coltypes } =
|
||||
chart?.queriesResponse?.[0] ?? {};
|
||||
|
||||
@@ -347,6 +347,7 @@ const processComparisonColumns = (
|
||||
} = props;
|
||||
const savedFormat = columnFormats?.[col.key];
|
||||
const savedCurrency = currencyFormats?.[col.key];
|
||||
const originalLabel = col.label;
|
||||
if (
|
||||
(col.isMetric || col.isPercentMetric) &&
|
||||
!col.key.includes(comparisonSuffix) &&
|
||||
@@ -355,6 +356,7 @@ const processComparisonColumns = (
|
||||
return [
|
||||
{
|
||||
...col,
|
||||
originalLabel,
|
||||
label: t('Main'),
|
||||
key: `${t('Main')} ${col.key}`,
|
||||
config: getComparisonColConfig(t('Main'), col.key, columnConfig),
|
||||
@@ -368,6 +370,7 @@ const processComparisonColumns = (
|
||||
},
|
||||
{
|
||||
...col,
|
||||
originalLabel,
|
||||
label: `#`,
|
||||
key: `# ${col.key}`,
|
||||
config: getComparisonColConfig(`#`, col.key, columnConfig),
|
||||
@@ -381,6 +384,7 @@ const processComparisonColumns = (
|
||||
},
|
||||
{
|
||||
...col,
|
||||
originalLabel,
|
||||
label: `△`,
|
||||
key: `△ ${col.key}`,
|
||||
config: getComparisonColConfig(`△`, col.key, columnConfig),
|
||||
@@ -394,6 +398,7 @@ const processComparisonColumns = (
|
||||
},
|
||||
{
|
||||
...col,
|
||||
originalLabel,
|
||||
label: `%`,
|
||||
key: `% ${col.key}`,
|
||||
config: getComparisonColConfig(`%`, col.key, columnConfig),
|
||||
|
||||
@@ -56,6 +56,8 @@ export interface DataColumnMeta {
|
||||
key: string;
|
||||
// `label` is verbose column name used for rendering
|
||||
label: string;
|
||||
// `originalLabel` preserves the original label when time comparison transforms the labels
|
||||
originalLabel?: string;
|
||||
dataType: GenericDataType;
|
||||
formatter?:
|
||||
| TimeFormatter
|
||||
|
||||
@@ -175,6 +175,75 @@ describe('plugin-chart-table', () => {
|
||||
?.formatter?.(0.123456);
|
||||
expect(formattedPercentMetric).toBe('0.123');
|
||||
});
|
||||
|
||||
it('should set originalLabel for comparison columns when time_compare and comparison_type are set', () => {
|
||||
const transformedProps = transformProps(testData.comparison);
|
||||
|
||||
// Check if comparison columns are processed
|
||||
const comparisonColumns = transformedProps.columns.filter(
|
||||
col =>
|
||||
col.label === 'Main' ||
|
||||
col.label === '#' ||
|
||||
col.label === '△' ||
|
||||
col.label === '%',
|
||||
);
|
||||
|
||||
expect(comparisonColumns.length).toBeGreaterThan(0);
|
||||
expect(comparisonColumns.some(col => col.label === 'Main')).toBe(true);
|
||||
expect(comparisonColumns.some(col => col.label === '#')).toBe(true);
|
||||
expect(comparisonColumns.some(col => col.label === '△')).toBe(true);
|
||||
expect(comparisonColumns.some(col => col.label === '%')).toBe(true);
|
||||
|
||||
// Verify originalLabel for metric_1 comparison columns
|
||||
const mainMetric1 = transformedProps.columns.find(
|
||||
col => col.key === 'Main metric_1',
|
||||
);
|
||||
expect(mainMetric1).toBeDefined();
|
||||
expect(mainMetric1?.originalLabel).toBe('metric_1');
|
||||
|
||||
const hashMetric1 = transformedProps.columns.find(
|
||||
col => col.key === '# metric_1',
|
||||
);
|
||||
expect(hashMetric1).toBeDefined();
|
||||
expect(hashMetric1?.originalLabel).toBe('metric_1');
|
||||
|
||||
const deltaMetric1 = transformedProps.columns.find(
|
||||
col => col.key === '△ metric_1',
|
||||
);
|
||||
expect(deltaMetric1).toBeDefined();
|
||||
expect(deltaMetric1?.originalLabel).toBe('metric_1');
|
||||
|
||||
const percentMetric1 = transformedProps.columns.find(
|
||||
col => col.key === '% metric_1',
|
||||
);
|
||||
expect(percentMetric1).toBeDefined();
|
||||
expect(percentMetric1?.originalLabel).toBe('metric_1');
|
||||
|
||||
// Verify originalLabel for metric_2 comparison columns
|
||||
const mainMetric2 = transformedProps.columns.find(
|
||||
col => col.key === 'Main metric_2',
|
||||
);
|
||||
expect(mainMetric2).toBeDefined();
|
||||
expect(mainMetric2?.originalLabel).toBe('metric_2');
|
||||
|
||||
const hashMetric2 = transformedProps.columns.find(
|
||||
col => col.key === '# metric_2',
|
||||
);
|
||||
expect(hashMetric2).toBeDefined();
|
||||
expect(hashMetric2?.originalLabel).toBe('metric_2');
|
||||
|
||||
const deltaMetric2 = transformedProps.columns.find(
|
||||
col => col.key === '△ metric_2',
|
||||
);
|
||||
expect(deltaMetric2).toBeDefined();
|
||||
expect(deltaMetric2?.originalLabel).toBe('metric_2');
|
||||
|
||||
const percentMetric2 = transformedProps.columns.find(
|
||||
col => col.key === '% metric_2',
|
||||
);
|
||||
expect(percentMetric2).toBeDefined();
|
||||
expect(percentMetric2?.originalLabel).toBe('metric_2');
|
||||
});
|
||||
});
|
||||
|
||||
describe('TableChart', () => {
|
||||
@@ -400,6 +469,17 @@ describe('plugin-chart-table', () => {
|
||||
);
|
||||
expect(getComputedStyle(screen.getByText('N/A')).background).toBe('');
|
||||
});
|
||||
it('should display originalLabel in grouped headers', () => {
|
||||
render(
|
||||
<ThemeProvider theme={supersetTheme}>
|
||||
<TableChart {...transformProps(testData.comparison)} sticky={false} />
|
||||
</ThemeProvider>,
|
||||
);
|
||||
|
||||
const groupHeaders = screen.getAllByRole('columnheader');
|
||||
expect(groupHeaders[0]).toHaveTextContent('metric_1');
|
||||
expect(groupHeaders[1]).toHaveTextContent('metric_2');
|
||||
});
|
||||
});
|
||||
|
||||
it('render cell bars properly, and only when it is toggled on in both regular and percent metrics', () => {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user