-
Notifications
You must be signed in to change notification settings - Fork 14.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
chore(explore): update Explore icons and icon colors #20612
Changes from all commits
f942447
00ba952
bcf2275
1f69feb
5e3a927
36edd57
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,7 +16,7 @@ | |
* specific language governing permissions and limitations | ||
* under the License. | ||
*/ | ||
import React, { FC, ReactNode } from 'react'; | ||
import React, { FC, ReactNode, useMemo, useRef } from 'react'; | ||
import { t, css, useTheme, SupersetTheme } from '@superset-ui/core'; | ||
import { InfoTooltipWithTrigger } from '@superset-ui/chart-controls'; | ||
import { Tooltip } from 'src/components/Tooltip'; | ||
|
@@ -40,6 +40,16 @@ export type ControlHeaderProps = { | |
danger?: string; | ||
}; | ||
|
||
const iconStyles = css` | ||
&.anticon { | ||
font-size: unset; | ||
.anticon { | ||
line-height: unset; | ||
vertical-align: unset; | ||
} | ||
} | ||
`; | ||
|
||
const ControlHeader: FC<ControlHeaderProps> = ({ | ||
name, | ||
label, | ||
|
@@ -55,6 +65,22 @@ const ControlHeader: FC<ControlHeaderProps> = ({ | |
danger, | ||
}) => { | ||
const { gridUnit, colors } = useTheme(); | ||
const hasHadNoErrors = useRef(false); | ||
const labelColor = useMemo(() => { | ||
if (!validationErrors.length) { | ||
hasHadNoErrors.current = true; | ||
} | ||
|
||
if (hasHadNoErrors.current) { | ||
if (validationErrors.length) { | ||
return colors.error.base; | ||
} | ||
|
||
return 'unset'; | ||
} | ||
|
||
return colors.alert.base; | ||
}, [colors.error.base, colors.alert.base, validationErrors.length]); | ||
|
||
if (!label) { | ||
return null; | ||
|
@@ -78,12 +104,16 @@ const ControlHeader: FC<ControlHeaderProps> = ({ | |
> | ||
{description && ( | ||
<span> | ||
<InfoTooltipWithTrigger | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's still used on line 96 to render the lightning bolt icon, do you think I should replace that with a plain |
||
label={t('description')} | ||
tooltip={description} | ||
<Tooltip | ||
id={`${t('description')}-tooltip`} | ||
title={description} | ||
placement="top" | ||
onClick={tooltipOnClick} | ||
/>{' '} | ||
> | ||
<Icons.InfoCircleOutlined | ||
css={iconStyles} | ||
onClick={tooltipOnClick} | ||
/> | ||
</Tooltip>{' '} | ||
</span> | ||
)} | ||
{renderTrigger && ( | ||
|
@@ -100,8 +130,6 @@ const ControlHeader: FC<ControlHeaderProps> = ({ | |
); | ||
}; | ||
|
||
const labelClass = validationErrors?.length > 0 ? 'text-danger' : ''; | ||
|
||
return ( | ||
<div className="ControlHeader" data-test={`${name}-header`}> | ||
<div className="pull-left"> | ||
|
@@ -118,7 +146,6 @@ const ControlHeader: FC<ControlHeaderProps> = ({ | |
role="button" | ||
tabIndex={0} | ||
onClick={onClick} | ||
className={labelClass} | ||
style={{ cursor: onClick ? 'pointer' : '' }} | ||
> | ||
{label} | ||
|
@@ -138,13 +165,18 @@ const ControlHeader: FC<ControlHeaderProps> = ({ | |
</span> | ||
)} | ||
{validationErrors?.length > 0 && ( | ||
<span> | ||
<span data-test="error-tooltip"> | ||
<Tooltip | ||
id="error-tooltip" | ||
placement="top" | ||
title={validationErrors?.join(' ')} | ||
> | ||
<Icons.ErrorSolid iconColor={colors.error.base} iconSize="s" /> | ||
<Icons.ExclamationCircleOutlined | ||
css={css` | ||
${iconStyles} | ||
color: ${labelColor}; | ||
`} | ||
/> | ||
</Tooltip>{' '} | ||
</span> | ||
)} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -35,14 +35,14 @@ import { | |
DatasourceType, | ||
css, | ||
SupersetTheme, | ||
useTheme, | ||
} from '@superset-ui/core'; | ||
import { | ||
ControlPanelSectionConfig, | ||
ControlState, | ||
CustomControlItem, | ||
Dataset, | ||
ExpandedControlItem, | ||
InfoTooltipWithTrigger, | ||
sections, | ||
} from '@superset-ui/chart-controls'; | ||
|
||
|
@@ -56,8 +56,10 @@ import { getSectionsToRender } from 'src/explore/controlUtils'; | |
import { ExploreActions } from 'src/explore/actions/exploreActions'; | ||
import { ChartState, ExplorePageState } from 'src/explore/types'; | ||
import { Tooltip } from 'src/components/Tooltip'; | ||
import Icons from 'src/components/Icons'; | ||
|
||
import { rgba } from 'emotion-rgba'; | ||
import { kebabCase } from 'lodash'; | ||
import ControlRow from './ControlRow'; | ||
import Control from './Control'; | ||
import { ExploreAlert } from './ExploreAlert'; | ||
|
@@ -85,6 +87,16 @@ export type ExpandedControlPanelSectionConfig = Omit< | |
controlSetRows: ExpandedControlItem[][]; | ||
}; | ||
|
||
const iconStyles = css` | ||
&.anticon { | ||
font-size: unset; | ||
.anticon { | ||
line-height: unset; | ||
vertical-align: unset; | ||
} | ||
} | ||
`; | ||
|
||
const actionButtonsContainerStyles = (theme: SupersetTheme) => css` | ||
display: flex; | ||
position: sticky; | ||
|
@@ -235,7 +247,19 @@ function getState( | |
}; | ||
} | ||
|
||
function useResetOnChangeRef(initialValue: () => any, resetOnChangeValue: any) { | ||
const value = useRef(initialValue()); | ||
const prevResetOnChangeValue = useRef(resetOnChangeValue); | ||
if (prevResetOnChangeValue.current !== resetOnChangeValue) { | ||
value.current = initialValue(); | ||
prevResetOnChangeValue.current = resetOnChangeValue; | ||
} | ||
|
||
return value; | ||
} | ||
|
||
export const ControlPanelsContainer = (props: ControlPanelsContainerProps) => { | ||
const { colors } = useTheme(); | ||
const pluginContext = useContext(PluginContext); | ||
|
||
const prevState = usePrevious(props.exploreState); | ||
|
@@ -367,6 +391,11 @@ export const ControlPanelsContainer = (props: ControlPanelsContainerProps) => { | |
); | ||
}; | ||
|
||
const sectionHasHadNoErrors = useResetOnChangeRef( | ||
() => ({}), | ||
props.form_data.viz_type, | ||
); | ||
|
||
const renderControlPanelSection = ( | ||
section: ExpandedControlPanelSectionConfig, | ||
) => { | ||
|
@@ -394,6 +423,15 @@ export const ControlPanelsContainer = (props: ControlPanelsContainerProps) => { | |
); | ||
}), | ||
); | ||
|
||
if (!hasErrors) { | ||
sectionHasHadNoErrors.current[sectionId] = true; | ||
} | ||
|
||
const errorColor = sectionHasHadNoErrors.current[sectionId] | ||
? colors.error.base | ||
: colors.alert.base; | ||
|
||
const PanelHeader = () => ( | ||
<span data-test="collapsible-control-panel-header"> | ||
<span | ||
|
@@ -405,15 +443,22 @@ export const ControlPanelsContainer = (props: ControlPanelsContainerProps) => { | |
{label} | ||
</span>{' '} | ||
{description && ( | ||
// label is only used in tooltip id (should probably call this prop `id`) | ||
<InfoTooltipWithTrigger label={sectionId} tooltip={description} /> | ||
<Tooltip id={sectionId} title={description}> | ||
<Icons.InfoCircleOutlined css={iconStyles} /> | ||
</Tooltip> | ||
)} | ||
{hasErrors && ( | ||
<InfoTooltipWithTrigger | ||
label="validation-errors" | ||
bsStyle="danger" | ||
tooltip="This section contains validation errors" | ||
/> | ||
<Tooltip | ||
id={`${kebabCase('validation-errors')}-tooltip`} | ||
title="This section contains validation errors" | ||
> | ||
<Icons.InfoCircleOutlined | ||
css={css` | ||
${iconStyles} | ||
color: ${errorColor}; | ||
`} | ||
/> | ||
</Tooltip> | ||
)} | ||
</span> | ||
); | ||
|
@@ -514,14 +559,26 @@ export const ControlPanelsContainer = (props: ControlPanelsContainerProps) => { | |
[handleClearFormClick, handleContinueClick, hasControlsTransferred], | ||
); | ||
|
||
const dataTabTitle = useMemo( | ||
() => ( | ||
const dataTabHasHadNoErrors = useResetOnChangeRef( | ||
() => false, | ||
props.form_data.viz_type, | ||
); | ||
|
||
const dataTabTitle = useMemo(() => { | ||
if (!props.errorMessage) { | ||
dataTabHasHadNoErrors.current = true; | ||
} | ||
|
||
const errorColor = dataTabHasHadNoErrors.current | ||
? colors.error.base | ||
: colors.alert.base; | ||
|
||
return ( | ||
<> | ||
<span>{t('Data')}</span> | ||
{props.errorMessage && ( | ||
<span | ||
css={(theme: SupersetTheme) => css` | ||
font-size: ${theme.typography.sizes.xs}px; | ||
margin-left: ${theme.gridUnit * 2}px; | ||
`} | ||
> | ||
|
@@ -531,14 +588,23 @@ export const ControlPanelsContainer = (props: ControlPanelsContainerProps) => { | |
placement="right" | ||
title={props.errorMessage} | ||
> | ||
<i className="fa fa-exclamation-circle text-danger fa-lg" /> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I can't tell you how happy it makes me to see these fa-* icons fading away one by one :D |
||
<Icons.ExclamationCircleOutlined | ||
css={css` | ||
${iconStyles} | ||
color: ${errorColor}; | ||
`} | ||
/> | ||
</Tooltip> | ||
</span> | ||
)} | ||
</> | ||
), | ||
[props.errorMessage], | ||
); | ||
); | ||
}, [ | ||
colors.error.base, | ||
colors.alert.base, | ||
dataTabHasHadNoErrors, | ||
props.errorMessage, | ||
]); | ||
|
||
const controlPanelRegistry = getChartControlPanelRegistry(); | ||
if ( | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is fine for now, but let's talk about this chunk in person sometime. I'd love to be in a state where we don't need to be adding/overriding/tweaking Icon styles in any particular use/implementation, instead adding classes/config/props on the Icon component itself to handle these needs more globally.