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 f272c3804ae3d..60debb6fb40fd 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 @@ -18,7 +18,7 @@ */ import { DASHBOARD_LIST } from './dashboard_list.helper'; -describe('dashboard filters', () => { +describe('dashboard filters card view', () => { beforeEach(() => { cy.login(); cy.server(); @@ -36,14 +36,63 @@ describe('dashboard 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 published correctly', () => { // filter by published - cy.get('.Select__control').eq(1).click(); + cy.get('.Select__control').eq(2).click(); cy.get('.Select__menu').contains('Published').click(); cy.get('.ant-card').should('have.length', 2); cy.get('.ant-card').first().contains('USA Births Names').should('exist'); - cy.get('.Select__control').eq(1).click(); - cy.get('.Select__control').eq(1).type('unpub{enter}'); + cy.get('.Select__control').eq(2).click(); + cy.get('.Select__control').eq(2).type('unpub{enter}'); cy.get('.ant-card').should('have.length', 2); }); }); + +describe('dashboard filters list view', () => { + beforeEach(() => { + cy.login(); + cy.server(); + cy.visit(DASHBOARD_LIST); + }); + + 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 published correctly', () => { + // filter by published + cy.get('.Select__control').eq(2).click(); + cy.get('.Select__menu').contains('Published').click(); + cy.get('.table-row').should('have.length', 2); + cy.get('.table-row').first().contains('USA Births Names').should('exist'); + cy.get('.Select__control').eq(2).click(); + cy.get('.Select__control').eq(2).type('unpub{enter}'); + cy.get('.table-row').should('have.length', 2); + }); +}); diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard_list/list_view.test.ts b/superset-frontend/cypress-base/cypress/integration/dashboard_list/list_view.test.ts index 380a9cee5e493..5afe356de3afd 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard_list/list_view.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/dashboard_list/list_view.test.ts @@ -31,17 +31,22 @@ describe('dashboard list view', () => { cy.get('table[role="table"]').should('be.visible'); // check dashboard list view header cy.get('th[role="columnheader"]:nth-child(2)').contains('Title'); - cy.get('th[role="columnheader"]:nth-child(3)').contains('Owners'); - cy.get('th[role="columnheader"]:nth-child(4)').contains('Modified By'); - cy.get('th[role="columnheader"]:nth-child(5)').contains('Published'); - cy.get('th[role="columnheader"]:nth-child(6)').contains('Modified'); - cy.get('th[role="columnheader"]:nth-child(7)').contains('Actions'); + cy.get('th[role="columnheader"]:nth-child(3)').contains('Modified By'); + cy.get('th[role="columnheader"]:nth-child(4)').contains('Published'); + cy.get('th[role="columnheader"]:nth-child(5)').contains('Modified'); + cy.get('th[role="columnheader"]:nth-child(6)').contains('Created By'); + cy.get('th[role="columnheader"]:nth-child(7)').contains('Owners'); + cy.get('th[role="columnheader"]:nth-child(8)').contains('Actions'); cy.get('.table-row').should('have.length', 4); }); it('should sort correctly', () => { cy.get('th[role="columnheader"]:nth-child(2)').click(); cy.get('.table-row td:nth-child(2):eq(0)').contains('Tabbed Dashboard'); + cy.get('th[role="columnheader"]:nth-child(3)').click(); + cy.get('.table-row td:nth-child(2):eq(0)').contains('Tabbed Dashboard'); + cy.get('th[role="columnheader"]:nth-child(5)').click(); + cy.get('.table-row td:nth-child(2):eq(0)').contains("World Bank's Data"); cy.get('th[role="columnheader"]:nth-child(6)').click(); cy.get('.table-row td:nth-child(2):eq(0)').contains("World Bank's Data"); }); diff --git a/superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx b/superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx index 4efdd9ff87964..983e14c818c9c 100644 --- a/superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx +++ b/superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx @@ -55,6 +55,7 @@ interface Dashboard { url: string; thumbnail_url: string; owners: Owner[]; + created_by: object; } function DashboardList(props: DashboardListProps) { @@ -195,24 +196,7 @@ function DashboardList(props: DashboardListProps) { Header: t('Title'), accessor: 'dashboard_title', }, - { - Cell: ({ - row: { - original: { owners }, - }, - }: any) => ( - - `${firstName} ${lastName}`, - )} - display={2} - /> - ), - Header: t('Owners'), - accessor: 'owners', - disableSortBy: true, - }, + { Cell: ({ row: { @@ -252,6 +236,35 @@ function DashboardList(props: DashboardListProps) { 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: { owners }, + }, + }: any) => ( + + `${firstName} ${lastName}`, + )} + display={2} + /> + ), + Header: t('Owners'), + accessor: 'owners', + disableSortBy: true, + }, { Cell: ({ row: { original } }: any) => { const handleDelete = () => handleDashboardDelete(original); @@ -329,7 +342,27 @@ function DashboardList(props: DashboardListProps) { createErrorHandler(errMsg => props.addDangerToast( t( - 'An error occurred while fetching chart owner values: %s', + 'An error occurred while fetching dashboard owner values: %s', + errMsg, + ), + ), + ), + ), + paginate: true, + }, + { + Header: t('Created By'), + id: 'created_by', + input: 'select', + operator: 'rel_o_m', + unfilteredLabel: 'All', + fetchSelects: createFetchRelated( + 'dashboard', + 'created_by', + createErrorHandler(errMsg => + props.addDangerToast( + t( + 'An error occurred while fetching dashboard created by values: %s', errMsg, ), ), diff --git a/superset/dashboards/api.py b/superset/dashboards/api.py index d691316836b5c..c9c1fc3e24b45 100644 --- a/superset/dashboards/api.py +++ b/superset/dashboards/api.py @@ -113,6 +113,9 @@ class DashboardRestApi(BaseSupersetModelRestApi): "changed_by_url", "changed_on_utc", "changed_on_delta_humanized", + "created_by.first_name", + "created_by.id", + "created_by.last_name", "dashboard_title", "owners.id", "owners.username", @@ -121,10 +124,11 @@ class DashboardRestApi(BaseSupersetModelRestApi): ] list_select_columns = list_columns + ["changed_on", "changed_by_fk"] order_columns = [ - "dashboard_title", + "changed_by.first_name", "changed_on_delta_humanized", + "created_by.first_name", + "dashboard_title", "published", - "changed_by.first_name", ] add_columns = [ @@ -138,7 +142,7 @@ class DashboardRestApi(BaseSupersetModelRestApi): ] edit_columns = add_columns - search_columns = ("dashboard_title", "slug", "owners", "published") + search_columns = ("dashboard_title", "slug", "owners", "published", "created_by") search_filters = {"dashboard_title": [DashboardTitleOrSlugFilter]} base_order = ("changed_on", "desc") @@ -152,9 +156,10 @@ class DashboardRestApi(BaseSupersetModelRestApi): "owners": ("first_name", "asc"), } 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"} openapi_spec_tag = "Dashboards" apispec_parameter_schemas = { diff --git a/tests/dashboards/api_tests.py b/tests/dashboards/api_tests.py index 6645e802fc13d..17cffd411bff8 100644 --- a/tests/dashboards/api_tests.py +++ b/tests/dashboards/api_tests.py @@ -51,6 +51,7 @@ def insert_dashboard( dashboard_title: str, slug: Optional[str], owners: List[int], + created_by=None, slices: Optional[List[Slice]] = None, position_json: str = "", css: str = "", @@ -71,6 +72,7 @@ def insert_dashboard( json_metadata=json_metadata, slices=slices, published=published, + created_by=created_by, ) db.session.add(dashboard) db.session.commit() @@ -81,7 +83,7 @@ def test_get_dashboard(self): Dashboard API: Test get dashboard """ admin = self.get_user("admin") - dashboard = self.insert_dashboard("title", "slug1", [admin.id]) + dashboard = self.insert_dashboard("title", "slug1", [admin.id], admin) self.login(username="admin") uri = f"api/v1/dashboard/{dashboard.id}" rv = self.get_assert_metric(uri, "get") @@ -91,6 +93,7 @@ def test_get_dashboard(self): "changed_by_name": "", "changed_by_url": "", "charts": [], + "created_by": {"id": 1, "first_name": "admin", "last_name": "user",}, "id": dashboard.id, "css": "", "dashboard_title": "title",