Skip to content

Commit

Permalink
feat(dashboard): Add metadata bar to the header
Browse files Browse the repository at this point in the history
  • Loading branch information
justinpark committed Apr 2, 2024
1 parent 38eecfc commit adf75f0
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 0 deletions.
16 changes: 16 additions & 0 deletions superset-frontend/src/dashboard/components/Header/Header.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ const createProps = () => ({
],
},
},
changed_on_delta_humanized: '7 minutes ago',
changed_by_name: 'John Doe',
created_on_delta_humanized: '10 days ago',
created_by_name: 'Kay Mon',
owners_by_name: ['John Doe'],
},
user: {
createdOn: '2021-04-27T18:12:38.952304',
Expand Down Expand Up @@ -187,6 +192,17 @@ test('should publish', () => {
expect(mockedProps.savePublished).toHaveBeenCalledTimes(1);
});

test('should render metadata', () => {
const mockedProps = createProps();
setup(mockedProps);
expect(
screen.getByText(mockedProps.dashboardInfo.created_by_name),
).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
27 changes: 27 additions & 0 deletions superset-frontend/src/dashboard/components/Header/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,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 +436,26 @@ 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: dashboardInfo.changed_by_name || t('Not available'),
},
{
type: MetadataType.Owner,
createdBy: dashboardInfo.created_by_name || t('Not available'),
owners:
dashboardInfo.owners_by_name.length > 0
? dashboardInfo.owners_by_name
: t('None'),
createdOn: dashboardInfo.created_on_delta_humanized,
},
];
};

render() {
const {
dashboardTitle,
Expand Down Expand Up @@ -535,6 +556,12 @@ class Header extends React.PureComponent {
visible={!editMode}
/>
),
!editMode && (
<MetadataBar
items={this.getMetadataItems()}
tooltipPlacement="bottom"
/>
),
]}
rightPanelAdditionalItems={
<div className="button-container">
Expand Down
1 change: 1 addition & 0 deletions superset/dashboards/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ def ensure_thumbnails_enabled(self) -> Optional[Response]:
"created_by.first_name",
"created_by.id",
"created_by.last_name",
"created_by_name",
"dashboard_title",
"owners.id",
"owners.first_name",
Expand Down
3 changes: 3 additions & 0 deletions superset/dashboards/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,13 +187,16 @@ class DashboardGetResponseSchema(Schema):
certification_details = fields.String(
metadata={"description": certification_details_description}
)
created_by_name = fields.String()
changed_by_name = fields.String()
changed_by = fields.Nested(UserSchema(exclude=["username"]))
changed_on = fields.DateTime()
charts = fields.List(fields.String(metadata={"description": charts_description}))
owners = fields.List(fields.Nested(UserSchema(exclude=["username"])))
owners_by_name = fields.List(fields.String())
roles = fields.List(fields.Nested(RolesSchema))
tags = fields.Nested(TagSchema, many=True)
created_on_humanized = fields.String(data_key="created_on_delta_humanized")
changed_on_humanized = fields.String(data_key="changed_on_delta_humanized")
is_managed_externally = fields.Boolean(allow_none=True, dump_default=False)

Expand Down
10 changes: 10 additions & 0 deletions superset/models/dashboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,16 @@ def changed_by_name(self) -> str:
return ""
return str(self.changed_by)

@property
def created_by_name(self) -> str:
if not self.created_by:
return ""
return str(self.created_by)

@property
def owners_by_name(self) -> list[str]:
return [owner.get_full_name() for owner in self.owners]

@property
def data(self) -> dict[str, Any]:
positions = self.position_json
Expand Down
4 changes: 4 additions & 0 deletions tests/integration_tests/dashboards/api_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,7 @@ def test_get_dashboard(self):
"first_name": "admin",
"last_name": "user",
},
"created_by_name": "admin user",
"id": dashboard.id,
"css": "",
"dashboard_title": "title",
Expand All @@ -405,6 +406,7 @@ def test_get_dashboard(self):
"last_name": "user",
}
],
"owners_by_name": ["admin user"],
"roles": [],
"position_json": "",
"published": False,
Expand All @@ -417,11 +419,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 adf75f0

Please sign in to comment.