This is an automated email from the ASF dual-hosted git repository.

justinpark pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/superset.git


The following commit(s) were added to refs/heads/master by this push:
     new 02478e5b95 feat(dashboard): Add metadata bar to the header (#27857)
02478e5b95 is described below

commit 02478e5b95c186332efdf1e5a7a65c7f8c61e980
Author: JUST.in DO IT <[email protected]>
AuthorDate: Fri May 10 10:28:57 2024 -0700

    feat(dashboard): Add metadata bar to the header (#27857)
---
 .../spec/fixtures/mockDashboardInfo.js             | 13 ++++++++++
 .../dashboard/components/Header/Header.test.tsx    | 25 +++++++++++++++++++
 .../src/dashboard/components/Header/index.jsx      | 29 ++++++++++++++++++++++
 superset/dashboards/schemas.py                     |  2 ++
 tests/integration_tests/dashboards/api_tests.py    |  2 ++
 5 files changed, 71 insertions(+)

diff --git a/superset-frontend/spec/fixtures/mockDashboardInfo.js 
b/superset-frontend/spec/fixtures/mockDashboardInfo.js
index 4fd599ea3b..2f747fd07b 100644
--- a/superset-frontend/spec/fixtures/mockDashboardInfo.js
+++ b/superset-frontend/spec/fixtures/mockDashboardInfo.js
@@ -31,6 +31,19 @@ export default {
       },
     ],
   },
+  changed_on_delta_humanized: '7 minutes ago',
+  changed_by: {
+    id: 3,
+    first_name: 'John',
+    last_name: 'Doe',
+  },
+  created_on_delta_humanized: '10 days ago',
+  created_by: {
+    id: 2,
+    first_name: 'Kay',
+    last_name: 'Mon',
+  },
+  owners: [{ first_name: 'John', last_name: 'Doe', id: 1 }],
   userId: 'mock_user_id',
   dash_edit_perm: true,
   dash_save_perm: true,
diff --git a/superset-frontend/src/dashboard/components/Header/Header.test.tsx 
b/superset-frontend/src/dashboard/components/Header/Header.test.tsx
index 2df5fa8318..9160be6ad8 100644
--- a/superset-frontend/src/dashboard/components/Header/Header.test.tsx
+++ b/superset-frontend/src/dashboard/components/Header/Header.test.tsx
@@ -22,6 +22,7 @@ import userEvent from '@testing-library/user-event';
 import fetchMock from 'fetch-mock';
 import { getExtensionsRegistry } from '@superset-ui/core';
 import setupExtensions from 'src/setup/setupExtensions';
+import getOwnerName from 'src/utils/getOwnerName';
 import { HeaderProps } from './types';
 import Header from '.';
 
@@ -44,6 +45,19 @@ const createProps = () => ({
         ],
       },
     },
+    changed_on_delta_humanized: '7 minutes ago',
+    changed_by: {
+      id: 3,
+      first_name: 'John',
+      last_name: 'Doe',
+    },
+    created_on_delta_humanized: '10 days ago',
+    created_by: {
+      id: 2,
+      first_name: 'Kay',
+      last_name: 'Mon',
+    },
+    owners: [{ first_name: 'John', last_name: 'Doe', id: 1 }],
   },
   user: {
     createdOn: '2021-04-27T18:12:38.952304',
@@ -187,6 +201,17 @@ test('should publish', () => {
   expect(mockedProps.savePublished).toHaveBeenCalledTimes(1);
 });
 
+test('should render metadata', () => {
+  const mockedProps = createProps();
+  setup(mockedProps);
+  expect(
+    screen.getByText(getOwnerName(mockedProps.dashboardInfo.created_by)),
+  ).toBeInTheDocument();
+  expect(
+    screen.getByText(mockedProps.dashboardInfo.changed_on_delta_humanized),
+  ).toBeInTheDocument();
+});
+
 test('should render the "Undo" action as disabled', () => {
   setup(editableProps);
   expect(screen.getByTestId('undo-action').parentElement).toBeDisabled();
diff --git a/superset-frontend/src/dashboard/components/Header/index.jsx 
b/superset-frontend/src/dashboard/components/Header/index.jsx
index f4a864b835..bce3e60d6f 100644
--- a/superset-frontend/src/dashboard/components/Header/index.jsx
+++ b/superset-frontend/src/dashboard/components/Header/index.jsx
@@ -46,6 +46,7 @@ import PublishedStatus from 
'src/dashboard/components/PublishedStatus';
 import UndoRedoKeyListeners from 
'src/dashboard/components/UndoRedoKeyListeners';
 import PropertiesModal from 'src/dashboard/components/PropertiesModal';
 import { chartPropShape } from 'src/dashboard/util/propShapes';
+import getOwnerName from 'src/utils/getOwnerName';
 import {
   UNDO_LIMIT,
   SAVE_TYPE_OVERWRITE,
@@ -55,6 +56,7 @@ import setPeriodicRunner, {
   stopPeriodicRender,
 } from 'src/dashboard/util/setPeriodicRunner';
 import { PageHeaderWithActions } from 'src/components/PageHeaderWithActions';
+import MetadataBar, { MetadataType } from 'src/components/MetadataBar';
 import DashboardEmbedModal from '../EmbeddedModal';
 import OverwriteConfirm from '../OverwriteConfirm';
 
@@ -435,6 +437,27 @@ class Header extends React.PureComponent {
     this.setState({ showingEmbedModal: false });
   };
 
+  getMetadataItems = () => {
+    const { dashboardInfo } = this.props;
+    return [
+      {
+        type: MetadataType.LastModified,
+        value: dashboardInfo.changed_on_delta_humanized,
+        modifiedBy:
+          getOwnerName(dashboardInfo.changed_by) || t('Not available'),
+      },
+      {
+        type: MetadataType.Owner,
+        createdBy: getOwnerName(dashboardInfo.created_by) || t('Not 
available'),
+        owners:
+          dashboardInfo.owners.length > 0
+            ? dashboardInfo.owners.map(getOwnerName)
+            : t('None'),
+        createdOn: dashboardInfo.created_on_delta_humanized,
+      },
+    ];
+  };
+
   render() {
     const {
       dashboardTitle,
@@ -535,6 +558,12 @@ class Header extends React.PureComponent {
                 visible={!editMode}
               />
             ),
+            !editMode && (
+              <MetadataBar
+                items={this.getMetadataItems()}
+                tooltipPlacement="bottom"
+              />
+            ),
           ]}
           rightPanelAdditionalItems={
             <div className="button-container">
diff --git a/superset/dashboards/schemas.py b/superset/dashboards/schemas.py
index 29b13ae7b8..6a6debe397 100644
--- a/superset/dashboards/schemas.py
+++ b/superset/dashboards/schemas.py
@@ -190,11 +190,13 @@ class DashboardGetResponseSchema(Schema):
     changed_by_name = fields.String()
     changed_by = fields.Nested(UserSchema(exclude=["username"]))
     changed_on = fields.DateTime()
+    created_by = fields.Nested(UserSchema(exclude=["username"]))
     charts = fields.List(fields.String(metadata={"description": 
charts_description}))
     owners = fields.List(fields.Nested(UserSchema(exclude=["username"])))
     roles = fields.List(fields.Nested(RolesSchema))
     tags = fields.Nested(TagSchema, many=True)
     changed_on_humanized = fields.String(data_key="changed_on_delta_humanized")
+    created_on_humanized = fields.String(data_key="created_on_delta_humanized")
     is_managed_externally = fields.Boolean(allow_none=True, dump_default=False)
 
     # pylint: disable=unused-argument
diff --git a/tests/integration_tests/dashboards/api_tests.py 
b/tests/integration_tests/dashboards/api_tests.py
index 949b655119..328fb5774e 100644
--- a/tests/integration_tests/dashboards/api_tests.py
+++ b/tests/integration_tests/dashboards/api_tests.py
@@ -423,11 +423,13 @@ class TestDashboardApi(ApiOwnersTestCaseMixin, 
InsertChartMixin, SupersetTestCas
         data = json.loads(rv.data.decode("utf-8"))
         self.assertIn("changed_on", data["result"])
         self.assertIn("changed_on_delta_humanized", data["result"])
+        self.assertIn("created_on_delta_humanized", data["result"])
         for key, value in data["result"].items():
             # We can't assert timestamp values
             if key not in (
                 "changed_on",
                 "changed_on_delta_humanized",
+                "created_on_delta_humanized",
             ):
                 self.assertEqual(value, expected_result[key])
         # rollback changes

Reply via email to