changeSchema({ value: schema }, true)}
+ onClick={onRefresh}
tooltipContent={t('Force refresh table list')}
/>
);
- return renderSelectRow(select, refresh);
- }
- function renderSeeTableLabel() {
- return (
-
-
- {t('See table schema')}{' '}
- {schema && (
-
- {tableOptions.length} in {schema}
-
- )}
-
-
- );
+ return renderSelectRow(select, refresh);
}
return (
{renderDatabaseSelector()}
- {!formMode && }
- {sqlLabMode && renderSeeTableLabel()}
- {formMode && {t('Table')}}
+ {sqlLabMode && !formMode && }
{renderTableSelect()}
);
diff --git a/superset-frontend/src/components/WarningIconWithTooltip/index.tsx b/superset-frontend/src/components/WarningIconWithTooltip/index.tsx
index f160ade50ec72..f732554e15aaa 100644
--- a/superset-frontend/src/components/WarningIconWithTooltip/index.tsx
+++ b/superset-frontend/src/components/WarningIconWithTooltip/index.tsx
@@ -18,16 +18,17 @@
*/
import React from 'react';
import { useTheme, SafeMarkdown } from '@superset-ui/core';
-import Icons from 'src/components/Icons';
+import Icons, { IconType } from 'src/components/Icons';
import { Tooltip } from 'src/components/Tooltip';
export interface WarningIconWithTooltipProps {
warningMarkdown: string;
- size?: number;
+ size?: IconType['iconSize'];
}
function WarningIconWithTooltip({
warningMarkdown,
+ size,
}: WarningIconWithTooltipProps) {
const theme = useTheme();
return (
@@ -37,6 +38,7 @@ function WarningIconWithTooltip({
>
diff --git a/superset-frontend/src/datasource/DatasourceEditor.jsx b/superset-frontend/src/datasource/DatasourceEditor.jsx
index e11b8310bb75c..d8a0a3425f244 100644
--- a/superset-frontend/src/datasource/DatasourceEditor.jsx
+++ b/superset-frontend/src/datasource/DatasourceEditor.jsx
@@ -775,41 +775,47 @@ class DatasourceEditor extends React.PureComponent {
{this.state.isSqla && (
<>
-
- this.state.isEditMode &&
- this.onDatasourcePropChange('schema', schema)
- }
- onDbChange={database =>
- this.state.isEditMode &&
- this.onDatasourcePropChange('database', database)
+
+
+
+ this.state.isEditMode &&
+ this.onDatasourcePropChange('schema', schema)
+ }
+ onDbChange={database =>
+ this.state.isEditMode &&
+ this.onDatasourcePropChange('database', database)
+ }
+ formMode={false}
+ handleError={this.props.addDangerToast}
+ readOnly={!this.state.isEditMode}
+ />
+
+ }
+ />
+
+ {
+ this.onDatasourcePropChange('table_name', table);
+ }}
+ placeholder={t('Dataset name')}
+ disabled={!this.state.isEditMode}
+ />
}
- formMode={false}
- handleError={this.props.addDangerToast}
- readOnly={!this.state.isEditMode}
- />
- }
- />
- {
- this.onDatasourcePropChange('table_name', table);
- }}
- placeholder={t('Dataset name')}
- disabled={!this.state.isEditMode}
/>
- }
- />
+
+
- this.onDatasourcePropChange('schema', schema)
- : undefined
- }
- onDbChange={
- this.state.isEditMode
- ? database =>
- this.onDatasourcePropChange('database', database)
- : undefined
- }
- onTableChange={
- this.state.isEditMode
- ? table =>
- this.onDatasourcePropChange('table_name', table)
- : undefined
- }
- readOnly={!this.state.isEditMode}
- />
+
+
+ this.onDatasourcePropChange('schema', schema)
+ : undefined
+ }
+ onDbChange={
+ this.state.isEditMode
+ ? database =>
+ this.onDatasourcePropChange(
+ 'database',
+ database,
+ )
+ : undefined
+ }
+ onTableChange={
+ this.state.isEditMode
+ ? table =>
+ this.onDatasourcePropChange('table_name', table)
+ : undefined
+ }
+ readOnly={!this.state.isEditMode}
+ />
+
}
description={t(
'The pointer to a physical table (or view). Keep in mind that the chart is ' +
diff --git a/superset-frontend/src/explore/components/controls/DatasourceControl/index.jsx b/superset-frontend/src/explore/components/controls/DatasourceControl/index.jsx
index 9278c29e79c09..3df55323d11d7 100644
--- a/superset-frontend/src/explore/components/controls/DatasourceControl/index.jsx
+++ b/superset-frontend/src/explore/components/controls/DatasourceControl/index.jsx
@@ -227,10 +227,7 @@ class DatasourceControl extends React.PureComponent {
)}
{extra?.warning_markdown && (
-
+
)}
= ({
)}
{parsedExtra?.warning_markdown && (
)}
{titleLink}
diff --git a/superset/datasets/api.py b/superset/datasets/api.py
index 8d8eb6efee875..261a7d749e40e 100644
--- a/superset/datasets/api.py
+++ b/superset/datasets/api.py
@@ -160,7 +160,7 @@ class DatasetRestApi(BaseSupersetModelRestApi):
"url",
"extra",
]
- show_columns = show_select_columns + ["columns.type_generic"]
+ show_columns = show_select_columns + ["columns.type_generic", "database.backend"]
add_model_schema = DatasetPostSchema()
edit_model_schema = DatasetPutSchema()
add_columns = ["database", "schema", "table_name", "owners"]
diff --git a/superset/views/core.py b/superset/views/core.py
index dc4a8a2da1c49..836bee4916b5c 100755
--- a/superset/views/core.py
+++ b/superset/views/core.py
@@ -1064,8 +1064,14 @@ def schemas( # pylint: disable=no-self-use
@event_logger.log_this
@expose("/tables////")
@expose("/tables/////")
- def tables( # pylint: disable=too-many-locals,no-self-use
- self, db_id: int, schema: str, substr: str, force_refresh: str = "false"
+ @expose("/tables/////")
+ def tables( # pylint: disable=too-many-locals,no-self-use,too-many-arguments
+ self,
+ db_id: int,
+ schema: str,
+ substr: str,
+ force_refresh: str = "false",
+ exact_match: str = "false",
) -> FlaskResponse:
"""Endpoint to fetch the list of tables for given database"""
# Guarantees database filtering by security access
@@ -1078,6 +1084,7 @@ def tables( # pylint: disable=too-many-locals,no-self-use
return json_error_response("Not found", 404)
force_refresh_parsed = force_refresh.lower() == "true"
+ exact_match_parsed = exact_match.lower() == "true"
schema_parsed = utils.parse_js_uri_path_item(schema, eval_undefined=True)
substr_parsed = utils.parse_js_uri_path_item(substr, eval_undefined=True)
@@ -1119,9 +1126,15 @@ def get_datasource_label(ds_name: utils.DatasourceName) -> str:
ds_name.table if schema_parsed else f"{ds_name.schema}.{ds_name.table}"
)
+ def is_match(src: str, target: utils.DatasourceName) -> bool:
+ target_label = get_datasource_label(target)
+ if exact_match_parsed:
+ return src == target_label
+ return src in target_label
+
if substr_parsed:
- tables = [tn for tn in tables if substr_parsed in get_datasource_label(tn)]
- views = [vn for vn in views if substr_parsed in get_datasource_label(vn)]
+ tables = [tn for tn in tables if is_match(substr_parsed, tn)]
+ views = [vn for vn in views if is_match(substr_parsed, vn)]
if not schema_parsed and database.default_schemas:
user_schemas = (
diff --git a/tests/integration_tests/datasets/api_tests.py b/tests/integration_tests/datasets/api_tests.py
index 385025e3835cc..c9701534b2664 100644
--- a/tests/integration_tests/datasets/api_tests.py
+++ b/tests/integration_tests/datasets/api_tests.py
@@ -222,6 +222,7 @@ def test_get_dataset_item(self):
Dataset API: Test get dataset item
"""
table = self.get_energy_usage_dataset()
+ main_db = get_main_database()
self.login(username="admin")
uri = f"api/v1/dataset/{table.id}"
rv = self.get_assert_metric(uri, "get")
@@ -229,7 +230,11 @@ def test_get_dataset_item(self):
response = json.loads(rv.data.decode("utf-8"))
expected_result = {
"cache_timeout": None,
- "database": {"database_name": "examples", "id": 1},
+ "database": {
+ "backend": main_db.backend,
+ "database_name": "examples",
+ "id": 1,
+ },
"default_endpoint": None,
"description": "Energy consumption",
"extra": None,
@@ -244,9 +249,10 @@ def test_get_dataset_item(self):
"table_name": "energy_usage",
"template_params": None,
}
- assert {
- k: v for k, v in response["result"].items() if k in expected_result
- } == expected_result
+ if response["result"]["database"]["backend"] not in ("presto", "hive"):
+ assert {
+ k: v for k, v in response["result"].items() if k in expected_result
+ } == expected_result
assert len(response["result"]["columns"]) == 3
assert len(response["result"]["metrics"]) == 2