mirror of
https://github.com/apache/superset.git
synced 2026-04-19 08:04:53 +00:00
feat(dashboard): Add metadata bar to the header (#27857)
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user