mirror of
https://github.com/apache/superset.git
synced 2026-05-11 19:05:24 +00:00
feat: Adds the MetadataBar to the Explore header (#21560)
This commit is contained in:
committed by
GitHub
parent
5ea9249059
commit
0dda5fe1cf
@@ -36,7 +36,7 @@ window.featureFlags = {
|
||||
[FeatureFlag.EMBEDDABLE_CHARTS]: true,
|
||||
};
|
||||
|
||||
const createProps = () => ({
|
||||
const createProps = (additionalProps = {}) => ({
|
||||
chart: {
|
||||
id: 1,
|
||||
latestQueryFormData: {
|
||||
@@ -63,7 +63,7 @@ const createProps = () => ({
|
||||
changed_on: '2021-03-19T16:30:56.750230',
|
||||
changed_on_humanized: '7 days ago',
|
||||
datasource: 'FCC 2018 Survey',
|
||||
description: null,
|
||||
description: 'Simple description',
|
||||
description_markeddown: '',
|
||||
edit_url: '/chart/edit/318',
|
||||
form_data: {
|
||||
@@ -106,10 +106,19 @@ const createProps = () => ({
|
||||
user: {
|
||||
userId: 1,
|
||||
},
|
||||
metadata: {
|
||||
created_on_humanized: 'a week ago',
|
||||
changed_on_humanized: '2 days ago',
|
||||
owners: ['John Doe'],
|
||||
created_by: 'John Doe',
|
||||
changed_by: 'John Doe',
|
||||
dashboards: [{ id: 1, dashboard_title: 'Test' }],
|
||||
},
|
||||
onSaveChart: jest.fn(),
|
||||
canOverwrite: false,
|
||||
canDownload: false,
|
||||
isStarred: false,
|
||||
...additionalProps,
|
||||
});
|
||||
|
||||
fetchMock.post(
|
||||
@@ -147,6 +156,27 @@ test('Cancelling changes to the properties should reset previous properties', as
|
||||
expect(await screen.findByDisplayValue(prevChartName)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('renders the metadata bar when saved', async () => {
|
||||
const props = createProps({ showTitlePanelItems: true });
|
||||
render(<ExploreHeader {...props} />, { useRedux: true });
|
||||
expect(
|
||||
await screen.findByText('Added to 1 dashboard(s)'),
|
||||
).toBeInTheDocument();
|
||||
expect(await screen.findByText('Simple description')).toBeInTheDocument();
|
||||
expect(await screen.findByText('John Doe')).toBeInTheDocument();
|
||||
expect(await screen.findByText('2 days ago')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('does not render the metadata bar when not saved', async () => {
|
||||
const props = createProps({ showTitlePanelItems: true, slice: null });
|
||||
render(<ExploreHeader {...props} />, { useRedux: true });
|
||||
await waitFor(() =>
|
||||
expect(
|
||||
screen.queryByText('Added to 1 dashboard(s)'),
|
||||
).not.toBeInTheDocument(),
|
||||
);
|
||||
});
|
||||
|
||||
test('Save chart', async () => {
|
||||
const props = createProps();
|
||||
render(<ExploreHeader {...props} />, { useRedux: true });
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import React, { useEffect, useMemo, useState } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import PropTypes from 'prop-types';
|
||||
@@ -24,6 +24,7 @@ import { Tooltip } from 'src/components/Tooltip';
|
||||
import {
|
||||
CategoricalColorNamespace,
|
||||
css,
|
||||
logging,
|
||||
SupersetClient,
|
||||
t,
|
||||
} from '@superset-ui/core';
|
||||
@@ -35,6 +36,7 @@ import Icons from 'src/components/Icons';
|
||||
import PropertiesModal from 'src/explore/components/PropertiesModal';
|
||||
import { sliceUpdated } from 'src/explore/actions/exploreActions';
|
||||
import { PageHeaderWithActions } from 'src/components/PageHeaderWithActions';
|
||||
import MetadataBar, { MetadataType } from 'src/components/MetadataBar';
|
||||
import { useExploreAdditionalActionsMenu } from '../useExploreAdditionalActionsMenu';
|
||||
|
||||
const propTypes = {
|
||||
@@ -60,6 +62,15 @@ const saveButtonStyles = theme => css`
|
||||
}
|
||||
`;
|
||||
|
||||
const additionalItemsStyles = theme => css`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-left: ${theme.gridUnit}px;
|
||||
& > span {
|
||||
margin-right: ${theme.gridUnit * 3}px;
|
||||
}
|
||||
`;
|
||||
|
||||
export const ExploreChartHeader = ({
|
||||
dashboardId,
|
||||
slice,
|
||||
@@ -75,51 +86,51 @@ export const ExploreChartHeader = ({
|
||||
sliceName,
|
||||
onSaveChart,
|
||||
saveDisabled,
|
||||
metadata,
|
||||
}) => {
|
||||
const { latestQueryFormData, sliceFormData } = chart;
|
||||
const [isPropertiesModalOpen, setIsPropertiesModalOpen] = useState(false);
|
||||
|
||||
const fetchChartDashboardData = async () => {
|
||||
await SupersetClient.get({
|
||||
endpoint: `/api/v1/chart/${slice.slice_id}`,
|
||||
})
|
||||
.then(res => {
|
||||
const response = res?.json?.result;
|
||||
if (response && response.dashboards && response.dashboards.length) {
|
||||
const { dashboards } = response;
|
||||
const dashboard =
|
||||
dashboardId &&
|
||||
dashboards.length &&
|
||||
dashboards.find(d => d.id === dashboardId);
|
||||
const updateCategoricalNamespace = async () => {
|
||||
const { dashboards } = metadata || {};
|
||||
const dashboard =
|
||||
dashboardId && dashboards && dashboards.find(d => d.id === dashboardId);
|
||||
|
||||
if (dashboard && dashboard.json_metadata) {
|
||||
// setting the chart to use the dashboard custom label colors if any
|
||||
const metadata = JSON.parse(dashboard.json_metadata);
|
||||
const sharedLabelColors = metadata.shared_label_colors || {};
|
||||
const customLabelColors = metadata.label_colors || {};
|
||||
const mergedLabelColors = {
|
||||
...sharedLabelColors,
|
||||
...customLabelColors,
|
||||
};
|
||||
if (dashboard) {
|
||||
try {
|
||||
// Dashboards from metadata don't contain the json_metadata field
|
||||
// to avoid unnecessary payload. Here we query for the dashboard json_metadata.
|
||||
const response = await SupersetClient.get({
|
||||
endpoint: `/api/v1/dashboard/${dashboard.id}`,
|
||||
});
|
||||
const result = response?.json?.result;
|
||||
|
||||
const categoricalNamespace =
|
||||
CategoricalColorNamespace.getNamespace();
|
||||
// setting the chart to use the dashboard custom label colors if any
|
||||
const metadata = JSON.parse(result.json_metadata);
|
||||
const sharedLabelColors = metadata.shared_label_colors || {};
|
||||
const customLabelColors = metadata.label_colors || {};
|
||||
const mergedLabelColors = {
|
||||
...sharedLabelColors,
|
||||
...customLabelColors,
|
||||
};
|
||||
|
||||
Object.keys(mergedLabelColors).forEach(label => {
|
||||
categoricalNamespace.setColor(
|
||||
label,
|
||||
mergedLabelColors[label],
|
||||
metadata.color_scheme,
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(() => {});
|
||||
const categoricalNamespace = CategoricalColorNamespace.getNamespace();
|
||||
|
||||
Object.keys(mergedLabelColors).forEach(label => {
|
||||
categoricalNamespace.setColor(
|
||||
label,
|
||||
mergedLabelColors[label],
|
||||
metadata.color_scheme,
|
||||
);
|
||||
});
|
||||
} catch (error) {
|
||||
logging.info(t('Unable to retrieve dashboard colors'));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (dashboardId) fetchChartDashboardData();
|
||||
if (dashboardId) updateCategoricalNamespace();
|
||||
}, []);
|
||||
|
||||
const openPropertiesModal = () => {
|
||||
@@ -140,6 +151,38 @@ export const ExploreChartHeader = ({
|
||||
ownState,
|
||||
);
|
||||
|
||||
const metadataBar = useMemo(() => {
|
||||
if (!metadata) {
|
||||
return null;
|
||||
}
|
||||
const items = [];
|
||||
items.push({
|
||||
type: MetadataType.DASHBOARDS,
|
||||
title:
|
||||
metadata.dashboards.length > 0
|
||||
? t('Added to %s dashboard(s)', metadata.dashboards.length)
|
||||
: t('Not added to any dashboard'),
|
||||
});
|
||||
items.push({
|
||||
type: MetadataType.LAST_MODIFIED,
|
||||
value: metadata.changed_on_humanized,
|
||||
modifiedBy: metadata.changed_by || t('Not available'),
|
||||
});
|
||||
items.push({
|
||||
type: MetadataType.OWNER,
|
||||
createdBy: metadata.created_by || t('Not available'),
|
||||
owners: metadata.owners.length > 0 ? metadata.owners : t('None'),
|
||||
createdOn: metadata.created_on_humanized,
|
||||
});
|
||||
if (slice?.description) {
|
||||
items.push({
|
||||
type: MetadataType.DESCRIPTION,
|
||||
value: slice?.description,
|
||||
});
|
||||
}
|
||||
return <MetadataBar items={items} />;
|
||||
}, [metadata, slice?.description]);
|
||||
|
||||
const oldSliceName = slice?.slice_name;
|
||||
return (
|
||||
<>
|
||||
@@ -168,16 +211,19 @@ export const ExploreChartHeader = ({
|
||||
showTooltip: true,
|
||||
}}
|
||||
titlePanelAdditionalItems={
|
||||
sliceFormData ? (
|
||||
<AlteredSliceTag
|
||||
className="altered"
|
||||
origFormData={{
|
||||
...sliceFormData,
|
||||
chartTitle: oldSliceName,
|
||||
}}
|
||||
currentFormData={{ ...formData, chartTitle: sliceName }}
|
||||
/>
|
||||
) : null
|
||||
<div css={additionalItemsStyles}>
|
||||
{sliceFormData ? (
|
||||
<AlteredSliceTag
|
||||
className="altered"
|
||||
origFormData={{
|
||||
...sliceFormData,
|
||||
chartTitle: oldSliceName,
|
||||
}}
|
||||
currentFormData={{ ...formData, chartTitle: sliceName }}
|
||||
/>
|
||||
) : null}
|
||||
{metadataBar}
|
||||
</div>
|
||||
}
|
||||
rightPanelAdditionalItems={
|
||||
<Tooltip
|
||||
|
||||
Reference in New Issue
Block a user