diff --git a/superset-frontend/spec/javascripts/components/TableSelector_spec.jsx b/superset-frontend/spec/javascripts/components/TableSelector_spec.jsx index 96b1d2e343a..320e4f52803 100644 --- a/superset-frontend/spec/javascripts/components/TableSelector_spec.jsx +++ b/superset-frontend/spec/javascripts/components/TableSelector_spec.jsx @@ -60,11 +60,12 @@ const schemaOptions = { }; const selectedSchema = { label: 'main', title: 'main', value: 'main' }; const selectedTable = { + extra: null, label: 'birth_names', schema: 'main', title: 'birth_names', - value: 'birth_names', type: undefined, + value: 'birth_names', }; async function mountAndWait(props = mockedProps) { diff --git a/superset-frontend/src/components/CertifiedIconWithTooltip.tsx b/superset-frontend/src/components/CertifiedIconWithTooltip.tsx index e96b35f5140..e4132dc828b 100644 --- a/superset-frontend/src/components/CertifiedIconWithTooltip.tsx +++ b/superset-frontend/src/components/CertifiedIconWithTooltip.tsx @@ -24,11 +24,13 @@ import TooltipWrapper from 'src/components/TooltipWrapper'; interface CertifiedIconWithTooltipProps { certifiedBy?: string; details?: string; + size?: number; } function CertifiedIconWithTooltip({ certifiedBy, details, + size = 24, }: CertifiedIconWithTooltipProps) { return ( } > - + ); } diff --git a/superset-frontend/src/components/TableSelector.tsx b/superset-frontend/src/components/TableSelector.tsx index 4c59359091f..c5c3a52af21 100644 --- a/superset-frontend/src/components/TableSelector.tsx +++ b/superset-frontend/src/components/TableSelector.tsx @@ -29,6 +29,7 @@ import FormLabel from 'src/components/FormLabel'; import DatabaseSelector from './DatabaseSelector'; import RefreshLabel from './RefreshLabel'; +import CertifiedIconWithTooltip from './CertifiedIconWithTooltip'; const FieldTitle = styled.p` color: ${({ theme }) => theme.colors.secondary.light2}; @@ -65,7 +66,14 @@ const TableSelectorWrapper = styled.div` `; const TableLabel = styled.span` + align-items: center; + display: flex; white-space: nowrap; + + > svg, + > small { + margin-right: ${({ theme }) => theme.gridUnit}px; + } `; interface TableSelectorProps { @@ -146,6 +154,7 @@ const TableSelector: FunctionComponent = ({ label: o.label, title: o.title, type: o.type, + extra: o?.extra, })); setTableLoading(false); setTableOptions(options); @@ -244,13 +253,16 @@ const TableSelector: FunctionComponent = ({ function renderTableOption(option: any) { return ( - - - - - + {option.extra?.certification && ( + + )} + + + {option.label} ); @@ -308,6 +320,7 @@ const TableSelector: FunctionComponent = ({ // @ts-ignore value={currentTableName} optionRenderer={renderTableOption} + valueRenderer={renderTableOption} /> ); } else if (formMode) { diff --git a/superset/connectors/sqla/models.py b/superset/connectors/sqla/models.py index c75c081cb55..e19c1b93945 100644 --- a/superset/connectors/sqla/models.py +++ b/superset/connectors/sqla/models.py @@ -700,6 +700,13 @@ class SqlaTable( # pylint: disable=too-many-public-methods,too-many-instance-at data_["is_sqllab_view"] = self.is_sqllab_view return data_ + @property + def extra_dict(self) -> Dict[str, Any]: + try: + return json.loads(self.extra) + except (TypeError, json.JSONDecodeError): + return {} + def values_for_column(self, column_name: str, limit: int = 10000) -> List[Any]: """Runs query against sqla to retrieve some sample values for the given column. diff --git a/superset/views/core.py b/superset/views/core.py index e12e50c248c..e5730e5f99f 100755 --- a/superset/views/core.py +++ b/superset/views/core.py @@ -981,6 +981,8 @@ class Superset(BaseSupersetView): # pylint: disable=too-many-public-methods max_tables = max_items * len(tables) // total_items max_views = max_items * len(views) // total_items + dataset_tables = {table.name: table for table in database.tables} + table_options = [ { "value": tn.table, @@ -988,6 +990,9 @@ class Superset(BaseSupersetView): # pylint: disable=too-many-public-methods "label": get_datasource_label(tn), "title": get_datasource_label(tn), "type": "table", + "extra": dataset_tables[f"{tn.schema}.{tn.table}"].extra_dict + if (f"{tn.schema}.{tn.table}" in dataset_tables) + else None, } for tn in tables[:max_tables] ] diff --git a/tests/core_tests.py b/tests/core_tests.py index 87b698f4d80..94f3c29a60f 100644 --- a/tests/core_tests.py +++ b/tests/core_tests.py @@ -155,7 +155,7 @@ class TestCore(SupersetTestCase): response = json.loads(rv.data.decode("utf-8")) self.assertEqual(rv.status_code, 200) - expeted_response = { + expected_response = { "options": [ { "label": "ab_role", @@ -163,11 +163,12 @@ class TestCore(SupersetTestCase): "title": "ab_role", "type": "table", "value": "ab_role", + "extra": None, } ], "tableLength": 1, } - self.assertEqual(response, expeted_response) + self.assertEqual(response, expected_response) def test_get_superset_tables_not_found(self): self.login(username="admin") @@ -862,7 +863,7 @@ class TestCore(SupersetTestCase): def test_get_select_star_not_allowed(self): """ - Database API: Test get select star not allowed + Database API: Test get select star not allowed """ self.login(username="gamma") example_db = utils.get_example_database()