Skip to content

Commit

Permalink
feat(dashboard): Add metadata bar to the header (#27857)
Browse files Browse the repository at this point in the history
  • Loading branch information
justinpark committed May 10, 2024
1 parent 3a62eab commit 02478e5
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 0 deletions.
13 changes: 13 additions & 0 deletions superset-frontend/spec/fixtures/mockDashboardInfo.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
25 changes: 25 additions & 0 deletions superset-frontend/src/dashboard/components/Header/Header.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 '.';

Expand All @@ -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',
Expand Down Expand Up @@ -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();
Expand Down
29 changes: 29 additions & 0 deletions superset-frontend/src/dashboard/components/Header/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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';

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -535,6 +558,12 @@ class Header extends React.PureComponent {
visible={!editMode}
/>
),
!editMode && (
<MetadataBar
items={this.getMetadataItems()}
tooltipPlacement="bottom"
/>
),
]}
rightPanelAdditionalItems={
<div className="button-container">
Expand Down
2 changes: 2 additions & 0 deletions superset/dashboards/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions tests/integration_tests/dashboards/api_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -423,11 +423,13 @@ def test_get_dashboard(self):
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
Expand Down

0 comments on commit 02478e5

Please sign in to comment.