diff --git a/UPDATING.md b/UPDATING.md index 4b4d9f0022c46..d7868622f7c51 100644 --- a/UPDATING.md +++ b/UPDATING.md @@ -79,6 +79,8 @@ assists people when migrating to a new version. ### Other +- [24982](https://github.com/apache/superset/pull/24982): By default, physical datasets on Oracle-like dialects like Snowflake will now use denormalized column names. However, existing datasets won't be affected. To change this behavior, the "Advanced" section on the dataset modal has a "Normalize column names" flag which can be changed to change this behavior. + ## 2.1.0 - [22809](https://github.com/apache/superset/pull/22809): Migrated endpoint `/superset/sql_json` and `/superset/results/` to `/api/v1/sqllab/execute/` and `/api/v1/sqllab/results/` respectively. Corresponding permissions are `can sql_json on Superset` to `can execute on SQLLab`, `can results on Superset` to `can results on SQLLab`. Make sure you add/replace the necessary permissions on any custom roles you may have. diff --git a/docker-compose.yml b/docker-compose.yml index 2b8ad0cc47095..dc9f9d5589fa0 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -47,6 +47,7 @@ services: - "127.0.0.1:5432:5432" volumes: - db_home:/var/lib/postgresql/data + - ./docker/docker-entrypoint-initdb.d:/docker-entrypoint-initdb.d superset: env_file: docker/.env diff --git a/docker/.env b/docker/.env index a2e9faeacd86d..25bdac0ab7fa0 100644 --- a/docker/.env +++ b/docker/.env @@ -22,6 +22,12 @@ DATABASE_HOST=db DATABASE_PASSWORD=superset DATABASE_USER=superset +EXAMPLES_DB=examples +EXAMPLES_HOST=db +EXAMPLES_USER=examples +EXAMPLES_PASSWORD=examples +EXAMPLES_PORT=5432 + # database engine specific environment variables # change the below if you prefer another database engine DATABASE_PORT=5432 diff --git a/docker/docker-entrypoint-initdb.d/examples-init.sh b/docker/docker-entrypoint-initdb.d/examples-init.sh new file mode 100755 index 0000000000000..9a729078239a9 --- /dev/null +++ b/docker/docker-entrypoint-initdb.d/examples-init.sh @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------------ +# Creates the examples database and repective user. This database location +# and access credentials are defined on the environment variables +# ------------------------------------------------------------------------ +set -e + +psql -v ON_ERROR_STOP=1 --username "${POSTGRES_USER}" <<-EOSQL + CREATE USER ${EXAMPLES_USER} WITH PASSWORD '${EXAMPLES_PASSWORD}'; + CREATE DATABASE ${EXAMPLES_DB}; + GRANT ALL PRIVILEGES ON DATABASE ${EXAMPLES_DB} TO ${EXAMPLES_USER}; +EOSQL + +psql -v ON_ERROR_STOP=1 --username "${POSTGRES_USER}" -d "${EXAMPLES_DB}" <<-EOSQL + GRANT ALL ON SCHEMA public TO ${EXAMPLES_USER}; +EOSQL diff --git a/docker/pythonpath_dev/superset_config.py b/docker/pythonpath_dev/superset_config.py index 199e79f66e6d7..2e3c1fdda4597 100644 --- a/docker/pythonpath_dev/superset_config.py +++ b/docker/pythonpath_dev/superset_config.py @@ -51,14 +51,24 @@ def get_env_variable(var_name: str, default: Optional[str] = None) -> str: DATABASE_PORT = get_env_variable("DATABASE_PORT") DATABASE_DB = get_env_variable("DATABASE_DB") +EXAMPLES_USER = get_env_variable("EXAMPLES_USER") +EXAMPLES_PASSWORD = get_env_variable("EXAMPLES_PASSWORD") +EXAMPLES_HOST = get_env_variable("EXAMPLES_HOST") +EXAMPLES_PORT = get_env_variable("EXAMPLES_PORT") +EXAMPLES_DB = get_env_variable("EXAMPLES_DB") + + # The SQLAlchemy connection string. -SQLALCHEMY_DATABASE_URI = "{}://{}:{}@{}:{}/{}".format( - DATABASE_DIALECT, - DATABASE_USER, - DATABASE_PASSWORD, - DATABASE_HOST, - DATABASE_PORT, - DATABASE_DB, +SQLALCHEMY_DATABASE_URI = ( + f"{DATABASE_DIALECT}://" + f"{DATABASE_USER}:{DATABASE_PASSWORD}@" + f"{DATABASE_HOST}:{DATABASE_PORT}/{DATABASE_DB}" +) + +SQLALCHEMY_EXAMPLES_URI = ( + f"{DATABASE_DIALECT}://" + f"{EXAMPLES_USER}:{EXAMPLES_PASSWORD}@" + f"{EXAMPLES_HOST}:{EXAMPLES_PORT}/{EXAMPLES_DB}" ) REDIS_HOST = get_env_variable("REDIS_HOST") diff --git a/docs/static/resources/openapi.json b/docs/static/resources/openapi.json index 94dca800c3ab4..6ad0be5756701 100644 --- a/docs/static/resources/openapi.json +++ b/docs/static/resources/openapi.json @@ -124,7 +124,11 @@ "type": "object" }, "level": { - "enum": ["info", "warning", "error"], + "enum": [ + "info", + "warning", + "error" + ], "type": "string" }, "message": { @@ -206,7 +210,12 @@ "properties": { "annotationType": { "description": "Type of annotation layer", - "enum": ["FORMULA", "INTERVAL", "EVENT", "TIME_SERIES"], + "enum": [ + "FORMULA", + "INTERVAL", + "EVENT", + "TIME_SERIES" + ], "type": "string" }, "color": { @@ -237,7 +246,12 @@ }, "opacity": { "description": "Opacity of layer", - "enum": ["", "opacityLow", "opacityMedium", "opacityHigh"], + "enum": [ + "", + "opacityLow", + "opacityMedium", + "opacityHigh" + ], "nullable": true, "type": "string" }, @@ -264,12 +278,22 @@ }, "sourceType": { "description": "Type of source for annotation data", - "enum": ["", "line", "NATIVE", "table"], + "enum": [ + "", + "line", + "NATIVE", + "table" + ], "type": "string" }, "style": { "description": "Line style. Only applies to time-series annotations", - "enum": ["dashed", "dotted", "solid", "longDashed"], + "enum": [ + "dashed", + "dotted", + "solid", + "longDashed" + ], "type": "string" }, "timeColumn": { @@ -287,12 +311,16 @@ }, "width": { "description": "Width of annotation line", - "format": "float", - "minimum": 0, + "minimum": 0.0, "type": "number" } }, - "required": ["name", "show", "showMarkers", "value"], + "required": [ + "name", + "show", + "showMarkers", + "value" + ], "type": "object" }, "AnnotationLayerRestApi.get": { @@ -302,7 +330,6 @@ "type": "string" }, "id": { - "format": "int32", "type": "integer" }, "name": { @@ -316,7 +343,7 @@ "AnnotationLayerRestApi.get_list": { "properties": { "changed_by": { - "$ref": "#/components/schemas/AnnotationLayerRestApi.get_list.User" + "$ref": "#/components/schemas/AnnotationLayerRestApi.get_list.User1" }, "changed_on": { "format": "date-time", @@ -327,7 +354,7 @@ "readOnly": true }, "created_by": { - "$ref": "#/components/schemas/AnnotationLayerRestApi.get_list.User1" + "$ref": "#/components/schemas/AnnotationLayerRestApi.get_list.User" }, "created_on": { "format": "date-time", @@ -339,7 +366,6 @@ "type": "string" }, "id": { - "format": "int32", "type": "integer" }, "name": { @@ -361,7 +387,10 @@ "type": "string" } }, - "required": ["first_name", "last_name"], + "required": [ + "first_name", + "last_name" + ], "type": "object" }, "AnnotationLayerRestApi.get_list.User1": { @@ -375,7 +404,10 @@ "type": "string" } }, - "required": ["first_name", "last_name"], + "required": [ + "first_name", + "last_name" + ], "type": "object" }, "AnnotationLayerRestApi.post": { @@ -392,7 +424,9 @@ "type": "string" } }, - "required": ["name"], + "required": [ + "name" + ], "type": "object" }, "AnnotationLayerRestApi.put": { @@ -418,7 +452,6 @@ "type": "string" }, "id": { - "format": "int32", "type": "integer" }, "json_metadata": { @@ -443,13 +476,14 @@ "type": "string" } }, - "required": ["layer"], + "required": [ + "layer" + ], "type": "object" }, "AnnotationRestApi.get.AnnotationLayer": { "properties": { "id": { - "format": "int32", "type": "integer" }, "name": { @@ -463,13 +497,13 @@ "AnnotationRestApi.get_list": { "properties": { "changed_by": { - "$ref": "#/components/schemas/AnnotationRestApi.get_list.User" + "$ref": "#/components/schemas/AnnotationRestApi.get_list.User1" }, "changed_on_delta_humanized": { "readOnly": true }, "created_by": { - "$ref": "#/components/schemas/AnnotationRestApi.get_list.User1" + "$ref": "#/components/schemas/AnnotationRestApi.get_list.User" }, "end_dttm": { "format": "date-time", @@ -477,7 +511,6 @@ "type": "string" }, "id": { - "format": "int32", "type": "integer" }, "long_descr": { @@ -504,11 +537,12 @@ "type": "string" }, "id": { - "format": "int32", "type": "integer" } }, - "required": ["first_name"], + "required": [ + "first_name" + ], "type": "object" }, "AnnotationRestApi.get_list.User1": { @@ -518,11 +552,12 @@ "type": "string" }, "id": { - "format": "int32", "type": "integer" } }, - "required": ["first_name"], + "required": [ + "first_name" + ], "type": "object" }, "AnnotationRestApi.post": { @@ -554,7 +589,11 @@ "type": "string" } }, - "required": ["end_dttm", "short_descr", "start_dttm"], + "required": [ + "end_dttm", + "short_descr", + "start_dttm" + ], "type": "object" }, "AnnotationRestApi.put": { @@ -621,7 +660,6 @@ "CacheRestApi.get": { "properties": { "id": { - "format": "int32", "type": "integer" } }, @@ -630,7 +668,6 @@ "CacheRestApi.get_list": { "properties": { "id": { - "format": "int32", "type": "integer" } }, @@ -639,7 +676,6 @@ "CacheRestApi.post": { "properties": { "id": { - "format": "int32", "type": "integer" } }, @@ -648,7 +684,6 @@ "CacheRestApi.put": { "properties": { "id": { - "format": "int32", "type": "integer" } }, @@ -671,11 +706,67 @@ }, "type": "object" }, + "ChartCacheWarmUpRequestSchema": { + "properties": { + "chart_id": { + "description": "The ID of the chart to warm up cache for", + "type": "integer" + }, + "dashboard_id": { + "description": "The ID of the dashboard to get filters for when warming cache", + "type": "integer" + }, + "extra_filters": { + "description": "Extra filters to apply when warming up cache", + "type": "string" + } + }, + "required": [ + "chart_id" + ], + "type": "object" + }, + "ChartCacheWarmUpResponseSchema": { + "properties": { + "result": { + "description": "A list of each chart's warmup status and errors if any", + "items": { + "$ref": "#/components/schemas/ChartCacheWarmUpResponseSingle" + }, + "type": "array" + } + }, + "type": "object" + }, + "ChartCacheWarmUpResponseSingle": { + "properties": { + "chart_id": { + "description": "The ID of the chart the status belongs to", + "type": "integer" + }, + "viz_error": { + "description": "Error that occurred when warming cache for chart", + "type": "string" + }, + "viz_status": { + "description": "Status of the underlying query for the viz", + "type": "string" + } + }, + "type": "object" + }, "ChartDataAdhocMetricSchema": { "properties": { "aggregate": { - "description": "Aggregation operator. Only required for simple expression types.", - "enum": ["AVG", "COUNT", "COUNT_DISTINCT", "MAX", "MIN", "SUM"], + "description": "Aggregation operator.Only required for simple expression types.", + "enum": [ + "AVG", + "COUNT", + "COUNT_DISTINCT", + "MAX", + "MIN", + "SUM" + ], "type": "string" }, "column": { @@ -683,7 +774,10 @@ }, "expressionType": { "description": "Simple or SQL metric", - "enum": ["SIMPLE", "SQL"], + "enum": [ + "SIMPLE", + "SQL" + ], "example": "SQL", "type": "string" }, @@ -697,12 +791,12 @@ "type": "boolean" }, "label": { - "description": "Label for the metric. Is automatically generated unless hasCustomLabel is true, in which case label must be defined.", + "description": "Label for the metric. Is automatically generated unlesshasCustomLabel is true, in which case label must be defined.", "example": "Weighted observations", "type": "string" }, "optionName": { - "description": "Unique identifier. Can be any string value, as long as all metrics have a unique identifier. If undefined, a random name will be generated.", + "description": "Unique identifier. Can be any string value, as long as all metrics have a unique identifier. If undefined, a random namewill be generated.", "example": "metric_aec60732-fac0-4b17-b736-93f1a5c93e30", "type": "string" }, @@ -717,7 +811,9 @@ "type": "string" } }, - "required": ["expressionType"], + "required": [ + "expressionType" + ], "type": "object" }, "ChartDataAggregateOptionsSchema": { @@ -782,16 +878,25 @@ }, "percentiles": { "description": "Upper and lower percentiles for percentile whisker type.", - "example": [1, 99] + "example": [ + 1, + 99 + ] }, "whisker_type": { "description": "Whisker type. Any numpy function will work.", - "enum": ["tukey", "min/max", "percentile"], + "enum": [ + "tukey", + "min/max", + "percentile" + ], "example": "tukey", "type": "string" } }, - "required": ["whisker_type"], + "required": [ + "whisker_type" + ], "type": "object" }, "ChartDataColumn": { @@ -813,19 +918,23 @@ "properties": { "orientation": { "description": "Should cell values be calculated across the row or column.", - "enum": ["row", "column"], + "enum": [ + "row", + "column" + ], "example": "row", "type": "string" } }, - "required": ["orientation"], + "required": [ + "orientation" + ], "type": "object" }, "ChartDataDatasource": { "properties": { "id": { "description": "Datasource id", - "format": "int32", "type": "integer" }, "type": { @@ -841,7 +950,9 @@ "type": "string" } }, - "required": ["id"], + "required": [ + "id" + ], "type": "object" }, "ChartDataExtras": { @@ -852,12 +963,18 @@ }, "relative_end": { "description": "End time for relative time deltas. Default: `config[\"DEFAULT_RELATIVE_START_TIME\"]`", - "enum": ["today", "now"], + "enum": [ + "today", + "now" + ], "type": "string" }, "relative_start": { "description": "Start time for relative time deltas. Default: `config[\"DEFAULT_RELATIVE_START_TIME\"]`", - "enum": ["today", "now"], + "enum": [ + "today", + "now" + ], "type": "string" }, "time_grain_sqla": { @@ -881,7 +998,12 @@ "1969-12-28T00:00:00Z/P1W", "1969-12-29T00:00:00Z/P1W", "P1W/1970-01-03T00:00:00Z", - "P1W/1970-01-04T00:00:00Z" + "P1W/1970-01-04T00:00:00Z", + "PT2H", + "PT4H", + "PT8H", + "PT10H", + "PT12H" ], "example": "P1D", "nullable": true, @@ -924,7 +1046,6 @@ "IS NOT NULL", "IN", "NOT IN", - "REGEX", "IS TRUE", "IS FALSE", "TEMPORAL_RANGE" @@ -934,11 +1055,18 @@ }, "val": { "description": "The value or values to compare against. Can be a string, integer, decimal, None or list, depending on the operator.", - "example": ["China", "France", "Japan"], + "example": [ + "China", + "France", + "Japan" + ], "nullable": true } }, - "required": ["col", "op"], + "required": [ + "col", + "op" + ], "type": "object" }, "ChartDataGeodeticParseOptionsSchema": { @@ -960,7 +1088,11 @@ "type": "string" } }, - "required": ["geodetic", "latitude", "longitude"], + "required": [ + "geodetic", + "latitude", + "longitude" + ], "type": "object" }, "ChartDataGeohashDecodeOptionsSchema": { @@ -978,7 +1110,11 @@ "type": "string" } }, - "required": ["geohash", "latitude", "longitude"], + "required": [ + "geohash", + "latitude", + "longitude" + ], "type": "object" }, "ChartDataGeohashEncodeOptionsSchema": { @@ -996,7 +1132,11 @@ "type": "string" } }, - "required": ["geohash", "latitude", "longitude"], + "required": [ + "geohash", + "latitude", + "longitude" + ], "type": "object" }, "ChartDataPivotOptionsSchema": { @@ -1088,12 +1228,17 @@ } } }, - "groupby": ["country", "gender"] + "groupby": [ + "country", + "gender" + ] }, "type": "object" } }, - "required": ["operation"], + "required": [ + "operation" + ], "type": "object" }, "ChartDataProphetOptionsSchema": { @@ -1101,9 +1246,8 @@ "confidence_interval": { "description": "Width of predicted confidence interval", "example": 0.8, - "format": "float", - "maximum": 1, - "minimum": 0, + "maximum": 1.0, + "minimum": 0.0, "type": "number" }, "monthly_seasonality": { @@ -1113,7 +1257,6 @@ "periods": { "description": "Time periods (in units of `time_grain`) to predict into the future", "example": 7, - "format": "int32", "type": "integer" }, "time_grain": { @@ -1137,7 +1280,12 @@ "1969-12-28T00:00:00Z/P1W", "1969-12-29T00:00:00Z/P1W", "P1W/1970-01-03T00:00:00Z", - "P1W/1970-01-04T00:00:00Z" + "P1W/1970-01-04T00:00:00Z", + "PT2H", + "PT4H", + "PT8H", + "PT10H", + "PT12H" ], "example": "P1D", "type": "string" @@ -1151,14 +1299,17 @@ "example": false } }, - "required": ["confidence_interval", "periods", "time_grain"], + "required": [ + "confidence_interval", + "periods", + "time_grain" + ], "type": "object" }, "ChartDataQueryContextSchema": { "properties": { "custom_cache_timeout": { "description": "Override the default cache timeout", - "format": "int32", "nullable": true, "type": "integer" }, @@ -1179,8 +1330,25 @@ }, "type": "array" }, - "result_format": {}, - "result_type": {} + "result_format": { + "enum": [ + "csv", + "json", + "xlsx" + ] + }, + "result_type": { + "enum": [ + "columns", + "full", + "query", + "results", + "samples", + "timegrains", + "post_processed", + "drill_detail" + ] + } }, "type": "object" }, @@ -1238,11 +1406,12 @@ "type": "array" }, "granularity": { - "description": "Name of temporal column used for time filtering.", + "description": "Name of temporal column used for time filtering. ", "nullable": true, "type": "string" }, "granularity_sqla": { + "deprecated": true, "description": "Name of temporal column used for time filtering for SQL datasources. This field is deprecated, use `granularity` instead.", "nullable": true, "type": "string" @@ -1254,6 +1423,7 @@ "type": "array" }, "having": { + "deprecated": true, "description": "HAVING clause to be added to aggregate queries using AND operator. This field is deprecated and should be passed to `extras`.", "nullable": true, "type": "string" @@ -1282,8 +1452,14 @@ "orderby": { "description": "Expects a list of lists where the first element is the column name which to sort by, and the second element is a boolean.", "example": [ - ["my_col_1", false], - ["my_col_2", true] + [ + "my_col_1", + false + ], + [ + "my_col_2", + true + ] ], "items": {}, "nullable": true, @@ -1303,18 +1479,26 @@ "type": "array" }, "result_type": { + "enum": [ + "columns", + "full", + "query", + "results", + "samples", + "timegrains", + "post_processed", + "drill_detail" + ], "nullable": true }, "row_limit": { "description": "Maximum row count (0=disabled). Default: `config[\"ROW_LIMIT\"]`", - "format": "int32", "minimum": 0, "nullable": true, "type": "integer" }, "row_offset": { "description": "Number of rows to skip. Default: `0`", - "format": "int32", "minimum": 0, "nullable": true, "type": "integer" @@ -1327,7 +1511,6 @@ }, "series_limit": { "description": "Maximum number of series. Requires `series` and `series_limit_metric` to be set.", - "format": "int32", "nullable": true, "type": "integer" }, @@ -1355,7 +1538,6 @@ }, "timeseries_limit": { "description": "Maximum row count for timeseries queries. This field is deprecated, use `series_limit` instead.Default: `0`", - "format": "int32", "nullable": true, "type": "integer" }, @@ -1368,11 +1550,12 @@ "description": "The value of the query parameter", "type": "string" }, - "description": "Optional query parameters passed to a dashboard or Explore view", + "description": "Optional query parameters passed to a dashboard or Explore view", "nullable": true, "type": "object" }, "where": { + "deprecated": true, "description": "WHERE clause to be added to queries using AND operator.This field is deprecated and should be passed to `extras`.", "nullable": true, "type": "string" @@ -1407,7 +1590,6 @@ }, "cache_timeout": { "description": "Cache timeout in following order: custom timeout, datasource timeout, cache default timeout, config default cache timeout.", - "format": "int32", "nullable": true, "type": "integer" }, @@ -1426,7 +1608,6 @@ "coltypes": { "description": "A list of generic data types of each column", "items": { - "format": "int32", "type": "integer" }, "type": "array" @@ -1445,7 +1626,6 @@ }, "from_dttm": { "description": "Start timestamp of time range", - "format": "int32", "nullable": true, "type": "integer" }, @@ -1466,7 +1646,6 @@ }, "rowcount": { "description": "Amount of rows in result set", - "format": "int32", "type": "integer" }, "stacktrace": { @@ -1489,7 +1668,6 @@ }, "to_dttm": { "description": "End timestamp of time range", - "format": "int32", "nullable": true, "type": "integer" } @@ -1518,7 +1696,6 @@ "ChartDataRestApi.get": { "properties": { "cache_timeout": { - "format": "int32", "nullable": true, "type": "integer" }, @@ -1541,7 +1718,6 @@ "type": "string" }, "id": { - "format": "int32", "type": "integer" }, "is_managed_externally": { @@ -1563,6 +1739,9 @@ "nullable": true, "type": "string" }, + "tags": { + "$ref": "#/components/schemas/ChartDataRestApi.get.Tag" + }, "thumbnail_url": { "readOnly": true }, @@ -1585,7 +1764,6 @@ "type": "string" }, "id": { - "format": "int32", "type": "integer" }, "json_metadata": { @@ -1595,6 +1773,27 @@ }, "type": "object" }, + "ChartDataRestApi.get.Tag": { + "properties": { + "id": { + "type": "integer" + }, + "name": { + "maxLength": 250, + "nullable": true, + "type": "string" + }, + "type": { + "enum": [ + 1, + 2, + 3, + 4 + ] + } + }, + "type": "object" + }, "ChartDataRestApi.get.User": { "properties": { "first_name": { @@ -1602,25 +1801,22 @@ "type": "string" }, "id": { - "format": "int32", "type": "integer" }, "last_name": { "maxLength": 64, "type": "string" - }, - "username": { - "maxLength": 64, - "type": "string" } }, - "required": ["first_name", "last_name", "username"], + "required": [ + "first_name", + "last_name" + ], "type": "object" }, "ChartDataRestApi.get_list": { "properties": { "cache_timeout": { - "format": "int32", "nullable": true, "type": "integer" }, @@ -1633,14 +1829,11 @@ "type": "string" }, "changed_by": { - "$ref": "#/components/schemas/ChartDataRestApi.get_list.User" + "$ref": "#/components/schemas/ChartDataRestApi.get_list.User3" }, "changed_by_name": { "readOnly": true }, - "changed_by_url": { - "readOnly": true - }, "changed_on_delta_humanized": { "readOnly": true }, @@ -1651,14 +1844,11 @@ "readOnly": true }, "created_by": { - "$ref": "#/components/schemas/ChartDataRestApi.get_list.User2" + "$ref": "#/components/schemas/ChartDataRestApi.get_list.User" }, "created_by_name": { "readOnly": true }, - "created_by_url": { - "readOnly": true - }, "created_on_delta_humanized": { "readOnly": true }, @@ -1666,7 +1856,6 @@ "$ref": "#/components/schemas/ChartDataRestApi.get_list.Dashboard" }, "datasource_id": { - "format": "int32", "nullable": true, "type": "integer" }, @@ -1695,7 +1884,6 @@ "readOnly": true }, "id": { - "format": "int32", "type": "integer" }, "is_managed_externally": { @@ -1707,10 +1895,10 @@ "type": "string" }, "last_saved_by": { - "$ref": "#/components/schemas/ChartDataRestApi.get_list.User1" + "$ref": "#/components/schemas/ChartDataRestApi.get_list.User2" }, "owners": { - "$ref": "#/components/schemas/ChartDataRestApi.get_list.User3" + "$ref": "#/components/schemas/ChartDataRestApi.get_list.User1" }, "params": { "nullable": true, @@ -1727,6 +1915,9 @@ "table": { "$ref": "#/components/schemas/ChartDataRestApi.get_list.SqlaTable" }, + "tags": { + "$ref": "#/components/schemas/ChartDataRestApi.get_list.Tag" + }, "thumbnail_url": { "readOnly": true }, @@ -1749,7 +1940,6 @@ "type": "string" }, "id": { - "format": "int32", "type": "integer" } }, @@ -1766,7 +1956,30 @@ "type": "string" } }, - "required": ["table_name"], + "required": [ + "table_name" + ], + "type": "object" + }, + "ChartDataRestApi.get_list.Tag": { + "properties": { + "id": { + "type": "integer" + }, + "name": { + "maxLength": 250, + "nullable": true, + "type": "string" + }, + "type": { + "enum": [ + 1, + 2, + 3, + 4 + ] + } + }, "type": "object" }, "ChartDataRestApi.get_list.User": { @@ -1775,12 +1988,18 @@ "maxLength": 64, "type": "string" }, + "id": { + "type": "integer" + }, "last_name": { "maxLength": 64, "type": "string" } }, - "required": ["first_name", "last_name"], + "required": [ + "first_name", + "last_name" + ], "type": "object" }, "ChartDataRestApi.get_list.User1": { @@ -1790,7 +2009,6 @@ "type": "string" }, "id": { - "format": "int32", "type": "integer" }, "last_name": { @@ -1798,7 +2016,10 @@ "type": "string" } }, - "required": ["first_name", "last_name"], + "required": [ + "first_name", + "last_name" + ], "type": "object" }, "ChartDataRestApi.get_list.User2": { @@ -1808,7 +2029,6 @@ "type": "string" }, "id": { - "format": "int32", "type": "integer" }, "last_name": { @@ -1816,7 +2036,10 @@ "type": "string" } }, - "required": ["first_name", "last_name"], + "required": [ + "first_name", + "last_name" + ], "type": "object" }, "ChartDataRestApi.get_list.User3": { @@ -1825,27 +2048,21 @@ "maxLength": 64, "type": "string" }, - "id": { - "format": "int32", - "type": "integer" - }, "last_name": { "maxLength": 64, "type": "string" - }, - "username": { - "maxLength": 64, - "type": "string" } }, - "required": ["first_name", "last_name", "username"], + "required": [ + "first_name", + "last_name" + ], "type": "object" }, "ChartDataRestApi.post": { "properties": { "cache_timeout": { "description": "Duration (in seconds) of the caching timeout for this chart. Note this defaults to the datasource/table timeout if undefined.", - "format": "int32", "nullable": true, "type": "integer" }, @@ -1862,14 +2079,12 @@ "dashboards": { "items": { "description": "A list of dashboards to include this new chart to.", - "format": "int32", "type": "integer" }, "type": "array" }, "datasource_id": { "description": "The id of the dataset/datasource this new chart will use. A complete datasource identification needs `datasouce_id` and `datasource_type`.", - "format": "int32", "type": "integer" }, "datasource_name": { @@ -1905,7 +2120,6 @@ "owners": { "items": { "description": "Owner are users ids allowed to delete or change this chart. If left empty you will be one of the owners of the chart.", - "format": "int32", "type": "integer" }, "type": "array" @@ -1933,20 +2147,27 @@ }, "viz_type": { "description": "The type of chart visualization used.", - "example": ["bar", "area", "table"], + "example": [ + "bar", + "area", + "table" + ], "maxLength": 250, "minLength": 0, "type": "string" } }, - "required": ["datasource_id", "datasource_type", "slice_name"], + "required": [ + "datasource_id", + "datasource_type", + "slice_name" + ], "type": "object" }, "ChartDataRestApi.put": { "properties": { "cache_timeout": { "description": "Duration (in seconds) of the caching timeout for this chart. Note this defaults to the datasource/table timeout if undefined.", - "format": "int32", "nullable": true, "type": "integer" }, @@ -1963,14 +2184,12 @@ "dashboards": { "items": { "description": "A list of dashboards to include this new chart to.", - "format": "int32", "type": "integer" }, "type": "array" }, "datasource_id": { "description": "The id of the dataset/datasource this new chart will use. A complete datasource identification needs `datasouce_id` and `datasource_type`.", - "format": "int32", "nullable": true, "type": "integer" }, @@ -2003,7 +2222,6 @@ "owners": { "items": { "description": "Owner are users ids allowed to delete or change this chart. If left empty you will be one of the owners of the chart.", - "format": "int32", "type": "integer" }, "type": "array" @@ -2030,9 +2248,19 @@ "nullable": true, "type": "string" }, + "tags": { + "items": { + "$ref": "#/components/schemas/Tag" + }, + "type": "array" + }, "viz_type": { "description": "The type of chart visualization used.", - "example": ["bar", "area", "table"], + "example": [ + "bar", + "area", + "table" + ], "maxLength": 250, "minLength": 0, "nullable": true, @@ -2044,14 +2272,13 @@ "ChartDataRollingOptionsSchema": { "properties": { "center": { - "description": "Should the label be at the center of the window. Default: `false`", + "description": "Should the label be at the center of the window.Default: `false`", "example": false, "type": "boolean" }, "min_periods": { "description": "The minimum amount of periods required for a row to be included in the result set.", "example": 7, - "format": "int32", "type": "integer" }, "rolling_type": { @@ -2088,7 +2315,7 @@ "type": "object" }, "win_type": { - "description": "Type of window function. See [SciPy window functions](https://docs.scipy.org/doc/scipy/reference/signal.windows.html#module-scipy.signal.windows) for more details. Some window functions require passing additional parameters to `rolling_type_options`. For instance, to use `gaussian`, the parameter `std` needs to be provided.", + "description": "Type of window function. See [SciPy window functions](https://docs.scipy.org/doc/scipy/reference /signal.windows.html#module-scipy.signal.windows) for more details. Some window functions require passing additional parameters to `rolling_type_options`. For instance, to use `gaussian`, the parameter `std` needs to be provided.", "enum": [ "boxcar", "triang", @@ -2111,18 +2338,24 @@ "window": { "description": "Size of the rolling window in days.", "example": 7, - "format": "int32", "type": "integer" } }, - "required": ["rolling_type", "window"], + "required": [ + "rolling_type", + "window" + ], "type": "object" }, "ChartDataSelectOptionsSchema": { "properties": { "columns": { "description": "Columns which to select from the input data, in the desired order. If columns are renamed, the original column name should be referenced here.", - "example": ["country", "gender", "age"], + "example": [ + "country", + "gender", + "age" + ], "items": { "type": "string" }, @@ -2130,7 +2363,9 @@ }, "exclude": { "description": "Columns to exclude from selection.", - "example": ["my_temp_column"], + "example": [ + "my_temp_column" + ], "items": { "type": "string" }, @@ -2175,14 +2410,15 @@ "type": "object" } }, - "required": ["columns"], + "required": [ + "columns" + ], "type": "object" }, "ChartEntityResponseSchema": { "properties": { "cache_timeout": { "description": "Duration (in seconds) of the caching timeout for this chart. Note this defaults to the datasource/table timeout if undefined.", - "format": "int32", "type": "integer" }, "certification_details": { @@ -2195,6 +2431,7 @@ }, "changed_on": { "description": "The ISO date that the chart was last changed.", + "format": "date-time", "type": "string" }, "description": { @@ -2211,7 +2448,6 @@ }, "id": { "description": "The id of the chart.", - "format": "int32", "type": "integer" }, "slice_name": { @@ -2229,7 +2465,6 @@ "properties": { "id": { "description": "The Chart id", - "format": "int32", "type": "integer" }, "value": { @@ -2243,12 +2478,10 @@ "properties": { "datasource_id": { "description": "The datasource identifier", - "format": "int32", "type": "integer" }, "datasource_type": { "description": "The datasource type", - "format": "int32", "type": "integer" } }, @@ -2270,7 +2503,6 @@ "properties": { "count": { "description": "The total number of datasources", - "format": "int32", "type": "integer" }, "result": { @@ -2282,7 +2514,6 @@ "ChartRestApi.get": { "properties": { "cache_timeout": { - "format": "int32", "nullable": true, "type": "integer" }, @@ -2305,7 +2536,6 @@ "type": "string" }, "id": { - "format": "int32", "type": "integer" }, "is_managed_externally": { @@ -2327,6 +2557,9 @@ "nullable": true, "type": "string" }, + "tags": { + "$ref": "#/components/schemas/ChartRestApi.get.Tag" + }, "thumbnail_url": { "readOnly": true }, @@ -2349,7 +2582,6 @@ "type": "string" }, "id": { - "format": "int32", "type": "integer" }, "json_metadata": { @@ -2359,6 +2591,27 @@ }, "type": "object" }, + "ChartRestApi.get.Tag": { + "properties": { + "id": { + "type": "integer" + }, + "name": { + "maxLength": 250, + "nullable": true, + "type": "string" + }, + "type": { + "enum": [ + 1, + 2, + 3, + 4 + ] + } + }, + "type": "object" + }, "ChartRestApi.get.User": { "properties": { "first_name": { @@ -2366,25 +2619,22 @@ "type": "string" }, "id": { - "format": "int32", "type": "integer" }, "last_name": { "maxLength": 64, "type": "string" - }, - "username": { - "maxLength": 64, - "type": "string" } }, - "required": ["first_name", "last_name", "username"], + "required": [ + "first_name", + "last_name" + ], "type": "object" }, "ChartRestApi.get_list": { "properties": { "cache_timeout": { - "format": "int32", "nullable": true, "type": "integer" }, @@ -2397,14 +2647,11 @@ "type": "string" }, "changed_by": { - "$ref": "#/components/schemas/ChartRestApi.get_list.User" + "$ref": "#/components/schemas/ChartRestApi.get_list.User3" }, "changed_by_name": { "readOnly": true }, - "changed_by_url": { - "readOnly": true - }, "changed_on_delta_humanized": { "readOnly": true }, @@ -2415,14 +2662,11 @@ "readOnly": true }, "created_by": { - "$ref": "#/components/schemas/ChartRestApi.get_list.User2" + "$ref": "#/components/schemas/ChartRestApi.get_list.User" }, "created_by_name": { "readOnly": true }, - "created_by_url": { - "readOnly": true - }, "created_on_delta_humanized": { "readOnly": true }, @@ -2430,7 +2674,6 @@ "$ref": "#/components/schemas/ChartRestApi.get_list.Dashboard" }, "datasource_id": { - "format": "int32", "nullable": true, "type": "integer" }, @@ -2459,7 +2702,6 @@ "readOnly": true }, "id": { - "format": "int32", "type": "integer" }, "is_managed_externally": { @@ -2471,10 +2713,10 @@ "type": "string" }, "last_saved_by": { - "$ref": "#/components/schemas/ChartRestApi.get_list.User1" + "$ref": "#/components/schemas/ChartRestApi.get_list.User2" }, "owners": { - "$ref": "#/components/schemas/ChartRestApi.get_list.User3" + "$ref": "#/components/schemas/ChartRestApi.get_list.User1" }, "params": { "nullable": true, @@ -2491,6 +2733,9 @@ "table": { "$ref": "#/components/schemas/ChartRestApi.get_list.SqlaTable" }, + "tags": { + "$ref": "#/components/schemas/ChartRestApi.get_list.Tag" + }, "thumbnail_url": { "readOnly": true }, @@ -2513,7 +2758,6 @@ "type": "string" }, "id": { - "format": "int32", "type": "integer" } }, @@ -2530,31 +2774,39 @@ "type": "string" } }, - "required": ["table_name"], + "required": [ + "table_name" + ], "type": "object" }, - "ChartRestApi.get_list.User": { + "ChartRestApi.get_list.Tag": { "properties": { - "first_name": { - "maxLength": 64, - "type": "string" + "id": { + "type": "integer" }, - "last_name": { - "maxLength": 64, + "name": { + "maxLength": 250, + "nullable": true, "type": "string" + }, + "type": { + "enum": [ + 1, + 2, + 3, + 4 + ] } }, - "required": ["first_name", "last_name"], "type": "object" }, - "ChartRestApi.get_list.User1": { + "ChartRestApi.get_list.User": { "properties": { "first_name": { "maxLength": 64, "type": "string" }, "id": { - "format": "int32", "type": "integer" }, "last_name": { @@ -2562,17 +2814,19 @@ "type": "string" } }, - "required": ["first_name", "last_name"], + "required": [ + "first_name", + "last_name" + ], "type": "object" }, - "ChartRestApi.get_list.User2": { + "ChartRestApi.get_list.User1": { "properties": { "first_name": { "maxLength": 64, "type": "string" }, "id": { - "format": "int32", "type": "integer" }, "last_name": { @@ -2580,36 +2834,53 @@ "type": "string" } }, - "required": ["first_name", "last_name"], + "required": [ + "first_name", + "last_name" + ], "type": "object" }, - "ChartRestApi.get_list.User3": { + "ChartRestApi.get_list.User2": { "properties": { "first_name": { "maxLength": 64, "type": "string" }, "id": { - "format": "int32", "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" }, - "username": { + "last_name": { "maxLength": 64, "type": "string" } }, - "required": ["first_name", "last_name", "username"], + "required": [ + "first_name", + "last_name" + ], "type": "object" }, "ChartRestApi.post": { "properties": { "cache_timeout": { "description": "Duration (in seconds) of the caching timeout for this chart. Note this defaults to the datasource/table timeout if undefined.", - "format": "int32", "nullable": true, "type": "integer" }, @@ -2626,14 +2897,12 @@ "dashboards": { "items": { "description": "A list of dashboards to include this new chart to.", - "format": "int32", "type": "integer" }, "type": "array" }, "datasource_id": { "description": "The id of the dataset/datasource this new chart will use. A complete datasource identification needs `datasouce_id` and `datasource_type`.", - "format": "int32", "type": "integer" }, "datasource_name": { @@ -2669,7 +2938,6 @@ "owners": { "items": { "description": "Owner are users ids allowed to delete or change this chart. If left empty you will be one of the owners of the chart.", - "format": "int32", "type": "integer" }, "type": "array" @@ -2697,20 +2965,27 @@ }, "viz_type": { "description": "The type of chart visualization used.", - "example": ["bar", "area", "table"], + "example": [ + "bar", + "area", + "table" + ], "maxLength": 250, "minLength": 0, "type": "string" } }, - "required": ["datasource_id", "datasource_type", "slice_name"], + "required": [ + "datasource_id", + "datasource_type", + "slice_name" + ], "type": "object" }, "ChartRestApi.put": { "properties": { "cache_timeout": { "description": "Duration (in seconds) of the caching timeout for this chart. Note this defaults to the datasource/table timeout if undefined.", - "format": "int32", "nullable": true, "type": "integer" }, @@ -2727,14 +3002,12 @@ "dashboards": { "items": { "description": "A list of dashboards to include this new chart to.", - "format": "int32", "type": "integer" }, "type": "array" }, "datasource_id": { "description": "The id of the dataset/datasource this new chart will use. A complete datasource identification needs `datasouce_id` and `datasource_type`.", - "format": "int32", "nullable": true, "type": "integer" }, @@ -2767,7 +3040,6 @@ "owners": { "items": { "description": "Owner are users ids allowed to delete or change this chart. If left empty you will be one of the owners of the chart.", - "format": "int32", "type": "integer" }, "type": "array" @@ -2794,9 +3066,19 @@ "nullable": true, "type": "string" }, + "tags": { + "items": { + "$ref": "#/components/schemas/Tag" + }, + "type": "array" + }, "viz_type": { "description": "The type of chart visualization used.", - "example": ["bar", "area", "table"], + "example": [ + "bar", + "area", + "table" + ], "maxLength": 250, "minLength": 0, "nullable": true, @@ -2815,7 +3097,6 @@ "type": "string" }, "id": { - "format": "int32", "type": "integer" }, "template_name": { @@ -2833,7 +3114,6 @@ "type": "string" }, "id": { - "format": "int32", "type": "integer" }, "last_name": { @@ -2841,19 +3121,22 @@ "type": "string" } }, - "required": ["first_name", "last_name"], + "required": [ + "first_name", + "last_name" + ], "type": "object" }, "CssTemplateRestApi.get_list": { "properties": { "changed_by": { - "$ref": "#/components/schemas/CssTemplateRestApi.get_list.User" + "$ref": "#/components/schemas/CssTemplateRestApi.get_list.User1" }, "changed_on_delta_humanized": { "readOnly": true }, "created_by": { - "$ref": "#/components/schemas/CssTemplateRestApi.get_list.User1" + "$ref": "#/components/schemas/CssTemplateRestApi.get_list.User" }, "created_on": { "format": "date-time", @@ -2865,7 +3148,6 @@ "type": "string" }, "id": { - "format": "int32", "type": "integer" }, "template_name": { @@ -2883,7 +3165,6 @@ "type": "string" }, "id": { - "format": "int32", "type": "integer" }, "last_name": { @@ -2891,7 +3172,10 @@ "type": "string" } }, - "required": ["first_name", "last_name"], + "required": [ + "first_name", + "last_name" + ], "type": "object" }, "CssTemplateRestApi.get_list.User1": { @@ -2901,7 +3185,6 @@ "type": "string" }, "id": { - "format": "int32", "type": "integer" }, "last_name": { @@ -2909,7 +3192,10 @@ "type": "string" } }, - "required": ["first_name", "last_name"], + "required": [ + "first_name", + "last_name" + ], "type": "object" }, "CssTemplateRestApi.post": { @@ -2940,10 +3226,36 @@ }, "type": "object" }, + "DashboardCopySchema": { + "properties": { + "css": { + "description": "Override CSS for the dashboard.", + "type": "string" + }, + "dashboard_title": { + "description": "A title for the dashboard.", + "maxLength": 500, + "minLength": 0, + "nullable": true, + "type": "string" + }, + "duplicate_slices": { + "description": "Whether or not to also copy all charts on the dashboard", + "type": "boolean" + }, + "json_metadata": { + "description": "This JSON object is generated dynamically when clicking the save or overwrite button in the dashboard view. It is exposed here for reference and for power users who may want to alter specific parameters.", + "type": "string" + } + }, + "required": [ + "json_metadata" + ], + "type": "object" + }, "DashboardDatasetSchema": { "properties": { "cache_timeout": { - "format": "int32", "type": "integer" }, "column_formats": { @@ -2951,7 +3263,6 @@ }, "column_types": { "items": { - "format": "int32", "type": "integer" }, "type": "array" @@ -2962,6 +3273,9 @@ }, "type": "array" }, + "currency_formats": { + "type": "object" + }, "database": { "$ref": "#/components/schemas/Database" }, @@ -2996,7 +3310,6 @@ "type": "string" }, "id": { - "format": "int32", "type": "integer" }, "is_sqllab_view": { @@ -3015,7 +3328,6 @@ "type": "string" }, "offset": { - "format": "int32", "type": "integer" }, "order_by_choices": { @@ -3094,9 +3406,6 @@ "changed_by_name": { "type": "string" }, - "changed_by_url": { - "type": "string" - }, "changed_on": { "format": "date-time", "type": "string" @@ -3120,7 +3429,6 @@ "type": "string" }, "id": { - "format": "int32", "type": "integer" }, "is_managed_externally": { @@ -3153,6 +3461,12 @@ "slug": { "type": "string" }, + "tags": { + "items": { + "$ref": "#/components/schemas/Tag1" + }, + "type": "array" + }, "thumbnail_url": { "type": "string" }, @@ -3162,7 +3476,7 @@ }, "type": "object" }, - "DashboardPermalinkPostSchema": { + "DashboardPermalinkStateSchema": { "properties": { "activeTabs": { "description": "Current active dashboard tabs", @@ -3197,7 +3511,6 @@ "DashboardRestApi.get": { "properties": { "id": { - "format": "int32", "type": "integer" } }, @@ -3214,14 +3527,11 @@ "type": "string" }, "changed_by": { - "$ref": "#/components/schemas/DashboardRestApi.get_list.User" + "$ref": "#/components/schemas/DashboardRestApi.get_list.User2" }, "changed_by_name": { "readOnly": true }, - "changed_by_url": { - "readOnly": true - }, "changed_on_delta_humanized": { "readOnly": true }, @@ -3229,7 +3539,7 @@ "readOnly": true }, "created_by": { - "$ref": "#/components/schemas/DashboardRestApi.get_list.User1" + "$ref": "#/components/schemas/DashboardRestApi.get_list.User" }, "created_on_delta_humanized": { "readOnly": true @@ -3244,7 +3554,6 @@ "type": "string" }, "id": { - "format": "int32", "type": "integer" }, "is_managed_externally": { @@ -3255,7 +3564,7 @@ "type": "string" }, "owners": { - "$ref": "#/components/schemas/DashboardRestApi.get_list.User2" + "$ref": "#/components/schemas/DashboardRestApi.get_list.User1" }, "position_json": { "nullable": true, @@ -3276,6 +3585,9 @@ "status": { "readOnly": true }, + "tags": { + "$ref": "#/components/schemas/DashboardRestApi.get_list.Tag" + }, "thumbnail_url": { "readOnly": true }, @@ -3288,7 +3600,6 @@ "DashboardRestApi.get_list.Role": { "properties": { "id": { - "format": "int32", "type": "integer" }, "name": { @@ -3296,7 +3607,30 @@ "type": "string" } }, - "required": ["name"], + "required": [ + "name" + ], + "type": "object" + }, + "DashboardRestApi.get_list.Tag": { + "properties": { + "id": { + "type": "integer" + }, + "name": { + "maxLength": 250, + "nullable": true, + "type": "string" + }, + "type": { + "enum": [ + 1, + 2, + 3, + 4 + ] + } + }, "type": "object" }, "DashboardRestApi.get_list.User": { @@ -3306,19 +3640,17 @@ "type": "string" }, "id": { - "format": "int32", "type": "integer" }, "last_name": { "maxLength": 64, "type": "string" - }, - "username": { - "maxLength": 64, - "type": "string" } }, - "required": ["first_name", "last_name", "username"], + "required": [ + "first_name", + "last_name" + ], "type": "object" }, "DashboardRestApi.get_list.User1": { @@ -3328,7 +3660,6 @@ "type": "string" }, "id": { - "format": "int32", "type": "integer" }, "last_name": { @@ -3336,33 +3667,30 @@ "type": "string" } }, - "required": ["first_name", "last_name"], + "required": [ + "first_name", + "last_name" + ], "type": "object" }, "DashboardRestApi.get_list.User2": { "properties": { - "email": { - "maxLength": 64, - "type": "string" - }, "first_name": { "maxLength": 64, "type": "string" }, "id": { - "format": "int32", "type": "integer" }, "last_name": { "maxLength": 64, "type": "string" - }, - "username": { - "maxLength": 64, - "type": "string" } }, - "required": ["email", "first_name", "last_name", "username"], + "required": [ + "first_name", + "last_name" + ], "type": "object" }, "DashboardRestApi.post": { @@ -3378,6 +3706,7 @@ "type": "string" }, "css": { + "description": "Override CSS for the dashboard.", "type": "string" }, "dashboard_title": { @@ -3402,7 +3731,6 @@ "owners": { "items": { "description": "Owner are users ids allowed to delete or change this dashboard. If left empty you will be one of the owners of the dashboard.", - "format": "int32", "type": "integer" }, "type": "array" @@ -3418,7 +3746,6 @@ "roles": { "items": { "description": "Roles is a list which defines access to the dashboard. These roles are always applied in addition to restrictions on dataset level access. If no roles defined then the dashboard is available to all roles.", - "format": "int32", "type": "integer" }, "type": "array" @@ -3473,7 +3800,6 @@ "owners": { "items": { "description": "Owner are users ids allowed to delete or change this dashboard. If left empty you will be one of the owners of the dashboard.", - "format": "int32", "nullable": true, "type": "integer" }, @@ -3492,7 +3818,6 @@ "roles": { "items": { "description": "Roles is a list which defines access to the dashboard. These roles are always applied in addition to restrictions on dataset level access. If no roles defined then the dashboard is available to all roles.", - "format": "int32", "nullable": true, "type": "integer" }, @@ -3526,11 +3851,9 @@ "type": "boolean" }, "explore_database_id": { - "format": "int32", "type": "integer" }, "id": { - "format": "int32", "type": "integer" }, "name": { @@ -3547,6 +3870,125 @@ }, "type": "object" }, + "DatabaseConnectionSchema": { + "properties": { + "allow_ctas": { + "description": "Allow CREATE TABLE AS option in SQL Lab", + "type": "boolean" + }, + "allow_cvas": { + "description": "Allow CREATE VIEW AS option in SQL Lab", + "type": "boolean" + }, + "allow_dml": { + "description": "Allow users to run non-SELECT statements (UPDATE, DELETE, CREATE, ...) in SQL Lab", + "type": "boolean" + }, + "allow_file_upload": { + "description": "Allow to upload CSV file data into this databaseIf selected, please set the schemas allowed for csv upload in Extra.", + "type": "boolean" + }, + "allow_run_async": { + "description": "Operate the database in asynchronous mode, meaning that the queries are executed on remote workers as opposed to on the web server itself. This assumes that you have a Celery worker setup as well as a results backend. Refer to the installation docs for more information.", + "type": "boolean" + }, + "backend": { + "description": "SQLAlchemy engine to use", + "nullable": true, + "type": "string" + }, + "cache_timeout": { + "description": "Duration (in seconds) of the caching timeout for charts of this database. A timeout of 0 indicates that the cache never expires. Note this defaults to the global timeout if undefined.", + "nullable": true, + "type": "integer" + }, + "configuration_method": { + "description": "Configuration_method is used on the frontend to inform the backend whether to explode parameters or to provide only a sqlalchemy_uri.", + "type": "string" + }, + "database_name": { + "description": "A database name to identify this connection.", + "maxLength": 250, + "minLength": 1, + "nullable": true, + "type": "string" + }, + "driver": { + "description": "SQLAlchemy driver to use", + "nullable": true, + "type": "string" + }, + "engine_information": { + "additionalProperties": {}, + "type": "object" + }, + "expose_in_sqllab": { + "description": "Expose this database to SQLLab", + "type": "boolean" + }, + "extra": { + "description": "

JSON string containing extra configuration elements.
1. The engine_params object gets unpacked into the sqlalchemy.create_engine call, while the metadata_params gets unpacked into the sqlalchemy.MetaData call.
2. The metadata_cache_timeout is a cache timeout setting in seconds for metadata fetch of this database. Specify it as \"metadata_cache_timeout\": {\"schema_cache_timeout\": 600, \"table_cache_timeout\": 600}. If unset, cache will not be enabled for the functionality. A timeout of 0 indicates that the cache never expires.
3. The schemas_allowed_for_file_upload is a comma separated list of schemas that CSVs are allowed to upload to. Specify it as \"schemas_allowed_for_file_upload\": [\"public\", \"csv_upload\"]. If database flavor does not support schema or any schema is allowed to be accessed, just leave the list empty
4. The version field is a string specifying the this db's version. This should be used with Presto DBs so that the syntax is correct
5. The allows_virtual_table_explore field is a boolean specifying whether or not the Explore button in SQL Lab results is shown.
6. The disable_data_preview field is a boolean specifying whether or not data preview queries will be run when fetching table metadata in SQL Lab.

", + "type": "string" + }, + "force_ctas_schema": { + "description": "When allowing CREATE TABLE AS option in SQL Lab, this option forces the table to be created in this schema", + "maxLength": 250, + "minLength": 0, + "nullable": true, + "type": "string" + }, + "id": { + "description": "Database ID (for updates)", + "type": "integer" + }, + "impersonate_user": { + "description": "If Presto, all the queries in SQL Lab are going to be executed as the currently logged on user who must have permission to run them.
If Hive and hive.server2.enable.doAs is enabled, will run the queries as service account, but impersonate the currently logged on user via hive.server2.proxy.user property.", + "type": "boolean" + }, + "is_managed_externally": { + "nullable": true, + "type": "boolean" + }, + "masked_encrypted_extra": { + "description": "

JSON string containing additional connection configuration.
This is used to provide connection information for systems like Hive, Presto, and BigQuery, which do not conform to the username:password syntax normally used by SQLAlchemy.

", + "nullable": true, + "type": "string" + }, + "parameters": { + "additionalProperties": {}, + "description": "DB-specific parameters for configuration", + "type": "object" + }, + "parameters_schema": { + "additionalProperties": {}, + "description": "JSONSchema for configuring the database by parameters instead of SQLAlchemy URI", + "type": "object" + }, + "server_cert": { + "description": "

Optional CA_BUNDLE contents to validate HTTPS requests. Only available on certain database engines.

", + "nullable": true, + "type": "string" + }, + "sqlalchemy_uri": { + "description": "

Refer to the SqlAlchemy docs for more information on how to structure your URI.

", + "maxLength": 1024, + "minLength": 1, + "type": "string" + }, + "ssh_tunnel": { + "allOf": [ + { + "$ref": "#/components/schemas/DatabaseSSHTunnel" + } + ], + "nullable": true + }, + "uuid": { + "type": "string" + } + }, + "type": "object" + }, "DatabaseFunctionNamesResponse": { "properties": { "function_names": { @@ -3561,7 +4003,6 @@ "DatabaseRelatedChart": { "properties": { "id": { - "format": "int32", "type": "integer" }, "slice_name": { @@ -3577,7 +4018,6 @@ "properties": { "count": { "description": "Chart count", - "format": "int32", "type": "integer" }, "result": { @@ -3593,7 +4033,6 @@ "DatabaseRelatedDashboard": { "properties": { "id": { - "format": "int32", "type": "integer" }, "json_metadata": { @@ -3612,7 +4051,6 @@ "properties": { "count": { "description": "Dashboard count", - "format": "int32", "type": "integer" }, "result": { @@ -3662,7 +4100,6 @@ "readOnly": true }, "cache_timeout": { - "format": "int32", "nullable": true, "type": "integer" }, @@ -3685,17 +4122,12 @@ "nullable": true, "type": "boolean" }, - "extra": { - "nullable": true, - "type": "string" - }, "force_ctas_schema": { "maxLength": 250, "nullable": true, "type": "string" }, "id": { - "format": "int32", "type": "integer" }, "impersonate_user": { @@ -3705,31 +4137,16 @@ "is_managed_externally": { "type": "boolean" }, - "masked_encrypted_extra": { - "readOnly": true - }, - "parameters": { - "readOnly": true - }, - "parameters_schema": { - "readOnly": true - }, - "server_cert": { - "nullable": true, - "type": "string" - }, - "sqlalchemy_uri": { - "maxLength": 1024, - "type": "string" - }, "uuid": { "format": "uuid", "nullable": true, "type": "string" } }, - "required": ["database_name", "sqlalchemy_uri"], - "type": "object" + "required": [ + "database_name" + ], + "type": "object" }, "DatabaseRestApi.get_list": { "properties": { @@ -3803,7 +4220,6 @@ "type": "string" }, "id": { - "format": "int32", "type": "integer" }, "uuid": { @@ -3812,7 +4228,9 @@ "type": "string" } }, - "required": ["database_name"], + "required": [ + "database_name" + ], "type": "object" }, "DatabaseRestApi.get_list.User": { @@ -3826,7 +4244,10 @@ "type": "string" } }, - "required": ["first_name", "last_name"], + "required": [ + "first_name", + "last_name" + ], "type": "object" }, "DatabaseRestApi.post": { @@ -3853,13 +4274,16 @@ }, "cache_timeout": { "description": "Duration (in seconds) of the caching timeout for charts of this database. A timeout of 0 indicates that the cache never expires. Note this defaults to the global timeout if undefined.", - "format": "int32", "nullable": true, "type": "integer" }, "configuration_method": { "default": "sqlalchemy_form", - "description": "Configuration_method is used on the frontend to inform the backend whether to explode parameters or to provide only a sqlalchemy_uri." + "description": "Configuration_method is used on the frontend to inform the backend whether to explode parameters or to provide only a sqlalchemy_uri.", + "enum": [ + "sqlalchemy_form", + "dynamic_form" + ] }, "database_name": { "description": "A database name to identify this connection.", @@ -3886,7 +4310,7 @@ "type": "string" }, "extra": { - "description": "

JSON string containing extra configuration elements.
1. The engine_params object gets unpacked into the sqlalchemy.create_engine call, while the metadata_params gets unpacked into the sqlalchemy.MetaData call.
2. The metadata_cache_timeout is a cache timeout setting in seconds for metadata fetch of this database. Specify it as \"metadata_cache_timeout\": {\"schema_cache_timeout\": 600, \"table_cache_timeout\": 600}. If unset, cache will not be enabled for the functionality. A timeout of 0 indicates that the cache never expires.
3. The schemas_allowed_for_file_upload is a comma separated list of schemas that CSVs are allowed to upload to. Specify it as \"schemas_allowed_for_file_upload\": [\"public\", \"csv_upload\"]. If database flavor does not support schema or any schema is allowed to be accessed, just leave the list empty
4. The version field is a string specifying the this db's version. This should be used with Presto DBs so that the syntax is correct
5. The allows_virtual_table_explore field is a boolean specifying whether or not the Explore button in SQL Lab results is shown.
6. The disable_data_preview field is a boolean specifying whether or not data preview queries will be run when fetching table metadata in SQL Lab.

", + "description": "

JSON string containing extra configuration elements.
1. The engine_params object gets unpacked into the sqlalchemy.create_engine call, while the metadata_params gets unpacked into the sqlalchemy.MetaData call.
2. The metadata_cache_timeout is a cache timeout setting in seconds for metadata fetch of this database. Specify it as \"metadata_cache_timeout\": {\"schema_cache_timeout\": 600, \"table_cache_timeout\": 600}. If unset, cache will not be enabled for the functionality. A timeout of 0 indicates that the cache never expires.
3. The schemas_allowed_for_file_upload is a comma separated list of schemas that CSVs are allowed to upload to. Specify it as \"schemas_allowed_for_file_upload\": [\"public\", \"csv_upload\"]. If database flavor does not support schema or any schema is allowed to be accessed, just leave the list empty
4. The version field is a string specifying the this db's version. This should be used with Presto DBs so that the syntax is correct
5. The allows_virtual_table_explore field is a boolean specifying whether or not the Explore button in SQL Lab results is shown.
6. The disable_data_preview field is a boolean specifying whether or not data preview queries will be run when fetching table metadata in SQL Lab.

", "type": "string" }, "force_ctas_schema": { @@ -3920,7 +4344,7 @@ "type": "string" }, "sqlalchemy_uri": { - "description": "

Refer to the SqlAlchemy docs for more information on how to structure your URI.

", + "description": "

Refer to the SqlAlchemy docs for more information on how to structure your URI.

", "maxLength": 1024, "minLength": 1, "type": "string" @@ -3937,7 +4361,9 @@ "type": "string" } }, - "required": ["database_name"], + "required": [ + "database_name" + ], "type": "object" }, "DatabaseRestApi.put": { @@ -3964,13 +4390,16 @@ }, "cache_timeout": { "description": "Duration (in seconds) of the caching timeout for charts of this database. A timeout of 0 indicates that the cache never expires. Note this defaults to the global timeout if undefined.", - "format": "int32", "nullable": true, "type": "integer" }, "configuration_method": { "default": "sqlalchemy_form", - "description": "Configuration_method is used on the frontend to inform the backend whether to explode parameters or to provide only a sqlalchemy_uri." + "description": "Configuration_method is used on the frontend to inform the backend whether to explode parameters or to provide only a sqlalchemy_uri.", + "enum": [ + "sqlalchemy_form", + "dynamic_form" + ] }, "database_name": { "description": "A database name to identify this connection.", @@ -3998,7 +4427,7 @@ "type": "string" }, "extra": { - "description": "

JSON string containing extra configuration elements.
1. The engine_params object gets unpacked into the sqlalchemy.create_engine call, while the metadata_params gets unpacked into the sqlalchemy.MetaData call.
2. The metadata_cache_timeout is a cache timeout setting in seconds for metadata fetch of this database. Specify it as \"metadata_cache_timeout\": {\"schema_cache_timeout\": 600, \"table_cache_timeout\": 600}. If unset, cache will not be enabled for the functionality. A timeout of 0 indicates that the cache never expires.
3. The schemas_allowed_for_file_upload is a comma separated list of schemas that CSVs are allowed to upload to. Specify it as \"schemas_allowed_for_file_upload\": [\"public\", \"csv_upload\"]. If database flavor does not support schema or any schema is allowed to be accessed, just leave the list empty
4. The version field is a string specifying the this db's version. This should be used with Presto DBs so that the syntax is correct
5. The allows_virtual_table_explore field is a boolean specifying whether or not the Explore button in SQL Lab results is shown.
6. The disable_data_preview field is a boolean specifying whether or not data preview queries will be run when fetching table metadata in SQL Lab.

", + "description": "

JSON string containing extra configuration elements.
1. The engine_params object gets unpacked into the sqlalchemy.create_engine call, while the metadata_params gets unpacked into the sqlalchemy.MetaData call.
2. The metadata_cache_timeout is a cache timeout setting in seconds for metadata fetch of this database. Specify it as \"metadata_cache_timeout\": {\"schema_cache_timeout\": 600, \"table_cache_timeout\": 600}. If unset, cache will not be enabled for the functionality. A timeout of 0 indicates that the cache never expires.
3. The schemas_allowed_for_file_upload is a comma separated list of schemas that CSVs are allowed to upload to. Specify it as \"schemas_allowed_for_file_upload\": [\"public\", \"csv_upload\"]. If database flavor does not support schema or any schema is allowed to be accessed, just leave the list empty
4. The version field is a string specifying the this db's version. This should be used with Presto DBs so that the syntax is correct
5. The allows_virtual_table_explore field is a boolean specifying whether or not the Explore button in SQL Lab results is shown.
6. The disable_data_preview field is a boolean specifying whether or not data preview queries will be run when fetching table metadata in SQL Lab.

", "type": "string" }, "force_ctas_schema": { @@ -4032,7 +4461,7 @@ "type": "string" }, "sqlalchemy_uri": { - "description": "

Refer to the SqlAlchemy docs for more information on how to structure your URI.

", + "description": "

Refer to the SqlAlchemy docs for more information on how to structure your URI.

", "maxLength": 1024, "minLength": 0, "type": "string" @@ -4044,6 +4473,9 @@ } ], "nullable": true + }, + "uuid": { + "type": "string" } }, "type": "object" @@ -4052,7 +4484,6 @@ "properties": { "id": { "description": "SSH Tunnel ID (for updates)", - "format": "int32", "nullable": true, "type": "integer" }, @@ -4069,7 +4500,6 @@ "type": "string" }, "server_port": { - "format": "int32", "type": "integer" }, "username": { @@ -4111,7 +4541,11 @@ "properties": { "configuration_method": { "default": "sqlalchemy_form", - "description": "Configuration_method is used on the frontend to inform the backend whether to explode parameters or to provide only a sqlalchemy_uri." + "description": "Configuration_method is used on the frontend to inform the backend whether to explode parameters or to provide only a sqlalchemy_uri.", + "enum": [ + "sqlalchemy_form", + "dynamic_form" + ] }, "database_name": { "description": "A database name to identify this connection.", @@ -4131,7 +4565,7 @@ "type": "string" }, "extra": { - "description": "

JSON string containing extra configuration elements.
1. The engine_params object gets unpacked into the sqlalchemy.create_engine call, while the metadata_params gets unpacked into the sqlalchemy.MetaData call.
2. The metadata_cache_timeout is a cache timeout setting in seconds for metadata fetch of this database. Specify it as \"metadata_cache_timeout\": {\"schema_cache_timeout\": 600, \"table_cache_timeout\": 600}. If unset, cache will not be enabled for the functionality. A timeout of 0 indicates that the cache never expires.
3. The schemas_allowed_for_file_upload is a comma separated list of schemas that CSVs are allowed to upload to. Specify it as \"schemas_allowed_for_file_upload\": [\"public\", \"csv_upload\"]. If database flavor does not support schema or any schema is allowed to be accessed, just leave the list empty
4. The version field is a string specifying the this db's version. This should be used with Presto DBs so that the syntax is correct
5. The allows_virtual_table_explore field is a boolean specifying whether or not the Explore button in SQL Lab results is shown.
6. The disable_data_preview field is a boolean specifying whether or not data preview queries will be run when fetching table metadata in SQL Lab.

", + "description": "

JSON string containing extra configuration elements.
1. The engine_params object gets unpacked into the sqlalchemy.create_engine call, while the metadata_params gets unpacked into the sqlalchemy.MetaData call.
2. The metadata_cache_timeout is a cache timeout setting in seconds for metadata fetch of this database. Specify it as \"metadata_cache_timeout\": {\"schema_cache_timeout\": 600, \"table_cache_timeout\": 600}. If unset, cache will not be enabled for the functionality. A timeout of 0 indicates that the cache never expires.
3. The schemas_allowed_for_file_upload is a comma separated list of schemas that CSVs are allowed to upload to. Specify it as \"schemas_allowed_for_file_upload\": [\"public\", \"csv_upload\"]. If database flavor does not support schema or any schema is allowed to be accessed, just leave the list empty
4. The version field is a string specifying the this db's version. This should be used with Presto DBs so that the syntax is correct
5. The allows_virtual_table_explore field is a boolean specifying whether or not the Explore button in SQL Lab results is shown.
6. The disable_data_preview field is a boolean specifying whether or not data preview queries will be run when fetching table metadata in SQL Lab.

", "type": "string" }, "impersonate_user": { @@ -4154,7 +4588,7 @@ "type": "string" }, "sqlalchemy_uri": { - "description": "

Refer to the SqlAlchemy docs for more information on how to structure your URI.

", + "description": "

Refer to the SqlAlchemy docs for more information on how to structure your URI.

", "maxLength": 1024, "minLength": 1, "type": "string" @@ -4180,7 +4614,11 @@ "type": "object" }, "configuration_method": { - "description": "Configuration_method is used on the frontend to inform the backend whether to explode parameters or to provide only a sqlalchemy_uri." + "description": "Configuration_method is used on the frontend to inform the backend whether to explode parameters or to provide only a sqlalchemy_uri.", + "enum": [ + "sqlalchemy_form", + "dynamic_form" + ] }, "database_name": { "description": "A database name to identify this connection.", @@ -4199,12 +4637,11 @@ "type": "string" }, "extra": { - "description": "

JSON string containing extra configuration elements.
1. The engine_params object gets unpacked into the sqlalchemy.create_engine call, while the metadata_params gets unpacked into the sqlalchemy.MetaData call.
2. The metadata_cache_timeout is a cache timeout setting in seconds for metadata fetch of this database. Specify it as \"metadata_cache_timeout\": {\"schema_cache_timeout\": 600, \"table_cache_timeout\": 600}. If unset, cache will not be enabled for the functionality. A timeout of 0 indicates that the cache never expires.
3. The schemas_allowed_for_file_upload is a comma separated list of schemas that CSVs are allowed to upload to. Specify it as \"schemas_allowed_for_file_upload\": [\"public\", \"csv_upload\"]. If database flavor does not support schema or any schema is allowed to be accessed, just leave the list empty
4. The version field is a string specifying the this db's version. This should be used with Presto DBs so that the syntax is correct
5. The allows_virtual_table_explore field is a boolean specifying whether or not the Explore button in SQL Lab results is shown.
6. The disable_data_preview field is a boolean specifying whether or not data preview queries will be run when fetching table metadata in SQL Lab.

", + "description": "

JSON string containing extra configuration elements.
1. The engine_params object gets unpacked into the sqlalchemy.create_engine call, while the metadata_params gets unpacked into the sqlalchemy.MetaData call.
2. The metadata_cache_timeout is a cache timeout setting in seconds for metadata fetch of this database. Specify it as \"metadata_cache_timeout\": {\"schema_cache_timeout\": 600, \"table_cache_timeout\": 600}. If unset, cache will not be enabled for the functionality. A timeout of 0 indicates that the cache never expires.
3. The schemas_allowed_for_file_upload is a comma separated list of schemas that CSVs are allowed to upload to. Specify it as \"schemas_allowed_for_file_upload\": [\"public\", \"csv_upload\"]. If database flavor does not support schema or any schema is allowed to be accessed, just leave the list empty
4. The version field is a string specifying the this db's version. This should be used with Presto DBs so that the syntax is correct
5. The allows_virtual_table_explore field is a boolean specifying whether or not the Explore button in SQL Lab results is shown.
6. The disable_data_preview field is a boolean specifying whether or not data preview queries will be run when fetching table metadata in SQL Lab.

", "type": "string" }, "id": { "description": "Database ID (for updates)", - "format": "int32", "nullable": true, "type": "integer" }, @@ -4230,14 +4667,16 @@ "type": "string" } }, - "required": ["configuration_method", "engine"], + "required": [ + "configuration_method", + "engine" + ], "type": "object" }, "Dataset": { "properties": { "cache_timeout": { "description": "Duration (in seconds) of the caching timeout for this dataset.", - "format": "int32", "type": "integer" }, "column_formats": { @@ -4251,6 +4690,10 @@ }, "type": "array" }, + "currency_formats": { + "description": "Currency formats.", + "type": "object" + }, "database": { "description": "Database associated with the dataset.", "type": "object" @@ -4303,7 +4746,6 @@ }, "id": { "description": "Dataset ID.", - "format": "int32", "type": "integer" }, "is_sqllab_view": { @@ -4327,7 +4769,6 @@ }, "offset": { "description": "Dataset offset.", - "format": "int32", "type": "integer" }, "order_by_choices": { @@ -4343,7 +4784,6 @@ "owners": { "description": "List of owners identifiers", "items": { - "format": "int32", "type": "integer" }, "type": "array" @@ -4401,6 +4841,60 @@ }, "type": "object" }, + "DatasetCacheWarmUpRequestSchema": { + "properties": { + "dashboard_id": { + "description": "The ID of the dashboard to get filters for when warming cache", + "type": "integer" + }, + "db_name": { + "description": "The name of the database where the table is located", + "type": "string" + }, + "extra_filters": { + "description": "Extra filters to apply when warming up cache", + "type": "string" + }, + "table_name": { + "description": "The name of the table to warm up cache for", + "type": "string" + } + }, + "required": [ + "db_name", + "table_name" + ], + "type": "object" + }, + "DatasetCacheWarmUpResponseSchema": { + "properties": { + "result": { + "description": "A list of each chart's warmup status and errors if any", + "items": { + "$ref": "#/components/schemas/DatasetCacheWarmUpResponseSingle" + }, + "type": "array" + } + }, + "type": "object" + }, + "DatasetCacheWarmUpResponseSingle": { + "properties": { + "chart_id": { + "description": "The ID of the chart the status belongs to", + "type": "integer" + }, + "viz_error": { + "description": "Error that occurred when warming cache for chart", + "type": "string" + }, + "viz_status": { + "description": "Status of the underlying query for the viz", + "type": "string" + } + }, + "type": "object" + }, "DatasetColumnsPut": { "properties": { "advanced_data_type": { @@ -4433,13 +4927,14 @@ "type": "boolean" }, "id": { - "format": "int32", "type": "integer" }, "is_active": { + "nullable": true, "type": "boolean" }, "is_dttm": { + "nullable": true, "type": "boolean" }, "python_date_format": { @@ -4462,13 +4957,14 @@ "type": "string" } }, - "required": ["column_name"], + "required": [ + "column_name" + ], "type": "object" }, "DatasetColumnsRestApi.get": { "properties": { "id": { - "format": "int32", "type": "integer" } }, @@ -4477,7 +4973,6 @@ "DatasetColumnsRestApi.get_list": { "properties": { "id": { - "format": "int32", "type": "integer" } }, @@ -4486,7 +4981,6 @@ "DatasetColumnsRestApi.post": { "properties": { "id": { - "format": "int32", "type": "integer" } }, @@ -4495,7 +4989,6 @@ "DatasetColumnsRestApi.put": { "properties": { "id": { - "format": "int32", "type": "integer" } }, @@ -4504,7 +4997,6 @@ "DatasetDuplicateSchema": { "properties": { "base_model_id": { - "format": "int32", "type": "integer" }, "table_name": { @@ -4513,13 +5005,15 @@ "type": "string" } }, - "required": ["base_model_id", "table_name"], + "required": [ + "base_model_id", + "table_name" + ], "type": "object" }, "DatasetMetricRestApi.get": { "properties": { "id": { - "format": "int32", "type": "integer" } }, @@ -4528,7 +5022,6 @@ "DatasetMetricRestApi.get_list": { "properties": { "id": { - "format": "int32", "type": "integer" } }, @@ -4537,7 +5030,6 @@ "DatasetMetricRestApi.post": { "properties": { "id": { - "format": "int32", "type": "integer" } }, @@ -4546,7 +5038,6 @@ "DatasetMetricRestApi.put": { "properties": { "id": { - "format": "int32", "type": "integer" } }, @@ -4554,6 +5045,12 @@ }, "DatasetMetricsPut": { "properties": { + "currency": { + "maxLength": 128, + "minLength": 1, + "nullable": true, + "type": "string" + }, "d3format": { "maxLength": 128, "minLength": 1, @@ -4572,7 +5069,6 @@ "type": "string" }, "id": { - "format": "int32", "type": "integer" }, "metric_name": { @@ -4600,13 +5096,15 @@ "type": "string" } }, - "required": ["expression", "metric_name"], + "required": [ + "expression", + "metric_name" + ], "type": "object" }, "DatasetRelatedChart": { "properties": { "id": { - "format": "int32", "type": "integer" }, "slice_name": { @@ -4622,7 +5120,6 @@ "properties": { "count": { "description": "Chart count", - "format": "int32", "type": "integer" }, "result": { @@ -4638,7 +5135,6 @@ "DatasetRelatedDashboard": { "properties": { "id": { - "format": "int32", "type": "integer" }, "json_metadata": { @@ -4657,7 +5153,6 @@ "properties": { "count": { "description": "Dashboard count", - "format": "int32", "type": "integer" }, "result": { @@ -4684,12 +5179,11 @@ "DatasetRestApi.get": { "properties": { "cache_timeout": { - "format": "int32", "nullable": true, "type": "integer" }, "changed_by": { - "$ref": "#/components/schemas/DatasetRestApi.get.User" + "$ref": "#/components/schemas/DatasetRestApi.get.User2" }, "changed_on": { "format": "date-time", @@ -4699,11 +5193,14 @@ "changed_on_humanized": { "readOnly": true }, + "column_formats": { + "readOnly": true + }, "columns": { "$ref": "#/components/schemas/DatasetRestApi.get.TableColumn" }, "created_by": { - "$ref": "#/components/schemas/DatasetRestApi.get.User1" + "$ref": "#/components/schemas/DatasetRestApi.get.User" }, "created_on": { "format": "date-time", @@ -4713,9 +5210,15 @@ "created_on_humanized": { "readOnly": true }, + "currency_formats": { + "readOnly": true + }, "database": { "$ref": "#/components/schemas/DatasetRestApi.get.Database" }, + "datasource_name": { + "readOnly": true + }, "datasource_type": { "readOnly": true }, @@ -4739,8 +5242,10 @@ "nullable": true, "type": "boolean" }, + "granularity_sqla": { + "readOnly": true + }, "id": { - "format": "int32", "type": "integer" }, "is_managed_externally": { @@ -4761,13 +5266,18 @@ "metrics": { "$ref": "#/components/schemas/DatasetRestApi.get.SqlMetric" }, + "name": { + "readOnly": true + }, "offset": { - "format": "int32", "nullable": true, "type": "integer" }, + "order_by_choices": { + "readOnly": true + }, "owners": { - "$ref": "#/components/schemas/DatasetRestApi.get.User2" + "$ref": "#/components/schemas/DatasetRestApi.get.User1" }, "schema": { "maxLength": 255, @@ -4789,11 +5299,25 @@ "nullable": true, "type": "string" }, + "time_grain_sqla": { + "readOnly": true + }, + "uid": { + "readOnly": true + }, "url": { "readOnly": true + }, + "verbose_map": { + "readOnly": true } }, - "required": ["columns", "database", "metrics", "table_name"], + "required": [ + "columns", + "database", + "metrics", + "table_name" + ], "type": "object" }, "DatasetRestApi.get.Database": { @@ -4806,11 +5330,12 @@ "type": "string" }, "id": { - "format": "int32", "type": "integer" } }, - "required": ["database_name"], + "required": [ + "database_name" + ], "type": "object" }, "DatasetRestApi.get.SqlMetric": { @@ -4825,6 +5350,11 @@ "nullable": true, "type": "string" }, + "currency": { + "maxLength": 128, + "nullable": true, + "type": "string" + }, "d3format": { "maxLength": 128, "nullable": true, @@ -4842,7 +5372,6 @@ "type": "string" }, "id": { - "format": "int32", "type": "integer" }, "metric_name": { @@ -4864,7 +5393,10 @@ "type": "string" } }, - "required": ["expression", "metric_name"], + "required": [ + "expression", + "metric_name" + ], "type": "object" }, "DatasetRestApi.get.TableColumn": { @@ -4909,7 +5441,6 @@ "type": "boolean" }, "id": { - "format": "int32", "type": "integer" }, "is_active": { @@ -4943,7 +5474,9 @@ "type": "string" } }, - "required": ["column_name"], + "required": [ + "column_name" + ], "type": "object" }, "DatasetRestApi.get.User": { @@ -4957,7 +5490,10 @@ "type": "string" } }, - "required": ["first_name", "last_name"], + "required": [ + "first_name", + "last_name" + ], "type": "object" }, "DatasetRestApi.get.User1": { @@ -4966,12 +5502,18 @@ "maxLength": 64, "type": "string" }, + "id": { + "type": "integer" + }, "last_name": { "maxLength": 64, "type": "string" } }, - "required": ["first_name", "last_name"], + "required": [ + "first_name", + "last_name" + ], "type": "object" }, "DatasetRestApi.get.User2": { @@ -4980,33 +5522,25 @@ "maxLength": 64, "type": "string" }, - "id": { - "format": "int32", - "type": "integer" - }, "last_name": { "maxLength": 64, "type": "string" - }, - "username": { - "maxLength": 64, - "type": "string" } }, - "required": ["first_name", "last_name", "username"], + "required": [ + "first_name", + "last_name" + ], "type": "object" }, "DatasetRestApi.get_list": { "properties": { "changed_by": { - "$ref": "#/components/schemas/DatasetRestApi.get_list.User" + "$ref": "#/components/schemas/DatasetRestApi.get_list.User1" }, "changed_by_name": { "readOnly": true }, - "changed_by_url": { - "readOnly": true - }, "changed_on_delta_humanized": { "readOnly": true }, @@ -5035,14 +5569,13 @@ "type": "string" }, "id": { - "format": "int32", "type": "integer" }, "kind": { "readOnly": true }, "owners": { - "$ref": "#/components/schemas/DatasetRestApi.get_list.User1" + "$ref": "#/components/schemas/DatasetRestApi.get_list.User" }, "schema": { "maxLength": 255, @@ -5058,7 +5591,10 @@ "type": "string" } }, - "required": ["database", "table_name"], + "required": [ + "database", + "table_name" + ], "type": "object" }, "DatasetRestApi.get_list.Database": { @@ -5068,11 +5604,12 @@ "type": "string" }, "id": { - "format": "int32", "type": "integer" } }, - "required": ["database_name"], + "required": [ + "database_name" + ], "type": "object" }, "DatasetRestApi.get_list.User": { @@ -5081,12 +5618,18 @@ "maxLength": 64, "type": "string" }, - "username": { + "id": { + "type": "integer" + }, + "last_name": { "maxLength": 64, "type": "string" } }, - "required": ["first_name", "username"], + "required": [ + "first_name", + "last_name" + ], "type": "object" }, "DatasetRestApi.get_list.User1": { @@ -5095,26 +5638,20 @@ "maxLength": 64, "type": "string" }, - "id": { - "format": "int32", - "type": "integer" - }, "last_name": { "maxLength": 64, "type": "string" - }, - "username": { - "maxLength": 64, - "type": "string" } }, - "required": ["first_name", "last_name", "username"], + "required": [ + "first_name", + "last_name" + ], "type": "object" }, "DatasetRestApi.post": { "properties": { "database": { - "format": "int32", "type": "integer" }, "external_url": { @@ -5127,7 +5664,6 @@ }, "owners": { "items": { - "format": "int32", "type": "integer" }, "type": "array" @@ -5135,6 +5671,7 @@ "schema": { "maxLength": 250, "minLength": 0, + "nullable": true, "type": "string" }, "sql": { @@ -5147,13 +5684,15 @@ "type": "string" } }, - "required": ["database", "table_name"], + "required": [ + "database", + "table_name" + ], "type": "object" }, "DatasetRestApi.put": { "properties": { "cache_timeout": { - "format": "int32", "nullable": true, "type": "integer" }, @@ -5164,7 +5703,6 @@ "type": "array" }, "database_id": { - "format": "int32", "type": "integer" }, "default_endpoint": { @@ -5212,13 +5750,11 @@ "type": "array" }, "offset": { - "format": "int32", "nullable": true, "type": "integer" }, "owners": { "items": { - "format": "int32", "type": "integer" }, "type": "array" @@ -5273,14 +5809,15 @@ "type": "string" } }, - "required": ["datasource_type"], + "required": [ + "datasource_type" + ], "type": "object" }, "DistincResponseSchema": { "properties": { "count": { "description": "The total number of distinct values", - "format": "int32", "type": "integer" }, "result": { @@ -5310,7 +5847,9 @@ "type": "array" } }, - "required": ["allowed_domains"], + "required": [ + "allowed_domains" + ], "type": "object" }, "EmbeddedDashboardResponseSchema": { @@ -5322,7 +5861,7 @@ "type": "array" }, "changed_by": { - "$ref": "#/components/schemas/User" + "$ref": "#/components/schemas/User1" }, "changed_on": { "format": "date-time", @@ -5373,6 +5912,32 @@ }, "type": "object" }, + "EstimateQueryCostSchema": { + "properties": { + "database_id": { + "description": "The database id", + "type": "integer" + }, + "schema": { + "description": "The database schema", + "nullable": true, + "type": "string" + }, + "sql": { + "description": "The SQL query to estimate", + "type": "string" + }, + "template_params": { + "description": "The SQL query template params", + "type": "object" + } + }, + "required": [ + "database_id", + "sql" + ], + "type": "object" + }, "ExecutePayloadSchema": { "properties": { "client_id": { @@ -5384,7 +5949,6 @@ "type": "string" }, "database_id": { - "format": "int32", "type": "integer" }, "expand_data": { @@ -5396,7 +5960,6 @@ "type": "boolean" }, "queryLimit": { - "format": "int32", "nullable": true, "type": "integer" }, @@ -5432,7 +5995,10 @@ "type": "string" } }, - "required": ["database_id", "sql"], + "required": [ + "database_id", + "sql" + ], "type": "object" }, "ExploreContextSchema": { @@ -5454,7 +6020,7 @@ }, "type": "object" }, - "ExplorePermalinkPostSchema": { + "ExplorePermalinkStateSchema": { "properties": { "formData": { "description": "Chart form data", @@ -5470,13 +6036,14 @@ "type": "array" } }, - "required": ["formData"], + "required": [ + "formData" + ], "type": "object" }, "FilterSetRestApi.get": { "properties": { "dashboard_id": { - "format": "int32", "nullable": true, "type": "integer" }, @@ -5485,7 +6052,6 @@ "type": "string" }, "id": { - "format": "int32", "type": "integer" }, "name": { @@ -5493,7 +6059,6 @@ "type": "string" }, "owner_id": { - "format": "int32", "type": "integer" }, "owner_type": { @@ -5504,13 +6069,16 @@ "readOnly": true } }, - "required": ["name", "owner_id", "owner_type"], + "required": [ + "name", + "owner_id", + "owner_type" + ], "type": "object" }, "FilterSetRestApi.get_list": { "properties": { "changed_by_fk": { - "format": "int32", "nullable": true, "type": "integer" }, @@ -5520,7 +6088,6 @@ "type": "string" }, "created_by_fk": { - "format": "int32", "nullable": true, "type": "integer" }, @@ -5530,7 +6097,6 @@ "type": "string" }, "dashboard_id": { - "format": "int32", "nullable": true, "type": "integer" }, @@ -5539,7 +6105,6 @@ "type": "string" }, "id": { - "format": "int32", "type": "integer" }, "name": { @@ -5547,7 +6112,6 @@ "type": "string" }, "owner_id": { - "format": "int32", "type": "integer" }, "owner_type": { @@ -5558,7 +6122,11 @@ "readOnly": true } }, - "required": ["name", "owner_id", "owner_type"], + "required": [ + "name", + "owner_id", + "owner_type" + ], "type": "object" }, "FilterSetRestApi.post": { @@ -5578,15 +6146,21 @@ "type": "string" }, "owner_id": { - "format": "int32", "type": "integer" }, "owner_type": { - "enum": ["User", "Dashboard"], + "enum": [ + "User", + "Dashboard" + ], "type": "string" } }, - "required": ["json_metadata", "name", "owner_type"], + "required": [ + "json_metadata", + "name", + "owner_type" + ], "type": "object" }, "FilterSetRestApi.put": { @@ -5605,7 +6179,9 @@ "type": "string" }, "owner_type": { - "enum": ["Dashboard"], + "enum": [ + "Dashboard" + ], "type": "string" } }, @@ -5615,12 +6191,10 @@ "properties": { "chart_id": { "description": "The chart ID", - "format": "int32", "type": "integer" }, "datasource_id": { "description": "The datasource ID", - "format": "int32", "type": "integer" }, "datasource_type": { @@ -5640,19 +6214,21 @@ "type": "string" } }, - "required": ["datasource_id", "datasource_type", "form_data"], + "required": [ + "datasource_id", + "datasource_type", + "form_data" + ], "type": "object" }, "FormDataPutSchema": { "properties": { "chart_id": { "description": "The chart ID", - "format": "int32", "type": "integer" }, "datasource_id": { "description": "The datasource ID", - "format": "int32", "type": "integer" }, "datasource_type": { @@ -5672,7 +6248,11 @@ "type": "string" } }, - "required": ["datasource_id", "datasource_type", "form_data"], + "required": [ + "datasource_id", + "datasource_type", + "form_data" + ], "type": "object" }, "GetFavStarIdsSchema": { @@ -5687,6 +6267,34 @@ }, "type": "object" }, + "GetOrCreateDatasetSchema": { + "properties": { + "database_id": { + "description": "ID of database table belongs to", + "type": "integer" + }, + "schema": { + "description": "The schema the table belongs to", + "maxLength": 250, + "minLength": 0, + "nullable": true, + "type": "string" + }, + "table_name": { + "description": "Name of table", + "type": "string" + }, + "template_params": { + "description": "Template params for the table", + "type": "string" + } + }, + "required": [ + "database_id", + "table_name" + ], + "type": "object" + }, "GuestTokenCreate": { "properties": { "resources": { @@ -5702,10 +6310,13 @@ "type": "array" }, "user": { - "$ref": "#/components/schemas/User1" + "$ref": "#/components/schemas/User2" } }, - "required": ["resources", "rls"], + "required": [ + "resources", + "rls" + ], "type": "object" }, "LogRestApi.get": { @@ -5716,7 +6327,6 @@ "type": "string" }, "dashboard_id": { - "format": "int32", "nullable": true, "type": "integer" }, @@ -5726,7 +6336,6 @@ "type": "string" }, "duration_ms": { - "format": "int32", "nullable": true, "type": "integer" }, @@ -5740,7 +6349,6 @@ "type": "string" }, "slice_id": { - "format": "int32", "nullable": true, "type": "integer" }, @@ -5748,7 +6356,6 @@ "$ref": "#/components/schemas/LogRestApi.get.User" }, "user_id": { - "format": "int32", "nullable": true, "type": "integer" } @@ -5762,7 +6369,9 @@ "type": "string" } }, - "required": ["username"], + "required": [ + "username" + ], "type": "object" }, "LogRestApi.get_list": { @@ -5773,7 +6382,6 @@ "type": "string" }, "dashboard_id": { - "format": "int32", "nullable": true, "type": "integer" }, @@ -5783,7 +6391,6 @@ "type": "string" }, "duration_ms": { - "format": "int32", "nullable": true, "type": "integer" }, @@ -5797,7 +6404,6 @@ "type": "string" }, "slice_id": { - "format": "int32", "nullable": true, "type": "integer" }, @@ -5805,7 +6411,6 @@ "$ref": "#/components/schemas/LogRestApi.get_list.User" }, "user_id": { - "format": "int32", "nullable": true, "type": "integer" } @@ -5819,13 +6424,14 @@ "type": "string" } }, - "required": ["username"], + "required": [ + "username" + ], "type": "object" }, "LogRestApi.post": { "properties": { "id": { - "format": "int32", "type": "integer" } }, @@ -5877,7 +6483,6 @@ "$ref": "#/components/schemas/QueryResult" }, "query_id": { - "format": "int32", "type": "integer" }, "selected_columns": { @@ -5923,16 +6528,13 @@ "type": "string" }, "id": { - "format": "int32", "type": "integer" }, "limit": { - "format": "int32", "nullable": true, "type": "integer" }, "progress": { - "format": "int32", "nullable": true, "type": "integer" }, @@ -5942,7 +6544,6 @@ "type": "string" }, "rows": { - "format": "int32", "nullable": true, "type": "integer" }, @@ -6004,13 +6605,15 @@ "readOnly": true } }, - "required": ["client_id", "database"], + "required": [ + "client_id", + "database" + ], "type": "object" }, "QueryRestApi.get.Database": { "properties": { "id": { - "format": "int32", "type": "integer" } }, @@ -6026,18 +6629,15 @@ "$ref": "#/components/schemas/Database1" }, "end_time": { - "format": "float", "type": "number" }, "executed_sql": { "type": "string" }, "id": { - "format": "int32", "type": "integer" }, "rows": { - "format": "int32", "type": "integer" }, "schema": { @@ -6050,7 +6650,6 @@ "readOnly": true }, "start_time": { - "format": "float", "type": "number" }, "status": { @@ -6074,7 +6673,6 @@ "QueryRestApi.post": { "properties": { "id": { - "format": "int32", "type": "integer" } }, @@ -6083,7 +6681,6 @@ "QueryRestApi.put": { "properties": { "id": { - "format": "int32", "type": "integer" } }, @@ -6091,11 +6688,8 @@ }, "QueryResult": { "properties": { - "changedOn": { - "format": "date-time", - "type": "string" - }, "changed_on": { + "format": "date-time", "type": "string" }, "ctas": { @@ -6105,11 +6699,9 @@ "type": "string" }, "dbId": { - "format": "int32", "type": "integer" }, "endDttm": { - "format": "float", "type": "number" }, "errorMessage": { @@ -6126,32 +6718,27 @@ "type": "string" }, "limit": { - "format": "int32", "type": "integer" }, "limitingFactor": { "type": "string" }, "progress": { - "format": "int32", "type": "integer" }, "queryId": { - "format": "int32", "type": "integer" }, "resultsKey": { "type": "string" }, "rows": { - "format": "int32", "type": "integer" }, "schema": { "type": "string" }, "serverId": { - "format": "int32", "type": "integer" }, "sql": { @@ -6161,7 +6748,6 @@ "type": "string" }, "startDttm": { - "format": "float", "type": "number" }, "state": { @@ -6186,37 +6772,230 @@ "type": "string" }, "userId": { - "format": "int32", "type": "integer" } }, "type": "object" }, - "RecentActivity": { + "RLSRestApi.get": { "properties": { - "action": { - "description": "Action taken describing type of activity", + "clause": { + "description": "clause_description", "type": "string" }, - "item_title": { - "description": "Title of item", + "description": { + "description": "description_description", "type": "string" }, - "item_type": { - "description": "Type of item, e.g. slice or dashboard", + "filter_type": { + "description": "filter_type_description", + "enum": [ + "Regular", + "Base" + ], "type": "string" }, - "item_url": { - "description": "URL to item", + "group_key": { + "description": "group_key_description", "type": "string" }, - "time": { - "description": "Time of activity, in epoch milliseconds", - "format": "float", - "type": "number" + "id": { + "description": "id_description", + "type": "integer" }, - "time_delta_humanized": { - "description": "Human-readable description of how long ago activity took place", + "name": { + "description": "name_description", + "type": "string" + }, + "roles": { + "items": { + "$ref": "#/components/schemas/Roles1" + }, + "type": "array" + }, + "tables": { + "items": { + "$ref": "#/components/schemas/Tables" + }, + "type": "array" + } + }, + "type": "object" + }, + "RLSRestApi.get_list": { + "properties": { + "changed_on_delta_humanized": { + "readOnly": true + }, + "clause": { + "description": "clause_description", + "type": "string" + }, + "description": { + "description": "description_description", + "type": "string" + }, + "filter_type": { + "description": "filter_type_description", + "enum": [ + "Regular", + "Base" + ], + "type": "string" + }, + "group_key": { + "description": "group_key_description", + "type": "string" + }, + "id": { + "description": "id_description", + "type": "integer" + }, + "name": { + "description": "name_description", + "type": "string" + }, + "roles": { + "items": { + "$ref": "#/components/schemas/Roles1" + }, + "type": "array" + }, + "tables": { + "items": { + "$ref": "#/components/schemas/Tables" + }, + "type": "array" + } + }, + "type": "object" + }, + "RLSRestApi.post": { + "properties": { + "clause": { + "description": "clause_description", + "type": "string" + }, + "description": { + "description": "description_description", + "nullable": true, + "type": "string" + }, + "filter_type": { + "description": "filter_type_description", + "enum": [ + "Regular", + "Base" + ], + "type": "string" + }, + "group_key": { + "description": "group_key_description", + "nullable": true, + "type": "string" + }, + "name": { + "description": "name_description", + "maxLength": 255, + "minLength": 1, + "type": "string" + }, + "roles": { + "description": "roles_description", + "items": { + "type": "integer" + }, + "type": "array" + }, + "tables": { + "description": "tables_description", + "items": { + "type": "integer" + }, + "minItems": 1, + "type": "array" + } + }, + "required": [ + "clause", + "filter_type", + "name", + "roles", + "tables" + ], + "type": "object" + }, + "RLSRestApi.put": { + "properties": { + "clause": { + "description": "clause_description", + "type": "string" + }, + "description": { + "description": "description_description", + "nullable": true, + "type": "string" + }, + "filter_type": { + "description": "filter_type_description", + "enum": [ + "Regular", + "Base" + ], + "type": "string" + }, + "group_key": { + "description": "group_key_description", + "nullable": true, + "type": "string" + }, + "name": { + "description": "name_description", + "maxLength": 255, + "minLength": 1, + "type": "string" + }, + "roles": { + "description": "roles_description", + "items": { + "type": "integer" + }, + "type": "array" + }, + "tables": { + "description": "tables_description", + "items": { + "type": "integer" + }, + "type": "array" + } + }, + "type": "object" + }, + "RecentActivity": { + "properties": { + "action": { + "description": "Action taken describing type of activity", + "type": "string" + }, + "item_title": { + "description": "Title of item", + "type": "string" + }, + "item_type": { + "description": "Type of item, e.g. slice or dashboard", + "type": "string" + }, + "item_url": { + "description": "URL to item", + "type": "string" + }, + "time": { + "description": "Time of activity, in epoch milliseconds", + "type": "number" + }, + "time_delta_humanized": { + "description": "Human-readable description of how long ago activity took place.", "type": "string" } }, @@ -6254,11 +7033,10 @@ }, "time": { "description": "Time of activity, in epoch milliseconds", - "format": "float", "type": "number" }, "time_delta_humanized": { - "description": "Human-readable description of how long ago activity took place", + "description": "Human-readable description of how long ago activity took place.", "type": "string" } }, @@ -6268,7 +7046,6 @@ "properties": { "count": { "description": "The total number of related values", - "format": "int32", "type": "integer" }, "result": { @@ -6292,7 +7069,6 @@ }, "value": { "description": "The related item identifier", - "format": "int32", "type": "integer" } }, @@ -6310,7 +7086,6 @@ "type": "string" }, "id": { - "format": "int32", "type": "integer" }, "scheduled_dttm": { @@ -6332,7 +7107,6 @@ "type": "string" }, "value": { - "format": "float", "nullable": true, "type": "number" }, @@ -6341,7 +7115,10 @@ "type": "string" } }, - "required": ["scheduled_dttm", "state"], + "required": [ + "scheduled_dttm", + "state" + ], "type": "object" }, "ReportExecutionLogRestApi.get_list": { @@ -6356,7 +7133,6 @@ "type": "string" }, "id": { - "format": "int32", "type": "integer" }, "scheduled_dttm": { @@ -6378,7 +7154,6 @@ "type": "string" }, "value": { - "format": "float", "nullable": true, "type": "number" }, @@ -6387,13 +7162,15 @@ "type": "string" } }, - "required": ["scheduled_dttm", "state"], + "required": [ + "scheduled_dttm", + "state" + ], "type": "object" }, "ReportExecutionLogRestApi.post": { "properties": { "id": { - "format": "int32", "type": "integer" } }, @@ -6402,7 +7179,6 @@ "ReportExecutionLogRestApi.put": { "properties": { "id": { - "format": "int32", "type": "integer" } }, @@ -6415,11 +7191,16 @@ }, "type": { "description": "The recipient type, check spec for valid options", - "enum": ["Email", "Slack"], + "enum": [ + "Email", + "Slack" + ], "type": "string" } }, - "required": ["type"], + "required": [ + "type" + ], "type": "object" }, "ReportRecipientConfigJSON": { @@ -6452,6 +7233,10 @@ "maxLength": 1000, "type": "string" }, + "custom_width": { + "nullable": true, + "type": "integer" + }, "dashboard": { "$ref": "#/components/schemas/ReportScheduleRestApi.get.Dashboard" }, @@ -6470,12 +7255,10 @@ "type": "boolean" }, "grace_period": { - "format": "int32", "nullable": true, "type": "integer" }, "id": { - "format": "int32", "type": "integer" }, "last_eval_dttm": { @@ -6489,7 +7272,6 @@ "type": "string" }, "last_value": { - "format": "float", "nullable": true, "type": "number" }, @@ -6498,7 +7280,6 @@ "type": "string" }, "log_retention": { - "format": "int32", "nullable": true, "type": "integer" }, @@ -6539,12 +7320,16 @@ "type": "string" }, "working_timeout": { - "format": "int32", "nullable": true, "type": "integer" } }, - "required": ["crontab", "name", "recipients", "type"], + "required": [ + "crontab", + "name", + "recipients", + "type" + ], "type": "object" }, "ReportScheduleRestApi.get.Dashboard": { @@ -6555,7 +7340,6 @@ "type": "string" }, "id": { - "format": "int32", "type": "integer" } }, @@ -6568,17 +7352,17 @@ "type": "string" }, "id": { - "format": "int32", "type": "integer" } }, - "required": ["database_name"], + "required": [ + "database_name" + ], "type": "object" }, "ReportScheduleRestApi.get.ReportRecipients": { "properties": { "id": { - "format": "int32", "type": "integer" }, "recipient_config_json": { @@ -6590,13 +7374,14 @@ "type": "string" } }, - "required": ["type"], + "required": [ + "type" + ], "type": "object" }, "ReportScheduleRestApi.get.Slice": { "properties": { "id": { - "format": "int32", "type": "integer" }, "slice_name": { @@ -6619,7 +7404,6 @@ "type": "string" }, "id": { - "format": "int32", "type": "integer" }, "last_name": { @@ -6627,7 +7411,10 @@ "type": "string" } }, - "required": ["first_name", "last_name"], + "required": [ + "first_name", + "last_name" + ], "type": "object" }, "ReportScheduleRestApi.get_list": { @@ -6637,7 +7424,7 @@ "type": "boolean" }, "changed_by": { - "$ref": "#/components/schemas/ReportScheduleRestApi.get_list.User" + "$ref": "#/components/schemas/ReportScheduleRestApi.get_list.User2" }, "changed_on": { "format": "date-time", @@ -6648,12 +7435,11 @@ "readOnly": true }, "chart_id": { - "format": "int32", "nullable": true, "type": "integer" }, "created_by": { - "$ref": "#/components/schemas/ReportScheduleRestApi.get_list.User1" + "$ref": "#/components/schemas/ReportScheduleRestApi.get_list.User" }, "created_on": { "format": "date-time", @@ -6673,7 +7459,6 @@ "readOnly": true }, "dashboard_id": { - "format": "int32", "nullable": true, "type": "integer" }, @@ -6685,7 +7470,6 @@ "readOnly": true }, "id": { - "format": "int32", "type": "integer" }, "last_eval_dttm": { @@ -6703,7 +7487,7 @@ "type": "string" }, "owners": { - "$ref": "#/components/schemas/ReportScheduleRestApi.get_list.User2" + "$ref": "#/components/schemas/ReportScheduleRestApi.get_list.User1" }, "recipients": { "$ref": "#/components/schemas/ReportScheduleRestApi.get_list.ReportRecipients" @@ -6717,13 +7501,17 @@ "type": "string" } }, - "required": ["crontab", "name", "recipients", "type"], + "required": [ + "crontab", + "name", + "recipients", + "type" + ], "type": "object" }, "ReportScheduleRestApi.get_list.ReportRecipients": { "properties": { "id": { - "format": "int32", "type": "integer" }, "type": { @@ -6731,7 +7519,9 @@ "type": "string" } }, - "required": ["type"], + "required": [ + "type" + ], "type": "object" }, "ReportScheduleRestApi.get_list.User": { @@ -6745,7 +7535,10 @@ "type": "string" } }, - "required": ["first_name", "last_name"], + "required": [ + "first_name", + "last_name" + ], "type": "object" }, "ReportScheduleRestApi.get_list.User1": { @@ -6754,12 +7547,18 @@ "maxLength": 64, "type": "string" }, + "id": { + "type": "integer" + }, "last_name": { "maxLength": 64, "type": "string" } }, - "required": ["first_name", "last_name"], + "required": [ + "first_name", + "last_name" + ], "type": "object" }, "ReportScheduleRestApi.get_list.User2": { @@ -6768,16 +7567,15 @@ "maxLength": 64, "type": "string" }, - "id": { - "format": "int32", - "type": "integer" - }, "last_name": { "maxLength": 64, "type": "string" } }, - "required": ["first_name", "last_name"], + "required": [ + "first_name", + "last_name" + ], "type": "object" }, "ReportScheduleRestApi.post": { @@ -6786,7 +7584,6 @@ "type": "boolean" }, "chart": { - "format": "int32", "nullable": true, "type": "integer" }, @@ -6796,7 +7593,12 @@ "type": "string" }, "creation_method": { - "description": "Creation method is used to inform the frontend whether the report/alert was created in the dashboard, chart, or alerts and reports UI." + "description": "Creation method is used to inform the frontend whether the report/alert was created in the dashboard, chart, or alerts and reports UI.", + "enum": [ + "charts", + "dashboards", + "alerts_reports" + ] }, "crontab": { "description": "A CRON expression.[Crontab Guru](https://crontab.guru/) is a helpful resource that can help you craft a CRON expression.", @@ -6805,13 +7607,17 @@ "minLength": 1, "type": "string" }, + "custom_width": { + "description": "Custom width of the screenshot in pixels", + "example": 1000, + "nullable": true, + "type": "integer" + }, "dashboard": { - "format": "int32", "nullable": true, "type": "integer" }, "database": { - "format": "int32", "type": "integer" }, "description": { @@ -6829,14 +7635,12 @@ "grace_period": { "description": "Once an alert is triggered, how long, in seconds, before Superset nags you again. (in seconds)", "example": 14400, - "format": "int32", "minimum": 1, "type": "integer" }, "log_retention": { "description": "How long to keep the logs around for this report (in days)", "example": 90, - "format": "int32", "minimum": 1, "type": "integer" }, @@ -6850,7 +7654,6 @@ "owners": { "items": { "description": "Owner are users ids allowed to delete or change this report. If left empty you will be one of the owners of the report.", - "format": "int32", "type": "integer" }, "type": "array" @@ -6862,12 +7665,15 @@ "type": "array" }, "report_format": { - "enum": ["PNG", "CSV", "TEXT"], + "enum": [ + "PNG", + "CSV", + "TEXT" + ], "type": "string" }, "selected_tabs": { "items": { - "format": "int32", "type": "integer" }, "nullable": true, @@ -7480,7 +8286,10 @@ }, "type": { "description": "The report schedule type", - "enum": ["Alert", "Report"], + "enum": [ + "Alert", + "Report" + ], "type": "string" }, "validator_config_json": { @@ -7488,18 +8297,24 @@ }, "validator_type": { "description": "Determines when to trigger alert based off value from alert query. Alerts will be triggered with these validator types:\n- Not Null - When the return value is Not NULL, Empty, or 0\n- Operator - When `sql_return_value comparison_operator threshold` is True e.g. `50 <= 75`
Supports the comparison operators <, <=, >, >=, ==, and !=", - "enum": ["not null", "operator"], + "enum": [ + "not null", + "operator" + ], "type": "string" }, "working_timeout": { "description": "If an alert is staled at a working state, how long until it's state is reseted to error", "example": 3600, - "format": "int32", "minimum": 1, "type": "integer" } }, - "required": ["crontab", "name", "type"], + "required": [ + "crontab", + "name", + "type" + ], "type": "object" }, "ReportScheduleRestApi.put": { @@ -7508,7 +8323,6 @@ "type": "boolean" }, "chart": { - "format": "int32", "nullable": true, "type": "integer" }, @@ -7519,6 +8333,11 @@ }, "creation_method": { "description": "Creation method is used to inform the frontend whether the report/alert was created in the dashboard, chart, or alerts and reports UI.", + "enum": [ + "charts", + "dashboards", + "alerts_reports" + ], "nullable": true }, "crontab": { @@ -7527,13 +8346,17 @@ "minLength": 1, "type": "string" }, + "custom_width": { + "description": "Custom width of the screenshot in pixels", + "example": 1000, + "nullable": true, + "type": "integer" + }, "dashboard": { - "format": "int32", "nullable": true, "type": "integer" }, "database": { - "format": "int32", "type": "integer" }, "description": { @@ -7551,14 +8374,12 @@ "grace_period": { "description": "Once an alert is triggered, how long, in seconds, before Superset nags you again. (in seconds)", "example": 14400, - "format": "int32", "minimum": 1, "type": "integer" }, "log_retention": { "description": "How long to keep the logs around for this report (in days)", "example": 90, - "format": "int32", "minimum": 1, "type": "integer" }, @@ -7571,7 +8392,6 @@ "owners": { "items": { "description": "Owner are users ids allowed to delete or change this report. If left empty you will be one of the owners of the report.", - "format": "int32", "type": "integer" }, "type": "array" @@ -7583,7 +8403,11 @@ "type": "array" }, "report_format": { - "enum": ["PNG", "CSV", "TEXT"], + "enum": [ + "PNG", + "CSV", + "TEXT" + ], "type": "string" }, "sql": { @@ -8194,7 +9018,10 @@ }, "type": { "description": "The report schedule type", - "enum": ["Alert", "Report"], + "enum": [ + "Alert", + "Report" + ], "type": "string" }, "validator_config_json": { @@ -8202,14 +9029,16 @@ }, "validator_type": { "description": "Determines when to trigger alert based off value from alert query. Alerts will be triggered with these validator types:\n- Not Null - When the return value is Not NULL, Empty, or 0\n- Operator - When `sql_return_value comparison_operator threshold` is True e.g. `50 <= 75`
Supports the comparison operators <, <=, >, >=, ==, and !=", - "enum": ["not null", "operator"], + "enum": [ + "not null", + "operator" + ], "nullable": true, "type": "string" }, "working_timeout": { "description": "If an alert is staled at a working state, how long until it's state is reseted to error", "example": 3600, - "format": "int32", "minimum": 1, "nullable": true, "type": "integer" @@ -8222,9 +9051,16 @@ "id": { "type": "string" }, - "type": {} + "type": { + "enum": [ + "dashboard" + ] + } }, - "required": ["id", "type"], + "required": [ + "id", + "type" + ], "type": "object" }, "RlsRule": { @@ -8233,17 +9069,28 @@ "type": "string" }, "dataset": { - "format": "int32", "type": "integer" } }, - "required": ["clause"], + "required": [ + "clause" + ], "type": "object" }, "Roles": { "properties": { "id": { - "format": "int32", + "type": "integer" + }, + "name": { + "type": "string" + } + }, + "type": "object" + }, + "Roles1": { + "properties": { + "id": { "type": "integer" }, "name": { @@ -8268,7 +9115,6 @@ "type": "string" }, "id": { - "format": "int32", "type": "integer" }, "label": { @@ -8302,11 +9148,12 @@ "type": "string" }, "id": { - "format": "int32", "type": "integer" } }, - "required": ["database_name"], + "required": [ + "database_name" + ], "type": "object" }, "SavedQueryRestApi.get.User": { @@ -8316,7 +9163,6 @@ "type": "string" }, "id": { - "format": "int32", "type": "integer" }, "last_name": { @@ -8324,7 +9170,10 @@ "type": "string" } }, - "required": ["first_name", "last_name"], + "required": [ + "first_name", + "last_name" + ], "type": "object" }, "SavedQueryRestApi.get_list": { @@ -8344,7 +9193,6 @@ "$ref": "#/components/schemas/SavedQueryRestApi.get_list.Database" }, "db_id": { - "format": "int32", "nullable": true, "type": "integer" }, @@ -8356,7 +9204,6 @@ "readOnly": true }, "id": { - "format": "int32", "type": "integer" }, "label": { @@ -8368,7 +9215,6 @@ "readOnly": true }, "rows": { - "format": "int32", "nullable": true, "type": "integer" }, @@ -8383,6 +9229,9 @@ }, "sql_tables": { "readOnly": true + }, + "tags": { + "$ref": "#/components/schemas/SavedQueryRestApi.get_list.Tag" } }, "type": "object" @@ -8394,11 +9243,33 @@ "type": "string" }, "id": { - "format": "int32", "type": "integer" } }, - "required": ["database_name"], + "required": [ + "database_name" + ], + "type": "object" + }, + "SavedQueryRestApi.get_list.Tag": { + "properties": { + "id": { + "type": "integer" + }, + "name": { + "maxLength": 250, + "nullable": true, + "type": "string" + }, + "type": { + "enum": [ + 1, + 2, + 3, + 4 + ] + } + }, "type": "object" }, "SavedQueryRestApi.get_list.User": { @@ -8408,7 +9279,6 @@ "type": "string" }, "id": { - "format": "int32", "type": "integer" }, "last_name": { @@ -8416,13 +9286,15 @@ "type": "string" } }, - "required": ["first_name", "last_name"], + "required": [ + "first_name", + "last_name" + ], "type": "object" }, "SavedQueryRestApi.post": { "properties": { "db_id": { - "format": "int32", "nullable": true, "type": "integer" }, @@ -8454,7 +9326,6 @@ "SavedQueryRestApi.put": { "properties": { "db_id": { - "format": "int32", "nullable": true, "type": "integer" }, @@ -8508,7 +9379,6 @@ "properties": { "cache_timeout": { "description": "Duration (in seconds) of the caching timeout for this chart.", - "format": "int32", "type": "integer" }, "certification_details": { @@ -8521,6 +9391,7 @@ }, "changed_on": { "description": "Timestamp of the last modification.", + "format": "date-time", "type": "string" }, "changed_on_humanized": { @@ -8558,7 +9429,6 @@ "owners": { "description": "Owners identifiers.", "items": { - "format": "int32", "type": "integer" }, "type": "array" @@ -8569,7 +9439,6 @@ }, "slice_id": { "description": "The slice ID.", - "format": "int32", "type": "integer" }, "slice_name": { @@ -8636,7 +9505,7 @@ "properties": { "column_names": { "items": { - "description": "A list of column names that compose the foreign key or index", + "description": "A list of column names that compose the foreign key or index", "type": "string" }, "type": "array" @@ -8747,221 +9616,538 @@ }, "type": "object" }, - "TemporaryCachePostSchema": { + "Tables": { "properties": { - "value": { - "description": "Any type of JSON supported text.", + "id": { + "type": "integer" + }, + "schema": { + "type": "string" + }, + "table_name": { "type": "string" } }, - "required": ["value"], "type": "object" }, - "TemporaryCachePutSchema": { + "Tag": { "properties": { - "value": { - "description": "Any type of JSON supported text.", + "id": { + "type": "integer" + }, + "name": { "type": "string" + }, + "type": { + "enum": [ + 1, + 2, + 3, + 4 + ] } }, - "required": ["value"], "type": "object" }, - "User": { + "Tag1": { "properties": { - "first_name": { + "id": { + "type": "integer" + }, + "name": { "type": "string" }, + "type": { + "enum": [ + 1, + 2, + 3, + 4 + ] + } + }, + "type": "object" + }, + "TagGetResponseSchema": { + "properties": { "id": { - "format": "int32", "type": "integer" }, - "last_name": { + "name": { "type": "string" }, - "username": { + "type": { "type": "string" } }, "type": "object" }, - "User1": { + "TagRestApi.get": { "properties": { - "first_name": { - "type": "string" + "changed_by": { + "$ref": "#/components/schemas/TagRestApi.get.User1" }, - "last_name": { - "type": "string" + "changed_on_delta_humanized": { + "readOnly": true }, - "username": { + "created_by": { + "$ref": "#/components/schemas/TagRestApi.get.User" + }, + "id": { + "type": "integer" + }, + "name": { + "maxLength": 250, + "nullable": true, "type": "string" + }, + "type": { + "enum": [ + 1, + 2, + 3, + 4 + ] } }, "type": "object" }, - "UserResponseSchema": { + "TagRestApi.get.User": { "properties": { + "active": { + "nullable": true, + "type": "boolean" + }, + "changed_on": { + "format": "date-time", + "nullable": true, + "type": "string" + }, + "created_on": { + "format": "date-time", + "nullable": true, + "type": "string" + }, "email": { + "maxLength": 64, "type": "string" }, + "fail_login_count": { + "nullable": true, + "type": "integer" + }, "first_name": { + "maxLength": 64, "type": "string" }, "id": { - "format": "int32", "type": "integer" }, - "is_active": { - "type": "boolean" - }, - "is_anonymous": { - "type": "boolean" + "last_login": { + "format": "date-time", + "nullable": true, + "type": "string" }, "last_name": { + "maxLength": 64, + "type": "string" + }, + "login_count": { + "nullable": true, + "type": "integer" + }, + "password": { + "maxLength": 256, + "nullable": true, "type": "string" }, "username": { + "maxLength": 64, "type": "string" } }, + "required": [ + "email", + "first_name", + "last_name", + "username" + ], "type": "object" }, - "ValidateSQLRequest": { + "TagRestApi.get.User1": { "properties": { - "schema": { - "nullable": true, + "first_name": { + "maxLength": 64, "type": "string" }, - "sql": { - "description": "SQL statement to validate", + "last_name": { + "maxLength": 64, "type": "string" - }, - "template_params": { - "nullable": true, - "type": "object" } }, - "required": ["sql"], + "required": [ + "first_name", + "last_name" + ], "type": "object" }, - "ValidateSQLResponse": { + "TagRestApi.get_list": { "properties": { - "end_column": { - "format": "int32", - "type": "integer" + "changed_by": { + "$ref": "#/components/schemas/TagRestApi.get_list.User1" }, - "line_number": { - "format": "int32", + "changed_on_delta_humanized": { + "readOnly": true + }, + "created_by": { + "$ref": "#/components/schemas/TagRestApi.get_list.User" + }, + "id": { "type": "integer" }, - "message": { + "name": { + "maxLength": 250, + "nullable": true, "type": "string" }, - "start_column": { - "format": "int32", - "type": "integer" + "type": { + "enum": [ + 1, + 2, + 3, + 4 + ] } }, "type": "object" }, - "ValidatorConfigJSON": { + "TagRestApi.get_list.User": { "properties": { - "op": { - "description": "The operation to compare with a threshold to apply to the SQL output\n", - "enum": ["<", "<=", ">", ">=", "==", "!="], + "first_name": { + "maxLength": 64, "type": "string" }, - "threshold": { - "format": "float", - "type": "number" + "last_name": { + "maxLength": 64, + "type": "string" } }, + "required": [ + "first_name", + "last_name" + ], "type": "object" }, - "advanced_data_type_convert_schema": { + "TagRestApi.get_list.User1": { "properties": { - "type": { - "default": "port", + "first_name": { + "maxLength": 64, "type": "string" }, - "values": { + "last_name": { + "maxLength": 64, + "type": "string" + } + }, + "required": [ + "first_name", + "last_name" + ], + "type": "object" + }, + "TagRestApi.post": { + "properties": { + "tags": { "items": { - "default": "http" + "type": "string" }, - "minItems": 1, "type": "array" } }, - "required": ["type", "values"], "type": "object" }, - "database_schemas_query_schema": { + "TagRestApi.put": { "properties": { - "force": { - "type": "boolean" + "id": { + "type": "integer" } }, "type": "object" }, - "database_tables_query_schema": { + "TaggedObjectEntityResponseSchema": { "properties": { - "force": { - "type": "boolean" + "changed_on": { + "format": "date-time", + "type": "string" }, - "schema_name": { + "created_by": { + "$ref": "#/components/schemas/User" + }, + "creator": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "type": { + "type": "string" + }, + "url": { "type": "string" } }, - "required": ["schema_name"], "type": "object" }, - "get_delete_ids_schema": { - "items": { - "type": "integer" + "TemporaryCachePostSchema": { + "properties": { + "value": { + "description": "Any type of JSON supported text.", + "type": "string" + } }, - "type": "array" + "required": [ + "value" + ], + "type": "object" }, - "get_export_ids_schema": { - "items": { - "type": "integer" + "TemporaryCachePutSchema": { + "properties": { + "value": { + "description": "Any type of JSON supported text.", + "type": "string" + } }, - "type": "array" + "required": [ + "value" + ], + "type": "object" }, - "get_fav_star_ids_schema": { - "items": { - "type": "integer" + "User": { + "properties": { + "first_name": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "last_name": { + "type": "string" + } }, - "type": "array" + "type": "object" }, - "get_info_schema": { + "User1": { "properties": { - "add_columns": { - "additionalProperties": { - "properties": { - "page": { - "type": "integer" - }, - "page_size": { - "type": "integer" - } - }, - "type": "object" - }, - "type": "object" + "first_name": { + "type": "string" }, - "edit_columns": { - "additionalProperties": { - "properties": { - "page": { - "type": "integer" - }, - "page_size": { - "type": "integer" - } - }, - "type": "object" - }, - "type": "object" + "id": { + "type": "integer" + }, + "last_name": { + "type": "string" + }, + "username": { + "type": "string" + } + }, + "type": "object" + }, + "User2": { + "properties": { + "first_name": { + "type": "string" + }, + "last_name": { + "type": "string" + }, + "username": { + "type": "string" + } + }, + "type": "object" + }, + "UserResponseSchema": { + "properties": { + "email": { + "type": "string" + }, + "first_name": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "is_active": { + "type": "boolean" + }, + "is_anonymous": { + "type": "boolean" + }, + "last_name": { + "type": "string" + }, + "username": { + "type": "string" + } + }, + "type": "object" + }, + "ValidateSQLRequest": { + "properties": { + "schema": { + "nullable": true, + "type": "string" + }, + "sql": { + "description": "SQL statement to validate", + "type": "string" + }, + "template_params": { + "nullable": true, + "type": "object" + } + }, + "required": [ + "sql" + ], + "type": "object" + }, + "ValidateSQLResponse": { + "properties": { + "end_column": { + "type": "integer" + }, + "line_number": { + "type": "integer" + }, + "message": { + "type": "string" + }, + "start_column": { + "type": "integer" + } + }, + "type": "object" + }, + "ValidatorConfigJSON": { + "properties": { + "op": { + "description": "The operation to compare with a threshold to apply to the SQL output\n", + "enum": [ + "<", + "<=", + ">", + ">=", + "==", + "!=" + ], + "type": "string" + }, + "threshold": { + "type": "number" + } + }, + "type": "object" + }, + "advanced_data_type_convert_schema": { + "properties": { + "type": { + "default": "port", + "type": "string" + }, + "values": { + "items": { + "default": "http" + }, + "minItems": 1, + "type": "array" + } + }, + "required": [ + "type", + "values" + ], + "type": "object" + }, + "database_schemas_query_schema": { + "properties": { + "force": { + "type": "boolean" + } + }, + "type": "object" + }, + "database_tables_query_schema": { + "properties": { + "force": { + "type": "boolean" + }, + "schema_name": { + "type": "string" + } + }, + "required": [ + "schema_name" + ], + "type": "object" + }, + "delete_tags_schema": { + "items": { + "type": "string" + }, + "type": "array" + }, + "get_delete_ids_schema": { + "items": { + "type": "integer" + }, + "type": "array" + }, + "get_export_ids_schema": { + "items": { + "type": "integer" + }, + "type": "array" + }, + "get_fav_star_ids_schema": { + "items": { + "type": "integer" + }, + "type": "array" + }, + "get_info_schema": { + "properties": { + "add_columns": { + "additionalProperties": { + "properties": { + "page": { + "type": "integer" + }, + "page_size": { + "type": "integer" + } + }, + "type": "object" + }, + "type": "object" + }, + "edit_columns": { + "additionalProperties": { + "properties": { + "page": { + "type": "integer" + }, + "page_size": { + "type": "integer" + } + }, + "type": "object" + }, + "type": "object" }, "keys": { "items": { @@ -9039,7 +10225,11 @@ ] } }, - "required": ["col", "opr", "value"], + "required": [ + "col", + "opr", + "value" + ], "type": "object" }, "type": "array" @@ -9062,7 +10252,10 @@ "type": "string" }, "order_direction": { - "enum": ["asc", "desc"], + "enum": [ + "asc", + "desc" + ], "type": "string" }, "page": { @@ -9120,7 +10313,9 @@ "type": "number" } }, - "required": ["last_updated_ms"], + "required": [ + "last_updated_ms" + ], "type": "object" }, "screenshot_query_schema": { @@ -9149,7 +10344,9 @@ "type": "string" } }, - "required": ["key"], + "required": [ + "key" + ], "type": "object" }, "thumbnail_query_schema": { @@ -9226,7 +10423,9 @@ } ], "summary": "Returns a AdvancedDataTypeResponse object populated with the passed in args.", - "tags": ["Advanced Data Type"] + "tags": [ + "Advanced Data Type" + ] } }, "/api/v1/advanced_data_type/types": { @@ -9266,7 +10465,9 @@ "jwt": [] } ], - "tags": ["Advanced Data Type"] + "tags": [ + "Advanced Data Type" + ] } }, "/api/v1/annotation_layer/": { @@ -9319,7 +10520,9 @@ "jwt": [] } ], - "tags": ["Annotation Layers"] + "tags": [ + "Annotation Layers" + ] }, "get": { "description": "Get a list of Annotation layers, use Rison or JSON query parameters for filtering, sorting, pagination and for selecting specific columns and metadata.", @@ -9424,7 +10627,9 @@ "jwt": [] } ], - "tags": ["Annotation Layers"] + "tags": [ + "Annotation Layers" + ] }, "post": { "description": "Create an Annotation layer", @@ -9476,7 +10681,9 @@ "jwt": [] } ], - "tags": ["Annotation Layers"] + "tags": [ + "Annotation Layers" + ] } }, "/api/v1/annotation_layer/_info": { @@ -9560,7 +10767,9 @@ "jwt": [] } ], - "tags": ["Annotation Layers"] + "tags": [ + "Annotation Layers" + ] } }, "/api/v1/annotation_layer/related/{column_name}": { @@ -9615,7 +10824,9 @@ "jwt": [] } ], - "tags": ["Annotation Layers"] + "tags": [ + "Annotation Layers" + ] } }, "/api/v1/annotation_layer/{pk}": { @@ -9663,7 +10874,9 @@ "jwt": [] } ], - "tags": ["Annotation Layers"] + "tags": [ + "Annotation Layers" + ] }, "get": { "description": "Get an Annotation layer", @@ -9761,7 +10974,9 @@ "jwt": [] } ], - "tags": ["Annotation Layers"] + "tags": [ + "Annotation Layers" + ] }, "put": { "description": "Update an Annotation layer", @@ -9824,7 +11039,9 @@ "jwt": [] } ], - "tags": ["Annotation Layers"] + "tags": [ + "Annotation Layers" + ] } }, "/api/v1/annotation_layer/{pk}/annotation/": { @@ -9886,7 +11103,9 @@ "jwt": [] } ], - "tags": ["Annotation Layers"] + "tags": [ + "Annotation Layers" + ] }, "get": { "description": "Get a list of Annotation layers, use Rison or JSON query parameters for filtering, sorting, pagination and for selecting specific columns and metadata.", @@ -9961,7 +11180,9 @@ "jwt": [] } ], - "tags": ["Annotation Layers"] + "tags": [ + "Annotation Layers" + ] }, "post": { "description": "Create an Annotation layer", @@ -10024,7 +11245,9 @@ "jwt": [] } ], - "tags": ["Annotation Layers"] + "tags": [ + "Annotation Layers" + ] } }, "/api/v1/annotation_layer/{pk}/annotation/{annotation_id}": { @@ -10081,7 +11304,9 @@ "jwt": [] } ], - "tags": ["Annotation Layers"] + "tags": [ + "Annotation Layers" + ] }, "get": { "description": "Get an Annotation layer", @@ -10157,7 +11382,9 @@ "jwt": [] } ], - "tags": ["Annotation Layers"] + "tags": [ + "Annotation Layers" + ] }, "put": { "description": "Update an Annotation layer", @@ -10229,7 +11456,9 @@ "jwt": [] } ], - "tags": ["Annotation Layers"] + "tags": [ + "Annotation Layers" + ] } }, "/api/v1/assets/export/": { @@ -10262,7 +11491,9 @@ "jwt": [] } ], - "tags": ["Import/export"] + "tags": [ + "Import/export" + ] } }, "/api/v1/assets/import/": { @@ -10285,12 +11516,12 @@ "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" }, - "ssh_tunnel_private_keys": { - "description": "JSON map of private_keys 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 private_key should be provided in the following format: `{\"databases/MyDatabase.yaml\": \"my_private_key\"}`.", + "ssh_tunnel_private_key_passwords": { + "description": "JSON map of private_key_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 private_key should be provided in the following format: `{\"databases/MyDatabase.yaml\": \"my_private_key_password\"}`.", "type": "string" }, - "ssh_tunnel_private_keyspasswords": { - "description": "JSON map of private_key_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 private_key_password should be provided in the following format: `{\"databases/MyDatabase.yaml\": \"my_private_key_password\"}`.", + "ssh_tunnel_private_keys": { + "description": "JSON map of private_keys 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 private_key should be provided in the following format: `{\"databases/MyDatabase.yaml\": \"my_private_key\"}`.", "type": "string" } }, @@ -10334,7 +11565,9 @@ "jwt": [] } ], - "tags": ["Import/export"] + "tags": [ + "Import/export" + ] } }, "/api/v1/async_event/": { @@ -10407,7 +11640,9 @@ "jwt": [] } ], - "tags": ["AsyncEventsRestApi"] + "tags": [ + "AsyncEventsRestApi" + ] } }, "/api/v1/available_domains/": { @@ -10441,7 +11676,9 @@ "jwt": [] } ], - "tags": ["Available Domains"] + "tags": [ + "Available Domains" + ] } }, "/api/v1/cachekey/invalidate": { @@ -10474,7 +11711,9 @@ "jwt": [] } ], - "tags": ["CacheRestApi"] + "tags": [ + "CacheRestApi" + ] } }, "/api/v1/chart/": { @@ -10530,7 +11769,9 @@ "jwt": [] } ], - "tags": ["Charts"] + "tags": [ + "Charts" + ] }, "get": { "description": "Get a list of charts, use Rison or JSON query parameters for filtering, sorting, pagination and for selecting specific columns and metadata.", @@ -10635,7 +11876,9 @@ "jwt": [] } ], - "tags": ["Charts"] + "tags": [ + "Charts" + ] }, "post": { "description": "Create a new Chart.", @@ -10675,6 +11918,9 @@ "401": { "$ref": "#/components/responses/401" }, + "403": { + "$ref": "#/components/responses/403" + }, "422": { "$ref": "#/components/responses/422" }, @@ -10687,7 +11933,9 @@ "jwt": [] } ], - "tags": ["Charts"] + "tags": [ + "Charts" + ] } }, "/api/v1/chart/_info": { @@ -10771,7 +12019,9 @@ "jwt": [] } ], - "tags": ["Charts"] + "tags": [ + "Charts" + ] } }, "/api/v1/chart/data": { @@ -10824,7 +12074,9 @@ "jwt": [] } ], - "tags": ["Charts"] + "tags": [ + "Charts" + ] } }, "/api/v1/chart/data/{cache_key}": { @@ -10872,7 +12124,9 @@ "jwt": [] } ], - "tags": ["Charts"] + "tags": [ + "Charts" + ] } }, "/api/v1/chart/export/": { @@ -10921,7 +12175,9 @@ "jwt": [] } ], - "tags": ["Charts"] + "tags": [ + "Charts" + ] } }, "/api/v1/chart/favorite_status/": { @@ -10969,7 +12225,9 @@ "jwt": [] } ], - "tags": ["Charts"] + "tags": [ + "Charts" + ] } }, "/api/v1/chart/import/": { @@ -10996,12 +12254,12 @@ "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" }, - "ssh_tunnel_private_keys": { - "description": "JSON map of private_keys 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 private_key should be provided in the following format: `{\"databases/MyDatabase.yaml\": \"my_private_key\"}`.", + "ssh_tunnel_private_key_passwords": { + "description": "JSON map of private_key_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 private_key should be provided in the following format: `{\"databases/MyDatabase.yaml\": \"my_private_key_password\"}`.", "type": "string" }, - "ssh_tunnel_private_keyspasswords": { - "description": "JSON map of private_key_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 private_key_password should be provided in the following format: `{\"databases/MyDatabase.yaml\": \"my_private_key_password\"}`.", + "ssh_tunnel_private_keys": { + "description": "JSON map of private_keys 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 private_key should be provided in the following format: `{\"databases/MyDatabase.yaml\": \"my_private_key\"}`.", "type": "string" } }, @@ -11045,7 +12303,9 @@ "jwt": [] } ], - "tags": ["Charts"] + "tags": [ + "Charts" + ] } }, "/api/v1/chart/related/{column_name}": { @@ -11101,7 +12361,55 @@ "jwt": [] } ], - "tags": ["Charts"] + "tags": [ + "Charts" + ] + } + }, + "/api/v1/chart/warm_up_cache": { + "put": { + "description": "Warms up the cache for the chart. Note for slices a force refresh occurs. In terms of the `extra_filters` these can be obtained from records in the JSON encoded `logs.json` column associated with the `explore_json` action.", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ChartCacheWarmUpRequestSchema" + } + } + }, + "description": "Identifies the chart to warm up cache for, and any additional dashboard or filter context to use.", + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ChartCacheWarmUpResponseSchema" + } + } + }, + "description": "Each chart's warmup status" + }, + "400": { + "$ref": "#/components/responses/400" + }, + "404": { + "$ref": "#/components/responses/404" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "summary": "Warms up the cache for the chart", + "tags": [ + "Charts" + ] } }, "/api/v1/chart/{pk}": { @@ -11154,7 +12462,9 @@ "jwt": [] } ], - "tags": ["Charts"] + "tags": [ + "Charts" + ] }, "get": { "description": "Get a chart detail information.", @@ -11252,7 +12562,9 @@ "jwt": [] } ], - "tags": ["Charts"] + "tags": [ + "Charts" + ] }, "put": { "description": "Changes a Chart.", @@ -11320,7 +12632,9 @@ "jwt": [] } ], - "tags": ["Charts"] + "tags": [ + "Charts" + ] } }, "/api/v1/chart/{pk}/cache_screenshot/": { @@ -11376,7 +12690,9 @@ "jwt": [] } ], - "tags": ["Charts"] + "tags": [ + "Charts" + ] } }, "/api/v1/chart/{pk}/data/": { @@ -11453,12 +12769,14 @@ "jwt": [] } ], - "tags": ["Charts"] + "tags": [ + "Charts" + ] } }, - "/api/v1/chart/{pk}/screenshot/{digest}/": { - "get": { - "description": "Get a computed screenshot from cache.", + "/api/v1/chart/{pk}/favorites/": { + "delete": { + "description": "Remove the chart from the user favorite list", "parameters": [ { "in": "path", @@ -11467,10 +12785,106 @@ "schema": { "type": "integer" } - }, - { - "in": "path", - "name": "digest", + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "result": { + "type": "object" + } + }, + "type": "object" + } + } + }, + "description": "Chart removed from favorites" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "404": { + "$ref": "#/components/responses/404" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "tags": [ + "Charts" + ] + }, + "post": { + "description": "Marks the chart as favorite for the current user", + "parameters": [ + { + "in": "path", + "name": "pk", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "result": { + "type": "object" + } + }, + "type": "object" + } + } + }, + "description": "Chart added to favorites" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "404": { + "$ref": "#/components/responses/404" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "tags": [ + "Charts" + ] + } + }, + "/api/v1/chart/{pk}/screenshot/{digest}/": { + "get": { + "description": "Get a computed screenshot from cache.", + "parameters": [ + { + "in": "path", + "name": "pk", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "in": "path", + "name": "digest", "required": true, "schema": { "type": "string" @@ -11507,7 +12921,9 @@ "jwt": [] } ], - "tags": ["Charts"] + "tags": [ + "Charts" + ] } }, "/api/v1/chart/{pk}/thumbnail/{digest}/": { @@ -11564,7 +12980,9 @@ "jwt": [] } ], - "tags": ["Charts"] + "tags": [ + "Charts" + ] } }, "/api/v1/css_template/": { @@ -11617,7 +13035,9 @@ "jwt": [] } ], - "tags": ["CSS Templates"] + "tags": [ + "CSS Templates" + ] }, "get": { "description": "Get a list of CSS templates, use Rison or JSON query parameters for filtering, sorting, pagination and for selecting specific columns and metadata.", @@ -11722,7 +13142,9 @@ "jwt": [] } ], - "tags": ["CSS Templates"] + "tags": [ + "CSS Templates" + ] }, "post": { "description": "Create a CSS template", @@ -11774,7 +13196,9 @@ "jwt": [] } ], - "tags": ["CSS Templates"] + "tags": [ + "CSS Templates" + ] } }, "/api/v1/css_template/_info": { @@ -11858,7 +13282,9 @@ "jwt": [] } ], - "tags": ["CSS Templates"] + "tags": [ + "CSS Templates" + ] } }, "/api/v1/css_template/related/{column_name}": { @@ -11913,7 +13339,9 @@ "jwt": [] } ], - "tags": ["CSS Templates"] + "tags": [ + "CSS Templates" + ] } }, "/api/v1/css_template/{pk}": { @@ -11960,7 +13388,9 @@ "jwt": [] } ], - "tags": ["CSS Templates"] + "tags": [ + "CSS Templates" + ] }, "get": { "description": "Get a CSS template", @@ -12058,7 +13488,9 @@ "jwt": [] } ], - "tags": ["CSS Templates"] + "tags": [ + "CSS Templates" + ] }, "put": { "description": "Update a CSS template", @@ -12120,7 +13552,9 @@ "jwt": [] } ], - "tags": ["CSS Templates"] + "tags": [ + "CSS Templates" + ] } }, "/api/v1/dashboard/": { @@ -12176,7 +13610,9 @@ "jwt": [] } ], - "tags": ["Dashboards"] + "tags": [ + "Dashboards" + ] }, "get": { "description": "Get a list of dashboards, use Rison or JSON query parameters for filtering, sorting, pagination and for selecting specific columns and metadata.", @@ -12281,7 +13717,9 @@ "jwt": [] } ], - "tags": ["Dashboards"] + "tags": [ + "Dashboards" + ] }, "post": { "description": "Create a new Dashboard.", @@ -12333,7 +13771,9 @@ "jwt": [] } ], - "tags": ["Dashboards"] + "tags": [ + "Dashboards" + ] } }, "/api/v1/dashboard/_info": { @@ -12417,7 +13857,9 @@ "jwt": [] } ], - "tags": ["Dashboards"] + "tags": [ + "Dashboards" + ] } }, "/api/v1/dashboard/export/": { @@ -12468,7 +13910,9 @@ "jwt": [] } ], - "tags": ["Dashboards"] + "tags": [ + "Dashboards" + ] } }, "/api/v1/dashboard/favorite_status/": { @@ -12516,7 +13960,9 @@ "jwt": [] } ], - "tags": ["Dashboards"] + "tags": [ + "Dashboards" + ] } }, "/api/v1/dashboard/import/": { @@ -12543,12 +13989,12 @@ "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" }, - "ssh_tunnel_private_keys": { - "description": "JSON map of private_keys 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 private_key should be provided in the following format: `{\"databases/MyDatabase.yaml\": \"my_private_key\"}`.", + "ssh_tunnel_private_key_passwords": { + "description": "JSON map of private_key_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 private_key should be provided in the following format: `{\"databases/MyDatabase.yaml\": \"my_private_key_password\"}`.", "type": "string" }, - "ssh_tunnel_private_keyspasswords": { - "description": "JSON map of private_key_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 private_key_password should be provided in the following format: `{\"databases/MyDatabase.yaml\": \"my_private_key_password\"}`.", + "ssh_tunnel_private_keys": { + "description": "JSON map of private_keys 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 private_key should be provided in the following format: `{\"databases/MyDatabase.yaml\": \"my_private_key\"}`.", "type": "string" } }, @@ -12592,7 +14038,9 @@ "jwt": [] } ], - "tags": ["Dashboards"] + "tags": [ + "Dashboards" + ] } }, "/api/v1/dashboard/permalink/{key}": { @@ -12646,7 +14094,9 @@ "jwt": [] } ], - "tags": ["Dashboard Permanent Link"] + "tags": [ + "Dashboard Permanent Link" + ] } }, "/api/v1/dashboard/related/{column_name}": { @@ -12702,7 +14152,9 @@ "jwt": [] } ], - "tags": ["Dashboards"] + "tags": [ + "Dashboards" + ] } }, "/api/v1/dashboard/{dashboard_id}/filtersets": { @@ -12776,7 +14228,9 @@ "jwt": [] } ], - "tags": ["FilterSetRestApi"] + "tags": [ + "FilterSetRestApi" + ] }, "post": { "description": "Create a new Dashboard's Filter Set.", @@ -12842,7 +14296,9 @@ "jwt": [] } ], - "tags": ["FilterSetRestApi"] + "tags": [ + "FilterSetRestApi" + ] } }, "/api/v1/dashboard/{dashboard_id}/filtersets/{pk}": { @@ -12903,7 +14359,9 @@ "jwt": [] } ], - "tags": ["FilterSetRestApi"] + "tags": [ + "FilterSetRestApi" + ] }, "put": { "description": "Changes a Dashboard's Filter set.", @@ -12979,7 +14437,9 @@ "jwt": [] } ], - "tags": ["FilterSetRestApi"] + "tags": [ + "FilterSetRestApi" + ] } }, "/api/v1/dashboard/{id_or_slug}": { @@ -13030,7 +14490,9 @@ "jwt": [] } ], - "tags": ["Dashboards"] + "tags": [ + "Dashboards" + ] } }, "/api/v1/dashboard/{id_or_slug}/charts": { @@ -13083,7 +14545,78 @@ "jwt": [] } ], - "tags": ["Dashboards"] + "tags": [ + "Dashboards" + ] + } + }, + "/api/v1/dashboard/{id_or_slug}/copy/": { + "post": { + "parameters": [ + { + "description": "The dashboard id or slug", + "in": "path", + "name": "id_or_slug", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DashboardCopySchema" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "id": { + "type": "number" + }, + "last_modified_time": { + "type": "number" + } + }, + "type": "object" + } + } + }, + "description": "Id of new dashboard and last modified time" + }, + "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": "Makes a copy of an existing dashboard", + "tags": [ + "Dashboards" + ] } }, "/api/v1/dashboard/{id_or_slug}/datasets": { @@ -13137,7 +14670,9 @@ "jwt": [] } ], - "tags": ["Dashboards"] + "tags": [ + "Dashboards" + ] } }, "/api/v1/dashboard/{id_or_slug}/embedded": { @@ -13182,7 +14717,9 @@ "jwt": [] } ], - "tags": ["Dashboards"] + "tags": [ + "Dashboards" + ] }, "get": { "description": "Returns the dashboard's embedded configuration", @@ -13225,7 +14762,9 @@ "jwt": [] } ], - "tags": ["Dashboards"] + "tags": [ + "Dashboards" + ] }, "post": { "description": "Sets a dashboard's embedded configuration.", @@ -13279,7 +14818,9 @@ "jwt": [] } ], - "tags": ["Dashboards"] + "tags": [ + "Dashboards" + ] }, "put": { "description": "Sets a dashboard's embedded configuration.", @@ -13333,7 +14874,9 @@ "jwt": [] } ], - "tags": ["Dashboards"] + "tags": [ + "Dashboards" + ] } }, "/api/v1/dashboard/{pk}": { @@ -13386,7 +14929,9 @@ "jwt": [] } ], - "tags": ["Dashboards"] + "tags": [ + "Dashboards" + ] }, "put": { "description": "Changes a Dashboard.", @@ -13457,7 +15002,105 @@ "jwt": [] } ], - "tags": ["Dashboards"] + "tags": [ + "Dashboards" + ] + } + }, + "/api/v1/dashboard/{pk}/favorites/": { + "delete": { + "description": "Remove the dashboard from the user favorite list", + "parameters": [ + { + "in": "path", + "name": "pk", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "result": { + "type": "object" + } + }, + "type": "object" + } + } + }, + "description": "Dashboard removed from favorites" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "404": { + "$ref": "#/components/responses/404" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "tags": [ + "Dashboards" + ] + }, + "post": { + "description": "Marks the dashboard as favorite for the current user", + "parameters": [ + { + "in": "path", + "name": "pk", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "result": { + "type": "object" + } + }, + "type": "object" + } + } + }, + "description": "Dashboard added to favorites" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "404": { + "$ref": "#/components/responses/404" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "tags": [ + "Dashboards" + ] } }, "/api/v1/dashboard/{pk}/filter_state": { @@ -13525,7 +15168,9 @@ "jwt": [] } ], - "tags": ["Dashboard Filter State"] + "tags": [ + "Dashboard Filter State" + ] } }, "/api/v1/dashboard/{pk}/filter_state/{key}": { @@ -13588,7 +15233,9 @@ "jwt": [] } ], - "tags": ["Dashboard Filter State"] + "tags": [ + "Dashboard Filter State" + ] }, "get": { "description": "Retrives a value.", @@ -13648,7 +15295,9 @@ "jwt": [] } ], - "tags": ["Dashboard Filter State"] + "tags": [ + "Dashboard Filter State" + ] }, "put": { "description": "Updates an existing value.", @@ -13725,7 +15374,9 @@ "jwt": [] } ], - "tags": ["Dashboard Filter State"] + "tags": [ + "Dashboard Filter State" + ] } }, "/api/v1/dashboard/{pk}/permalink": { @@ -13745,7 +15396,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DashboardPermalinkPostSchema" + "$ref": "#/components/schemas/DashboardPermalinkStateSchema" } } }, @@ -13790,7 +15441,9 @@ "jwt": [] } ], - "tags": ["Dashboard Permanent Link"] + "tags": [ + "Dashboard Permanent Link" + ] } }, "/api/v1/dashboard/{pk}/thumbnail/{digest}/": { @@ -13874,7 +15527,9 @@ "jwt": [] } ], - "tags": ["Dashboards"] + "tags": [ + "Dashboards" + ] } }, "/api/v1/database/": { @@ -13981,7 +15636,9 @@ "jwt": [] } ], - "tags": ["Database"] + "tags": [ + "Database" + ] }, "post": { "description": "Create a new Database.", @@ -14033,7 +15690,9 @@ "jwt": [] } ], - "tags": ["Database"] + "tags": [ + "Database" + ] } }, "/api/v1/database/_info": { @@ -14117,7 +15776,9 @@ "jwt": [] } ], - "tags": ["Database"] + "tags": [ + "Database" + ] } }, "/api/v1/database/available/": { @@ -14196,7 +15857,9 @@ "jwt": [] } ], - "tags": ["Database"] + "tags": [ + "Database" + ] } }, "/api/v1/database/export/": { @@ -14242,7 +15905,9 @@ "jwt": [] } ], - "tags": ["Database"] + "tags": [ + "Database" + ] } }, "/api/v1/database/import/": { @@ -14269,12 +15934,12 @@ "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" }, - "ssh_tunnel_private_keys": { - "description": "JSON map of private_keys 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 private_key should be provided in the following format: `{\"databases/MyDatabase.yaml\": \"my_private_key\"}`.", + "ssh_tunnel_private_key_passwords": { + "description": "JSON map of private_key_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 private_key should be provided in the following format: `{\"databases/MyDatabase.yaml\": \"my_private_key_password\"}`.", "type": "string" }, - "ssh_tunnel_private_keyspasswords": { - "description": "JSON map of private_key_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 private_key_password should be provided in the following format: `{\"databases/MyDatabase.yaml\": \"my_private_key_password\"}`.", + "ssh_tunnel_private_keys": { + "description": "JSON map of private_keys 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 private_key should be provided in the following format: `{\"databases/MyDatabase.yaml\": \"my_private_key\"}`.", "type": "string" } }, @@ -14318,44 +15983,2164 @@ "jwt": [] } ], - "tags": ["Database"] + "tags": [ + "Database" + ] + } + }, + "/api/v1/database/test_connection/": { + "post": { + "description": "Tests a database connection", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DatabaseTestConnectionSchema" + } + } + }, + "description": "Database schema", + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "message": { + "type": "string" + } + }, + "type": "object" + } + } + }, + "description": "Database Test Connection" + }, + "400": { + "$ref": "#/components/responses/400" + }, + "422": { + "$ref": "#/components/responses/422" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "tags": [ + "Database" + ] + } + }, + "/api/v1/database/validate_parameters/": { + "post": { + "description": "Validates parameters used to connect to a database", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DatabaseValidateParametersSchema" + } + } + }, + "description": "DB-specific parameters", + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "message": { + "type": "string" + } + }, + "type": "object" + } + } + }, + "description": "Database Test Connection" + }, + "400": { + "$ref": "#/components/responses/400" + }, + "422": { + "$ref": "#/components/responses/422" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "tags": [ + "Database" + ] + } + }, + "/api/v1/database/{pk}": { + "delete": { + "description": "Deletes a Database.", + "parameters": [ + { + "in": "path", + "name": "pk", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "message": { + "type": "string" + } + }, + "type": "object" + } + } + }, + "description": "Database deleted" + }, + "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": [] + } + ], + "tags": [ + "Database" + ] + }, + "get": { + "description": "Get a database", + "parameters": [ + { + "description": "The database id", + "in": "path", + "name": "pk", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "type": "object" + } + } + }, + "description": "Database" + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "422": { + "$ref": "#/components/responses/422" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "tags": [ + "Database" + ] + }, + "put": { + "description": "Changes a Database.", + "parameters": [ + { + "in": "path", + "name": "pk", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DatabaseRestApi.put" + } + } + }, + "description": "Database schema", + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "id": { + "type": "number" + }, + "result": { + "$ref": "#/components/schemas/DatabaseRestApi.put" + } + }, + "type": "object" + } + } + }, + "description": "Database changed" + }, + "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": [] + } + ], + "tags": [ + "Database" + ] + } + }, + "/api/v1/database/{pk}/connection": { + "get": { + "parameters": [ + { + "description": "The database id", + "in": "path", + "name": "pk", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DatabaseConnectionSchema" + } + } + }, + "description": "Database with connection info" + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "422": { + "$ref": "#/components/responses/422" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "summary": "Get a database connection info", + "tags": [ + "Database" + ] + } + }, + "/api/v1/database/{pk}/function_names/": { + "get": { + "description": "Get function names supported by a database", + "parameters": [ + { + "in": "path", + "name": "pk", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DatabaseFunctionNamesResponse" + } + } + }, + "description": "Query result" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "404": { + "$ref": "#/components/responses/404" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "tags": [ + "Database" + ] + } + }, + "/api/v1/database/{pk}/related_objects/": { + "get": { + "description": "Get charts and dashboards count associated to a database", + "parameters": [ + { + "in": "path", + "name": "pk", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DatabaseRelatedObjectsResponse" + } + } + }, + "description": "Query result" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "404": { + "$ref": "#/components/responses/404" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "tags": [ + "Database" + ] + } + }, + "/api/v1/database/{pk}/schemas/": { + "get": { + "description": "Get all schemas from a database", + "parameters": [ + { + "description": "The database id", + "in": "path", + "name": "pk", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/database_schemas_query_schema" + } + } + }, + "in": "query", + "name": "q" + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SchemasResponseSchema" + } + } + }, + "description": "A List of all schemas from the database" + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "404": { + "$ref": "#/components/responses/404" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "tags": [ + "Database" + ] + } + }, + "/api/v1/database/{pk}/schemas_access_for_file_upload/": { + "get": { + "parameters": [ + { + "in": "path", + "name": "pk", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DatabaseSchemaAccessForFileUploadResponse" + } + } + }, + "description": "The list of the database schemas where to upload information" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "404": { + "$ref": "#/components/responses/404" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "summary": "The list of the database schemas where to upload information", + "tags": [ + "Database" + ] + } + }, + "/api/v1/database/{pk}/select_star/{table_name}/": { + "get": { + "description": "Get database select star for table", + "parameters": [ + { + "description": "The database id", + "in": "path", + "name": "pk", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "description": "Table name", + "in": "path", + "name": "table_name", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Table schema", + "in": "path", + "name": "schema_name", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SelectStarResponseSchema" + } + } + }, + "description": "SQL statement for a select star for table" + }, + "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": [ + "Database" + ] + } + }, + "/api/v1/database/{pk}/select_star/{table_name}/{schema_name}/": { + "get": { + "description": "Get database select star for table", + "parameters": [ + { + "description": "The database id", + "in": "path", + "name": "pk", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "description": "Table name", + "in": "path", + "name": "table_name", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Table schema", + "in": "path", + "name": "schema_name", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SelectStarResponseSchema" + } + } + }, + "description": "SQL statement for a select star for table" + }, + "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": [ + "Database" + ] + } + }, + "/api/v1/database/{pk}/ssh_tunnel/": { + "delete": { + "description": "Deletes a SSH Tunnel.", + "parameters": [ + { + "in": "path", + "name": "pk", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "message": { + "type": "string" + } + }, + "type": "object" + } + } + }, + "description": "SSH Tunnel deleted" + }, + "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": [] + } + ], + "tags": [ + "Database" + ] + } + }, + "/api/v1/database/{pk}/table/{table_name}/{schema_name}/": { + "get": { + "description": "Get database table metadata", + "parameters": [ + { + "description": "The database id", + "in": "path", + "name": "pk", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "description": "Table name", + "in": "path", + "name": "table_name", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Table schema", + "in": "path", + "name": "schema_name", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TableMetadataResponseSchema" + } + } + }, + "description": "Table metadata information" + }, + "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": [ + "Database" + ] + } + }, + "/api/v1/database/{pk}/table_extra/{table_name}/{schema_name}/": { + "get": { + "description": "Response depends on each DB engine spec normally focused on partitions", + "parameters": [ + { + "description": "The database id", + "in": "path", + "name": "pk", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "description": "Table name", + "in": "path", + "name": "table_name", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Table schema", + "in": "path", + "name": "schema_name", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TableExtraMetadataResponseSchema" + } + } + }, + "description": "Table extra metadata information" + }, + "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 table extra metadata", + "tags": [ + "Database" + ] + } + }, + "/api/v1/database/{pk}/tables/": { + "get": { + "parameters": [ + { + "description": "The database id", + "in": "path", + "name": "pk", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/database_tables_query_schema" + } + } + }, + "in": "query", + "name": "q" + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "count": { + "type": "integer" + }, + "result": { + "description": "A List of tables for given database", + "items": { + "$ref": "#/components/schemas/DatabaseTablesResponse" + }, + "type": "array" + } + }, + "type": "object" + } + } + }, + "description": "Tables list" + }, + "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 a list of tables for given database", + "tags": [ + "Database" + ] + } + }, + "/api/v1/database/{pk}/validate_sql/": { + "post": { + "description": "Validates arbitrary SQL.", + "parameters": [ + { + "in": "path", + "name": "pk", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidateSQLRequest" + } + } + }, + "description": "Validate SQL request", + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "result": { + "description": "A List of SQL errors found on the statement", + "items": { + "$ref": "#/components/schemas/ValidateSQLResponse" + }, + "type": "array" + } + }, + "type": "object" + } + } + }, + "description": "Validation result" + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "404": { + "$ref": "#/components/responses/404" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "summary": "Validates that arbitrary sql is acceptable for the given database", + "tags": [ + "Database" + ] + } + }, + "/api/v1/dataset/": { + "delete": { + "description": "Deletes multiple Datasets in a bulk operation.", + "parameters": [ + { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/get_delete_ids_schema" + } + } + }, + "in": "query", + "name": "q" + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "message": { + "type": "string" + } + }, + "type": "object" + } + } + }, + "description": "Dataset bulk delete" + }, + "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": [] + } + ], + "tags": [ + "Datasets" + ] + }, + "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/DatasetRestApi.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": [ + "Datasets" + ] + }, + "post": { + "description": "Create a new Dataset", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DatasetRestApi.post" + } + } + }, + "description": "Dataset schema", + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "properties": { + "id": { + "type": "number" + }, + "result": { + "$ref": "#/components/schemas/DatasetRestApi.post" + } + }, + "type": "object" + } + } + }, + "description": "Dataset added" + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "422": { + "$ref": "#/components/responses/422" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "tags": [ + "Datasets" + ] + } + }, + "/api/v1/dataset/_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": [ + "Datasets" + ] + } + }, + "/api/v1/dataset/distinct/{column_name}": { + "get": { + "parameters": [ + { + "in": "path", + "name": "column_name", + "required": true, + "schema": { + "type": "string" + } + }, + { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/get_related_schema" + } + } + }, + "in": "query", + "name": "q" + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DistincResponseSchema" + } + } + }, + "description": "Distinct field data" + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "404": { + "$ref": "#/components/responses/404" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "tags": [ + "Datasets" + ] + } + }, + "/api/v1/dataset/duplicate": { + "post": { + "description": "Duplicates a Dataset", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DatasetDuplicateSchema" + } + } + }, + "description": "Dataset schema", + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "properties": { + "id": { + "type": "number" + }, + "result": { + "$ref": "#/components/schemas/DatasetDuplicateSchema" + } + }, + "type": "object" + } + } + }, + "description": "Dataset duplicated" + }, + "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": [] + } + ], + "tags": [ + "Datasets" + ] + } + }, + "/api/v1/dataset/export/": { + "get": { + "description": "Exports multiple datasets and downloads them as YAML files", + "parameters": [ + { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/get_export_ids_schema" + } + } + }, + "in": "query", + "name": "q" + } + ], + "responses": { + "200": { + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + }, + "description": "Dataset export" + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "404": { + "$ref": "#/components/responses/404" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "tags": [ + "Datasets" + ] + } + }, + "/api/v1/dataset/get_or_create/": { + "post": { + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetOrCreateDatasetSchema" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "result": { + "properties": { + "table_id": { + "type": "integer" + } + }, + "type": "object" + } + }, + "type": "object" + } + } + }, + "description": "The ID of the table" + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "422": { + "$ref": "#/components/responses/422" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "summary": "Retrieve a table by name, or create it if it does not exist", + "tags": [ + "Datasets" + ] + } + }, + "/api/v1/dataset/import/": { + "post": { + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "properties": { + "formData": { + "description": "upload file (ZIP or YAML)", + "format": "binary", + "type": "string" + }, + "overwrite": { + "description": "overwrite existing datasets?", + "type": "boolean" + }, + "passwords": { + "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" + }, + "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" + }, + "ssh_tunnel_private_key_passwords": { + "description": "JSON map of private_key_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 private_key should be provided in the following format: `{\"databases/MyDatabase.yaml\": \"my_private_key_password\"}`.", + "type": "string" + }, + "ssh_tunnel_private_keys": { + "description": "JSON map of private_keys 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 private_key should be provided in the following format: `{\"databases/MyDatabase.yaml\": \"my_private_key\"}`.", + "type": "string" + }, + "sync_columns": { + "description": "sync columns?", + "type": "boolean" + }, + "sync_metrics": { + "description": "sync metrics?", + "type": "boolean" + } + }, + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "message": { + "type": "string" + } + }, + "type": "object" + } + } + }, + "description": "Dataset import result" + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "422": { + "$ref": "#/components/responses/422" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "tags": [ + "Datasets" + ] + } + }, + "/api/v1/dataset/related/{column_name}": { + "get": { + "parameters": [ + { + "in": "path", + "name": "column_name", + "required": true, + "schema": { + "type": "string" + } + }, + { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/get_related_schema" + } + } + }, + "in": "query", + "name": "q" + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RelatedResponseSchema" + } + } + }, + "description": "Related column data" + }, + "400": { + "$ref": "#/components/responses/400" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "404": { + "$ref": "#/components/responses/404" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "tags": [ + "Datasets" + ] + } + }, + "/api/v1/dataset/warm_up_cache": { + "put": { + "description": "Warms up the cache for the table. Note for slices a force refresh occurs. In terms of the `extra_filters` these can be obtained from records in the JSON encoded `logs.json` column associated with the `explore_json` action.", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DatasetCacheWarmUpRequestSchema" + } + } + }, + "description": "Identifies the database and table to warm up cache for, and any additional dashboard or filter context to use.", + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DatasetCacheWarmUpResponseSchema" + } + } + }, + "description": "Each chart's warmup status" + }, + "400": { + "$ref": "#/components/responses/400" + }, + "404": { + "$ref": "#/components/responses/404" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] + } + ], + "summary": "Warms up the cache for each chart powered by the given table", + "tags": [ + "Datasets" + ] + } + }, + "/api/v1/dataset/{pk}": { + "delete": { + "description": "Deletes a Dataset", + "parameters": [ + { + "in": "path", + "name": "pk", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "message": { + "type": "string" + } + }, + "type": "object" + } + } + }, + "description": "Dataset delete" + }, + "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": [] + } + ], + "tags": [ + "Datasets" + ] + }, + "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/DatasetRestApi.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": [ + "Datasets" + ] + }, + "put": { + "description": "Changes a Dataset", + "parameters": [ + { + "in": "path", + "name": "pk", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "in": "query", + "name": "override_columns", + "schema": { + "type": "boolean" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DatasetRestApi.put" + } + } + }, + "description": "Dataset schema", + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "id": { + "type": "number" + }, + "result": { + "$ref": "#/components/schemas/DatasetRestApi.put" + } + }, + "type": "object" + } + } + }, + "description": "Dataset changed" + }, + "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": [] + } + ], + "tags": [ + "Datasets" + ] + } + }, + "/api/v1/dataset/{pk}/column/{column_id}": { + "delete": { + "description": "Delete a Dataset column", + "parameters": [ + { + "description": "The dataset pk for this column", + "in": "path", + "name": "pk", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "description": "The column id for this dataset", + "in": "path", + "name": "column_id", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "message": { + "type": "string" + } + }, + "type": "object" + } + } + }, + "description": "Column deleted" + }, + "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": [] + } + ], + "tags": [ + "Datasets" + ] + } + }, + "/api/v1/dataset/{pk}/metric/{metric_id}": { + "delete": { + "description": "Delete a Dataset metric", + "parameters": [ + { + "description": "The dataset pk for this column", + "in": "path", + "name": "pk", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "description": "The metric id for this dataset", + "in": "path", + "name": "metric_id", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "message": { + "type": "string" + } + }, + "type": "object" + } + } + }, + "description": "Metric deleted" + }, + "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": [] + } + ], + "tags": [ + "Datasets" + ] + } + }, + "/api/v1/dataset/{pk}/refresh": { + "put": { + "description": "Refreshes and updates columns of a dataset", + "parameters": [ + { + "in": "path", + "name": "pk", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "message": { + "type": "string" + } + }, + "type": "object" + } + } + }, + "description": "Dataset delete" + }, + "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": [] + } + ], + "tags": [ + "Datasets" + ] } }, - "/api/v1/database/test_connection/": { - "post": { - "description": "Tests a database connection", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DatabaseTestConnectionSchema" - } + "/api/v1/dataset/{pk}/related_objects": { + "get": { + "description": "Get charts and dashboards count associated to a dataset", + "parameters": [ + { + "in": "path", + "name": "pk", + "required": true, + "schema": { + "type": "integer" } - }, - "description": "Database schema", - "required": true - }, + } + ], "responses": { "200": { "content": { "application/json": { "schema": { - "properties": { - "message": { - "type": "string" - } - }, - "type": "object" + "$ref": "#/components/schemas/DatasetRelatedObjectsResponse" } } }, - "description": "Database Test Connection" + "description": "Query result" }, - "400": { - "$ref": "#/components/responses/400" + "401": { + "$ref": "#/components/responses/401" }, - "422": { - "$ref": "#/components/responses/422" + "404": { + "$ref": "#/components/responses/404" }, "500": { "$ref": "#/components/responses/500" @@ -14366,44 +18151,88 @@ "jwt": [] } ], - "tags": ["Database"] + "tags": [ + "Datasets" + ] } }, - "/api/v1/database/validate_parameters/": { - "post": { - "description": "Validates parameters used to connect to a database", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DatabaseValidateParametersSchema" - } + "/api/v1/datasource/{datasource_type}/{datasource_id}/column/{column_name}/values/": { + "get": { + "parameters": [ + { + "description": "The type of datasource", + "in": "path", + "name": "datasource_type", + "required": true, + "schema": { + "type": "string" } }, - "description": "DB-specific parameters", - "required": true - }, + { + "description": "The id of the datasource", + "in": "path", + "name": "datasource_id", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "description": "The name of the column to get values for", + "in": "path", + "name": "column_name", + "required": true, + "schema": { + "type": "string" + } + } + ], "responses": { "200": { "content": { "application/json": { "schema": { "properties": { - "message": { - "type": "string" + "result": { + "items": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "integer" + }, + { + "type": "number" + }, + { + "type": "boolean" + }, + { + "type": "object" + } + ] + }, + "type": "array" } }, "type": "object" } } }, - "description": "Database Test Connection" + "description": "A List of distinct values for the column" }, "400": { "$ref": "#/components/responses/400" }, - "422": { - "$ref": "#/components/responses/422" + "401": { + "$ref": "#/components/responses/401" + }, + "403": { + "$ref": "#/components/responses/403" + }, + "404": { + "$ref": "#/components/responses/404" }, "500": { "$ref": "#/components/responses/500" @@ -14414,19 +18243,23 @@ "jwt": [] } ], - "tags": ["Database"] + "summary": "Get possible values for a datasource column", + "tags": [ + "Datasources" + ] } }, - "/api/v1/database/{pk}": { - "delete": { - "description": "Deletes a Database.", + "/api/v1/embedded_dashboard/{uuid}": { + "get": { + "description": "Get a report schedule log", "parameters": [ { + "description": "The embedded configuration uuid", "in": "path", - "name": "pk", + "name": "uuid", "required": true, "schema": { - "type": "integer" + "type": "string" } } ], @@ -14436,28 +18269,22 @@ "application/json": { "schema": { "properties": { - "message": { - "type": "string" + "result": { + "$ref": "#/components/schemas/EmbeddedDashboardResponseSchema" } }, "type": "object" } } }, - "description": "Database deleted" + "description": "Result contains the embedded dashboard configuration" }, "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" } @@ -14467,19 +18294,49 @@ "jwt": [] } ], - "tags": ["Database"] - }, + "tags": [ + "Embedded Dashboard" + ] + } + }, + "/api/v1/explore/": { "get": { - "description": "Get a database", + "description": "Assembles Explore related information (form_data, slice, dataset)\\n in a single endpoint.

\\nThe information can be assembled from:
- The cache using a form_data_key
- The metadata database using a permalink_key
- Build from scratch using dataset or slice identifiers.", "parameters": [ { - "description": "The database id", - "in": "path", - "name": "pk", - "required": true, + "in": "query", + "name": "form_data_key", + "schema": { + "type": "string" + } + }, + { + "in": "query", + "name": "permalink_key", + "schema": { + "type": "string" + } + }, + { + "in": "query", + "name": "slice_id", + "schema": { + "type": "integer" + } + }, + { + "in": "query", + "name": "datasource_id", "schema": { "type": "integer" } + }, + { + "in": "query", + "name": "datasource_type", + "schema": { + "type": "string" + } } ], "responses": { @@ -14487,11 +18344,11 @@ "content": { "application/json": { "schema": { - "type": "object" + "$ref": "#/components/schemas/ExploreContextSchema" } } }, - "description": "Database" + "description": "Returns the initial context." }, "400": { "$ref": "#/components/responses/400" @@ -14499,6 +18356,9 @@ "401": { "$ref": "#/components/responses/401" }, + "404": { + "$ref": "#/components/responses/404" + }, "422": { "$ref": "#/components/responses/422" }, @@ -14511,15 +18371,19 @@ "jwt": [] } ], - "tags": ["Database"] - }, - "put": { - "description": "Changes a Database.", + "summary": "Assembles Explore related information (form_data, slice, dataset)\\n in a single endpoint.", + "tags": [ + "Explore" + ] + } + }, + "/api/v1/explore/form_data": { + "post": { + "description": "Stores a new form_data.", "parameters": [ { - "in": "path", - "name": "pk", - "required": true, + "in": "query", + "name": "tab_id", "schema": { "type": "integer" } @@ -14529,31 +18393,28 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DatabaseRestApi.put" + "$ref": "#/components/schemas/FormDataPostSchema" } } }, - "description": "Database schema", "required": true }, "responses": { - "200": { + "201": { "content": { "application/json": { "schema": { "properties": { - "id": { - "type": "number" - }, - "result": { - "$ref": "#/components/schemas/DatabaseRestApi.put" + "key": { + "description": "The key to retrieve the form_data.", + "type": "string" } }, "type": "object" } } }, - "description": "Database changed" + "description": "The form_data was stored successfully." }, "400": { "$ref": "#/components/responses/400" @@ -14561,12 +18422,6 @@ "401": { "$ref": "#/components/responses/401" }, - "403": { - "$ref": "#/components/responses/403" - }, - "404": { - "$ref": "#/components/responses/404" - }, "422": { "$ref": "#/components/responses/422" }, @@ -14579,19 +18434,22 @@ "jwt": [] } ], - "tags": ["Database"] + "tags": [ + "Explore Form Data" + ] } }, - "/api/v1/database/{pk}/function_names/": { - "get": { - "description": "Get function names supported by a database", + "/api/v1/explore/form_data/{key}": { + "delete": { + "description": "Deletes a form_data.", "parameters": [ { + "description": "The form_data key.", "in": "path", - "name": "pk", + "name": "key", "required": true, "schema": { - "type": "integer" + "type": "string" } } ], @@ -14600,11 +18458,20 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DatabaseFunctionNamesResponse" + "properties": { + "message": { + "description": "The result of the operation", + "type": "string" + } + }, + "type": "object" } } }, - "description": "Query result" + "description": "Deleted the stored form_data." + }, + "400": { + "$ref": "#/components/responses/400" }, "401": { "$ref": "#/components/responses/401" @@ -14612,6 +18479,9 @@ "404": { "$ref": "#/components/responses/404" }, + "422": { + "$ref": "#/components/responses/422" + }, "500": { "$ref": "#/components/responses/500" } @@ -14621,19 +18491,19 @@ "jwt": [] } ], - "tags": ["Database"] - } - }, - "/api/v1/database/{pk}/related_objects/": { + "tags": [ + "Explore Form Data" + ] + }, "get": { - "description": "Get charts and dashboards count associated to a database", + "description": "Retrives a form_data.", "parameters": [ { "in": "path", - "name": "pk", + "name": "key", "required": true, "schema": { - "type": "integer" + "type": "string" } } ], @@ -14642,11 +18512,20 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DatabaseRelatedObjectsResponse" + "properties": { + "form_data": { + "description": "The stored form_data", + "type": "string" + } + }, + "type": "object" } } }, - "description": "Query result" + "description": "Returns the stored form_data." + }, + "400": { + "$ref": "#/components/responses/400" }, "401": { "$ref": "#/components/responses/401" @@ -14654,6 +18533,9 @@ "404": { "$ref": "#/components/responses/404" }, + "422": { + "$ref": "#/components/responses/422" + }, "500": { "$ref": "#/components/responses/500" } @@ -14663,44 +18545,55 @@ "jwt": [] } ], - "tags": ["Database"] - } - }, - "/api/v1/database/{pk}/schemas/": { - "get": { - "description": "Get all schemas from a database", + "tags": [ + "Explore Form Data" + ] + }, + "put": { + "description": "Updates an existing form_data.", "parameters": [ { - "description": "The database id", "in": "path", - "name": "pk", + "name": "key", "required": true, "schema": { - "type": "integer" + "type": "string" } }, { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/database_schemas_query_schema" - } - } - }, "in": "query", - "name": "q" + "name": "tab_id", + "schema": { + "type": "integer" + } } ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FormDataPutSchema" + } + } + }, + "required": true + }, "responses": { "200": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SchemasResponseSchema" + "properties": { + "key": { + "description": "The key to retrieve the form_data.", + "type": "string" + } + }, + "type": "object" } } }, - "description": "A List of all schemas from the database" + "description": "The form_data was stored successfully." }, "400": { "$ref": "#/components/responses/400" @@ -14711,6 +18604,9 @@ "404": { "$ref": "#/components/responses/404" }, + "422": { + "$ref": "#/components/responses/422" + }, "500": { "$ref": "#/components/responses/500" } @@ -14720,37 +18616,53 @@ "jwt": [] } ], - "tags": ["Database"] + "tags": [ + "Explore Form Data" + ] } }, - "/api/v1/database/{pk}/schemas_access_for_file_upload/": { - "get": { - "parameters": [ - { - "in": "path", - "name": "pk", - "required": true, - "schema": { - "type": "integer" + "/api/v1/explore/permalink": { + "post": { + "description": "Stores a new permanent link.", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExplorePermalinkStateSchema" + } } - } - ], + }, + "required": true + }, "responses": { - "200": { + "201": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DatabaseSchemaAccessForFileUploadResponse" + "properties": { + "key": { + "description": "The key to retrieve the permanent link data.", + "type": "string" + }, + "url": { + "description": "permanent link.", + "type": "string" + } + }, + "type": "object" } } }, - "description": "The list of the database schemas where to upload information" + "description": "The permanent link was stored successfully." + }, + "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" @@ -14761,36 +18673,18 @@ "jwt": [] } ], - "summary": "The list of the database schemas where to upload information", - "tags": ["Database"] + "tags": [ + "Explore Permanent Link" + ] } }, - "/api/v1/database/{pk}/select_star/{table_name}/": { + "/api/v1/explore/permalink/{key}": { "get": { - "description": "Get database select star for table", + "description": "Retrives chart state associated with a permanent link.", "parameters": [ { - "description": "The database id", - "in": "path", - "name": "pk", - "required": true, - "schema": { - "type": "integer" - } - }, - { - "description": "Table name", - "in": "path", - "name": "table_name", - "required": true, - "schema": { - "type": "string" - } - }, - { - "description": "Table schema", "in": "path", - "name": "schema_name", + "name": "key", "required": true, "schema": { "type": "string" @@ -14802,11 +18696,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SelectStarResponseSchema" + "properties": { + "state": { + "description": "The stored state", + "type": "object" + } + }, + "type": "object" } } }, - "description": "SQL statement for a select star for table" + "description": "Returns the stored form_data." }, "400": { "$ref": "#/components/responses/400" @@ -14829,39 +18729,25 @@ "jwt": [] } ], - "tags": ["Database"] + "tags": [ + "Explore Permanent Link" + ] } }, - "/api/v1/database/{pk}/select_star/{table_name}/{schema_name}/": { + "/api/v1/log/": { "get": { - "description": "Get database select star for table", + "description": "Get a list of models", "parameters": [ { - "description": "The database id", - "in": "path", - "name": "pk", - "required": true, - "schema": { - "type": "integer" - } - }, - { - "description": "Table name", - "in": "path", - "name": "table_name", - "required": true, - "schema": { - "type": "string" - } - }, - { - "description": "Table schema", - "in": "path", - "name": "schema_name", - "required": true, - "schema": { - "type": "string" - } + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/get_list_schema" + } + } + }, + "in": "query", + "name": "q" } ], "responses": { @@ -14869,11 +18755,70 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SelectStarResponseSchema" + "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/LogRestApi.get_list" + }, + "type": "array" + } + }, + "type": "object" } } }, - "description": "SQL statement for a select star for table" + "description": "Items from Model" }, "400": { "$ref": "#/components/responses/400" @@ -14881,9 +18826,6 @@ "401": { "$ref": "#/components/responses/401" }, - "404": { - "$ref": "#/components/responses/404" - }, "422": { "$ref": "#/components/responses/422" }, @@ -14896,47 +18838,47 @@ "jwt": [] } ], - "tags": ["Database"] - } - }, - "/api/v1/database/{pk}/ssh_tunnel/": { - "delete": { - "description": "Deletes a SSH Tunnel.", - "parameters": [ - { - "in": "path", - "name": "pk", - "required": true, - "schema": { - "type": "integer" + "tags": [ + "LogRestApi" + ] + }, + "post": { + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LogRestApi.post" + } } - } - ], + }, + "description": "Model schema", + "required": true + }, "responses": { - "200": { + "201": { "content": { "application/json": { "schema": { "properties": { - "message": { + "id": { "type": "string" + }, + "result": { + "$ref": "#/components/schemas/LogRestApi.post" } }, "type": "object" } } }, - "description": "SSH Tunnel deleted" + "description": "Item inserted" + }, + "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" }, @@ -14949,106 +18891,33 @@ "jwt": [] } ], - "tags": ["Database"] + "tags": [ + "LogRestApi" + ] } }, - "/api/v1/database/{pk}/table/{table_name}/{schema_name}/": { + "/api/v1/log/recent_activity/": { "get": { - "description": "Get database table metadata", "parameters": [ { - "description": "The database id", + "description": "The id of the user", "in": "path", - "name": "pk", + "name": "user_id", "required": true, "schema": { "type": "integer" } }, { - "description": "Table name", - "in": "path", - "name": "table_name", - "required": true, - "schema": { - "type": "string" - } - }, - { - "description": "Table schema", - "in": "path", - "name": "schema_name", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/TableMetadataResponseSchema" + "$ref": "#/components/schemas/get_recent_activity_schema" } } }, - "description": "Table metadata information" - }, - "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": ["Database"] - } - }, - "/api/v1/database/{pk}/table_extra/{table_name}/{schema_name}/": { - "get": { - "description": "Response depends on each DB engine spec normally focused on partitions", - "parameters": [ - { - "description": "The database id", - "in": "path", - "name": "pk", - "required": true, - "schema": { - "type": "integer" - } - }, - { - "description": "Table name", - "in": "path", - "name": "table_name", - "required": true, - "schema": { - "type": "string" - } - }, - { - "description": "Table schema", - "in": "path", - "name": "schema_name", - "required": true, - "schema": { - "type": "string" - } + "in": "query", + "name": "q" } ], "responses": { @@ -15056,11 +18925,11 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/TableExtraMetadataResponseSchema" + "$ref": "#/components/schemas/RecentActivityResponseSchema" } } }, - "description": "Table extra metadata information" + "description": "A List of recent activity objects" }, "400": { "$ref": "#/components/responses/400" @@ -15068,11 +18937,8 @@ "401": { "$ref": "#/components/responses/401" }, - "404": { - "$ref": "#/components/responses/404" - }, - "422": { - "$ref": "#/components/responses/422" + "403": { + "$ref": "#/components/responses/403" }, "500": { "$ref": "#/components/responses/500" @@ -15083,15 +18949,17 @@ "jwt": [] } ], - "summary": "Get table extra metadata", - "tags": ["Database"] + "summary": "Get recent activity data for a user", + "tags": [ + "LogRestApi" + ] } }, - "/api/v1/database/{pk}/tables/": { + "/api/v1/log/{pk}": { "get": { + "description": "Get an item model", "parameters": [ { - "description": "The database id", "in": "path", "name": "pk", "required": true, @@ -15103,7 +18971,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/database_tables_query_schema" + "$ref": "#/components/schemas/get_item_schema" } } }, @@ -15117,22 +18985,51 @@ "application/json": { "schema": { "properties": { - "count": { - "type": "integer" + "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": { - "description": "A List of tables for given database", + "$ref": "#/components/schemas/LogRestApi.get" + }, + "show_columns": { + "description": "A list of columns", "items": { - "$ref": "#/components/schemas/DatabaseTablesResponse" + "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": "Tables list" + "description": "Item from Model" }, "400": { "$ref": "#/components/responses/400" @@ -15155,34 +19052,14 @@ "jwt": [] } ], - "summary": "Get a list of tables for given database", - "tags": ["Database"] + "tags": [ + "LogRestApi" + ] } }, - "/api/v1/database/{pk}/validate_sql/": { - "post": { - "description": "Validates arbitrary SQL.", - "parameters": [ - { - "in": "path", - "name": "pk", - "required": true, - "schema": { - "type": "integer" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ValidateSQLRequest" - } - } - }, - "description": "Validate SQL request", - "required": true - }, + "/api/v1/me/": { + "get": { + "description": "Returns the user object corresponding to the agent making the request, or returns a 401 error if the user is unauthenticated.", "responses": { "200": { "content": { @@ -15190,90 +19067,101 @@ "schema": { "properties": { "result": { - "description": "A List of SQL errors found on the statement", - "items": { - "$ref": "#/components/schemas/ValidateSQLResponse" - }, - "type": "array" + "$ref": "#/components/schemas/UserResponseSchema" } }, "type": "object" } } }, - "description": "Validation result" - }, - "400": { - "$ref": "#/components/responses/400" + "description": "The current user" }, "401": { "$ref": "#/components/responses/401" - }, - "404": { - "$ref": "#/components/responses/404" - }, - "500": { - "$ref": "#/components/responses/500" } }, - "security": [ - { - "jwt": [] - } - ], - "summary": "Validates that arbitrary sql is acceptable for the given database", - "tags": ["Database"] + "tags": [ + "Current User" + ] } }, - "/api/v1/dataset/": { - "delete": { - "description": "Deletes multiple Datasets in a bulk operation.", - "parameters": [ - { + "/api/v1/me/roles/": { + "get": { + "description": "Returns the user roles corresponding to the agent making the request, or returns a 401 error if the user is unauthenticated.", + "responses": { + "200": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/get_delete_ids_schema" + "properties": { + "result": { + "$ref": "#/components/schemas/UserResponseSchema" + } + }, + "type": "object" } } }, - "in": "query", - "name": "q" + "description": "The current user" + }, + "401": { + "$ref": "#/components/responses/401" } - ], + }, + "tags": [ + "Current User" + ] + } + }, + "/api/v1/menu/": { + "get": { + "description": "Get the menu data structure. Returns a forest like structure with the menu the user has access to", "responses": { "200": { "content": { "application/json": { "schema": { "properties": { - "message": { - "type": "string" + "result": { + "description": "Menu items in a forest like data structure", + "items": { + "properties": { + "childs": { + "items": { + "type": "object" + }, + "type": "array" + }, + "icon": { + "description": "Icon name to show for this menu item", + "type": "string" + }, + "label": { + "description": "Pretty name for the menu item", + "type": "string" + }, + "name": { + "description": "The internal menu item name, maps to permission_name", + "type": "string" + }, + "url": { + "description": "The URL for the menu item", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" } }, "type": "object" } } }, - "description": "Dataset bulk delete" - }, - "400": { - "$ref": "#/components/responses/400" + "description": "Get menu data" }, "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": [ @@ -15281,10 +19169,14 @@ "jwt": [] } ], - "tags": ["Datasets"] - }, + "tags": [ + "Menu" + ] + } + }, + "/api/v1/query/": { "get": { - "description": "Get a list of models", + "description": "Get a list of queries, use Rison or JSON query parameters for filtering, sorting, pagination and for selecting specific columns and metadata.", "parameters": [ { "content": { @@ -15357,7 +19249,7 @@ "result": { "description": "The result from the get list query", "items": { - "$ref": "#/components/schemas/DatasetRestApi.get_list" + "$ref": "#/components/schemas/QueryRestApi.get_list" }, "type": "array" } @@ -15386,70 +19278,27 @@ "jwt": [] } ], - "tags": ["Datasets"] - }, - "post": { - "description": "Create a new Dataset", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DatasetRestApi.post" - } - } - }, - "description": "Dataset schema", - "required": true - }, - "responses": { - "201": { - "content": { - "application/json": { - "schema": { - "properties": { - "id": { - "type": "number" - }, - "result": { - "$ref": "#/components/schemas/DatasetRestApi.post" - } - }, - "type": "object" - } - } - }, - "description": "Dataset added" - }, - "400": { - "$ref": "#/components/responses/400" - }, - "401": { - "$ref": "#/components/responses/401" - }, - "422": { - "$ref": "#/components/responses/422" - }, - "500": { - "$ref": "#/components/responses/500" - } - }, - "security": [ - { - "jwt": [] - } - ], - "tags": ["Datasets"] + "tags": [ + "Queries" + ] } }, - "/api/v1/dataset/_info": { + "/api/v1/query/distinct/{column_name}": { "get": { - "description": "Get metadata information about this API resource", "parameters": [ + { + "in": "path", + "name": "column_name", + "required": true, + "schema": { + "type": "string" + } + }, { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/get_info_schema" + "$ref": "#/components/schemas/get_related_schema" } } }, @@ -15462,47 +19311,11 @@ "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" + "$ref": "#/components/schemas/DistincResponseSchema" } } }, - "description": "Item from Model" + "description": "Distinct field data" }, "400": { "$ref": "#/components/responses/400" @@ -15510,8 +19323,8 @@ "401": { "$ref": "#/components/responses/401" }, - "422": { - "$ref": "#/components/responses/422" + "404": { + "$ref": "#/components/responses/404" }, "500": { "$ref": "#/components/responses/500" @@ -15522,10 +19335,12 @@ "jwt": [] } ], - "tags": ["Datasets"] + "tags": [ + "Queries" + ] } }, - "/api/v1/dataset/distinct/{column_name}": { + "/api/v1/query/related/{column_name}": { "get": { "parameters": [ { @@ -15553,11 +19368,11 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DistincResponseSchema" + "$ref": "#/components/schemas/RelatedResponseSchema" } } }, - "description": "Distinct field data" + "description": "Related column data" }, "400": { "$ref": "#/components/responses/400" @@ -15577,95 +19392,39 @@ "jwt": [] } ], - "tags": ["Datasets"] + "tags": [ + "Queries" + ] } }, - "/api/v1/dataset/duplicate": { + "/api/v1/query/stop": { "post": { - "description": "Duplicates a Dataset", "requestBody": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DatasetDuplicateSchema" + "$ref": "#/components/schemas/StopQuerySchema" } } }, - "description": "Dataset schema", + "description": "Stop query schema", "required": true }, - "responses": { - "201": { - "content": { - "application/json": { - "schema": { - "properties": { - "id": { - "type": "number" - }, - "result": { - "$ref": "#/components/schemas/DatasetDuplicateSchema" - } - }, - "type": "object" - } - } - }, - "description": "Dataset duplicated" - }, - "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": [] - } - ], - "tags": ["Datasets"] - } - }, - "/api/v1/dataset/export/": { - "get": { - "description": "Exports multiple datasets and downloads them as YAML files", - "parameters": [ - { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/get_export_ids_schema" - } - } - }, - "in": "query", - "name": "q" - } - ], "responses": { "200": { "content": { - "text/plain": { + "application/json": { "schema": { - "type": "string" + "properties": { + "result": { + "type": "string" + } + }, + "type": "object" } } }, - "description": "Dataset export" + "description": "Query stopped" }, "400": { "$ref": "#/components/responses/400" @@ -15685,71 +19444,46 @@ "jwt": [] } ], - "tags": ["Datasets"] + "summary": "Manually stop a query with client_id", + "tags": [ + "Queries" + ] } }, - "/api/v1/dataset/import/": { - "post": { - "requestBody": { - "content": { - "multipart/form-data": { - "schema": { - "properties": { - "formData": { - "description": "upload file (ZIP or YAML)", - "format": "binary", - "type": "string" - }, - "overwrite": { - "description": "overwrite existing datasets?", - "type": "boolean" - }, - "passwords": { - "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" - }, - "sync_columns": { - "description": "sync columns?", - "type": "boolean" - }, - "sync_metrics": { - "description": "sync metrics?", - "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" - }, - "ssh_tunnel_private_keys": { - "description": "JSON map of private_keys 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 private_key should be provided in the following format: `{\"databases/MyDatabase.yaml\": \"my_private_key\"}`.", - "type": "string" - }, - "ssh_tunnel_private_keyspasswords": { - "description": "JSON map of private_key_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 private_key_password should be provided in the following format: `{\"databases/MyDatabase.yaml\": \"my_private_key_password\"}`.", - "type": "string" - } - }, - "type": "object" + "/api/v1/query/updated_since": { + "get": { + "parameters": [ + { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/queries_get_updated_since_schema" + } } - } - }, - "required": true - }, + }, + "in": "query", + "name": "q" + } + ], "responses": { "200": { "content": { "application/json": { "schema": { "properties": { - "message": { - "type": "string" + "result": { + "description": "A List of queries that changed after last_updated_ms", + "items": { + "$ref": "#/components/schemas/QueryRestApi.get" + }, + "type": "array" } }, "type": "object" } } }, - "description": "Dataset import result" + "description": "Queries list" }, "400": { "$ref": "#/components/responses/400" @@ -15757,8 +19491,8 @@ "401": { "$ref": "#/components/responses/401" }, - "422": { - "$ref": "#/components/responses/422" + "404": { + "$ref": "#/components/responses/404" }, "500": { "$ref": "#/components/responses/500" @@ -15769,25 +19503,29 @@ "jwt": [] } ], - "tags": ["Datasets"] + "summary": "Get a list of queries that changed after last_updated_ms", + "tags": [ + "Queries" + ] } }, - "/api/v1/dataset/related/{column_name}": { + "/api/v1/query/{pk}": { "get": { + "description": "Get query detail information.", "parameters": [ { "in": "path", - "name": "column_name", + "name": "pk", "required": true, "schema": { - "type": "string" + "type": "integer" } }, { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/get_related_schema" + "$ref": "#/components/schemas/get_item_schema" } } }, @@ -15800,11 +19538,52 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/RelatedResponseSchema" + "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/QueryRestApi.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": "Related column data" + "description": "Item from Model" }, "400": { "$ref": "#/components/responses/400" @@ -15815,6 +19594,9 @@ "404": { "$ref": "#/components/responses/404" }, + "422": { + "$ref": "#/components/responses/422" + }, "500": { "$ref": "#/components/responses/500" } @@ -15824,20 +19606,25 @@ "jwt": [] } ], - "tags": ["Datasets"] + "tags": [ + "Queries" + ] } }, - "/api/v1/dataset/{pk}": { + "/api/v1/report/": { "delete": { - "description": "Deletes a Dataset", + "description": "Deletes multiple report schedules in a bulk operation.", "parameters": [ { - "in": "path", - "name": "pk", - "required": true, - "schema": { - "type": "integer" - } + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/get_delete_ids_schema" + } + } + }, + "in": "query", + "name": "q" } ], "responses": { @@ -15854,7 +19641,7 @@ } } }, - "description": "Dataset delete" + "description": "Report Schedule bulk delete" }, "401": { "$ref": "#/components/responses/401" @@ -15877,24 +19664,18 @@ "jwt": [] } ], - "tags": ["Datasets"] + "tags": [ + "Report Schedules" + ] }, "get": { - "description": "Get an item model", + "description": "Get a list of report schedules, use Rison or JSON query parameters for filtering, sorting, pagination and for selecting specific columns and metadata.", "parameters": [ - { - "in": "path", - "name": "pk", - "required": true, - "schema": { - "type": "integer" - } - }, { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/get_item_schema" + "$ref": "#/components/schemas/get_list_schema" } } }, @@ -15908,6 +19689,10 @@ "application/json": { "schema": { "properties": { + "count": { + "description": "The total record count on the backend", + "type": "number" + }, "description_columns": { "properties": { "column_name": { @@ -15918,9 +19703,12 @@ }, "type": "object" }, - "id": { - "description": "The item id", - "type": "string" + "ids": { + "description": "A list of item ids, useful when you don't know the column id", + "items": { + "type": "string" + }, + "type": "array" }, "label_columns": { "properties": { @@ -15932,27 +19720,92 @@ }, "type": "object" }, - "result": { - "$ref": "#/components/schemas/DatasetRestApi.get" - }, - "show_columns": { + "list_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" + "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/ReportScheduleRestApi.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": [ + "Report Schedules" + ] + }, + "post": { + "description": "Create a report schedule", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ReportScheduleRestApi.post" + } + } + }, + "description": "Report Schedule schema", + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "properties": { + "id": { + "type": "number" + }, + "result": { + "$ref": "#/components/schemas/ReportScheduleRestApi.post" } }, "type": "object" } } }, - "description": "Item from Model" + "description": "Report schedule added" }, "400": { "$ref": "#/components/responses/400" @@ -15975,56 +19828,73 @@ "jwt": [] } ], - "tags": ["Datasets"] - }, - "put": { - "description": "Changes a Dataset", + "tags": [ + "Report Schedules" + ] + } + }, + "/api/v1/report/_info": { + "get": { + "description": "Get metadata information about this API resource", "parameters": [ { - "in": "path", - "name": "pk", - "required": true, - "schema": { - "type": "integer" - } - }, - { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/get_info_schema" + } + } + }, "in": "query", - "name": "override_columns", - "schema": { - "type": "boolean" - } + "name": "q" } ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DatasetRestApi.put" - } - } - }, - "description": "Dataset schema", - "required": true - }, "responses": { "200": { "content": { "application/json": { "schema": { "properties": { - "id": { - "type": "number" + "add_columns": { + "type": "object" }, - "result": { - "$ref": "#/components/schemas/DatasetRestApi.put" + "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": "Dataset changed" + "description": "Item from Model" }, "400": { "$ref": "#/components/responses/400" @@ -16032,12 +19902,6 @@ "401": { "$ref": "#/components/responses/401" }, - "403": { - "$ref": "#/components/responses/403" - }, - "404": { - "$ref": "#/components/responses/404" - }, "422": { "$ref": "#/components/responses/422" }, @@ -16050,30 +19914,32 @@ "jwt": [] } ], - "tags": ["Datasets"] + "tags": [ + "Report Schedules" + ] } }, - "/api/v1/dataset/{pk}/column/{column_id}": { - "delete": { - "description": "Delete a Dataset column", + "/api/v1/report/related/{column_name}": { + "get": { "parameters": [ { - "description": "The dataset pk for this column", "in": "path", - "name": "pk", + "name": "column_name", "required": true, "schema": { - "type": "integer" + "type": "string" } }, { - "description": "The column id for this dataset", - "in": "path", - "name": "column_id", - "required": true, - "schema": { - "type": "integer" - } + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/get_related_schema" + } + } + }, + "in": "query", + "name": "q" } ], "responses": { @@ -16081,29 +19947,21 @@ "content": { "application/json": { "schema": { - "properties": { - "message": { - "type": "string" - } - }, - "type": "object" + "$ref": "#/components/schemas/RelatedResponseSchema" } } }, - "description": "Column deleted" + "description": "Related column data" + }, + "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" } @@ -16113,30 +19971,23 @@ "jwt": [] } ], - "tags": ["Datasets"] + "tags": [ + "Report Schedules" + ] } }, - "/api/v1/dataset/{pk}/metric/{metric_id}": { + "/api/v1/report/{pk}": { "delete": { - "description": "Delete a Dataset metric", + "description": "Delete a report schedule", "parameters": [ { - "description": "The dataset pk for this column", + "description": "The report schedule pk", "in": "path", "name": "pk", "required": true, "schema": { "type": "integer" } - }, - { - "description": "The metric id for this dataset", - "in": "path", - "name": "metric_id", - "required": true, - "schema": { - "type": "integer" - } } ], "responses": { @@ -16153,10 +20004,7 @@ } } }, - "description": "Metric deleted" - }, - "401": { - "$ref": "#/components/responses/401" + "description": "Item deleted" }, "403": { "$ref": "#/components/responses/403" @@ -16176,12 +20024,12 @@ "jwt": [] } ], - "tags": ["Datasets"] - } - }, - "/api/v1/dataset/{pk}/refresh": { - "put": { - "description": "Refreshes and updates columns of a dataset", + "tags": [ + "Report Schedules" + ] + }, + "get": { + "description": "Get a report schedule", "parameters": [ { "in": "path", @@ -16190,6 +20038,17 @@ "schema": { "type": "integer" } + }, + { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/get_item_schema" + } + } + }, + "in": "query", + "name": "q" } ], "responses": { @@ -16198,7 +20057,43 @@ "application/json": { "schema": { "properties": { - "message": { + "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/ReportScheduleRestApi.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" } }, @@ -16206,14 +20101,14 @@ } } }, - "description": "Dataset delete" + "description": "Item from Model" + }, + "400": { + "$ref": "#/components/responses/400" }, "401": { "$ref": "#/components/responses/401" }, - "403": { - "$ref": "#/components/responses/403" - }, "404": { "$ref": "#/components/responses/404" }, @@ -16229,14 +20124,15 @@ "jwt": [] } ], - "tags": ["Datasets"] - } - }, - "/api/v1/dataset/{pk}/related_objects": { - "get": { - "description": "Get charts and dashboards count associated to a dataset", + "tags": [ + "Report Schedules" + ] + }, + "put": { + "description": "Update a report schedule", "parameters": [ { + "description": "The Report Schedule pk", "in": "path", "name": "pk", "required": true, @@ -16245,23 +20141,51 @@ } } ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ReportScheduleRestApi.put" + } + } + }, + "description": "Report Schedule schema", + "required": true + }, "responses": { "200": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DatasetRelatedObjectsResponse" + "properties": { + "id": { + "type": "number" + }, + "result": { + "$ref": "#/components/schemas/ReportScheduleRestApi.put" + } + }, + "type": "object" } } }, - "description": "Query result" + "description": "Report Schedule changed" + }, + "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" } @@ -16271,38 +20195,34 @@ "jwt": [] } ], - "tags": ["Datasets"] + "tags": [ + "Report Schedules" + ] } }, - "/api/v1/datasource/{datasource_type}/{datasource_id}/column/{column_name}/values/": { + "/api/v1/report/{pk}/log/": { "get": { + "description": "Get a list of report schedule logs, use Rison or JSON query parameters for filtering, sorting, pagination and for selecting specific columns and metadata.", "parameters": [ { - "description": "The type of datasource", - "in": "path", - "name": "datasource_type", - "required": true, - "schema": { - "type": "string" - } - }, - { - "description": "The id of the datasource", + "description": "The report schedule id for these logs", "in": "path", - "name": "datasource_id", + "name": "pk", "required": true, "schema": { "type": "integer" } }, { - "description": "The name of the column to get values for", - "in": "path", - "name": "column_name", - "required": true, - "schema": { - "type": "string" - } + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/get_list_schema" + } + } + }, + "in": "query", + "name": "q" } ], "responses": { @@ -16311,25 +20231,21 @@ "application/json": { "schema": { "properties": { + "count": { + "description": "The total record count on the backend", + "type": "number" + }, + "ids": { + "description": "A list of log ids", + "items": { + "type": "string" + }, + "type": "array" + }, "result": { + "description": "The result from the get list query", "items": { - "oneOf": [ - { - "type": "string" - }, - { - "type": "integer" - }, - { - "type": "number" - }, - { - "type": "boolean" - }, - { - "type": "object" - } - ] + "$ref": "#/components/schemas/ReportExecutionLogRestApi.get_list" }, "type": "array" } @@ -16338,7 +20254,7 @@ } } }, - "description": "A List of distinct values for the column" + "description": "Items from logs" }, "400": { "$ref": "#/components/responses/400" @@ -16346,11 +20262,8 @@ "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" @@ -16361,22 +20274,43 @@ "jwt": [] } ], - "summary": "Get possible values for a datasource column", - "tags": ["Datasources"] + "tags": [ + "Report Schedules" + ] } }, - "/api/v1/embedded_dashboard/{uuid}": { + "/api/v1/report/{pk}/log/{log_id}": { "get": { "description": "Get a report schedule log", "parameters": [ { - "description": "The embedded configuration uuid", + "description": "The report schedule pk for log", "in": "path", - "name": "uuid", + "name": "pk", "required": true, "schema": { - "type": "string" + "type": "integer" + } + }, + { + "description": "The log pk", + "in": "path", + "name": "log_id", + "required": true, + "schema": { + "type": "integer" } + }, + { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/get_item_schema" + } + } + }, + "in": "query", + "name": "q" } ], "responses": { @@ -16385,15 +20319,22 @@ "application/json": { "schema": { "properties": { + "id": { + "description": "The log id", + "type": "string" + }, "result": { - "$ref": "#/components/schemas/EmbeddedDashboardResponseSchema" + "$ref": "#/components/schemas/ReportExecutionLogRestApi.get" } }, "type": "object" } } }, - "description": "Result contains the embedded dashboard configuration" + "description": "Item log" + }, + "400": { + "$ref": "#/components/responses/400" }, "401": { "$ref": "#/components/responses/401" @@ -16401,6 +20342,9 @@ "404": { "$ref": "#/components/responses/404" }, + "422": { + "$ref": "#/components/responses/422" + }, "500": { "$ref": "#/components/responses/500" } @@ -16410,47 +20354,25 @@ "jwt": [] } ], - "tags": ["Embedded Dashboard"] + "tags": [ + "Report Schedules" + ] } }, - "/api/v1/explore/": { - "get": { - "description": "Assembles Explore related information (form_data, slice, dataset)\\n in a single endpoint.

\\nThe information can be assembled from:
- The cache using a form_data_key
- The metadata database using a permalink_key
- Build from scratch using dataset or slice identifiers.", + "/api/v1/rowlevelsecurity/": { + "delete": { + "description": "Deletes multiple RLS rules in a bulk operation.", "parameters": [ { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/get_delete_ids_schema" + } + } + }, "in": "query", - "name": "form_data_key", - "schema": { - "type": "string" - } - }, - { - "in": "query", - "name": "permalink_key", - "schema": { - "type": "string" - } - }, - { - "in": "query", - "name": "slice_id", - "schema": { - "type": "integer" - } - }, - { - "in": "query", - "name": "datasource_id", - "schema": { - "type": "integer" - } - }, - { - "in": "query", - "name": "datasource_type", - "schema": { - "type": "string" - } + "name": "q" } ], "responses": { @@ -16458,18 +20380,23 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ExploreContextSchema" + "properties": { + "message": { + "type": "string" + } + }, + "type": "object" } } }, - "description": "Returns the initial context." - }, - "400": { - "$ref": "#/components/responses/400" + "description": "RLS Rule bulk delete" }, "401": { "$ref": "#/components/responses/401" }, + "403": { + "$ref": "#/components/responses/403" + }, "404": { "$ref": "#/components/responses/404" }, @@ -16485,48 +20412,94 @@ "jwt": [] } ], - "summary": "Assembles Explore related information (form_data, slice, dataset)\\n in a single endpoint.", - "tags": ["Explore"] - } - }, - "/api/v1/explore/form_data": { - "post": { - "description": "Stores a new form_data.", + "tags": [ + "Row Level Security" + ] + }, + "get": { + "description": "Get a list of models", "parameters": [ { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/get_list_schema" + } + } + }, "in": "query", - "name": "tab_id", - "schema": { - "type": "integer" - } + "name": "q" } ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/FormDataPostSchema" - } - } - }, - "required": true - }, "responses": { - "201": { + "200": { "content": { "application/json": { "schema": { "properties": { - "key": { - "description": "The key to retrieve the form_data.", + "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/RLSRestApi.get_list" + }, + "type": "array" } }, "type": "object" } } }, - "description": "The form_data was stored successfully." + "description": "Items from Model" }, "400": { "$ref": "#/components/responses/400" @@ -16546,39 +20519,41 @@ "jwt": [] } ], - "tags": ["Explore Form Data"] - } - }, - "/api/v1/explore/form_data/{key}": { - "delete": { - "description": "Deletes a form_data.", - "parameters": [ - { - "description": "The form_data key.", - "in": "path", - "name": "key", - "required": true, - "schema": { - "type": "string" + "tags": [ + "Row Level Security" + ] + }, + "post": { + "description": "Create a new RLS Rule", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RLSRestApi.post" + } } - } - ], + }, + "description": "RLS schema", + "required": true + }, "responses": { - "200": { + "201": { "content": { "application/json": { "schema": { "properties": { - "message": { - "description": "The result of the operation", - "type": "string" + "id": { + "type": "number" + }, + "result": { + "$ref": "#/components/schemas/RLSRestApi.post" } }, "type": "object" } } }, - "description": "Deleted the stored form_data." + "description": "RLS Rule added" }, "400": { "$ref": "#/components/responses/400" @@ -16601,18 +20576,25 @@ "jwt": [] } ], - "tags": ["Explore Form Data"] - }, + "tags": [ + "Row Level Security" + ] + } + }, + "/api/v1/rowlevelsecurity/_info": { "get": { - "description": "Retrives a form_data.", + "description": "Get metadata information about this API resource", "parameters": [ { - "in": "path", - "name": "key", - "required": true, - "schema": { - "type": "string" - } + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/get_info_schema" + } + } + }, + "in": "query", + "name": "q" } ], "responses": { @@ -16621,16 +20603,46 @@ "application/json": { "schema": { "properties": { - "form_data": { - "description": "The stored form_data", - "type": "string" + "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": "Returns the stored form_data." + "description": "Item from Model" }, "400": { "$ref": "#/components/responses/400" @@ -16638,9 +20650,6 @@ "401": { "$ref": "#/components/responses/401" }, - "404": { - "$ref": "#/components/responses/404" - }, "422": { "$ref": "#/components/responses/422" }, @@ -16653,111 +20662,44 @@ "jwt": [] } ], - "tags": ["Explore Form Data"] - }, - "put": { - "description": "Updates an existing form_data.", + "tags": [ + "Row Level Security" + ] + } + }, + "/api/v1/rowlevelsecurity/related/{column_name}": { + "get": { "parameters": [ { "in": "path", - "name": "key", + "name": "column_name", "required": true, "schema": { "type": "string" } }, { - "in": "query", - "name": "tab_id", - "schema": { - "type": "integer" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/FormDataPutSchema" - } - } - }, - "required": true - }, - "responses": { - "200": { "content": { "application/json": { "schema": { - "properties": { - "key": { - "description": "The key to retrieve the form_data.", - "type": "string" - } - }, - "type": "object" + "$ref": "#/components/schemas/get_related_schema" } } }, - "description": "The form_data was stored successfully." - }, - "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": [] + "in": "query", + "name": "q" } ], - "tags": ["Explore Form Data"] - } - }, - "/api/v1/explore/permalink": { - "post": { - "description": "Stores a new permanent link.", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ExplorePermalinkPostSchema" - } - } - }, - "required": true - }, "responses": { - "201": { + "200": { "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" + "$ref": "#/components/schemas/RelatedResponseSchema" } } }, - "description": "The permanent link was stored successfully." + "description": "Related column data" }, "400": { "$ref": "#/components/responses/400" @@ -16765,8 +20707,8 @@ "401": { "$ref": "#/components/responses/401" }, - "422": { - "$ref": "#/components/responses/422" + "404": { + "$ref": "#/components/responses/404" }, "500": { "$ref": "#/components/responses/500" @@ -16777,19 +20719,20 @@ "jwt": [] } ], - "tags": ["Explore Permanent Link"] + "tags": [ + "Row Level Security" + ] } }, - "/api/v1/explore/permalink/{key}": { - "get": { - "description": "Retrives chart state associated with a permanent link.", + "/api/v1/rowlevelsecurity/{pk}": { + "delete": { "parameters": [ { "in": "path", - "name": "key", + "name": "pk", "required": true, "schema": { - "type": "string" + "type": "integer" } } ], @@ -16799,22 +20742,15 @@ "application/json": { "schema": { "properties": { - "state": { - "description": "The stored state", - "type": "object" + "message": { + "type": "string" } }, "type": "object" } } }, - "description": "Returns the stored form_data." - }, - "400": { - "$ref": "#/components/responses/400" - }, - "401": { - "$ref": "#/components/responses/401" + "description": "Item deleted" }, "404": { "$ref": "#/components/responses/404" @@ -16831,18 +20767,26 @@ "jwt": [] } ], - "tags": ["Explore Permanent Link"] - } - }, - "/api/v1/log/": { + "tags": [ + "Row Level Security" + ] + }, "get": { - "description": "Get a list of models", + "description": "Get an item model", "parameters": [ + { + "in": "path", + "name": "pk", + "required": true, + "schema": { + "type": "integer" + } + }, { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/get_list_schema" + "$ref": "#/components/schemas/get_item_schema" } } }, @@ -16856,10 +20800,6 @@ "application/json": { "schema": { "properties": { - "count": { - "description": "The total record count on the backend", - "type": "number" - }, "description_columns": { "properties": { "column_name": { @@ -16870,12 +20810,9 @@ }, "type": "object" }, - "ids": { - "description": "A list of item ids, useful when you don't know the column id", - "items": { - "type": "string" - }, - "type": "array" + "id": { + "description": "The item id", + "type": "string" }, "label_columns": { "properties": { @@ -16887,38 +20824,27 @@ }, "type": "object" }, - "list_columns": { + "result": { + "$ref": "#/components/schemas/RLSRestApi.get" + }, + "show_columns": { "description": "A list of columns", "items": { "type": "string" }, "type": "array" }, - "list_title": { + "show_title": { "description": "A title to render. Will be translated by babel", - "example": "List Items", + "example": "Show Item Details", "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/LogRestApi.get_list" - }, - "type": "array" } }, "type": "object" } } }, - "description": "Items from Model" + "description": "Item from Model" }, "400": { "$ref": "#/components/responses/400" @@ -16926,6 +20852,9 @@ "401": { "$ref": "#/components/responses/401" }, + "404": { + "$ref": "#/components/responses/404" + }, "422": { "$ref": "#/components/responses/422" }, @@ -16938,38 +20867,52 @@ "jwt": [] } ], - "tags": ["LogRestApi"] + "tags": [ + "Row Level Security" + ] }, - "post": { + "put": { + "description": "Updates an RLS Rule", + "parameters": [ + { + "description": "The Rule pk", + "in": "path", + "name": "pk", + "required": true, + "schema": { + "type": "integer" + } + } + ], "requestBody": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/LogRestApi.post" + "$ref": "#/components/schemas/RLSRestApi.put" } } }, - "description": "Model schema", + "description": "RLS schema", "required": true }, "responses": { - "201": { + "200": { "content": { "application/json": { "schema": { "properties": { "id": { - "type": "string" + "type": "number" }, "result": { - "$ref": "#/components/schemas/LogRestApi.post" + "$ref": "#/components/schemas/RLSRestApi.put" } }, "type": "object" } } }, - "description": "Item inserted" + "description": "Rule changed" }, "400": { "$ref": "#/components/responses/400" @@ -16977,6 +20920,12 @@ "401": { "$ref": "#/components/responses/401" }, + "403": { + "$ref": "#/components/responses/403" + }, + "404": { + "$ref": "#/components/responses/404" + }, "422": { "$ref": "#/components/responses/422" }, @@ -16989,26 +20938,20 @@ "jwt": [] } ], - "tags": ["LogRestApi"] + "tags": [ + "Row Level Security" + ] } }, - "/api/v1/log/recent_activity/{user_id}/": { - "get": { + "/api/v1/saved_query/": { + "delete": { + "description": "Deletes multiple saved queries in a bulk operation.", "parameters": [ - { - "description": "The id of the user", - "in": "path", - "name": "user_id", - "required": true, - "schema": { - "type": "integer" - } - }, { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/get_recent_activity_schema" + "$ref": "#/components/schemas/get_delete_ids_schema" } } }, @@ -17021,20 +20964,25 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/RecentActivityResponseSchema" + "properties": { + "message": { + "type": "string" + } + }, + "type": "object" } } }, - "description": "A List of recent activity objects" - }, - "400": { - "$ref": "#/components/responses/400" + "description": "Saved queries bulk delete" }, "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" @@ -17045,27 +20993,18 @@ "jwt": [] } ], - "summary": "Get recent activity data for a user", - "tags": ["LogRestApi"] - } - }, - "/api/v1/log/{pk}": { + "tags": [ + "Queries" + ] + }, "get": { - "description": "Get an item model", + "description": "Get a list of saved queries, use Rison or JSON query parameters for filtering, sorting, pagination and for selecting specific columns and metadata.", "parameters": [ - { - "in": "path", - "name": "pk", - "required": true, - "schema": { - "type": "integer" - } - }, { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/get_item_schema" + "$ref": "#/components/schemas/get_list_schema" } } }, @@ -17079,6 +21018,10 @@ "application/json": { "schema": { "properties": { + "count": { + "description": "The total record count on the backend", + "type": "number" + }, "description_columns": { "properties": { "column_name": { @@ -17089,9 +21032,12 @@ }, "type": "object" }, - "id": { - "description": "The item id", - "type": "string" + "ids": { + "description": "A list of item ids, useful when you don't know the column id", + "items": { + "type": "string" + }, + "type": "array" }, "label_columns": { "properties": { @@ -17103,27 +21049,38 @@ }, "type": "object" }, - "result": { - "$ref": "#/components/schemas/LogRestApi.get" - }, - "show_columns": { + "list_columns": { "description": "A list of columns", "items": { "type": "string" }, "type": "array" }, - "show_title": { + "list_title": { "description": "A title to render. Will be translated by babel", - "example": "Show Item Details", + "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/SavedQueryRestApi.get_list" + }, + "type": "array" } }, "type": "object" } } }, - "description": "Item from Model" + "description": "Items from Model" }, "400": { "$ref": "#/components/responses/400" @@ -17131,9 +21088,6 @@ "401": { "$ref": "#/components/responses/401" }, - "404": { - "$ref": "#/components/responses/404" - }, "422": { "$ref": "#/components/responses/422" }, @@ -17146,110 +21100,53 @@ "jwt": [] } ], - "tags": ["LogRestApi"] - } - }, - "/api/v1/me/": { - "get": { - "description": "Returns the user object corresponding to the agent making the request, or returns a 401 error if the user is unauthenticated.", - "responses": { - "200": { - "content": { - "application/json": { - "schema": { - "properties": { - "result": { - "$ref": "#/components/schemas/UserResponseSchema" - } - }, - "type": "object" - } + "tags": [ + "Queries" + ] + }, + "post": { + "description": "Create a saved query", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SavedQueryRestApi.post" } - }, - "description": "The current user" + } }, - "401": { - "$ref": "#/components/responses/401" - } + "description": "Model schema", + "required": true }, - "tags": ["Current User"] - } - }, - "/api/v1/me/roles/": { - "get": { - "description": "Returns the user roles corresponding to the agent making the request, or returns a 401 error if the user is unauthenticated.", "responses": { - "200": { + "201": { "content": { "application/json": { "schema": { "properties": { + "id": { + "type": "string" + }, "result": { - "$ref": "#/components/schemas/UserResponseSchema" + "$ref": "#/components/schemas/SavedQueryRestApi.post" } }, "type": "object" } } }, - "description": "The current user" + "description": "Item inserted" }, - "401": { - "$ref": "#/components/responses/401" - } - }, - "tags": ["Current User"] - } - }, - "/api/v1/menu/": { - "get": { - "description": "Get the menu data structure. Returns a forest like structure with the menu the user has access to", - "responses": { - "200": { - "content": { - "application/json": { - "schema": { - "properties": { - "result": { - "description": "Menu items in a forest like data structure", - "items": { - "properties": { - "childs": { - "items": { - "type": "object" - }, - "type": "array" - }, - "icon": { - "description": "Icon name to show for this menu item", - "type": "string" - }, - "label": { - "description": "Pretty name for the menu item", - "type": "string" - }, - "name": { - "description": "The internal menu item name, maps to permission_name", - "type": "string" - }, - "url": { - "description": "The URL for the menu item", - "type": "string" - } - }, - "type": "object" - }, - "type": "array" - } - }, - "type": "object" - } - } - }, - "description": "Get menu data" + "400": { + "$ref": "#/components/responses/400" }, "401": { "$ref": "#/components/responses/401" + }, + "422": { + "$ref": "#/components/responses/422" + }, + "500": { + "$ref": "#/components/responses/500" } }, "security": [ @@ -17257,18 +21154,20 @@ "jwt": [] } ], - "tags": ["Menu"] + "tags": [ + "Queries" + ] } }, - "/api/v1/query/": { + "/api/v1/saved_query/_info": { "get": { - "description": "Get a list of queries, use Rison or JSON query parameters for filtering, sorting, pagination and for selecting specific columns and metadata.", + "description": "Get metadata information about this API resource", "parameters": [ { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/get_list_schema" + "$ref": "#/components/schemas/get_info_schema" } } }, @@ -17282,69 +21181,46 @@ "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" - } - }, + "add_columns": { "type": "object" }, - "ids": { - "description": "A list of item ids, useful when you don't know the column id", - "items": { - "type": "string" - }, - "type": "array" + "edit_columns": { + "type": "object" }, - "label_columns": { + "filters": { "properties": { "column_name": { - "description": "The label for the column name. Will be translated by babel", - "example": "A Nice label for the column", - "type": "string" + "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" }, - "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", + "permissions": { + "description": "The user permissions for this API resource", "items": { "type": "string" }, "type": "array" - }, - "result": { - "description": "The result from the get list query", - "items": { - "$ref": "#/components/schemas/QueryRestApi.get_list" - }, - "type": "array" } }, "type": "object" } } }, - "description": "Items from Model" + "description": "Item from Model" }, "400": { "$ref": "#/components/responses/400" @@ -17364,10 +21240,12 @@ "jwt": [] } ], - "tags": ["Queries"] + "tags": [ + "Queries" + ] } }, - "/api/v1/query/distinct/{column_name}": { + "/api/v1/saved_query/distinct/{column_name}": { "get": { "parameters": [ { @@ -17419,25 +21297,20 @@ "jwt": [] } ], - "tags": ["Queries"] + "tags": [ + "Queries" + ] } }, - "/api/v1/query/related/{column_name}": { + "/api/v1/saved_query/export/": { "get": { + "description": "Exports multiple saved queries and downloads them as YAML files", "parameters": [ - { - "in": "path", - "name": "column_name", - "required": true, - "schema": { - "type": "string" - } - }, { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/get_related_schema" + "$ref": "#/components/schemas/get_export_ids_schema" } } }, @@ -17448,13 +21321,14 @@ "responses": { "200": { "content": { - "application/json": { + "application/zip": { "schema": { - "$ref": "#/components/schemas/RelatedResponseSchema" + "format": "binary", + "type": "string" } } }, - "description": "Related column data" + "description": "A zip file with saved query(ies) and database(s) as YAML" }, "400": { "$ref": "#/components/responses/400" @@ -17474,20 +21348,48 @@ "jwt": [] } ], - "tags": ["Queries"] + "tags": [ + "Queries" + ] } }, - "/api/v1/query/stop": { + "/api/v1/saved_query/import/": { "post": { "requestBody": { "content": { - "application/json": { + "multipart/form-data": { "schema": { - "$ref": "#/components/schemas/StopQuerySchema" + "properties": { + "formData": { + "description": "upload file (ZIP)", + "format": "binary", + "type": "string" + }, + "overwrite": { + "description": "overwrite existing saved queries?", + "type": "boolean" + }, + "passwords": { + "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" + }, + "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" + }, + "ssh_tunnel_private_key_passwords": { + "description": "JSON map of private_key_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 private_key should be provided in the following format: `{\"databases/MyDatabase.yaml\": \"my_private_key_password\"}`.", + "type": "string" + }, + "ssh_tunnel_private_keys": { + "description": "JSON map of private_keys 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 private_key should be provided in the following format: `{\"databases/MyDatabase.yaml\": \"my_private_key\"}`.", + "type": "string" + } + }, + "type": "object" } } }, - "description": "Stop query schema", "required": true }, "responses": { @@ -17496,7 +21398,7 @@ "application/json": { "schema": { "properties": { - "result": { + "message": { "type": "string" } }, @@ -17504,64 +21406,7 @@ } } }, - "description": "Query stopped" - }, - "400": { - "$ref": "#/components/responses/400" - }, - "401": { - "$ref": "#/components/responses/401" - }, - "404": { - "$ref": "#/components/responses/404" - }, - "500": { - "$ref": "#/components/responses/500" - } - }, - "security": [ - { - "jwt": [] - } - ], - "summary": "Manually stop a query with client_id", - "tags": ["Queries"] - } - }, - "/api/v1/query/updated_since": { - "get": { - "parameters": [ - { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/queries_get_updated_since_schema" - } - } - }, - "in": "query", - "name": "q" - } - ], - "responses": { - "200": { - "content": { - "application/json": { - "schema": { - "properties": { - "result": { - "description": "A List of queries that changed after last_updated_ms", - "items": { - "$ref": "#/components/schemas/QueryRestApi.get" - }, - "type": "array" - } - }, - "type": "object" - } - } - }, - "description": "Queries list" + "description": "Saved Query import result" }, "400": { "$ref": "#/components/responses/400" @@ -17569,8 +21414,8 @@ "401": { "$ref": "#/components/responses/401" }, - "404": { - "$ref": "#/components/responses/404" + "422": { + "$ref": "#/components/responses/422" }, "500": { "$ref": "#/components/responses/500" @@ -17581,27 +21426,27 @@ "jwt": [] } ], - "summary": "Get a list of queries that changed after last_updated_ms", - "tags": ["Queries"] + "tags": [ + "Queries" + ] } }, - "/api/v1/query/{pk}": { + "/api/v1/saved_query/related/{column_name}": { "get": { - "description": "Get query detail information.", "parameters": [ { "in": "path", - "name": "pk", + "name": "column_name", "required": true, "schema": { - "type": "integer" + "type": "string" } }, { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/get_item_schema" + "$ref": "#/components/schemas/get_related_schema" } } }, @@ -17614,52 +21459,11 @@ "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/QueryRestApi.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" + "$ref": "#/components/schemas/RelatedResponseSchema" } } }, - "description": "Item from Model" + "description": "Related column data" }, "400": { "$ref": "#/components/responses/400" @@ -17670,9 +21474,6 @@ "404": { "$ref": "#/components/responses/404" }, - "422": { - "$ref": "#/components/responses/422" - }, "500": { "$ref": "#/components/responses/500" } @@ -17682,23 +21483,22 @@ "jwt": [] } ], - "tags": ["Queries"] + "tags": [ + "Queries" + ] } - }, - "/api/v1/report/": { - "delete": { - "description": "Deletes multiple report schedules in a bulk operation.", - "parameters": [ - { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/get_delete_ids_schema" - } - } - }, - "in": "query", - "name": "q" + }, + "/api/v1/saved_query/{pk}": { + "delete": { + "description": "Delete saved query", + "parameters": [ + { + "in": "path", + "name": "pk", + "required": true, + "schema": { + "type": "integer" + } } ], "responses": { @@ -17715,13 +21515,7 @@ } } }, - "description": "Report Schedule bulk delete" - }, - "401": { - "$ref": "#/components/responses/401" - }, - "403": { - "$ref": "#/components/responses/403" + "description": "Item deleted" }, "404": { "$ref": "#/components/responses/404" @@ -17738,16 +21532,26 @@ "jwt": [] } ], - "tags": ["Report Schedules"] + "tags": [ + "Queries" + ] }, "get": { - "description": "Get a list of report schedules, use Rison or JSON query parameters for filtering, sorting, pagination and for selecting specific columns and metadata.", + "description": "Get a saved query", "parameters": [ + { + "in": "path", + "name": "pk", + "required": true, + "schema": { + "type": "integer" + } + }, { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/get_list_schema" + "$ref": "#/components/schemas/get_item_schema" } } }, @@ -17761,10 +21565,6 @@ "application/json": { "schema": { "properties": { - "count": { - "description": "The total record count on the backend", - "type": "number" - }, "description_columns": { "properties": { "column_name": { @@ -17775,12 +21575,9 @@ }, "type": "object" }, - "ids": { - "description": "A list of item ids, useful when you don't know the column id", - "items": { - "type": "string" - }, - "type": "array" + "id": { + "description": "The item id", + "type": "string" }, "label_columns": { "properties": { @@ -17792,38 +21589,27 @@ }, "type": "object" }, - "list_columns": { + "result": { + "$ref": "#/components/schemas/SavedQueryRestApi.get" + }, + "show_columns": { "description": "A list of columns", "items": { "type": "string" }, "type": "array" }, - "list_title": { + "show_title": { "description": "A title to render. Will be translated by babel", - "example": "List Items", + "example": "Show Item Details", "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/ReportScheduleRestApi.get_list" - }, - "type": "array" } }, "type": "object" } } }, - "description": "Items from Model" + "description": "Item from Model" }, "400": { "$ref": "#/components/responses/400" @@ -17831,6 +21617,9 @@ "401": { "$ref": "#/components/responses/401" }, + "404": { + "$ref": "#/components/responses/404" + }, "422": { "$ref": "#/components/responses/422" }, @@ -17843,39 +21632,48 @@ "jwt": [] } ], - "tags": ["Report Schedules"] + "tags": [ + "Queries" + ] }, - "post": { - "description": "Create a report schedule", + "put": { + "description": "Update a saved query", + "parameters": [ + { + "in": "path", + "name": "pk", + "required": true, + "schema": { + "type": "integer" + } + } + ], "requestBody": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ReportScheduleRestApi.post" + "$ref": "#/components/schemas/SavedQueryRestApi.put" } } }, - "description": "Report Schedule schema", + "description": "Model schema", "required": true }, "responses": { - "201": { + "200": { "content": { "application/json": { "schema": { "properties": { - "id": { - "type": "number" - }, "result": { - "$ref": "#/components/schemas/ReportScheduleRestApi.post" + "$ref": "#/components/schemas/SavedQueryRestApi.put" } }, "type": "object" } } }, - "description": "Report schedule added" + "description": "Item changed" }, "400": { "$ref": "#/components/responses/400" @@ -17898,71 +21696,76 @@ "jwt": [] } ], - "tags": ["Report Schedules"] + "tags": [ + "Queries" + ] } }, - "/api/v1/report/_info": { + "/api/v1/security/csrf_token/": { "get": { - "description": "Get metadata information about this API resource", - "parameters": [ - { + "description": "Fetch the CSRF token", + "responses": { + "200": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/get_info_schema" + "properties": { + "result": { + "type": "string" + } + }, + "type": "object" } } }, - "in": "query", - "name": "q" + "description": "Result contains the CSRF token" + }, + "401": { + "$ref": "#/components/responses/401" + }, + "500": { + "$ref": "#/components/responses/500" + } + }, + "security": [ + { + "jwt": [] } ], + "tags": [ + "Security" + ] + } + }, + "/api/v1/security/guest_token/": { + "post": { + "description": "Fetches a guest token", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GuestTokenCreate" + } + } + }, + "description": "Parameters for the guest token", + "required": true + }, "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" + "token": { + "type": "string" } }, "type": "object" } } }, - "description": "Item from Model" + "description": "Result contains the guest token" }, "400": { "$ref": "#/components/responses/400" @@ -17970,9 +21773,6 @@ "401": { "$ref": "#/components/responses/401" }, - "422": { - "$ref": "#/components/responses/422" - }, "500": { "$ref": "#/components/responses/500" } @@ -17982,85 +21782,95 @@ "jwt": [] } ], - "tags": ["Report Schedules"] + "tags": [ + "Security" + ] } }, - "/api/v1/report/related/{column_name}": { - "get": { - "parameters": [ - { - "in": "path", - "name": "column_name", - "required": true, - "schema": { - "type": "string" + "/api/v1/security/login": { + "post": { + "description": "Authenticate and get a JWT access and refresh token", + "requestBody": { + "content": { + "application/json": { + "schema": { + "properties": { + "password": { + "description": "The password for authentication", + "example": "complex-password", + "type": "string" + }, + "provider": { + "description": "Choose an authentication provider", + "enum": [ + "db", + "ldap" + ], + "example": "db", + "type": "string" + }, + "refresh": { + "description": "If true a refresh token is provided also", + "example": true, + "type": "boolean" + }, + "username": { + "description": "The username for authentication", + "example": "admin", + "type": "string" + } + }, + "type": "object" + } } }, - { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/get_related_schema" - } - } - }, - "in": "query", - "name": "q" - } - ], + "required": true + }, "responses": { "200": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/RelatedResponseSchema" + "properties": { + "access_token": { + "type": "string" + }, + "refresh_token": { + "type": "string" + } + }, + "type": "object" } } }, - "description": "Related column data" + "description": "Authentication Successful" }, "400": { "$ref": "#/components/responses/400" }, - "401": { - "$ref": "#/components/responses/401" - }, - "404": { - "$ref": "#/components/responses/404" + "401": { + "$ref": "#/components/responses/401" }, "500": { "$ref": "#/components/responses/500" } }, - "security": [ - { - "jwt": [] - } - ], - "tags": ["Report Schedules"] + "tags": [ + "Security" + ] } }, - "/api/v1/report/{pk}": { - "delete": { - "description": "Delete a report schedule", - "parameters": [ - { - "description": "The report schedule pk", - "in": "path", - "name": "pk", - "required": true, - "schema": { - "type": "integer" - } - } - ], + "/api/v1/security/refresh": { + "post": { + "description": "Use the refresh token to get a new JWT access token", "responses": { "200": { "content": { "application/json": { "schema": { "properties": { - "message": { + "access_token": { + "description": "A new refreshed access token", "type": "string" } }, @@ -18068,16 +21878,10 @@ } } }, - "description": "Item deleted" - }, - "403": { - "$ref": "#/components/responses/403" - }, - "404": { - "$ref": "#/components/responses/404" + "description": "Refresh Successful" }, - "422": { - "$ref": "#/components/responses/422" + "401": { + "$ref": "#/components/responses/401" }, "500": { "$ref": "#/components/responses/500" @@ -18085,85 +21889,42 @@ }, "security": [ { - "jwt": [] + "jwt_refresh": [] } ], - "tags": ["Report Schedules"] - }, - "get": { - "description": "Get a report schedule", - "parameters": [ - { - "in": "path", - "name": "pk", - "required": true, - "schema": { - "type": "integer" + "tags": [ + "Security" + ] + } + }, + "/api/v1/sqllab/estimate/": { + "post": { + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EstimateQueryCostSchema" + } } }, - { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/get_item_schema" - } - } - }, - "in": "query", - "name": "q" - } - ], + "description": "SQL query and params", + "required": true + }, "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/ReportScheduleRestApi.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" } }, "type": "object" } } }, - "description": "Item from Model" + "description": "Query estimation result" }, "400": { "$ref": "#/components/responses/400" @@ -18171,11 +21932,8 @@ "401": { "$ref": "#/components/responses/401" }, - "404": { - "$ref": "#/components/responses/404" - }, - "422": { - "$ref": "#/components/responses/422" + "403": { + "$ref": "#/components/responses/403" }, "500": { "$ref": "#/components/responses/500" @@ -18186,30 +21944,24 @@ "jwt": [] } ], - "tags": ["Report Schedules"] - }, - "put": { - "description": "Update a report schedule", - "parameters": [ - { - "description": "The Report Schedule pk", - "in": "path", - "name": "pk", - "required": true, - "schema": { - "type": "integer" - } - } - ], + "summary": "Estimates the SQL query execution cost", + "tags": [ + "SQL Lab" + ] + } + }, + "/api/v1/sqllab/execute/": { + "post": { + "description": "Starts the execution of a SQL query", "requestBody": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ReportScheduleRestApi.put" + "$ref": "#/components/schemas/ExecutePayloadSchema" } } }, - "description": "Report Schedule schema", + "description": "SQL query and params", "required": true }, "responses": { @@ -18217,19 +21969,21 @@ "content": { "application/json": { "schema": { - "properties": { - "id": { - "type": "number" - }, - "result": { - "$ref": "#/components/schemas/ReportScheduleRestApi.put" - } - }, - "type": "object" + "$ref": "#/components/schemas/QueryExecutionResponseSchema" } } }, - "description": "Report Schedule changed" + "description": "Query execution result" + }, + "202": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/QueryExecutionResponseSchema" + } + } + }, + "description": "Query execution result, query still running" }, "400": { "$ref": "#/components/responses/400" @@ -18243,9 +21997,6 @@ "404": { "$ref": "#/components/responses/404" }, - "422": { - "$ref": "#/components/responses/422" - }, "500": { "$ref": "#/components/responses/500" } @@ -18255,64 +22006,34 @@ "jwt": [] } ], - "tags": ["Report Schedules"] + "tags": [ + "SQL Lab" + ] } }, - "/api/v1/report/{pk}/log/": { + "/api/v1/sqllab/export/{client_id}/": { "get": { - "description": "Get a list of report schedule logs, use Rison or JSON query parameters for filtering, sorting, pagination and for selecting specific columns and metadata.", "parameters": [ { - "description": "The report schedule id for these logs", + "description": "The SQL query result identifier", "in": "path", - "name": "pk", + "name": "client_id", "required": true, "schema": { "type": "integer" } - }, - { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/get_list_schema" - } - } - }, - "in": "query", - "name": "q" } ], "responses": { "200": { "content": { - "application/json": { + "text/csv": { "schema": { - "properties": { - "count": { - "description": "The total record count on the backend", - "type": "number" - }, - "ids": { - "description": "A list of log ids", - "items": { - "type": "string" - }, - "type": "array" - }, - "result": { - "description": "The result from the get list query", - "items": { - "$ref": "#/components/schemas/ReportExecutionLogRestApi.get_list" - }, - "type": "array" - } - }, - "type": "object" + "type": "string" } } }, - "description": "Items from logs" + "description": "SQL query results" }, "400": { "$ref": "#/components/responses/400" @@ -18320,8 +22041,11 @@ "401": { "$ref": "#/components/responses/401" }, - "422": { - "$ref": "#/components/responses/422" + "403": { + "$ref": "#/components/responses/403" + }, + "404": { + "$ref": "#/components/responses/404" }, "500": { "$ref": "#/components/responses/500" @@ -18332,36 +22056,20 @@ "jwt": [] } ], - "tags": ["Report Schedules"] + "summary": "Exports the SQL query results to a CSV", + "tags": [ + "SQL Lab" + ] } }, - "/api/v1/report/{pk}/log/{log_id}": { + "/api/v1/sqllab/results/": { "get": { - "description": "Get a report schedule log", "parameters": [ - { - "description": "The report schedule pk for log", - "in": "path", - "name": "pk", - "required": true, - "schema": { - "type": "integer" - } - }, - { - "description": "The log pk", - "in": "path", - "name": "log_id", - "required": true, - "schema": { - "type": "integer" - } - }, { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/get_item_schema" + "$ref": "#/components/schemas/sql_lab_get_results_schema" } } }, @@ -18371,23 +22079,14 @@ ], "responses": { "200": { - "content": { - "application/json": { - "schema": { - "properties": { - "id": { - "description": "The log id", - "type": "string" - }, - "result": { - "$ref": "#/components/schemas/ReportExecutionLogRestApi.get" - } - }, - "type": "object" + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/QueryExecutionResponseSchema" } } }, - "description": "Item log" + "description": "SQL query execution result" }, "400": { "$ref": "#/components/responses/400" @@ -18395,11 +22094,14 @@ "401": { "$ref": "#/components/responses/401" }, + "403": { + "$ref": "#/components/responses/403" + }, "404": { "$ref": "#/components/responses/404" }, - "422": { - "$ref": "#/components/responses/422" + "410": { + "$ref": "#/components/responses/410" }, "500": { "$ref": "#/components/responses/500" @@ -18410,18 +22112,21 @@ "jwt": [] } ], - "tags": ["Report Schedules"] + "summary": "Gets the result of a SQL query execution", + "tags": [ + "SQL Lab" + ] } }, - "/api/v1/saved_query/": { + "/api/v1/tag/": { "delete": { - "description": "Deletes multiple saved queries in a bulk operation.", + "description": "Deletes multiple Tags. This will remove all tagged objects with this tag", "parameters": [ { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/get_delete_ids_schema" + "$ref": "#/components/schemas/delete_tags_schema" } } }, @@ -18443,11 +22148,14 @@ } } }, - "description": "Saved queries bulk delete" + "description": "Deletes multiple Tags" }, "401": { "$ref": "#/components/responses/401" }, + "403": { + "$ref": "#/components/responses/403" + }, "404": { "$ref": "#/components/responses/404" }, @@ -18463,10 +22171,12 @@ "jwt": [] } ], - "tags": ["Queries"] + "tags": [ + "Tags" + ] }, "get": { - "description": "Get a list of saved queries, use Rison or JSON query parameters for filtering, sorting, pagination and for selecting specific columns and metadata.", + "description": "Get a list of tags, use Rison or JSON query parameters for filtering, sorting, pagination and for selecting specific columns and metadata.", "parameters": [ { "content": { @@ -18539,7 +22249,7 @@ "result": { "description": "The result from the get list query", "items": { - "$ref": "#/components/schemas/SavedQueryRestApi.get_list" + "$ref": "#/components/schemas/TagRestApi.get_list" }, "type": "array" } @@ -18568,15 +22278,16 @@ "jwt": [] } ], - "tags": ["Queries"] + "tags": [ + "Tags" + ] }, "post": { - "description": "Create a saved query", "requestBody": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SavedQueryRestApi.post" + "$ref": "#/components/schemas/TagRestApi.post" } } }, @@ -18593,7 +22304,7 @@ "type": "string" }, "result": { - "$ref": "#/components/schemas/SavedQueryRestApi.post" + "$ref": "#/components/schemas/TagRestApi.post" } }, "type": "object" @@ -18613,258 +22324,80 @@ }, "500": { "$ref": "#/components/responses/500" - } - }, - "security": [ - { - "jwt": [] - } - ], - "tags": ["Queries"] - } - }, - "/api/v1/saved_query/_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": ["Queries"] - } - }, - "/api/v1/saved_query/distinct/{column_name}": { - "get": { - "parameters": [ - { - "in": "path", - "name": "column_name", - "required": true, - "schema": { - "type": "string" - } - }, - { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/get_related_schema" - } - } - }, - "in": "query", - "name": "q" - } - ], - "responses": { - "200": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DistincResponseSchema" - } - } - }, - "description": "Distinct field data" - }, - "400": { - "$ref": "#/components/responses/400" - }, - "401": { - "$ref": "#/components/responses/401" - }, - "404": { - "$ref": "#/components/responses/404" - }, - "500": { - "$ref": "#/components/responses/500" - } - }, - "security": [ - { - "jwt": [] - } - ], - "tags": ["Queries"] - } - }, - "/api/v1/saved_query/export/": { - "get": { - "description": "Exports multiple saved queries and downloads them as YAML files", - "parameters": [ - { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/get_export_ids_schema" - } - } - }, - "in": "query", - "name": "q" - } - ], - "responses": { - "200": { - "content": { - "application/zip": { - "schema": { - "format": "binary", - "type": "string" - } - } - }, - "description": "A zip file with saved query(ies) and database(s) as YAML" - }, - "400": { - "$ref": "#/components/responses/400" - }, - "401": { - "$ref": "#/components/responses/401" - }, - "404": { - "$ref": "#/components/responses/404" - }, - "500": { - "$ref": "#/components/responses/500" - } - }, - "security": [ - { - "jwt": [] - } - ], - "tags": ["Queries"] - } - }, - "/api/v1/saved_query/import/": { - "post": { - "requestBody": { - "content": { - "multipart/form-data": { - "schema": { - "properties": { - "formData": { - "description": "upload file (ZIP)", - "format": "binary", - "type": "string" - }, - "overwrite": { - "description": "overwrite existing saved queries?", - "type": "boolean" - }, - "passwords": { - "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" - }, - "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" - }, - "ssh_tunnel_private_keys": { - "description": "JSON map of private_keys 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 private_key should be provided in the following format: `{\"databases/MyDatabase.yaml\": \"my_private_key\"}`.", - "type": "string" - }, - "ssh_tunnel_private_keyspasswords": { - "description": "JSON map of private_key_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 private_key_password should be provided in the following format: `{\"databases/MyDatabase.yaml\": \"my_private_key_password\"}`.", - "type": "string" - } - }, - "type": "object" - } - } - }, - "required": true + } }, + "security": [ + { + "jwt": [] + } + ], + "tags": [ + "Tags" + ] + } + }, + "/api/v1/tag/_info": { + "get": { + "description": "Several metadata information about tag API endpoints.", + "parameters": [ + { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/get_info_schema" + } + } + }, + "in": "query", + "name": "q" + } + ], "responses": { "200": { "content": { "application/json": { "schema": { "properties": { - "message": { - "type": "string" + "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": "Saved Query import result" + "description": "Item from Model" }, "400": { "$ref": "#/components/responses/400" @@ -18884,25 +22417,20 @@ "jwt": [] } ], - "tags": ["Queries"] + "tags": [ + "Tags" + ] } }, - "/api/v1/saved_query/related/{column_name}": { + "/api/v1/tag/favorite_status/": { "get": { + "description": "Check favorited dashboards for current user", "parameters": [ - { - "in": "path", - "name": "column_name", - "required": true, - "schema": { - "type": "string" - } - }, { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/get_related_schema" + "$ref": "#/components/schemas/get_fav_star_ids_schema" } } }, @@ -18915,11 +22443,11 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/RelatedResponseSchema" + "$ref": "#/components/schemas/GetFavStarIdsSchema" } } }, - "description": "Related column data" + "description": "None" }, "400": { "$ref": "#/components/responses/400" @@ -18939,16 +22467,18 @@ "jwt": [] } ], - "tags": ["Queries"] + "tags": [ + "Tags" + ] } }, - "/api/v1/saved_query/{pk}": { - "delete": { - "description": "Delete saved query", + "/api/v1/tag/get_objects/": { + "get": { + "description": "Gets all objects associated with a Tag.", "parameters": [ { "in": "path", - "name": "pk", + "name": "tag_id", "required": true, "schema": { "type": "integer" @@ -18961,22 +22491,31 @@ "application/json": { "schema": { "properties": { - "message": { - "type": "string" + "result": { + "items": { + "$ref": "#/components/schemas/TaggedObjectEntityResponseSchema" + }, + "type": "array" } }, "type": "object" } } }, - "description": "Item deleted" + "description": "List of tagged objects associated with a Tag" + }, + "302": { + "description": "Redirects to the current digest" + }, + "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" } @@ -18986,24 +22525,27 @@ "jwt": [] } ], - "tags": ["Queries"] - }, + "tags": [ + "Tags" + ] + } + }, + "/api/v1/tag/related/{column_name}": { "get": { - "description": "Get a saved query", "parameters": [ { "in": "path", - "name": "pk", + "name": "column_name", "required": true, "schema": { - "type": "integer" + "type": "string" } }, { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/get_item_schema" + "$ref": "#/components/schemas/get_related_schema" } } }, @@ -19016,52 +22558,11 @@ "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/SavedQueryRestApi.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" + "$ref": "#/components/schemas/RelatedResponseSchema" } } }, - "description": "Item from Model" + "description": "Related column data" }, "400": { "$ref": "#/components/responses/400" @@ -19072,9 +22573,6 @@ "404": { "$ref": "#/components/responses/404" }, - "422": { - "$ref": "#/components/responses/422" - }, "500": { "$ref": "#/components/responses/500" } @@ -19084,14 +22582,26 @@ "jwt": [] } ], - "tags": ["Queries"] - }, - "put": { - "description": "Update a saved query", + "tags": [ + "Tags" + ] + } + }, + "/api/v1/tag/{object_type}/{object_id}/": { + "post": { + "description": "Add tags to an object..", "parameters": [ { "in": "path", - "name": "pk", + "name": "object_type", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "in": "path", + "name": "object_id", "required": true, "schema": { "type": "integer" @@ -19102,28 +22612,28 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SavedQueryRestApi.put" + "properties": { + "tags": { + "description": "list of tag names to add to object", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" } } }, - "description": "Model schema", + "description": "Tag schema", "required": true }, "responses": { - "200": { - "content": { - "application/json": { - "schema": { - "properties": { - "result": { - "$ref": "#/components/schemas/SavedQueryRestApi.put" - } - }, - "type": "object" - } - } - }, - "description": "Item changed" + "201": { + "description": "Tag added" + }, + "302": { + "description": "Redirects to the current digest" }, "400": { "$ref": "#/components/responses/400" @@ -19134,9 +22644,6 @@ "404": { "$ref": "#/components/responses/404" }, - "422": { - "$ref": "#/components/responses/422" - }, "500": { "$ref": "#/components/responses/500" } @@ -19146,19 +22653,47 @@ "jwt": [] } ], - "tags": ["Queries"] + "tags": [ + "Tags" + ] } }, - "/api/v1/security/csrf_token/": { - "get": { - "description": "Fetch the CSRF token", + "/api/v1/tag/{object_type}/{object_id}/{tag}/": { + "delete": { + "description": "Deletes a Tagged Object.", + "parameters": [ + { + "in": "path", + "name": "tag", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "object_type", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "in": "path", + "name": "object_id", + "required": true, + "schema": { + "type": "integer" + } + } + ], "responses": { "200": { "content": { "application/json": { "schema": { "properties": { - "result": { + "message": { "type": "string" } }, @@ -19166,11 +22701,20 @@ } } }, - "description": "Result contains the CSRF token" + "description": "Chart delete" }, "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" } @@ -19180,30 +22724,30 @@ "jwt": [] } ], - "tags": ["Security"] + "tags": [ + "Tags" + ] } }, - "/api/v1/security/guest_token/": { - "post": { - "description": "Fetches a guest token", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/GuestTokenCreate" - } + "/api/v1/tag/{pk}": { + "delete": { + "parameters": [ + { + "in": "path", + "name": "pk", + "required": true, + "schema": { + "type": "integer" } - }, - "description": "Parameters for the guest token", - "required": true - }, + } + ], "responses": { "200": { "content": { "application/json": { "schema": { "properties": { - "token": { + "message": { "type": "string" } }, @@ -19211,13 +22755,13 @@ } } }, - "description": "Result contains the guest token" + "description": "Item deleted" }, - "400": { - "$ref": "#/components/responses/400" + "404": { + "$ref": "#/components/responses/404" }, - "401": { - "$ref": "#/components/responses/401" + "422": { + "$ref": "#/components/responses/422" }, "500": { "$ref": "#/components/responses/500" @@ -19228,88 +22772,76 @@ "jwt": [] } ], - "tags": ["Security"] - } - }, - "/api/v1/security/login": { - "post": { - "description": "Authenticate and get a JWT access and refresh token", - "requestBody": { - "content": { - "application/json": { - "schema": { - "properties": { - "password": { - "description": "The password for authentication", - "example": "complex-password", - "type": "string" - }, - "provider": { - "description": "Choose an authentication provider", - "enum": ["db", "ldap"], - "example": "db", - "type": "string" - }, - "refresh": { - "description": "If true a refresh token is provided also", - "example": true, - "type": "boolean" - }, - "username": { - "description": "The username for authentication", - "example": "admin", - "type": "string" - } - }, - "type": "object" - } + "tags": [ + "Tags" + ] + }, + "get": { + "description": "Get a tag detail information.", + "parameters": [ + { + "in": "path", + "name": "pk", + "required": true, + "schema": { + "type": "integer" } }, - "required": true - }, - "responses": { - "200": { + { "content": { "application/json": { "schema": { - "properties": { - "access_token": { - "type": "string" - }, - "refresh_token": { - "type": "string" - } - }, - "type": "object" + "$ref": "#/components/schemas/get_item_schema" } } }, - "description": "Authentication Successful" - }, - "400": { - "$ref": "#/components/responses/400" - }, - "401": { - "$ref": "#/components/responses/401" - }, - "500": { - "$ref": "#/components/responses/500" + "in": "query", + "name": "q" } - }, - "tags": ["Security"] - } - }, - "/api/v1/security/refresh": { - "post": { - "description": "Use the refresh token to get a new JWT access token", + ], "responses": { "200": { "content": { "application/json": { "schema": { "properties": { - "access_token": { - "description": "A new refreshed access token", + "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/TagRestApi.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" } }, @@ -19317,35 +22849,53 @@ } } }, - "description": "Refresh Successful" + "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_refresh": [] + "jwt": [] + } + ], + "tags": [ + "Tags" + ] + }, + "put": { + "parameters": [ + { + "in": "path", + "name": "pk", + "required": true, + "schema": { + "type": "integer" + } } ], - "tags": ["Security"] - } - }, - "/api/v1/sqllab/execute/": { - "post": { - "description": "Starts the execution of a SQL query", "requestBody": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ExecutePayloadSchema" + "$ref": "#/components/schemas/TagRestApi.put" } } }, - "description": "SQL query and params", + "description": "Model schema", "required": true }, "responses": { @@ -19353,21 +22903,16 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/QueryExecutionResponseSchema" - } - } - }, - "description": "Query execution result" - }, - "202": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/QueryExecutionResponseSchema" + "properties": { + "result": { + "$ref": "#/components/schemas/TagRestApi.put" + } + }, + "type": "object" } } }, - "description": "Query execution result, query still running" + "description": "Item changed" }, "400": { "$ref": "#/components/responses/400" @@ -19375,12 +22920,12 @@ "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" } @@ -19390,16 +22935,18 @@ "jwt": [] } ], - "tags": ["SQL Lab"] + "tags": [ + "Tags" + ] } }, - "/api/v1/sqllab/export/{client_id}/": { - "get": { + "/api/v1/tag/{pk}/favorites/": { + "delete": { + "description": "Remove the tag from the user favorite list", "parameters": [ { - "description": "The SQL query result identifier", "in": "path", - "name": "client_id", + "name": "pk", "required": true, "schema": { "type": "integer" @@ -19409,26 +22956,28 @@ "responses": { "200": { "content": { - "text/csv": { + "application/json": { "schema": { - "type": "string" + "properties": { + "result": { + "type": "object" + } + }, + "type": "object" } } }, - "description": "SQL query results" - }, - "400": { - "$ref": "#/components/responses/400" + "description": "Tag removed from favorites" }, "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" } @@ -19438,23 +22987,20 @@ "jwt": [] } ], - "summary": "Exports the SQL query results to a CSV", - "tags": ["SQL Lab"] - } - }, - "/api/v1/sqllab/results/": { - "get": { + "tags": [ + "Tags" + ] + }, + "post": { + "description": "Marks the tag as favorite for the current user", "parameters": [ { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/sql_lab_get_results_schema" - } - } - }, - "in": "query", - "name": "q" + "in": "path", + "name": "pk", + "required": true, + "schema": { + "type": "integer" + } } ], "responses": { @@ -19462,26 +23008,25 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/QueryExecutionResponseSchema" + "properties": { + "result": { + "type": "object" + } + }, + "type": "object" } } }, - "description": "SQL query execution result" - }, - "400": { - "$ref": "#/components/responses/400" + "description": "Tag added to favorites" }, "401": { "$ref": "#/components/responses/401" }, - "403": { - "$ref": "#/components/responses/403" - }, "404": { "$ref": "#/components/responses/404" }, - "410": { - "$ref": "#/components/responses/410" + "422": { + "$ref": "#/components/responses/422" }, "500": { "$ref": "#/components/responses/500" @@ -19492,8 +23037,9 @@ "jwt": [] } ], - "summary": "Gets the result of a SQL query execution", - "tags": ["SQL Lab"] + "tags": [ + "Tags" + ] } }, "/api/{version}/_openapi": { @@ -19532,7 +23078,9 @@ "jwt": [] } ], - "tags": ["OpenApi"] + "tags": [ + "OpenApi" + ] } } }, diff --git a/requirements/base.txt b/requirements/base.txt index 820faca0e491a..68cd81ba24f19 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -59,6 +59,8 @@ colorama==0.4.6 # via # apache-superset # flask-appbuilder +convertdate==2.4.0 + # via holidays cron-descriptor==1.2.24 # via apache-superset croniter==1.0.15 @@ -128,7 +130,9 @@ gunicorn==20.1.0 # via apache-superset hashids==1.3.1 # via apache-superset -holidays==0.28 +hijri-converter==2.3.1 + # via holidays +holidays==0.23 # via apache-superset humanize==3.11.0 # via apache-superset @@ -154,6 +158,8 @@ jsonschema==4.17.3 # via flask-appbuilder kombu==5.2.4 # via celery +korean-lunar-calendar==0.3.1 + # via holidays limits==3.4.0 # via flask-limiter llvmlite==0.40.1 @@ -230,6 +236,8 @@ pyjwt==2.4.0 # apache-superset # flask-appbuilder # flask-jwt-extended +pymeeus==0.5.12 + # via convertdate pynacl==1.5.0 # via paramiko pyparsing==3.0.6 diff --git a/requirements/testing.txt b/requirements/testing.txt index c8a3221b455de..85dfddb91642e 100644 --- a/requirements/testing.txt +++ b/requirements/testing.txt @@ -18,8 +18,6 @@ cmdstanpy==1.1.0 # via prophet contourpy==1.0.7 # via matplotlib -convertdate==2.4.0 - # via prophet coverage[toml]==7.2.5 # via pytest-cov cycler==0.11.0 @@ -106,7 +104,7 @@ parameterized==0.9.0 # via -r requirements/testing.in pathable==0.4.3 # via jsonschema-spec -prophet==1.1.3 +prophet==1.1.1 # via apache-superset proto-plus==1.22.2 # via @@ -126,8 +124,6 @@ pyfakefs==5.2.2 # via -r requirements/testing.in pyhive[presto]==0.6.5 # via apache-superset -pymeeus==0.5.12 - # via convertdate pytest==7.3.1 # via # -r requirements/testing.in @@ -145,6 +141,8 @@ rfc3339-validator==0.1.4 # via openapi-schema-validator rsa==4.9 # via google-auth +setuptools-git==1.2 + # via prophet shillelagh[gsheetsapi]==1.2.6 # via apache-superset sqlalchemy-bigquery==1.6.1 diff --git a/setup.py b/setup.py index 24b1b890d5565..d6eb1d68a6fc5 100644 --- a/setup.py +++ b/setup.py @@ -92,7 +92,7 @@ def get_git_sha() -> str: "geopy", "gunicorn>=20.1.0; sys_platform != 'win32'", "hashids>=1.3.1, <2", - "holidays>=0.28, <1.0", + "holidays>=0.23, <0.24", "humanize", "importlib_metadata", "isodate", @@ -177,7 +177,7 @@ def get_git_sha() -> str: "postgres": ["psycopg2-binary==2.9.6"], "presto": ["pyhive[presto]>=0.6.5"], "trino": ["trino>=0.324.0"], - "prophet": ["prophet>=1.1.0, <2.0.0"], + "prophet": ["prophet==1.1.1"], "redshift": ["sqlalchemy-redshift>=0.8.1, < 0.9"], "rockset": ["rockset-sqlalchemy>=0.0.1, <1.0.0"], "shillelagh": [ diff --git a/superset-frontend/plugins/legacy-plugin-chart-heatmap/src/Heatmap.js b/superset-frontend/plugins/legacy-plugin-chart-heatmap/src/Heatmap.js index 7d62622313b92..a6967301c6a6b 100644 --- a/superset-frontend/plugins/legacy-plugin-chart-heatmap/src/Heatmap.js +++ b/superset-frontend/plugins/legacy-plugin-chart-heatmap/src/Heatmap.js @@ -99,9 +99,16 @@ function Heatmap(element, props) { xScaleInterval, yScaleInterval, yAxisBounds, + xAxisFormatter, + yAxisFormatter, } = props; - const { records, extents } = data; + const { extents } = data; + const records = data.records.map(record => ({ + ...record, + x: xAxisFormatter(record.x), + y: yAxisFormatter(record.y), + })); const margin = { top: 10, diff --git a/superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.tsx b/superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.tsx index 70a71e5024da5..1b115a17e994a 100644 --- a/superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.tsx +++ b/superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.tsx @@ -31,6 +31,7 @@ import { sections, sharedControls, getStandardizedControls, + D3_TIME_FORMAT_DOCS, } from '@superset-ui/chart-controls'; const sortAxisChoices = [ @@ -257,6 +258,16 @@ const config: ControlPanelConfig = { }, ], ['y_axis_format'], + [ + { + name: 'time_format', + config: { + ...sharedControls.x_axis_time_format, + default: '%d/%m/%Y', + description: `${D3_TIME_FORMAT_DOCS}.`, + }, + }, + ], ['currency_format'], [ { diff --git a/superset-frontend/plugins/legacy-plugin-chart-heatmap/src/transformProps.js b/superset-frontend/plugins/legacy-plugin-chart-heatmap/src/transformProps.js index c4906ddbe96e9..fa531ef9da1d3 100644 --- a/superset-frontend/plugins/legacy-plugin-chart-heatmap/src/transformProps.js +++ b/superset-frontend/plugins/legacy-plugin-chart-heatmap/src/transformProps.js @@ -1,5 +1,3 @@ -import { getValueFormatter } from '@superset-ui/core'; - /** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -18,6 +16,12 @@ import { getValueFormatter } from '@superset-ui/core'; * specific language governing permissions and limitations * under the License. */ +import { + GenericDataType, + getTimeFormatter, + getValueFormatter, +} from '@superset-ui/core'; + export default function transformProps(chartProps) { const { width, height, formData, queriesData, datasource } = chartProps; const { @@ -38,8 +42,10 @@ export default function transformProps(chartProps) { yscaleInterval, yAxisBounds, yAxisFormat, + timeFormat, currencyFormat, } = formData; + const { data = [], coltypes = [] } = queriesData[0]; const { columnFormats = {}, currencyFormats = {} } = datasource; const valueFormatter = getValueFormatter( metric, @@ -48,10 +54,18 @@ export default function transformProps(chartProps) { yAxisFormat, currencyFormat, ); + const xAxisFormatter = + coltypes[0] === GenericDataType.TEMPORAL + ? getTimeFormatter(timeFormat) + : String; + const yAxisFormatter = + coltypes[1] === GenericDataType.TEMPORAL + ? getTimeFormatter(timeFormat) + : String; return { width, height, - data: queriesData[0].data, + data, bottomMargin, canvasImageRendering, colorScheme: linearColorScheme, @@ -69,5 +83,7 @@ export default function transformProps(chartProps) { yScaleInterval: parseInt(yscaleInterval, 10), yAxisBounds, valueFormatter, + xAxisFormatter, + yAxisFormatter, }; } diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/transformProps.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/transformProps.ts index 0f29282c5fb4d..f76c457e1c34d 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/transformProps.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/transformProps.ts @@ -20,7 +20,6 @@ import { invert } from 'lodash'; import { AnnotationLayer, - AxisType, CategoricalColorNamespace, ensureIsArray, GenericDataType, @@ -447,23 +446,13 @@ export default function transformProps( rotate: xAxisLabelRotation, }, minInterval: - xAxisType === AxisType.time && timeGrainSqla + xAxisType === 'time' && timeGrainSqla ? TIMEGRAIN_TO_TIMESTAMP[timeGrainSqla] : 0, }; - - if (xAxisType === AxisType.time) { - /** - * Overriding default behavior (false) for time axis regardless of the granilarity. - * Not including this in the initial declaration above so if echarts changes the default - * behavior for other axist types we won't unintentionally override it - */ - xAxis.axisLabel.showMaxLabel = null; - } - let yAxis: any = { ...defaultYAxis, - type: logAxis ? AxisType.log : AxisType.value, + type: logAxis ? 'log' : 'value', min, max, minorTick: { show: true }, diff --git a/superset-frontend/src/components/Chart/chartAction.js b/superset-frontend/src/components/Chart/chartAction.js index c204d58ebe32b..7b4b70377b205 100644 --- a/superset-frontend/src/components/Chart/chartAction.js +++ b/superset-frontend/src/components/Chart/chartAction.js @@ -35,8 +35,6 @@ import { getQuerySettings, getChartDataUri, } from 'src/explore/exploreUtils'; -import { requiresQuery } from 'src/modules/AnnotationTypes'; - import { addDangerToast } from 'src/components/MessageToasts/actions'; import { logEvent } from 'src/logger/actions'; import { Logger, LOG_ACTIONS_LOAD_CHART } from 'src/logger/LogUtils'; @@ -268,7 +266,7 @@ export function runAnnotationQuery({ ...(formData || getState().charts[sliceKey].latestQueryFormData), }; - if (!requiresQuery(annotation.sourceType)) { + if (!annotation.sourceType) { return Promise.resolve(); } diff --git a/superset-frontend/src/components/Datasource/DatasourceEditor.jsx b/superset-frontend/src/components/Datasource/DatasourceEditor.jsx index 8801e2e8600f3..3d0cc7da57a71 100644 --- a/superset-frontend/src/components/Datasource/DatasourceEditor.jsx +++ b/superset-frontend/src/components/Datasource/DatasourceEditor.jsx @@ -765,6 +765,7 @@ class DatasourceEditor extends React.PureComponent { table_name: datasource.table_name ? encodeURIComponent(datasource.table_name) : datasource.table_name, + normalize_columns: datasource.normalize_columns, }; Object.entries(params).forEach(([key, value]) => { // rison can't encode the undefined value @@ -993,6 +994,15 @@ class DatasourceEditor extends React.PureComponent { control={} /> )} + } + /> ); } diff --git a/superset-frontend/src/components/Datasource/DatasourceModal.tsx b/superset-frontend/src/components/Datasource/DatasourceModal.tsx index 78859f4a2fe47..f9c40c47ba02e 100644 --- a/superset-frontend/src/components/Datasource/DatasourceModal.tsx +++ b/superset-frontend/src/components/Datasource/DatasourceModal.tsx @@ -128,6 +128,7 @@ const DatasourceModal: FunctionComponent = ({ schema, description: currentDatasource.description, main_dttm_col: currentDatasource.main_dttm_col, + normalize_columns: currentDatasource.normalize_columns, offset: currentDatasource.offset, default_endpoint: currentDatasource.default_endpoint, cache_timeout: diff --git a/superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx b/superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx index d04b20cb0d8b3..563b94682385e 100644 --- a/superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx +++ b/superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx @@ -32,10 +32,13 @@ import { getColumnLabel, withTheme, } from '@superset-ui/core'; - import SelectControl from 'src/explore/components/controls/SelectControl'; import TextControl from 'src/explore/components/controls/TextControl'; import CheckboxControl from 'src/explore/components/controls/CheckboxControl'; +import PopoverSection from 'src/components/PopoverSection'; +import ControlHeader from 'src/explore/components/ControlHeader'; +import { EmptyStateSmall } from 'src/components/EmptyState'; +import { FILTER_OPTIONS_LIMIT } from 'src/explore/constants'; import { ANNOTATION_SOURCE_TYPES, ANNOTATION_TYPES, @@ -43,11 +46,7 @@ import { DEFAULT_ANNOTATION_TYPE, requiresQuery, ANNOTATION_SOURCE_TYPES_METADATA, -} from 'src/modules/AnnotationTypes'; -import PopoverSection from 'src/components/PopoverSection'; -import ControlHeader from 'src/explore/components/ControlHeader'; -import { EmptyStateSmall } from 'src/components/EmptyState'; -import { FILTER_OPTIONS_LIMIT } from 'src/explore/constants'; +} from './AnnotationTypes'; const AUTOMATIC_COLOR = ''; diff --git a/superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.test.tsx b/superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.test.tsx index c1969769e636d..914be7361919a 100644 --- a/superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.test.tsx +++ b/superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.test.tsx @@ -22,7 +22,7 @@ import userEvent from '@testing-library/user-event'; import { getChartMetadataRegistry, ChartMetadata } from '@superset-ui/core'; import fetchMock from 'fetch-mock'; import setupColors from 'src/setup/setupColors'; -import { ANNOTATION_TYPES_METADATA } from 'src/modules/AnnotationTypes'; +import { ANNOTATION_TYPES_METADATA } from './AnnotationTypes'; import AnnotationLayer from './AnnotationLayer'; const defaultProps = { diff --git a/superset-frontend/src/modules/AnnotationTypes.js b/superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationTypes.js similarity index 100% rename from superset-frontend/src/modules/AnnotationTypes.js rename to superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationTypes.js diff --git a/superset-frontend/src/features/datasets/types.ts b/superset-frontend/src/features/datasets/types.ts index 4c2c5b8a95516..9163306267b89 100644 --- a/superset-frontend/src/features/datasets/types.ts +++ b/superset-frontend/src/features/datasets/types.ts @@ -63,4 +63,5 @@ export type DatasetObject = { metrics: MetricObject[]; extra?: string; is_managed_externally: boolean; + normalize_columns: boolean; }; diff --git a/superset-frontend/src/features/home/RightMenu.tsx b/superset-frontend/src/features/home/RightMenu.tsx index d0b8e44ab756b..831ae85ba39f3 100644 --- a/superset-frontend/src/features/home/RightMenu.tsx +++ b/superset-frontend/src/features/home/RightMenu.tsx @@ -474,7 +474,7 @@ const RightMenu = ({ {navbarRight.user_profile_url && ( - {t('Profile')} + {t('Profile')} )} {navbarRight.user_info_url && ( diff --git a/superset-frontend/src/profile/components/CreatedContent.test.tsx b/superset-frontend/src/features/profile/CreatedContent.test.tsx similarity index 95% rename from superset-frontend/src/profile/components/CreatedContent.test.tsx rename to superset-frontend/src/features/profile/CreatedContent.test.tsx index 817448cf35ea7..df49e98aff90d 100644 --- a/superset-frontend/src/profile/components/CreatedContent.test.tsx +++ b/superset-frontend/src/features/profile/CreatedContent.test.tsx @@ -20,8 +20,8 @@ import React from 'react'; import { shallow } from 'enzyme'; import thunk from 'redux-thunk'; import configureStore from 'redux-mock-store'; -import CreatedContent from 'src/profile/components/CreatedContent'; import TableLoader from 'src/components/TableLoader'; +import CreatedContent from './CreatedContent'; import { user } from './fixtures'; diff --git a/superset-frontend/src/profile/components/CreatedContent.tsx b/superset-frontend/src/features/profile/CreatedContent.tsx similarity index 100% rename from superset-frontend/src/profile/components/CreatedContent.tsx rename to superset-frontend/src/features/profile/CreatedContent.tsx diff --git a/superset-frontend/src/profile/components/Favorites.test.tsx b/superset-frontend/src/features/profile/Favorites.test.tsx similarity index 96% rename from superset-frontend/src/profile/components/Favorites.test.tsx rename to superset-frontend/src/features/profile/Favorites.test.tsx index 8b5eaf4e86c45..e21967f3bf170 100644 --- a/superset-frontend/src/profile/components/Favorites.test.tsx +++ b/superset-frontend/src/features/profile/Favorites.test.tsx @@ -20,8 +20,8 @@ import React from 'react'; import { shallow } from 'enzyme'; import thunk from 'redux-thunk'; import configureStore from 'redux-mock-store'; -import Favorites from 'src/profile/components/Favorites'; import TableLoader from 'src/components/TableLoader'; +import Favorites from './Favorites'; import { user } from './fixtures'; diff --git a/superset-frontend/src/profile/components/Favorites.tsx b/superset-frontend/src/features/profile/Favorites.tsx similarity index 98% rename from superset-frontend/src/profile/components/Favorites.tsx rename to superset-frontend/src/features/profile/Favorites.tsx index 834f933071676..f38f174779689 100644 --- a/superset-frontend/src/profile/components/Favorites.tsx +++ b/superset-frontend/src/features/profile/Favorites.tsx @@ -22,7 +22,7 @@ import moment from 'moment'; import { t } from '@superset-ui/core'; import { DashboardResponse, BootstrapUser } from 'src/types/bootstrapTypes'; import TableLoader from '../../components/TableLoader'; -import { Chart } from '../types'; +import { Chart } from './types'; interface FavoritesProps { user: BootstrapUser; diff --git a/superset-frontend/src/profile/components/RecentActivity.test.tsx b/superset-frontend/src/features/profile/RecentActivity.test.tsx similarity index 95% rename from superset-frontend/src/profile/components/RecentActivity.test.tsx rename to superset-frontend/src/features/profile/RecentActivity.test.tsx index 73fdeb6e841c8..a64c209296743 100644 --- a/superset-frontend/src/profile/components/RecentActivity.test.tsx +++ b/superset-frontend/src/features/profile/RecentActivity.test.tsx @@ -18,8 +18,8 @@ */ import React from 'react'; import { shallow } from 'enzyme'; -import RecentActivity from 'src/profile/components/RecentActivity'; import TableLoader from 'src/components/TableLoader'; +import RecentActivity from './RecentActivity'; import { user } from './fixtures'; diff --git a/superset-frontend/src/profile/components/RecentActivity.tsx b/superset-frontend/src/features/profile/RecentActivity.tsx similarity index 91% rename from superset-frontend/src/profile/components/RecentActivity.tsx rename to superset-frontend/src/features/profile/RecentActivity.tsx index 2810fb3544963..d550d2a9531c4 100644 --- a/superset-frontend/src/profile/components/RecentActivity.tsx +++ b/superset-frontend/src/features/profile/RecentActivity.tsx @@ -20,10 +20,9 @@ import React from 'react'; import moment from 'moment'; import { t } from '@superset-ui/core'; import rison from 'rison'; - -import TableLoader from '../../components/TableLoader'; -import { ActivityResult } from '../types'; -import { BootstrapUser } from '../../types/bootstrapTypes'; +import TableLoader from 'src/components/TableLoader'; +import { BootstrapUser } from 'src/types/bootstrapTypes'; +import { ActivityResult } from './types'; interface RecentActivityProps { user: BootstrapUser; diff --git a/superset-frontend/src/profile/components/Security.test.tsx b/superset-frontend/src/features/profile/Security.test.tsx similarity index 97% rename from superset-frontend/src/profile/components/Security.test.tsx rename to superset-frontend/src/features/profile/Security.test.tsx index 31eda0aae7652..af4706375c848 100644 --- a/superset-frontend/src/profile/components/Security.test.tsx +++ b/superset-frontend/src/features/profile/Security.test.tsx @@ -18,9 +18,9 @@ */ import React from 'react'; import { styledMount as mount } from 'spec/helpers/theming'; -import Security from 'src/profile/components/Security'; import Label from 'src/components/Label'; import { user, userNoPerms } from './fixtures'; +import Security from './Security'; describe('Security', () => { const mockedProps = { diff --git a/superset-frontend/src/profile/components/Security.tsx b/superset-frontend/src/features/profile/Security.tsx similarity index 100% rename from superset-frontend/src/profile/components/Security.tsx rename to superset-frontend/src/features/profile/Security.tsx diff --git a/superset-frontend/src/profile/components/UserInfo.test.tsx b/superset-frontend/src/features/profile/UserInfo.test.tsx similarity index 97% rename from superset-frontend/src/profile/components/UserInfo.test.tsx rename to superset-frontend/src/features/profile/UserInfo.test.tsx index 9d8a904cb568b..6bbc2b52d1e8e 100644 --- a/superset-frontend/src/profile/components/UserInfo.test.tsx +++ b/superset-frontend/src/features/profile/UserInfo.test.tsx @@ -19,7 +19,7 @@ import React from 'react'; import Gravatar from 'react-gravatar'; import { mount } from 'enzyme'; -import UserInfo from 'src/profile/components/UserInfo'; +import UserInfo from './UserInfo'; import { user } from './fixtures'; diff --git a/superset-frontend/src/profile/components/UserInfo.tsx b/superset-frontend/src/features/profile/UserInfo.tsx similarity index 100% rename from superset-frontend/src/profile/components/UserInfo.tsx rename to superset-frontend/src/features/profile/UserInfo.tsx diff --git a/superset-frontend/src/profile/components/fixtures.tsx b/superset-frontend/src/features/profile/fixtures.tsx similarity index 100% rename from superset-frontend/src/profile/components/fixtures.tsx rename to superset-frontend/src/features/profile/fixtures.tsx diff --git a/superset-frontend/src/profile/types.ts b/superset-frontend/src/features/profile/types.ts similarity index 100% rename from superset-frontend/src/profile/types.ts rename to superset-frontend/src/features/profile/types.ts diff --git a/superset-frontend/src/profile/components/App.test.tsx b/superset-frontend/src/pages/Profile/Profile.test.tsx similarity index 79% rename from superset-frontend/src/profile/components/App.test.tsx rename to superset-frontend/src/pages/Profile/Profile.test.tsx index 4f7a4caa1e1f8..cf1446c29ac62 100644 --- a/superset-frontend/src/profile/components/App.test.tsx +++ b/superset-frontend/src/pages/Profile/Profile.test.tsx @@ -19,26 +19,25 @@ import React from 'react'; import { Row, Col } from 'src/components'; import { shallow } from 'enzyme'; -import App from 'src/profile/components/App'; +import Profile from 'src/pages/Profile'; +import { user } from 'src/features/profile/fixtures'; -import { user } from './fixtures'; - -describe('App', () => { +describe('Profile', () => { const mockedProps = { user, }; it('is valid', () => { - expect(React.isValidElement()).toBe(true); + expect(React.isValidElement()).toBe(true); }); it('renders 2 Col', () => { - const wrapper = shallow(); + const wrapper = shallow(); expect(wrapper.find(Row)).toExist(); expect(wrapper.find(Col)).toHaveLength(2); }); it('renders 4 Tabs', () => { - const wrapper = shallow(); + const wrapper = shallow(); expect(wrapper.find('[tab]')).toHaveLength(4); }); }); diff --git a/superset-frontend/src/profile/components/App.tsx b/superset-frontend/src/pages/Profile/index.tsx similarity index 90% rename from superset-frontend/src/profile/components/App.tsx rename to superset-frontend/src/pages/Profile/index.tsx index 08130176fe61a..511017941a85b 100644 --- a/superset-frontend/src/profile/components/App.tsx +++ b/superset-frontend/src/pages/Profile/index.tsx @@ -21,11 +21,11 @@ import { t, styled } from '@superset-ui/core'; import { Row, Col } from 'src/components'; import Tabs from 'src/components/Tabs'; import { BootstrapUser } from 'src/types/bootstrapTypes'; -import Favorites from './Favorites'; -import UserInfo from './UserInfo'; -import Security from './Security'; -import RecentActivity from './RecentActivity'; -import CreatedContent from './CreatedContent'; +import Favorites from 'src/features/profile/Favorites'; +import UserInfo from 'src/features/profile/UserInfo'; +import Security from 'src/features/profile/Security'; +import RecentActivity from 'src/features/profile/RecentActivity'; +import CreatedContent from 'src/features/profile/CreatedContent'; interface AppProps { user: BootstrapUser; diff --git a/superset-frontend/src/profile/App.tsx b/superset-frontend/src/profile/App.tsx deleted file mode 100644 index ed331ce73725c..0000000000000 --- a/superset-frontend/src/profile/App.tsx +++ /dev/null @@ -1,58 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -import React from 'react'; -import { hot } from 'react-hot-loader/root'; -import thunk from 'redux-thunk'; -import { createStore, applyMiddleware, compose, combineReducers } from 'redux'; -import { Provider } from 'react-redux'; -import { ThemeProvider } from '@superset-ui/core'; -import { GlobalStyles } from 'src/GlobalStyles'; -import App from 'src/profile/components/App'; -import messageToastReducer from 'src/components/MessageToasts/reducers'; -import { initEnhancer } from 'src/reduxUtils'; -import setupApp from 'src/setup/setupApp'; -import setupExtensions from 'src/setup/setupExtensions'; -import { theme } from 'src/preamble'; -import ToastContainer from 'src/components/MessageToasts/ToastContainer'; -import getBootstrapData from 'src/utils/getBootstrapData'; - -setupApp(); -setupExtensions(); - -const bootstrapData = getBootstrapData(); - -const store = createStore( - combineReducers({ - messageToasts: messageToastReducer, - }), - {}, - compose(applyMiddleware(thunk), initEnhancer(false)), -); - -const Application = () => ( - - - - - - - -); - -export default hot(Application); diff --git a/superset-frontend/src/profile/index.tsx b/superset-frontend/src/profile/index.tsx deleted file mode 100644 index c257009e64fd5..0000000000000 --- a/superset-frontend/src/profile/index.tsx +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -import React from 'react'; -import ReactDOM from 'react-dom'; -import App from './App'; - -ReactDOM.render(, document.getElementById('app')); diff --git a/superset-frontend/src/showSavedQuery/index.jsx b/superset-frontend/src/showSavedQuery/index.jsx deleted file mode 100644 index 10c09703f7206..0000000000000 --- a/superset-frontend/src/showSavedQuery/index.jsx +++ /dev/null @@ -1,73 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -import React from 'react'; -import ReactDom from 'react-dom'; -import Form from 'react-jsonschema-form'; -import { interpolate } from 'src/showSavedQuery/utils'; -import { styled } from '@superset-ui/core'; -import getBootstrapData from 'src/utils/getBootstrapData'; - -const scheduleInfoContainer = document.getElementById('schedule-info'); -const bootstrapData = getBootstrapData(); -const config = bootstrapData.common.conf.SCHEDULED_QUERIES; -const { query } = bootstrapData.common; -const scheduleInfo = query.extra_json.schedule_info; -const linkback = config.linkback ? interpolate(config.linkback, query) : null; - -const StyledSavedQueryContainer = styled.div` - .btn-add { - display: none; - } -`; - -const StyledLinkBack = styled.div` - ${({ theme }) => ` - padding-top: 0; - padding-right: ${theme.gridUnit * 2 + 2}px; - padding-bottom: ${theme.gridUnit * 5}px; - padding-left: ${theme.gridUnit / 2}px; -`} -`; - -if (scheduleInfo && config) { - // hide instructions when showing schedule info - config.JSONSCHEMA.description = ''; - - ReactDom.render( - -
-
-
- {linkback && ( - - - -   Pipeline status - - - )} -
, - scheduleInfoContainer, - ); -} diff --git a/superset-frontend/src/showSavedQuery/utils.js b/superset-frontend/src/showSavedQuery/utils.js deleted file mode 100644 index 9cd712bc893f3..0000000000000 --- a/superset-frontend/src/showSavedQuery/utils.js +++ /dev/null @@ -1,44 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -export function getNestedValue(obj, id, separator = '.') { - /* - * Given a nested object and an id, return the nested value. - * - * > getNestedValue({a:{b:1}}, 'a.b') - * < 1 - */ - const index = id.indexOf(separator); - if (index === -1) { - return obj[id]; - } - const name = id.slice(0, index); - const rest = id.slice(index + separator.length); - return getNestedValue(obj[name], rest, separator); -} - -export function interpolate(str, obj) { - /* - * Programmatic template string for interpolation. - * - * > interpolate('foo ${a.b}', {a:{b:1}}) - * < "foo 1" - */ - return str.replace(/\$\{(.+?)\}/g, (match, id) => getNestedValue(obj, id)); -} diff --git a/superset-frontend/src/showSavedQuery/utils.test.jsx b/superset-frontend/src/showSavedQuery/utils.test.jsx deleted file mode 100644 index 8d999824812a8..0000000000000 --- a/superset-frontend/src/showSavedQuery/utils.test.jsx +++ /dev/null @@ -1,64 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -import { getNestedValue, interpolate } from 'src/showSavedQuery/utils'; - -describe('getNestedValue', () => { - it('is a function', () => { - expect(typeof getNestedValue).toBe('function'); - }); - - it('works with simple ids', () => { - const obj = { a: '1' }; - const id = 'a'; - expect(getNestedValue(obj, id)).toEqual('1'); - }); - - it('works with complex ids', () => { - const obj = { a: { b: '1' } }; - const id = 'a.b'; - expect(getNestedValue(obj, id)).toEqual('1'); - }); - - it('works with other separators', () => { - const obj = { a: { b: { c: '1' } } }; - const id = 'a__b__c'; - const separator = '__'; - expect(getNestedValue(obj, id, separator)).toEqual('1'); - }); -}); - -describe('interpolate', () => { - it('is a function', () => { - expect(typeof interpolate).toBe('function'); - }); - - it('works with simple ids', () => { - const obj = { a: '1' }; - // eslint-disable-next-line no-template-curly-in-string - const str = 'value: ${a}'; - expect(interpolate(str, obj)).toEqual('value: 1'); - }); - - it('works with complex ids', () => { - const obj = { a: { b: '1' } }; - // eslint-disable-next-line no-template-curly-in-string - const str = 'value: ${a.b}'; - expect(interpolate(str, obj)).toEqual('value: 1'); - }); -}); diff --git a/superset-frontend/src/views/routes.tsx b/superset-frontend/src/views/routes.tsx index 23a25a5d855b8..197284d3acb6a 100644 --- a/superset-frontend/src/views/routes.tsx +++ b/superset-frontend/src/views/routes.tsx @@ -119,6 +119,10 @@ const RowLevelSecurityList = lazy( ), ); +const Profile = lazy( + () => import(/* webpackChunkName: "Profile" */ 'src/pages/Profile'), +); + type Routes = { path: string; Component: React.ComponentType; @@ -217,6 +221,10 @@ export const routes: Routes = [ path: '/rowlevelsecurity/list', Component: RowLevelSecurityList, }, + { + path: '/profile', + Component: Profile, + }, ]; if (isFeatureEnabled(FeatureFlag.TAGGING_SYSTEM)) { diff --git a/superset-frontend/webpack.config.js b/superset-frontend/webpack.config.js index fb137c06cbe60..7bad2ea875393 100644 --- a/superset-frontend/webpack.config.js +++ b/superset-frontend/webpack.config.js @@ -212,8 +212,6 @@ const config = { spa: addPreamble('/src/views/index.tsx'), embedded: addPreamble('/src/embedded/index.tsx'), sqllab: addPreamble('/src/SqlLab/index.tsx'), - profile: addPreamble('/src/profile/index.tsx'), - showSavedQuery: [path.join(APP_DIR, '/src/showSavedQuery/index.jsx')], }, output, stats: 'minimal', diff --git a/superset-websocket/package-lock.json b/superset-websocket/package-lock.json index 3398eff505501..02b4ff52d78cf 100644 --- a/superset-websocket/package-lock.json +++ b/superset-websocket/package-lock.json @@ -30,7 +30,7 @@ "eslint": "^8.47.0", "eslint-config-prettier": "^9.0.0", "jest": "^27.3.1", - "prettier": "^3.0.1", + "prettier": "^3.0.2", "ts-jest": "^27.0.7", "ts-node": "^10.9.1", "typescript": "^4.9.5" @@ -4856,9 +4856,9 @@ } }, "node_modules/prettier": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.1.tgz", - "integrity": "sha512-fcOWSnnpCrovBsmFZIGIy9UqK2FaI7Hqax+DIO0A9UxeVoY4iweyaFjS5TavZN97Hfehph0nhsZnjlVKzEQSrQ==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.2.tgz", + "integrity": "sha512-o2YR9qtniXvwEZlOKbveKfDQVyqxbEIWn48Z8m3ZJjBjcCmUy3xZGIv+7AkaeuaTr6yPXJjwv07ZWlsWbEy1rQ==", "dev": true, "bin": { "prettier": "bin/prettier.cjs" @@ -9699,9 +9699,9 @@ "dev": true }, "prettier": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.1.tgz", - "integrity": "sha512-fcOWSnnpCrovBsmFZIGIy9UqK2FaI7Hqax+DIO0A9UxeVoY4iweyaFjS5TavZN97Hfehph0nhsZnjlVKzEQSrQ==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.2.tgz", + "integrity": "sha512-o2YR9qtniXvwEZlOKbveKfDQVyqxbEIWn48Z8m3ZJjBjcCmUy3xZGIv+7AkaeuaTr6yPXJjwv07ZWlsWbEy1rQ==", "dev": true }, "pretty-format": { diff --git a/superset-websocket/package.json b/superset-websocket/package.json index 301f4673b2f37..523bb758becc6 100644 --- a/superset-websocket/package.json +++ b/superset-websocket/package.json @@ -37,7 +37,7 @@ "eslint": "^8.47.0", "eslint-config-prettier": "^9.0.0", "jest": "^27.3.1", - "prettier": "^3.0.1", + "prettier": "^3.0.2", "ts-jest": "^27.0.7", "ts-node": "^10.9.1", "typescript": "^4.9.5" diff --git a/superset/config.py b/superset/config.py index 0b70328e0b4c0..21f275e42da23 100644 --- a/superset/config.py +++ b/superset/config.py @@ -1452,7 +1452,7 @@ def EMAIL_HEADER_MUTATOR( # pylint: disable=invalid-name,unused-argument # URI to database storing the example data, points to # SQLALCHEMY_DATABASE_URI by default if set to `None` -SQLALCHEMY_EXAMPLES_URI = None +SQLALCHEMY_EXAMPLES_URI = "sqlite:///" + os.path.join(DATA_DIR, "examples.db") # Optional prefix to be added to all static asset paths when rendering the UI. # This is useful for hosting assets in an external CDN, for example diff --git a/superset/connectors/sqla/models.py b/superset/connectors/sqla/models.py index e7a3f50ae1879..adeddaa009130 100644 --- a/superset/connectors/sqla/models.py +++ b/superset/connectors/sqla/models.py @@ -546,6 +546,7 @@ class SqlaTable( is_sqllab_view = Column(Boolean, default=False) template_params = Column(Text) extra = Column(Text) + normalize_columns = Column(Boolean, default=False) baselink = "tablemodelview" @@ -564,6 +565,7 @@ class SqlaTable( "filter_select_enabled", "fetch_values_predicate", "extra", + "normalize_columns", ] update_from_object_fields = [f for f in export_fields if f != "database_id"] export_parent = "database" @@ -717,6 +719,7 @@ def external_metadata(self) -> list[ResultSetColumnType]: database=self.database, table_name=self.table_name, schema_name=self.schema, + normalize_columns=self.normalize_columns, ) @property diff --git a/superset/connectors/sqla/utils.py b/superset/connectors/sqla/utils.py index 4bff059b37a0d..66594084c82d5 100644 --- a/superset/connectors/sqla/utils.py +++ b/superset/connectors/sqla/utils.py @@ -48,6 +48,7 @@ def get_physical_table_metadata( database: Database, table_name: str, + normalize_columns: bool, schema_name: str | None = None, ) -> list[ResultSetColumnType]: """Use SQLAlchemy inspector to get table metadata""" @@ -67,7 +68,10 @@ def get_physical_table_metadata( for col in cols: try: if isinstance(col["type"], TypeEngine): - name = db_engine_spec.denormalize_name(db_dialect, col["column_name"]) + name = col["column_name"] + if not normalize_columns: + name = db_engine_spec.denormalize_name(db_dialect, name) + db_type = db_engine_spec.column_datatype_to_string( col["type"], db_dialect ) diff --git a/superset/connectors/sqla/views.py b/superset/connectors/sqla/views.py index 373db21dad08c..bce647dcda2d4 100644 --- a/superset/connectors/sqla/views.py +++ b/superset/connectors/sqla/views.py @@ -313,6 +313,7 @@ class TableModelView( # pylint: disable=too-many-ancestors "is_sqllab_view", "template_params", "extra", + "normalize_columns", ] base_filters = [["id", DatasourceFilter, lambda: []]] show_columns = edit_columns + ["perm", "slices"] @@ -379,6 +380,10 @@ class TableModelView( # pylint: disable=too-many-ancestors '}, "warning_markdown": "This is a warning." }`.', True, ), + "normalize_columns": _( + "Allow column names to be changed to case insensitive format, " + "if supported (e.g. Oracle, Snowflake)." + ), } label_columns = { "slices": _("Associated Charts"), diff --git a/superset/daos/chart.py b/superset/daos/chart.py index 8bed30014c955..f6a18915cbe1d 100644 --- a/superset/daos/chart.py +++ b/superset/daos/chart.py @@ -20,14 +20,12 @@ from datetime import datetime from typing import cast, TYPE_CHECKING -from sqlalchemy.exc import SQLAlchemyError - from superset.charts.filters import ChartFilter from superset.daos.base import BaseDAO from superset.extensions import db from superset.models.core import FavStar, FavStarClassName from superset.models.slice import Slice -from superset.utils.core import as_list, get_user_id +from superset.utils.core import get_user_id if TYPE_CHECKING: from superset.connectors.base.models import BaseDatasource @@ -38,22 +36,6 @@ class ChartDAO(BaseDAO[Slice]): base_filter = ChartFilter - @classmethod - def delete(cls, item_or_items: Slice | list[Slice], commit: bool = True) -> None: - items = cast(list[Slice], as_list(item_or_items)) - item_ids = [item.id for item in items] - # bulk delete, first delete related data - # bulk delete itself - try: - db.session.query(Slice).filter(Slice.id.in_(item_ids)).delete( - synchronize_session="fetch" - ) - if commit: - db.session.commit() - except SQLAlchemyError as ex: - db.session.rollback() - raise ex - @staticmethod def favorited_ids(charts: list[Slice]) -> list[FavStar]: ids = [chart.id for chart in charts] diff --git a/superset/daos/dashboard.py b/superset/daos/dashboard.py index 067d44e8fc934..3cdda13aa7fdc 100644 --- a/superset/daos/dashboard.py +++ b/superset/daos/dashboard.py @@ -23,7 +23,6 @@ from flask import g from flask_appbuilder.models.sqla.interface import SQLAInterface -from sqlalchemy.exc import SQLAlchemyError from superset import is_feature_enabled, security_manager from superset.daos.base import BaseDAO @@ -48,7 +47,7 @@ from superset.models.embedded_dashboard import EmbeddedDashboard from superset.models.filter_set import FilterSet from superset.models.slice import Slice -from superset.utils.core import as_list, get_user_id +from superset.utils.core import get_user_id from superset.utils.dashboard_filter_scopes_converter import copy_filter_scopes logger = logging.getLogger(__name__) @@ -190,22 +189,6 @@ def update_charts_owners(model: Dashboard, commit: bool = True) -> Dashboard: db.session.commit() return model - @classmethod - def delete( - cls, item_or_items: Dashboard | list[Dashboard], commit: bool = True - ) -> None: - items = cast(list[Dashboard], as_list(item_or_items)) - item_ids = [item.id for item in items] - try: - db.session.query(Dashboard).filter(Dashboard.id.in_(item_ids)).delete( - synchronize_session="fetch" - ) - if commit: - db.session.commit() - except SQLAlchemyError as ex: - db.session.rollback() - raise ex - @staticmethod def set_dash_metadata( # pylint: disable=too-many-locals dashboard: Dashboard, diff --git a/superset/daos/dataset.py b/superset/daos/dataset.py index 561ae5d548661..af5ebd3746178 100644 --- a/superset/daos/dataset.py +++ b/superset/daos/dataset.py @@ -21,20 +21,19 @@ from sqlalchemy.exc import SQLAlchemyError -from superset import security_manager from superset.connectors.sqla.models import SqlaTable, SqlMetric, TableColumn from superset.daos.base import BaseDAO from superset.extensions import db from superset.models.core import Database from superset.models.dashboard import Dashboard from superset.models.slice import Slice -from superset.utils.core import as_list, DatasourceType +from superset.utils.core import DatasourceType from superset.views.base import DatasourceFilter logger = logging.getLogger(__name__) -class DatasetDAO(BaseDAO[SqlaTable]): # pylint: disable=too-many-public-methods +class DatasetDAO(BaseDAO[SqlaTable]): base_filter = DatasourceFilter @staticmethod @@ -309,42 +308,6 @@ def find_dataset_metric(cls, dataset_id: int, metric_id: int) -> SqlMetric | Non return None return db.session.query(SqlMetric).get(metric_id) - @classmethod - def delete( - cls, - item_or_items: SqlaTable | list[SqlaTable], - commit: bool = True, - ) -> None: - """ - Delete the specified items(s) including their associated relationships. - - Note that bulk deletion via `delete` does not dispatch the `after_delete` event - and thus the ORM event listener callback needs to be invoked manually. - - :param items: The item(s) to delete - :param commit: Whether to commit the transaction - :raises DAODeleteFailedError: If the deletion failed - :see: https://docs.sqlalchemy.org/en/latest/orm/queryguide/dml.html - """ - items = cast(list[SqlaTable], as_list(item_or_items)) - try: - db.session.query(SqlaTable).filter( - SqlaTable.id.in_(item.id for item in items) - ).delete(synchronize_session="fetch") - - connection = db.session.connection() - mapper = next(iter(cls.model_cls.registry.mappers)) # type: ignore - - for item in items: - security_manager.dataset_after_delete(mapper, connection, item) - - if commit: - db.session.commit() - except SQLAlchemyError as ex: - if commit: - db.session.rollback() - raise ex - @staticmethod def get_table_by_name(database_id: int, table_name: str) -> SqlaTable | None: return ( diff --git a/superset/dashboards/filters.py b/superset/dashboards/filters.py index 596e97de31de4..0c7878d508626 100644 --- a/superset/dashboards/filters.py +++ b/superset/dashboards/filters.py @@ -24,7 +24,7 @@ from superset import db, is_feature_enabled, security_manager from superset.connectors.sqla.models import SqlaTable -from superset.models.core import Database, FavStar +from superset.models.core import Database from superset.models.dashboard import Dashboard, is_uuid from superset.models.embedded_dashboard import EmbeddedDashboard from superset.models.slice import Slice @@ -92,8 +92,8 @@ class DashboardAccessFilter(BaseFilter): # pylint: disable=too-few-public-metho """ List dashboards with the following criteria: 1. Those which the user owns - 2. Those which the user has favorited - 3. Those which have been published (if they have access to at least one slice) + 2. Those which have been published (if they have access to at least one slice) + 3. Those that they have access to via a role (if `DASHBOARD_RBAC` is enabled) If the user is an admin then show all dashboards. This means they do not get curation but can still sort by "published" @@ -126,12 +126,6 @@ def apply(self, query: Query, value: Any) -> Query: ) ) - users_favorite_dash_query = db.session.query(FavStar.obj_id).filter( - and_( - FavStar.user_id == get_user_id(), - FavStar.class_name == "Dashboard", - ) - ) owner_ids_query = ( db.session.query(Dashboard.id) .join(Dashboard.owners) @@ -179,7 +173,6 @@ def apply(self, query: Query, value: Any) -> Query: or_( Dashboard.id.in_(owner_ids_query), Dashboard.id.in_(datasource_perm_query), - Dashboard.id.in_(users_favorite_dash_query), *feature_flagged_filters, ) ) diff --git a/superset/dashboards/schemas.py b/superset/dashboards/schemas.py index 9054af6da8ce1..7384d4877586b 100644 --- a/superset/dashboards/schemas.py +++ b/superset/dashboards/schemas.py @@ -244,6 +244,7 @@ class DashboardDatasetSchema(Schema): verbose_map = fields.Dict(fields.Str(), fields.Str()) time_grain_sqla = fields.List(fields.List(fields.Str())) granularity_sqla = fields.List(fields.List(fields.Str())) + normalize_columns = fields.Bool() class BaseDashboardSchema(Schema): diff --git a/superset/datasets/api.py b/superset/datasets/api.py index 70bf03936a6ad..9bbb6acd218f0 100644 --- a/superset/datasets/api.py +++ b/superset/datasets/api.py @@ -142,6 +142,7 @@ class DatasetRestApi(BaseSupersetModelRestApi): "schema", "description", "main_dttm_col", + "normalize_columns", "offset", "default_endpoint", "cache_timeout", @@ -219,6 +220,7 @@ class DatasetRestApi(BaseSupersetModelRestApi): "schema", "description", "main_dttm_col", + "normalize_columns", "offset", "default_endpoint", "cache_timeout", diff --git a/superset/datasets/commands/duplicate.py b/superset/datasets/commands/duplicate.py index dc3ccb85d4b0c..9fc05c0960a5f 100644 --- a/superset/datasets/commands/duplicate.py +++ b/superset/datasets/commands/duplicate.py @@ -67,6 +67,7 @@ def run(self) -> Model: table.database = database table.schema = self._base_model.schema table.template_params = self._base_model.template_params + table.normalize_columns = self._base_model.normalize_columns table.is_sqllab_view = True table.sql = ParsedQuery(self._base_model.sql).stripped() db.session.add(table) diff --git a/superset/datasets/schemas.py b/superset/datasets/schemas.py index 4da0cdb400638..66d80e1842b9a 100644 --- a/superset/datasets/schemas.py +++ b/superset/datasets/schemas.py @@ -98,6 +98,7 @@ class DatasetPostSchema(Schema): owners = fields.List(fields.Integer()) is_managed_externally = fields.Boolean(allow_none=True, dump_default=False) external_url = fields.String(allow_none=True) + normalize_columns = fields.Boolean(load_default=False) class DatasetPutSchema(Schema): @@ -109,6 +110,7 @@ class DatasetPutSchema(Schema): schema = fields.String(allow_none=True, validate=Length(0, 255)) description = fields.String(allow_none=True) main_dttm_col = fields.String(allow_none=True) + normalize_columns = fields.Boolean(allow_none=True, dump_default=False) offset = fields.Integer(allow_none=True) default_endpoint = fields.String(allow_none=True) cache_timeout = fields.Integer(allow_none=True) @@ -247,6 +249,7 @@ def fix_extra(self, data: dict[str, Any], **kwargs: Any) -> dict[str, Any]: data = fields.URL() is_managed_externally = fields.Boolean(allow_none=True, dump_default=False) external_url = fields.String(allow_none=True) + normalize_columns = fields.Boolean(load_default=False) class GetOrCreateDatasetSchema(Schema): @@ -262,6 +265,7 @@ class GetOrCreateDatasetSchema(Schema): template_params = fields.String( metadata={"description": "Template params for the table"} ) + normalize_columns = fields.Boolean(load_default=False) class DatasetSchema(SQLAlchemyAutoSchema): diff --git a/superset/explore/permalink/api.py b/superset/explore/permalink/api.py index f03e5f7962d0a..b249d4dee2384 100644 --- a/superset/explore/permalink/api.py +++ b/superset/explore/permalink/api.py @@ -68,7 +68,7 @@ def post(self) -> Response: content: application/json: schema: - $ref: '#/components/schemas/ExplorePermalinkPostSchema' + $ref: '#/components/schemas/ExplorePermalinkStateSchema' responses: 201: description: The permanent link was stored successfully. diff --git a/superset/initialization/__init__.py b/superset/initialization/__init__.py index 828be7840162b..f5473ba25e84c 100644 --- a/superset/initialization/__init__.py +++ b/superset/initialization/__init__.py @@ -182,10 +182,10 @@ def init_views(self) -> None: from superset.views.key_value import KV from superset.views.log.api import LogRestApi from superset.views.log.views import LogModelView + from superset.views.profile import ProfileView from superset.views.redirects import R from superset.views.sql_lab.views import ( SavedQueryView, - SavedQueryViewApi, SqlLab, TableSchemaView, TabStateView, @@ -309,8 +309,8 @@ def init_views(self) -> None: appbuilder.add_view_no_menu(ExplorePermalinkView) appbuilder.add_view_no_menu(KV) appbuilder.add_view_no_menu(R) + appbuilder.add_view_no_menu(ProfileView) appbuilder.add_view_no_menu(SavedQueryView) - appbuilder.add_view_no_menu(SavedQueryViewApi) appbuilder.add_view_no_menu(SliceAsync) appbuilder.add_view_no_menu(SqlLab) appbuilder.add_view_no_menu(SqlMetricInlineView) diff --git a/superset/migrations/versions/2023-08-14_09-38_9f4a086c2676_add_normalize_columns_to_sqla_model.py b/superset/migrations/versions/2023-08-14_09-38_9f4a086c2676_add_normalize_columns_to_sqla_model.py new file mode 100644 index 0000000000000..8eaee8207ce0b --- /dev/null +++ b/superset/migrations/versions/2023-08-14_09-38_9f4a086c2676_add_normalize_columns_to_sqla_model.py @@ -0,0 +1,67 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +"""add_normalize_columns_to_sqla_model + +Revision ID: 9f4a086c2676 +Revises: 4448fa6deeb1 +Create Date: 2023-08-14 09:38:11.897437 + +""" + +# revision identifiers, used by Alembic. +revision = "9f4a086c2676" +down_revision = "4448fa6deeb1" + +import sqlalchemy as sa +from alembic import op +from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy.orm import Session + +from superset import db +from superset.migrations.shared.utils import paginated_update + +Base = declarative_base() + + +class SqlaTable(Base): + __tablename__ = "tables" + + id = sa.Column(sa.Integer, primary_key=True) + normalize_columns = sa.Column(sa.Boolean()) + + +def upgrade(): + op.add_column( + "tables", + sa.Column( + "normalize_columns", + sa.Boolean(), + nullable=True, + default=False, + server_default=sa.false(), + ), + ) + + bind = op.get_bind() + session = db.Session(bind=bind) + + for table in paginated_update(session.query(SqlaTable)): + table.normalize_columns = True + + +def downgrade(): + op.drop_column("tables", "normalize_columns") diff --git a/superset/security/manager.py b/superset/security/manager.py index b996188a8ea49..f5b4a7160a426 100644 --- a/superset/security/manager.py +++ b/superset/security/manager.py @@ -236,6 +236,7 @@ class SupersetSecurityManager( # pylint: disable=too-many-public-methods ("can_execute_sql_query", "SQLLab"), ("can_estimate_query_cost", "SQL Lab"), ("can_export_csv", "SQLLab"), + ("can_read", "SQLLab"), ("can_sqllab_history", "Superset"), ("can_sqllab", "Superset"), ("can_test_conn", "Superset"), # Deprecated permission remove on 3.0.0 diff --git a/superset/sqllab/api.py b/superset/sqllab/api.py index ebf7fab32afd9..d085174b5fc11 100644 --- a/superset/sqllab/api.py +++ b/superset/sqllab/api.py @@ -20,7 +20,7 @@ import simplejson as json from flask import request, Response -from flask_appbuilder.api import expose, protect, rison +from flask_appbuilder.api import expose, protect, rison, safe from flask_appbuilder.models.sqla.interface import SQLAInterface from marshmallow import ValidationError @@ -47,6 +47,7 @@ ExecutePayloadSchema, QueryExecutionResponseSchema, sql_lab_get_results_schema, + SQLLabBootstrapSchema, ) from superset.sqllab.sql_json_executer import ( ASynchronousSqlJsonExecutor, @@ -54,6 +55,7 @@ SynchronousSqlJsonExecutor, ) from superset.sqllab.sqllab_execution_context import SqlJsonExecutionContext +from superset.sqllab.utils import bootstrap_sqllab_data from superset.sqllab.validators import CanAccessQueryValidatorImpl from superset.superset_typing import FlaskResponse from superset.utils import core as utils @@ -83,8 +85,55 @@ class SqlLabRestApi(BaseSupersetApi): EstimateQueryCostSchema, ExecutePayloadSchema, QueryExecutionResponseSchema, + SQLLabBootstrapSchema, ) + @expose("/", methods=("GET",)) + @protect() + @safe + @statsd_metrics + @event_logger.log_this_with_context( + action=lambda self, *args, **kwargs: f"{self.__class__.__name__}.get", + log_to_statsd=False, + ) + def get(self) -> Response: + """Get the bootstrap data for SqlLab + --- + get: + summary: Get the bootstrap data for SqlLab page + 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. + responses: + 200: + description: Returns the initial bootstrap data for SqlLab + content: + application/json: + schema: + $ref: '#/components/schemas/SQLLabBootstrapSchema' + 400: + $ref: '#/components/responses/400' + 401: + $ref: '#/components/responses/401' + 403: + $ref: '#/components/responses/403' + 500: + $ref: '#/components/responses/500' + """ + user_id = utils.get_user_id() + # TODO: Replace with a command class once fully migrated to SPA + result = bootstrap_sqllab_data(user_id) + + return json_success( + json.dumps( + {"result": result}, + default=utils.json_iso_dttm_ser, + ignore_nan=True, + ), + 200, + ) + @expose("/estimate/", methods=("POST",)) @protect() @statsd_metrics diff --git a/superset/sqllab/schemas.py b/superset/sqllab/schemas.py index d388dc0353d72..46ee773222fc2 100644 --- a/superset/sqllab/schemas.py +++ b/superset/sqllab/schemas.py @@ -16,6 +16,8 @@ # under the License. from marshmallow import fields, Schema +from superset.databases.schemas import ImportV1DatabaseSchema + sql_lab_get_results_schema = { "type": "object", "properties": { @@ -95,3 +97,50 @@ class QueryExecutionResponseSchema(Schema): expanded_columns = fields.List(fields.Dict()) query = fields.Nested(QueryResultSchema) query_id = fields.Integer() + + +class TableSchema(Schema): + database_id = fields.Integer() + description = fields.String() + expanded = fields.Boolean() + id = fields.Integer() + schema = fields.String() + tab_state_id = fields.Integer() + table = fields.String() + + +class TabStateSchema(Schema): + active = fields.Boolean() + autorun = fields.Boolean() + database_id = fields.Integer() + extra_json = fields.Dict() + hide_left_bar = fields.Boolean() + id = fields.String() + label = fields.String() + latest_query = fields.Nested(QueryResultSchema) + query_limit = fields.Integer() + saved_query = fields.Dict( + allow_none=True, + metadata={"id": "SavedQuery id"}, + ) + schema = fields.String() + sql = fields.String() + table_schemas = fields.List(fields.Nested(TableSchema)) + user_id = fields.Integer() + + +class SQLLabBootstrapSchema(Schema): + active_tab = fields.Nested(TabStateSchema) + databases = fields.Dict( + keys=fields.String( + metadata={"description": "Database id"}, + ), + values=fields.Nested(ImportV1DatabaseSchema), + ) + queries = fields.Dict( + keys=fields.String( + metadata={"description": "Query id"}, + ), + values=fields.Nested(QueryResultSchema), + ) + tab_state_ids = fields.List(fields.String()) diff --git a/superset/utils/database.py b/superset/utils/database.py index 70730554f393c..b34dda1164a45 100644 --- a/superset/utils/database.py +++ b/superset/utils/database.py @@ -65,11 +65,7 @@ def get_or_create_db( def get_example_database() -> Database: - db_uri = ( - current_app.config.get("SQLALCHEMY_EXAMPLES_URI") - or current_app.config["SQLALCHEMY_DATABASE_URI"] - ) - return get_or_create_db("examples", db_uri) + return get_or_create_db("examples", current_app.config["SQLALCHEMY_EXAMPLES_URI"]) def get_main_database() -> Database: diff --git a/superset/views/base.py b/superset/views/base.py index a2c62df41bf7e..d1c865374a424 100644 --- a/superset/views/base.py +++ b/superset/views/base.py @@ -406,7 +406,7 @@ def menu_data(user: User) -> dict[str, Any]: "user_login_url": appbuilder.get_url_for_login, "user_profile_url": None if user.is_anonymous or is_feature_enabled("MENU_HIDE_USER_INFO") - else "/superset/profile/", + else "/profile/", "locale": session.get("locale", "en"), }, } diff --git a/superset/views/core.py b/superset/views/core.py index d377f94d653c3..366ec6d664e38 100755 --- a/superset/views/core.py +++ b/superset/views/core.py @@ -80,7 +80,6 @@ base_json_conv, DatasourceType, get_user_id, - get_username, ReservedUrlParameters, ) from superset.views.base import ( @@ -985,24 +984,9 @@ def welcome(self) -> FlaskResponse: @has_access @event_logger.log_this @expose("/profile/") + @deprecated(new_target="/profile") def profile(self) -> FlaskResponse: - """User profile page""" - user = g.user if hasattr(g, "user") and g.user else None - if not user or security_manager.is_guest_user(user) or user.is_anonymous: - abort(404) - payload = { - "user": bootstrap_user_data(user, include_perms=True), - "common": common_bootstrap_payload(user), - } - - return self.render_template( - "superset/basic.html", - title=_("%(user)s's profile", user=get_username()), - entry="profile", - bootstrap_data=json.dumps( - payload, default=utils.pessimistic_json_iso_dttm_ser - ), - ) + return redirect("/profile/") @has_access @event_logger.log_this diff --git a/superset/views/datasource/schemas.py b/superset/views/datasource/schemas.py index e718057ce6653..daefb2a7ed052 100644 --- a/superset/views/datasource/schemas.py +++ b/superset/views/datasource/schemas.py @@ -14,7 +14,7 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -from typing import Any +from typing import Any, Optional from marshmallow import fields, post_load, pre_load, Schema, validate from typing_extensions import TypedDict @@ -29,6 +29,7 @@ class ExternalMetadataParams(TypedDict): database_name: str schema_name: str table_name: str + normalize_columns: Optional[bool] get_external_metadata_schema = { @@ -36,6 +37,7 @@ class ExternalMetadataParams(TypedDict): "database_name": "string", "schema_name": "string", "table_name": "string", + "normalize_columns": "boolean", } @@ -44,6 +46,7 @@ class ExternalMetadataSchema(Schema): database_name = fields.Str(required=True) schema_name = fields.Str(allow_none=True) table_name = fields.Str(required=True) + normalize_columns = fields.Bool(allow_none=True) # pylint: disable=unused-argument @post_load @@ -57,6 +60,7 @@ def normalize( database_name=data["database_name"], schema_name=data.get("schema_name", ""), table_name=data["table_name"], + normalize_columns=data["normalize_columns"], ) diff --git a/superset/views/datasource/views.py b/superset/views/datasource/views.py index f1086acd47330..b2fd387379fd9 100644 --- a/superset/views/datasource/views.py +++ b/superset/views/datasource/views.py @@ -77,6 +77,8 @@ def save(self) -> FlaskResponse: return json_error_response(_("Request missing data field."), status=500) datasource_dict = json.loads(data) + normalize_columns = datasource_dict.get("normalize_columns", False) + datasource_dict["normalize_columns"] = normalize_columns datasource_id = datasource_dict.get("id") datasource_type = datasource_dict.get("type") database_id = datasource_dict["database"].get("id") @@ -196,6 +198,7 @@ def external_metadata_by_name(self, **kwargs: Any) -> FlaskResponse: database=database, table_name=params["table_name"], schema_name=params["schema_name"], + normalize_columns=params.get("normalize_columns") or False, ) except (NoResultFound, NoSuchTableError) as ex: raise DatasetNotFoundError() from ex diff --git a/superset/views/profile.py b/superset/views/profile.py new file mode 100644 index 0000000000000..3308a0f645edc --- /dev/null +++ b/superset/views/profile.py @@ -0,0 +1,40 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +from flask import abort, g +from flask_appbuilder import permission_name +from flask_appbuilder.api import expose +from flask_appbuilder.security.decorators import has_access + +from superset import event_logger, security_manager +from superset.superset_typing import FlaskResponse + +from .base import BaseSupersetView + + +class ProfileView(BaseSupersetView): + route_base = "/profile" + class_permission_name = "Profile" + + @expose("/") + @has_access + @permission_name("read") + @event_logger.log_this + def root(self) -> FlaskResponse: + user = g.user if hasattr(g, "user") and g.user else None + if not user or security_manager.is_guest_user(user) or user.is_anonymous: + abort(404) + return super().render_app_template() diff --git a/superset/views/sql_lab/views.py b/superset/views/sql_lab/views.py index 0da95612de2e0..62558f5ab524f 100644 --- a/superset/views/sql_lab/views.py +++ b/superset/views/sql_lab/views.py @@ -17,120 +17,31 @@ import logging import simplejson as json -from flask import g, redirect, request, Response +from flask import redirect, request, Response from flask_appbuilder import expose -from flask_appbuilder.models.sqla.interface import SQLAInterface from flask_appbuilder.security.decorators import has_access, has_access_api from flask_babel import lazy_gettext as _ from sqlalchemy import and_ from superset import db -from superset.constants import MODEL_VIEW_RW_METHOD_PERMISSION_MAP, RouteMethod -from superset.models.sql_lab import Query, SavedQuery, TableSchema, TabState +from superset.models.sql_lab import Query, TableSchema, TabState from superset.superset_typing import FlaskResponse from superset.utils import core as utils from superset.utils.core import get_user_id -from superset.views.base import ( - BaseSupersetView, - DeleteMixin, - json_success, - SupersetModelView, -) +from superset.views.base import BaseSupersetView, json_success logger = logging.getLogger(__name__) -class SavedQueryView( # pylint: disable=too-many-ancestors - SupersetModelView, - DeleteMixin, -): - datamodel = SQLAInterface(SavedQuery) - include_route_methods = RouteMethod.CRUD_SET - +class SavedQueryView(BaseSupersetView): + route_base = "/savedqueryview" class_permission_name = "SavedQuery" - method_permission_name = MODEL_VIEW_RW_METHOD_PERMISSION_MAP - list_title = _("List Saved Query") - show_title = _("Show Saved Query") - add_title = _("Add Saved Query") - edit_title = _("Edit Saved Query") - - list_columns = [ - "label", - "user", - "database", - "schema", - "description", - "modified", - "pop_tab_link", - ] - order_columns = ["label", "schema", "description", "modified"] - show_columns = [ - "id", - "label", - "user", - "database", - "description", - "sql", - "pop_tab_link", - ] - search_columns = ("label", "user", "database", "schema", "changed_on") - add_columns = ["label", "database", "description", "sql"] - edit_columns = add_columns - base_order = ("changed_on", "desc") - label_columns = { - "label": _("Label"), - "user": _("User"), - "database": _("Database"), - "description": _("Description"), - "modified": _("Modified"), - "end_time": _("End Time"), - "pop_tab_link": _("Pop Tab Link"), - "changed_on": _("Changed on"), - } @expose("/list/") @has_access def list(self) -> FlaskResponse: return super().render_app_template() - def pre_add(self, item: "SavedQueryView") -> None: - item.user = g.user - - def pre_update(self, item: "SavedQueryView") -> None: - self.pre_add(item) - - -class SavedQueryViewApi(SavedQueryView): # pylint: disable=too-many-ancestors - include_route_methods = { - RouteMethod.API_READ, - RouteMethod.API_CREATE, - RouteMethod.API_UPDATE, - RouteMethod.API_GET, - } - - class_permission_name = "SavedQuery" - method_permission_name = MODEL_VIEW_RW_METHOD_PERMISSION_MAP - - list_columns = [ - "id", - "label", - "sqlalchemy_uri", - "user_email", - "schema", - "description", - "sql", - "extra_json", - "extra", - ] - add_columns = ["label", "db_id", "schema", "description", "sql", "extra_json"] - edit_columns = add_columns - show_columns = add_columns + ["id"] - - @has_access_api - @expose("show/") - def show(self, pk: int) -> FlaskResponse: - return super().show(pk) - def _get_owner_id(tab_state_id: int) -> int: return db.session.query(TabState.user_id).filter_by(id=tab_state_id).scalar() diff --git a/tests/integration_tests/core_tests.py b/tests/integration_tests/core_tests.py index ddcfa189b2b28..2f346564e9b60 100644 --- a/tests/integration_tests/core_tests.py +++ b/tests/integration_tests/core_tests.py @@ -26,12 +26,10 @@ from urllib.parse import quote import pandas as pd -import prison import pytest import pytz import sqlalchemy as sqla from flask_babel import lazy_gettext as _ -from sqlalchemy import Table from sqlalchemy.exc import SQLAlchemyError import superset.utils.database @@ -43,10 +41,9 @@ from superset.connectors.sqla.models import SqlaTable from superset.db_engine_specs.base import BaseEngineSpec from superset.db_engine_specs.mssql import MssqlEngineSpec -from superset.exceptions import QueryObjectValidationError, SupersetException +from superset.exceptions import SupersetException from superset.extensions import async_query_manager, cache_manager from superset.models import core as models -from superset.models.annotations import Annotation, AnnotationLayer from superset.models.cache import CacheKey from superset.models.dashboard import Dashboard from superset.models.slice import Slice @@ -56,9 +53,8 @@ from superset.utils import core as utils from superset.utils.core import backend from superset.utils.database import get_example_database -from superset.views import core as views from superset.views.database.views import DatabaseView -from tests.integration_tests.conftest import CTAS_SCHEMA_NAME, with_feature_flags +from tests.integration_tests.conftest import with_feature_flags from tests.integration_tests.fixtures.birth_names_dashboard import ( load_birth_names_dashboard_with_slices, load_birth_names_data, @@ -67,12 +63,10 @@ load_energy_table_data, load_energy_table_with_slice, ) -from tests.integration_tests.fixtures.public_role import public_role_like_gamma from tests.integration_tests.fixtures.world_bank_dashboard import ( load_world_bank_dashboard_with_slices, load_world_bank_data, ) -from tests.integration_tests.insert_chart_mixin import InsertChartMixin from tests.integration_tests.test_app import app from .base_tests import SupersetTestCase @@ -88,7 +82,7 @@ def cleanup(): yield -class TestCore(SupersetTestCase, InsertChartMixin): +class TestCore(SupersetTestCase): def setUp(self): self.table_ids = { tbl.table_name: tbl.id for tbl in (db.session.query(SqlaTable).all()) @@ -109,25 +103,6 @@ def insert_dashboard_created_by(self, username: str) -> Dashboard: ) return dashboard - def insert_chart_created_by(self, username: str) -> Slice: - user = self.get_user(username) - dataset = db.session.query(SqlaTable).first() - chart = self.insert_chart( - f"create_title_test", - [user.id], - dataset.id, - created_by=user, - ) - return chart - - @pytest.fixture() - def insert_dashboard_created_by_admin(self): - with self.create_app().app_context(): - dashboard = self.insert_dashboard_created_by("admin") - yield dashboard - db.session.delete(dashboard) - db.session.commit() - @pytest.fixture() def insert_dashboard_created_by_gamma(self): dashboard = self.insert_dashboard_created_by("gamma") @@ -135,14 +110,6 @@ def insert_dashboard_created_by_gamma(self): db.session.delete(dashboard) db.session.commit() - @pytest.fixture() - def insert_chart_created_by_admin(self): - with self.create_app().app_context(): - chart = self.insert_chart_created_by("admin") - yield chart - db.session.delete(chart) - db.session.commit() - def test_login(self): resp = self.get_resp("/login/", data=dict(username="admin", password="general")) self.assertNotIn("User confirmation needed", resp) @@ -515,100 +482,6 @@ def test_fetch_datasource_metadata(self): for k in keys: self.assertIn(k, resp.keys()) - @pytest.mark.usefixtures("insert_dashboard_created_by_admin") - @pytest.mark.usefixtures("insert_chart_created_by_admin") - @pytest.mark.usefixtures("load_birth_names_dashboard_with_slices") - def test_user_profile(self, username="admin"): - self.login(username=username) - slc = self.get_slice("Girls", db.session) - dashboard = db.session.query(Dashboard).filter_by(slug="births").first() - # Set a favorite dashboard - self.client.post(f"/api/v1/dashboard/{dashboard.id}/favorites/", json={}) - # Set a favorite chart - self.client.post(f"/api/v1/chart/{slc.id}/favorites/", json={}) - - # Get favorite dashboards: - request_query = { - "columns": ["created_on_delta_humanized", "dashboard_title", "url"], - "filters": [{"col": "id", "opr": "dashboard_is_favorite", "value": True}], - "keys": ["none"], - "order_column": "changed_on", - "order_direction": "desc", - "page": 0, - "page_size": 100, - } - url = f"/api/v1/dashboard/?q={prison.dumps(request_query)}" - resp = self.client.get(url) - assert resp.json["count"] == 1 - assert resp.json["result"][0]["dashboard_title"] == "USA Births Names" - - # Get Favorite Charts - request_query = { - "filters": [{"col": "id", "opr": "chart_is_favorite", "value": True}], - "order_column": "slice_name", - "order_direction": "asc", - "page": 0, - "page_size": 25, - } - url = f"api/v1/chart/?q={prison.dumps(request_query)}" - resp = self.client.get(url) - assert resp.json["count"] == 1 - assert resp.json["result"][0]["id"] == slc.id - - # Get recent activity - url = "/api/v1/log/recent_activity/?q=(page_size:50)" - resp = self.client.get(url) - # TODO data for recent activity varies for sqlite, we should be able to assert - # the returned data - assert resp.status_code == 200 - - # Get dashboards created by the user - request_query = { - "columns": ["created_on_delta_humanized", "dashboard_title", "url"], - "filters": [ - {"col": "created_by", "opr": "dashboard_created_by_me", "value": "me"} - ], - "keys": ["none"], - "order_column": "changed_on", - "order_direction": "desc", - "page": 0, - "page_size": 100, - } - url = f"/api/v1/dashboard/?q={prison.dumps(request_query)}" - resp = self.client.get(url) - assert resp.json["result"][0]["dashboard_title"] == "create_title_test" - - # Get charts created by the user - request_query = { - "columns": ["created_on_delta_humanized", "slice_name", "url"], - "filters": [ - {"col": "created_by", "opr": "chart_created_by_me", "value": "me"} - ], - "keys": ["none"], - "order_column": "changed_on_delta_humanized", - "order_direction": "desc", - "page": 0, - "page_size": 100, - } - url = f"/api/v1/chart/?q={prison.dumps(request_query)}" - resp = self.client.get(url) - assert resp.json["count"] == 1 - assert resp.json["result"][0]["slice_name"] == "create_title_test" - - resp = self.get_resp(f"/superset/profile/") - self.assertIn('"app"', resp) - - def test_user_profile_gamma(self): - self.login(username="gamma") - resp = self.get_resp(f"/superset/profile/") - self.assertIn('"app"', resp) - - @pytest.mark.usefixtures("public_role_like_gamma") - def test_user_profile_anonymous(self): - self.logout() - resp = self.client.get("/superset/profile/") - assert resp.status_code == 404 - @pytest.mark.usefixtures("load_birth_names_dashboard_with_slices") def test_slice_id_is_always_logged_correctly_on_web_request(self): # explore case @@ -1092,54 +965,6 @@ def test_feature_flag_serialization(self): data = self.get_resp(url) self.assertTrue(html_string in data) - @mock.patch.dict( - "superset.extensions.feature_flag_manager._feature_flags", - {"SQLLAB_BACKEND_PERSISTENCE": True}, - clear=True, - ) - def test_sqllab_backend_persistence_payload(self): - username = "admin" - self.login(username) - user_id = security_manager.find_user(username).id - - # create a tab - data = { - "queryEditor": json.dumps( - { - "title": "Untitled Query 1", - "dbId": 1, - "schema": None, - "autorun": False, - "sql": "SELECT ...", - "queryLimit": 1000, - } - ) - } - resp = self.get_json_resp("/tabstateview/", data=data) - tab_state_id = resp["id"] - - # run a query in the created tab - self.run_sql( - "SELECT name FROM birth_names", - "client_id_1", - username=username, - raise_on_error=True, - sql_editor_id=str(tab_state_id), - ) - # run an orphan query (no tab) - self.run_sql( - "SELECT name FROM birth_names", - "client_id_2", - username=username, - raise_on_error=True, - ) - - # we should have only 1 query returned, since the second one is not - # associated with any tabs - # TODO: replaces this spec by api/v1/sqllab spec later - payload = bootstrap_sqllab_data(user_id) - self.assertEqual(len(payload["queries"]), 1) - @mock.patch.dict( "superset.extensions.feature_flag_manager._feature_flags", {"SQLLAB_BACKEND_PERSISTENCE": True}, @@ -1330,6 +1155,11 @@ def test_has_table_by_name(self): is True ) + def test_redirect_new_profile(self): + self.login(username="admin") + resp = self.client.get("/superset/profile/") + assert resp.status_code == 302 + if __name__ == "__main__": unittest.main() diff --git a/tests/integration_tests/dashboard_tests.py b/tests/integration_tests/dashboard_tests.py index fef4edd6cc4d1..0df9b22267386 100644 --- a/tests/integration_tests/dashboard_tests.py +++ b/tests/integration_tests/dashboard_tests.py @@ -27,7 +27,6 @@ from tests.integration_tests.test_app import app from superset import db, security_manager from superset.connectors.sqla.models import SqlaTable -from superset.models import core as models from superset.models.dashboard import Dashboard from superset.models.slice import Slice from tests.integration_tests.fixtures.birth_names_dashboard import ( @@ -227,44 +226,6 @@ def test_users_can_view_own_dashboard(self): self.assertIn(f"/superset/dashboard/{my_dash_slug}/", resp) self.assertNotIn(f"/superset/dashboard/{not_my_dash_slug}/", resp) - def test_users_can_view_favorited_dashboards(self): - user = security_manager.find_user("gamma") - fav_dash_slug = f"my_favorite_dash_{random()}" - regular_dash_slug = f"regular_dash_{random()}" - - favorite_dash = Dashboard() - favorite_dash.dashboard_title = "My Favorite Dashboard" - favorite_dash.slug = fav_dash_slug - - regular_dash = Dashboard() - regular_dash.dashboard_title = "A Plain Ol Dashboard" - regular_dash.slug = regular_dash_slug - - db.session.add(favorite_dash) - db.session.add(regular_dash) - db.session.commit() - - dash = db.session.query(Dashboard).filter_by(slug=fav_dash_slug).first() - - favorites = models.FavStar() - favorites.obj_id = dash.id - favorites.class_name = "Dashboard" - favorites.user_id = user.id - - db.session.add(favorites) - db.session.commit() - - self.login(user.username) - - resp = self.get_resp("/api/v1/dashboard/") - - db.session.delete(favorites) - db.session.delete(regular_dash) - db.session.delete(favorite_dash) - db.session.commit() - - self.assertIn(f"/superset/dashboard/{fav_dash_slug}/", resp) - def test_user_can_not_view_unpublished_dash(self): admin_user = security_manager.find_user("admin") gamma_user = security_manager.find_user("gamma") diff --git a/tests/integration_tests/dashboard_utils.py b/tests/integration_tests/dashboard_utils.py index 6c3d000051f35..e284e21ca4bd9 100644 --- a/tests/integration_tests/dashboard_utils.py +++ b/tests/integration_tests/dashboard_utils.py @@ -53,7 +53,7 @@ def create_table_metadata( table = get_table(table_name, database, schema) if not table: - table = SqlaTable(schema=schema, table_name=table_name) + table = SqlaTable(schema=schema, table_name=table_name, normalize_columns=False) if fetch_values_predicate: table.fetch_values_predicate = fetch_values_predicate table.database = database diff --git a/tests/integration_tests/dashboards/security/security_dataset_tests.py b/tests/integration_tests/dashboards/security/security_dataset_tests.py index dffab61a7abef..54e8b81442970 100644 --- a/tests/integration_tests/dashboards/security/security_dataset_tests.py +++ b/tests/integration_tests/dashboards/security/security_dataset_tests.py @@ -23,7 +23,6 @@ from superset import app from superset.daos.dashboard import DashboardDAO -from superset.models import core as models from tests.integration_tests.dashboards.base_case import DashboardTestCase from tests.integration_tests.dashboards.consts import * from tests.integration_tests.dashboards.dashboard_test_utils import * @@ -124,48 +123,6 @@ def test_get_dashboards__owners_can_view_empty_dashboard(self): # assert self.assertNotIn(dashboard_url, get_dashboards_response) - def test_get_dashboards__users_can_view_favorites_dashboards(self): - # arrange - user = security_manager.find_user("gamma") - fav_dash_slug = f"my_favorite_dash_{random_slug()}" - regular_dash_slug = f"regular_dash_{random_slug()}" - - favorite_dash = Dashboard() - favorite_dash.dashboard_title = "My Favorite Dashboard" - favorite_dash.slug = fav_dash_slug - - regular_dash = Dashboard() - regular_dash.dashboard_title = "A Plain Ol Dashboard" - regular_dash.slug = regular_dash_slug - - db.session.add(favorite_dash) - db.session.add(regular_dash) - db.session.commit() - - dash = db.session.query(Dashboard).filter_by(slug=fav_dash_slug).first() - - favorites = models.FavStar() - favorites.obj_id = dash.id - favorites.class_name = "Dashboard" - favorites.user_id = user.id - - db.session.add(favorites) - db.session.commit() - - self.login(user.username) - - # act - get_dashboards_response = self.get_resp(DASHBOARDS_API_URL) - - # cleanup - db.session.delete(favorites) - db.session.delete(favorite_dash) - db.session.delete(regular_dash) - db.session.commit() - - # assert - self.assertIn(f"/superset/dashboard/{fav_dash_slug}/", get_dashboards_response) - def test_get_dashboards__user_can_not_view_unpublished_dash(self): # arrange admin_user = security_manager.find_user(ADMIN_USERNAME) diff --git a/tests/integration_tests/datasets/api_tests.py b/tests/integration_tests/datasets/api_tests.py index 027002507aece..2c6850e5bb5a0 100644 --- a/tests/integration_tests/datasets/api_tests.py +++ b/tests/integration_tests/datasets/api_tests.py @@ -25,6 +25,7 @@ import prison import pytest import yaml +from sqlalchemy import inspect from sqlalchemy.orm import joinedload from sqlalchemy.sql import func @@ -153,7 +154,9 @@ def create_datasets(self): # rollback changes for dataset in datasets: - db.session.delete(dataset) + state = inspect(dataset) + if not state.was_deleted: + db.session.delete(dataset) db.session.commit() @staticmethod @@ -540,6 +543,8 @@ def test_create_dataset_item(self): model = db.session.query(SqlaTable).get(table_id) assert model.table_name == table_data["table_name"] assert model.database_id == table_data["database"] + # normalize_columns should default to False + assert model.normalize_columns is False # Assert that columns were created columns = ( @@ -563,6 +568,34 @@ def test_create_dataset_item(self): db.session.delete(model) db.session.commit() + def test_create_dataset_item_normalize(self): + """ + Dataset API: Test create dataset item with column normalization enabled + """ + if backend() == "sqlite": + return + + main_db = get_main_database() + self.login(username="admin") + table_data = { + "database": main_db.id, + "schema": None, + "table_name": "ab_permission", + "normalize_columns": True, + } + uri = "api/v1/dataset/" + rv = self.post_assert_metric(uri, table_data, "post") + assert rv.status_code == 201 + data = json.loads(rv.data.decode("utf-8")) + table_id = data.get("id") + model = db.session.query(SqlaTable).get(table_id) + assert model.table_name == table_data["table_name"] + assert model.database_id == table_data["database"] + assert model.normalize_columns is True + + db.session.delete(model) + db.session.commit() + def test_create_dataset_item_gamma(self): """ Dataset API: Test create dataset item gamma @@ -2494,8 +2527,9 @@ def test_get_or_create_dataset_creates_table(self): .filter_by(table_name="test_create_sqla_table_api") .one() ) - self.assertEqual(response["result"], {"table_id": table.id}) - self.assertEqual(table.template_params, '{"param": 1}') + assert response["result"] == {"table_id": table.id} + assert table.template_params == '{"param": 1}' + assert table.normalize_columns is False db.session.delete(table) with examples_db.get_sqla_engine_with_context() as engine: diff --git a/tests/integration_tests/datasets/commands_tests.py b/tests/integration_tests/datasets/commands_tests.py index b3b5084e35cb0..19caa9e1a111a 100644 --- a/tests/integration_tests/datasets/commands_tests.py +++ b/tests/integration_tests/datasets/commands_tests.py @@ -170,6 +170,7 @@ def test_export_dataset_command(self, mock_g): "warning_text": None, }, ], + "normalize_columns": False, "offset": 0, "params": None, "schema": get_example_default_schema(), @@ -229,6 +230,7 @@ def test_export_dataset_command_key_order(self, mock_g): "filter_select_enabled", "fetch_values_predicate", "extra", + "normalize_columns", "uuid", "metrics", "columns", diff --git a/tests/integration_tests/datasource_tests.py b/tests/integration_tests/datasource_tests.py index 5de1cf6ef85e1..4c05898cfe75e 100644 --- a/tests/integration_tests/datasource_tests.py +++ b/tests/integration_tests/datasource_tests.py @@ -105,6 +105,7 @@ def test_external_metadata_by_name_for_physical_table(self): "database_name": tbl.database.database_name, "schema_name": tbl.schema, "table_name": tbl.table_name, + "normalize_columns": tbl.normalize_columns, } ) url = f"/datasource/external_metadata_by_name/?q={params}" @@ -133,6 +134,7 @@ def test_external_metadata_by_name_for_virtual_table(self): "database_name": tbl.database.database_name, "schema_name": tbl.schema, "table_name": tbl.table_name, + "normalize_columns": tbl.normalize_columns, } ) url = f"/datasource/external_metadata_by_name/?q={params}" @@ -151,6 +153,7 @@ def test_external_metadata_by_name_from_sqla_inspector(self): "database_name": example_database.database_name, "table_name": "test_table", "schema_name": get_example_default_schema(), + "normalize_columns": False, } ) url = f"/datasource/external_metadata_by_name/?q={params}" @@ -164,6 +167,7 @@ def test_external_metadata_by_name_from_sqla_inspector(self): "datasource_type": "table", "database_name": "foo", "table_name": "bar", + "normalize_columns": False, } ) url = f"/datasource/external_metadata_by_name/?q={params}" @@ -180,6 +184,7 @@ def test_external_metadata_by_name_from_sqla_inspector(self): "datasource_type": "table", "database_name": example_database.database_name, "table_name": "fooooooooobarrrrrr", + "normalize_columns": False, } ) url = f"/datasource/external_metadata_by_name/?q={params}" diff --git a/tests/integration_tests/fixtures/importexport.py b/tests/integration_tests/fixtures/importexport.py index d0fa04e97dfc7..cda9dd0bcc379 100644 --- a/tests/integration_tests/fixtures/importexport.py +++ b/tests/integration_tests/fixtures/importexport.py @@ -312,6 +312,7 @@ "sql": None, "table_name": "birth_names_2", "template_params": None, + "normalize_columns": False, } } ], @@ -494,6 +495,7 @@ "sql": "", "params": None, "template_params": {}, + "normalize_columns": False, "filter_select_enabled": True, "fetch_values_predicate": None, "extra": '{ "certification": { "certified_by": "Data Platform Team", "details": "This table is the source of truth." }, "warning_markdown": "This is a warning." }', diff --git a/tests/integration_tests/import_export_tests.py b/tests/integration_tests/import_export_tests.py index 4c7f2477c9ada..5dc8143f77616 100644 --- a/tests/integration_tests/import_export_tests.py +++ b/tests/integration_tests/import_export_tests.py @@ -123,7 +123,10 @@ def create_dashboard(self, title, id=0, slcs=[]): def create_table(self, name, schema=None, id=0, cols_names=[], metric_names=[]): params = {"remote_id": id, "database_name": "examples"} table = SqlaTable( - id=id, schema=schema, table_name=name, params=json.dumps(params) + id=id, + schema=schema, + table_name=name, + params=json.dumps(params), ) for col_name in cols_names: table.columns.append(TableColumn(column_name=col_name)) diff --git a/tests/integration_tests/profile_tests.py b/tests/integration_tests/profile_tests.py new file mode 100644 index 0000000000000..aa5448139e707 --- /dev/null +++ b/tests/integration_tests/profile_tests.py @@ -0,0 +1,164 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +import prison +import pytest + +from superset import db +from superset.connectors.sqla.models import SqlaTable +from superset.models.dashboard import Dashboard +from superset.models.slice import Slice +from tests.integration_tests.fixtures.birth_names_dashboard import ( + load_birth_names_dashboard_with_slices, + load_birth_names_data, +) +from tests.integration_tests.fixtures.public_role import public_role_like_gamma +from tests.integration_tests.insert_chart_mixin import InsertChartMixin + +from .base_tests import SupersetTestCase + + +class TestProfile(SupersetTestCase, InsertChartMixin): + def insert_dashboard_created_by(self, username: str) -> Dashboard: + user = self.get_user(username) + dashboard = self.insert_dashboard( + f"create_title_test", + f"create_slug_test", + [user.id], + created_by=user, + ) + return dashboard + + @pytest.fixture() + def insert_dashboard_created_by_admin(self): + with self.create_app().app_context(): + dashboard = self.insert_dashboard_created_by("admin") + yield dashboard + db.session.delete(dashboard) + db.session.commit() + + def insert_chart_created_by(self, username: str) -> Slice: + user = self.get_user(username) + dataset = db.session.query(SqlaTable).first() + chart = self.insert_chart( + f"create_title_test", + [user.id], + dataset.id, + created_by=user, + ) + return chart + + @pytest.fixture() + def insert_chart_created_by_admin(self): + with self.create_app().app_context(): + chart = self.insert_chart_created_by("admin") + yield chart + db.session.delete(chart) + db.session.commit() + + @pytest.mark.usefixtures("insert_dashboard_created_by_admin") + @pytest.mark.usefixtures("insert_chart_created_by_admin") + @pytest.mark.usefixtures("load_birth_names_dashboard_with_slices") + def test_user_profile(self, username="admin"): + self.login(username=username) + slc = self.get_slice("Girls", db.session) + dashboard = db.session.query(Dashboard).filter_by(slug="births").first() + # Set a favorite dashboard + self.client.post(f"/api/v1/dashboard/{dashboard.id}/favorites/", json={}) + # Set a favorite chart + self.client.post(f"/api/v1/chart/{slc.id}/favorites/", json={}) + + # Get favorite dashboards: + request_query = { + "columns": ["created_on_delta_humanized", "dashboard_title", "url"], + "filters": [{"col": "id", "opr": "dashboard_is_favorite", "value": True}], + "keys": ["none"], + "order_column": "changed_on", + "order_direction": "desc", + "page": 0, + "page_size": 100, + } + url = f"/api/v1/dashboard/?q={prison.dumps(request_query)}" + resp = self.client.get(url) + assert resp.json["count"] == 1 + assert resp.json["result"][0]["dashboard_title"] == "USA Births Names" + + # Get Favorite Charts + request_query = { + "filters": [{"col": "id", "opr": "chart_is_favorite", "value": True}], + "order_column": "slice_name", + "order_direction": "asc", + "page": 0, + "page_size": 25, + } + url = f"api/v1/chart/?q={prison.dumps(request_query)}" + resp = self.client.get(url) + assert resp.json["count"] == 1 + assert resp.json["result"][0]["id"] == slc.id + + # Get recent activity + url = "/api/v1/log/recent_activity/?q=(page_size:50)" + resp = self.client.get(url) + # TODO data for recent activity varies for sqlite, we should be able to assert + # the returned data + assert resp.status_code == 200 + + # Get dashboards created by the user + request_query = { + "columns": ["created_on_delta_humanized", "dashboard_title", "url"], + "filters": [ + {"col": "created_by", "opr": "dashboard_created_by_me", "value": "me"} + ], + "keys": ["none"], + "order_column": "changed_on", + "order_direction": "desc", + "page": 0, + "page_size": 100, + } + url = f"/api/v1/dashboard/?q={prison.dumps(request_query)}" + resp = self.client.get(url) + assert resp.json["result"][0]["dashboard_title"] == "create_title_test" + + # Get charts created by the user + request_query = { + "columns": ["created_on_delta_humanized", "slice_name", "url"], + "filters": [ + {"col": "created_by", "opr": "chart_created_by_me", "value": "me"} + ], + "keys": ["none"], + "order_column": "changed_on_delta_humanized", + "order_direction": "desc", + "page": 0, + "page_size": 100, + } + url = f"/api/v1/chart/?q={prison.dumps(request_query)}" + resp = self.client.get(url) + assert resp.json["count"] == 1 + assert resp.json["result"][0]["slice_name"] == "create_title_test" + + resp = self.get_resp(f"/profile/") + self.assertIn('"app"', resp) + + def test_user_profile_gamma(self): + self.login(username="gamma") + resp = self.get_resp(f"/profile/") + self.assertIn('"app"', resp) + + @pytest.mark.usefixtures("public_role_like_gamma") + def test_user_profile_anonymous(self): + self.logout() + resp = self.client.get("/profile/") + assert resp.status_code == 404 diff --git a/tests/integration_tests/sql_lab/api_tests.py b/tests/integration_tests/sql_lab/api_tests.py index 89aefdfd0979d..ebe00add61393 100644 --- a/tests/integration_tests/sql_lab/api_tests.py +++ b/tests/integration_tests/sql_lab/api_tests.py @@ -28,6 +28,7 @@ from sqlalchemy.sql import func from unittest import mock +from flask_appbuilder.security.sqla.models import Role from tests.integration_tests.test_app import app from superset import db, sql_lab from superset.common.db_query_status import QueryStatus @@ -37,11 +38,95 @@ from superset.models.sql_lab import Query from tests.integration_tests.base_tests import SupersetTestCase +from tests.integration_tests.fixtures.users import create_gamma_sqllab_no_data QUERIES_FIXTURE_COUNT = 10 class TestSqlLabApi(SupersetTestCase): + @pytest.mark.usefixtures("create_gamma_sqllab_no_data") + @mock.patch.dict( + "superset.extensions.feature_flag_manager._feature_flags", + {"SQLLAB_BACKEND_PERSISTENCE": False}, + clear=True, + ) + def test_get_from_empty_bootsrap_data(self): + self.login(username="gamma_sqllab_no_data") + resp = self.client.get("/api/v1/sqllab/") + assert resp.status_code == 200 + data = json.loads(resp.data.decode("utf-8")) + result = data.get("result") + assert result["active_tab"] == None + assert result["queries"] == {} + assert result["tab_state_ids"] == [] + self.assertEqual(len(result["databases"]), 0) + + @mock.patch.dict( + "superset.extensions.feature_flag_manager._feature_flags", + {"SQLLAB_BACKEND_PERSISTENCE": True}, + clear=True, + ) + def test_get_from_bootstrap_data_with_queries(self): + username = "admin" + self.login(username) + + # create a tab + data = { + "queryEditor": json.dumps( + { + "title": "Untitled Query 1", + "dbId": 1, + "schema": None, + "autorun": False, + "sql": "SELECT ...", + "queryLimit": 1000, + } + ) + } + resp = self.get_json_resp("/tabstateview/", data=data) + tab_state_id = resp["id"] + + # run a query in the created tab + self.run_sql( + "SELECT name FROM birth_names", + "client_id_1", + username=username, + raise_on_error=True, + sql_editor_id=str(tab_state_id), + ) + # run an orphan query (no tab) + self.run_sql( + "SELECT name FROM birth_names", + "client_id_2", + username=username, + raise_on_error=True, + ) + + # we should have only 1 query returned, since the second one is not + # associated with any tabs + resp = self.get_json_resp("/api/v1/sqllab/") + result = resp["result"] + self.assertEqual(len(result["queries"]), 1) + + def test_get_access_denied(self): + new_role = Role(name="Dummy Role", permissions=[]) + db.session.add(new_role) + db.session.commit() + unauth_user = self.create_user( + "unauth_user1", + "password", + "Dummy Role", + email=f"unauth_user1@superset.org", + ) + self.login(username="unauth_user1", password="password") + rv = self.client.get("/api/v1/sqllab/") + + assert rv.status_code == 403 + + db.session.delete(unauth_user) + db.session.delete(new_role) + db.session.commit() + def test_estimate_required_params(self): self.login() diff --git a/tests/unit_tests/datasets/commands/export_test.py b/tests/unit_tests/datasets/commands/export_test.py index 17913c2ca4bd4..e9c217a1916e4 100644 --- a/tests/unit_tests/datasets/commands/export_test.py +++ b/tests/unit_tests/datasets/commands/export_test.py @@ -81,6 +81,7 @@ def test_export(session: Session) -> None: is_sqllab_view=0, # no longer used? template_params=json.dumps({"answer": "42"}), schema_perm=None, + normalize_columns=False, extra=json.dumps({"warning_markdown": "*WARNING*"}), ) @@ -108,6 +109,7 @@ def test_export(session: Session) -> None: fetch_values_predicate: foo IN (1, 2) extra: warning_markdown: '*WARNING*' +normalize_columns: false uuid: null metrics: - metric_name: cnt