diff --git a/docs/package.json b/docs/package.json index 4b09a463ab0..e3670ac9af8 100644 --- a/docs/package.json +++ b/docs/package.json @@ -26,7 +26,7 @@ "@emotion/styled": "^10.0.27", "@saucelabs/theme-github-codeblock": "^0.3.0", "@superset-ui/style": "^0.14.23", - "antd": "^5.24.5", + "antd": "^5.24.9", "docusaurus-plugin-less": "^2.0.2", "less": "^4.3.0", "less-loader": "^11.0.0", diff --git a/docs/static/resources/openapi.json b/docs/static/resources/openapi.json index 9c360c71e43..bb8858fb6cc 100644 --- a/docs/static/resources/openapi.json +++ b/docs/static/resources/openapi.json @@ -635,37 +635,6 @@ }, "type": "object" }, - "AppleHealthResponseSchema": { - "properties": { - "cache_message": { - "description": "Human readable status message for the cache connection", - "type": "string" - }, - "cache_status": { - "description": "The status of the cache", - "enum": [ - "NA", - "HEALTHY", - "ERROR" - ], - "type": "string" - }, - "metastore_message": { - "description": "Human readable status message for the metastore connection", - "type": "string" - }, - "metastore_status": { - "description": "The status of the metastore", - "enum": [ - "NA", - "HEALTHY", - "ERROR" - ], - "type": "string" - } - }, - "type": "object" - }, "AvailableDomainsSchema": { "properties": { "domains": { @@ -677,132 +646,6 @@ }, "type": "object" }, - "CSVMetadataUploadFilePostSchema": { - "properties": { - "delimiter": { - "description": "The delimiter of the CSV file", - "type": "string" - }, - "file": { - "description": "The file to upload", - "format": "binary", - "type": "string" - }, - "header_row": { - "description": "Row containing the headers to use as column names(0 is first line of data). Leave empty if there is no header row.", - "type": "integer" - } - }, - "required": [ - "file" - ], - "type": "object" - }, - "CSVUploadPostSchema": { - "properties": { - "already_exists": { - "default": "fail", - "description": "What to do if the table already exists accepts: fail, replace, append", - "enum": [ - "fail", - "replace", - "append" - ], - "type": "string" - }, - "column_data_types": { - "description": "A dictionary with column names and their data types if you need to change the defaults. Example: {'user_id':'int'}. Check Python Pandas library for supported data types", - "type": "string" - }, - "column_dates": { - "description": "A list of column names that should be parsed as dates. Example: date,timestamp", - "items": { - "type": "string" - }, - "type": "array" - }, - "columns_read": { - "description": "A List of the column names that should be read", - "items": { - "type": "string" - }, - "type": "array" - }, - "dataframe_index": { - "description": "Write dataframe index as a column.", - "type": "boolean" - }, - "day_first": { - "description": "DD/MM format dates, international and European format", - "type": "boolean" - }, - "decimal_character": { - "description": "Character to recognize as decimal point. Default is '.'", - "type": "string" - }, - "delimiter": { - "description": "The delimiter of the CSV file", - "type": "string" - }, - "file": { - "description": "The CSV file to upload", - "format": "text/csv", - "type": "string" - }, - "header_row": { - "description": "Row containing the headers to use as column names(0 is first line of data). Leave empty if there is no header row.", - "type": "integer" - }, - "index_column": { - "description": "Column to use as the row labels of the dataframe. Leave empty if no index column", - "type": "string" - }, - "index_label": { - "description": "Index label for index column.", - "type": "string" - }, - "null_values": { - "description": "A list of strings that should be treated as null. Examples: '' for empty strings, 'None', 'N/A',Warning: Hive database supports only a single value", - "items": { - "type": "string" - }, - "type": "array" - }, - "rows_to_read": { - "description": "Number of rows to read from the file. If None, reads all rows.", - "minimum": 1, - "nullable": true, - "type": "integer" - }, - "schema": { - "description": "The schema to upload the data file to.", - "type": "string" - }, - "skip_blank_lines": { - "description": "Skip blank lines in the CSV file.", - "type": "boolean" - }, - "skip_initial_space": { - "description": "Skip spaces after delimiter.", - "type": "boolean" - }, - "skip_rows": { - "description": "Number of rows to skip at start of file.", - "type": "integer" - }, - "table_name": { - "description": "The name of the table to be created/appended", - "maxLength": 10000, - "minLength": 1, - "type": "string" - } - }, - "required": [ - "file", - "table_name" - ], - "type": "object" - }, "CacheInvalidationRequestSchema": { "properties": { "datasource_uids": { @@ -879,6 +722,14 @@ "image_url": { "description": "The url to fetch the screenshot", "type": "string" + }, + "task_status": { + "description": "The status of the async screenshot", + "type": "string" + }, + "task_updated_at": { + "description": "The timestamp of the last change in status", + "type": "string" } }, "type": "object" @@ -1898,7 +1749,7 @@ "type": "boolean" }, "owners": { - "$ref": "#/components/schemas/ChartDataRestApi.get.AppleUser" + "$ref": "#/components/schemas/ChartDataRestApi.get.User" }, "params": { "nullable": true, @@ -1930,26 +1781,6 @@ }, "type": "object" }, - "ChartDataRestApi.get.AppleUser": { - "properties": { - "first_name": { - "maxLength": 64, - "type": "string" - }, - "id": { - "type": "integer" - }, - "last_name": { - "maxLength": 64, - "type": "string" - } - }, - "required": [ - "first_name", - "last_name" - ], - "type": "object" - }, "ChartDataRestApi.get.Dashboard": { "properties": { "dashboard_title": { @@ -1988,6 +1819,26 @@ }, "type": "object" }, + "ChartDataRestApi.get.User": { + "properties": { + "first_name": { + "maxLength": 64, + "type": "string" + }, + "id": { + "type": "integer" + }, + "last_name": { + "maxLength": 64, + "type": "string" + } + }, + "required": [ + "first_name", + "last_name" + ], + "type": "object" + }, "ChartDataRestApi.get_list": { "properties": { "cache_timeout": { @@ -2069,10 +1920,10 @@ "type": "string" }, "last_saved_by": { - "$ref": "#/components/schemas/ChartDataRestApi.get_list.AppleUser" + "$ref": "#/components/schemas/ChartDataRestApi.get_list.User2" }, "owners": { - "$ref": "#/components/schemas/ChartDataRestApi.get_list.AppleUser1" + "$ref": "#/components/schemas/ChartDataRestApi.get_list.User3" }, "params": { "nullable": true, @@ -2098,6 +1949,11 @@ "url": { "readOnly": true }, + "uuid": { + "format": "uuid", + "nullable": true, + "type": "string" + }, "viz_type": { "maxLength": 250, "nullable": true, @@ -2106,46 +1962,6 @@ }, "type": "object" }, - "ChartDataRestApi.get_list.AppleUser": { - "properties": { - "first_name": { - "maxLength": 64, - "type": "string" - }, - "id": { - "type": "integer" - }, - "last_name": { - "maxLength": 64, - "type": "string" - } - }, - "required": [ - "first_name", - "last_name" - ], - "type": "object" - }, - "ChartDataRestApi.get_list.AppleUser1": { - "properties": { - "first_name": { - "maxLength": 64, - "type": "string" - }, - "id": { - "type": "integer" - }, - "last_name": { - "maxLength": 64, - "type": "string" - } - }, - "required": [ - "first_name", - "last_name" - ], - "type": "object" - }, "ChartDataRestApi.get_list.Dashboard": { "properties": { "dashboard_title": { @@ -2236,6 +2052,46 @@ ], "type": "object" }, + "ChartDataRestApi.get_list.User2": { + "properties": { + "first_name": { + "maxLength": 64, + "type": "string" + }, + "id": { + "type": "integer" + }, + "last_name": { + "maxLength": 64, + "type": "string" + } + }, + "required": [ + "first_name", + "last_name" + ], + "type": "object" + }, + "ChartDataRestApi.get_list.User3": { + "properties": { + "first_name": { + "maxLength": 64, + "type": "string" + }, + "id": { + "type": "integer" + }, + "last_name": { + "maxLength": 64, + "type": "string" + } + }, + "required": [ + "first_name", + "last_name" + ], + "type": "object" + }, "ChartDataRestApi.post": { "properties": { "cache_timeout": { @@ -2718,7 +2574,7 @@ "type": "boolean" }, "owners": { - "$ref": "#/components/schemas/ChartRestApi.get.AppleUser" + "$ref": "#/components/schemas/ChartRestApi.get.User" }, "params": { "nullable": true, @@ -2750,26 +2606,6 @@ }, "type": "object" }, - "ChartRestApi.get.AppleUser": { - "properties": { - "first_name": { - "maxLength": 64, - "type": "string" - }, - "id": { - "type": "integer" - }, - "last_name": { - "maxLength": 64, - "type": "string" - } - }, - "required": [ - "first_name", - "last_name" - ], - "type": "object" - }, "ChartRestApi.get.Dashboard": { "properties": { "dashboard_title": { @@ -2808,6 +2644,26 @@ }, "type": "object" }, + "ChartRestApi.get.User": { + "properties": { + "first_name": { + "maxLength": 64, + "type": "string" + }, + "id": { + "type": "integer" + }, + "last_name": { + "maxLength": 64, + "type": "string" + } + }, + "required": [ + "first_name", + "last_name" + ], + "type": "object" + }, "ChartRestApi.get_list": { "properties": { "cache_timeout": { @@ -2889,10 +2745,10 @@ "type": "string" }, "last_saved_by": { - "$ref": "#/components/schemas/ChartRestApi.get_list.AppleUser" + "$ref": "#/components/schemas/ChartRestApi.get_list.User2" }, "owners": { - "$ref": "#/components/schemas/ChartRestApi.get_list.AppleUser1" + "$ref": "#/components/schemas/ChartRestApi.get_list.User3" }, "params": { "nullable": true, @@ -2918,6 +2774,11 @@ "url": { "readOnly": true }, + "uuid": { + "format": "uuid", + "nullable": true, + "type": "string" + }, "viz_type": { "maxLength": 250, "nullable": true, @@ -2926,46 +2787,6 @@ }, "type": "object" }, - "ChartRestApi.get_list.AppleUser": { - "properties": { - "first_name": { - "maxLength": 64, - "type": "string" - }, - "id": { - "type": "integer" - }, - "last_name": { - "maxLength": 64, - "type": "string" - } - }, - "required": [ - "first_name", - "last_name" - ], - "type": "object" - }, - "ChartRestApi.get_list.AppleUser1": { - "properties": { - "first_name": { - "maxLength": 64, - "type": "string" - }, - "id": { - "type": "integer" - }, - "last_name": { - "maxLength": 64, - "type": "string" - } - }, - "required": [ - "first_name", - "last_name" - ], - "type": "object" - }, "ChartRestApi.get_list.Dashboard": { "properties": { "dashboard_title": { @@ -3056,6 +2877,46 @@ ], "type": "object" }, + "ChartRestApi.get_list.User2": { + "properties": { + "first_name": { + "maxLength": 64, + "type": "string" + }, + "id": { + "type": "integer" + }, + "last_name": { + "maxLength": 64, + "type": "string" + } + }, + "required": [ + "first_name", + "last_name" + ], + "type": "object" + }, + "ChartRestApi.get_list.User3": { + "properties": { + "first_name": { + "maxLength": 64, + "type": "string" + }, + "id": { + "type": "integer" + }, + "last_name": { + "maxLength": 64, + "type": "string" + } + }, + "required": [ + "first_name", + "last_name" + ], + "type": "object" + }, "ChartRestApi.post": { "properties": { "cache_timeout": { @@ -3265,68 +3126,6 @@ }, "type": "object" }, - "ColumnarMetadataUploadFilePostSchema": { - "properties": { - "file": { - "description": "The file to upload", - "format": "binary", - "type": "string" - } - }, - "required": [ - "file" - ], - "type": "object" - }, - "ColumnarUploadPostSchema": { - "properties": { - "already_exists": { - "default": "fail", - "description": "What to do if the table already exists accepts: fail, replace, append", - "enum": [ - "fail", - "replace", - "append" - ], - "type": "string" - }, - "columns_read": { - "description": "A List of the column names that should be read", - "items": { - "type": "string" - }, - "type": "array" - }, - "dataframe_index": { - "description": "Write dataframe index as a column.", - "type": "boolean" - }, - "file": { - "description": "The Columnar file to upload", - "format": "binary", - "type": "string" - }, - "index_label": { - "description": "Index label for index column.", - "type": "string" - }, - "schema": { - "description": "The schema to upload the data file to.", - "type": "string" - }, - "table_name": { - "description": "The name of the table to be created/appended", - "maxLength": 10000, - "minLength": 1, - "type": "string" - } - }, - "required": [ - "file", - "table_name" - ], - "type": "object" - }, "CssTemplateRestApi.get": { "properties": { "changed_by": { @@ -3505,6 +3304,14 @@ "image_url": { "description": "The url to fetch the screenshot", "type": "string" + }, + "task_status": { + "description": "The status of the async screenshot", + "type": "string" + }, + "task_updated_at": { + "description": "The timestamp of the last change in status", + "type": "string" } }, "type": "object" @@ -3766,6 +3573,7 @@ "type": "array" }, "thumbnail_url": { + "nullable": true, "type": "string" }, "url": { @@ -3842,10 +3650,6 @@ "created_on_delta_humanized": { "readOnly": true }, - "css": { - "nullable": true, - "type": "string" - }, "dashboard_title": { "maxLength": 500, "nullable": true, @@ -3857,16 +3661,8 @@ "is_managed_externally": { "type": "boolean" }, - "json_metadata": { - "nullable": true, - "type": "string" - }, "owners": { - "$ref": "#/components/schemas/DashboardRestApi.get_list.AppleUser" - }, - "position_json": { - "nullable": true, - "type": "string" + "$ref": "#/components/schemas/DashboardRestApi.get_list.User2" }, "published": { "nullable": true, @@ -3891,28 +3687,13 @@ }, "url": { "readOnly": true - } - }, - "type": "object" - }, - "DashboardRestApi.get_list.AppleUser": { - "properties": { - "first_name": { - "maxLength": 64, - "type": "string" }, - "id": { - "type": "integer" - }, - "last_name": { - "maxLength": 64, + "uuid": { + "format": "uuid", + "nullable": true, "type": "string" } }, - "required": [ - "first_name", - "last_name" - ], "type": "object" }, "DashboardRestApi.get_list.Role": { @@ -3991,6 +3772,26 @@ ], "type": "object" }, + "DashboardRestApi.get_list.User2": { + "properties": { + "first_name": { + "maxLength": 64, + "type": "string" + }, + "id": { + "type": "integer" + }, + "last_name": { + "maxLength": 64, + "type": "string" + } + }, + "required": [ + "first_name", + "last_name" + ], + "type": "object" + }, "DashboardRestApi.post": { "properties": { "certification_details": { @@ -5525,7 +5326,7 @@ "type": "string" }, "changed_by": { - "$ref": "#/components/schemas/DatasetRestApi.get.User1" + "$ref": "#/components/schemas/DatasetRestApi.get.User2" }, "changed_on": { "format": "date-time", @@ -5542,7 +5343,7 @@ "$ref": "#/components/schemas/DatasetRestApi.get.TableColumn" }, "created_by": { - "$ref": "#/components/schemas/DatasetRestApi.get.User" + "$ref": "#/components/schemas/DatasetRestApi.get.User1" }, "created_on": { "format": "date-time", @@ -5581,6 +5382,9 @@ "nullable": true, "type": "boolean" }, + "folders": { + "nullable": true + }, "granularity_sqla": { "readOnly": true }, @@ -5620,7 +5424,7 @@ "readOnly": true }, "owners": { - "$ref": "#/components/schemas/DatasetRestApi.get.AppleUser" + "$ref": "#/components/schemas/DatasetRestApi.get.User" }, "schema": { "maxLength": 255, @@ -5663,26 +5467,6 @@ ], "type": "object" }, - "DatasetRestApi.get.AppleUser": { - "properties": { - "first_name": { - "maxLength": 64, - "type": "string" - }, - "id": { - "type": "integer" - }, - "last_name": { - "maxLength": 64, - "type": "string" - } - }, - "required": [ - "first_name", - "last_name" - ], - "type": "object" - }, "DatasetRestApi.get.Database": { "properties": { "allow_multi_catalog": { @@ -5717,9 +5501,7 @@ "type": "string" }, "currency": { - "maxLength": 128, - "nullable": true, - "type": "string" + "nullable": true }, "d3format": { "maxLength": 128, @@ -5749,6 +5531,11 @@ "nullable": true, "type": "string" }, + "uuid": { + "format": "uuid", + "nullable": true, + "type": "string" + }, "verbose_name": { "maxLength": 1024, "nullable": true, @@ -5851,6 +5638,9 @@ "maxLength": 64, "type": "string" }, + "id": { + "type": "integer" + }, "last_name": { "maxLength": 64, "type": "string" @@ -5879,6 +5669,23 @@ ], "type": "object" }, + "DatasetRestApi.get.User2": { + "properties": { + "first_name": { + "maxLength": 64, + "type": "string" + }, + "last_name": { + "maxLength": 64, + "type": "string" + } + }, + "required": [ + "first_name", + "last_name" + ], + "type": "object" + }, "DatasetRestApi.get_list": { "properties": { "catalog": { @@ -5926,7 +5733,7 @@ "readOnly": true }, "owners": { - "$ref": "#/components/schemas/DatasetRestApi.get_list.AppleUser" + "$ref": "#/components/schemas/DatasetRestApi.get_list.User1" }, "schema": { "maxLength": 255, @@ -5940,6 +5747,11 @@ "table_name": { "maxLength": 250, "type": "string" + }, + "uuid": { + "format": "uuid", + "nullable": true, + "type": "string" } }, "required": [ @@ -5948,26 +5760,6 @@ ], "type": "object" }, - "DatasetRestApi.get_list.AppleUser": { - "properties": { - "first_name": { - "maxLength": 64, - "type": "string" - }, - "id": { - "type": "integer" - }, - "last_name": { - "maxLength": 64, - "type": "string" - } - }, - "required": [ - "first_name", - "last_name" - ], - "type": "object" - }, "DatasetRestApi.get_list.Database": { "properties": { "database_name": { @@ -6003,6 +5795,26 @@ ], "type": "object" }, + "DatasetRestApi.get_list.User1": { + "properties": { + "first_name": { + "maxLength": 64, + "type": "string" + }, + "id": { + "type": "integer" + }, + "last_name": { + "maxLength": 64, + "type": "string" + } + }, + "required": [ + "first_name", + "last_name" + ], + "type": "object" + }, "DatasetRestApi.post": { "properties": { "always_filter_main_dttm": { @@ -6109,6 +5921,12 @@ "nullable": true, "type": "boolean" }, + "folders": { + "items": { + "$ref": "#/components/schemas/Folder" + }, + "type": "array" + }, "is_managed_externally": { "nullable": true, "type": "boolean" @@ -6350,112 +6168,6 @@ ], "type": "object" }, - "ExcelMetadataUploadFilePostSchema": { - "properties": { - "file": { - "description": "The file to upload", - "format": "binary", - "type": "string" - }, - "header_row": { - "description": "Row containing the headers to use as column names(0 is first line of data). Leave empty if there is no header row.", - "type": "integer" - } - }, - "required": [ - "file" - ], - "type": "object" - }, - "ExcelUploadPostSchema": { - "properties": { - "already_exists": { - "default": "fail", - "description": "What to do if the table already exists accepts: fail, replace, append", - "enum": [ - "fail", - "replace", - "append" - ], - "type": "string" - }, - "column_dates": { - "description": "A list of column names that should be parsed as dates. Example: date,timestamp", - "items": { - "type": "string" - }, - "type": "array" - }, - "columns_read": { - "description": "A List of the column names that should be read", - "items": { - "type": "string" - }, - "type": "array" - }, - "dataframe_index": { - "description": "Write dataframe index as a column.", - "type": "boolean" - }, - "decimal_character": { - "description": "Character to recognize as decimal point. Default is '.'", - "type": "string" - }, - "file": { - "description": "The Excel file to upload", - "format": "binary", - "type": "string" - }, - "header_row": { - "description": "Row containing the headers to use as column names(0 is first line of data). Leave empty if there is no header row.", - "type": "integer" - }, - "index_column": { - "description": "Column to use as the row labels of the dataframe. Leave empty if no index column", - "type": "string" - }, - "index_label": { - "description": "Index label for index column.", - "type": "string" - }, - "null_values": { - "description": "A list of strings that should be treated as null. Examples: '' for empty strings, 'None', 'N/A',Warning: Hive database supports only a single value", - "items": { - "type": "string" - }, - "type": "array" - }, - "rows_to_read": { - "description": "Number of rows to read from the file. If None, reads all rows.", - "minimum": 1, - "nullable": true, - "type": "integer" - }, - "schema": { - "description": "The schema to upload the data file to.", - "type": "string" - }, - "sheet_name": { - "description": "Strings used for sheet names (default is the first sheet).", - "type": "string" - }, - "skip_rows": { - "description": "Number of rows to skip at start of file.", - "type": "integer" - }, - "table_name": { - "description": "The name of the table to be created/appended", - "maxLength": 10000, - "minLength": 1, - "type": "string" - } - }, - "required": [ - "file", - "table_name" - ], - "type": "object" - }, "ExecutePayloadSchema": { "properties": { "catalog": { @@ -6563,6 +6275,44 @@ ], "type": "object" }, + "Folder": { + "properties": { + "children": { + "items": { + "$ref": "#/components/schemas/Folder" + }, + "nullable": true, + "type": "array" + }, + "description": { + "maxLength": 1000, + "minLength": 0, + "nullable": true, + "type": "string" + }, + "name": { + "maxLength": 250, + "minLength": 1, + "type": "string" + }, + "type": { + "enum": [ + "metric", + "column", + "folder" + ], + "type": "string" + }, + "uuid": { + "format": "uuid", + "type": "string" + } + }, + "required": [ + "uuid" + ], + "type": "object" + }, "FormDataPostSchema": { "properties": { "chart_id": { @@ -6708,130 +6458,6 @@ ], "type": "object" }, - "IASLoginTokenRequestSchema": { - "properties": { - "access_token": { - "description": "IAS Access token. Can be requested by adding `token` to the `responseTypes`.", - "nullable": true, - "type": "string" - }, - "client_id": { - "description": "IAS client id. Only needed if `refresh_token` is provided.", - "nullable": true, - "type": "string" - }, - "client_secret": { - "description": "IAS client secret. Only needed if `refresh_token` and `client_id` is provided.", - "nullable": true, - "type": "string" - }, - "id_token": { - "description": "IAS ID token. Can be requested by adding `id_token` to the `responseTypes`. The following scopes should be added:`iam:ds:groups`, `corpds:ds:username`, `corpds:ds:firstName`, `corpds:ds:lastName`, `corpds:ds:email`, `corpds:ds:uidNumber`, `iam:ds:explicitgroups`.", - "type": "string" - }, - "refresh_token": { - "description": "IAS refresh token. This can be requested by adding `offline` to `scopes`. To be able to refresh the token, the IAS `client_id` and `client_secret` need to be added, as the same client needs to be used for refreshing as logging in.", - "nullable": true, - "type": "string" - } - }, - "required": [ - "id_token" - ], - "type": "object" - }, - "IASLoginTokenResponseSchema": { - "properties": { - "access_token": { - "description": "Access that can be used access the Superset API", - "type": "string" - }, - "refresh_token": { - "description": "Refresh token that can be used to refresh the `access_token`", - "type": "string" - } - }, - "required": [ - "access_token" - ], - "type": "object" - }, - "IASProfileResponse": { - "properties": { - "client_id": { - "description": "The client id", - "type": "string" - }, - "profile": { - "description": "The IAS profile", - "type": "string" - }, - "scope": { - "description": "The scope of the client", - "type": "string" - } - }, - "required": [ - "client_id", - "profile" - ], - "type": "object" - }, - "IASProfilesResponseSchema": { - "properties": { - "result": { - "description": "A list of all available IAS profiles", - "items": { - "$ref": "#/components/schemas/IASProfileResponse" - }, - "type": "array" - } - }, - "type": "object" - }, - "IASTokenResponse": { - "properties": { - "access_token": { - "description": "The access token", - "type": "string" - }, - "has_client_credentials": { - "description": "Are the original client credentials available or not", - "type": "boolean" - }, - "has_refresh_token": { - "description": "Is there a refresh token available or not", - "type": "boolean" - }, - "ias_profile": { - "description": "The IAS profile", - "type": "string" - }, - "id_token": { - "description": "The id token", - "type": "string" - } - }, - "required": [ - "has_client_credentials", - "has_refresh_token", - "ias_profile", - "id_token" - ], - "type": "object" - }, - "IASTokensResponseSchema": { - "properties": { - "result": { - "description": "A list of all requested tokens", - "items": { - "$ref": "#/components/schemas/IASTokenResponse" - }, - "type": "array" - } - }, - "type": "object" - }, "ImportV1Database": { "properties": { "allow_csv_upload": { @@ -6856,6 +6482,10 @@ "database_name": { "type": "string" }, + "encrypted_extra": { + "nullable": true, + "type": "string" + }, "expose_in_sqllab": { "type": "boolean" }, @@ -6938,6 +6568,10 @@ "additionalProperties": {}, "type": "object" }, + "schema_options": { + "additionalProperties": {}, + "type": "object" + }, "schemas_allowed_for_csv_upload": { "items": { "type": "string" @@ -6951,310 +6585,6 @@ }, "type": "object" }, - "LakehouseCatalog": { - "properties": { - "database_id": { - "description": "The numerical id of the database", - "type": "integer" - }, - "database_name": { - "description": "The name of the database", - "type": "string" - }, - "id": { - "description": "The numerical id of the catalog", - "type": "integer" - }, - "name": { - "description": "The name of the catalog", - "type": "string" - }, - "sqlalchemy_uri": { - "description": "The SQLAlchemy URI", - "type": "string" - } - }, - "type": "object" - }, - "LakehouseConnectRequestSchema": { - "properties": { - "catalogs": { - "description": "A list of catalogs to connect to. If empty or undefined, connect all available catalogs.", - "example": [ - "my_catalog" - ], - "items": { - "type": "string" - }, - "nullable": true, - "type": "array" - }, - "database_names": { - "description": "Custom catalog-database name mappings. If undefined, the default naming convention will be used", - "example": { - "my_catalog": "my_database" - }, - "nullable": true, - "type": "object" - }, - "dry_run": { - "description": "Should the task be executed in dry run mode. Useful for testing.", - "example": false, - "type": "boolean" - }, - "engine_type": { - "description": "The type of the engine (only trino is currently supported)", - "enum": [ - "trino" - ], - "example": "trino", - "type": "string" - }, - "engine_url": { - "description": "The URL to the engine", - "example": "https://myengine.corp.apple.com", - "type": "string" - }, - "environment": { - "description": "Prod or Int", - "enum": [ - "int", - "prod" - ], - "example": "int", - "type": "string" - }, - "name": { - "description": "The name of the Lakehouse (subject to change over time). If left undefined, use lakehouse id", - "example": "My Lakehouse", - "nullable": true, - "type": "string" - }, - "superset_url": { - "description": "The URL of the Superset instance connecting to", - "example": "http://localhost:8088", - "type": "string" - } - }, - "required": [ - "engine_type", - "engine_url", - "environment", - "superset_url" - ], - "type": "object" - }, - "LakehouseConnectResponseSchema": { - "properties": { - "task_id": { - "description": "The id of the connection task", - "type": "string" - } - }, - "type": "object" - }, - "LakehouseConnectResultResponseSchema": { - "properties": { - "existing_catalogs": { - "description": "A list of connected catalogs before the connect operation", - "items": { - "description": "Catalogs", - "items": { - "$ref": "#/components/schemas/LakehouseCatalog" - }, - "type": "array" - }, - "type": "array" - }, - "lakehouse": { - "allOf": [ - { - "$ref": "#/components/schemas/LakehouseGetResponseSchema" - } - ], - "description": "The connected Lakehouse", - "nullable": true - }, - "message": { - "description": "A message to provide additional context on what has happened", - "type": "string" - }, - "new_catalogs": { - "description": "A list of newly connected catalogs after the connect operation", - "items": { - "description": "Catalogs", - "items": { - "$ref": "#/components/schemas/LakehouseCatalog" - }, - "type": "array" - }, - "type": "array" - }, - "status": { - "description": "The status of the task", - "enum": [ - "scheduled", - "running", - "completed", - "failed", - "reconnect_failed", - "cancelled" - ], - "type": "string" - } - }, - "required": [ - "lakehouse" - ], - "type": "object" - }, - "LakehouseConnectStatusResponseSchema": { - "properties": { - "message": { - "description": "A message to provide additional context on what has happened", - "type": "string" - }, - "status": { - "description": "The status of the task", - "enum": [ - "scheduled", - "running", - "completed", - "failed", - "reconnect_failed", - "cancelled" - ], - "type": "string" - } - }, - "type": "object" - }, - "LakehouseDatasetListResponseSchema": { - "properties": { - "name": { - "description": "The name of the dataset", - "type": "string" - }, - "schema": { - "description": "The schema", - "nullable": true, - "type": "string" - }, - "sql": { - "description": "The virtual dataset query", - "type": "string" - } - }, - "required": [ - "name", - "sql" - ], - "type": "object" - }, - "LakehouseDatasetRequestSchema": { - "properties": { - "catalog": { - "description": "The catalog. If left empty, uses an arbitrary connected catalog.", - "nullable": true, - "type": "string" - }, - "lakehouse_id": { - "description": "Deprecated, not used for anything", - "type": "string" - }, - "name": { - "description": "The name of the dataset to be created", - "type": "string" - }, - "overwrite": { - "default": false, - "description": "Should the virtual dataset be overwritten if it already exists", - "type": "boolean" - }, - "schema": { - "description": "The schema", - "nullable": true, - "type": "string" - }, - "sql": { - "description": "The virtual dataset query", - "type": "string" - } - }, - "required": [ - "name", - "sql" - ], - "type": "object" - }, - "LakehouseDatasetResponseSchema": { - "properties": { - "url": { - "description": "The url for exploring the virtual dataset", - "type": "string" - } - }, - "required": [ - "url" - ], - "type": "object" - }, - "LakehouseDisconnectResponseSchema": { - "properties": { - "lakehouse": { - "allOf": [ - { - "$ref": "#/components/schemas/LakehouseGetResponseSchema" - } - ], - "description": "A list of disconnected lakehouses" - } - }, - "type": "object" - }, - "LakehouseGetListResponseSchema": { - "properties": { - "lakehouses": { - "description": "A list of connected lakehouses", - "items": { - "$ref": "#/components/schemas/LakehouseGetResponseSchema" - }, - "type": "array" - } - }, - "type": "object" - }, - "LakehouseGetResponseSchema": { - "properties": { - "catalogs": { - "description": "A list of connected catalogs", - "items": { - "description": "Catalogs", - "items": { - "$ref": "#/components/schemas/LakehouseCatalog" - }, - "type": "array" - }, - "type": "array" - }, - "engine_url": { - "description": "The URL uf the engine", - "type": "string" - }, - "id": { - "description": "The unique id of the Lakehouse", - "type": "string" - }, - "name": { - "type": "string" - }, - "superset_url": { - "description": "The URL uf the Superset instance", - "type": "string" - } - }, - "type": "object" - }, "LogRestApi.get": { "properties": { "action": { @@ -7289,7 +6619,7 @@ "type": "integer" }, "user": { - "$ref": "#/components/schemas/LogRestApi.get.AppleUser" + "$ref": "#/components/schemas/LogRestApi.get.User" }, "user_id": { "nullable": true, @@ -7298,7 +6628,7 @@ }, "type": "object" }, - "LogRestApi.get.AppleUser": { + "LogRestApi.get.User": { "properties": { "username": { "maxLength": 64, @@ -7344,7 +6674,7 @@ "type": "integer" }, "user": { - "$ref": "#/components/schemas/LogRestApi.get_list.AppleUser" + "$ref": "#/components/schemas/LogRestApi.get_list.User" }, "user_id": { "nullable": true, @@ -7353,7 +6683,7 @@ }, "type": "object" }, - "LogRestApi.get_list.AppleUser": { + "LogRestApi.get_list.User": { "properties": { "username": { "maxLength": 64, @@ -7395,6 +6725,162 @@ }, "type": "object" }, + "PermissionApi.get": { + "properties": { + "id": { + "type": "integer" + }, + "name": { + "maxLength": 100, + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "PermissionApi.get_list": { + "properties": { + "id": { + "type": "integer" + }, + "name": { + "maxLength": 100, + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "PermissionApi.post": { + "properties": { + "name": { + "maxLength": 100, + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "PermissionApi.put": { + "properties": { + "name": { + "maxLength": 100, + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "PermissionViewMenuApi.get": { + "properties": { + "id": { + "type": "integer" + }, + "permission": { + "$ref": "#/components/schemas/PermissionViewMenuApi.get.Permission" + }, + "view_menu": { + "$ref": "#/components/schemas/PermissionViewMenuApi.get.ViewMenu" + } + }, + "type": "object" + }, + "PermissionViewMenuApi.get.Permission": { + "properties": { + "name": { + "maxLength": 100, + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "PermissionViewMenuApi.get.ViewMenu": { + "properties": { + "name": { + "maxLength": 250, + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "PermissionViewMenuApi.get_list": { + "properties": { + "id": { + "type": "integer" + }, + "permission": { + "$ref": "#/components/schemas/PermissionViewMenuApi.get_list.Permission" + }, + "view_menu": { + "$ref": "#/components/schemas/PermissionViewMenuApi.get_list.ViewMenu" + } + }, + "type": "object" + }, + "PermissionViewMenuApi.get_list.Permission": { + "properties": { + "name": { + "maxLength": 100, + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "PermissionViewMenuApi.get_list.ViewMenu": { + "properties": { + "name": { + "maxLength": 250, + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "PermissionViewMenuApi.post": { + "properties": { + "permission_id": { + "nullable": true, + "type": "integer" + }, + "view_menu_id": { + "nullable": true, + "type": "integer" + } + }, + "type": "object" + }, + "PermissionViewMenuApi.put": { + "properties": { + "permission_id": { + "nullable": true, + "type": "integer" + }, + "view_menu_id": { + "nullable": true, + "type": "integer" + } + }, + "type": "object" + }, "QueryExecutionResponseSchema": { "properties": { "columns": { @@ -8239,7 +7725,7 @@ "type": "string" }, "owners": { - "$ref": "#/components/schemas/ReportScheduleRestApi.get.AppleUser" + "$ref": "#/components/schemas/ReportScheduleRestApi.get.User" }, "recipients": { "$ref": "#/components/schemas/ReportScheduleRestApi.get.ReportRecipients" @@ -8283,26 +7769,6 @@ ], "type": "object" }, - "ReportScheduleRestApi.get.AppleUser": { - "properties": { - "first_name": { - "maxLength": 64, - "type": "string" - }, - "id": { - "type": "integer" - }, - "last_name": { - "maxLength": 64, - "type": "string" - } - }, - "required": [ - "first_name", - "last_name" - ], - "type": "object" - }, "ReportScheduleRestApi.get.Dashboard": { "properties": { "dashboard_title": { @@ -8368,6 +7834,26 @@ }, "type": "object" }, + "ReportScheduleRestApi.get.User": { + "properties": { + "first_name": { + "maxLength": 64, + "type": "string" + }, + "id": { + "type": "integer" + }, + "last_name": { + "maxLength": 64, + "type": "string" + } + }, + "required": [ + "first_name", + "last_name" + ], + "type": "object" + }, "ReportScheduleRestApi.get_list": { "properties": { "active": { @@ -8438,7 +7924,7 @@ "type": "string" }, "owners": { - "$ref": "#/components/schemas/ReportScheduleRestApi.get_list.AppleUser" + "$ref": "#/components/schemas/ReportScheduleRestApi.get_list.User2" }, "recipients": { "$ref": "#/components/schemas/ReportScheduleRestApi.get_list.ReportRecipients" @@ -8460,26 +7946,6 @@ ], "type": "object" }, - "ReportScheduleRestApi.get_list.AppleUser": { - "properties": { - "first_name": { - "maxLength": 64, - "type": "string" - }, - "id": { - "type": "integer" - }, - "last_name": { - "maxLength": 64, - "type": "string" - } - }, - "required": [ - "first_name", - "last_name" - ], - "type": "object" - }, "ReportScheduleRestApi.get_list.ReportRecipients": { "properties": { "id": { @@ -8529,6 +7995,26 @@ ], "type": "object" }, + "ReportScheduleRestApi.get_list.User2": { + "properties": { + "first_name": { + "maxLength": 64, + "type": "string" + }, + "id": { + "type": "integer" + }, + "last_name": { + "maxLength": 64, + "type": "string" + } + }, + "required": [ + "first_name", + "last_name" + ], + "type": "object" + }, "ReportScheduleRestApi.post": { "properties": { "active": { @@ -10046,6 +9532,73 @@ ], "type": "object" }, + "RolePermissionListSchema": { + "properties": { + "id": { + "type": "integer" + }, + "permission_name": { + "type": "string" + }, + "view_menu_name": { + "type": "string" + } + }, + "type": "object" + }, + "RolePermissionPostSchema": { + "properties": { + "permission_view_menu_ids": { + "description": "List of permission view menu id", + "items": { + "type": "integer" + }, + "type": "array" + } + }, + "required": [ + "permission_view_menu_ids" + ], + "type": "object" + }, + "RoleResponseSchema": { + "properties": { + "id": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "permission_ids": { + "items": { + "type": "integer" + }, + "type": "array" + }, + "user_ids": { + "items": { + "type": "integer" + }, + "type": "array" + } + }, + "type": "object" + }, + "RoleUserPutSchema": { + "properties": { + "user_ids": { + "description": "List of user ids", + "items": { + "type": "integer" + }, + "type": "array" + } + }, + "required": [ + "user_ids" + ], + "type": "object" + }, "Roles": { "properties": { "id": { @@ -10068,6 +9621,26 @@ }, "type": "object" }, + "RolesResponseSchema": { + "properties": { + "count": { + "type": "integer" + }, + "ids": { + "items": { + "type": "integer" + }, + "type": "array" + }, + "result": { + "items": { + "$ref": "#/components/schemas/RoleResponseSchema" + }, + "type": "array" + } + }, + "type": "object" + }, "SQLLabBootstrapSchema": { "properties": { "active_tab": { @@ -10531,6 +10104,46 @@ }, "type": "object" }, + "SqlLabPermalinkSchema": { + "properties": { + "autorun": { + "type": "boolean" + }, + "catalog": { + "description": "The catalog name of the query", + "nullable": true, + "type": "string" + }, + "dbId": { + "description": "The id of the database", + "type": "integer" + }, + "name": { + "description": "The label of the editor tab", + "type": "string" + }, + "schema": { + "description": "The schema name of the query", + "nullable": true, + "type": "string" + }, + "sql": { + "description": "SQL query text", + "type": "string" + }, + "templateParams": { + "description": "stringfied JSON string for template parameters", + "nullable": true, + "type": "string" + } + }, + "required": [ + "dbId", + "name", + "sql" + ], + "type": "object" + }, "StopQuerySchema": { "properties": { "client_id": { @@ -10539,6 +10152,340 @@ }, "type": "object" }, + "SupersetRoleApi.get": { + "properties": { + "id": { + "type": "integer" + }, + "name": { + "maxLength": 64, + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "SupersetRoleApi.get_list": { + "properties": { + "id": { + "type": "integer" + }, + "name": { + "maxLength": 64, + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "SupersetRoleApi.post": { + "properties": { + "name": { + "maxLength": 64, + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "SupersetRoleApi.put": { + "properties": { + "name": { + "maxLength": 64, + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "SupersetUserApi.get": { + "properties": { + "active": { + "nullable": true, + "type": "boolean" + }, + "changed_by": { + "$ref": "#/components/schemas/SupersetUserApi.get.User1" + }, + "changed_on": { + "format": "date-time", + "nullable": true, + "type": "string" + }, + "created_by": { + "$ref": "#/components/schemas/SupersetUserApi.get.User" + }, + "created_on": { + "format": "date-time", + "nullable": true, + "type": "string" + }, + "email": { + "maxLength": 320, + "type": "string" + }, + "fail_login_count": { + "nullable": true, + "type": "integer" + }, + "first_name": { + "maxLength": 64, + "type": "string" + }, + "id": { + "type": "integer" + }, + "last_login": { + "format": "date-time", + "nullable": true, + "type": "string" + }, + "last_name": { + "maxLength": 64, + "type": "string" + }, + "login_count": { + "nullable": true, + "type": "integer" + }, + "roles": { + "$ref": "#/components/schemas/SupersetUserApi.get.Role" + }, + "username": { + "maxLength": 64, + "type": "string" + } + }, + "required": [ + "email", + "first_name", + "last_name", + "username" + ], + "type": "object" + }, + "SupersetUserApi.get.Role": { + "properties": { + "id": { + "type": "integer" + }, + "name": { + "maxLength": 64, + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "SupersetUserApi.get.User": { + "properties": { + "id": { + "type": "integer" + } + }, + "type": "object" + }, + "SupersetUserApi.get.User1": { + "properties": { + "id": { + "type": "integer" + } + }, + "type": "object" + }, + "SupersetUserApi.get_list": { + "properties": { + "active": { + "nullable": true, + "type": "boolean" + }, + "changed_by": { + "$ref": "#/components/schemas/SupersetUserApi.get_list.User1" + }, + "changed_on": { + "format": "date-time", + "nullable": true, + "type": "string" + }, + "created_by": { + "$ref": "#/components/schemas/SupersetUserApi.get_list.User" + }, + "created_on": { + "format": "date-time", + "nullable": true, + "type": "string" + }, + "email": { + "maxLength": 320, + "type": "string" + }, + "fail_login_count": { + "nullable": true, + "type": "integer" + }, + "first_name": { + "maxLength": 64, + "type": "string" + }, + "id": { + "type": "integer" + }, + "last_login": { + "format": "date-time", + "nullable": true, + "type": "string" + }, + "last_name": { + "maxLength": 64, + "type": "string" + }, + "login_count": { + "nullable": true, + "type": "integer" + }, + "roles": { + "$ref": "#/components/schemas/SupersetUserApi.get_list.Role" + }, + "username": { + "maxLength": 64, + "type": "string" + } + }, + "required": [ + "email", + "first_name", + "last_name", + "username" + ], + "type": "object" + }, + "SupersetUserApi.get_list.Role": { + "properties": { + "id": { + "type": "integer" + }, + "name": { + "maxLength": 64, + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "SupersetUserApi.get_list.User": { + "properties": { + "id": { + "type": "integer" + } + }, + "type": "object" + }, + "SupersetUserApi.get_list.User1": { + "properties": { + "id": { + "type": "integer" + } + }, + "type": "object" + }, + "SupersetUserApi.post": { + "properties": { + "active": { + "description": "Is user active?It's not a good policy to remove a user, just make it inactive", + "type": "boolean" + }, + "email": { + "description": "The user's email", + "type": "string" + }, + "first_name": { + "description": "The user's first name", + "type": "string" + }, + "last_name": { + "description": "The user's last name", + "type": "string" + }, + "password": { + "description": "The user's password for authentication", + "type": "string" + }, + "roles": { + "description": "The user's roles", + "items": { + "type": "integer" + }, + "minItems": 1, + "type": "array" + }, + "username": { + "description": "The user's username", + "maxLength": 250, + "minLength": 1, + "type": "string" + } + }, + "required": [ + "email", + "first_name", + "last_name", + "password", + "roles", + "username" + ], + "type": "object" + }, + "SupersetUserApi.put": { + "properties": { + "active": { + "description": "Is user active?It's not a good policy to remove a user, just make it inactive", + "type": "boolean" + }, + "email": { + "description": "The user's email", + "type": "string" + }, + "first_name": { + "description": "The user's first name", + "type": "string" + }, + "last_name": { + "description": "The user's last name", + "type": "string" + }, + "password": { + "description": "The user's password for authentication", + "type": "string" + }, + "roles": { + "description": "The user's roles", + "items": { + "type": "integer" + }, + "minItems": 1, + "type": "array" + }, + "username": { + "description": "The user's username", + "maxLength": 250, + "minLength": 1, + "type": "string" + } + }, + "type": "object" + }, "Tab": { "properties": { "children": { @@ -11224,6 +11171,154 @@ }, "type": "object" }, + "UploadFileMetadataPostSchema": { + "properties": { + "delimiter": { + "description": "The character used to separate values in the CSV file (e.g., a comma, semicolon, or tab).", + "type": "string" + }, + "file": { + "description": "The file to upload", + "format": "binary", + "type": "string" + }, + "header_row": { + "description": "Row containing the headers to use as column names(0 is first line of data). Leave empty if there is no header row.", + "type": "integer" + }, + "type": { + "description": "File type to upload", + "enum": [ + "csv", + "excel", + "columnar" + ] + } + }, + "required": [ + "file", + "type" + ], + "type": "object" + }, + "UploadPostSchema": { + "properties": { + "already_exists": { + "default": "fail", + "description": "What to do if the table already exists accepts: fail, replace, append", + "enum": [ + "fail", + "replace", + "append" + ], + "type": "string" + }, + "column_data_types": { + "description": "[CSV only] A dictionary with column names and their data types if you need to change the defaults. Example: {'user_id':'int'}. Check Python Pandas library for supported data types", + "type": "string" + }, + "column_dates": { + "description": "[CSV and Excel only] A list of column names that should be parsed as dates. Example: date,timestamp", + "items": { + "type": "string" + }, + "type": "array" + }, + "columns_read": { + "description": "A List of the column names that should be read", + "items": { + "type": "string" + }, + "type": "array" + }, + "dataframe_index": { + "description": "Write dataframe index as a column.", + "type": "boolean" + }, + "day_first": { + "description": "[CSV only] DD/MM format dates, international and European format", + "type": "boolean" + }, + "decimal_character": { + "description": "[CSV and Excel only] Character to recognize as decimal point. Default is '.'", + "type": "string" + }, + "delimiter": { + "description": "[CSV only] The character used to separate values in the CSV file (e.g., a comma, semicolon, or tab).", + "type": "string" + }, + "file": { + "description": "The file to upload", + "format": "text/csv", + "type": "string" + }, + "header_row": { + "description": "[CSV and Excel only] Row containing the headers to use as column names (0 is first line of data). Leave empty if there is no header row.", + "type": "integer" + }, + "index_column": { + "description": "[CSV and Excel only] Column to use as the row labels of the dataframe. Leave empty if no index column", + "type": "string" + }, + "index_label": { + "description": "Index label for index column.", + "type": "string" + }, + "null_values": { + "description": "[CSV and Excel only] A list of strings that should be treated as null. Examples: '' for empty strings, 'None', 'N/A', Warning: Hive database supports only a single value", + "items": { + "type": "string" + }, + "type": "array" + }, + "rows_to_read": { + "description": "[CSV and Excel only] Number of rows to read from the file. If None, reads all rows.", + "minimum": 1, + "nullable": true, + "type": "integer" + }, + "schema": { + "description": "The schema to upload the data file to.", + "type": "string" + }, + "sheet_name": { + "description": "[Excel only]] Strings used for sheet names (default is the first sheet).", + "type": "string" + }, + "skip_blank_lines": { + "description": "[CSV only] Skip blank lines in the CSV file.", + "type": "boolean" + }, + "skip_initial_space": { + "description": "[CSV only] Skip spaces after delimiter.", + "type": "boolean" + }, + "skip_rows": { + "description": "[CSV and Excel only] Number of rows to skip at start of file.", + "type": "integer" + }, + "table_name": { + "description": "The name of the table to be created/appended", + "maxLength": 10000, + "minLength": 1, + "type": "string" + }, + "type": { + "description": "File type to upload", + "enum": [ + "csv", + "excel", + "columnar" + ] + } + }, + "required": [ + "file", + "table_name", + "type" + ], + "type": "object" + }, "User": { "properties": { "first_name": { @@ -11356,6 +11451,60 @@ }, "type": "object" }, + "ViewMenuApi.get": { + "properties": { + "id": { + "type": "integer" + }, + "name": { + "maxLength": 250, + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "ViewMenuApi.get_list": { + "properties": { + "id": { + "type": "integer" + }, + "name": { + "maxLength": 250, + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "ViewMenuApi.post": { + "properties": { + "name": { + "maxLength": 250, + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "ViewMenuApi.put": { + "properties": { + "name": { + "maxLength": 250, + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, "advanced_data_type_convert_schema": { "properties": { "type": { @@ -11391,6 +11540,9 @@ }, "force": { "type": "boolean" + }, + "upload_allowed": { + "type": "boolean" } }, "type": "object" @@ -12796,39 +12948,6 @@ ] } }, - "/api/v1/apple/health": { - "get": { - "description": "Endpoint for checking the health status of the metastore and cache", - "responses": { - "200": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AppleHealthResponseSchema" - } - } - }, - "description": "The" - }, - "400": { - "$ref": "#/components/responses/400" - }, - "401": { - "$ref": "#/components/responses/401" - }, - "403": { - "$ref": "#/components/responses/403" - }, - "500": { - "$ref": "#/components/responses/500" - } - }, - "summary": "Get the health status of the metastore and cache", - "tags": [ - "Apple" - ] - } - }, "/api/v1/assets/export/": { "get": { "description": "Gets a ZIP file with all the Superset assets (databases, datasets, charts, dashboards, saved queries) as YAML files.", @@ -12881,6 +13000,10 @@ "description": "JSON map of passwords for each featured database in the ZIP file. If the ZIP includes a database config in the path `databases/MyDatabase.yaml`, the password should be provided in the following format: `{\"databases/MyDatabase.yaml\": \"my_password\"}`.", "type": "string" }, + "sparse": { + "description": "allow sparse update of resources", + "type": "boolean" + }, "ssh_tunnel_passwords": { "description": "JSON map of passwords for each ssh_tunnel associated to a featured database in the ZIP file. If the ZIP includes a ssh_tunnel config in the path `databases/MyDatabase.yaml`, the password should be provided in the following format: `{\"databases/MyDatabase.yaml\": \"my_password\"}`.", "type": "string" @@ -14040,7 +14163,7 @@ } ], "responses": { - "202": { + "200": { "content": { "application/json": { "schema": { @@ -14050,6 +14173,16 @@ }, "description": "Chart async result" }, + "202": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ChartCacheScreenshotResponseSchema" + } + } + }, + "description": "Chart screenshot task created" + }, "400": { "$ref": "#/components/responses/400" }, @@ -14280,7 +14413,7 @@ } } }, - "description": "Chart thumbnail image" + "description": "Chart screenshot image" }, "400": { "$ref": "#/components/responses/400" @@ -14319,6 +14452,7 @@ } }, { + "description": "A hex digest that makes this chart unique", "in": "path", "name": "digest", "required": true, @@ -16225,6 +16359,83 @@ ] } }, + "/api/v1/dashboard/{pk}/colors": { + "put": { + "parameters": [ + { + "in": "path", + "name": "pk", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "in": "query", + "name": "mark_updated", + "schema": { + "description": "Whether to update the dashboard changed_on field", + "type": "boolean" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DashboardColorsConfigUpdateSchema" + } + } + }, + "description": "Colors configuration", + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "result": { + "type": "array" + } + }, + "type": "object" + } + } + }, + "description": "Dashboard colors updated" + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "403": { + "$ref": "#/components/responses/403" + }, + "404": { + "$ref": "#/components/responses/404" + }, + "422": { + "$ref": "#/components/responses/422" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "summary": "Update colors configuration for a dashboard.", + "tags": [ + "Dashboards" + ] + } + }, "/api/v1/dashboard/{pk}/favorites/": { "delete": { "parameters": [ @@ -16343,6 +16554,107 @@ "requestBody": { "content": { "application/json": { + "examples": { + "numerical_range_filter": { + "description": "**This body should be stringified and put into the value field.**", + "summary": "Numerical Range Filter", + "value": { + "extraFormData": { + "filters": [ + { + "col": "tz_offset", + "op": ">=", + "val": [ + 1000 + ] + }, + { + "col": "tz_offset", + "op": "<=", + "val": [ + 2000 + ] + } + ] + }, + "filterState": { + "label": "1000 <= x <= 2000", + "value": [ + 1000, + 2000 + ] + }, + "id": "NATIVE_FILTER_ID" + } + }, + "time_grain_filter": { + "description": "**This body should be stringified and put into the value field.**", + "summary": "Time Grain Filter", + "value": { + "extraFormData": { + "time_grain_sqla": "P1W/1970-01-03T00:00:00Z" + }, + "filterState": { + "label": "Week ending Saturday", + "value": [ + "P1W/1970-01-03T00:00:00Z" + ] + }, + "id": "NATIVE_FILTER_ID" + } + }, + "time_range_filter": { + "description": "**This body should be stringified and put into the value field.**", + "summary": "Time Range Filter", + "value": { + "extraFormData": { + "time_range": "DATEADD(DATETIME('2025-01-16T00:00:00'), -7, day) : 2025-01-16T00:00:00" + }, + "filterState": { + "value": "DATEADD(DATETIME('2025-01-16T00:00:00'), -7, day) : 2025-01-16T00:00:00" + }, + "id": "NATIVE_FILTER_ID" + } + }, + "timecolumn_filter": { + "description": "**This body should be stringified and put into the value field.**", + "summary": "Time Column Filter", + "value": { + "extraFormData": { + "granularity_sqla": "order_date" + }, + "filterState": { + "value": [ + "order_date" + ] + }, + "id": "NATIVE_FILTER_ID" + } + }, + "value_filter": { + "description": "**This body should be stringified and put into the value field.**", + "summary": "Value Filter", + "value": { + "extraFormData": { + "filters": [ + { + "col": "real_name", + "op": "IN", + "val": [ + "John Doe" + ] + } + ] + }, + "filterState": { + "value": [ + "John Doe" + ] + }, + "id": "NATIVE_FILTER_ID" + } + } + }, "schema": { "$ref": "#/components/schemas/TemporaryCachePostSchema" } @@ -16681,6 +16993,112 @@ "requestBody": { "content": { "application/json": { + "examples": { + "numerical_range_filter": { + "summary": "Numerical Range Filter", + "value": { + "dataMask": { + "extraFormData": { + "filters": [ + { + "col": "tz_offset", + "op": ">=", + "val": [ + 1000 + ] + }, + { + "col": "tz_offset", + "op": "<=", + "val": [ + 2000 + ] + } + ] + }, + "filterState": { + "label": "1000 <= x <= 200", + "value": [ + 1000, + 2000 + ] + }, + "id": "NATIVE_FILTER_ID" + } + } + }, + "time_grain_filter": { + "summary": "Time Grain Filter", + "value": { + "dataMask": { + "extraFormData": { + "time_grain_sqla": "P1W/1970-01-03T00:00:00Z" + }, + "filterState": { + "label": "Week ending Saturday", + "value": [ + "P1W/1970-01-03T00:00:00Z" + ] + }, + "id": "NATIVE_FILTER_ID" + } + } + }, + "time_range_filter": { + "summary": "Time Range Filter", + "value": { + "dataMask": { + "extraFormData": { + "time_range": "DATEADD(DATETIME(\"2025-01-16T00:00:00\"), -7, day) : 2025-01-16T00:00:00" + }, + "filterState": { + "value": "DATEADD(DATETIME(\"2025-01-16T00:00:00\"), -7, day) : 2025-01-16T00:00:00" + }, + "id": "NATIVE_FILTER_ID" + } + } + }, + "timecolumn_filter": { + "summary": "Time Column Filter", + "value": { + "dataMask": { + "extraFormData": { + "granularity_sqla": "order_date" + }, + "filterState": { + "value": [ + "order_date" + ] + }, + "id": "NATIVE_FILTER_ID" + } + } + }, + "value_filter": { + "summary": "Value Filter", + "value": { + "dataMask": { + "extraFormData": { + "filters": [ + { + "col": "real_name", + "op": "IN", + "val": [ + "John Doe" + ] + } + ] + }, + "filterState": { + "value": [ + "John Doe" + ] + }, + "id": "NATIVE_FILTER_ID" + } + } + } + }, "schema": { "$ref": "#/components/schemas/DashboardPermalinkStateSchema" } @@ -16751,6 +17169,17 @@ "schema": { "type": "string" } + }, + { + "in": "query", + "name": "download_format", + "schema": { + "enum": [ + "png", + "pdf" + ], + "type": "string" + } } ], "responses": { @@ -16809,17 +17238,6 @@ "schema": { "type": "string" } - }, - { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/thumbnail_query_schema" - } - } - }, - "in": "query", - "name": "q" } ], "responses": { @@ -17208,162 +17626,6 @@ ] } }, - "/api/v1/database/columnar_metadata/": { - "post": { - "requestBody": { - "content": { - "multipart/form-data": { - "schema": { - "$ref": "#/components/schemas/ColumnarMetadataUploadFilePostSchema" - } - } - }, - "required": true - }, - "responses": { - "200": { - "content": { - "application/json": { - "schema": { - "properties": { - "result": { - "$ref": "#/components/schemas/UploadFileMetadata" - } - }, - "type": "object" - } - } - }, - "description": "Columnar upload response" - }, - "400": { - "$ref": "#/components/responses/400" - }, - "401": { - "$ref": "#/components/responses/401" - }, - "404": { - "$ref": "#/components/responses/404" - }, - "500": { - "$ref": "#/components/responses/500" - } - }, - "security": [ - { - "jwt": [] - } - ], - "summary": "Upload a Columnar file and returns file metadata", - "tags": [ - "Database" - ] - } - }, - "/api/v1/database/csv_metadata/": { - "post": { - "requestBody": { - "content": { - "multipart/form-data": { - "schema": { - "$ref": "#/components/schemas/CSVMetadataUploadFilePostSchema" - } - } - }, - "required": true - }, - "responses": { - "200": { - "content": { - "application/json": { - "schema": { - "properties": { - "result": { - "$ref": "#/components/schemas/UploadFileMetadata" - } - }, - "type": "object" - } - } - }, - "description": "Columnar upload response" - }, - "400": { - "$ref": "#/components/responses/400" - }, - "401": { - "$ref": "#/components/responses/401" - }, - "404": { - "$ref": "#/components/responses/404" - }, - "500": { - "$ref": "#/components/responses/500" - } - }, - "security": [ - { - "jwt": [] - } - ], - "summary": "Upload an CSV file and returns file metadata", - "tags": [ - "Database" - ] - } - }, - "/api/v1/database/excel_metadata/": { - "post": { - "requestBody": { - "content": { - "multipart/form-data": { - "schema": { - "$ref": "#/components/schemas/ExcelMetadataUploadFilePostSchema" - } - } - }, - "required": true - }, - "responses": { - "200": { - "content": { - "application/json": { - "schema": { - "properties": { - "result": { - "$ref": "#/components/schemas/UploadFileMetadata" - } - }, - "type": "object" - } - } - }, - "description": "Columnar upload response" - }, - "400": { - "$ref": "#/components/responses/400" - }, - "401": { - "$ref": "#/components/responses/401" - }, - "404": { - "$ref": "#/components/responses/404" - }, - "500": { - "$ref": "#/components/responses/500" - } - }, - "security": [ - { - "jwt": [] - } - ], - "summary": "Upload an Excel file and returns file metadata", - "tags": [ - "Database" - ] - } - }, "/api/v1/database/export/": { "get": { "parameters": [ @@ -17664,6 +17926,58 @@ ] } }, + "/api/v1/database/upload_metadata/": { + "post": { + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "$ref": "#/components/schemas/UploadFileMetadataPostSchema" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "result": { + "$ref": "#/components/schemas/UploadFileMetadata" + } + }, + "type": "object" + } + } + }, + "description": "Upload response" + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "404": { + "$ref": "#/components/responses/404" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "summary": "Upload a file and returns file metadata", + "tags": [ + "Database" + ] + } + }, "/api/v1/database/validate_parameters/": { "post": { "requestBody": { @@ -17944,71 +18258,6 @@ ] } }, - "/api/v1/database/{pk}/columnar_upload/": { - "post": { - "parameters": [ - { - "in": "path", - "name": "pk", - "required": true, - "schema": { - "type": "integer" - } - } - ], - "requestBody": { - "content": { - "multipart/form-data": { - "schema": { - "$ref": "#/components/schemas/ColumnarUploadPostSchema" - } - } - }, - "required": true - }, - "responses": { - "201": { - "content": { - "application/json": { - "schema": { - "properties": { - "message": { - "type": "string" - } - }, - "type": "object" - } - } - }, - "description": "Columnar upload response" - }, - "400": { - "$ref": "#/components/responses/400" - }, - "401": { - "$ref": "#/components/responses/401" - }, - "404": { - "$ref": "#/components/responses/404" - }, - "422": { - "$ref": "#/components/responses/422" - }, - "500": { - "$ref": "#/components/responses/500" - } - }, - "security": [ - { - "jwt": [] - } - ], - "summary": "Upload a Columnar file to a database table", - "tags": [ - "Database" - ] - } - }, "/api/v1/database/{pk}/connection": { "get": { "parameters": [ @@ -18057,136 +18306,6 @@ ] } }, - "/api/v1/database/{pk}/csv_upload/": { - "post": { - "parameters": [ - { - "in": "path", - "name": "pk", - "required": true, - "schema": { - "type": "integer" - } - } - ], - "requestBody": { - "content": { - "multipart/form-data": { - "schema": { - "$ref": "#/components/schemas/CSVUploadPostSchema" - } - } - }, - "required": true - }, - "responses": { - "201": { - "content": { - "application/json": { - "schema": { - "properties": { - "message": { - "type": "string" - } - }, - "type": "object" - } - } - }, - "description": "CSV upload response" - }, - "400": { - "$ref": "#/components/responses/400" - }, - "401": { - "$ref": "#/components/responses/401" - }, - "404": { - "$ref": "#/components/responses/404" - }, - "422": { - "$ref": "#/components/responses/422" - }, - "500": { - "$ref": "#/components/responses/500" - } - }, - "security": [ - { - "jwt": [] - } - ], - "summary": "Upload a CSV file to a database table", - "tags": [ - "Database" - ] - } - }, - "/api/v1/database/{pk}/excel_upload/": { - "post": { - "parameters": [ - { - "in": "path", - "name": "pk", - "required": true, - "schema": { - "type": "integer" - } - } - ], - "requestBody": { - "content": { - "multipart/form-data": { - "schema": { - "$ref": "#/components/schemas/ExcelUploadPostSchema" - } - } - }, - "required": true - }, - "responses": { - "201": { - "content": { - "application/json": { - "schema": { - "properties": { - "message": { - "type": "string" - } - }, - "type": "object" - } - } - }, - "description": "Excel upload response" - }, - "400": { - "$ref": "#/components/responses/400" - }, - "401": { - "$ref": "#/components/responses/401" - }, - "404": { - "$ref": "#/components/responses/404" - }, - "422": { - "$ref": "#/components/responses/422" - }, - "500": { - "$ref": "#/components/responses/500" - } - }, - "security": [ - { - "jwt": [] - } - ], - "summary": "Upload an Excel file to a database table", - "tags": [ - "Database" - ] - } - }, "/api/v1/database/{pk}/function_names/": { "get": { "parameters": [ @@ -18571,6 +18690,59 @@ ] } }, + "/api/v1/database/{pk}/sync_permissions/": { + "post": { + "parameters": [ + { + "description": "The database connection ID", + "in": "path", + "name": "pk", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "message": { + "type": "string" + } + }, + "type": "object" + } + } + }, + "description": "Task created to sync permissions." + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "404": { + "$ref": "#/components/responses/404" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "summary": "Re-sync all permissions for a database connection", + "tags": [ + "Database" + ] + } + }, "/api/v1/database/{pk}/table/{table_name}/{schema_name}/": { "get": { "parameters": [ @@ -18926,6 +19098,71 @@ ] } }, + "/api/v1/database/{pk}/upload/": { + "post": { + "parameters": [ + { + "in": "path", + "name": "pk", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "$ref": "#/components/schemas/UploadPostSchema" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "properties": { + "message": { + "type": "string" + } + }, + "type": "object" + } + } + }, + "description": "CSV upload response" + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "404": { + "$ref": "#/components/responses/404" + }, + "422": { + "$ref": "#/components/responses/422" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "summary": "Upload a file to a database table", + "tags": [ + "Database" + ] + } + }, "/api/v1/database/{pk}/validate_sql/": { "post": { "description": "Validates that arbitrary SQL is acceptable for the given database.", @@ -20262,6 +20499,46 @@ "schema": { "type": "string" } + }, + { + "description": "The ui config of embedded dashboard (optional).", + "in": "query", + "name": "uiConfig", + "schema": { + "type": "number" + } + }, + { + "description": "Show filters (optional).", + "in": "query", + "name": "show_filters", + "schema": { + "type": "boolean" + } + }, + { + "description": "Expand filters (optional).", + "in": "query", + "name": "expand_filters", + "schema": { + "type": "boolean" + } + }, + { + "description": "Native filters key to apply filters. (optional).", + "in": "query", + "name": "native_filters_key", + "schema": { + "type": "string" + } + }, + { + "description": "Permalink key to apply filters. (optional).", + "in": "query", + "name": "permalink_key", + "schema": { + "type": "string" + } } ], "responses": { @@ -20276,6 +20553,11 @@ }, "type": "object" } + }, + "text/html": { + "schema": { + "type": "string" + } } }, "description": "Result contains the embedded dashboard configuration" @@ -20736,663 +21018,6 @@ ] } }, - "/api/v1/ias/login_token": { - "post": { - "description": "Endpoint for exchanging IAS tokens for Superset API tokens. IAS Tokens should be requested from the `acssuperset` IAS application, typically using [client credential flow](https://docs.aci.apple.com/ias/tutorials/client_credentials/index.html). At a minimum, an `id_token` needs to be provided, but by providing a `refresh_token` Superset will be able to automatically refresh the token after the initial one expires. However, to be able to refresh the token, `client_id` and `client_secret` must be provided, as the token needs to be refreshed with the same client that was used for logging in. Unless `refresh_token`, `client_id` and `client_secret` are provided, a `refresh_token` will not be returned.\\nThe following scope should be requested in the token request: `offline openid iam:ds:groups corpds:ds:username corpds:ds:firstName corpds:ds:lastName corpds:ds:email iam:ds:explicitgroups`", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/IASLoginTokenRequestSchema" - } - } - }, - "description": "Payload containing IAS tokens.", - "required": true - }, - "responses": { - "200": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/IASLoginTokenResponseSchema" - } - } - }, - "description": "Query result" - }, - "400": { - "$ref": "#/components/responses/400" - }, - "401": { - "$ref": "#/components/responses/401" - }, - "500": { - "$ref": "#/components/responses/500" - } - }, - "tags": [ - "IAS" - ] - } - }, - "/api/v1/ias/profiles": { - "get": { - "description": "Endpoint for retrieving available IAS profiles.", - "parameters": [ - { - "description": "The name of the IAS profile", - "in": "query", - "name": "profile", - "required": false, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/IASProfilesResponseSchema" - } - } - }, - "description": "IAS Tokens" - } - }, - "security": [ - { - "jwt": [] - } - ], - "tags": [ - "IAS" - ] - } - }, - "/api/v1/ias/tokens": { - "get": { - "description": "Endpoint for retrieving IAS tokens for the logged in user. If no token is provided, all tokens are returned.", - "parameters": [ - { - "description": "The name of the IAS profile", - "in": "query", - "name": "profile", - "required": false, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/IASTokensResponseSchema" - } - } - }, - "description": "IAS Tokens" - }, - "400": { - "$ref": "#/components/responses/400" - } - }, - "security": [ - { - "jwt": [] - } - ], - "tags": [ - "IAS" - ] - } - }, - "/api/v1/ias/tokens/{pk}": { - "get": { - "description": "Endpoint for retrieving IAS tokens for a specific user. If no token is provided, all tokens are returned. Only Admin users are able to view other users' tokens.", - "parameters": [ - { - "in": "path", - "name": "pk", - "required": true, - "schema": { - "type": "string" - } - }, - { - "description": "The name of the IAS profile", - "in": "query", - "name": "profile", - "required": false, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/IASTokensResponseSchema" - } - } - }, - "description": "IAS Tokens" - }, - "400": { - "$ref": "#/components/responses/400" - } - }, - "security": [ - { - "jwt": [] - } - ], - "tags": [ - "IAS" - ] - } - }, - "/api/v1/lakehouse": { - "get": { - "description": "Disconnect a Lakehouse.", - "responses": { - "200": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/LakehouseGetListResponseSchema" - } - } - }, - "description": "Lakehouse has been deleted" - }, - "401": { - "$ref": "#/components/responses/401" - }, - "403": { - "$ref": "#/components/responses/403" - }, - "500": { - "$ref": "#/components/responses/500" - } - }, - "security": [ - { - "jwt": [] - } - ], - "summary": "Get a list of all connected Lakehouses", - "tags": [ - "Lakehouse" - ] - } - }, - "/api/v1/lakehouse/{lakehouse_id}": { - "delete": { - "description": "Disconnect a Lakehouse.", - "parameters": [ - { - "description": "The unique id of the lakehouse", - "in": "path", - "name": "lakehouse_id", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/LakehouseDisconnectResponseSchema" - } - } - }, - "description": "Lakehouse has been deleted" - }, - "401": { - "$ref": "#/components/responses/401" - }, - "403": { - "$ref": "#/components/responses/403" - }, - "404": { - "$ref": "#/components/responses/404" - }, - "500": { - "$ref": "#/components/responses/500" - } - }, - "security": [ - { - "jwt": [] - } - ], - "summary": "Disconnect a Lakehouse and all catalogs", - "tags": [ - "Lakehouse" - ] - }, - "get": { - "description": "Get information regarding a connected Lakehouse", - "parameters": [ - { - "description": "The unique id of the lakehouse", - "in": "path", - "name": "lakehouse_id", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/LakehouseGetResponseSchema" - } - } - }, - "description": "Lakehouses" - }, - "401": { - "$ref": "#/components/responses/401" - }, - "403": { - "$ref": "#/components/responses/403" - }, - "404": { - "$ref": "#/components/responses/404" - }, - "500": { - "$ref": "#/components/responses/500" - } - }, - "security": [ - { - "jwt": [] - } - ], - "summary": "Get information about a specific Lakehouse", - "tags": [ - "Lakehouse" - ] - }, - "post": { - "description": "Endpoint for connecting a Lakehouse and associated catalogs to the ACS Superset instance.", - "parameters": [ - { - "description": "The unique id of the lakehouse", - "in": "path", - "name": "lakehouse_id", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/LakehouseConnectRequestSchema" - } - } - }, - "description": "Payload containing connection parameters.", - "required": true - }, - "responses": { - "200": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/LakehouseConnectResponseSchema" - } - } - }, - "description": "The connection task has been scheduled." - }, - "400": { - "$ref": "#/components/responses/400" - }, - "401": { - "$ref": "#/components/responses/401" - }, - "403": { - "$ref": "#/components/responses/403" - }, - "500": { - "$ref": "#/components/responses/500" - } - }, - "security": [ - { - "jwt": [] - } - ], - "summary": "Schedule a task to connect a Lakehouse and catalogs", - "tags": [ - "Lakehouse" - ] - } - }, - "/api/v1/lakehouse/{lakehouse_id}/dataset": { - "get": { - "description": "Endpoint for listing all virtual datasets on a Lakehouse", - "parameters": [ - { - "description": "The unique id of the lakehouse", - "in": "path", - "name": "lakehouse_id", - "required": true, - "schema": { - "type": "string" - } - }, - { - "description": "The catalog. Leave empty for all catalogs", - "in": "query", - "name": "catalog", - "schema": { - "type": "string" - } - }, - { - "description": "The schema. Leave empty for all schemas", - "in": "query", - "name": "schema", - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/LakehouseDatasetListResponseSchema" - } - } - }, - "description": "All virtual datasets satisfying the query params." - }, - "400": { - "$ref": "#/components/responses/400" - }, - "401": { - "$ref": "#/components/responses/401" - }, - "403": { - "$ref": "#/components/responses/403" - }, - "500": { - "$ref": "#/components/responses/500" - } - }, - "security": [ - { - "jwt": [] - } - ], - "summary": "Get a list of virtual datasets", - "tags": [ - "Lakehouse" - ] - }, - "post": { - "description": "Endpoint for creating a virtual dataset from a query", - "parameters": [ - { - "description": "The unique id of the lakehouse", - "in": "path", - "name": "lakehouse_id", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/LakehouseDatasetRequestSchema" - } - } - }, - "description": "Payload containing virtual dataset parameters.", - "required": true - }, - "responses": { - "200": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/LakehouseDatasetResponseSchema" - } - } - }, - "description": "The virtual dataset has been created." - }, - "400": { - "$ref": "#/components/responses/400" - }, - "401": { - "$ref": "#/components/responses/401" - }, - "403": { - "$ref": "#/components/responses/403" - }, - "422": { - "$ref": "#/components/responses/422" - }, - "500": { - "$ref": "#/components/responses/500" - } - }, - "security": [ - { - "jwt": [] - } - ], - "summary": "Create a virtual dataset out of a query", - "tags": [ - "Lakehouse" - ] - } - }, - "/api/v1/lakehouse/{lakehouse_id}/task/{task_id}/cancel": { - "post": { - "description": "Endpoint for cancelling a scheduled connection request.", - "parameters": [ - { - "description": "The unique id of the lakehouse", - "in": "path", - "name": "lakehouse_id", - "required": true, - "schema": { - "type": "string" - } - }, - { - "description": "The id of the connection task", - "in": "path", - "name": "task_id", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/LakehouseConnectStatusResponseSchema" - } - } - }, - "description": "The status of the task." - }, - "400": { - "$ref": "#/components/responses/400" - }, - "401": { - "$ref": "#/components/responses/401" - }, - "403": { - "$ref": "#/components/responses/403" - }, - "404": { - "$ref": "#/components/responses/404" - }, - "500": { - "$ref": "#/components/responses/500" - } - }, - "security": [ - { - "jwt": [] - } - ], - "summary": "Cancel a running task", - "tags": [ - "Lakehouse" - ] - } - }, - "/api/v1/lakehouse/{lakehouse_id}/task/{task_id}/result": { - "get": { - "description": "Endpoint for retrieving the payload of a scheduled connection request.", - "parameters": [ - { - "description": "The unique id of the lakehouse", - "in": "path", - "name": "lakehouse_id", - "required": true, - "schema": { - "type": "string" - } - }, - { - "description": "The id of the connection task", - "in": "path", - "name": "task_id", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/LakehouseConnectResultResponseSchema" - } - } - }, - "description": "The status of the task." - }, - "400": { - "$ref": "#/components/responses/400" - }, - "401": { - "$ref": "#/components/responses/401" - }, - "403": { - "$ref": "#/components/responses/404" - }, - "500": { - "$ref": "#/components/responses/500" - } - }, - "security": [ - { - "jwt": [] - } - ], - "summary": "Get the payload of a completed connection task", - "tags": [ - "Lakehouse" - ] - } - }, - "/api/v1/lakehouse/{lakehouse_id}/task/{task_id}/status": { - "get": { - "description": "Endpoint for checking what the status of a scheduled connection request is.", - "parameters": [ - { - "description": "The unique id of the lakehouse", - "in": "path", - "name": "lakehouse_id", - "required": true, - "schema": { - "type": "string" - } - }, - { - "description": "The id of the connection task", - "in": "path", - "name": "task_id", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/LakehouseConnectStatusResponseSchema" - } - } - }, - "description": "The status of the task." - }, - "400": { - "$ref": "#/components/responses/400" - }, - "401": { - "$ref": "#/components/responses/401" - }, - "403": { - "$ref": "#/components/responses/403" - }, - "404": { - "$ref": "#/components/responses/404" - }, - "500": { - "$ref": "#/components/responses/500" - } - }, - "security": [ - { - "jwt": [] - } - ], - "summary": "Check the status of a connection task", - "tags": [ - "Lakehouse" - ] - } - }, "/api/v1/log/": { "get": { "description": "Gets a list of logs, use Rison or JSON query parameters for filtering, sorting, pagination and for selecting specific columns and metadata.", @@ -24613,6 +24238,762 @@ ] } }, + "/api/v1/security/permissions-resources/": { + "get": { + "description": "Get a list of models", + "parameters": [ + { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/get_list_schema" + } + } + }, + "in": "query", + "name": "q" + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "count": { + "description": "The total record count on the backend", + "type": "number" + }, + "description_columns": { + "properties": { + "column_name": { + "description": "The description for the column name. Will be translated by babel", + "example": "A Nice description for the column", + "type": "string" + } + }, + "type": "object" + }, + "ids": { + "description": "A list of item ids, useful when you don't know the column id", + "items": { + "type": "string" + }, + "type": "array" + }, + "label_columns": { + "properties": { + "column_name": { + "description": "The label for the column name. Will be translated by babel", + "example": "A Nice label for the column", + "type": "string" + } + }, + "type": "object" + }, + "list_columns": { + "description": "A list of columns", + "items": { + "type": "string" + }, + "type": "array" + }, + "list_title": { + "description": "A title to render. Will be translated by babel", + "example": "List Items", + "type": "string" + }, + "order_columns": { + "description": "A list of allowed columns to sort", + "items": { + "type": "string" + }, + "type": "array" + }, + "result": { + "description": "The result from the get list query", + "items": { + "$ref": "#/components/schemas/PermissionViewMenuApi.get_list" + }, + "type": "array" + } + }, + "type": "object" + } + } + }, + "description": "Items from Model" + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "422": { + "$ref": "#/components/responses/422" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "tags": [ + "Security Permissions on Resources (View Menus)" + ] + }, + "post": { + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PermissionViewMenuApi.post" + } + } + }, + "description": "Model schema", + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "properties": { + "id": { + "type": "string" + }, + "result": { + "$ref": "#/components/schemas/PermissionViewMenuApi.post" + } + }, + "type": "object" + } + } + }, + "description": "Item inserted" + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "422": { + "$ref": "#/components/responses/422" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "tags": [ + "Security Permissions on Resources (View Menus)" + ] + } + }, + "/api/v1/security/permissions-resources/_info": { + "get": { + "description": "Get metadata information about this API resource", + "parameters": [ + { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/get_info_schema" + } + } + }, + "in": "query", + "name": "q" + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "add_columns": { + "type": "object" + }, + "edit_columns": { + "type": "object" + }, + "filters": { + "properties": { + "column_name": { + "items": { + "properties": { + "name": { + "description": "The filter name. Will be translated by babel", + "type": "string" + }, + "operator": { + "description": "The filter operation key to use on list filters", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "permissions": { + "description": "The user permissions for this API resource", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + } + } + }, + "description": "Item from Model" + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "422": { + "$ref": "#/components/responses/422" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "tags": [ + "Security Permissions on Resources (View Menus)" + ] + } + }, + "/api/v1/security/permissions-resources/{pk}": { + "delete": { + "parameters": [ + { + "in": "path", + "name": "pk", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "message": { + "type": "string" + } + }, + "type": "object" + } + } + }, + "description": "Item deleted" + }, + "404": { + "$ref": "#/components/responses/404" + }, + "422": { + "$ref": "#/components/responses/422" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "tags": [ + "Security Permissions on Resources (View Menus)" + ] + }, + "get": { + "description": "Get an item model", + "parameters": [ + { + "in": "path", + "name": "pk", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/get_item_schema" + } + } + }, + "in": "query", + "name": "q" + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "description_columns": { + "properties": { + "column_name": { + "description": "The description for the column name. Will be translated by babel", + "example": "A Nice description for the column", + "type": "string" + } + }, + "type": "object" + }, + "id": { + "description": "The item id", + "type": "string" + }, + "label_columns": { + "properties": { + "column_name": { + "description": "The label for the column name. Will be translated by babel", + "example": "A Nice label for the column", + "type": "string" + } + }, + "type": "object" + }, + "result": { + "$ref": "#/components/schemas/PermissionViewMenuApi.get" + }, + "show_columns": { + "description": "A list of columns", + "items": { + "type": "string" + }, + "type": "array" + }, + "show_title": { + "description": "A title to render. Will be translated by babel", + "example": "Show Item Details", + "type": "string" + } + }, + "type": "object" + } + } + }, + "description": "Item from Model" + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "404": { + "$ref": "#/components/responses/404" + }, + "422": { + "$ref": "#/components/responses/422" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "tags": [ + "Security Permissions on Resources (View Menus)" + ] + }, + "put": { + "parameters": [ + { + "in": "path", + "name": "pk", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PermissionViewMenuApi.put" + } + } + }, + "description": "Model schema", + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "result": { + "$ref": "#/components/schemas/PermissionViewMenuApi.put" + } + }, + "type": "object" + } + } + }, + "description": "Item changed" + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "404": { + "$ref": "#/components/responses/404" + }, + "422": { + "$ref": "#/components/responses/422" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "tags": [ + "Security Permissions on Resources (View Menus)" + ] + } + }, + "/api/v1/security/permissions/": { + "get": { + "description": "Get a list of models", + "parameters": [ + { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/get_list_schema" + } + } + }, + "in": "query", + "name": "q" + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "count": { + "description": "The total record count on the backend", + "type": "number" + }, + "description_columns": { + "properties": { + "column_name": { + "description": "The description for the column name. Will be translated by babel", + "example": "A Nice description for the column", + "type": "string" + } + }, + "type": "object" + }, + "ids": { + "description": "A list of item ids, useful when you don't know the column id", + "items": { + "type": "string" + }, + "type": "array" + }, + "label_columns": { + "properties": { + "column_name": { + "description": "The label for the column name. Will be translated by babel", + "example": "A Nice label for the column", + "type": "string" + } + }, + "type": "object" + }, + "list_columns": { + "description": "A list of columns", + "items": { + "type": "string" + }, + "type": "array" + }, + "list_title": { + "description": "A title to render. Will be translated by babel", + "example": "List Items", + "type": "string" + }, + "order_columns": { + "description": "A list of allowed columns to sort", + "items": { + "type": "string" + }, + "type": "array" + }, + "result": { + "description": "The result from the get list query", + "items": { + "$ref": "#/components/schemas/PermissionApi.get_list" + }, + "type": "array" + } + }, + "type": "object" + } + } + }, + "description": "Items from Model" + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "422": { + "$ref": "#/components/responses/422" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "tags": [ + "Security Permissions" + ] + } + }, + "/api/v1/security/permissions/_info": { + "get": { + "description": "Get metadata information about this API resource", + "parameters": [ + { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/get_info_schema" + } + } + }, + "in": "query", + "name": "q" + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "add_columns": { + "type": "object" + }, + "edit_columns": { + "type": "object" + }, + "filters": { + "properties": { + "column_name": { + "items": { + "properties": { + "name": { + "description": "The filter name. Will be translated by babel", + "type": "string" + }, + "operator": { + "description": "The filter operation key to use on list filters", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "permissions": { + "description": "The user permissions for this API resource", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + } + } + }, + "description": "Item from Model" + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "422": { + "$ref": "#/components/responses/422" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "tags": [ + "Security Permissions" + ] + } + }, + "/api/v1/security/permissions/{pk}": { + "get": { + "description": "Get an item model", + "parameters": [ + { + "in": "path", + "name": "pk", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/get_item_schema" + } + } + }, + "in": "query", + "name": "q" + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "description_columns": { + "properties": { + "column_name": { + "description": "The description for the column name. Will be translated by babel", + "example": "A Nice description for the column", + "type": "string" + } + }, + "type": "object" + }, + "id": { + "description": "The item id", + "type": "string" + }, + "label_columns": { + "properties": { + "column_name": { + "description": "The label for the column name. Will be translated by babel", + "example": "A Nice label for the column", + "type": "string" + } + }, + "type": "object" + }, + "result": { + "$ref": "#/components/schemas/PermissionApi.get" + }, + "show_columns": { + "description": "A list of columns", + "items": { + "type": "string" + }, + "type": "array" + }, + "show_title": { + "description": "A title to render. Will be translated by babel", + "example": "Show Item Details", + "type": "string" + } + }, + "type": "object" + } + } + }, + "description": "Item from Model" + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "404": { + "$ref": "#/components/responses/404" + }, + "422": { + "$ref": "#/components/responses/422" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "tags": [ + "Security Permissions" + ] + } + }, "/api/v1/security/refresh": { "post": { "description": "Use the refresh token to get a new JWT access token", @@ -24650,6 +25031,1677 @@ ] } }, + "/api/v1/security/resources/": { + "get": { + "description": "Get a list of models", + "parameters": [ + { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/get_list_schema" + } + } + }, + "in": "query", + "name": "q" + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "count": { + "description": "The total record count on the backend", + "type": "number" + }, + "description_columns": { + "properties": { + "column_name": { + "description": "The description for the column name. Will be translated by babel", + "example": "A Nice description for the column", + "type": "string" + } + }, + "type": "object" + }, + "ids": { + "description": "A list of item ids, useful when you don't know the column id", + "items": { + "type": "string" + }, + "type": "array" + }, + "label_columns": { + "properties": { + "column_name": { + "description": "The label for the column name. Will be translated by babel", + "example": "A Nice label for the column", + "type": "string" + } + }, + "type": "object" + }, + "list_columns": { + "description": "A list of columns", + "items": { + "type": "string" + }, + "type": "array" + }, + "list_title": { + "description": "A title to render. Will be translated by babel", + "example": "List Items", + "type": "string" + }, + "order_columns": { + "description": "A list of allowed columns to sort", + "items": { + "type": "string" + }, + "type": "array" + }, + "result": { + "description": "The result from the get list query", + "items": { + "$ref": "#/components/schemas/ViewMenuApi.get_list" + }, + "type": "array" + } + }, + "type": "object" + } + } + }, + "description": "Items from Model" + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "422": { + "$ref": "#/components/responses/422" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "tags": [ + "Security Resources (View Menus)" + ] + }, + "post": { + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ViewMenuApi.post" + } + } + }, + "description": "Model schema", + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "properties": { + "id": { + "type": "string" + }, + "result": { + "$ref": "#/components/schemas/ViewMenuApi.post" + } + }, + "type": "object" + } + } + }, + "description": "Item inserted" + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "422": { + "$ref": "#/components/responses/422" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "tags": [ + "Security Resources (View Menus)" + ] + } + }, + "/api/v1/security/resources/_info": { + "get": { + "description": "Get metadata information about this API resource", + "parameters": [ + { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/get_info_schema" + } + } + }, + "in": "query", + "name": "q" + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "add_columns": { + "type": "object" + }, + "edit_columns": { + "type": "object" + }, + "filters": { + "properties": { + "column_name": { + "items": { + "properties": { + "name": { + "description": "The filter name. Will be translated by babel", + "type": "string" + }, + "operator": { + "description": "The filter operation key to use on list filters", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "permissions": { + "description": "The user permissions for this API resource", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + } + } + }, + "description": "Item from Model" + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "422": { + "$ref": "#/components/responses/422" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "tags": [ + "Security Resources (View Menus)" + ] + } + }, + "/api/v1/security/resources/{pk}": { + "delete": { + "parameters": [ + { + "in": "path", + "name": "pk", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "message": { + "type": "string" + } + }, + "type": "object" + } + } + }, + "description": "Item deleted" + }, + "404": { + "$ref": "#/components/responses/404" + }, + "422": { + "$ref": "#/components/responses/422" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "tags": [ + "Security Resources (View Menus)" + ] + }, + "get": { + "description": "Get an item model", + "parameters": [ + { + "in": "path", + "name": "pk", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/get_item_schema" + } + } + }, + "in": "query", + "name": "q" + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "description_columns": { + "properties": { + "column_name": { + "description": "The description for the column name. Will be translated by babel", + "example": "A Nice description for the column", + "type": "string" + } + }, + "type": "object" + }, + "id": { + "description": "The item id", + "type": "string" + }, + "label_columns": { + "properties": { + "column_name": { + "description": "The label for the column name. Will be translated by babel", + "example": "A Nice label for the column", + "type": "string" + } + }, + "type": "object" + }, + "result": { + "$ref": "#/components/schemas/ViewMenuApi.get" + }, + "show_columns": { + "description": "A list of columns", + "items": { + "type": "string" + }, + "type": "array" + }, + "show_title": { + "description": "A title to render. Will be translated by babel", + "example": "Show Item Details", + "type": "string" + } + }, + "type": "object" + } + } + }, + "description": "Item from Model" + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "404": { + "$ref": "#/components/responses/404" + }, + "422": { + "$ref": "#/components/responses/422" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "tags": [ + "Security Resources (View Menus)" + ] + }, + "put": { + "parameters": [ + { + "in": "path", + "name": "pk", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ViewMenuApi.put" + } + } + }, + "description": "Model schema", + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "result": { + "$ref": "#/components/schemas/ViewMenuApi.put" + } + }, + "type": "object" + } + } + }, + "description": "Item changed" + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "404": { + "$ref": "#/components/responses/404" + }, + "422": { + "$ref": "#/components/responses/422" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "tags": [ + "Security Resources (View Menus)" + ] + } + }, + "/api/v1/security/roles/": { + "get": { + "description": "Get a list of models", + "parameters": [ + { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/get_list_schema" + } + } + }, + "in": "query", + "name": "q" + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "count": { + "description": "The total record count on the backend", + "type": "number" + }, + "description_columns": { + "properties": { + "column_name": { + "description": "The description for the column name. Will be translated by babel", + "example": "A Nice description for the column", + "type": "string" + } + }, + "type": "object" + }, + "ids": { + "description": "A list of item ids, useful when you don't know the column id", + "items": { + "type": "string" + }, + "type": "array" + }, + "label_columns": { + "properties": { + "column_name": { + "description": "The label for the column name. Will be translated by babel", + "example": "A Nice label for the column", + "type": "string" + } + }, + "type": "object" + }, + "list_columns": { + "description": "A list of columns", + "items": { + "type": "string" + }, + "type": "array" + }, + "list_title": { + "description": "A title to render. Will be translated by babel", + "example": "List Items", + "type": "string" + }, + "order_columns": { + "description": "A list of allowed columns to sort", + "items": { + "type": "string" + }, + "type": "array" + }, + "result": { + "description": "The result from the get list query", + "items": { + "$ref": "#/components/schemas/SupersetRoleApi.get_list" + }, + "type": "array" + } + }, + "type": "object" + } + } + }, + "description": "Items from Model" + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "422": { + "$ref": "#/components/responses/422" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "tags": [ + "Security Roles" + ] + }, + "post": { + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SupersetRoleApi.post" + } + } + }, + "description": "Model schema", + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "properties": { + "id": { + "type": "string" + }, + "result": { + "$ref": "#/components/schemas/SupersetRoleApi.post" + } + }, + "type": "object" + } + } + }, + "description": "Item inserted" + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "422": { + "$ref": "#/components/responses/422" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "tags": [ + "Security Roles" + ] + } + }, + "/api/v1/security/roles/_info": { + "get": { + "description": "Get metadata information about this API resource", + "parameters": [ + { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/get_info_schema" + } + } + }, + "in": "query", + "name": "q" + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "add_columns": { + "type": "object" + }, + "edit_columns": { + "type": "object" + }, + "filters": { + "properties": { + "column_name": { + "items": { + "properties": { + "name": { + "description": "The filter name. Will be translated by babel", + "type": "string" + }, + "operator": { + "description": "The filter operation key to use on list filters", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "permissions": { + "description": "The user permissions for this API resource", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + } + } + }, + "description": "Item from Model" + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "422": { + "$ref": "#/components/responses/422" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "tags": [ + "Security Roles" + ] + } + }, + "/api/v1/security/roles/search/": { + "get": { + "description": "Fetch a paginated list of roles with user and permission IDs.", + "parameters": [ + { + "in": "query", + "name": "q", + "schema": { + "properties": { + "filters": { + "items": { + "properties": { + "col": { + "enum": [ + "user_ids", + "permission_ids", + "name" + ], + "type": "string" + }, + "value": { + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "order_column": { + "default": "id", + "enum": [ + "id", + "name" + ], + "type": "string" + }, + "order_direction": { + "default": "asc", + "enum": [ + "asc", + "desc" + ], + "type": "string" + }, + "page": { + "default": 0, + "type": "integer" + }, + "page_size": { + "default": 10, + "type": "integer" + } + }, + "type": "object" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RolesResponseSchema" + } + } + }, + "description": "Successfully retrieved roles" + }, + "400": { + "content": { + "application/json": { + "schema": { + "properties": { + "error": { + "type": "string" + } + }, + "type": "object" + } + } + }, + "description": "Bad request (invalid input)" + }, + "403": { + "content": { + "application/json": { + "schema": { + "properties": { + "error": { + "type": "string" + } + }, + "type": "object" + } + } + }, + "description": "Forbidden" + } + }, + "security": [ + { + "jwt": [] + } + ], + "summary": "List roles", + "tags": [ + "Security Roles" + ] + } + }, + "/api/v1/security/roles/{pk}": { + "delete": { + "parameters": [ + { + "in": "path", + "name": "pk", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "message": { + "type": "string" + } + }, + "type": "object" + } + } + }, + "description": "Item deleted" + }, + "404": { + "$ref": "#/components/responses/404" + }, + "422": { + "$ref": "#/components/responses/422" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "tags": [ + "Security Roles" + ] + }, + "get": { + "description": "Get an item model", + "parameters": [ + { + "in": "path", + "name": "pk", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/get_item_schema" + } + } + }, + "in": "query", + "name": "q" + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "description_columns": { + "properties": { + "column_name": { + "description": "The description for the column name. Will be translated by babel", + "example": "A Nice description for the column", + "type": "string" + } + }, + "type": "object" + }, + "id": { + "description": "The item id", + "type": "string" + }, + "label_columns": { + "properties": { + "column_name": { + "description": "The label for the column name. Will be translated by babel", + "example": "A Nice label for the column", + "type": "string" + } + }, + "type": "object" + }, + "result": { + "$ref": "#/components/schemas/SupersetRoleApi.get" + }, + "show_columns": { + "description": "A list of columns", + "items": { + "type": "string" + }, + "type": "array" + }, + "show_title": { + "description": "A title to render. Will be translated by babel", + "example": "Show Item Details", + "type": "string" + } + }, + "type": "object" + } + } + }, + "description": "Item from Model" + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "404": { + "$ref": "#/components/responses/404" + }, + "422": { + "$ref": "#/components/responses/422" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "tags": [ + "Security Roles" + ] + }, + "put": { + "parameters": [ + { + "in": "path", + "name": "pk", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SupersetRoleApi.put" + } + } + }, + "description": "Model schema", + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "result": { + "$ref": "#/components/schemas/SupersetRoleApi.put" + } + }, + "type": "object" + } + } + }, + "description": "Item changed" + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "404": { + "$ref": "#/components/responses/404" + }, + "422": { + "$ref": "#/components/responses/422" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "tags": [ + "Security Roles" + ] + } + }, + "/api/v1/security/roles/{role_id}/permissions": { + "post": { + "parameters": [ + { + "in": "path", + "name": "role_id", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RolePermissionPostSchema" + } + } + }, + "description": "Add role permissions schema", + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "result": { + "$ref": "#/components/schemas/RolePermissionPostSchema" + } + }, + "type": "object" + } + } + }, + "description": "Permissions added" + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "404": { + "$ref": "#/components/responses/404" + }, + "422": { + "$ref": "#/components/responses/422" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "tags": [ + "Security Roles" + ] + } + }, + "/api/v1/security/roles/{role_id}/permissions/": { + "get": { + "parameters": [ + { + "in": "path", + "name": "role_id", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "result": { + "$ref": "#/components/schemas/RolePermissionListSchema" + } + }, + "type": "object" + } + } + }, + "description": "List of permissions" + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "404": { + "$ref": "#/components/responses/404" + }, + "422": { + "$ref": "#/components/responses/422" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "tags": [ + "Security Roles" + ] + } + }, + "/api/v1/security/roles/{role_id}/users": { + "put": { + "parameters": [ + { + "in": "path", + "name": "role_id", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RoleUserPutSchema" + } + } + }, + "description": "Update role users schema", + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "result": { + "$ref": "#/components/schemas/RoleUserPutSchema" + } + }, + "type": "object" + } + } + }, + "description": "Role users updated" + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "404": { + "$ref": "#/components/responses/404" + }, + "422": { + "$ref": "#/components/responses/422" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "tags": [ + "Security Roles" + ] + } + }, + "/api/v1/security/users/": { + "get": { + "description": "Get a list of models", + "parameters": [ + { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/get_list_schema" + } + } + }, + "in": "query", + "name": "q" + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "count": { + "description": "The total record count on the backend", + "type": "number" + }, + "description_columns": { + "properties": { + "column_name": { + "description": "The description for the column name. Will be translated by babel", + "example": "A Nice description for the column", + "type": "string" + } + }, + "type": "object" + }, + "ids": { + "description": "A list of item ids, useful when you don't know the column id", + "items": { + "type": "string" + }, + "type": "array" + }, + "label_columns": { + "properties": { + "column_name": { + "description": "The label for the column name. Will be translated by babel", + "example": "A Nice label for the column", + "type": "string" + } + }, + "type": "object" + }, + "list_columns": { + "description": "A list of columns", + "items": { + "type": "string" + }, + "type": "array" + }, + "list_title": { + "description": "A title to render. Will be translated by babel", + "example": "List Items", + "type": "string" + }, + "order_columns": { + "description": "A list of allowed columns to sort", + "items": { + "type": "string" + }, + "type": "array" + }, + "result": { + "description": "The result from the get list query", + "items": { + "$ref": "#/components/schemas/SupersetUserApi.get_list" + }, + "type": "array" + } + }, + "type": "object" + } + } + }, + "description": "Items from Model" + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "422": { + "$ref": "#/components/responses/422" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "tags": [ + "Security Users" + ] + }, + "post": { + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SupersetUserApi.post" + } + } + }, + "description": "Model schema", + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "properties": { + "result": { + "$ref": "#/components/schemas/SupersetUserApi.post" + } + }, + "type": "object" + } + } + }, + "description": "Item changed" + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "404": { + "$ref": "#/components/responses/404" + }, + "422": { + "$ref": "#/components/responses/422" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "tags": [ + "Security Users" + ] + } + }, + "/api/v1/security/users/_info": { + "get": { + "description": "Get metadata information about this API resource", + "parameters": [ + { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/get_info_schema" + } + } + }, + "in": "query", + "name": "q" + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "add_columns": { + "type": "object" + }, + "edit_columns": { + "type": "object" + }, + "filters": { + "properties": { + "column_name": { + "items": { + "properties": { + "name": { + "description": "The filter name. Will be translated by babel", + "type": "string" + }, + "operator": { + "description": "The filter operation key to use on list filters", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "permissions": { + "description": "The user permissions for this API resource", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + } + } + }, + "description": "Item from Model" + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "422": { + "$ref": "#/components/responses/422" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "tags": [ + "Security Users" + ] + } + }, + "/api/v1/security/users/{pk}": { + "delete": { + "parameters": [ + { + "in": "path", + "name": "pk", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "message": { + "type": "string" + } + }, + "type": "object" + } + } + }, + "description": "Item deleted" + }, + "404": { + "$ref": "#/components/responses/404" + }, + "422": { + "$ref": "#/components/responses/422" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "tags": [ + "Security Users" + ] + }, + "get": { + "description": "Get an item model", + "parameters": [ + { + "in": "path", + "name": "pk", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/get_item_schema" + } + } + }, + "in": "query", + "name": "q" + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "description_columns": { + "properties": { + "column_name": { + "description": "The description for the column name. Will be translated by babel", + "example": "A Nice description for the column", + "type": "string" + } + }, + "type": "object" + }, + "id": { + "description": "The item id", + "type": "string" + }, + "label_columns": { + "properties": { + "column_name": { + "description": "The label for the column name. Will be translated by babel", + "example": "A Nice label for the column", + "type": "string" + } + }, + "type": "object" + }, + "result": { + "$ref": "#/components/schemas/SupersetUserApi.get" + }, + "show_columns": { + "description": "A list of columns", + "items": { + "type": "string" + }, + "type": "array" + }, + "show_title": { + "description": "A title to render. Will be translated by babel", + "example": "Show Item Details", + "type": "string" + } + }, + "type": "object" + } + } + }, + "description": "Item from Model" + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "404": { + "$ref": "#/components/responses/404" + }, + "422": { + "$ref": "#/components/responses/422" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "tags": [ + "Security Users" + ] + }, + "put": { + "parameters": [ + { + "in": "path", + "name": "pk", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SupersetUserApi.put" + } + } + }, + "description": "Model schema", + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "result": { + "$ref": "#/components/schemas/SupersetUserApi.put" + } + }, + "type": "object" + } + } + }, + "description": "Item changed" + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "404": { + "$ref": "#/components/responses/404" + }, + "422": { + "$ref": "#/components/responses/422" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "tags": [ + "Security Users" + ] + } + }, "/api/v1/sqllab/": { "get": { "description": "Assembles SQLLab bootstrap data (active_tab, databases, queries, tab_state_ids) in a single endpoint. The data can be assembled from the current user's id.", @@ -24906,6 +26958,119 @@ ] } }, + "/api/v1/sqllab/permalink": { + "post": { + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExplorePermalinkStateSchema" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "properties": { + "key": { + "description": "The key to retrieve the permanent link data.", + "type": "string" + }, + "url": { + "description": "permanent link.", + "type": "string" + } + }, + "type": "object" + } + } + }, + "description": "The permanent link was stored successfully." + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "422": { + "$ref": "#/components/responses/422" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "summary": "Create a new permanent link", + "tags": [ + "SQL Lab Permanent Link" + ] + } + }, + "/api/v1/sqllab/permalink/{key}": { + "get": { + "parameters": [ + { + "in": "path", + "name": "key", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "state": { + "description": "The stored state", + "type": "object" + } + }, + "type": "object" + } + } + }, + "description": "Returns the stored form_data." + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "404": { + "$ref": "#/components/responses/404" + }, + "422": { + "$ref": "#/components/responses/422" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "summary": "Get permanent link state for SQLLab editor.", + "tags": [ + "SQL Lab Permanent Link" + ] + } + }, "/api/v1/sqllab/results/": { "get": { "parameters": [ diff --git a/docs/yarn.lock b/docs/yarn.lock index 475df2f00ed..c23e15f21b3 100644 --- a/docs/yarn.lock +++ b/docs/yarn.lock @@ -1092,20 +1092,13 @@ core-js-pure "^3.30.2" regenerator-runtime "^0.14.0" -"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.3", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.25.9", "@babel/runtime@^7.8.4": +"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.1", "@babel/runtime@^7.10.3", "@babel/runtime@^7.10.4", "@babel/runtime@^7.11.1", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.16.7", "@babel/runtime@^7.18.0", "@babel/runtime@^7.18.3", "@babel/runtime@^7.20.0", "@babel/runtime@^7.20.7", "@babel/runtime@^7.21.0", "@babel/runtime@^7.22.5", "@babel/runtime@^7.23.2", "@babel/runtime@^7.23.6", "@babel/runtime@^7.23.9", "@babel/runtime@^7.24.4", "@babel/runtime@^7.24.7", "@babel/runtime@^7.24.8", "@babel/runtime@^7.25.7", "@babel/runtime@^7.25.9", "@babel/runtime@^7.26.0", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4": version "7.27.0" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.27.0.tgz#fbee7cf97c709518ecc1f590984481d5460d4762" integrity sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw== dependencies: regenerator-runtime "^0.14.0" -"@babel/runtime@^7.10.1", "@babel/runtime@^7.10.4", "@babel/runtime@^7.11.1", "@babel/runtime@^7.11.2", "@babel/runtime@^7.16.7", "@babel/runtime@^7.18.0", "@babel/runtime@^7.18.3", "@babel/runtime@^7.20.0", "@babel/runtime@^7.20.7", "@babel/runtime@^7.21.0", "@babel/runtime@^7.22.5", "@babel/runtime@^7.23.2", "@babel/runtime@^7.23.6", "@babel/runtime@^7.23.9", "@babel/runtime@^7.24.4", "@babel/runtime@^7.24.7", "@babel/runtime@^7.24.8", "@babel/runtime@^7.25.7", "@babel/runtime@^7.26.0", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2": - version "7.26.10" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.26.10.tgz#a07b4d8fa27af131a633d7b3524db803eb4764c2" - integrity sha512-2WJMeRQPHKSPemqk/awGrAiuFfzBmOIPXKizAsVhWH9YJqLZ0H+HS4c8loHGgW6utJ3E/ejXQUsiGaQy2NZ9Fw== - dependencies: - regenerator-runtime "^0.14.0" - "@babel/template@^7.25.9", "@babel/template@^7.26.9", "@babel/template@^7.27.0": version "7.27.0" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.27.0.tgz#b253e5406cc1df1c57dcd18f11760c2dbf40c0b4" @@ -4186,10 +4179,10 @@ ansi-styles@^6.1.0: resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== -antd@^5.24.5: - version "5.24.5" - resolved "https://registry.yarnpkg.com/antd/-/antd-5.24.5.tgz#b0976a113163888d1477f9e666c3c23352b098e9" - integrity sha512-1lAv/G+9ewQanyoAo3JumQmIlVxwo5QwWGb6QCHYc40Cq0NxC/EzITcjsgq1PSaTUpLkKq8A2l7Fjtu47vqQBg== +antd@^5.24.9: + version "5.24.9" + resolved "https://registry.yarnpkg.com/antd/-/antd-5.24.9.tgz#c5862e02ed770bd95e312961f4f0b7b158a004d9" + integrity sha512-liB+Y/JwD5/KSKbK1Z1EVAbWcoWYvWJ1s97AbbT+mOdigpJQuWwH7kG8IXNEljI7onvj0DdD43TXhSRLUu9AMA== dependencies: "@ant-design/colors" "^7.2.0" "@ant-design/cssinjs" "^1.23.0" @@ -4213,13 +4206,13 @@ antd@^5.24.5: rc-drawer "~7.2.0" rc-dropdown "~4.2.1" rc-field-form "~2.7.0" - rc-image "~7.11.1" - rc-input "~1.7.3" - rc-input-number "~9.4.0" - rc-mentions "~2.19.1" + rc-image "~7.12.0" + rc-input "~1.8.0" + rc-input-number "~9.5.0" + rc-mentions "~2.20.0" rc-menu "~9.16.1" rc-motion "^2.9.5" - rc-notification "~5.6.3" + rc-notification "~5.6.4" rc-pagination "~5.1.0" rc-picker "~4.11.3" rc-progress "~4.0.0" @@ -4231,8 +4224,8 @@ antd@^5.24.5: rc-steps "~6.0.1" rc-switch "~4.1.0" rc-table "~7.50.4" - rc-tabs "~15.5.1" - rc-textarea "~1.9.0" + rc-tabs "~15.6.1" + rc-textarea "~1.10.0" rc-tooltip "~6.4.0" rc-tree "~5.13.1" rc-tree-select "~5.27.0" @@ -5674,12 +5667,7 @@ data-view-byte-offset@^1.0.1: es-errors "^1.3.0" is-data-view "^1.0.1" -dayjs@^1.11.11: - version "1.11.12" - resolved "https://registry.npmjs.org/dayjs/-/dayjs-1.11.12.tgz" - integrity sha512-Rt2g+nTbLlDWZTwwrIXjy9MeiZmSDI375FvZs72ngxx8PDC6YXOeR3q5LAuPzjZQxhiWdRKac7RKV+YyQYfYIg== - -dayjs@^1.11.13: +dayjs@^1.11.11, dayjs@^1.11.13: version "1.11.13" resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.13.tgz#92430b0139055c3ebb60150aa13e860a4b5a366c" integrity sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg== @@ -10688,10 +10676,10 @@ rc-field-form@~2.7.0: "@rc-component/async-validator" "^5.0.3" rc-util "^5.32.2" -rc-image@~7.11.1: - version "7.11.1" - resolved "https://registry.yarnpkg.com/rc-image/-/rc-image-7.11.1.tgz#3ab290708dc053d3681de94186522e4e594f6772" - integrity sha512-XuoWx4KUXg7hNy5mRTy1i8c8p3K8boWg6UajbHpDXS5AlRVucNfTi5YxTtPBTBzegxAZpvuLfh3emXFt6ybUdA== +rc-image@~7.12.0: + version "7.12.0" + resolved "https://registry.yarnpkg.com/rc-image/-/rc-image-7.12.0.tgz#95e9314701e668217d113c1f29b4f01ac025cafe" + integrity sha512-cZ3HTyyckPnNnUb9/DRqduqzLfrQRyi+CdHjdqgsyDpI3Ln5UX1kXnAhPBSJj9pVRzwRFgqkN7p9b6HBDjmu/Q== dependencies: "@babel/runtime" "^7.11.2" "@rc-component/portal" "^1.0.2" @@ -10700,37 +10688,37 @@ rc-image@~7.11.1: rc-motion "^2.6.2" rc-util "^5.34.1" -rc-input-number@~9.4.0: - version "9.4.0" - resolved "https://registry.npmjs.org/rc-input-number/-/rc-input-number-9.4.0.tgz" - integrity sha512-Tiy4DcXcFXAf9wDhN8aUAyMeCLHJUHA/VA/t7Hj8ZEx5ETvxG7MArDOSE6psbiSCo+vJPm4E3fGN710ITVn6GA== +rc-input-number@~9.5.0: + version "9.5.0" + resolved "https://registry.yarnpkg.com/rc-input-number/-/rc-input-number-9.5.0.tgz#b47963d0f2cbd85ab2f1badfdc089a904c073f38" + integrity sha512-bKaEvB5tHebUURAEXw35LDcnRZLq3x1k7GxfAqBMzmpHkDGzjAtnUL8y4y5N15rIFIg5IJgwr211jInl3cipag== dependencies: "@babel/runtime" "^7.10.1" "@rc-component/mini-decimal" "^1.0.1" classnames "^2.2.5" - rc-input "~1.7.1" + rc-input "~1.8.0" rc-util "^5.40.1" -rc-input@~1.7.1, rc-input@~1.7.3: - version "1.7.3" - resolved "https://registry.yarnpkg.com/rc-input/-/rc-input-1.7.3.tgz#cb334a17b93ce985bceb243b4c111a5ed641e0e3" - integrity sha512-A5w4egJq8+4JzlQ55FfQjDnPvOaAbzwC3VLOAdOytyek3TboSOP9qxN+Gifup+shVXfvecBLBbWBpWxmk02SWQ== +rc-input@~1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/rc-input/-/rc-input-1.8.0.tgz#d2f4404befebf2fbdc28390d5494c302f74ae974" + integrity sha512-KXvaTbX+7ha8a/k+eg6SYRVERK0NddX8QX7a7AnRvUa/rEH0CNMlpcBzBkhI0wp2C8C4HlMoYl8TImSN+fuHKA== dependencies: "@babel/runtime" "^7.11.1" classnames "^2.2.1" rc-util "^5.18.1" -rc-mentions@~2.19.1: - version "2.19.1" - resolved "https://registry.npmjs.org/rc-mentions/-/rc-mentions-2.19.1.tgz" - integrity sha512-KK3bAc/bPFI993J3necmaMXD2reZTzytZdlTvkeBbp50IGH1BDPDvxLdHDUrpQx2b2TGaVJsn+86BvYa03kGqA== +rc-mentions@~2.20.0: + version "2.20.0" + resolved "https://registry.yarnpkg.com/rc-mentions/-/rc-mentions-2.20.0.tgz#3bbeac0352b02e0ce3e1244adb48701bb6903bf7" + integrity sha512-w8HCMZEh3f0nR8ZEd466ATqmXFCMGMN5UFCzEUL0bM/nGw/wOS2GgRzKBcm19K++jDyuWCOJOdgcKGXU3fXfbQ== dependencies: "@babel/runtime" "^7.22.5" "@rc-component/trigger" "^2.0.0" classnames "^2.2.6" - rc-input "~1.7.1" + rc-input "~1.8.0" rc-menu "~9.16.0" - rc-textarea "~1.9.0" + rc-textarea "~1.10.0" rc-util "^5.34.1" rc-menu@~9.16.0, rc-menu@~9.16.1: @@ -10754,10 +10742,10 @@ rc-motion@^2.0.0, rc-motion@^2.0.1, rc-motion@^2.3.0, rc-motion@^2.3.4, rc-motio classnames "^2.2.1" rc-util "^5.44.0" -rc-notification@~5.6.3: - version "5.6.3" - resolved "https://registry.npmjs.org/rc-notification/-/rc-notification-5.6.3.tgz" - integrity sha512-42szwnn8VYQoT6GnjO00i1iwqV9D1TTMvxObWsuLwgl0TsOokzhkYiufdtQBsJMFjJravS1hfDKVMHLKLcPE4g== +rc-notification@~5.6.4: + version "5.6.4" + resolved "https://registry.yarnpkg.com/rc-notification/-/rc-notification-5.6.4.tgz#ea89c39c13cd517fdfd97fe63f03376fabb78544" + integrity sha512-KcS4O6B4qzM3KH7lkwOB7ooLPZ4b6J+VMmQgT51VZCeEcmghdeR4IrMcFq0LG+RPdnbe/ArT086tGM8Snimgiw== dependencies: "@babel/runtime" "^7.10.1" classnames "2.x" @@ -10885,10 +10873,10 @@ rc-table@~7.50.4: rc-util "^5.44.3" rc-virtual-list "^3.14.2" -rc-tabs@~15.5.1: - version "15.5.1" - resolved "https://registry.npmjs.org/rc-tabs/-/rc-tabs-15.5.1.tgz" - integrity sha512-yiWivLAjEo5d1v2xlseB2dQocsOhkoVSfo1krS8v8r+02K+TBUjSjXIf7dgyVSxp6wRIPv5pMi5hanNUlQMgUA== +rc-tabs@~15.6.1: + version "15.6.1" + resolved "https://registry.yarnpkg.com/rc-tabs/-/rc-tabs-15.6.1.tgz#f0b6c65384dfa09a64eb539e86a0667c7a650708" + integrity sha512-/HzDV1VqOsUWyuC0c6AkxVYFjvx9+rFPKZ32ejxX0Uc7QCzcEjTA9/xMgv4HemPKwzBNX8KhGVbbumDjnj92aA== dependencies: "@babel/runtime" "^7.11.2" classnames "2.x" @@ -10898,14 +10886,14 @@ rc-tabs@~15.5.1: rc-resize-observer "^1.0.0" rc-util "^5.34.1" -rc-textarea@~1.9.0: - version "1.9.0" - resolved "https://registry.npmjs.org/rc-textarea/-/rc-textarea-1.9.0.tgz" - integrity sha512-dQW/Bc/MriPBTugj2Kx9PMS5eXCCGn2cxoIaichjbNvOiARlaHdI99j4DTxLl/V8+PIfW06uFy7kjfUIDDKyxQ== +rc-textarea@~1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/rc-textarea/-/rc-textarea-1.10.0.tgz#f8f962ef83be0b8e35db97cf03dbfb86ddd9c46c" + integrity sha512-ai9IkanNuyBS4x6sOL8qu/Ld40e6cEs6pgk93R+XLYg0mDSjNBGey6/ZpDs5+gNLD7urQ14po3V6Ck2dJLt9SA== dependencies: "@babel/runtime" "^7.10.1" classnames "^2.2.1" - rc-input "~1.7.1" + rc-input "~1.8.0" rc-resize-observer "^1.0.0" rc-util "^5.27.0" diff --git a/pyproject.toml b/pyproject.toml index dd28c805f68..687c0b56f57 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -44,7 +44,7 @@ dependencies = [ "cryptography>=42.0.4, <45.0.0", "deprecation>=2.1.0, <2.2.0", "flask>=2.2.5, <3.0.0", - "flask-appbuilder>=4.6.1, <5.0.0", + "flask-appbuilder>=4.6.3, <5.0.0", "flask-caching>=2.1.0, <3", "flask-compress>=1.13, <2.0", "flask-talisman>=1.0.0, <2.0", @@ -371,12 +371,14 @@ authorized_licenses = [ "apache software", "apache software, bsd", "bsd", + "bsd-3-clause", "isc license (iscl)", "isc license", "mit", "mozilla public license 2.0 (mpl 2.0)", "osi approved", "osi approved", + "psf-2.0", "python software foundation", "the unlicense (unlicense)", "the unlicense", diff --git a/requirements/base.txt b/requirements/base.txt index e3e88fd3fcb..9d280721a6d 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -82,7 +82,7 @@ cron-descriptor==1.4.5 # via apache-superset (pyproject.toml) croniter==6.0.0 # via apache-superset (pyproject.toml) -cryptography==44.0.2 +cryptography==44.0.3 # via # apache-superset (pyproject.toml) # paramiko @@ -118,7 +118,7 @@ flask==2.3.3 # flask-session # flask-sqlalchemy # flask-wtf -flask-appbuilder==4.6.1 +flask-appbuilder==4.6.3 # via apache-superset (pyproject.toml) flask-babel==2.0.0 # via flask-appbuilder @@ -161,13 +161,13 @@ greenlet==3.1.1 # sqlalchemy gunicorn==23.0.0 # via apache-superset (pyproject.toml) -h11==0.14.0 +h11==0.16.0 # via wsproto hashids==1.3.1 # via apache-superset (pyproject.toml) holidays==0.25 # via apache-superset (pyproject.toml) -humanize==4.12.2 +humanize==4.12.3 # via apache-superset (pyproject.toml) idna==3.10 # via @@ -202,7 +202,7 @@ mako==1.3.10 # via # apache-superset (pyproject.toml) # alembic -markdown==3.7 +markdown==3.8 # via apache-superset (pyproject.toml) markdown-it-py==3.0.0 # via rich @@ -236,7 +236,6 @@ numpy==1.26.4 # bottleneck # numexpr # pandas - # pyarrow odfpy==1.4.1 # via pandas openpyxl==3.1.5 @@ -374,7 +373,7 @@ sqlalchemy-utils==0.38.3 # via # apache-superset (pyproject.toml) # flask-appbuilder -sqlglot==26.16.2 +sqlglot==26.16.4 # via apache-superset (pyproject.toml) sqlparse==0.5.3 # via apache-superset (pyproject.toml) diff --git a/requirements/development.txt b/requirements/development.txt index 9e5f08a4790..aa5af1ba892 100644 --- a/requirements/development.txt +++ b/requirements/development.txt @@ -138,7 +138,7 @@ croniter==6.0.0 # via # -c requirements/base.txt # apache-superset -cryptography==44.0.2 +cryptography==44.0.3 # via # -c requirements/base.txt # apache-superset @@ -202,7 +202,7 @@ flask==2.3.3 # flask-sqlalchemy # flask-testing # flask-wtf -flask-appbuilder==4.6.1 +flask-appbuilder==4.6.3 # via # -c requirements/base.txt # apache-superset @@ -330,7 +330,7 @@ gunicorn==23.0.0 # via # -c requirements/base.txt # apache-superset -h11==0.14.0 +h11==0.16.0 # via # -c requirements/base.txt # wsproto @@ -343,7 +343,7 @@ holidays==0.25 # -c requirements/base.txt # apache-superset # prophet -humanize==4.12.2 +humanize==4.12.3 # via # -c requirements/base.txt # apache-superset @@ -415,7 +415,7 @@ mako==1.3.10 # -c requirements/base.txt # alembic # apache-superset -markdown==3.7 +markdown==3.8 # via # -c requirements/base.txt # apache-superset @@ -473,7 +473,6 @@ numpy==1.26.4 # pandas # pandas-gbq # prophet - # pyarrow oauthlib==3.2.2 # via requests-oauthlib odfpy==1.4.1 @@ -800,7 +799,7 @@ sqlalchemy-utils==0.38.3 # -c requirements/base.txt # apache-superset # flask-appbuilder -sqlglot==26.16.2 +sqlglot==26.16.4 # via # -c requirements/base.txt # apache-superset diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberPeriodOverPeriod/PopKPI.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberPeriodOverPeriod/PopKPI.tsx index 3746e1d01e9..53e33ada82c 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberPeriodOverPeriod/PopKPI.tsx +++ b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberPeriodOverPeriod/PopKPI.tsx @@ -36,13 +36,25 @@ import { } from './types'; import { useOverflowDetection } from './useOverflowDetection'; +const MetricNameText = styled.div<{ metricNameFontSize?: number }>` + ${({ theme, metricNameFontSize }) => ` + font-family: ${theme.typography.families.sansSerif}; + font-weight: ${theme.typography.weights.normal}; + font-size: ${metricNameFontSize || theme.typography.sizes.s * 2}px; + text-align: center; + margin-bottom: ${theme.gridUnit * 3}px; + `} +`; + const NumbersContainer = styled.div` display: flex; justify-content: center; align-items: center; flex-direction: column; width: 100%; + height: 100%; overflow: auto; + padding: 12px; `; const ComparisonValue = styled.div` @@ -73,6 +85,8 @@ export default function PopKPI(props: PopKPIProps) { prevNumber, valueDifference, percentDifferenceFormattedString, + metricName, + metricNameFontSize, headerFontSize, subheaderFontSize, comparisonColorEnabled, @@ -84,8 +98,8 @@ export default function PopKPI(props: PopKPIProps) { subtitle, subtitleFontSize, dashboardTimeRange, + showMetricName, } = props; - const [comparisonRange, setComparisonRange] = useState(''); useEffect(() => { @@ -258,9 +272,16 @@ export default function PopKPI(props: PopKPIProps) { width: fit-content; margin: auto; align-items: flex-start; + overflow: auto; ` } > + {showMetricName && metricName && ( + + {metricName} + + )} +
{bigNumber} {percentDifferenceNumber !== 0 && ( diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberPeriodOverPeriod/controlPanel.ts b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberPeriodOverPeriod/controlPanel.ts index 63c126216b2..57ac9dfdd82 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberPeriodOverPeriod/controlPanel.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberPeriodOverPeriod/controlPanel.ts @@ -28,6 +28,8 @@ import { subheaderFontSize, subtitleControl, subtitleFontSize, + showMetricNameControl, + metricNameFontSizeWithVisibility, } from '../sharedControls'; import { ColorSchemeEnum } from './types'; @@ -70,6 +72,8 @@ const config: ControlPanelConfig = { ], [subtitleControl], [subtitleFontSize], + [showMetricNameControl], + [metricNameFontSizeWithVisibility], [ { ...subheaderFontSize, diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberPeriodOverPeriod/transformProps.ts b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberPeriodOverPeriod/transformProps.ts index a40f18b24c3..70189f70faf 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberPeriodOverPeriod/transformProps.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberPeriodOverPeriod/transformProps.ts @@ -26,7 +26,13 @@ import { SimpleAdhocFilter, ensureIsArray, } from '@superset-ui/core'; -import { getComparisonFontSize, getHeaderFontSize } from './utils'; +import { + getComparisonFontSize, + getHeaderFontSize, + getMetricNameFontSize, +} from './utils'; + +import { getOriginalLabel } from '../utils'; dayjs.extend(utc); @@ -83,6 +89,7 @@ export default function transformProps(chartProps: ChartProps) { headerFontSize, headerText, metric, + metricNameFontSize, yAxisFormat, currencyFormat, subheaderFontSize, @@ -91,11 +98,14 @@ export default function transformProps(chartProps: ChartProps) { percentDifferenceFormat, subtitle = '', subtitleFontSize, - columnConfig, + columnConfig = {}, } = formData; const { data: dataA = [] } = queriesData[0]; const data = dataA; const metricName = metric ? getMetricLabel(metric) : ''; + const metrics = chartProps.datasource?.metrics || []; + const originalLabel = getOriginalLabel(metric, metrics); + const showMetricName = chartProps.rawFormData?.show_metric_name ?? false; const timeComparison = ensureIsArray(chartProps.rawFormData?.time_compare)[0]; const startDateOffset = chartProps.rawFormData?.start_date_offset; const currentTimeRangeFilter = chartProps.rawFormData?.adhoc_filters?.filter( @@ -179,7 +189,7 @@ export default function transformProps(chartProps: ChartProps) { width, height, data, - metricName, + metricName: originalLabel, bigNumber, prevNumber, valueDifference, @@ -187,6 +197,8 @@ export default function transformProps(chartProps: ChartProps) { boldText, subtitle, subtitleFontSize, + showMetricName, + metricNameFontSize: getMetricNameFontSize(metricNameFontSize), headerFontSize: getHeaderFontSize(headerFontSize), subheaderFontSize: getComparisonFontSize(subheaderFontSize), headerText, diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberPeriodOverPeriod/types.ts b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberPeriodOverPeriod/types.ts index e03eaca3243..d2933f236d1 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberPeriodOverPeriod/types.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberPeriodOverPeriod/types.ts @@ -62,6 +62,8 @@ export type PopKPIProps = PopKPIStylesProps & data: TimeseriesDataRecord[]; metrics: Metric[]; metricName: string; + metricNameFontSize?: number; + showMetricName: boolean; bigNumber: string; prevNumber: string; subtitle?: string; diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberPeriodOverPeriod/utils.ts b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberPeriodOverPeriod/utils.ts index 4fb45ab88ac..9b658593298 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberPeriodOverPeriod/utils.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberPeriodOverPeriod/utils.ts @@ -16,10 +16,19 @@ * specific language governing permissions and limitations * under the License. */ -import { headerFontSize, subheaderFontSize } from '../sharedControls'; +import { + headerFontSize, + subheaderFontSize, + metricNameFontSize, +} from '../sharedControls'; const headerFontSizes = [16, 20, 30, 48, 60]; -const comparisonFontSizes = [16, 20, 26, 32, 40]; +const sharedFontSizes = [16, 20, 26, 32, 40]; + +const metricNameProportionValues = + metricNameFontSize.config.options.map( + (option: { label: string; value: number }) => option.value, + ) ?? []; const headerProportionValues = headerFontSize.config.options.map( @@ -40,6 +49,10 @@ const getFontSizeMapping = ( return acc; }, {}); +const metricNameFontSizesMapping = getFontSizeMapping( + metricNameProportionValues, + sharedFontSizes, +); const headerFontSizesMapping = getFontSizeMapping( headerProportionValues, headerFontSizes, @@ -47,13 +60,17 @@ const headerFontSizesMapping = getFontSizeMapping( const comparisonFontSizesMapping = getFontSizeMapping( subheaderProportionValues, - comparisonFontSizes, + sharedFontSizes, ); +export const getMetricNameFontSize = (proportionValue: number) => + metricNameFontSizesMapping[proportionValue] ?? + sharedFontSizes[sharedFontSizes.length - 1]; + export const getHeaderFontSize = (proportionValue: number) => headerFontSizesMapping[proportionValue] ?? headerFontSizes[headerFontSizes.length - 1]; export const getComparisonFontSize = (proportionValue: number) => comparisonFontSizesMapping[proportionValue] ?? - comparisonFontSizes[comparisonFontSizes.length - 1]; + sharedFontSizes[sharedFontSizes.length - 1]; diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/controlPanel.ts b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/controlPanel.ts index f9b53ccaacf..33a2ba89df6 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/controlPanel.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/controlPanel.ts @@ -28,6 +28,8 @@ import { headerFontSize, subtitleFontSize, subtitleControl, + showMetricNameControl, + metricNameFontSizeWithVisibility, } from '../sharedControls'; export default { @@ -44,6 +46,8 @@ export default { [headerFontSize], [subtitleControl], [subtitleFontSize], + [showMetricNameControl], + [metricNameFontSizeWithVisibility], ['y_axis_format'], ['currency_format'], [ diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/transformProps.test.ts b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/transformProps.test.ts index e34e352683d..aea95effeb6 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/transformProps.test.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/transformProps.test.ts @@ -36,6 +36,7 @@ jest.mock('@superset-ui/core', () => ({ jest.mock('../utils', () => ({ getDateFormatter: jest.fn(() => (v: any) => `${v}pm`), parseMetricValue: jest.fn(val => Number(val)), + getOriginalLabel: jest.fn((metric, metrics) => metric), })); describe('BigNumberTotal transformProps', () => { diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/transformProps.ts b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/transformProps.ts index c0f9b2baeb3..fabac86ef0b 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/transformProps.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/transformProps.ts @@ -29,7 +29,7 @@ import { getValueFormatter, } from '@superset-ui/core'; import { BigNumberTotalChartProps, BigNumberVizProps } from '../types'; -import { getDateFormatter, parseMetricValue } from '../utils'; +import { getDateFormatter, getOriginalLabel, parseMetricValue } from '../utils'; import { Refs } from '../../types'; export default function transformProps( @@ -45,6 +45,7 @@ export default function transformProps( datasource: { currencyFormats = {}, columnFormats = {} }, } = chartProps; const { + metricNameFontSize, headerFontSize, metric = 'value', subtitle, @@ -58,9 +59,12 @@ export default function transformProps( subheaderFontSize, } = formData; const refs: Refs = {}; - const { data = [], coltypes = [] } = queriesData[0]; + const { data = [], coltypes = [] } = queriesData[0] || {}; const granularity = extractTimegrain(rawFormData as QueryFormData); + const metrics = chartProps.datasource?.metrics || []; + const originalLabel = getOriginalLabel(metric, metrics); const metricName = getMetricLabel(metric); + const showMetricName = chartProps.rawFormData?.show_metric_name ?? false; const formattedSubtitle = subtitle?.trim() ? subtitle : subheader || ''; const formattedSubtitleFontSize = subtitle?.trim() ? (subtitleFontSize ?? 1) @@ -103,7 +107,6 @@ export default function transformProps( const colorThresholdFormatters = getColorFormatters(conditionalFormatting, data, false) ?? defaultColorFormatters; - return { width, height, @@ -116,5 +119,8 @@ export default function transformProps( onContextMenu, refs, colorThresholdFormatters, + metricName: originalLabel, + showMetricName, + metricNameFontSize, }; } diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberViz.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberViz.tsx index b6209a227e6..d6f8f364d8e 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberViz.tsx +++ b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberViz.tsx @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -import { PureComponent, MouseEvent } from 'react'; +import { PureComponent, MouseEvent, createRef } from 'react'; import { t, getNumberFormatter, @@ -36,6 +36,7 @@ const defaultNumberFormatter = getNumberFormatter(); const PROPORTION = { // text size: proportion of the chart container sans trendline + METRIC_NAME: 0.125, KICKER: 0.1, HEADER: 0.3, SUBHEADER: 0.125, @@ -43,13 +44,20 @@ const PROPORTION = { TRENDLINE: 0.3, }; -class BigNumberVis extends PureComponent { +type BigNumberVisState = { + elementsRendered: boolean; + recalculateTrigger: boolean; +}; + +class BigNumberVis extends PureComponent { static defaultProps = { className: '', headerFormatter: defaultNumberFormatter, formatTime: getTimeFormatter(SMART_DATE_VERBOSE_ID), headerFontSize: PROPORTION.HEADER, kickerFontSize: PROPORTION.KICKER, + metricNameFontSize: PROPORTION.METRIC_NAME, + showMetricName: true, mainColor: BRAND_COLOR, showTimestamp: false, showTrendLine: false, @@ -59,6 +67,40 @@ class BigNumberVis extends PureComponent { timeRangeFixed: false, }; + // Create refs for each component to measure heights + metricNameRef = createRef(); + + kickerRef = createRef(); + + headerRef = createRef(); + + subheaderRef = createRef(); + + subtitleRef = createRef(); + + state = { + elementsRendered: false, + recalculateTrigger: false, + }; + + componentDidMount() { + // Wait for elements to render and then calculate heights + setTimeout(() => { + this.setState({ elementsRendered: true }); + }, 0); + } + + componentDidUpdate(prevProps: BigNumberVizProps) { + if ( + prevProps.height !== this.props.height || + prevProps.showTrendLine !== this.props.showTrendLine + ) { + this.setState(prevState => ({ + recalculateTrigger: !prevState.recalculateTrigger, + })); + } + } + getClassName() { const { className, showTrendLine, bigNumberFallback } = this.props; const names = `superset-legacy-chart-big-number ${className} ${ @@ -93,6 +135,37 @@ class BigNumberVis extends PureComponent { ); } + renderMetricName(maxHeight: number) { + const { metricName, width, showMetricName } = this.props; + if (!showMetricName || !metricName) return null; + + const text = metricName; + + const container = this.createTemporaryContainer(); + document.body.append(container); + const fontSize = computeMaxFontSize({ + text, + maxWidth: width, + maxHeight, + className: 'metric-name', + container, + }); + container.remove(); + + return ( +
+ {text} +
+ ); + } + renderKicker(maxHeight: number) { const { timestamp, showTimestamp, formatTime, width } = this.props; if ( @@ -119,6 +192,7 @@ class BigNumberVis extends PureComponent { return (
{ return (
{ return (
{ return ( <>
{ ); } + getTotalElementsHeight() { + const marginPerElement = 8; // theme.gridUnit = 4, so margin-bottom = 8px + + const refs = [ + this.metricNameRef, + this.kickerRef, + this.headerRef, + this.subheaderRef, + this.subtitleRef, + ]; + + // Filter refs to only those with a current element + const visibleRefs = refs.filter(ref => ref.current); + + const totalHeight = visibleRefs.reduce((sum, ref, index) => { + const height = ref.current?.offsetHeight || 0; + const margin = index < visibleRefs.length - 1 ? marginPerElement : 0; + return sum + height + margin; + }, 0); + + return totalHeight; + } + + shouldApplyOverflow(availableHeight: number) { + if (!this.state.elementsRendered) return false; + const totalHeight = this.getTotalElementsHeight(); + return totalHeight > availableHeight; + } + render() { const { showTrendLine, @@ -325,6 +431,7 @@ class BigNumberVis extends PureComponent { kickerFontSize, headerFontSize, subtitleFontSize, + metricNameFontSize, subheaderFontSize, } = this.props; const className = this.getClassName(); @@ -332,11 +439,31 @@ class BigNumberVis extends PureComponent { if (showTrendLine) { const chartHeight = Math.floor(PROPORTION.TRENDLINE * height); const allTextHeight = height - chartHeight; + const shouldApplyOverflow = this.shouldApplyOverflow(allTextHeight); return (
-
+
{this.renderFallbackWarning()} + {this.renderMetricName( + Math.ceil( + (metricNameFontSize || 0) * (1 - PROPORTION.TRENDLINE) * height, + ), + )} {this.renderKicker( Math.ceil( (kickerFontSize || 0) * (1 - PROPORTION.TRENDLINE) * height, @@ -358,16 +485,33 @@ class BigNumberVis extends PureComponent {
); } - + const shouldApplyOverflow = this.shouldApplyOverflow(height); return ( -
- {this.renderFallbackWarning()} - {this.renderKicker((kickerFontSize || 0) * height)} - {this.renderHeader(Math.ceil(headerFontSize * height))} - {this.rendermetricComparisonSummary( - Math.ceil(subheaderFontSize * height), - )} - {this.renderSubtitle(Math.ceil(subtitleFontSize * height))} +
+
+ {this.renderFallbackWarning()} + {this.renderMetricName((metricNameFontSize || 0) * height)} + {this.renderKicker((kickerFontSize || 0) * height)} + {this.renderHeader(Math.ceil(headerFontSize * height))} + {this.rendermetricComparisonSummary( + Math.ceil(subheaderFontSize * height), + )} + {this.renderSubtitle(Math.ceil(subtitleFontSize * height))} +
); } @@ -402,7 +546,12 @@ export default styled(BigNumberVis)` .kicker { line-height: 1em; - padding-bottom: 2em; + margin-bottom: ${theme.gridUnit * 2}px; + } + + .metric-name { + line-height: 1em; + margin-bottom: ${theme.gridUnit * 2}px; } .header-line { @@ -418,12 +567,12 @@ export default styled(BigNumberVis)` .subheader-line { line-height: 1em; - padding-bottom: 0; + margin-bottom: ${theme.gridUnit * 2}px; } .subtitle-line { line-height: 1em; - padding-bottom: 0; + margin-bottom: ${theme.gridUnit * 2}px; } &.is-fallback-value { diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx index 7f04a2efebd..153c76e4212 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx +++ b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx @@ -31,6 +31,8 @@ import { subheaderFontSize, subtitleFontSize, subtitleControl, + showMetricNameControl, + metricNameFontSizeWithVisibility, } from '../sharedControls'; const config: ControlPanelConfig = { @@ -141,6 +143,8 @@ const config: ControlPanelConfig = { [subheaderFontSize], [subtitleControl], [subtitleFontSize], + [showMetricNameControl], + [metricNameFontSizeWithVisibility], ['y_axis_format'], ['currency_format'], [ diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/transformProps.test.ts b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/transformProps.test.ts index 069b25722dc..c07a8b9477b 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/transformProps.test.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/transformProps.test.ts @@ -39,6 +39,7 @@ jest.mock('@superset-ui/core', () => ({ jest.mock('../utils', () => ({ getDateFormatter: jest.fn(() => (v: any) => `${v}pm`), parseMetricValue: jest.fn(val => Number(val)), + getOriginalLabel: jest.fn((metric, metrics) => metric), })); jest.mock('../../utils/tooltip', () => ({ diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/transformProps.ts b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/transformProps.ts index 3d933208fd7..79c5b992b34 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/transformProps.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/transformProps.ts @@ -35,7 +35,7 @@ import { BigNumberWithTrendlineChartProps, TimeSeriesDatum, } from '../types'; -import { getDateFormatter, parseMetricValue } from '../utils'; +import { getDateFormatter, parseMetricValue, getOriginalLabel } from '../utils'; import { getDefaultTooltip } from '../../utils/tooltip'; import { Refs } from '../../types'; @@ -62,6 +62,7 @@ export default function transformProps( compareLag: compareLag_, compareSuffix = '', timeFormat, + metricNameFontSize, headerFontSize, metric = 'value', showTimestamp, @@ -96,6 +97,9 @@ export default function transformProps( const aggregatedData = hasAggregatedData ? aggregatedQueryData.data[0] : null; const refs: Refs = {}; const metricName = getMetricLabel(metric); + const metrics = chartProps.datasource?.metrics || []; + const originalLabel = getOriginalLabel(metric, metrics); + const showMetricName = chartProps.rawFormData?.show_metric_name ?? false; const compareLag = Number(compareLag_) || 0; let formattedSubheader = subheader; @@ -303,6 +307,9 @@ export default function transformProps( headerFormatter, formatTime, formData, + metricName: originalLabel, + showMetricName, + metricNameFontSize, headerFontSize, subtitleFontSize, subtitle, diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/sharedControls.ts b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/sharedControls.ts index 09766ed4bf1..9610497382d 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/sharedControls.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/sharedControls.ts @@ -21,106 +21,68 @@ import { t } from '@superset-ui/core'; import { CustomControlItem } from '@superset-ui/chart-controls'; -export const headerFontSize: CustomControlItem = { - name: 'header_font_size', - config: { - type: 'SelectControl', - label: t('Big Number Font Size'), - renderTrigger: true, - clearable: false, - default: 0.4, - // Values represent the percentage of space a header should take - options: [ - { - label: t('Tiny'), - value: 0.2, - }, - { - label: t('Small'), - value: 0.3, - }, - { - label: t('Normal'), - value: 0.4, - }, - { - label: t('Large'), - value: 0.5, - }, - { - label: t('Huge'), - value: 0.6, - }, - ], - }, -}; +const FONT_SIZE_OPTIONS_SMALL = [ + { label: t('Tiny'), value: 0.125 }, + { label: t('Small'), value: 0.15 }, + { label: t('Normal'), value: 0.2 }, + { label: t('Large'), value: 0.3 }, + { label: t('Huge'), value: 0.4 }, +]; -export const subtitleFontSize: CustomControlItem = { - name: 'subtitle_font_size', - config: { - type: 'SelectControl', - label: t('Subtitle Font Size'), - renderTrigger: true, - clearable: false, - default: 0.15, - // Values represent the percentage of space a subtitle should take - options: [ - { - label: t('Tiny'), - value: 0.125, - }, - { - label: t('Small'), - value: 0.15, - }, - { - label: t('Normal'), - value: 0.2, - }, - { - label: t('Large'), - value: 0.3, - }, - { - label: t('Huge'), - value: 0.4, - }, - ], - }, -}; -export const subheaderFontSize: CustomControlItem = { - name: 'subheader_font_size', - config: { - type: 'SelectControl', - label: t('Subheader Font Size'), - renderTrigger: true, - clearable: false, - default: 0.15, - // Values represent the percentage of space a subheader should take - options: [ - { - label: t('Tiny'), - value: 0.125, - }, - { - label: t('Small'), - value: 0.15, - }, - { - label: t('Normal'), - value: 0.2, - }, - { - label: t('Large'), - value: 0.3, - }, - { - label: t('Huge'), - value: 0.4, - }, - ], - }, -}; +const FONT_SIZE_OPTIONS_LARGE = [ + { label: t('Tiny'), value: 0.2 }, + { label: t('Small'), value: 0.3 }, + { label: t('Normal'), value: 0.4 }, + { label: t('Large'), value: 0.5 }, + { label: t('Huge'), value: 0.6 }, +]; + +function makeFontSizeControl( + name: string, + label: string, + defaultValue: number, + options: { label: string; value: number }[], +): CustomControlItem { + return { + name, + config: { + type: 'SelectControl', + label: t(label), + renderTrigger: true, + clearable: false, + default: defaultValue, + options, + }, + }; +} + +export const headerFontSize = makeFontSizeControl( + 'header_font_size', + 'Big Number Font Size', + 0.4, + FONT_SIZE_OPTIONS_LARGE, +); + +export const subtitleFontSize = makeFontSizeControl( + 'subtitle_font_size', + 'Subtitle Font Size', + 0.15, + FONT_SIZE_OPTIONS_SMALL, +); + +export const subheaderFontSize = makeFontSizeControl( + 'subheader_font_size', + 'Subheader Font Size', + 0.15, + FONT_SIZE_OPTIONS_SMALL, +); + +export const metricNameFontSize = makeFontSizeControl( + 'metric_name_font_size', + 'Metric Name Font Size', + 0.15, + FONT_SIZE_OPTIONS_SMALL, +); export const subtitleControl: CustomControlItem = { name: 'subtitle', @@ -131,3 +93,23 @@ export const subtitleControl: CustomControlItem = { description: t('Description text that shows up below your Big Number'), }, }; + +export const showMetricNameControl: CustomControlItem = { + name: 'show_metric_name', + config: { + type: 'CheckboxControl', + label: t('Show Metric Name'), + renderTrigger: true, + default: false, + description: t('Whether to display the metric name'), + }, +}; + +export const metricNameFontSizeWithVisibility: CustomControlItem = { + ...metricNameFontSize, + config: { + ...metricNameFontSize.config, + visibility: ({ controls }) => controls?.show_metric_name?.value === true, + resetOnHide: false, + }, +}; diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/types.ts b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/types.ts index 44abef0c789..d2bec7d68e6 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/types.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/types.ts @@ -75,6 +75,10 @@ export type BigNumberVizProps = { bigNumberFallback?: TimeSeriesDatum; headerFormatter: ValueFormatter | TimeFormatter; formatTime?: TimeFormatter; + metricName?: string; + friendlyMetricName?: string; + metricNameFontSize?: number; + showMetricName?: boolean; headerFontSize: number; kickerFontSize?: number; subheader?: string; diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/utils.ts b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/utils.ts index a25ec74321e..ecad4d9ed96 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/utils.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/utils.ts @@ -22,6 +22,10 @@ import utc from 'dayjs/plugin/utc'; import { getTimeFormatter, getTimeFormatterForGranularity, + isAdhocMetricSimple, + isSavedMetric, + Metric, + QueryFormMetric, SMART_DATE_ID, TimeGranularity, } from '@superset-ui/core'; @@ -47,3 +51,43 @@ export const getDateFormatter = ( timeFormat === SMART_DATE_ID ? getTimeFormatterForGranularity(granularity) : getTimeFormatter(timeFormat ?? fallbackFormat); + +export function getOriginalLabel( + metric: QueryFormMetric, + metrics: Metric[] = [], +): string { + const metricLabel = typeof metric === 'string' ? metric : metric.label || ''; + + if (isSavedMetric(metric)) { + const metricEntry = metrics.find(m => m.metric_name === metric); + return ( + metricEntry?.verbose_name || + metricEntry?.metric_name || + metric || + 'Unknown Metric' + ); + } + + if (isAdhocMetricSimple(metric)) { + const column = metric.column || {}; + const columnName = column.column_name || 'unknown_column'; + const verboseName = column.verbose_name || columnName; + const aggregate = metric.aggregate || 'UNKNOWN'; + return metric.hasCustomLabel && metric.label + ? metric.label + : `${aggregate}(${verboseName})`; + } + + if ( + typeof metric === 'object' && + 'expressionType' in metric && + metric.expressionType === 'SQL' && + 'sqlExpression' in metric + ) { + return metric.hasCustomLabel && metric.label + ? metric.label + : metricLabel || 'Custom Metric'; + } + + return metricLabel || 'Unknown Metric'; +} diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterControl.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterControl.tsx index bf3af0e27fb..9666040f170 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterControl.tsx +++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterControl.tsx @@ -128,6 +128,14 @@ const VerticalFormItem = styled(StyledFormItem)<{ width: 140px; `} } + + .select-bulk-actions { + ${({ inverseSelection }) => + inverseSelection && + ` + flex-direction: column; + `} + } `; const HorizontalFormItem = styled(StyledFormItem)<{ @@ -166,6 +174,10 @@ const HorizontalFormItem = styled(StyledFormItem)<{ width: 164px; `} } + + .select-bulk-actions { + flex-direction: column; + } `; const HorizontalOverflowFormItem = VerticalFormItem; diff --git a/superset-frontend/src/dataMask/reducer.ts b/superset-frontend/src/dataMask/reducer.ts index c13b23fa433..bb5c3a5d1c3 100644 --- a/superset-frontend/src/dataMask/reducer.ts +++ b/superset-frontend/src/dataMask/reducer.ts @@ -27,10 +27,13 @@ import { Filter, FilterConfiguration, Filters, + FilterState, + ExtraFormData, } from '@superset-ui/core'; import { NATIVE_FILTER_PREFIX } from 'src/dashboard/components/nativeFilters/FiltersConfigModal/utils'; import { HYDRATE_DASHBOARD } from 'src/dashboard/actions/hydrate'; import { SaveFilterChangesType } from 'src/dashboard/components/nativeFilters/FiltersConfigModal/types'; +import { isEqual } from 'lodash'; import { AnyDataMaskAction, CLEAR_DATA_MASK_STATE, @@ -39,6 +42,11 @@ import { } from './actions'; import { areObjectsEqual } from '../reduxUtils'; +type FilterWithExtaFromData = Filter & { + extraFormData?: ExtraFormData; + filterState?: FilterState; +}; + export function getInitialDataMask( id?: string | number, moreProps: DataMask = {}, @@ -106,10 +114,27 @@ function updateDataMaskForFilterChanges( }); filterChanges.modified.forEach((filter: Filter) => { + const existingFilter = draftDataMask[filter.id] as FilterWithExtaFromData; + + // Check if targets are equal + const areTargetsEqual = isEqual(existingFilter?.targets, filter?.targets); + + // Preserve state only if filter exists, has enableEmptyFilter=true and targets match + const shouldPreserveState = + existingFilter && + areTargetsEqual && + (filter.controlValues?.enableEmptyFilter || + filter.controlValues?.defaultToFirstItem); + mergedDataMask[filter.id] = { ...getInitialDataMask(filter.id), ...filter.defaultDataMask, ...filter, + // Preserve extraFormData and filterState if conditions match + ...(shouldPreserveState && { + extraFormData: existingFilter.extraFormData, + filterState: existingFilter.filterState, + }), }; }); diff --git a/superset-frontend/src/filters/components/Select/SelectFilterPlugin.tsx b/superset-frontend/src/filters/components/Select/SelectFilterPlugin.tsx index a51d55623f8..c59af32625c 100644 --- a/superset-frontend/src/filters/components/Select/SelectFilterPlugin.tsx +++ b/superset-frontend/src/filters/components/Select/SelectFilterPlugin.tsx @@ -17,7 +17,7 @@ * under the License. */ /* eslint-disable no-param-reassign */ -import { useCallback, useEffect, useMemo, useState } from 'react'; +import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { AppSection, DataMask, @@ -80,7 +80,10 @@ function reducer(draft: DataMask, action: DataMaskAction) { } } -const StyledSpace = styled(Space)<{ $inverseSelection: boolean }>` +const StyledSpace = styled(Space)<{ + inverseSelection: boolean; + appSection: AppSection; +}>` display: flex; align-items: center; width: 100%; @@ -98,6 +101,9 @@ const StyledSpace = styled(Space)<{ $inverseSelection: boolean }>` } `; +// Keep track of orientation changes outside component with filter ID +const orientationMap = new Map(); + export default function PluginFilterSelect(props: PluginFilterSelectProps) { const { coltypeMap, @@ -154,6 +160,30 @@ export default function PluginFilterSelect(props: PluginFilterSelectProps) { : filterState?.excludeFilterValues, ); + const prevExcludeFilterValues = useRef(excludeFilterValues); + + const hasOnlyOrientationChanged = useRef(false); + + useEffect(() => { + // Get previous orientation for this specific filter + const previousOrientation = orientationMap.get(formData.nativeFilterId); + + // Check if only orientation changed for this filter + if ( + previousOrientation !== undefined && + previousOrientation !== filterBarOrientation + ) { + hasOnlyOrientationChanged.current = true; + } else { + hasOnlyOrientationChanged.current = false; + } + + // Update orientation for this filter + if (filterBarOrientation) { + orientationMap.set(formData.nativeFilterId, filterBarOrientation); + } + }, [filterBarOrientation]); + const updateDataMask = useCallback( (values: SelectValue) => { const emptyFilter = @@ -283,35 +313,44 @@ export default function PluginFilterSelect(props: PluginFilterSelectProps) { [formData.sortAscending], ); + // Use effect for initialisation for filter plugin + // this should run only once when filter is configured & saved + // & shouldnt run when the component is remounted on change of + // orientation of filter bar useEffect(() => { - if (defaultToFirstItem && filterState.value === undefined) { - // initialize to first value if set to default to first item + // Skip if only orientation changed + if (hasOnlyOrientationChanged.current) { + return; + } + + // Case 1: Handle disabled state first + if (isDisabled) { + updateDataMask(null); + return; + } + + // Case 2: Handle the default to first Value case + if (defaultToFirstItem) { + // Set to first item if defaultToFirstItem is true const firstItem: SelectValue = data[0] ? (groupby.map(col => data[0][col]) as string[]) : null; - // firstItem[0] !== undefined for a case when groupby changed but new data still not fetched - // TODO: still need repopulate default value in config modal when column changed if (firstItem?.[0] !== undefined) { updateDataMask(firstItem); } - } else if (isDisabled) { - // empty selection if filter is disabled - updateDataMask(null); - } else { - // reset data mask based on filter state - updateDataMask(filterState.value); + } else if (formData?.defaultValue) { + // Case 3 : Handle defalut value case + updateDataMask(formData.defaultValue); } }, [ - col, isDisabled, - defaultToFirstItem, enableEmptyFilter, - inverseSelection, - excludeFilterValues, - updateDataMask, + defaultToFirstItem, + formData?.defaultValue, data, groupby, - JSON.stringify(filterState.value), + col, + inverseSelection, ]); useEffect(() => { @@ -319,23 +358,26 @@ export default function PluginFilterSelect(props: PluginFilterSelectProps) { }, [JSON.stringify(dataMask)]); useEffect(() => { - dispatchDataMask({ - type: 'filterState', - extraFormData: getSelectExtraFormData( - col, - filterState.value, - !filterState.value?.length, - excludeFilterValues && inverseSelection, - ), - filterState: { - ...(filterState as { - value: SelectValue; - label?: string; - excludeFilterValues?: boolean; - }), - excludeFilterValues, - }, - }); + if (prevExcludeFilterValues.current !== excludeFilterValues) { + dispatchDataMask({ + type: 'filterState', + extraFormData: getSelectExtraFormData( + col, + filterState.value, + !filterState.value?.length, + excludeFilterValues && inverseSelection, + ), + filterState: { + ...(filterState as { + value: SelectValue; + label?: string; + excludeFilterValues?: boolean; + }), + excludeFilterValues, + }, + }); + prevExcludeFilterValues.current = excludeFilterValues; + } }, [excludeFilterValues]); const handleExclusionToggle = (value: string) => { @@ -348,8 +390,11 @@ export default function PluginFilterSelect(props: PluginFilterSelectProps) { validateStatus={filterState.validateStatus} extra={formItemExtra} > - - {inverseSelection && ( + + {appSection !== AppSection.FilterConfigModal && inverseSelection && (