feat(explore): Redesign of Run/Save buttons (#19558)

* feat(explore): Move save button to header, run button to bottom of control panel

* Make the tabs sticky

* Add error icon to Data tab

* Show message when creating chart and all controls are filled correctly

* Add tests and storybook

* Fix tests

* Disable save button when control have errors

* Fix types

* Apply code review comments

* Replace styled with css

* Remove unused import
This commit is contained in:
Kamil Gabryjelski
2022-04-13 16:58:39 +02:00
committed by GitHub
parent 32239b04aa
commit c8304a2821
13 changed files with 362 additions and 279 deletions

View File

@@ -90,6 +90,7 @@ const createProps = () => ({
user: {
userId: 1,
},
onSaveChart: jest.fn(),
});
test('Cancelling changes to the properties should reset previous properties', () => {
@@ -115,3 +116,17 @@ test('Cancelling changes to the properties should reset previous properties', ()
expect(screen.getByDisplayValue(prevChartName)).toBeInTheDocument();
});
test('Save chart', () => {
const props = createProps();
render(<ExploreHeader {...props} />, { useRedux: true });
userEvent.click(screen.getByText('Save'));
expect(props.onSaveChart).toHaveBeenCalled();
});
test('Save disabled', () => {
const props = createProps();
render(<ExploreHeader {...props} saveDisabled />, { useRedux: true });
userEvent.click(screen.getByText('Save'));
expect(props.onSaveChart).not.toHaveBeenCalled();
});

View File

@@ -24,7 +24,6 @@ import {
CategoricalColorNamespace,
css,
SupersetClient,
styled,
t,
} from '@superset-ui/core';
import {
@@ -36,9 +35,12 @@ import { isFeatureEnabled, FeatureFlag } from 'src/featureFlags';
import { chartPropShape } from 'src/dashboard/util/propShapes';
import AlteredSliceTag from 'src/components/AlteredSliceTag';
import FaveStar from 'src/components/FaveStar';
import Button from 'src/components/Button';
import Icons from 'src/components/Icons';
import PropertiesModal from 'src/explore/components/PropertiesModal';
import { sliceUpdated } from 'src/explore/actions/exploreActions';
import CertifiedBadge from 'src/components/CertifiedBadge';
import { Tooltip } from 'src/components/Tooltip';
import ExploreAdditionalActionsMenu from '../ExploreAdditionalActionsMenu';
import { ChartEditableTitle } from './ChartEditableTitle';
@@ -55,60 +57,58 @@ const propTypes = {
ownState: PropTypes.object,
timeout: PropTypes.number,
chart: chartPropShape,
saveDisabled: PropTypes.bool,
};
const StyledHeader = styled.div`
${({ theme }) => css`
display: flex;
flex-direction: row;
align-items: center;
flex-wrap: nowrap;
justify-content: space-between;
height: 100%;
span[role='button'] {
display: flex;
height: 100%;
}
.title-panel {
display: flex;
align-items: center;
min-width: 0;
margin-right: ${theme.gridUnit * 12}px;
}
.right-button-panel {
display: flex;
align-items: center;
> .btn-group {
flex: 0 0 auto;
margin-left: ${theme.gridUnit}px;
}
}
.action-button {
color: ${theme.colors.grayscale.base};
margin: 0 ${theme.gridUnit * 1.5}px 0 ${theme.gridUnit}px;
}
`}
const saveButtonStyles = theme => css`
color: ${theme.colors.primary.dark2};
& > span[role='img'] {
margin-right: 0;
}
`;
const StyledButtons = styled.span`
${({ theme }) => css`
const headerStyles = theme => css`
display: flex;
flex-direction: row;
align-items: center;
flex-wrap: nowrap;
justify-content: space-between;
height: 100%;
span[role='button'] {
display: flex;
height: 100%;
}
.title-panel {
display: flex;
align-items: center;
padding-left: ${theme.gridUnit * 2}px;
min-width: 0;
margin-right: ${theme.gridUnit * 12}px;
}
& .fave-unfave-icon {
padding: 0 ${theme.gridUnit}px;
.right-button-panel {
display: flex;
align-items: center;
}
`;
&:first-child {
padding-left: 0;
}
const buttonsStyles = theme => css`
display: flex;
align-items: center;
padding-left: ${theme.gridUnit * 2}px;
& .fave-unfave-icon {
padding: 0 ${theme.gridUnit}px;
&:first-child {
padding-left: 0;
}
`}
}
`;
const saveButtonContainerStyles = theme => css`
margin-right: ${theme.gridUnit * 2}px;
`;
export class ExploreChartHeader extends React.PureComponent {
@@ -231,11 +231,13 @@ export class ExploreChartHeader extends React.PureComponent {
isStarred,
sliceUpdated,
sliceName,
onSaveChart,
saveDisabled,
} = this.props;
const { latestQueryFormData, sliceFormData } = chart;
const oldSliceName = slice?.slice_name;
return (
<StyledHeader id="slice-header">
<div id="slice-header" css={headerStyles}>
<div className="title-panel">
<ChartEditableTitle
title={sliceName}
@@ -248,7 +250,7 @@ export class ExploreChartHeader extends React.PureComponent {
placeholder={t('Add the name of the chart')}
/>
{slice && (
<StyledButtons>
<span css={buttonsStyles}>
{slice.certified_by && (
<CertifiedBadge
certifiedBy={slice.certified_by}
@@ -279,10 +281,31 @@ export class ExploreChartHeader extends React.PureComponent {
currentFormData={{ ...formData, chartTitle: sliceName }}
/>
)}
</StyledButtons>
</span>
)}
</div>
<div className="right-button-panel">
<Tooltip
title={
saveDisabled
? t('Add required control values to save chart')
: null
}
>
{/* needed to wrap button in a div - antd tooltip doesn't work with disabled button */}
<div css={saveButtonContainerStyles}>
<Button
buttonStyle="secondary"
onClick={onSaveChart}
disabled={saveDisabled}
data-test="query-save-button"
css={saveButtonStyles}
>
<Icons.SaveOutlined iconSize="l" />
{t('Save')}
</Button>
</div>
</Tooltip>
<ExploreAdditionalActionsMenu
onOpenInEditor={actions.redirectSQLLab}
onOpenPropertiesModal={this.openPropertiesModal}
@@ -292,7 +315,7 @@ export class ExploreChartHeader extends React.PureComponent {
canAddReports={this.canAddReports()}
/>
</div>
</StyledHeader>
</div>
);
}
}