diff --git a/superset-frontend/cypress-base/cypress/integration/chart_list/filter.test.ts b/superset-frontend/cypress-base/cypress/integration/chart_list/filter.test.ts index b4b57c312..07f24916b 100644 --- a/superset-frontend/cypress-base/cypress/integration/chart_list/filter.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/chart_list/filter.test.ts @@ -18,7 +18,7 @@ */ import { CHART_LIST } from './chart_list.helper'; -describe('chart filters', () => { +describe('chart card view filters', () => { beforeEach(() => { cy.login(); cy.server(); @@ -36,26 +36,88 @@ describe('chart filters', () => { cy.get('.ant-card').should('not.exist'); }); + it('should filter by created by correctly', () => { + // filter by created by + cy.get('.Select__control').eq(1).click(); + cy.get('.Select__menu').contains('alpha user').click(); + cy.get('.ant-card').should('not.exist'); + cy.get('.Select__control').eq(1).click(); + cy.get('.Select__menu').contains('gamma user').click(); + cy.get('.ant-card').should('not.exist'); + }); + it('should filter by viz type correctly', () => { // filter by viz type - cy.get('.Select__control').eq(1).click(); + cy.get('.Select__control').eq(2).click(); cy.get('.Select__menu').contains('area').click({ timeout: 5000 }); cy.get('.ant-card').its('length').should('be.gt', 0); cy.get('.ant-card').contains("World's Pop Growth").should('exist'); - cy.get('.Select__control').eq(1).click(); - cy.get('.Select__control').eq(1).type('world_map{enter}'); + cy.get('.Select__control').eq(2).click(); + cy.get('.Select__control').eq(2).type('world_map{enter}'); cy.get('.ant-card').should('have.length', 1); cy.get('.ant-card').contains('% Rural').should('exist'); }); it('should filter by datasource correctly', () => { // filter by datasource - cy.get('.Select__control').eq(2).click(); + cy.get('.Select__control').eq(3).click(); cy.get('.Select__menu').contains('unicode_test').click(); cy.get('.ant-card').should('have.length', 1); cy.get('.ant-card').contains('Unicode Cloud').should('exist'); - cy.get('.Select__control').eq(2).click(); - cy.get('.Select__control').eq(2).type('energy_usage{enter}{enter}'); + cy.get('.Select__control').eq(3).click(); + cy.get('.Select__control').eq(3).type('energy_usage{enter}{enter}'); cy.get('.ant-card').its('length').should('be.gt', 0); }); }); + +describe('chart list view filters', () => { + beforeEach(() => { + cy.login(); + cy.server(); + cy.visit(CHART_LIST); + cy.get('[data-test="list-view"]').click(); + }); + + it('should filter by owners correctly', () => { + // filter by owners + cy.get('.Select__control').first().click(); + cy.get('.Select__menu').contains('alpha user').click(); + cy.get('.table-row').should('not.exist'); + cy.get('.Select__control').first().click(); + cy.get('.Select__menu').contains('gamma user').click(); + cy.get('.table-row').should('not.exist'); + }); + + it('should filter by created by correctly', () => { + // filter by created by + cy.get('.Select__control').eq(1).click(); + cy.get('.Select__menu').contains('alpha user').click(); + cy.get('.table-row').should('not.exist'); + cy.get('.Select__control').eq(1).click(); + cy.get('.Select__menu').contains('gamma user').click(); + cy.get('.table-row').should('not.exist'); + }); + + it('should filter by viz type correctly', () => { + // filter by viz type + cy.get('.Select__control').eq(2).click(); + cy.get('.Select__menu').contains('area').click({ timeout: 5000 }); + cy.get('.table-row').its('length').should('be.gt', 0); + cy.get('.table-row').contains("World's Pop Growth").should('exist'); + cy.get('.Select__control').eq(2).click(); + cy.get('.Select__control').eq(2).type('world_map{enter}'); + cy.get('.table-row').should('have.length', 1); + cy.get('.table-row').contains('% Rural').should('exist'); + }); + + it('should filter by datasource correctly', () => { + // filter by datasource + cy.get('.Select__control').eq(3).click(); + cy.get('.Select__menu').contains('unicode_test').click(); + cy.get('.table-row').should('have.length', 1); + cy.get('.table-row').contains('Unicode Cloud').should('exist'); + cy.get('.Select__control').eq(3).click(); + cy.get('.Select__control').eq(3).type('energy_usage{enter}{enter}'); + cy.get('.table-row').its('length').should('be.gt', 0); + }); +}); diff --git a/superset-frontend/cypress-base/cypress/integration/chart_list/list_view.test.ts b/superset-frontend/cypress-base/cypress/integration/chart_list/list_view.test.ts index 3f6815138..1aedf2a15 100644 --- a/superset-frontend/cypress-base/cypress/integration/chart_list/list_view.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/chart_list/list_view.test.ts @@ -26,7 +26,7 @@ describe('chart list view', () => { cy.get('[data-test="list-view"]').click(); }); - it.skip('should load rows', () => { + it('should load rows', () => { cy.get('.chart-list-view'); cy.get('table[role="table"]').should('be.visible'); @@ -38,7 +38,8 @@ describe('chart list view', () => { cy.get('th[role="columnheader"]:nth-child(4)').contains('Dataset'); cy.get('th[role="columnheader"]:nth-child(5)').contains('Modified By'); cy.get('th[role="columnheader"]:nth-child(6)').contains('Last Modified'); - cy.get('th[role="columnheader"]:nth-child(7)').contains('Actions'); + cy.get('th[role="columnheader"]:nth-child(7)').contains('Created By'); + cy.get('th[role="columnheader"]:nth-child(8)').contains('Actions'); cy.get('.table-row').should('have.length', 25); }); diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard_list/filter.test.ts b/superset-frontend/cypress-base/cypress/integration/dashboard_list/filter.test.ts index 60debb6fb..110560f9d 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard_list/filter.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/dashboard_list/filter.test.ts @@ -63,6 +63,7 @@ describe('dashboard filters list view', () => { cy.login(); cy.server(); cy.visit(DASHBOARD_LIST); + cy.get('[data-test="list-view"]').click(); }); it('should filter by owners correctly', () => { diff --git a/superset-frontend/src/views/CRUD/chart/ChartList.tsx b/superset-frontend/src/views/CRUD/chart/ChartList.tsx index 2cbc07ce7..3c29c379b 100644 --- a/superset-frontend/src/views/CRUD/chart/ChartList.tsx +++ b/superset-frontend/src/views/CRUD/chart/ChartList.tsx @@ -257,6 +257,17 @@ function ChartList(props: ChartListProps) { hidden: true, disableSortBy: true, }, + { + Cell: ({ + row: { + original: { created_by: createdBy }, + }, + }: any) => + createdBy ? `${createdBy.first_name} ${createdBy.last_name}` : '', + Header: t('Created By'), + accessor: 'created_by', + disableSortBy: true, + }, { Cell: ({ row: { original } }: any) => { const handleDelete = () => handleChartDelete(original); @@ -324,7 +335,27 @@ function ChartList(props: ChartListProps) { createErrorHandler(errMsg => props.addDangerToast( t( - 'An error occurred while fetching chart dataset values: %s', + 'An error occurred while fetching chart owners values: %s', + errMsg, + ), + ), + ), + ), + paginate: true, + }, + { + Header: t('Created By'), + id: 'created_by', + input: 'select', + operator: 'rel_o_m', + unfilteredLabel: 'All', + fetchSelects: createFetchRelated( + 'chart', + 'created_by', + createErrorHandler(errMsg => + props.addDangerToast( + t( + 'An error occurred while fetching chart created by values: %s', errMsg, ), ), diff --git a/superset/charts/api.py b/superset/charts/api.py index fc6527567..4999654c6 100644 --- a/superset/charts/api.py +++ b/superset/charts/api.py @@ -107,22 +107,25 @@ class ChartRestApi(BaseSupersetModelRestApi): "changed_by_url", "changed_on_delta_humanized", "changed_on_utc", + "created_by.first_name", + "created_by.id", + "created_by.last_name", "datasource_id", "datasource_name_text", "datasource_type", "datasource_url", "description", "id", + "owners.first_name", + "owners.id", + "owners.last_name", + "owners.username", "params", "slice_name", "table.default_endpoint", "table.table_name", "thumbnail_url", "url", - "owners.id", - "owners.username", - "owners.first_name", - "owners.last_name", "viz_type", ] list_select_columns = list_columns + ["changed_by_fk", "changed_on"] @@ -135,6 +138,7 @@ class ChartRestApi(BaseSupersetModelRestApi): "viz_type", ] search_columns = [ + "created_by", "datasource_id", "datasource_name", "datasource_type", @@ -172,10 +176,11 @@ class ChartRestApi(BaseSupersetModelRestApi): } related_field_filters = { - "owners": RelatedFieldFilter("first_name", FilterRelatedOwners) + "owners": RelatedFieldFilter("first_name", FilterRelatedOwners), + "created_by": RelatedFieldFilter("first_name", FilterRelatedOwners), } - allowed_rel_fields = {"owners"} + allowed_rel_fields = {"owners", "created_by"} def __init__(self) -> None: if is_feature_enabled("THUMBNAILS"): diff --git a/tests/charts/api_tests.py b/tests/charts/api_tests.py index 7127180fe..1d353be5d 100644 --- a/tests/charts/api_tests.py +++ b/tests/charts/api_tests.py @@ -48,6 +48,7 @@ class TestChartApi(SupersetTestCase, ApiOwnersTestCaseMixin): slice_name: str, owners: List[int], datasource_id: int, + created_by=None, datasource_type: str = "table", description: Optional[str] = None, viz_type: Optional[str] = None, @@ -62,15 +63,16 @@ class TestChartApi(SupersetTestCase, ApiOwnersTestCaseMixin): datasource_type, datasource_id, db.session ) slice = Slice( - slice_name=slice_name, + cache_timeout=cache_timeout, + created_by=created_by, datasource_id=datasource.id, datasource_name=datasource.name, datasource_type=datasource.type, - owners=obj_owners, description=description, - viz_type=viz_type, + owners=obj_owners, params=params, - cache_timeout=cache_timeout, + slice_name=slice_name, + viz_type=viz_type, ) db.session.add(slice) db.session.commit() @@ -93,12 +95,12 @@ class TestChartApi(SupersetTestCase, ApiOwnersTestCaseMixin): """ Chart API: Test delete bulk """ - admin_id = self.get_user("admin").id + admin = self.get_user("admin") chart_count = 4 chart_ids = list() for chart_name_index in range(chart_count): chart_ids.append( - self.insert_chart(f"title{chart_name_index}", [admin_id], 1).id + self.insert_chart(f"title{chart_name_index}", [admin.id], 1, admin).id ) self.login(username="admin") argument = chart_ids @@ -365,7 +367,7 @@ class TestChartApi(SupersetTestCase, ApiOwnersTestCaseMixin): admin = self.get_user("admin") gamma = self.get_user("gamma") - chart_id = self.insert_chart("title", [admin.id], 1).id + chart_id = self.insert_chart("title", [admin.id], 1, admin).id birth_names_table_id = SupersetTestCase.get_table_by_name("birth_names").id chart_data = { "slice_name": "title1_changed", @@ -384,6 +386,7 @@ class TestChartApi(SupersetTestCase, ApiOwnersTestCaseMixin): self.assertEqual(rv.status_code, 200) model = db.session.query(Slice).get(chart_id) related_dashboard = db.session.query(Dashboard).get(1) + self.assertEqual(model.created_by, admin) self.assertEqual(model.slice_name, "title1_changed") self.assertEqual(model.description, "description1") self.assertIn(admin, model.owners) @@ -902,7 +905,9 @@ class TestChartApi(SupersetTestCase, ApiOwnersTestCaseMixin): self.assertEqual(rv.status_code, 400) def test_chart_data_with_invalid_datasource(self): - """Chart data API: Test chart data query with invalid schema""" + """ + Chart data API: Test chart data query with invalid schema + """ self.login(username="admin") table = self.get_table_by_name("birth_names") payload = get_query_context(table.name, table.id, table.type) @@ -911,7 +916,9 @@ class TestChartApi(SupersetTestCase, ApiOwnersTestCaseMixin): self.assertEqual(rv.status_code, 400) def test_chart_data_with_invalid_enum_value(self): - """Chart data API: Test chart data query with invalid enum value""" + """ + Chart data API: Test chart data query with invalid enum value + """ self.login(username="admin") table = self.get_table_by_name("birth_names") payload = get_query_context(table.name, table.id, table.type)