mirror of
https://github.com/apache/superset.git
synced 2026-04-19 16:14:52 +00:00
feat: Certify Charts and Dashboards (#17335)
* Certify charts * Format * Certify dashboards * Format * Refactor card certification * Clear details when certified by empty * Show certification in detail page * Add RTL tests * Test charts api * Enhance integration tests * Lint * Fix dashboards count * Format * Handle empty value * Handle empty slice * Downgrade migration * Indent * Use alter * Fix revision * Fix revision
This commit is contained in:
@@ -80,7 +80,7 @@ class TestChartApi(SupersetTestCase, ApiOwnersTestCaseMixin, InsertChartMixin):
|
||||
charts = []
|
||||
admin = self.get_user("admin")
|
||||
for cx in range(CHARTS_FIXTURE_COUNT - 1):
|
||||
charts.append(self.insert_chart(f"name{cx}", [admin.id], 1))
|
||||
charts.append(self.insert_chart(f"name{cx}", [admin.id], 1,))
|
||||
fav_charts = []
|
||||
for cx in range(round(CHARTS_FIXTURE_COUNT / 2)):
|
||||
fav_star = FavStar(
|
||||
@@ -98,6 +98,29 @@ class TestChartApi(SupersetTestCase, ApiOwnersTestCaseMixin, InsertChartMixin):
|
||||
db.session.delete(fav_chart)
|
||||
db.session.commit()
|
||||
|
||||
@pytest.fixture()
|
||||
def create_certified_charts(self):
|
||||
with self.create_app().app_context():
|
||||
certified_charts = []
|
||||
admin = self.get_user("admin")
|
||||
for cx in range(CHARTS_FIXTURE_COUNT):
|
||||
certified_charts.append(
|
||||
self.insert_chart(
|
||||
f"certified{cx}",
|
||||
[admin.id],
|
||||
1,
|
||||
certified_by="John Doe",
|
||||
certification_details="Sample certification",
|
||||
)
|
||||
)
|
||||
|
||||
yield certified_charts
|
||||
|
||||
# rollback changes
|
||||
for chart in certified_charts:
|
||||
db.session.delete(chart)
|
||||
db.session.commit()
|
||||
|
||||
@pytest.fixture()
|
||||
def create_chart_with_report(self):
|
||||
with self.create_app().app_context():
|
||||
@@ -420,6 +443,8 @@ class TestChartApi(SupersetTestCase, ApiOwnersTestCaseMixin, InsertChartMixin):
|
||||
"datasource_id": 1,
|
||||
"datasource_type": "table",
|
||||
"dashboards": dashboards_ids,
|
||||
"certified_by": "John Doe",
|
||||
"certification_details": "Sample certification",
|
||||
}
|
||||
self.login(username="admin")
|
||||
uri = f"api/v1/chart/"
|
||||
@@ -535,6 +560,8 @@ class TestChartApi(SupersetTestCase, ApiOwnersTestCaseMixin, InsertChartMixin):
|
||||
"datasource_id": birth_names_table_id,
|
||||
"datasource_type": "table",
|
||||
"dashboards": [dash_id],
|
||||
"certified_by": "Mario Rossi",
|
||||
"certification_details": "Edited certification",
|
||||
}
|
||||
self.login(username="admin")
|
||||
uri = f"api/v1/chart/{chart_id}"
|
||||
@@ -553,6 +580,8 @@ class TestChartApi(SupersetTestCase, ApiOwnersTestCaseMixin, InsertChartMixin):
|
||||
self.assertEqual(model.datasource_id, birth_names_table_id)
|
||||
self.assertEqual(model.datasource_type, "table")
|
||||
self.assertEqual(model.datasource_name, full_table_name)
|
||||
self.assertEqual(model.certified_by, "Mario Rossi")
|
||||
self.assertEqual(model.certification_details, "Edited certification")
|
||||
self.assertIn(model.id, [slice.id for slice in related_dashboard.slices])
|
||||
db.session.delete(model)
|
||||
db.session.commit()
|
||||
@@ -703,6 +732,8 @@ class TestChartApi(SupersetTestCase, ApiOwnersTestCaseMixin, InsertChartMixin):
|
||||
self.assertEqual(rv.status_code, 200)
|
||||
expected_result = {
|
||||
"cache_timeout": None,
|
||||
"certified_by": None,
|
||||
"certification_details": None,
|
||||
"dashboards": [],
|
||||
"description": None,
|
||||
"owners": [
|
||||
@@ -897,6 +928,36 @@ class TestChartApi(SupersetTestCase, ApiOwnersTestCaseMixin, InsertChartMixin):
|
||||
data = json.loads(rv.data.decode("utf-8"))
|
||||
self.assertEqual(data["count"], 8)
|
||||
|
||||
@pytest.mark.usefixtures("create_certified_charts")
|
||||
def test_gets_certified_charts_filter(self):
|
||||
arguments = {
|
||||
"filters": [{"col": "id", "opr": "chart_is_certified", "value": True,}],
|
||||
"keys": ["none"],
|
||||
"columns": ["slice_name"],
|
||||
}
|
||||
self.login(username="admin")
|
||||
|
||||
uri = f"api/v1/chart/?q={prison.dumps(arguments)}"
|
||||
rv = self.get_assert_metric(uri, "get_list")
|
||||
self.assertEqual(rv.status_code, 200)
|
||||
data = json.loads(rv.data.decode("utf-8"))
|
||||
self.assertEqual(data["count"], CHARTS_FIXTURE_COUNT)
|
||||
|
||||
@pytest.mark.usefixtures("create_charts")
|
||||
def test_gets_not_certified_charts_filter(self):
|
||||
arguments = {
|
||||
"filters": [{"col": "id", "opr": "chart_is_certified", "value": False,}],
|
||||
"keys": ["none"],
|
||||
"columns": ["slice_name"],
|
||||
}
|
||||
self.login(username="admin")
|
||||
|
||||
uri = f"api/v1/chart/?q={prison.dumps(arguments)}"
|
||||
rv = self.get_assert_metric(uri, "get_list")
|
||||
self.assertEqual(rv.status_code, 200)
|
||||
data = json.loads(rv.data.decode("utf-8"))
|
||||
self.assertEqual(data["count"], 17)
|
||||
|
||||
@pytest.mark.usefixtures("load_energy_charts")
|
||||
def test_user_gets_none_filtered_energy_slices(self):
|
||||
# test filtering on datasource_name
|
||||
|
||||
@@ -86,6 +86,8 @@ class TestDashboardApi(SupersetTestCase, ApiOwnersTestCaseMixin, InsertChartMixi
|
||||
css: str = "",
|
||||
json_metadata: str = "",
|
||||
published: bool = False,
|
||||
certified_by: Optional[str] = None,
|
||||
certification_details: Optional[str] = None,
|
||||
) -> Dashboard:
|
||||
obj_owners = list()
|
||||
obj_roles = list()
|
||||
@@ -107,6 +109,8 @@ class TestDashboardApi(SupersetTestCase, ApiOwnersTestCaseMixin, InsertChartMixi
|
||||
slices=slices,
|
||||
published=published,
|
||||
created_by=created_by,
|
||||
certified_by=certified_by,
|
||||
certification_details=certification_details,
|
||||
)
|
||||
db.session.add(dashboard)
|
||||
db.session.commit()
|
||||
@@ -125,6 +129,8 @@ class TestDashboardApi(SupersetTestCase, ApiOwnersTestCaseMixin, InsertChartMixi
|
||||
f"slug{cx}",
|
||||
[admin.id],
|
||||
slices=charts if cx < half_dash_count else [],
|
||||
certified_by="John Doe",
|
||||
certification_details="Sample certification",
|
||||
)
|
||||
if cx < half_dash_count:
|
||||
chart = self.insert_chart(f"slice{cx}", [admin.id], 1, params="{}")
|
||||
@@ -315,6 +321,8 @@ class TestDashboardApi(SupersetTestCase, ApiOwnersTestCaseMixin, InsertChartMixi
|
||||
rv = self.get_assert_metric(uri, "get")
|
||||
self.assertEqual(rv.status_code, 200)
|
||||
expected_result = {
|
||||
"certified_by": None,
|
||||
"certification_details": None,
|
||||
"changed_by": None,
|
||||
"changed_by_name": "",
|
||||
"changed_by_url": "",
|
||||
@@ -611,6 +619,38 @@ class TestDashboardApi(SupersetTestCase, ApiOwnersTestCaseMixin, InsertChartMixi
|
||||
expected_model.dashboard_title == data["result"][i]["dashboard_title"]
|
||||
)
|
||||
|
||||
@pytest.mark.usefixtures("create_dashboards")
|
||||
def test_gets_certified_dashboards_filter(self):
|
||||
arguments = {
|
||||
"filters": [{"col": "id", "opr": "dashboard_is_certified", "value": True,}],
|
||||
"keys": ["none"],
|
||||
"columns": ["dashboard_title"],
|
||||
}
|
||||
self.login(username="admin")
|
||||
|
||||
uri = f"api/v1/dashboard/?q={prison.dumps(arguments)}"
|
||||
rv = self.get_assert_metric(uri, "get_list")
|
||||
self.assertEqual(rv.status_code, 200)
|
||||
data = json.loads(rv.data.decode("utf-8"))
|
||||
self.assertEqual(data["count"], DASHBOARDS_FIXTURE_COUNT)
|
||||
|
||||
@pytest.mark.usefixtures("create_dashboards")
|
||||
def test_gets_not_certified_dashboards_filter(self):
|
||||
arguments = {
|
||||
"filters": [
|
||||
{"col": "id", "opr": "dashboard_is_certified", "value": False,}
|
||||
],
|
||||
"keys": ["none"],
|
||||
"columns": ["dashboard_title"],
|
||||
}
|
||||
self.login(username="admin")
|
||||
|
||||
uri = f"api/v1/dashboard/?q={prison.dumps(arguments)}"
|
||||
rv = self.get_assert_metric(uri, "get_list")
|
||||
self.assertEqual(rv.status_code, 200)
|
||||
data = json.loads(rv.data.decode("utf-8"))
|
||||
self.assertEqual(data["count"], 6)
|
||||
|
||||
def create_dashboard_import(self):
|
||||
buf = BytesIO()
|
||||
with ZipFile(buf, "w") as bundle:
|
||||
|
||||
@@ -36,6 +36,8 @@ class InsertChartMixin:
|
||||
viz_type: Optional[str] = None,
|
||||
params: Optional[str] = None,
|
||||
cache_timeout: Optional[int] = None,
|
||||
certified_by: Optional[str] = None,
|
||||
certification_details: Optional[str] = None,
|
||||
) -> Slice:
|
||||
obj_owners = list()
|
||||
for owner in owners:
|
||||
@@ -46,6 +48,8 @@ class InsertChartMixin:
|
||||
)
|
||||
slice = Slice(
|
||||
cache_timeout=cache_timeout,
|
||||
certified_by=certified_by,
|
||||
certification_details=certification_details,
|
||||
created_by=created_by,
|
||||
datasource_id=datasource.id,
|
||||
datasource_name=datasource.name,
|
||||
|
||||
Reference in New Issue
Block a user