mirror of
https://github.com/apache/superset.git
synced 2026-05-01 05:54:26 +00:00
Compare commits
20 Commits
fix/postgr
...
docs/db-ca
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b8123f87ed | ||
|
|
5dc9ca153e | ||
|
|
88a28b180a | ||
|
|
5f0fe4a2b7 | ||
|
|
97af6bd9f7 | ||
|
|
3c19df8706 | ||
|
|
b9de3dba95 | ||
|
|
4c4905f689 | ||
|
|
2b13e07521 | ||
|
|
7c24214857 | ||
|
|
37bf729f75 | ||
|
|
0b78ffbb9c | ||
|
|
41823a3057 | ||
|
|
4cc4d62486 | ||
|
|
dece5415a7 | ||
|
|
ea8a8f8ac7 | ||
|
|
a216b23d5a | ||
|
|
6ad1583eb5 | ||
|
|
9a7938899e | ||
|
|
30bd490b84 |
@@ -64,7 +64,7 @@ There are two approaches to making dashboards publicly accessible:
|
||||
3. Edit each dashboard's properties and add the "Public" role
|
||||
4. Only dashboards with the Public role explicitly assigned are visible to anonymous users
|
||||
|
||||
See the [Public role documentation](/admin-docs/security/security#public) for more details.
|
||||
See the [Public role documentation](/admin-docs/security/#public) for more details.
|
||||
|
||||
#### Embedding a Public Dashboard
|
||||
|
||||
@@ -111,7 +111,7 @@ FEATURE_FLAGS = {
|
||||
This flag only hides the logout button when Superset detects it is running inside an iframe. Users accessing Superset directly (not embedded) will still see the logout button regardless of this setting.
|
||||
|
||||
:::note
|
||||
When embedding with SSO, also set `SESSION_COOKIE_SAMESITE = 'None'` and `SESSION_COOKIE_SECURE = True`. See [Security documentation](/docs/security/securing_superset) for details.
|
||||
When embedding with SSO, also set `SESSION_COOKIE_SAMESITE = 'None'` and `SESSION_COOKIE_SECURE = True`. See [Security documentation](/admin-docs/security/securing_superset) for details.
|
||||
:::
|
||||
|
||||
## CSRF settings
|
||||
|
||||
@@ -20,7 +20,7 @@ To help make the problem somewhat tractable—given that Apache Superset has no
|
||||
|
||||
To strive for data consistency (regardless of the timezone of the client) the Apache Superset backend tries to ensure that any timestamp sent to the client has an explicit (or semi-explicit as in the case with [Epoch time](https://en.wikipedia.org/wiki/Unix_time) which is always in reference to UTC) timezone encoded within.
|
||||
|
||||
The challenge however lies with the slew of [database engines](/admin-docs/databases#installing-drivers-in-docker) which Apache Superset supports and various inconsistencies between their [Python Database API (DB-API)](https://www.python.org/dev/peps/pep-0249/) implementations combined with the fact that we use [Pandas](https://pandas.pydata.org/) to read SQL into a DataFrame prior to serializing to JSON. Regrettably Pandas ignores the DB-API [type_code](https://www.python.org/dev/peps/pep-0249/#type-objects) relying by default on the underlying Python type returned by the DB-API. Currently only a subset of the supported database engines work correctly with Pandas, i.e., ensuring timestamps without an explicit timestamp are serializd to JSON with the server timezone, thus guaranteeing the client will display timestamps in a consistent manner irrespective of the client's timezone.
|
||||
The challenge however lies with the slew of [database engines](/user-docs/databases#installing-drivers-in-docker) which Apache Superset supports and various inconsistencies between their [Python Database API (DB-API)](https://www.python.org/dev/peps/pep-0249/) implementations combined with the fact that we use [Pandas](https://pandas.pydata.org/) to read SQL into a DataFrame prior to serializing to JSON. Regrettably Pandas ignores the DB-API [type_code](https://www.python.org/dev/peps/pep-0249/#type-objects) relying by default on the underlying Python type returned by the DB-API. Currently only a subset of the supported database engines work correctly with Pandas, i.e., ensuring timestamps without an explicit timestamp are serialized to JSON with the server timezone, thus guaranteeing the client will display timestamps in a consistent manner irrespective of the client's timezone.
|
||||
|
||||
For example the following is a comparison of MySQL and Presto,
|
||||
|
||||
|
||||
@@ -149,7 +149,7 @@ For production clusters it's recommended to build own image with this step done
|
||||
Superset requires a Python DB-API database driver and a SQLAlchemy
|
||||
dialect to be installed for each datastore you want to connect to.
|
||||
|
||||
See [Install Database Drivers](/admin-docs/databases#installing-database-drivers) for more information.
|
||||
See [Install Database Drivers](/user-docs/databases#installing-database-drivers) for more information.
|
||||
It is recommended that you refer to versions listed in
|
||||
[pyproject.toml](https://github.com/apache/superset/blob/master/pyproject.toml)
|
||||
instead of hard-coding them in your bootstrap script, as seen below.
|
||||
|
||||
@@ -59,7 +59,7 @@ curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
|
||||
#### Core Resources
|
||||
|
||||
<details>
|
||||
<summary><strong>Dashboards</strong> (26 endpoints) — Create, read, update, and delete dashboards.</summary>
|
||||
<summary><strong>Dashboards</strong> (28 endpoints) — Create, read, update, and delete dashboards.</summary>
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
@@ -68,23 +68,25 @@ curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
|
||||
| `POST` | [Create a new dashboard](/developer-docs/api/create-a-new-dashboard) | `/api/v1/dashboard/` |
|
||||
| `GET` | [Get metadata information about this API resource (dashboard--info)](/developer-docs/api/get-metadata-information-about-this-api-resource-dashboard-info) | `/api/v1/dashboard/_info` |
|
||||
| `GET` | [Get a dashboard detail information](/developer-docs/api/get-a-dashboard-detail-information) | `/api/v1/dashboard/{id_or_slug}` |
|
||||
| `GET` | [Get a dashboard's chart definitions.](/developer-docs/api/get-a-dashboard-s-chart-definitions) | `/api/v1/dashboard/{id_or_slug}/charts` |
|
||||
| `GET` | [Get a dashboard's chart definitions.](/developer-docs/api/get-a-dashboards-chart-definitions) | `/api/v1/dashboard/{id_or_slug}/charts` |
|
||||
| `POST` | [Create a copy of an existing dashboard](/developer-docs/api/create-a-copy-of-an-existing-dashboard) | `/api/v1/dashboard/{id_or_slug}/copy/` |
|
||||
| `GET` | [Get dashboard's datasets](/developer-docs/api/get-dashboard-s-datasets) | `/api/v1/dashboard/{id_or_slug}/datasets` |
|
||||
| `DELETE` | [Delete a dashboard's embedded configuration](/developer-docs/api/delete-a-dashboard-s-embedded-configuration) | `/api/v1/dashboard/{id_or_slug}/embedded` |
|
||||
| `GET` | [Get the dashboard's embedded configuration](/developer-docs/api/get-the-dashboard-s-embedded-configuration) | `/api/v1/dashboard/{id_or_slug}/embedded` |
|
||||
| `POST` | [Set a dashboard's embedded configuration](/developer-docs/api/set-a-dashboard-s-embedded-configuration) | `/api/v1/dashboard/{id_or_slug}/embedded` |
|
||||
| `GET` | [Get dashboard's datasets](/developer-docs/api/get-dashboards-datasets) | `/api/v1/dashboard/{id_or_slug}/datasets` |
|
||||
| `DELETE` | [Delete a dashboard's embedded configuration](/developer-docs/api/delete-a-dashboards-embedded-configuration) | `/api/v1/dashboard/{id_or_slug}/embedded` |
|
||||
| `GET` | [Get the dashboard's embedded configuration](/developer-docs/api/get-the-dashboards-embedded-configuration) | `/api/v1/dashboard/{id_or_slug}/embedded` |
|
||||
| `POST` | [Set a dashboard's embedded configuration](/developer-docs/api/set-a-dashboards-embedded-configuration) | `/api/v1/dashboard/{id_or_slug}/embedded` |
|
||||
| `PUT` | [Update dashboard by id_or_slug embedded](/developer-docs/api/update-dashboard-by-id-or-slug-embedded) | `/api/v1/dashboard/{id_or_slug}/embedded` |
|
||||
| `GET` | [Get dashboard's tabs](/developer-docs/api/get-dashboard-s-tabs) | `/api/v1/dashboard/{id_or_slug}/tabs` |
|
||||
| `GET` | [Get dashboard's tabs](/developer-docs/api/get-dashboards-tabs) | `/api/v1/dashboard/{id_or_slug}/tabs` |
|
||||
| `DELETE` | [Delete a dashboard](/developer-docs/api/delete-a-dashboard) | `/api/v1/dashboard/{pk}` |
|
||||
| `PUT` | [Update a dashboard](/developer-docs/api/update-a-dashboard) | `/api/v1/dashboard/{pk}` |
|
||||
| `POST` | [Compute and cache a screenshot (dashboard-pk-cache-dashboard-screenshot)](/developer-docs/api/compute-and-cache-a-screenshot-dashboard-pk-cache-dashboard-screenshot) | `/api/v1/dashboard/{pk}/cache_dashboard_screenshot/` |
|
||||
| `PUT` | [Update chart customizations configuration for a dashboard.](/developer-docs/api/update-chart-customizations-configuration-for-a-dashboard) | `/api/v1/dashboard/{pk}/chart_customizations` |
|
||||
| `PUT` | [Update colors configuration for a dashboard.](/developer-docs/api/update-colors-configuration-for-a-dashboard) | `/api/v1/dashboard/{pk}/colors` |
|
||||
| `GET` | [Export dashboard as example bundle](/developer-docs/api/export-dashboard-as-example-bundle) | `/api/v1/dashboard/{pk}/export_as_example/` |
|
||||
| `DELETE` | [Remove the dashboard from the user favorite list](/developer-docs/api/remove-the-dashboard-from-the-user-favorite-list) | `/api/v1/dashboard/{pk}/favorites/` |
|
||||
| `POST` | [Mark the dashboard as favorite for the current user](/developer-docs/api/mark-the-dashboard-as-favorite-for-the-current-user) | `/api/v1/dashboard/{pk}/favorites/` |
|
||||
| `PUT` | [Update native filters configuration for a dashboard.](/developer-docs/api/update-native-filters-configuration-for-a-dashboard) | `/api/v1/dashboard/{pk}/filters` |
|
||||
| `GET` | [Get a computed screenshot from cache (dashboard-pk-screenshot-digest)](/developer-docs/api/get-a-computed-screenshot-from-cache-dashboard-pk-screenshot-digest) | `/api/v1/dashboard/{pk}/screenshot/{digest}/` |
|
||||
| `GET` | [Get dashboard's thumbnail](/developer-docs/api/get-dashboard-s-thumbnail) | `/api/v1/dashboard/{pk}/thumbnail/{digest}/` |
|
||||
| `GET` | [Get dashboard's thumbnail](/developer-docs/api/get-dashboards-thumbnail) | `/api/v1/dashboard/{pk}/thumbnail/{digest}/` |
|
||||
| `GET` | [Download multiple dashboards as YAML files](/developer-docs/api/download-multiple-dashboards-as-yaml-files) | `/api/v1/dashboard/export/` |
|
||||
| `GET` | [Check favorited dashboards for current user](/developer-docs/api/check-favorited-dashboards-for-current-user) | `/api/v1/dashboard/favorite_status/` |
|
||||
| `POST` | [Import dashboard(s) with associated charts/datasets/databases](/developer-docs/api/import-dashboard-s-with-associated-charts-datasets-databases) | `/api/v1/dashboard/import/` |
|
||||
@@ -101,8 +103,8 @@ curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
|
||||
| `GET` | [Get a list of charts](/developer-docs/api/get-a-list-of-charts) | `/api/v1/chart/` |
|
||||
| `POST` | [Create a new chart](/developer-docs/api/create-a-new-chart) | `/api/v1/chart/` |
|
||||
| `GET` | [Get metadata information about this API resource (chart--info)](/developer-docs/api/get-metadata-information-about-this-api-resource-chart-info) | `/api/v1/chart/_info` |
|
||||
| `GET` | [Get a chart detail information](/developer-docs/api/get-a-chart-detail-information) | `/api/v1/chart/{id_or_uuid}` |
|
||||
| `DELETE` | [Delete a chart](/developer-docs/api/delete-a-chart) | `/api/v1/chart/{pk}` |
|
||||
| `GET` | [Get a chart detail information](/developer-docs/api/get-a-chart-detail-information) | `/api/v1/chart/{pk}` |
|
||||
| `PUT` | [Update a chart](/developer-docs/api/update-a-chart) | `/api/v1/chart/{pk}` |
|
||||
| `GET` | [Compute and cache a screenshot (chart-pk-cache-screenshot)](/developer-docs/api/compute-and-cache-a-screenshot-chart-pk-cache-screenshot) | `/api/v1/chart/{pk}/cache_screenshot/` |
|
||||
| `GET` | [Return payload data response for a chart](/developer-docs/api/return-payload-data-response-for-a-chart) | `/api/v1/chart/{pk}/data/` |
|
||||
@@ -121,7 +123,7 @@ curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Datasets</strong> (18 endpoints) — Manage datasets (tables) used for building charts.</summary>
|
||||
<summary><strong>Datasets</strong> (19 endpoints) — Manage datasets (tables) used for building charts.</summary>
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
@@ -129,13 +131,14 @@ curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
|
||||
| `GET` | [Get a list of datasets](/developer-docs/api/get-a-list-of-datasets) | `/api/v1/dataset/` |
|
||||
| `POST` | [Create a new dataset](/developer-docs/api/create-a-new-dataset) | `/api/v1/dataset/` |
|
||||
| `GET` | [Get metadata information about this API resource (dataset--info)](/developer-docs/api/get-metadata-information-about-this-api-resource-dataset-info) | `/api/v1/dataset/_info` |
|
||||
| `GET` | [Get a dataset](/developer-docs/api/get-a-dataset) | `/api/v1/dataset/{id_or_uuid}` |
|
||||
| `GET` | [Get charts and dashboards count associated to a dataset](/developer-docs/api/get-charts-and-dashboards-count-associated-to-a-dataset) | `/api/v1/dataset/{id_or_uuid}/related_objects` |
|
||||
| `DELETE` | [Delete a dataset](/developer-docs/api/delete-a-dataset) | `/api/v1/dataset/{pk}` |
|
||||
| `GET` | [Get a dataset](/developer-docs/api/get-a-dataset) | `/api/v1/dataset/{pk}` |
|
||||
| `PUT` | [Update a dataset](/developer-docs/api/update-a-dataset) | `/api/v1/dataset/{pk}` |
|
||||
| `DELETE` | [Delete a dataset column](/developer-docs/api/delete-a-dataset-column) | `/api/v1/dataset/{pk}/column/{column_id}` |
|
||||
| `GET` | [Get dataset drill info](/developer-docs/api/get-dataset-drill-info) | `/api/v1/dataset/{pk}/drill_info/` |
|
||||
| `DELETE` | [Delete a dataset metric](/developer-docs/api/delete-a-dataset-metric) | `/api/v1/dataset/{pk}/metric/{metric_id}` |
|
||||
| `PUT` | [Refresh and update columns of a dataset](/developer-docs/api/refresh-and-update-columns-of-a-dataset) | `/api/v1/dataset/{pk}/refresh` |
|
||||
| `GET` | [Get charts and dashboards count associated to a dataset](/developer-docs/api/get-charts-and-dashboards-count-associated-to-a-dataset) | `/api/v1/dataset/{pk}/related_objects` |
|
||||
| `GET` | [Get distinct values from field data (dataset-distinct-column-name)](/developer-docs/api/get-distinct-values-from-field-data-dataset-distinct-column-name) | `/api/v1/dataset/distinct/{column_name}` |
|
||||
| `POST` | [Duplicate a dataset](/developer-docs/api/duplicate-a-dataset) | `/api/v1/dataset/duplicate` |
|
||||
| `GET` | [Download multiple datasets as YAML files](/developer-docs/api/download-multiple-datasets-as-yaml-files) | `/api/v1/dataset/export/` |
|
||||
@@ -147,7 +150,7 @@ curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Database</strong> (31 endpoints) — Manage database connections and metadata.</summary>
|
||||
<summary><strong>Database</strong> (30 endpoints) — Manage database connections and metadata.</summary>
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
@@ -165,7 +168,6 @@ curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
|
||||
| `GET` | [Get all schemas from a database](/developer-docs/api/get-all-schemas-from-a-database) | `/api/v1/database/{pk}/schemas/` |
|
||||
| `GET` | [Get database select star for table (database-pk-select-star-table-name)](/developer-docs/api/get-database-select-star-for-table-database-pk-select-star-table-name) | `/api/v1/database/{pk}/select_star/{table_name}/` |
|
||||
| `GET` | [Get database select star for table (database-pk-select-star-table-name-schema-name)](/developer-docs/api/get-database-select-star-for-table-database-pk-select-star-table-name-schema-name) | `/api/v1/database/{pk}/select_star/{table_name}/{schema_name}/` |
|
||||
| `DELETE` | [Delete a SSH tunnel](/developer-docs/api/delete-a-ssh-tunnel) | `/api/v1/database/{pk}/ssh_tunnel/` |
|
||||
| `POST` | [Re-sync all permissions for a database connection](/developer-docs/api/re-sync-all-permissions-for-a-database-connection) | `/api/v1/database/{pk}/sync_permissions/` |
|
||||
| `GET` | [Get table extra metadata (database-pk-table-extra-table-name-schema-name)](/developer-docs/api/get-table-extra-metadata-database-pk-table-extra-table-name-schema-name) | `/api/v1/database/{pk}/table_extra/{table_name}/{schema_name}/` |
|
||||
| `GET` | [Get table metadata](/developer-docs/api/get-table-metadata) | `/api/v1/database/{pk}/table_metadata/` |
|
||||
@@ -177,7 +179,7 @@ curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
|
||||
| `GET` | [Get names of databases currently available](/developer-docs/api/get-names-of-databases-currently-available) | `/api/v1/database/available/` |
|
||||
| `GET` | [Download database(s) and associated dataset(s) as a zip file](/developer-docs/api/download-database-s-and-associated-dataset-s-as-a-zip-file) | `/api/v1/database/export/` |
|
||||
| `POST` | [Import database(s) with associated datasets](/developer-docs/api/import-database-s-with-associated-datasets) | `/api/v1/database/import/` |
|
||||
| `GET` | [Receive personal access tokens from OAuth2](/developer-docs/api/receive-personal-access-tokens-from-oauth2) | `/api/v1/database/oauth2/` |
|
||||
| `GET` | [Receive personal access tokens from OAuth2](/developer-docs/api/receive-personal-access-tokens-from-o-auth-2) | `/api/v1/database/oauth2/` |
|
||||
| `GET` | [Get related fields data (database-related-column-name)](/developer-docs/api/get-related-fields-data-database-related-column-name) | `/api/v1/database/related/{column_name}` |
|
||||
| `POST` | [Test a database connection](/developer-docs/api/test-a-database-connection) | `/api/v1/database/test_connection/` |
|
||||
| `POST` | [Upload a file and returns file metadata](/developer-docs/api/upload-a-file-and-returns-file-metadata) | `/api/v1/database/upload_metadata/` |
|
||||
@@ -197,13 +199,14 @@ curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>SQL Lab</strong> (6 endpoints) — Execute SQL queries and manage SQL Lab sessions.</summary>
|
||||
<summary><strong>SQL Lab</strong> (7 endpoints) — Execute SQL queries and manage SQL Lab sessions.</summary>
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `GET` | [Get the bootstrap data for SqlLab page](/developer-docs/api/get-the-bootstrap-data-for-sqllab-page) | `/api/v1/sqllab/` |
|
||||
| `GET` | [Get the bootstrap data for SqlLab page](/developer-docs/api/get-the-bootstrap-data-for-sql-lab-page) | `/api/v1/sqllab/` |
|
||||
| `POST` | [Estimate the SQL query execution cost](/developer-docs/api/estimate-the-sql-query-execution-cost) | `/api/v1/sqllab/estimate/` |
|
||||
| `POST` | [Execute a SQL query](/developer-docs/api/execute-a-sql-query) | `/api/v1/sqllab/execute/` |
|
||||
| `POST` | [Export SQL query results to CSV with streaming](/developer-docs/api/export-sql-query-results-to-csv-with-streaming) | `/api/v1/sqllab/export_streaming/` |
|
||||
| `GET` | [Export the SQL query results to a CSV](/developer-docs/api/export-the-sql-query-results-to-a-csv) | `/api/v1/sqllab/export/{client_id}/` |
|
||||
| `POST` | [Format SQL code](/developer-docs/api/format-sql-code) | `/api/v1/sqllab/format_sql/` |
|
||||
| `GET` | [Get the result of a SQL query execution](/developer-docs/api/get-the-result-of-a-sql-query-execution) | `/api/v1/sqllab/results/` |
|
||||
@@ -236,20 +239,21 @@ curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Datasources</strong> (1 endpoints) — Query datasource metadata and column values.</summary>
|
||||
<summary><strong>Datasources</strong> (2 endpoints) — Query datasource metadata and column values.</summary>
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `GET` | [Get possible values for a datasource column](/developer-docs/api/get-possible-values-for-a-datasource-column) | `/api/v1/datasource/{datasource_type}/{datasource_id}/column/{column_name}/values/` |
|
||||
| `POST` | [Validate a SQL expression against a datasource](/developer-docs/api/validate-a-sql-expression-against-a-datasource) | `/api/v1/datasource/{datasource_type}/{datasource_id}/validate_expression/` |
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Advanced Data Type</strong> (2 endpoints) — Endpoints for advanced data type operations and conversions.</summary>
|
||||
<summary><strong>Advanced Data Type</strong> (2 endpoints) — Advanced data type operations and conversions.</summary>
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `GET` | [Return an AdvancedDataTypeResponse](/developer-docs/api/return-an-advanceddatatyperesponse) | `/api/v1/advanced_data_type/convert` |
|
||||
| `GET` | [Return an AdvancedDataTypeResponse](/developer-docs/api/return-an-advanced-data-type-response) | `/api/v1/advanced_data_type/convert` |
|
||||
| `GET` | [Return a list of available advanced data types](/developer-docs/api/return-a-list-of-available-advanced-data-types) | `/api/v1/advanced_data_type/types` |
|
||||
|
||||
</details>
|
||||
@@ -320,32 +324,32 @@ curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
|
||||
#### Sharing & Embedding
|
||||
|
||||
<details>
|
||||
<summary><strong>Dashboard Permanent Link</strong> (2 endpoints) — Create and retrieve permanent links to dashboard states.</summary>
|
||||
<summary><strong>Dashboard Permanent Link</strong> (2 endpoints) — Permanent links to dashboard states.</summary>
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `POST` | [Create a new dashboard's permanent link](/developer-docs/api/create-a-new-dashboard-s-permanent-link) | `/api/v1/dashboard/{pk}/permalink` |
|
||||
| `GET` | [Get dashboard's permanent link state](/developer-docs/api/get-dashboard-s-permanent-link-state) | `/api/v1/dashboard/permalink/{key}` |
|
||||
| `POST` | [Create a new dashboard's permanent link](/developer-docs/api/create-a-new-dashboards-permanent-link) | `/api/v1/dashboard/{pk}/permalink` |
|
||||
| `GET` | [Get dashboard's permanent link state](/developer-docs/api/get-dashboards-permanent-link-state) | `/api/v1/dashboard/permalink/{key}` |
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Explore Permanent Link</strong> (2 endpoints) — Create and retrieve permanent links to chart explore states.</summary>
|
||||
<summary><strong>Explore Permanent Link</strong> (2 endpoints) — Permanent links to chart explore states.</summary>
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `POST` | [Create a new permanent link (explore-permalink)](/developer-docs/api/create-a-new-permanent-link-explore-permalink) | `/api/v1/explore/permalink` |
|
||||
| `GET` | [Get chart's permanent link state](/developer-docs/api/get-chart-s-permanent-link-state) | `/api/v1/explore/permalink/{key}` |
|
||||
| `GET` | [Get chart's permanent link state](/developer-docs/api/get-charts-permanent-link-state) | `/api/v1/explore/permalink/{key}` |
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>SQL Lab Permanent Link</strong> (2 endpoints) — Create and retrieve permanent links to SQL Lab states.</summary>
|
||||
<summary><strong>SQL Lab Permanent Link</strong> (2 endpoints) — Permanent links to SQL Lab states.</summary>
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `POST` | [Create a new permanent link (sqllab-permalink)](/developer-docs/api/create-a-new-permanent-link-sqllab-permalink) | `/api/v1/sqllab/permalink` |
|
||||
| `GET` | [Get permanent link state for SQLLab editor.](/developer-docs/api/get-permanent-link-state-for-sqllab-editor) | `/api/v1/sqllab/permalink/{key}` |
|
||||
| `GET` | [Get permanent link state for SQLLab editor.](/developer-docs/api/get-permanent-link-state-for-sql-lab-editor) | `/api/v1/sqllab/permalink/{key}` |
|
||||
|
||||
</details>
|
||||
|
||||
@@ -363,10 +367,10 @@ curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `POST` | [Create a dashboard's filter state](/developer-docs/api/create-a-dashboard-s-filter-state) | `/api/v1/dashboard/{pk}/filter_state` |
|
||||
| `DELETE` | [Delete a dashboard's filter state value](/developer-docs/api/delete-a-dashboard-s-filter-state-value) | `/api/v1/dashboard/{pk}/filter_state/{key}` |
|
||||
| `GET` | [Get a dashboard's filter state value](/developer-docs/api/get-a-dashboard-s-filter-state-value) | `/api/v1/dashboard/{pk}/filter_state/{key}` |
|
||||
| `PUT` | [Update a dashboard's filter state value](/developer-docs/api/update-a-dashboard-s-filter-state-value) | `/api/v1/dashboard/{pk}/filter_state/{key}` |
|
||||
| `POST` | [Create a dashboard's filter state](/developer-docs/api/create-a-dashboards-filter-state) | `/api/v1/dashboard/{pk}/filter_state` |
|
||||
| `DELETE` | [Delete a dashboard's filter state value](/developer-docs/api/delete-a-dashboards-filter-state-value) | `/api/v1/dashboard/{pk}/filter_state/{key}` |
|
||||
| `GET` | [Get a dashboard's filter state value](/developer-docs/api/get-a-dashboards-filter-state-value) | `/api/v1/dashboard/{pk}/filter_state/{key}` |
|
||||
| `PUT` | [Update a dashboard's filter state value](/developer-docs/api/update-a-dashboards-filter-state-value) | `/api/v1/dashboard/{pk}/filter_state/{key}` |
|
||||
|
||||
</details>
|
||||
|
||||
@@ -406,16 +410,17 @@ curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
|
||||
#### Security & Access Control
|
||||
|
||||
<details>
|
||||
<summary><strong>Security Roles</strong> (10 endpoints) — Manage security roles and their permissions.</summary>
|
||||
<summary><strong>Security Roles</strong> (11 endpoints) — Manage security roles and their permissions.</summary>
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `GET` | [Get security roles](/developer-docs/api/get-security-roles) | `/api/v1/security/roles/` |
|
||||
| `POST` | [Create security roles](/developer-docs/api/create-security-roles) | `/api/v1/security/roles/` |
|
||||
| `GET` | [Get security roles info](/developer-docs/api/get-security-roles-info) | `/api/v1/security/roles/_info` |
|
||||
| `GET` | [Get security roles info](/developer-docs/api/get-security-roles-info) | `/api/v1/security/roles/_info` |
|
||||
| `DELETE` | [Delete security roles by pk](/developer-docs/api/delete-security-roles-by-pk) | `/api/v1/security/roles/{pk}` |
|
||||
| `GET` | [Get security roles by pk](/developer-docs/api/get-security-roles-by-pk) | `/api/v1/security/roles/{pk}` |
|
||||
| `PUT` | [Update security roles by pk](/developer-docs/api/update-security-roles-by-pk) | `/api/v1/security/roles/{pk}` |
|
||||
| `PUT` | [Update security roles by role_id groups](/developer-docs/api/update-security-roles-by-role-id-groups) | `/api/v1/security/roles/{role_id}/groups` |
|
||||
| `POST` | [Create security roles by role_id permissions](/developer-docs/api/create-security-roles-by-role-id-permissions) | `/api/v1/security/roles/{role_id}/permissions` |
|
||||
| `GET` | [Get security roles by role_id permissions](/developer-docs/api/get-security-roles-by-role-id-permissions) | `/api/v1/security/roles/{role_id}/permissions/` |
|
||||
| `PUT` | [Update security roles by role_id users](/developer-docs/api/update-security-roles-by-role-id-users) | `/api/v1/security/roles/{role_id}/users` |
|
||||
@@ -430,7 +435,7 @@ curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
|
||||
|--------|----------|-------------|
|
||||
| `GET` | [Get security users](/developer-docs/api/get-security-users) | `/api/v1/security/users/` |
|
||||
| `POST` | [Create security users](/developer-docs/api/create-security-users) | `/api/v1/security/users/` |
|
||||
| `GET` | [Get security users info](/developer-docs/api/get-security-users-info) | `/api/v1/security/users/_info` |
|
||||
| `GET` | [Get security users info](/developer-docs/api/get-security-users-info) | `/api/v1/security/users/_info` |
|
||||
| `DELETE` | [Delete security users by pk](/developer-docs/api/delete-security-users-by-pk) | `/api/v1/security/users/{pk}` |
|
||||
| `GET` | [Get security users by pk](/developer-docs/api/get-security-users-by-pk) | `/api/v1/security/users/{pk}` |
|
||||
| `PUT` | [Update security users by pk](/developer-docs/api/update-security-users-by-pk) | `/api/v1/security/users/{pk}` |
|
||||
@@ -443,7 +448,7 @@ curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `GET` | [Get security permissions](/developer-docs/api/get-security-permissions) | `/api/v1/security/permissions/` |
|
||||
| `GET` | [Get security permissions info](/developer-docs/api/get-security-permissions-info) | `/api/v1/security/permissions/_info` |
|
||||
| `GET` | [Get security permissions info](/developer-docs/api/get-security-permissions-info) | `/api/v1/security/permissions/_info` |
|
||||
| `GET` | [Get security permissions by pk](/developer-docs/api/get-security-permissions-by-pk) | `/api/v1/security/permissions/{pk}` |
|
||||
|
||||
</details>
|
||||
@@ -455,7 +460,7 @@ curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
|
||||
|--------|----------|-------------|
|
||||
| `GET` | [Get security resources](/developer-docs/api/get-security-resources) | `/api/v1/security/resources/` |
|
||||
| `POST` | [Create security resources](/developer-docs/api/create-security-resources) | `/api/v1/security/resources/` |
|
||||
| `GET` | [Get security resources info](/developer-docs/api/get-security-resources-info) | `/api/v1/security/resources/_info` |
|
||||
| `GET` | [Get security resources info](/developer-docs/api/get-security-resources-info) | `/api/v1/security/resources/_info` |
|
||||
| `DELETE` | [Delete security resources by pk](/developer-docs/api/delete-security-resources-by-pk) | `/api/v1/security/resources/{pk}` |
|
||||
| `GET` | [Get security resources by pk](/developer-docs/api/get-security-resources-by-pk) | `/api/v1/security/resources/{pk}` |
|
||||
| `PUT` | [Update security resources by pk](/developer-docs/api/update-security-resources-by-pk) | `/api/v1/security/resources/{pk}` |
|
||||
@@ -463,13 +468,13 @@ curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Security Permissions on Resources (View Menus)</strong> (6 endpoints) — Manage permission-resource mappings.</summary>
|
||||
<summary><strong>Security Permissions on Resources (View Menus)</strong> (6 endpoints) — Permission-resource mappings.</summary>
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `GET` | [Get security permissions resources](/developer-docs/api/get-security-permissions-resources) | `/api/v1/security/permissions-resources/` |
|
||||
| `POST` | [Create security permissions resources](/developer-docs/api/create-security-permissions-resources) | `/api/v1/security/permissions-resources/` |
|
||||
| `GET` | [Get security permissions resources info](/developer-docs/api/get-security-permissions-resources-info) | `/api/v1/security/permissions-resources/_info` |
|
||||
| `GET` | [Get security permissions resources info](/developer-docs/api/get-security-permissions-resources-info) | `/api/v1/security/permissions-resources/_info` |
|
||||
| `DELETE` | [Delete security permissions resources by pk](/developer-docs/api/delete-security-permissions-resources-by-pk) | `/api/v1/security/permissions-resources/{pk}` |
|
||||
| `GET` | [Get security permissions resources by pk](/developer-docs/api/get-security-permissions-resources-by-pk) | `/api/v1/security/permissions-resources/{pk}` |
|
||||
| `PUT` | [Update security permissions resources by pk](/developer-docs/api/update-security-permissions-resources-by-pk) | `/api/v1/security/permissions-resources/{pk}` |
|
||||
@@ -477,7 +482,7 @@ curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Row Level Security</strong> (8 endpoints) — Manage row-level security rules for data access control.</summary>
|
||||
<summary><strong>Row Level Security</strong> (8 endpoints) — Manage row-level security rules for data access.</summary>
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
@@ -495,7 +500,7 @@ curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
|
||||
#### Import/Export & Administration
|
||||
|
||||
<details>
|
||||
<summary><strong>Import/export</strong> (2 endpoints) — Import and export Superset assets (dashboards, charts, databases).</summary>
|
||||
<summary><strong>Import/export</strong> (2 endpoints) — Import and export Superset assets.</summary>
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
@@ -528,11 +533,12 @@ curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
|
||||
#### User & System
|
||||
|
||||
<details>
|
||||
<summary><strong>Current User</strong> (2 endpoints) — Get information about the currently authenticated user.</summary>
|
||||
<summary><strong>Current User</strong> (3 endpoints) — Get information about the authenticated user.</summary>
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `GET` | [Get the user object](/developer-docs/api/get-the-user-object) | `/api/v1/me/` |
|
||||
| `PUT` | [Update the current user](/developer-docs/api/update-the-current-user) | `/api/v1/me/` |
|
||||
| `GET` | [Get the user roles](/developer-docs/api/get-the-user-roles) | `/api/v1/me/roles/` |
|
||||
|
||||
</details>
|
||||
@@ -578,7 +584,23 @@ curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `GET` | [Get api by version openapi](/developer-docs/api/get-api-by-version-openapi) | `/api/{version}/_openapi` |
|
||||
| `GET` | [Get api by version openapi](/developer-docs/api/get-api-by-version-openapi) | `/api/{version}/_openapi` |
|
||||
|
||||
</details>
|
||||
|
||||
#### Other
|
||||
|
||||
<details>
|
||||
<summary><strong>Security Groups</strong> (6 endpoints) — Endpoints related to Security Groups.</summary>
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `GET` | [Get security groups](/developer-docs/api/get-security-groups) | `/api/v1/security/groups/` |
|
||||
| `POST` | [Create security groups](/developer-docs/api/create-security-groups) | `/api/v1/security/groups/` |
|
||||
| `GET` | [Get security groups info](/developer-docs/api/get-security-groups-info) | `/api/v1/security/groups/_info` |
|
||||
| `DELETE` | [Delete security groups by pk](/developer-docs/api/delete-security-groups-by-pk) | `/api/v1/security/groups/{pk}` |
|
||||
| `GET` | [Get security groups by pk](/developer-docs/api/get-security-groups-by-pk) | `/api/v1/security/groups/{pk}` |
|
||||
| `PUT` | [Update security groups by pk](/developer-docs/api/update-security-groups-by-pk) | `/api/v1/security/groups/{pk}` |
|
||||
|
||||
</details>
|
||||
|
||||
@@ -590,7 +612,7 @@ curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
|
||||
| `DELETE` | [Bulk delete themes](/developer-docs/api/bulk-delete-themes) | `/api/v1/theme/` |
|
||||
| `GET` | [Get a list of themes](/developer-docs/api/get-a-list-of-themes) | `/api/v1/theme/` |
|
||||
| `POST` | [Create a theme](/developer-docs/api/create-a-theme) | `/api/v1/theme/` |
|
||||
| `GET` | [Get metadata information about this API resource (theme-info)](/developer-docs/api/get-metadata-information-about-this-api-resource-theme-info) | `/api/v1/theme/_info` |
|
||||
| `GET` | [Get metadata information about this API resource (theme--info)](/developer-docs/api/get-metadata-information-about-this-api-resource-theme-info) | `/api/v1/theme/_info` |
|
||||
| `DELETE` | [Delete a theme](/developer-docs/api/delete-a-theme) | `/api/v1/theme/{pk}` |
|
||||
| `GET` | [Get a theme](/developer-docs/api/get-a-theme) | `/api/v1/theme/{pk}` |
|
||||
| `PUT` | [Update a theme](/developer-docs/api/update-a-theme) | `/api/v1/theme/{pk}` |
|
||||
@@ -604,6 +626,22 @@ curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>UserRegistrationsRestAPI</strong> (8 endpoints) — Endpoints related to UserRegistrationsRestAPI.</summary>
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `GET` | [Get security user registrations](/developer-docs/api/get-security-user-registrations) | `/api/v1/security/user_registrations/` |
|
||||
| `POST` | [Create security user registrations](/developer-docs/api/create-security-user-registrations) | `/api/v1/security/user_registrations/` |
|
||||
| `GET` | [Get security user registrations info](/developer-docs/api/get-security-user-registrations-info) | `/api/v1/security/user_registrations/_info` |
|
||||
| `DELETE` | [Delete security user registrations by pk](/developer-docs/api/delete-security-user-registrations-by-pk) | `/api/v1/security/user_registrations/{pk}` |
|
||||
| `GET` | [Get security user registrations by pk](/developer-docs/api/get-security-user-registrations-by-pk) | `/api/v1/security/user_registrations/{pk}` |
|
||||
| `PUT` | [Update security user registrations by pk](/developer-docs/api/update-security-user-registrations-by-pk) | `/api/v1/security/user_registrations/{pk}` |
|
||||
| `GET` | [Get distinct values from field data (security-user-registrations-distinct-column-name)](/developer-docs/api/get-distinct-values-from-field-data-security-user-registrations-distinct-column-name) | `/api/v1/security/user_registrations/distinct/{column_name}` |
|
||||
| `GET` | [Get related fields data (security-user-registrations-related-column-name)](/developer-docs/api/get-related-fields-data-security-user-registrations-related-column-name) | `/api/v1/security/user_registrations/related/{column_name}` |
|
||||
|
||||
</details>
|
||||
|
||||
---
|
||||
|
||||
### Additional Resources
|
||||
|
||||
@@ -156,7 +156,7 @@ function SelectFilters() {
|
||||
## Import
|
||||
|
||||
```tsx
|
||||
import { DropdownContainer } from '@superset/components';
|
||||
import { DropdownContainer } from '@superset-ui/core/components';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -186,7 +186,7 @@ function JustifyAlign() {
|
||||
## Import
|
||||
|
||||
```tsx
|
||||
import { Flex } from '@superset/components';
|
||||
import { Flex } from '@superset-ui/core/components';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -181,7 +181,7 @@ function AlignmentDemo() {
|
||||
## Import
|
||||
|
||||
```tsx
|
||||
import Grid from '@superset/components';
|
||||
import { Grid } from '@superset-ui/core/components';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -128,7 +128,7 @@ function RightSidebar() {
|
||||
## Import
|
||||
|
||||
```tsx
|
||||
import { Layout } from '@superset/components';
|
||||
import { Layout } from '@superset-ui/core/components';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -163,7 +163,7 @@ function FullMetadata() {
|
||||
## Import
|
||||
|
||||
```tsx
|
||||
import MetadataBar from '@superset/components';
|
||||
import { MetadataBar } from '@superset-ui/core/components';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -157,7 +157,7 @@ function SpaceSizes() {
|
||||
## Import
|
||||
|
||||
```tsx
|
||||
import { Space } from '@superset/components';
|
||||
import { Space } from '@superset-ui/core/components';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -300,7 +300,7 @@ function LoadingTable() {
|
||||
## Import
|
||||
|
||||
```tsx
|
||||
import { Table } from '@superset/components';
|
||||
import { Table } from '@superset-ui/core/components';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -23,7 +23,16 @@ sidebar_position: 0
|
||||
under the License.
|
||||
-->
|
||||
|
||||
# Superset Design System
|
||||
import { ComponentIndex } from '@site/src/components/ui-components';
|
||||
import componentData from '@site/static/data/components.json';
|
||||
|
||||
# UI Components
|
||||
|
||||
<ComponentIndex data={componentData} />
|
||||
|
||||
---
|
||||
|
||||
## Design System
|
||||
|
||||
A design system is a complete set of standards intended to manage design at scale using reusable components and patterns.
|
||||
|
||||
@@ -35,19 +44,6 @@ The Superset Design System uses [Atomic Design](https://bradfrost.com/blog/post/
|
||||
|
||||
<img src="/img/atomic-design.png" alt="Atoms = Foundations, Molecules = Components, Organisms = Patterns, Templates = Templates, Pages / Screens = Features" style={{maxWidth: '100%'}} />
|
||||
|
||||
---
|
||||
|
||||
## Component Library
|
||||
|
||||
Interactive documentation for Superset's UI component library. **53 components** documented across 2 categories.
|
||||
|
||||
### [Core Components](./ui/)
|
||||
46 components — Buttons, inputs, modals, selects, and other fundamental UI elements.
|
||||
|
||||
### [Layout Components](./design-system/)
|
||||
7 components — Grid, Layout, Table, Flex, Space, and container components for page structure.
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
All components are exported from `@superset-ui/core/components`:
|
||||
|
||||
@@ -204,7 +204,7 @@ function Demo() {
|
||||
## Import
|
||||
|
||||
```tsx
|
||||
import { AutoComplete } from '@superset/components';
|
||||
import { AutoComplete } from '@superset-ui/core/components';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -129,7 +129,7 @@ function Demo() {
|
||||
## Import
|
||||
|
||||
```tsx
|
||||
import { Avatar } from '@superset/components';
|
||||
import { Avatar } from '@superset-ui/core/components';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -149,7 +149,7 @@ function ColorGallery() {
|
||||
## Import
|
||||
|
||||
```tsx
|
||||
import { Badge } from '@superset/components';
|
||||
import { Badge } from '@superset-ui/core/components';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -82,7 +82,7 @@ function Demo() {
|
||||
## Import
|
||||
|
||||
```tsx
|
||||
import { Breadcrumb } from '@superset/components';
|
||||
import { Breadcrumb } from '@superset-ui/core/components';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -43,7 +43,7 @@ The Button component from Superset's UI library.
|
||||
<StoryWithControls
|
||||
component="Button"
|
||||
props={{
|
||||
buttonStyle: "default",
|
||||
buttonStyle: "primary",
|
||||
buttonSize: "default",
|
||||
children: "Button!"
|
||||
}}
|
||||
@@ -111,7 +111,7 @@ Edit the code below to experiment with the component:
|
||||
function Demo() {
|
||||
return (
|
||||
<Button
|
||||
buttonStyle="default"
|
||||
buttonStyle="primary"
|
||||
buttonSize="default"
|
||||
>
|
||||
Button!
|
||||
@@ -124,14 +124,14 @@ function Demo() {
|
||||
|
||||
| Prop | Type | Default | Description |
|
||||
|------|------|---------|-------------|
|
||||
| `buttonStyle` | `string` | `"default"` | The style variant of the button. |
|
||||
| `buttonStyle` | `string` | `"primary"` | The style variant of the button. |
|
||||
| `buttonSize` | `string` | `"default"` | The size of the button. |
|
||||
| `children` | `string` | `"Button!"` | The button text or content. |
|
||||
|
||||
## Import
|
||||
|
||||
```tsx
|
||||
import { Button } from '@superset/components';
|
||||
import { Button } from '@superset-ui/core/components';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -77,7 +77,7 @@ function Demo() {
|
||||
## Import
|
||||
|
||||
```tsx
|
||||
import { ButtonGroup } from '@superset/components';
|
||||
import { ButtonGroup } from '@superset-ui/core/components';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -68,7 +68,7 @@ function Demo() {
|
||||
## Import
|
||||
|
||||
```tsx
|
||||
import { CachedLabel } from '@superset/components';
|
||||
import { CachedLabel } from '@superset-ui/core/components';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -131,7 +131,7 @@ function CardStates() {
|
||||
## Import
|
||||
|
||||
```tsx
|
||||
import { Card } from '@superset/components';
|
||||
import { Card } from '@superset-ui/core/components';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -130,7 +130,7 @@ function SelectAllDemo() {
|
||||
## Import
|
||||
|
||||
```tsx
|
||||
import { Checkbox } from '@superset/components';
|
||||
import { Checkbox } from '@superset-ui/core/components';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -95,7 +95,7 @@ function Demo() {
|
||||
## Import
|
||||
|
||||
```tsx
|
||||
import { Collapse } from '@superset/components';
|
||||
import { Collapse } from '@superset-ui/core/components';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -99,7 +99,7 @@ function Demo() {
|
||||
## Import
|
||||
|
||||
```tsx
|
||||
import { DatePicker } from '@superset/components';
|
||||
import { DatePicker } from '@superset-ui/core/components';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -133,7 +133,7 @@ function Demo() {
|
||||
## Import
|
||||
|
||||
```tsx
|
||||
import { Divider } from '@superset/components';
|
||||
import { Divider } from '@superset-ui/core/components';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -161,7 +161,7 @@ function Demo() {
|
||||
## Import
|
||||
|
||||
```tsx
|
||||
import { EditableTitle } from '@superset/components';
|
||||
import { EditableTitle } from '@superset-ui/core/components';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -136,7 +136,7 @@ function Demo() {
|
||||
## Import
|
||||
|
||||
```tsx
|
||||
import { EmptyState } from '@superset/components';
|
||||
import { EmptyState } from '@superset-ui/core/components';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -85,7 +85,7 @@ function Demo() {
|
||||
## Import
|
||||
|
||||
```tsx
|
||||
import { FaveStar } from '@superset/components';
|
||||
import { FaveStar } from '@superset-ui/core/components';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -95,7 +95,7 @@ function Demo() {
|
||||
## Import
|
||||
|
||||
```tsx
|
||||
import { IconButton } from '@superset/components';
|
||||
import { IconButton } from '@superset-ui/core/components';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -241,7 +241,7 @@ function IconWithText() {
|
||||
## Import
|
||||
|
||||
```tsx
|
||||
import { Icons } from '@superset/components';
|
||||
import { Icons } from '@superset-ui/core/components';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -89,7 +89,7 @@ function Demo() {
|
||||
## Import
|
||||
|
||||
```tsx
|
||||
import { IconTooltip } from '@superset/components';
|
||||
import { IconTooltip } from '@superset-ui/core/components';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -95,7 +95,7 @@ function Demo() {
|
||||
## Import
|
||||
|
||||
```tsx
|
||||
import { InfoTooltip } from '@superset/components';
|
||||
import { InfoTooltip } from '@superset-ui/core/components';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -151,7 +151,7 @@ function Demo() {
|
||||
## Import
|
||||
|
||||
```tsx
|
||||
import { Input } from '@superset/components';
|
||||
import { Input } from '@superset-ui/core/components';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -94,7 +94,7 @@ function Demo() {
|
||||
## Import
|
||||
|
||||
```tsx
|
||||
import { Label } from '@superset/components';
|
||||
import { Label } from '@superset-ui/core/components';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -106,7 +106,7 @@ function Demo() {
|
||||
## Import
|
||||
|
||||
```tsx
|
||||
import { List } from '@superset/components';
|
||||
import { List } from '@superset-ui/core/components';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -121,7 +121,7 @@ function Demo() {
|
||||
## Import
|
||||
|
||||
```tsx
|
||||
import { ListViewCard } from '@superset/components';
|
||||
import { ListViewCard } from '@superset-ui/core/components';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -176,7 +176,7 @@ function ContextualDemo() {
|
||||
## Import
|
||||
|
||||
```tsx
|
||||
import { Loading } from '@superset/components';
|
||||
import { Loading } from '@superset-ui/core/components';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -163,7 +163,7 @@ function MenuWithIcons() {
|
||||
## Import
|
||||
|
||||
```tsx
|
||||
import { Menu } from '@superset/components';
|
||||
import { Menu } from '@superset-ui/core/components';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -196,7 +196,7 @@ function ConfirmationDialogs() {
|
||||
## Import
|
||||
|
||||
```tsx
|
||||
import { Modal } from '@superset/components';
|
||||
import { Modal } from '@superset-ui/core/components';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -181,7 +181,7 @@ function DraggableModal() {
|
||||
## Import
|
||||
|
||||
```tsx
|
||||
import { ModalTrigger } from '@superset/components';
|
||||
import { ModalTrigger } from '@superset-ui/core/components';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -188,7 +188,7 @@ function RichPopover() {
|
||||
## Import
|
||||
|
||||
```tsx
|
||||
import { Popover } from '@superset/components';
|
||||
import { Popover } from '@superset-ui/core/components';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -195,7 +195,7 @@ function CustomColors() {
|
||||
## Import
|
||||
|
||||
```tsx
|
||||
import { ProgressBar } from '@superset/components';
|
||||
import { ProgressBar } from '@superset-ui/core/components';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -126,7 +126,7 @@ function VerticalDemo() {
|
||||
## Import
|
||||
|
||||
```tsx
|
||||
import { Radio } from '@superset/components';
|
||||
import { Radio } from '@superset-ui/core/components';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -74,7 +74,7 @@ function Demo() {
|
||||
## Import
|
||||
|
||||
```tsx
|
||||
import { SafeMarkdown } from '@superset/components';
|
||||
import { SafeMarkdown } from '@superset-ui/core/components';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -297,7 +297,7 @@ function OneLineDemo() {
|
||||
## Import
|
||||
|
||||
```tsx
|
||||
import { Select } from '@superset/components';
|
||||
import { Select } from '@superset-ui/core/components';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -129,7 +129,7 @@ function Demo() {
|
||||
## Import
|
||||
|
||||
```tsx
|
||||
import { Skeleton } from '@superset/components';
|
||||
import { Skeleton } from '@superset-ui/core/components';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -242,7 +242,7 @@ function VerticalDemo() {
|
||||
## Import
|
||||
|
||||
```tsx
|
||||
import { Slider } from '@superset/components';
|
||||
import { Slider } from '@superset-ui/core/components';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -261,7 +261,7 @@ function DotAndSmall() {
|
||||
## Import
|
||||
|
||||
```tsx
|
||||
import { Steps } from '@superset/components';
|
||||
import { Steps } from '@superset-ui/core/components';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -182,7 +182,7 @@ function SettingsPanel() {
|
||||
## Import
|
||||
|
||||
```tsx
|
||||
import { Switch } from '@superset/components';
|
||||
import { Switch } from '@superset-ui/core/components';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -52,12 +52,6 @@ function Demo() {
|
||||
|
||||
|
||||
|
||||
## Import
|
||||
|
||||
```tsx
|
||||
import { TableCollection } from '@superset/components';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
:::tip[Improve this page]
|
||||
|
||||
@@ -283,7 +283,7 @@ function SortingDemo() {
|
||||
## Import
|
||||
|
||||
```tsx
|
||||
import { TableView } from '@superset/components';
|
||||
import { TableView } from '@superset-ui/core/components';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -212,7 +212,7 @@ function IconTabs() {
|
||||
## Import
|
||||
|
||||
```tsx
|
||||
import { Tabs } from '@superset/components';
|
||||
import { Tabs } from '@superset-ui/core/components';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -161,7 +161,7 @@ function StartStop() {
|
||||
## Import
|
||||
|
||||
```tsx
|
||||
import { Timer } from '@superset/components';
|
||||
import { Timer } from '@superset-ui/core/components';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -160,7 +160,7 @@ function Triggers() {
|
||||
## Import
|
||||
|
||||
```tsx
|
||||
import { Tooltip } from '@superset/components';
|
||||
import { Tooltip } from '@superset-ui/core/components';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -257,7 +257,7 @@ function LinesAndIcons() {
|
||||
## Import
|
||||
|
||||
```tsx
|
||||
import { Tree } from '@superset/components';
|
||||
import { Tree } from '@superset-ui/core/components';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -275,7 +275,7 @@ function TreeLinesDemo() {
|
||||
## Import
|
||||
|
||||
```tsx
|
||||
import { TreeSelect } from '@superset/components';
|
||||
import { TreeSelect } from '@superset-ui/core/components';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -225,7 +225,7 @@ function TextStyles() {
|
||||
## Import
|
||||
|
||||
```tsx
|
||||
import { Typography } from '@superset/components';
|
||||
import { Typography } from '@superset-ui/core/components';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -115,7 +115,7 @@ function CustomTitle() {
|
||||
## Import
|
||||
|
||||
```tsx
|
||||
import { UnsavedChangesModal } from '@superset/components';
|
||||
import { UnsavedChangesModal } from '@superset-ui/core/components';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -125,7 +125,7 @@ function DragDrop() {
|
||||
## Import
|
||||
|
||||
```tsx
|
||||
import { Upload } from '@superset/components';
|
||||
import { Upload } from '@superset-ui/core/components';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -43,7 +43,7 @@ Extensions can provide:
|
||||
|
||||
## UI Components for Extensions
|
||||
|
||||
Extension developers have access to pre-built UI components via `@apache-superset/core/components`. Browse all available components on the [UI Components](/docs/components/) page and filter by **Extension Compatible** to see components available to extensions.
|
||||
Extension developers have access to pre-built UI components via `@apache-superset/core/components`. Browse all available components on the [UI Components](/developer-docs/components/) page and filter by **Extension Compatible** to see components available to extensions.
|
||||
|
||||
## Next Steps
|
||||
|
||||
|
||||
@@ -215,7 +215,7 @@ Access to dashboards is managed via owners and permissions. Non-owner access can
|
||||
through dataset permissions or dashboard-level roles (using the `DASHBOARD_RBAC` feature flag).
|
||||
|
||||
For detailed information on configuring dashboard access, see the
|
||||
[Dashboard Access Control](/admin-docs/security/security#dashboard-access-control) section in the
|
||||
[Dashboard Access Control](/admin-docs/security/#dashboard-access-control) section in the
|
||||
Security documentation.
|
||||
|
||||
<img src={useBaseUrl("/img/tutorial/tutorial_dashboard_access.png" )} />
|
||||
|
||||
@@ -178,7 +178,7 @@ if (!versionsConfig.admin_docs.disabled) {
|
||||
},
|
||||
{
|
||||
label: 'Security',
|
||||
to: '/admin-docs/security/security',
|
||||
to: '/admin-docs/security/',
|
||||
activeBaseRegex: '^/admin-docs/security/',
|
||||
},
|
||||
],
|
||||
@@ -227,35 +227,28 @@ if (!versionsConfig.developer_docs.disabled && !versionsConfig.developer_docs.hi
|
||||
});
|
||||
}
|
||||
|
||||
// Docusaurus Faster: Rspack bundler, SWC transpilation, and other build
|
||||
// optimizations. Only enabled for local development — CI runners (GitHub
|
||||
// Actions, Netlify) have ~8GB RAM and these features push memory usage over
|
||||
// the limit. See https://docusaurus.io/blog/releases/3.6#docusaurus-faster
|
||||
const isCI = process.env.CI === 'true';
|
||||
|
||||
const config: Config = {
|
||||
...(!isCI && {
|
||||
future: {
|
||||
v4: {
|
||||
removeLegacyPostBuildHeadAttribute: true,
|
||||
// Disabled: CSS cascade layers change specificity and cause antd
|
||||
// styles (from Storybook component pages) to override theme styles
|
||||
useCssCascadeLayers: false,
|
||||
},
|
||||
experimental_faster: {
|
||||
swcJsLoader: true,
|
||||
swcJsMinimizer: true,
|
||||
swcHtmlMinimizer: true,
|
||||
lightningCssMinimizer: true,
|
||||
rspackBundler: true,
|
||||
mdxCrossCompilerCache: true,
|
||||
rspackPersistentCache: true,
|
||||
// SSG worker threads spawn parallel Node processes, each consuming
|
||||
// significant memory. Disabled to keep total usage reasonable.
|
||||
ssgWorkerThreads: false,
|
||||
},
|
||||
future: {
|
||||
v4: {
|
||||
removeLegacyPostBuildHeadAttribute: true,
|
||||
// Disabled: CSS cascade layers change specificity and cause antd
|
||||
// styles (from Storybook component pages) to override theme styles
|
||||
useCssCascadeLayers: false,
|
||||
},
|
||||
}),
|
||||
faster: {
|
||||
swcJsLoader: false,
|
||||
swcJsMinimizer: true,
|
||||
swcHtmlMinimizer: true,
|
||||
lightningCssMinimizer: true,
|
||||
rspackBundler: true,
|
||||
mdxCrossCompilerCache: true,
|
||||
rspackPersistentCache: true,
|
||||
// SSG worker threads spawn parallel Node processes, each consuming
|
||||
// significant memory. Disabled to keep total usage reasonable.
|
||||
ssgWorkerThreads: false,
|
||||
},
|
||||
},
|
||||
title: 'Superset',
|
||||
tagline:
|
||||
'Apache Superset is a modern data exploration and visualization platform',
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
"version:remove:components": "node scripts/manage-versions.mjs remove components"
|
||||
},
|
||||
"dependencies": {
|
||||
"@ant-design/icons": "^6.1.1",
|
||||
"@ant-design/icons": "^6.2.0",
|
||||
"@docusaurus/core": "^3.10.0",
|
||||
"@docusaurus/faster": "^3.10.0",
|
||||
"@docusaurus/plugin-client-redirects": "^3.10.0",
|
||||
@@ -68,9 +68,9 @@
|
||||
"@storybook/theming": "^8.6.15",
|
||||
"@superset-ui/core": "^0.20.4",
|
||||
"@swc/core": "^1.15.30",
|
||||
"antd": "^6.3.6",
|
||||
"antd": "^6.3.7",
|
||||
"baseline-browser-mapping": "^2.10.21",
|
||||
"caniuse-lite": "^1.0.30001790",
|
||||
"caniuse-lite": "^1.0.30001791",
|
||||
"docusaurus-plugin-openapi-docs": "^5.0.1",
|
||||
"docusaurus-theme-openapi-docs": "^5.0.1",
|
||||
"js-yaml": "^4.1.1",
|
||||
|
||||
@@ -141,6 +141,47 @@ def eval_node(node):
|
||||
return "<f-string>"
|
||||
return None
|
||||
|
||||
def static_return_bool(func_node):
|
||||
"""
|
||||
Statically resolve a method's return value to a bool when possible.
|
||||
|
||||
Returns True/False for functions whose body is (effectively) a single
|
||||
\`return True\` / \`return False\` — allowing a leading docstring and
|
||||
ignoring pure-comment/pass statements. Returns None for anything more
|
||||
complex (conditional returns, computed values, no return, etc.).
|
||||
|
||||
Used by \`has_implicit_cancel\` handling: \`diagnose()\` in lib.py calls
|
||||
the method and checks the return value, so an override that explicitly
|
||||
returns False must NOT be treated as enabling query cancelation.
|
||||
"""
|
||||
returns = []
|
||||
other_logic = False
|
||||
docstring_skipped = False
|
||||
for stmt in func_node.body:
|
||||
# Skip docstring (only the FIRST expression statement that is a
|
||||
# string constant — later bare string literals are not docstrings
|
||||
# and should count as non-trivial logic).
|
||||
if (not docstring_skipped
|
||||
and isinstance(stmt, ast.Expr)
|
||||
and isinstance(stmt.value, ast.Constant)
|
||||
and isinstance(stmt.value.value, str)):
|
||||
docstring_skipped = True
|
||||
continue
|
||||
if isinstance(stmt, ast.Pass):
|
||||
continue
|
||||
if isinstance(stmt, ast.Return):
|
||||
returns.append(stmt)
|
||||
continue
|
||||
# Any other statement (if/for/assign/etc.) means control flow is
|
||||
# non-trivial; bail out to be conservative.
|
||||
other_logic = True
|
||||
break
|
||||
if other_logic or len(returns) != 1:
|
||||
return None
|
||||
val = eval_node(returns[0].value)
|
||||
return val if isinstance(val, bool) else None
|
||||
|
||||
|
||||
def deep_merge(base, override):
|
||||
"""Deep merge two dictionaries. Override values take precedence."""
|
||||
if base is None:
|
||||
@@ -186,8 +227,55 @@ if not os.path.isdir(specs_dir):
|
||||
print(json.dumps({"error": f"Directory not found: {specs_dir}", "cwd": os.getcwd()}))
|
||||
sys.exit(1)
|
||||
|
||||
# First pass: collect all class info (name, bases, metadata)
|
||||
class_info = {} # class_name -> {bases: [], metadata: {}, engine_name: str, filename: str}
|
||||
# Capability flag attributes with their defaults from BaseEngineSpec
|
||||
CAP_ATTR_DEFAULTS = {
|
||||
'supports_dynamic_schema': False,
|
||||
'supports_catalog': False,
|
||||
'supports_dynamic_catalog': False,
|
||||
'disable_ssh_tunneling': False,
|
||||
'supports_file_upload': True,
|
||||
'allows_joins': True,
|
||||
'allows_subqueries': True,
|
||||
}
|
||||
|
||||
# Maps source capability attribute -> output field name used in databases.json.
|
||||
# When a cap attr is assigned an unevaluable expression (e.g.
|
||||
# allows_joins = is_feature_enabled("DRUID_JOINS")), the JS layer uses this
|
||||
# mapping to preserve the corresponding field from the previously-generated
|
||||
# JSON rather than silently inheriting an incorrect parent default.
|
||||
CAP_ATTR_TO_OUTPUT_FIELD = {
|
||||
'allows_joins': 'joins',
|
||||
'allows_subqueries': 'subqueries',
|
||||
'supports_dynamic_schema': 'supports_dynamic_schema',
|
||||
'supports_catalog': 'supports_catalog',
|
||||
'supports_dynamic_catalog': 'supports_dynamic_catalog',
|
||||
'disable_ssh_tunneling': 'ssh_tunneling',
|
||||
'supports_file_upload': 'supports_file_upload',
|
||||
}
|
||||
|
||||
# Methods that indicate a capability when overridden by a non-BaseEngineSpec class.
|
||||
# Mirrors the has_custom_method checks in superset/db_engine_specs/lib.py.
|
||||
# cancel_query / has_implicit_cancel -> query_cancelation
|
||||
# (diagnose() checks cancel_query override OR has_implicit_cancel() == True;
|
||||
# base has_implicit_cancel returns False, so overriding it is the static
|
||||
# equivalent of that method returning True. get_cancel_query_id is NOT
|
||||
# part of the diagnose() heuristic and is intentionally excluded.)
|
||||
# estimate_statement_cost / estimate_query_cost -> query_cost_estimation
|
||||
# impersonate_user / update_impersonation_config / get_url_for_impersonation -> user_impersonation
|
||||
# validate_sql -> sql_validation (not used yet; validation is engine-based)
|
||||
CAP_METHODS = {
|
||||
'cancel_query', 'has_implicit_cancel',
|
||||
'estimate_statement_cost', 'estimate_query_cost',
|
||||
'impersonate_user', 'update_impersonation_config', 'get_url_for_impersonation',
|
||||
'validate_sql',
|
||||
}
|
||||
|
||||
# Only the literal BaseEngineSpec is excluded from method-override tracking.
|
||||
# Intermediate base classes (e.g. PrestoBaseEngineSpec) do count as overrides.
|
||||
TRUE_BASE_CLASS = 'BaseEngineSpec'
|
||||
|
||||
# First pass: collect all class info (name, bases, metadata, cap_attrs, direct_methods)
|
||||
class_info = {} # class_name -> {bases: [], metadata: {}, engine_name: str, filename: str, ...}
|
||||
|
||||
for filename in sorted(os.listdir(specs_dir)):
|
||||
if not filename.endswith('.py') or filename in ('__init__.py', 'lib.py', 'lint_metadata.py'):
|
||||
@@ -218,30 +306,54 @@ for filename in sorted(os.listdir(specs_dir)):
|
||||
|
||||
# Extract class attributes
|
||||
engine_name = None
|
||||
engine_attr = None
|
||||
metadata = None
|
||||
cap_attrs = {} # capability flag attributes defined directly in this class
|
||||
# Cap attrs assigned via expressions we can't statically resolve
|
||||
# (e.g. is_feature_enabled("FLAG")). Tracked so the JS layer can
|
||||
# fall back to the previously-generated databases.json value
|
||||
# rather than inherit a parent default that would be wrong.
|
||||
unresolved_cap_attrs = set()
|
||||
direct_methods = set() # capability methods defined directly in this class
|
||||
|
||||
for item in node.body:
|
||||
if isinstance(item, ast.Assign):
|
||||
for target in item.targets:
|
||||
if isinstance(target, ast.Name):
|
||||
if target.id == 'engine_name':
|
||||
val = eval_node(item.value)
|
||||
if isinstance(val, str):
|
||||
engine_name = val
|
||||
elif target.id == 'metadata':
|
||||
metadata = eval_node(item.value)
|
||||
if not isinstance(target, ast.Name):
|
||||
continue
|
||||
if target.id == 'engine_name':
|
||||
val = eval_node(item.value)
|
||||
if isinstance(val, str):
|
||||
engine_name = val
|
||||
elif target.id == 'engine':
|
||||
val = eval_node(item.value)
|
||||
if isinstance(val, str):
|
||||
engine_attr = val
|
||||
elif target.id == 'metadata':
|
||||
metadata = eval_node(item.value)
|
||||
elif target.id in CAP_ATTR_DEFAULTS:
|
||||
val = eval_node(item.value)
|
||||
if isinstance(val, bool):
|
||||
cap_attrs[target.id] = val
|
||||
else:
|
||||
# Unevaluable expression — defer to JS fallback.
|
||||
unresolved_cap_attrs.add(target.id)
|
||||
elif isinstance(item, (ast.FunctionDef, ast.AsyncFunctionDef)):
|
||||
if item.name in CAP_METHODS:
|
||||
# has_implicit_cancel is special: diagnose() uses the
|
||||
# method's RETURN VALUE, not just its presence. If the
|
||||
# override statically returns False, treat it as if
|
||||
# the method weren't overridden so query_cancelation
|
||||
# matches diagnose(). Unresolvable / True / anything
|
||||
# else falls through as an override (conservative).
|
||||
if item.name == 'has_implicit_cancel':
|
||||
if static_return_bool(item) is False:
|
||||
continue
|
||||
direct_methods.add(item.name)
|
||||
|
||||
# Check for engine attribute with non-empty value to distinguish
|
||||
# true base classes from product classes like OceanBaseEngineSpec
|
||||
has_non_empty_engine = False
|
||||
for item in node.body:
|
||||
if isinstance(item, ast.Assign):
|
||||
for target in item.targets:
|
||||
if isinstance(target, ast.Name) and target.id == 'engine':
|
||||
# Check if engine value is non-empty string
|
||||
if isinstance(item.value, ast.Constant):
|
||||
has_non_empty_engine = bool(item.value.value)
|
||||
break
|
||||
has_non_empty_engine = engine_attr is not None and bool(engine_attr)
|
||||
|
||||
# True base classes: end with BaseEngineSpec AND don't define engine
|
||||
# or have empty engine (like PostgresBaseEngineSpec with engine = "")
|
||||
@@ -254,13 +366,18 @@ for filename in sorted(os.listdir(specs_dir)):
|
||||
'bases': base_names,
|
||||
'metadata': metadata,
|
||||
'engine_name': engine_name,
|
||||
'engine': engine_attr,
|
||||
'filename': filename,
|
||||
'is_base_or_mixin': is_true_base,
|
||||
'cap_attrs': cap_attrs,
|
||||
'unresolved_cap_attrs': unresolved_cap_attrs,
|
||||
'direct_methods': direct_methods,
|
||||
}
|
||||
except Exception as e:
|
||||
errors.append(f"{filename}: {str(e)}")
|
||||
|
||||
# Second pass: resolve inheritance and build final metadata
|
||||
# Second pass: resolve inheritance and build final metadata + capability flags
|
||||
|
||||
def get_inherited_metadata(class_name, visited=None):
|
||||
"""Recursively get metadata from parent classes."""
|
||||
if visited is None:
|
||||
@@ -286,6 +403,64 @@ def get_inherited_metadata(class_name, visited=None):
|
||||
|
||||
return inherited
|
||||
|
||||
def get_resolved_caps(class_name, visited=None):
|
||||
"""
|
||||
Resolve capability flags and method overrides with inheritance.
|
||||
|
||||
Returns (attr_values, unresolved, methods):
|
||||
- attr_values: {attr: bool} for attrs where the nearest MRO assignment
|
||||
was a literal bool. Defaults are applied at the call site.
|
||||
- unresolved: attrs where the nearest MRO assignment was an unevaluable
|
||||
expression (e.g. is_feature_enabled("FLAG")). The JS layer falls
|
||||
back to the previously-generated JSON value for these.
|
||||
- methods: capability methods defined directly in some non-base ancestor,
|
||||
matching the has_custom_method() logic in db_engine_specs/lib.py.
|
||||
|
||||
attr_values and unresolved are disjoint — an attr is in at most one.
|
||||
"""
|
||||
if visited is None:
|
||||
visited = set()
|
||||
if class_name in visited:
|
||||
return {}, set(), set()
|
||||
visited.add(class_name)
|
||||
|
||||
info = class_info.get(class_name)
|
||||
if not info:
|
||||
return {}, set(), set()
|
||||
|
||||
attr_values = {}
|
||||
unresolved = set()
|
||||
resolved_methods = set()
|
||||
|
||||
# Collect from parents, iterating right-to-left so leftmost bases win
|
||||
# (matches Python MRO: for class C(A, B), A's attributes take precedence).
|
||||
for base_name in reversed(info['bases']):
|
||||
p_vals, p_unres, p_meth = get_resolved_caps(base_name, visited.copy())
|
||||
# A parent's literal assignments overwrite whatever we inherited so far.
|
||||
for attr, val in p_vals.items():
|
||||
attr_values[attr] = val
|
||||
unresolved.discard(attr)
|
||||
# A parent's unresolved assignments likewise take precedence.
|
||||
for attr in p_unres:
|
||||
unresolved.add(attr)
|
||||
attr_values.pop(attr, None)
|
||||
resolved_methods.update(p_meth)
|
||||
|
||||
# Apply this class's own assignments (override parents).
|
||||
for attr, val in info['cap_attrs'].items():
|
||||
attr_values[attr] = val
|
||||
unresolved.discard(attr)
|
||||
for attr in info['unresolved_cap_attrs']:
|
||||
unresolved.add(attr)
|
||||
attr_values.pop(attr, None)
|
||||
|
||||
# Accumulate method overrides, but skip the literal BaseEngineSpec
|
||||
# (its implementations are stubs; only non-base overrides count).
|
||||
if class_name != TRUE_BASE_CLASS:
|
||||
resolved_methods.update(info['direct_methods'])
|
||||
|
||||
return attr_values, unresolved, resolved_methods
|
||||
|
||||
for class_name, info in class_info.items():
|
||||
# Skip base classes and mixins
|
||||
if info['is_base_or_mixin']:
|
||||
@@ -310,7 +485,14 @@ for class_name, info in class_info.items():
|
||||
|
||||
if final_metadata and isinstance(final_metadata, dict) and display_name:
|
||||
debug_info["classes_with_metadata"] += 1
|
||||
databases[display_name] = {
|
||||
|
||||
# Resolve capability flags from Python source
|
||||
attr_values, unresolved_caps, cap_methods = get_resolved_caps(class_name)
|
||||
cap_attrs = dict(CAP_ATTR_DEFAULTS)
|
||||
cap_attrs.update(attr_values)
|
||||
engine_attr = info.get('engine') or ''
|
||||
|
||||
entry = {
|
||||
'engine': display_name.lower().replace(' ', '_'),
|
||||
'engine_name': display_name,
|
||||
'module': info['filename'][:-3], # Remove .py extension
|
||||
@@ -318,19 +500,40 @@ for class_name, info in class_info.items():
|
||||
'time_grains': {},
|
||||
'score': 0,
|
||||
'max_score': 0,
|
||||
'joins': True,
|
||||
'subqueries': True,
|
||||
'supports_dynamic_schema': False,
|
||||
'supports_catalog': False,
|
||||
'supports_dynamic_catalog': False,
|
||||
'ssh_tunneling': False,
|
||||
'query_cancelation': False,
|
||||
'supports_file_upload': False,
|
||||
'user_impersonation': False,
|
||||
'query_cost_estimation': False,
|
||||
'sql_validation': False,
|
||||
# Capability flags read from engine spec class attributes/methods
|
||||
'joins': cap_attrs['allows_joins'],
|
||||
'subqueries': cap_attrs['allows_subqueries'],
|
||||
'supports_dynamic_schema': cap_attrs['supports_dynamic_schema'],
|
||||
'supports_catalog': cap_attrs['supports_catalog'],
|
||||
'supports_dynamic_catalog': cap_attrs['supports_dynamic_catalog'],
|
||||
'ssh_tunneling': not cap_attrs['disable_ssh_tunneling'],
|
||||
'supports_file_upload': cap_attrs['supports_file_upload'],
|
||||
# Method-based flags: True only when a non-base class overrides them.
|
||||
# Matches diagnose() in lib.py: cancel_query override OR
|
||||
# has_implicit_cancel() returning True (which, given the base
|
||||
# returns False, is equivalent to overriding has_implicit_cancel).
|
||||
'query_cancelation': bool({'cancel_query', 'has_implicit_cancel'} & cap_methods),
|
||||
'query_cost_estimation': bool({'estimate_statement_cost', 'estimate_query_cost'} & cap_methods),
|
||||
# SQL validation is implemented in external validator classes keyed by engine name
|
||||
'sql_validation': engine_attr in {'presto', 'postgresql'},
|
||||
'user_impersonation': bool(
|
||||
{'impersonate_user', 'update_impersonation_config', 'get_url_for_impersonation'} & cap_methods
|
||||
),
|
||||
}
|
||||
|
||||
# Tell the JS layer which output fields were populated from the
|
||||
# BaseEngineSpec default because the source assignment was an
|
||||
# unevaluable expression; those get overridden from existing JSON.
|
||||
unresolved_fields = sorted(
|
||||
CAP_ATTR_TO_OUTPUT_FIELD[attr]
|
||||
for attr in unresolved_caps
|
||||
if attr in CAP_ATTR_TO_OUTPUT_FIELD
|
||||
)
|
||||
if unresolved_fields:
|
||||
entry['_unresolved_cap_fields'] = unresolved_fields
|
||||
|
||||
databases[display_name] = entry
|
||||
|
||||
if errors and not databases:
|
||||
print(json.dumps({"error": "Parse errors", "details": errors, "debug": debug_info}), file=sys.stderr)
|
||||
|
||||
@@ -851,24 +1054,52 @@ function loadExistingData() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fall back to the previously-generated databases.json for capability flags
|
||||
* whose source assignment couldn't be statically resolved (e.g.
|
||||
* `allows_joins = is_feature_enabled("DRUID_JOINS")`). The Python extractor
|
||||
* flags these via the internal `_unresolved_cap_fields` marker; without this
|
||||
* fallback those fields would silently inherit the BaseEngineSpec default
|
||||
* and disagree with runtime behavior. The marker is stripped before output.
|
||||
*/
|
||||
function fallbackUnresolvedCaps(newDatabases, existingData) {
|
||||
for (const [name, db] of Object.entries(newDatabases)) {
|
||||
const unresolved = db._unresolved_cap_fields;
|
||||
if (!unresolved || unresolved.length === 0) {
|
||||
delete db._unresolved_cap_fields;
|
||||
continue;
|
||||
}
|
||||
const existingDb = existingData?.databases?.[name];
|
||||
if (existingDb) {
|
||||
for (const field of unresolved) {
|
||||
if (existingDb[field] !== undefined) {
|
||||
db[field] = existingDb[field];
|
||||
}
|
||||
}
|
||||
}
|
||||
delete db._unresolved_cap_fields;
|
||||
}
|
||||
return newDatabases;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge new documentation with existing diagnostics
|
||||
* Preserves score, time_grains, and feature flags from existing data
|
||||
* Preserves score, max_score, and time_grains from existing data (these require
|
||||
* Flask context to generate and cannot be derived from static source analysis).
|
||||
* Capability flags (joins, supports_catalog, etc.) are NOT preserved here — they
|
||||
* are read fresh from the Python engine spec source by extractEngineSpecMetadata(),
|
||||
* with a separate fallback for expression-based assignments (see fallbackUnresolvedCaps).
|
||||
*/
|
||||
function mergeWithExistingDiagnostics(newDatabases, existingData) {
|
||||
if (!existingData?.databases) return newDatabases;
|
||||
|
||||
const diagnosticFields = [
|
||||
'score', 'max_score', 'time_grains', 'joins', 'subqueries',
|
||||
'supports_dynamic_schema', 'supports_catalog', 'supports_dynamic_catalog',
|
||||
'ssh_tunneling', 'query_cancelation', 'supports_file_upload',
|
||||
'user_impersonation', 'query_cost_estimation', 'sql_validation'
|
||||
];
|
||||
// Only preserve fields that require Flask/runtime context to generate
|
||||
const diagnosticFields = ['score', 'max_score', 'time_grains'];
|
||||
|
||||
for (const [name, db] of Object.entries(newDatabases)) {
|
||||
const existingDb = existingData.databases[name];
|
||||
if (existingDb && existingDb.score > 0) {
|
||||
// Preserve diagnostics from existing data
|
||||
// Preserve score/time_grain diagnostics from existing data
|
||||
for (const field of diagnosticFields) {
|
||||
if (existingDb[field] !== undefined) {
|
||||
db[field] = existingDb[field];
|
||||
@@ -879,7 +1110,7 @@ function mergeWithExistingDiagnostics(newDatabases, existingData) {
|
||||
|
||||
const preserved = Object.values(newDatabases).filter(d => d.score > 0).length;
|
||||
if (preserved > 0) {
|
||||
console.log(`Preserved diagnostics for ${preserved} databases from existing data`);
|
||||
console.log(`Preserved score/time_grains for ${preserved} databases from existing data`);
|
||||
}
|
||||
|
||||
return newDatabases;
|
||||
@@ -927,6 +1158,12 @@ async function main() {
|
||||
databases = mergeWithExistingDiagnostics(databases, existingData);
|
||||
}
|
||||
|
||||
// For cap flags assigned via unevaluable expressions (e.g.
|
||||
// `is_feature_enabled(...)`), prefer the value from a previously-generated
|
||||
// JSON. Runs regardless of scores since it addresses static-analysis gaps,
|
||||
// not missing Flask diagnostics. Always strips the internal marker.
|
||||
databases = fallbackUnresolvedCaps(databases, existingData);
|
||||
|
||||
// Extract and merge custom_errors for troubleshooting documentation
|
||||
const customErrors = extractCustomErrors();
|
||||
mergeCustomErrors(databases, customErrors);
|
||||
|
||||
@@ -185,6 +185,76 @@ const SKIP_STORIES = [
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* Collect the set of value names exported from a barrel file, following
|
||||
* `export * from './X'` re-exports one level deep. Used to verify that a
|
||||
* component the docs claim is importable is actually re-exported from the
|
||||
* public package entry point.
|
||||
*/
|
||||
function collectBarrelExports(barrelPath, visited = new Set()) {
|
||||
const exports = new Set();
|
||||
if (!fs.existsSync(barrelPath) || visited.has(barrelPath)) return exports;
|
||||
visited.add(barrelPath);
|
||||
|
||||
const content = fs.readFileSync(barrelPath, 'utf8');
|
||||
|
||||
for (const m of content.matchAll(/export\s+\{([\s\S]*?)\}(?:\s+from\s+['"][^'"]+['"])?/g)) {
|
||||
for (const part of m[1].split(',')) {
|
||||
const cleaned = part.trim().replace(/^type\s+/, '');
|
||||
if (!cleaned) continue;
|
||||
const asMatch = cleaned.match(/(?:^|\s)as\s+([A-Za-z_]\w*)\s*$/);
|
||||
if (asMatch) {
|
||||
exports.add(asMatch[1]);
|
||||
} else {
|
||||
const plain = cleaned.match(/^([A-Za-z_]\w*)\s*$/);
|
||||
if (plain) exports.add(plain[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const m of content.matchAll(
|
||||
/export\s+(?:const|let|var|function|class)\s+([A-Za-z_]\w*)/g
|
||||
)) {
|
||||
exports.add(m[1]);
|
||||
}
|
||||
|
||||
for (const m of content.matchAll(/export\s+\*\s+from\s+['"]([^'"]+)['"]/g)) {
|
||||
const target = m[1];
|
||||
if (!target.startsWith('.')) continue;
|
||||
const baseDir = path.dirname(barrelPath);
|
||||
const candidates = [
|
||||
path.resolve(baseDir, `${target}.ts`),
|
||||
path.resolve(baseDir, `${target}.tsx`),
|
||||
path.resolve(baseDir, target, 'index.ts'),
|
||||
path.resolve(baseDir, target, 'index.tsx'),
|
||||
];
|
||||
const resolved = candidates.find(p => fs.existsSync(p));
|
||||
if (resolved) {
|
||||
for (const name of collectBarrelExports(resolved, visited)) {
|
||||
exports.add(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return exports;
|
||||
}
|
||||
|
||||
const SOURCE_PUBLIC_EXPORTS = new Map();
|
||||
function getPublicExports(sourceConfig) {
|
||||
if (SOURCE_PUBLIC_EXPORTS.has(sourceConfig)) {
|
||||
return SOURCE_PUBLIC_EXPORTS.get(sourceConfig);
|
||||
}
|
||||
const sourceDir = path.join(FRONTEND_DIR, sourceConfig.path);
|
||||
const candidates = [
|
||||
path.join(sourceDir, 'index.ts'),
|
||||
path.join(sourceDir, 'index.tsx'),
|
||||
];
|
||||
const barrel = candidates.find(p => fs.existsSync(p));
|
||||
const result = barrel ? collectBarrelExports(barrel) : null;
|
||||
SOURCE_PUBLIC_EXPORTS.set(sourceConfig, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively find all story files in a directory
|
||||
*/
|
||||
@@ -1048,6 +1118,28 @@ function generateMDX(component, storyContent) {
|
||||
// Use resolved import path if available, otherwise fall back to source config
|
||||
const componentImportPath = resolvedImportPath || sourceConfig.importPrefix;
|
||||
|
||||
// The displayed import in user docs should reflect the public package path,
|
||||
// not the internal storybook alias.
|
||||
const docImportPath = sourceConfig.importPrefix.startsWith('@superset/')
|
||||
? sourceConfig.docImportPrefix
|
||||
: componentImportPath;
|
||||
|
||||
// When the source uses the internal storybook alias, the public package
|
||||
// re-exports components as named exports (e.g. `export { default as Foo }`),
|
||||
// so users must use named imports even when the story uses a default import.
|
||||
const useDefaultImport =
|
||||
isDefaultExport && !sourceConfig.importPrefix.startsWith('@superset/');
|
||||
|
||||
// Only render the import snippet if the component is actually re-exported
|
||||
// from the public package barrel; otherwise the snippet would mislead users
|
||||
// copy-pasting it (e.g. TableCollection, which has a story but is not
|
||||
// re-exported from `@superset-ui/core/components`).
|
||||
const publicExports = sourceConfig.importPrefix.startsWith('@superset/')
|
||||
? getPublicExports(sourceConfig)
|
||||
: null;
|
||||
const isPubliclyExported =
|
||||
!publicExports || publicExports.has(componentName);
|
||||
|
||||
// Determine component description based on source
|
||||
const defaultDesc = sourceConfig.category === 'ui'
|
||||
? `The ${componentName} component from Superset's UI library.`
|
||||
@@ -1134,13 +1226,13 @@ ${Object.keys(args).length > 0 ? `## Props
|
||||
|------|------|---------|-------------|
|
||||
${propsTable}` : ''}
|
||||
|
||||
## Import
|
||||
${isPubliclyExported ? `## Import
|
||||
|
||||
\`\`\`tsx
|
||||
${isDefaultExport ? `import ${componentName} from '${componentImportPath}';` : `import { ${componentName} } from '${componentImportPath}';`}
|
||||
${useDefaultImport ? `import ${componentName} from '${docImportPath}';` : `import { ${componentName} } from '${docImportPath}';`}
|
||||
\`\`\`
|
||||
|
||||
---
|
||||
---` : '---'}
|
||||
|
||||
:::tip[Improve this page]
|
||||
This documentation is auto-generated from the component's Storybook story.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -717,7 +717,7 @@ export default function Home(): JSX.Element {
|
||||
</span>
|
||||
</div>
|
||||
<img src="/img/community/line.png" alt="line" />
|
||||
<StyledButton className="default-button-theme" href="/docs/intro">
|
||||
<StyledButton className="default-button-theme" href="/user-docs/intro">
|
||||
Get Started
|
||||
</StyledButton>
|
||||
</div>
|
||||
|
||||
@@ -173,7 +173,7 @@
|
||||
dependencies:
|
||||
"@algolia/client-common" "5.40.0"
|
||||
|
||||
"@ant-design/colors@^8.0.0", "@ant-design/colors@^8.0.1":
|
||||
"@ant-design/colors@^8.0.1":
|
||||
version "8.0.1"
|
||||
resolved "https://registry.npmjs.org/@ant-design/colors/-/colors-8.0.1.tgz"
|
||||
integrity sha512-foPVl0+SWIslGUtD/xBr1p9U4AKzPhNYEseXYRRo5QSzGACYZrQbe11AYJbYfAWnWSpGBx6JjBmSeugUsD9vqQ==
|
||||
@@ -207,19 +207,19 @@
|
||||
resolved "https://registry.npmjs.org/@ant-design/fast-color/-/fast-color-3.0.1.tgz"
|
||||
integrity sha512-esKJegpW4nckh0o6kV3Tkb7NPIZYbPnnFxmQDUmL08ukXZAvV85TZBr70eGuke/CIArLaP6aw8lt9KILjnWuOw==
|
||||
|
||||
"@ant-design/icons-svg@^4.4.0":
|
||||
"@ant-design/icons-svg@^4.4.2":
|
||||
version "4.4.2"
|
||||
resolved "https://registry.npmjs.org/@ant-design/icons-svg/-/icons-svg-4.4.2.tgz"
|
||||
integrity sha512-vHbT+zJEVzllwP+CM+ul7reTEfBR0vgxFe7+lREAsAA7YGsYpboiq2sQNeQeRvh09GfQgs/GyFEvZpJ9cLXpXA==
|
||||
|
||||
"@ant-design/icons@^6.1.1":
|
||||
version "6.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@ant-design/icons/-/icons-6.1.1.tgz#068963d3de44ff7034dce32c9cec3ff7d343fe6b"
|
||||
integrity sha512-AMT4N2y++TZETNHiM77fs4a0uPVCJGuL5MTonk13Pvv7UN7sID1cNEZOc1qNqx6zLKAOilTEFAdAoAFKa0U//Q==
|
||||
"@ant-design/icons@^6.1.1", "@ant-design/icons@^6.2.0":
|
||||
version "6.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@ant-design/icons/-/icons-6.2.0.tgz#d5a1a364c3e795e06ef166ddf8171cfee9837150"
|
||||
integrity sha512-TQuzMZM+F/lpn3V1Z7NBxuc2VDo3z8VZduYvMZR5dUJP28gDlOZ6ar6B7vM9W13SxUT/FbNYBw2JoighULKgQA==
|
||||
dependencies:
|
||||
"@ant-design/colors" "^8.0.0"
|
||||
"@ant-design/icons-svg" "^4.4.0"
|
||||
"@rc-component/util" "^1.3.0"
|
||||
"@ant-design/colors" "^8.0.1"
|
||||
"@ant-design/icons-svg" "^4.4.2"
|
||||
"@rc-component/util" "^1.10.1"
|
||||
clsx "^2.1.1"
|
||||
|
||||
"@ant-design/react-slick@~2.0.0":
|
||||
@@ -2986,10 +2986,10 @@
|
||||
"@rc-component/util" "^1.2.1"
|
||||
clsx "^2.1.1"
|
||||
|
||||
"@rc-component/form@~1.8.0":
|
||||
version "1.8.0"
|
||||
resolved "https://registry.yarnpkg.com/@rc-component/form/-/form-1.8.0.tgz#ed565337a69ebb6cfa20d1ad0dd58e443a71313a"
|
||||
integrity sha512-eUD5KKYnIZWmJwRA0vnyO/ovYUfHGU1svydY1OrqU5fw8Oz9Tdqvxvrlh0wl6xI/EW69dT7II49xpgOWzK3T5A==
|
||||
"@rc-component/form@~1.8.1":
|
||||
version "1.8.1"
|
||||
resolved "https://registry.yarnpkg.com/@rc-component/form/-/form-1.8.1.tgz#d811fb52df41bf72297938ebfe5cf4a4774588d4"
|
||||
integrity sha512-8O7TB55Fi2mWIGvSnwZjk8jFqVNYyKDAswglwGShcbndxqzKz4cHwNtNaLjZlAeRge9wcB0LL8IWsC/Bl18raQ==
|
||||
dependencies:
|
||||
"@rc-component/async-validator" "^5.1.0"
|
||||
"@rc-component/util" "^1.6.2"
|
||||
@@ -5482,10 +5482,10 @@ ansis@^3.2.0:
|
||||
resolved "https://registry.yarnpkg.com/ansis/-/ansis-3.17.0.tgz#fa8d9c2a93fe7d1177e0c17f9eeb562a58a832d7"
|
||||
integrity sha512-0qWUglt9JEqLFr3w1I1pbrChn1grhaiAR2ocX1PP/flRmxgtwTzPFFFnfIlD6aMOLQZgSuCRlidD70lvx8yhzg==
|
||||
|
||||
antd@^6.3.6:
|
||||
version "6.3.6"
|
||||
resolved "https://registry.yarnpkg.com/antd/-/antd-6.3.6.tgz#e892b851cf45d62201d889fe9cac36f4d2412e5f"
|
||||
integrity sha512-zdCYjusrTUn4gNxEg4PH8MWlfuXYbKfuGOkjgZ0Rg6DpWbIVmG/MwvsZ5yvG6z3Y6UI/gzYpaQ82iTt4KdbeaA==
|
||||
antd@^6.3.7:
|
||||
version "6.3.7"
|
||||
resolved "https://registry.yarnpkg.com/antd/-/antd-6.3.7.tgz#620354ec04135356cbc5ce0a666871ddc73e4117"
|
||||
integrity sha512-WTHi4bHVNKpYXLHESzU0Tts7rRNQeL84Bph9dfI3Qw7mHbTulExDcYKNHny5CTXcrBBOpraXbU9miBAwUR5vaw==
|
||||
dependencies:
|
||||
"@ant-design/colors" "^8.0.1"
|
||||
"@ant-design/cssinjs" "^2.1.2"
|
||||
@@ -5501,7 +5501,7 @@ antd@^6.3.6:
|
||||
"@rc-component/dialog" "~1.8.4"
|
||||
"@rc-component/drawer" "~1.4.2"
|
||||
"@rc-component/dropdown" "~1.0.2"
|
||||
"@rc-component/form" "~1.8.0"
|
||||
"@rc-component/form" "~1.8.1"
|
||||
"@rc-component/image" "~1.9.0"
|
||||
"@rc-component/input" "~1.1.2"
|
||||
"@rc-component/input-number" "~1.6.2"
|
||||
@@ -6035,10 +6035,10 @@ caniuse-api@^3.0.0:
|
||||
lodash.memoize "^4.1.2"
|
||||
lodash.uniq "^4.5.0"
|
||||
|
||||
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001702, caniuse-lite@^1.0.30001759, caniuse-lite@^1.0.30001790:
|
||||
version "1.0.30001790"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001790.tgz#04660c7de15f445d86dd10ac88a8936ac0698e45"
|
||||
integrity sha512-bOoxfJPyYo+ds6W0YfptaCWbFnJYjh2Y1Eow5lRv+vI2u8ganPZqNm1JwNh0t2ELQCqIWg4B3dWEusgAmsoyOw==
|
||||
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001702, caniuse-lite@^1.0.30001759, caniuse-lite@^1.0.30001791:
|
||||
version "1.0.30001791"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001791.tgz#dfb93d85c40ad380c57123e72e10f3c575786b51"
|
||||
integrity sha512-yk0l/YSrOnFZk3UROpDLQD9+kC1l4meK/wed583AXrzoarMGJcbRi2Q4RaUYbKxYAsZ8sWmaSa/DsLmdBeI1vQ==
|
||||
|
||||
ccount@^2.0.0:
|
||||
version "2.0.1"
|
||||
|
||||
@@ -52,7 +52,7 @@ attrs==25.3.0
|
||||
# referencing
|
||||
# requests-cache
|
||||
# trio
|
||||
authlib==1.6.7
|
||||
authlib==1.6.9
|
||||
# via fastmcp
|
||||
babel==2.17.0
|
||||
# via
|
||||
|
||||
394
superset-frontend/package-lock.json
generated
394
superset-frontend/package-lock.json
generated
@@ -151,7 +151,7 @@
|
||||
"use-query-params": "^2.2.2",
|
||||
"uuid": "^14.0.0",
|
||||
"xlsx": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz",
|
||||
"yargs": "^17.7.2"
|
||||
"yargs": "^18.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.28.6",
|
||||
@@ -260,7 +260,7 @@
|
||||
"jest-html-reporter": "^4.4.0",
|
||||
"jest-websocket-mock": "^2.5.0",
|
||||
"js-yaml-loader": "^1.2.2",
|
||||
"jsdom": "^29.0.2",
|
||||
"jsdom": "^29.1.0",
|
||||
"lerna": "^9.0.4",
|
||||
"lightningcss": "^1.32.0",
|
||||
"mini-css-extract-plugin": "^2.10.2",
|
||||
@@ -463,14 +463,15 @@
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@asamuzakjp/css-color": {
|
||||
"version": "5.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-5.1.6.tgz",
|
||||
"integrity": "sha512-BXWCh8dHs9GOfpo/fWGDJtDmleta2VePN9rn6WQt3GjEbxzutVF4t0x2pmH+7dbMCLtuv3MlwqRsAuxlzFXqFg==",
|
||||
"version": "5.1.11",
|
||||
"resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-5.1.11.tgz",
|
||||
"integrity": "sha512-KVw6qIiCTUQhByfTd78h2yD1/00waTmm9uy/R7Ck/ctUyAPj+AEDLkQIdJW0T8+qGgj3j5bpNKK7Q3G+LedJWg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@csstools/css-calc": "^3.1.1",
|
||||
"@csstools/css-color-parser": "^4.0.2",
|
||||
"@asamuzakjp/generational-cache": "^1.0.1",
|
||||
"@csstools/css-calc": "^3.2.0",
|
||||
"@csstools/css-color-parser": "^4.1.0",
|
||||
"@csstools/css-parser-algorithms": "^4.0.0",
|
||||
"@csstools/css-tokenizer": "^4.0.0"
|
||||
},
|
||||
@@ -479,12 +480,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@asamuzakjp/dom-selector": {
|
||||
"version": "7.0.7",
|
||||
"resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-7.0.7.tgz",
|
||||
"integrity": "sha512-d2BgqDUOS1Hfp4IzKUZqCNz+Kg3Y88AkaBvJK/ZVSQPU1f7OpPNi7nQTH6/oI47Dkdg+Z3e8Yp6ynOu4UMINAQ==",
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-7.1.1.tgz",
|
||||
"integrity": "sha512-67RZDnYRc8H/8MLDgQCDE//zoqVFwajkepHZgmXrbwybzXOEwOWGPYGmALYl9J2DOLfFPPs6kKCqmbzV895hTQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@asamuzakjp/generational-cache": "^1.0.1",
|
||||
"@asamuzakjp/nwsapi": "^2.3.9",
|
||||
"bidi-js": "^1.0.3",
|
||||
"css-tree": "^3.2.1",
|
||||
@@ -515,6 +517,16 @@
|
||||
"dev": true,
|
||||
"license": "CC0-1.0"
|
||||
},
|
||||
"node_modules/@asamuzakjp/generational-cache": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@asamuzakjp/generational-cache/-/generational-cache-1.0.1.tgz",
|
||||
"integrity": "sha512-wajfB8KqzMCN2KGNFdLkReeHncd0AslUSrvHVvvYWuU8ghncRJoA50kT3zP9MVL0+9g4/67H+cdvBskj9THPzg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^20.19.0 || ^22.12.0 || >=24.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@asamuzakjp/nwsapi": {
|
||||
"version": "2.3.9",
|
||||
"resolved": "https://registry.npmjs.org/@asamuzakjp/nwsapi/-/nwsapi-2.3.9.tgz",
|
||||
@@ -2728,9 +2740,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@csstools/css-calc": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-3.1.1.tgz",
|
||||
"integrity": "sha512-HJ26Z/vmsZQqs/o3a6bgKslXGFAungXGbinULZO3eMsOyNJHeBBZfup5FiZInOghgoM4Hwnmw+OgbJCNg1wwUQ==",
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-3.2.0.tgz",
|
||||
"integrity": "sha512-bR9e6o2BDB12jzN/gIbjHa5wLJ4UjD1CB9pM7ehlc0ddk6EBz+yYS1EV2MF55/HUxrHcB/hehAyt5vhsA3hx7w==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
@@ -2752,9 +2764,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@csstools/css-color-parser": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-4.0.2.tgz",
|
||||
"integrity": "sha512-0GEfbBLmTFf0dJlpsNU7zwxRIH0/BGEMuXLTCvFYxuL1tNhqzTbtnFICyJLTNK4a+RechKP75e7w42ClXSnJQw==",
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-4.1.0.tgz",
|
||||
"integrity": "sha512-U0KhLYmy2GVj6q4T3WaAe6NPuFYCPQoE3b0dRGxejWDgcPp8TP7S5rVdM5ZrFaqu4N67X8YaPBw14dQSYx3IyQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
@@ -2769,7 +2781,7 @@
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@csstools/color-helpers": "^6.0.2",
|
||||
"@csstools/css-calc": "^3.1.1"
|
||||
"@csstools/css-calc": "^3.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.19.0"
|
||||
@@ -12769,6 +12781,25 @@
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/@storybook/test-runner/node_modules/yargs": {
|
||||
"version": "17.7.2",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
|
||||
"integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cliui": "^8.0.1",
|
||||
"escalade": "^3.1.1",
|
||||
"get-caller-file": "^2.0.5",
|
||||
"require-directory": "^2.1.1",
|
||||
"string-width": "^4.2.3",
|
||||
"y18n": "^5.0.5",
|
||||
"yargs-parser": "^21.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@storybook/test-runner/node_modules/yargs-parser": {
|
||||
"version": "18.1.3",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
|
||||
@@ -12793,6 +12824,59 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@storybook/test-runner/node_modules/yargs/node_modules/cliui": {
|
||||
"version": "8.0.1",
|
||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
|
||||
"integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"string-width": "^4.2.0",
|
||||
"strip-ansi": "^6.0.1",
|
||||
"wrap-ansi": "^7.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@storybook/test-runner/node_modules/yargs/node_modules/wrap-ansi": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
|
||||
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ansi-styles": "^4.0.0",
|
||||
"string-width": "^4.1.0",
|
||||
"strip-ansi": "^6.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/@storybook/test-runner/node_modules/yargs/node_modules/y18n": {
|
||||
"version": "5.0.8",
|
||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
||||
"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@storybook/test-runner/node_modules/yargs/node_modules/yargs-parser": {
|
||||
"version": "21.1.1",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
|
||||
"integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@storybook/test/node_modules/@storybook/instrumenter": {
|
||||
"version": "8.6.18",
|
||||
"resolved": "https://registry.npmjs.org/@storybook/instrumenter/-/instrumenter-8.6.18.tgz",
|
||||
@@ -20396,6 +20480,25 @@
|
||||
"url": "https://github.com/chalk/supports-color?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/concurrently/node_modules/yargs": {
|
||||
"version": "17.7.2",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
|
||||
"integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cliui": "^8.0.1",
|
||||
"escalade": "^3.1.1",
|
||||
"get-caller-file": "^2.0.5",
|
||||
"require-directory": "^2.1.1",
|
||||
"string-width": "^4.2.3",
|
||||
"y18n": "^5.0.5",
|
||||
"yargs-parser": "^21.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/config-chain": {
|
||||
"version": "1.1.13",
|
||||
"resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz",
|
||||
@@ -27011,7 +27114,6 @@
|
||||
"resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.3.0.tgz",
|
||||
"integrity": "sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
@@ -30709,6 +30811,25 @@
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/jest-cli/node_modules/yargs": {
|
||||
"version": "17.7.2",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
|
||||
"integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cliui": "^8.0.1",
|
||||
"escalade": "^3.1.1",
|
||||
"get-caller-file": "^2.0.5",
|
||||
"require-directory": "^2.1.1",
|
||||
"string-width": "^4.2.3",
|
||||
"y18n": "^5.0.5",
|
||||
"yargs-parser": "^21.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/jest-config": {
|
||||
"version": "30.3.0",
|
||||
"resolved": "https://registry.npmjs.org/jest-config/-/jest-config-30.3.0.tgz",
|
||||
@@ -33697,28 +33818,28 @@
|
||||
}
|
||||
},
|
||||
"node_modules/jsdom": {
|
||||
"version": "29.0.2",
|
||||
"resolved": "https://registry.npmjs.org/jsdom/-/jsdom-29.0.2.tgz",
|
||||
"integrity": "sha512-9VnGEBosc/ZpwyOsJBCQ/3I5p7Q5ngOY14a9bf5btenAORmZfDse1ZEheMiWcJ3h81+Fv7HmJFdS0szo/waF2w==",
|
||||
"version": "29.1.0",
|
||||
"resolved": "https://registry.npmjs.org/jsdom/-/jsdom-29.1.0.tgz",
|
||||
"integrity": "sha512-YNUc7fB9QuvSSQWfrH0xF+TyABkxUwx8sswgIDaCrw4Hol8BghdZDkITtZheRJeMtzWlnTfsM3bBBusRvpO1wg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@asamuzakjp/css-color": "^5.1.5",
|
||||
"@asamuzakjp/dom-selector": "^7.0.6",
|
||||
"@asamuzakjp/css-color": "^5.1.11",
|
||||
"@asamuzakjp/dom-selector": "^7.1.1",
|
||||
"@bramus/specificity": "^2.4.2",
|
||||
"@csstools/css-syntax-patches-for-csstree": "^1.1.1",
|
||||
"@csstools/css-syntax-patches-for-csstree": "^1.1.3",
|
||||
"@exodus/bytes": "^1.15.0",
|
||||
"css-tree": "^3.2.1",
|
||||
"data-urls": "^7.0.0",
|
||||
"decimal.js": "^10.6.0",
|
||||
"html-encoding-sniffer": "^6.0.0",
|
||||
"is-potential-custom-element-name": "^1.0.1",
|
||||
"lru-cache": "^11.2.7",
|
||||
"parse5": "^8.0.0",
|
||||
"lru-cache": "^11.3.5",
|
||||
"parse5": "^8.0.1",
|
||||
"saxes": "^6.0.0",
|
||||
"symbol-tree": "^3.2.4",
|
||||
"tough-cookie": "^6.0.1",
|
||||
"undici": "^7.24.5",
|
||||
"undici": "^7.25.0",
|
||||
"w3c-xmlserializer": "^5.0.0",
|
||||
"webidl-conversions": "^8.0.1",
|
||||
"whatwg-mimetype": "^5.0.0",
|
||||
@@ -33738,9 +33859,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/jsdom/node_modules/@csstools/css-syntax-patches-for-csstree": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.1.2.tgz",
|
||||
"integrity": "sha512-5GkLzz4prTIpoyeUiIu3iV6CSG3Plo7xRVOFPKI7FVEJ3mZ0A8SwK0XU3Gl7xAkiQ+mDyam+NNp875/C5y+jSA==",
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.1.3.tgz",
|
||||
"integrity": "sha512-SH60bMfrRCJF3morcdk57WklujF4Jr/EsQUzqkarfHXEFcAR1gg7fS/chAE922Sehgzc1/+Tz5H3Ypa1HiEKrg==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
@@ -33810,22 +33931,22 @@
|
||||
}
|
||||
},
|
||||
"node_modules/jsdom/node_modules/entities": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz",
|
||||
"integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==",
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-8.0.0.tgz",
|
||||
"integrity": "sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==",
|
||||
"dev": true,
|
||||
"license": "BSD-2-Clause",
|
||||
"engines": {
|
||||
"node": ">=0.12"
|
||||
"node": ">=20.19.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/fb55/entities?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/jsdom/node_modules/lru-cache": {
|
||||
"version": "11.2.7",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.7.tgz",
|
||||
"integrity": "sha512-aY/R+aEsRelme17KGQa/1ZSIpLpNYYrhcrepKTZgE+W3WM16YMCaPwOHLHsmopZHELU0Ojin1lPVxKR0MihncA==",
|
||||
"version": "11.3.5",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.5.tgz",
|
||||
"integrity": "sha512-NxVFwLAnrd9i7KUBxC4DrUhmgjzOs+1Qm50D3oF1/oL+r1NpZ4gA7xvG0/zJ8evR7zIKn4vLf7qTNduWFtCrRw==",
|
||||
"dev": true,
|
||||
"license": "BlueOak-1.0.0",
|
||||
"engines": {
|
||||
@@ -33840,13 +33961,13 @@
|
||||
"license": "CC0-1.0"
|
||||
},
|
||||
"node_modules/jsdom/node_modules/parse5": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.0.tgz",
|
||||
"integrity": "sha512-9m4m5GSgXjL4AjumKzq1Fgfp3Z8rsvjRNbnkVwfu2ImRqE5D0LnY2QfDen18FSY9C573YU5XxSapdHZTZ2WolA==",
|
||||
"version": "8.0.1",
|
||||
"resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.1.tgz",
|
||||
"integrity": "sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"entities": "^6.0.0"
|
||||
"entities": "^8.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/inikulin/parse5?sponsor=1"
|
||||
@@ -34960,6 +35081,25 @@
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/lerna/node_modules/yargs": {
|
||||
"version": "17.7.2",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
|
||||
"integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cliui": "^8.0.1",
|
||||
"escalade": "^3.1.1",
|
||||
"get-caller-file": "^2.0.5",
|
||||
"require-directory": "^2.1.1",
|
||||
"string-width": "^4.2.3",
|
||||
"y18n": "^5.0.5",
|
||||
"yargs-parser": "^21.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/leven": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
|
||||
@@ -37901,6 +38041,25 @@
|
||||
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/nx/node_modules/yargs": {
|
||||
"version": "17.7.2",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
|
||||
"integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cliui": "^8.0.1",
|
||||
"escalade": "^3.1.1",
|
||||
"get-caller-file": "^2.0.5",
|
||||
"require-directory": "^2.1.1",
|
||||
"string-width": "^4.2.3",
|
||||
"y18n": "^5.0.5",
|
||||
"yargs-parser": "^21.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/nyc": {
|
||||
"version": "17.1.0",
|
||||
"resolved": "https://registry.npmjs.org/nyc/-/nyc-17.1.0.tgz",
|
||||
@@ -47947,6 +48106,24 @@
|
||||
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/typescript-json-schema/node_modules/yargs": {
|
||||
"version": "17.7.2",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
|
||||
"integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cliui": "^8.0.1",
|
||||
"escalade": "^3.1.1",
|
||||
"get-caller-file": "^2.0.5",
|
||||
"require-directory": "^2.1.1",
|
||||
"string-width": "^4.2.3",
|
||||
"y18n": "^5.0.5",
|
||||
"yargs-parser": "^21.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/typewise": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/typewise/-/typewise-1.0.3.tgz",
|
||||
@@ -48026,9 +48203,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/undici": {
|
||||
"version": "7.24.6",
|
||||
"resolved": "https://registry.npmjs.org/undici/-/undici-7.24.6.tgz",
|
||||
"integrity": "sha512-Xi4agocCbRzt0yYMZGMA6ApD7gvtUFaxm4ZmeacWI4cZxaF6C+8I8QfofC20NAePiB/IcvZmzkJ7XPa471AEtA==",
|
||||
"version": "7.25.0",
|
||||
"resolved": "https://registry.npmjs.org/undici/-/undici-7.25.0.tgz",
|
||||
"integrity": "sha512-xXnp4kTyor2Zq+J1FfPI6Eq3ew5h6Vl0F/8d9XU5zZQf1tX9s2Su1/3PiMmUANFULpmksxkClamIZcaUqryHsQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -50364,21 +50541,20 @@
|
||||
}
|
||||
},
|
||||
"node_modules/yargs": {
|
||||
"version": "17.7.2",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
|
||||
"integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
|
||||
"version": "18.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-18.0.0.tgz",
|
||||
"integrity": "sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cliui": "^8.0.1",
|
||||
"cliui": "^9.0.1",
|
||||
"escalade": "^3.1.1",
|
||||
"get-caller-file": "^2.0.5",
|
||||
"require-directory": "^2.1.1",
|
||||
"string-width": "^4.2.3",
|
||||
"string-width": "^7.2.0",
|
||||
"y18n": "^5.0.5",
|
||||
"yargs-parser": "^21.1.1"
|
||||
"yargs-parser": "^22.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
"node": "^20.19.0 || ^22.12.0 || >=23"
|
||||
}
|
||||
},
|
||||
"node_modules/yargs-parser": {
|
||||
@@ -50390,6 +50566,108 @@
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/yargs/node_modules/ansi-regex": {
|
||||
"version": "6.2.2",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz",
|
||||
"integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/ansi-regex?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/yargs/node_modules/ansi-styles": {
|
||||
"version": "6.2.3",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz",
|
||||
"integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/yargs/node_modules/cliui": {
|
||||
"version": "9.0.1",
|
||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz",
|
||||
"integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"string-width": "^7.2.0",
|
||||
"strip-ansi": "^7.1.0",
|
||||
"wrap-ansi": "^9.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
}
|
||||
},
|
||||
"node_modules/yargs/node_modules/emoji-regex": {
|
||||
"version": "10.6.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz",
|
||||
"integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/yargs/node_modules/string-width": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz",
|
||||
"integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"emoji-regex": "^10.3.0",
|
||||
"get-east-asian-width": "^1.0.0",
|
||||
"strip-ansi": "^7.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/yargs/node_modules/strip-ansi": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz",
|
||||
"integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ansi-regex": "^6.2.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/strip-ansi?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/yargs/node_modules/wrap-ansi": {
|
||||
"version": "9.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz",
|
||||
"integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ansi-styles": "^6.2.1",
|
||||
"string-width": "^7.0.0",
|
||||
"strip-ansi": "^7.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/yargs/node_modules/yargs-parser": {
|
||||
"version": "22.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz",
|
||||
"integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==",
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": "^20.19.0 || ^22.12.0 || >=23"
|
||||
}
|
||||
},
|
||||
"node_modules/yauzl": {
|
||||
"version": "2.10.0",
|
||||
"resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
|
||||
@@ -51364,7 +51642,7 @@
|
||||
"react-js-cron": "^5.2.0",
|
||||
"react-markdown": "^8.0.7",
|
||||
"react-resize-detector": "^7.1.2",
|
||||
"react-syntax-highlighter": "^16.1.1",
|
||||
"react-syntax-highlighter": "^16.1.0",
|
||||
"react-ultimate-pagination": "^1.3.2",
|
||||
"regenerator-runtime": "^0.14.1",
|
||||
"rehype-raw": "^7.0.0",
|
||||
@@ -53046,7 +53324,7 @@
|
||||
"classnames": "^2.5.1",
|
||||
"d3-array": "^3.2.4",
|
||||
"lodash": "^4.18.1",
|
||||
"memoize-one": "^5.2.1",
|
||||
"memoize-one": "^6.0.0",
|
||||
"react-table": "^7.8.0",
|
||||
"regenerator-runtime": "^0.14.1",
|
||||
"xss": "^1.0.15"
|
||||
@@ -53079,13 +53357,19 @@
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"plugins/plugin-chart-table/node_modules/memoize-one": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz",
|
||||
"integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"plugins/plugin-chart-word-cloud": {
|
||||
"name": "@superset-ui/plugin-chart-word-cloud",
|
||||
"version": "0.20.4",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@types/d3-scale": "^4.0.9",
|
||||
"d3-cloud": "^1.2.8",
|
||||
"d3-cloud": "^1.2.9",
|
||||
"d3-scale": "^4.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -232,7 +232,7 @@
|
||||
"use-query-params": "^2.2.2",
|
||||
"uuid": "^14.0.0",
|
||||
"xlsx": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz",
|
||||
"yargs": "^17.7.2"
|
||||
"yargs": "^18.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.28.6",
|
||||
@@ -341,7 +341,7 @@
|
||||
"jest-html-reporter": "^4.4.0",
|
||||
"jest-websocket-mock": "^2.5.0",
|
||||
"js-yaml-loader": "^1.2.2",
|
||||
"jsdom": "^29.0.2",
|
||||
"jsdom": "^29.1.0",
|
||||
"lerna": "^9.0.4",
|
||||
"lightningcss": "^1.32.0",
|
||||
"mini-css-extract-plugin": "^2.10.2",
|
||||
|
||||
@@ -588,6 +588,7 @@ export type ControlFormItemSpec<T extends ControlType = ControlType> = {
|
||||
creatable?: boolean;
|
||||
minWidth?: number | string;
|
||||
validators?: ControlFormValueValidator<string>[];
|
||||
tokenSeparators?: string[];
|
||||
}
|
||||
: T extends 'RadioButtonControl'
|
||||
? {
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
"react-js-cron": "^5.2.0",
|
||||
"react-markdown": "^8.0.7",
|
||||
"react-resize-detector": "^7.1.2",
|
||||
"react-syntax-highlighter": "^16.1.1",
|
||||
"react-syntax-highlighter": "^16.1.0",
|
||||
"react-ultimate-pagination": "^1.3.2",
|
||||
"regenerator-runtime": "^0.14.1",
|
||||
"rehype-raw": "^7.0.0",
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
"classnames": "^2.5.1",
|
||||
"d3-array": "^3.2.4",
|
||||
"lodash": "^4.18.1",
|
||||
"memoize-one": "^5.2.1",
|
||||
"memoize-one": "^6.0.0",
|
||||
"react-table": "^7.8.0",
|
||||
"regenerator-runtime": "^0.14.1",
|
||||
"xss": "^1.0.15"
|
||||
|
||||
@@ -27,10 +27,11 @@ process.env.PATH = `./node_modules/.bin:${process.env.PATH}`;
|
||||
|
||||
const { spawnSync } = require('child_process');
|
||||
const fastGlob = require('fast-glob');
|
||||
const { argv } = require('yargs');
|
||||
const yargs = require('yargs');
|
||||
const { hideBin } = require('yargs/helpers');
|
||||
|
||||
const { _: globs } = argv;
|
||||
const glob = globs.length > 1 ? `{${globs.join(',')}}` : globs[0] || '*';
|
||||
const { globs } = yargs(hideBin(process.argv)).parse();
|
||||
const glob = globs?.length > 1 ? `{${globs.join(',')}}` : globs?.[0] || '*';
|
||||
|
||||
const BABEL_CONFIG = '--config-file=../../babel.config.js';
|
||||
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* 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 { SHARED_COLUMN_CONFIG_PROPS } from './constants';
|
||||
|
||||
const tokenSeparators =
|
||||
SHARED_COLUMN_CONFIG_PROPS.d3NumberFormat.tokenSeparators;
|
||||
|
||||
test('should allow commas in D3 format inputs', () => {
|
||||
expect(tokenSeparators).toBeDefined();
|
||||
expect(tokenSeparators).not.toContain(',');
|
||||
});
|
||||
|
||||
test('should have correct default token separators', () => {
|
||||
const expectedSeparators = ['\r\n', '\n', '\t', ';'];
|
||||
expect(tokenSeparators).toEqual(expectedSeparators);
|
||||
});
|
||||
@@ -58,6 +58,8 @@ const d3NumberFormat: ControlFormItemSpec<'Select'> = {
|
||||
creatable: true,
|
||||
minWidth: '14em',
|
||||
debounceDelay: 500,
|
||||
// default value tokenSeparators in superset-frontend/packages/superset-ui-core/src/components/Select/constants.ts
|
||||
tokenSeparators: ['\r\n', '\n', '\t', ';'],
|
||||
};
|
||||
|
||||
const d3TimeFormat: ControlFormItemSpec<'Select'> = {
|
||||
|
||||
@@ -34,6 +34,8 @@ import Chart from 'src/types/Chart';
|
||||
import { FacePile } from 'src/components';
|
||||
import { handleChartDelete, CardStyles } from 'src/views/CRUD/utils';
|
||||
import { assetUrl } from 'src/utils/assetUrl';
|
||||
import type { ListViewFetchDataConfig as FetchDataConfig } from 'src/components';
|
||||
import { TableTab } from 'src/views/CRUD/types';
|
||||
|
||||
interface ChartCardProps {
|
||||
chart: Chart;
|
||||
@@ -42,7 +44,7 @@ interface ChartCardProps {
|
||||
bulkSelectEnabled: boolean;
|
||||
addDangerToast: (msg: string) => void;
|
||||
addSuccessToast: (msg: string) => void;
|
||||
refreshData: () => void;
|
||||
refreshData: (config?: FetchDataConfig | null) => void;
|
||||
loading?: boolean;
|
||||
saveFavoriteStatus: (id: number, isStarred: boolean) => void;
|
||||
favoriteStatus: boolean;
|
||||
@@ -50,6 +52,7 @@ interface ChartCardProps {
|
||||
userId?: string | number;
|
||||
showThumbnails?: boolean;
|
||||
handleBulkChartExport: (chartsToExport: Chart[]) => void;
|
||||
getData?: (tab: TableTab) => void;
|
||||
}
|
||||
|
||||
export default function ChartCard({
|
||||
@@ -67,6 +70,7 @@ export default function ChartCard({
|
||||
chartFilter,
|
||||
userId,
|
||||
handleBulkChartExport,
|
||||
getData,
|
||||
}: ChartCardProps) {
|
||||
const history = useHistory();
|
||||
const canEdit = hasPerm('can_write');
|
||||
@@ -136,6 +140,7 @@ export default function ChartCard({
|
||||
refreshData,
|
||||
chartFilter,
|
||||
userId,
|
||||
getData,
|
||||
)
|
||||
}
|
||||
>
|
||||
|
||||
@@ -26,6 +26,7 @@ import { VizType } from '@superset-ui/core';
|
||||
import fetchMock from 'fetch-mock';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import handleResourceExport from 'src/utils/export';
|
||||
import { LocalStorageKeys } from 'src/utils/localStorageHelpers';
|
||||
import ChartTable from './ChartTable';
|
||||
|
||||
// Mock the export module
|
||||
@@ -53,12 +54,16 @@ const mockCharts = Array.from({ length: 3 }).map((_, i) => ({
|
||||
thumbnail_url: '',
|
||||
}));
|
||||
|
||||
fetchMock.get(chartsEndpoint, {
|
||||
result: mockCharts,
|
||||
});
|
||||
fetchMock.get(
|
||||
chartsEndpoint,
|
||||
{
|
||||
result: mockCharts,
|
||||
},
|
||||
{ name: chartsEndpoint },
|
||||
);
|
||||
|
||||
fetchMock.get(chartsInfoEndpoint, {
|
||||
permissions: ['can_add', 'can_edit', 'can_delete', 'can_export'],
|
||||
permissions: ['can_add', 'can_write', 'can_delete', 'can_export'],
|
||||
});
|
||||
|
||||
fetchMock.get(chartFavoriteStatusEndpoint, {
|
||||
@@ -99,6 +104,10 @@ const renderChartTable = (props: any) =>
|
||||
render(<ChartTable {...props} />, renderOptions);
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
window.localStorage.removeItem(LocalStorageKeys.HomepageChartFilter);
|
||||
});
|
||||
|
||||
test('renders with EmptyState if no data present', async () => {
|
||||
await renderChartTable(mockedProps);
|
||||
expect(screen.getAllByRole('tab')).toHaveLength(3);
|
||||
@@ -178,3 +187,58 @@ test('handles chart export with correct ID and shows spinner', async () => {
|
||||
{ timeout: 3000 },
|
||||
);
|
||||
});
|
||||
|
||||
test('refreshes other tab data after deleting a chart', async () => {
|
||||
fetchMock.removeRoute(chartsEndpoint);
|
||||
fetchMock.get(
|
||||
chartsEndpoint,
|
||||
{
|
||||
result: mockCharts.slice(1),
|
||||
count: mockCharts.length - 1,
|
||||
},
|
||||
{ name: chartsEndpoint },
|
||||
);
|
||||
fetchMock.delete('glob:*/api/v1/chart/0', {
|
||||
message: 'Chart deleted',
|
||||
});
|
||||
|
||||
await renderChartTable({
|
||||
...otherTabProps,
|
||||
otherTabTitle: 'All',
|
||||
});
|
||||
|
||||
expect(screen.getByText('cool chart 0')).toBeInTheDocument();
|
||||
|
||||
const refreshCallsBeforeDelete =
|
||||
fetchMock.callHistory.calls(chartsEndpoint).length;
|
||||
|
||||
const moreButtons = screen.getAllByRole('img', { name: /more/i });
|
||||
await userEvent.click(moreButtons[0]);
|
||||
|
||||
await userEvent.click(await screen.findByText('Delete'));
|
||||
|
||||
const deleteInput = screen.getByTestId('delete-modal-input');
|
||||
await userEvent.type(deleteInput, 'DELETE');
|
||||
await userEvent.click(screen.getByTestId('modal-confirm-button'));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(
|
||||
fetchMock.callHistory.calls(/api\/v1\/chart\/0/, {
|
||||
method: 'DELETE',
|
||||
}),
|
||||
).toHaveLength(1);
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(fetchMock.callHistory.calls(chartsEndpoint).length).toBe(
|
||||
refreshCallsBeforeDelete + 1,
|
||||
);
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByText('cool chart 0')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
expect(screen.getByText('cool chart 1')).toBeInTheDocument();
|
||||
expect(screen.getByText('cool chart 2')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
@@ -112,18 +112,19 @@ function ChartTable({
|
||||
const [preparingExport, setPreparingExport] = useState<boolean>(false);
|
||||
const [loaded, setLoaded] = useState<boolean>(false);
|
||||
|
||||
const getData = (tab: TableTab) =>
|
||||
fetchData({
|
||||
pageIndex: 0,
|
||||
pageSize: PAGE_SIZE,
|
||||
sortBy: [
|
||||
{
|
||||
id: 'changed_on_delta_humanized',
|
||||
desc: true,
|
||||
},
|
||||
],
|
||||
filters: getFilterValues(tab, WelcomeTable.Charts, user, otherTabFilters),
|
||||
});
|
||||
const getChartFetchDataConfig = (tab: TableTab) => ({
|
||||
pageIndex: 0,
|
||||
pageSize: PAGE_SIZE,
|
||||
sortBy: [
|
||||
{
|
||||
id: 'changed_on_delta_humanized',
|
||||
desc: true,
|
||||
},
|
||||
],
|
||||
filters: getFilterValues(tab, WelcomeTable.Charts, user, otherTabFilters),
|
||||
});
|
||||
|
||||
const getData = (tab: TableTab) => fetchData(getChartFetchDataConfig(tab));
|
||||
|
||||
useEffect(() => {
|
||||
if (loaded || activeTab === TableTab.Favorite) {
|
||||
@@ -234,6 +235,7 @@ function ChartTable({
|
||||
refreshData={refreshData}
|
||||
addDangerToast={addDangerToast}
|
||||
addSuccessToast={addSuccessToast}
|
||||
getData={getData}
|
||||
favoriteStatus={favoriteStatus[e.id]}
|
||||
saveFavoriteStatus={saveFavoriteStatus}
|
||||
handleBulkChartExport={handleBulkChartExport}
|
||||
|
||||
@@ -327,6 +327,7 @@ export function handleChartDelete(
|
||||
refreshData: (arg0?: FetchDataConfig | null) => void,
|
||||
chartFilter?: string,
|
||||
userId?: string | number,
|
||||
getData?: (tab: TableTab) => void,
|
||||
) {
|
||||
const filters = {
|
||||
pageIndex: 0,
|
||||
@@ -350,6 +351,7 @@ export function handleChartDelete(
|
||||
}).then(
|
||||
() => {
|
||||
if (chartFilter === 'Mine') refreshData(filters);
|
||||
else if (chartFilter && getData) getData(chartFilter as TableTab);
|
||||
else refreshData();
|
||||
addSuccessToast(t('Deleted: %s', sliceName));
|
||||
},
|
||||
|
||||
@@ -36,11 +36,14 @@ const {
|
||||
} = require('webpack-manifest-plugin');
|
||||
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
|
||||
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
|
||||
const parsedArgs = require('yargs').argv;
|
||||
const yargs = require('yargs');
|
||||
const { hideBin } = require('yargs/helpers');
|
||||
const Visualizer = require('webpack-visualizer-plugin2');
|
||||
const getProxyConfig = require('./webpack.proxy-config');
|
||||
const packageConfig = require('./package.json');
|
||||
|
||||
const parsedArgs = yargs(hideBin(process.argv)).parse();
|
||||
|
||||
// input dir
|
||||
const APP_DIR = path.resolve(__dirname, './');
|
||||
// output dir
|
||||
|
||||
@@ -20,8 +20,8 @@ const zlib = require('zlib');
|
||||
const { ZSTDDecompress } = require('simple-zstd');
|
||||
|
||||
const yargs = require('yargs');
|
||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
const parsedArgs = yargs.argv;
|
||||
const { hideBin } = require('yargs/helpers');
|
||||
const parsedArgs = yargs(hideBin(process.argv)).parse();
|
||||
|
||||
const parsedEnvArg = () => {
|
||||
let envArgs = {};
|
||||
|
||||
@@ -753,6 +753,15 @@ def generate_yaml_docs(output_dir: str | None = None) -> dict[str, dict[str, Any
|
||||
continue
|
||||
|
||||
name = get_name(spec)
|
||||
|
||||
# Skip "base" specs (e.g. PostgresBaseEngineSpec) that share an engine_name
|
||||
# with a real product spec but have no concrete engine value. When multiple
|
||||
# specs share the same engine_name the one with a non-empty engine string is
|
||||
# the authoritative product spec; letting a base class overwrite it would
|
||||
# produce incorrect capability flags.
|
||||
if not spec.engine and name in all_docs:
|
||||
continue
|
||||
|
||||
doc_data = diagnose(spec)
|
||||
|
||||
# Get documentation metadata (prefers spec.metadata over DATABASE_DOCS)
|
||||
@@ -766,6 +775,7 @@ def generate_yaml_docs(output_dir: str | None = None) -> dict[str, dict[str, Any
|
||||
doc_data["supports_file_upload"] = spec.supports_file_upload
|
||||
doc_data["supports_dynamic_schema"] = spec.supports_dynamic_schema
|
||||
doc_data["supports_catalog"] = spec.supports_catalog
|
||||
doc_data["supports_dynamic_catalog"] = spec.supports_dynamic_catalog
|
||||
|
||||
all_docs[name] = doc_data
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user