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