feat: Add label and tooltip for the color schemes control (#21040)
* Add tooltip * Remove title * Add license * Enhance E2E tests * Update tests * Lint and test fixes * Enhance layout
This commit is contained in:
parent
a1389d3a9f
commit
756ed0e36a
|
|
@ -154,7 +154,7 @@ describe('Dashboard edit action', () => {
|
|||
openAdvancedProperties().then(() => {
|
||||
assertMetadata('d3Category20');
|
||||
});
|
||||
cy.get('.ant-select-selection-item ul').should(
|
||||
cy.get('.ant-select-selection-item .color-scheme-option').should(
|
||||
'have.attr',
|
||||
'data-test',
|
||||
'd3Category20',
|
||||
|
|
|
|||
|
|
@ -88,6 +88,37 @@ describe('Datasource control', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('Color scheme control', () => {
|
||||
beforeEach(() => {
|
||||
cy.login();
|
||||
interceptChart({ legacy: true }).as('chartData');
|
||||
|
||||
cy.visitChartByName('Num Births Trend');
|
||||
cy.verifySliceSuccess({ waitAlias: '@chartData' });
|
||||
});
|
||||
|
||||
it('should show color options with and without tooltips', () => {
|
||||
cy.get('#controlSections-tab-display').click();
|
||||
cy.get('.ant-select-selection-item .color-scheme-label').contains(
|
||||
'Superset Colors',
|
||||
);
|
||||
cy.get('.ant-select-selection-item .color-scheme-label').trigger(
|
||||
'mouseover',
|
||||
);
|
||||
cy.get('.color-scheme-tooltip').contains('Superset Colors');
|
||||
cy.get('.Control[data-test="color_scheme"]').scrollIntoView();
|
||||
cy.get('.Control[data-test="color_scheme"] input[type="search"]')
|
||||
.focus()
|
||||
.type('lyftColors{enter}');
|
||||
cy.get(
|
||||
'.Control[data-test="color_scheme"] .ant-select-selection-item [data-test="lyftColors"]',
|
||||
).should('exist');
|
||||
cy.get('.ant-select-selection-item .color-scheme-label').trigger(
|
||||
'mouseover',
|
||||
);
|
||||
cy.get('.color-scheme-tooltip').should('not.exist');
|
||||
});
|
||||
});
|
||||
describe('VizType control', () => {
|
||||
beforeEach(() => {
|
||||
cy.login();
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@ describe('Visualization > Area', () => {
|
|||
.focus()
|
||||
.type('supersetColors{enter}');
|
||||
cy.get(
|
||||
'.Control[data-test="color_scheme"] .ant-select-selection-item ul[data-test="supersetColors"]',
|
||||
'.Control[data-test="color_scheme"] .ant-select-selection-item [data-test="supersetColors"]',
|
||||
).should('exist');
|
||||
cy.get('.area .nv-legend .nv-legend-symbol')
|
||||
.first()
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ describe('Visualization > Box Plot', () => {
|
|||
.focus()
|
||||
.type('supersetColors{enter}');
|
||||
cy.get(
|
||||
'.Control[data-test="color_scheme"] .ant-select-selection-item ul[data-test="supersetColors"]',
|
||||
'.Control[data-test="color_scheme"] .ant-select-selection-item [data-test="supersetColors"]',
|
||||
).should('exist');
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ describe('Visualization > Bubble', () => {
|
|||
.focus()
|
||||
.type('supersetColors{enter}');
|
||||
cy.get(
|
||||
'.Control[data-test="color_scheme"] .ant-select-selection-item ul[data-test="supersetColors"]',
|
||||
'.Control[data-test="color_scheme"] .ant-select-selection-item [data-test="supersetColors"]',
|
||||
).should('exist');
|
||||
cy.get('[data-test=run-query-button]').click();
|
||||
cy.get('.bubble .nv-legend .nv-legend-symbol').should(
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ describe('Visualization > Compare', () => {
|
|||
.focus()
|
||||
.type('supersetColors{enter}');
|
||||
cy.get(
|
||||
'.Control[data-test="color_scheme"] .ant-select-selection-item ul[data-test="supersetColors"]',
|
||||
'.Control[data-test="color_scheme"] .ant-select-selection-item [data-test="supersetColors"]',
|
||||
).should('exist');
|
||||
cy.get('.compare .nv-legend .nv-legend-symbol')
|
||||
.first()
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ describe('Visualization > Distribution bar chart', () => {
|
|||
.focus()
|
||||
.type('bnbColors{enter}');
|
||||
cy.get(
|
||||
'.Control[data-test="color_scheme"] .ant-select-selection-item ul[data-test="bnbColors"]',
|
||||
'.Control[data-test="color_scheme"] .ant-select-selection-item [data-test="bnbColors"]',
|
||||
).should('exist');
|
||||
cy.get('.dist_bar .nv-legend .nv-legend-symbol')
|
||||
.first()
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ describe('Visualization > Dual Line', () => {
|
|||
.focus()
|
||||
.type('supersetColors{enter}');
|
||||
cy.get(
|
||||
'.Control[data-test="color_scheme"] .ant-select-selection-item ul[data-test="supersetColors"]',
|
||||
'.Control[data-test="color_scheme"] .ant-select-selection-item [data-test="supersetColors"]',
|
||||
).should('exist');
|
||||
cy.get('.dual_line .nv-legend .nv-legend-symbol')
|
||||
.first()
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ describe('Visualization > Gauge', () => {
|
|||
.focus()
|
||||
.type('bnbColors{enter}');
|
||||
cy.get(
|
||||
'.Control[data-test="color_scheme"] .ant-select-selection-item ul[data-test="bnbColors"]',
|
||||
'.Control[data-test="color_scheme"] .ant-select-selection-item [data-test="bnbColors"]',
|
||||
).should('exist');
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ describe('Visualization > Graph', () => {
|
|||
.focus()
|
||||
.type('bnbColors{enter}');
|
||||
cy.get(
|
||||
'.Control[data-test="color_scheme"] .ant-select-selection-item ul[data-test="bnbColors"]',
|
||||
'.Control[data-test="color_scheme"] .ant-select-selection-item [data-test="bnbColors"]',
|
||||
).should('exist');
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ describe('Visualization > Histogram', () => {
|
|||
.focus()
|
||||
.type('supersetColors{enter}');
|
||||
cy.get(
|
||||
'.Control[data-test="color_scheme"] .ant-select-selection-item ul[data-test="supersetColors"]',
|
||||
'.Control[data-test="color_scheme"] .ant-select-selection-item [data-test="supersetColors"]',
|
||||
).should('exist');
|
||||
cy.get('.histogram .vx-legend .vx-legend-shape div')
|
||||
.first()
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ describe('Visualization > Line', () => {
|
|||
.focus()
|
||||
.type('bnbColors{enter}');
|
||||
cy.get(
|
||||
'.Control[data-test="color_scheme"] .ant-select-selection-item ul[data-test="bnbColors"]',
|
||||
'.Control[data-test="color_scheme"] .ant-select-selection-item [data-test="bnbColors"]',
|
||||
).should('exist');
|
||||
cy.get('.line .nv-legend .nv-legend-symbol')
|
||||
.first()
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ describe('Visualization > Pie', () => {
|
|||
.focus()
|
||||
.type('supersetColors{enter}');
|
||||
cy.get(
|
||||
'.Control[data-test="color_scheme"] .ant-select-selection-item ul[data-test="supersetColors"]',
|
||||
'.Control[data-test="color_scheme"] .ant-select-selection-item [data-test="supersetColors"]',
|
||||
).should('exist');
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ describe('Visualization > Sankey', () => {
|
|||
.focus()
|
||||
.type('bnbColors{enter}');
|
||||
cy.get(
|
||||
'.Control[data-test="color_scheme"] .ant-select-selection-item ul[data-test="bnbColors"]',
|
||||
'.Control[data-test="color_scheme"] .ant-select-selection-item [data-test="bnbColors"]',
|
||||
).should('exist');
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ describe('Visualization > Sunburst', () => {
|
|||
.focus()
|
||||
.type('supersetColors{enter}');
|
||||
cy.get(
|
||||
'.Control[data-test="color_scheme"] .ant-select-selection-item ul[data-test="supersetColors"]',
|
||||
'.Control[data-test="color_scheme"] .ant-select-selection-item [data-test="supersetColors"]',
|
||||
).should('exist');
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ describe('Visualization > Treemap', () => {
|
|||
.focus()
|
||||
.type('supersetColors{enter}');
|
||||
cy.get(
|
||||
'.Control[data-test="color_scheme"] .ant-select-selection-item ul[data-test="supersetColors"]',
|
||||
'.Control[data-test="color_scheme"] .ant-select-selection-item [data-test="supersetColors"]',
|
||||
).should('exist');
|
||||
cy.get('[data-test=run-query-button]').click();
|
||||
cy.get('#rect-IND').should('have.css', 'fill', 'rgb(69, 78, 124)');
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ describe('Visualization > World Map', () => {
|
|||
.focus()
|
||||
.type('greens{enter}');
|
||||
cy.get(
|
||||
'.Control[data-test="linear_color_scheme"] .ant-select-selection-item ul[data-test="greens"]',
|
||||
'.Control[data-test="linear_color_scheme"] .ant-select-selection-item [data-test="greens"]',
|
||||
).should('exist');
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -0,0 +1,59 @@
|
|||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import React from 'react';
|
||||
import { render, screen, waitFor } from 'spec/helpers/testing-library';
|
||||
import ColorSchemeLabel from './ColorSchemeLabel';
|
||||
|
||||
const defaultProps = {
|
||||
colors: [
|
||||
'#000000',
|
||||
'#FFFFFF',
|
||||
'#CCCCCC',
|
||||
'#000000',
|
||||
'#FFFFFF',
|
||||
'#CCCCCC',
|
||||
'#000000',
|
||||
'#FFFFFF',
|
||||
'#CCCCCC',
|
||||
'#000000',
|
||||
'#FFFFFF',
|
||||
'#CCCCCC',
|
||||
],
|
||||
label: 'Superset Colors',
|
||||
id: 'colorScheme',
|
||||
};
|
||||
|
||||
const setup = (overrides?: Record<string, any>) =>
|
||||
render(<ColorSchemeLabel {...defaultProps} {...overrides} />);
|
||||
|
||||
test('should render', async () => {
|
||||
const { container } = setup();
|
||||
await waitFor(() => expect(container).toBeVisible());
|
||||
});
|
||||
|
||||
test('should render the label', () => {
|
||||
setup();
|
||||
expect(screen.getByText('Superset Colors')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('should render the colors', () => {
|
||||
setup();
|
||||
const allColors = screen.getAllByTestId('color');
|
||||
expect(allColors).toHaveLength(12);
|
||||
});
|
||||
|
|
@ -0,0 +1,126 @@
|
|||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { css, SupersetTheme } from '@superset-ui/core';
|
||||
import React, { useRef, useState } from 'react';
|
||||
import { Tooltip } from 'src/components/Tooltip';
|
||||
|
||||
type ColorSchemeLabelProps = {
|
||||
colors: string[];
|
||||
id: string;
|
||||
label: string;
|
||||
};
|
||||
|
||||
export default function ColorSchemeLabel(props: ColorSchemeLabelProps) {
|
||||
const { id, label, colors } = props;
|
||||
const [showTooltip, setShowTooltip] = useState<boolean>(false);
|
||||
const labelNameRef = useRef<HTMLElement>(null);
|
||||
const labelColorsRef = useRef<HTMLElement>(null);
|
||||
const handleShowTooltip = () => {
|
||||
const labelNameElement = labelNameRef.current;
|
||||
const labelColorsElement = labelColorsRef.current;
|
||||
if (
|
||||
labelNameElement &&
|
||||
labelColorsElement &&
|
||||
(labelNameElement.scrollWidth > labelNameElement.offsetWidth ||
|
||||
labelNameElement.scrollHeight > labelNameElement.offsetHeight ||
|
||||
labelColorsElement.scrollWidth > labelColorsElement.offsetWidth ||
|
||||
labelColorsElement.scrollHeight > labelColorsElement.offsetHeight)
|
||||
) {
|
||||
setShowTooltip(true);
|
||||
}
|
||||
};
|
||||
const handleHideTooltip = () => {
|
||||
setShowTooltip(false);
|
||||
};
|
||||
|
||||
const colorsList = () =>
|
||||
colors.map((color: string, i: number) => (
|
||||
<span
|
||||
data-test="color"
|
||||
key={`${id}-${i}`}
|
||||
css={(theme: { gridUnit: number }) => css`
|
||||
padding-left: ${theme.gridUnit / 2}px;
|
||||
:before {
|
||||
content: '';
|
||||
display: inline-block;
|
||||
background-color: ${color};
|
||||
border: 1px solid ${color === 'white' ? 'black' : color};
|
||||
width: 9px;
|
||||
height: 10px;
|
||||
}
|
||||
`}
|
||||
/>
|
||||
));
|
||||
|
||||
const tooltipContent = () => (
|
||||
<>
|
||||
<span>{label}</span>
|
||||
<div>{colorsList()}</div>
|
||||
</>
|
||||
);
|
||||
|
||||
return (
|
||||
<Tooltip
|
||||
data-testid="tooltip"
|
||||
overlayClassName="color-scheme-tooltip"
|
||||
title={tooltipContent}
|
||||
key={id}
|
||||
visible={showTooltip}
|
||||
>
|
||||
<span
|
||||
className="color-scheme-option"
|
||||
onMouseEnter={handleShowTooltip}
|
||||
onMouseLeave={handleHideTooltip}
|
||||
css={css`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
`}
|
||||
data-test={id}
|
||||
>
|
||||
<span
|
||||
className="color-scheme-label"
|
||||
ref={labelNameRef}
|
||||
css={(theme: SupersetTheme) => css`
|
||||
min-width: 125px;
|
||||
padding-right: ${theme.gridUnit * 2}px;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
`}
|
||||
>
|
||||
{label}
|
||||
</span>
|
||||
<span
|
||||
ref={labelColorsRef}
|
||||
css={(theme: SupersetTheme) => css`
|
||||
flex: 100%;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
padding-right: ${theme.gridUnit}px;
|
||||
`}
|
||||
>
|
||||
{colorsList()}
|
||||
</span>
|
||||
</span>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
|
|
@ -24,6 +24,7 @@ import { Tooltip } from 'src/components/Tooltip';
|
|||
import { styled, t } from '@superset-ui/core';
|
||||
import Icons from 'src/components/Icons';
|
||||
import ControlHeader from 'src/explore/components/ControlHeader';
|
||||
import ColorSchemeLabel from './ColorSchemeLabel';
|
||||
|
||||
const propTypes = {
|
||||
hasCustomLabelColors: PropTypes.bool,
|
||||
|
|
@ -86,36 +87,11 @@ export default class ColorSchemeControl extends React.PureComponent {
|
|||
}
|
||||
|
||||
return (
|
||||
<span key={currentScheme.id} title={currentScheme.label}>
|
||||
<ul
|
||||
css={{
|
||||
listStyle: 'none',
|
||||
margin: 0,
|
||||
padding: 0,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
|
||||
'& li': {
|
||||
flexBasis: 9,
|
||||
height: 10,
|
||||
margin: '9px 1px',
|
||||
},
|
||||
}}
|
||||
data-test={currentScheme.id}
|
||||
>
|
||||
{colors.map((color, i) => (
|
||||
<li
|
||||
key={`${currentScheme.id}-${i}`}
|
||||
css={{
|
||||
backgroundColor: color,
|
||||
border: `1px solid ${color === 'white' ? 'black' : color}`,
|
||||
}}
|
||||
>
|
||||
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</span>
|
||||
<ColorSchemeLabel
|
||||
id={currentScheme.id}
|
||||
label={currentScheme.label}
|
||||
colors={colors}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue