From ca4087764074f9dcee2bf44e875c508c8e151a86 Mon Sep 17 00:00:00 2001 From: Erik Ritter Date: Fri, 30 Oct 2020 11:28:01 -0700 Subject: [PATCH] feat: add certifications to tables (#11450) --- .../src/datasource/DatasourceEditor.jsx | 19 ++++++++++ .../views/CRUD/data/dataset/DatasetList.tsx | 38 +++++++++++++++++-- superset/connectors/sqla/models.py | 2 + superset/connectors/sqla/views.py | 11 +++++- superset/datasets/api.py | 3 ++ superset/datasets/schemas.py | 1 + tests/databases/commands_tests.py | 1 + tests/datasets/api_tests.py | 2 + tests/datasets/commands_tests.py | 2 + 9 files changed, 75 insertions(+), 4 deletions(-) diff --git a/superset-frontend/src/datasource/DatasourceEditor.jsx b/superset-frontend/src/datasource/DatasourceEditor.jsx index a1c9a122b..30fb17a2c 100644 --- a/superset-frontend/src/datasource/DatasourceEditor.jsx +++ b/superset-frontend/src/datasource/DatasourceEditor.jsx @@ -516,6 +516,25 @@ class DatasourceEditor extends React.PureComponent { control={} /> )} + {this.state.isSqla && ( + + } + /> + )} svg { + margin-right: ${({ theme }) => theme.gridUnit}px; + } +`; + type Dataset = { changed_by_name: string; changed_by_url: string; @@ -178,9 +188,31 @@ const DatasetList: FunctionComponent = ({ { Cell: ({ row: { - original: { table_name: datasetTitle, explore_url: exploreURL }, + original: { + extra, + table_name: datasetTitle, + explore_url: exploreURL, + }, }, - }: any) => {datasetTitle}, + }: any) => { + const titleLink = {datasetTitle}; + try { + const parsedExtra = JSON.parse(extra); + return parsedExtra?.certification ? ( + + + {titleLink} + + ) : ( + titleLink + ); + } catch { + return titleLink; + } + }, Header: t('Name'), accessor: 'table_name', }, diff --git a/superset/connectors/sqla/models.py b/superset/connectors/sqla/models.py index c7ab7986a..c4bf97942 100644 --- a/superset/connectors/sqla/models.py +++ b/superset/connectors/sqla/models.py @@ -492,6 +492,7 @@ class SqlaTable( # pylint: disable=too-many-public-methods,too-many-instance-at sql = Column(Text) is_sqllab_view = Column(Boolean, default=False) template_params = Column(Text) + extra = Column(Text) baselink = "tablemodelview" @@ -509,6 +510,7 @@ class SqlaTable( # pylint: disable=too-many-public-methods,too-many-instance-at "template_params", "filter_select_enabled", "fetch_values_predicate", + "extra", ] update_from_object_fields = [f for f in export_fields if not f == "database_id"] export_parent = "database" diff --git a/superset/connectors/sqla/views.py b/superset/connectors/sqla/views.py index 684366506..1b54669db 100644 --- a/superset/connectors/sqla/views.py +++ b/superset/connectors/sqla/views.py @@ -210,7 +210,7 @@ class SqlMetricInlineView( # pylint: disable=too-many-ancestors "extra": utils.markdown( "Extra data to specify metric metadata. Currently supports " 'certification data of the format: `{ "certification": "certified_by": ' - '"Taylor Swift", "details": "This metric is the source of truth." ' + '"Data Platform Team", "details": "This metric is the source of truth." ' "} }`. This should be modified from the edit datasource model in " "Explore to ensure correct formatting.", True, @@ -352,6 +352,7 @@ class TableModelView( # pylint: disable=too-many-ancestors "cache_timeout", "is_sqllab_view", "template_params", + "extra", ] base_filters = [["id", DatasourceFilter, lambda: []]] show_columns = edit_columns + ["perm", "slices"] @@ -412,6 +413,13 @@ class TableModelView( # pylint: disable=too-many-ancestors "A timeout of 0 indicates that the cache never expires. " "Note this defaults to the database timeout if undefined." ), + "extra": utils.markdown( + "Extra data to specify table metadata. Currently supports " + 'certification data of the format: `{ "certification": { "certified_by": ' + '"Data Platform Team", "details": "This table is the source of truth." ' + "} }`.", + True, + ), } label_columns = { "slices": _("Associated Charts"), @@ -432,6 +440,7 @@ class TableModelView( # pylint: disable=too-many-ancestors "description": _("Description"), "is_sqllab_view": _("SQL Lab View"), "template_params": _("Template parameters"), + "extra": _("Extra"), "modified": _("Modified"), } edit_form_extra_fields = { diff --git a/superset/datasets/api.py b/superset/datasets/api.py index 17ac8918b..fbc01a137 100644 --- a/superset/datasets/api.py +++ b/superset/datasets/api.py @@ -94,6 +94,7 @@ class DatasetRestApi(BaseSupersetModelRestApi): "changed_on_delta_humanized", "default_endpoint", "explore_url", + "extra", "kind", "owners.id", "owners.username", @@ -135,6 +136,7 @@ class DatasetRestApi(BaseSupersetModelRestApi): "metrics", "datasource_type", "url", + "extra", ] add_model_schema = DatasetPostSchema() edit_model_schema = DatasetPutSchema() @@ -155,6 +157,7 @@ class DatasetRestApi(BaseSupersetModelRestApi): "owners", "columns", "metrics", + "extra", ] openapi_spec_tag = "Datasets" related_field_filters = { diff --git a/superset/datasets/schemas.py b/superset/datasets/schemas.py index dd30dbd1c..70d965699 100644 --- a/superset/datasets/schemas.py +++ b/superset/datasets/schemas.py @@ -89,6 +89,7 @@ class DatasetPutSchema(Schema): owners = fields.List(fields.Integer()) columns = fields.List(fields.Nested(DatasetColumnsPutSchema)) metrics = fields.List(fields.Nested(DatasetMetricsPutSchema)) + extra = fields.String(allow_none=True) class DatasetRelatedChart(Schema): diff --git a/tests/databases/commands_tests.py b/tests/databases/commands_tests.py index 5a4131abf..0ad2ad204 100644 --- a/tests/databases/commands_tests.py +++ b/tests/databases/commands_tests.py @@ -86,6 +86,7 @@ class TestExportDatabasesCommand(SupersetTestCase): "template_params": None, "filter_select_enabled": True, "fetch_values_predicate": None, + "extra": None, "metrics": [ { "metric_name": "ratio", diff --git a/tests/datasets/api_tests.py b/tests/datasets/api_tests.py index d7d6bb353..757ba77f5 100644 --- a/tests/datasets/api_tests.py +++ b/tests/datasets/api_tests.py @@ -156,6 +156,7 @@ class TestDatasetApi(SupersetTestCase): "database", "default_endpoint", "explore_url", + "extra", "id", "kind", "owners", @@ -204,6 +205,7 @@ class TestDatasetApi(SupersetTestCase): "database": {"database_name": "examples", "id": 1}, "default_endpoint": None, "description": "Energy consumption", + "extra": None, "fetch_values_predicate": None, "filter_select_enabled": False, "is_sqllab_view": False, diff --git a/tests/datasets/commands_tests.py b/tests/datasets/commands_tests.py index c46b5e2a8..bd038a4af 100644 --- a/tests/datasets/commands_tests.py +++ b/tests/datasets/commands_tests.py @@ -97,6 +97,7 @@ class TestExportDatasetsCommand(SupersetTestCase): "database_uuid": str(example_db.uuid), "default_endpoint": None, "description": "Energy consumption", + "extra": None, "fetch_values_predicate": None, "filter_select_enabled": False, "main_dttm_col": None, @@ -177,6 +178,7 @@ class TestExportDatasetsCommand(SupersetTestCase): "template_params", "filter_select_enabled", "fetch_values_predicate", + "extra", "uuid", "metrics", "columns",