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:
Geido 2022-08-22 10:44:15 +03:00 committed by GitHub
parent a1389d3a9f
commit 756ed0e36a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 238 additions and 46 deletions

View File

@ -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',

View File

@ -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();

View File

@ -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()

View File

@ -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');
});
});

View File

@ -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(

View File

@ -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()

View File

@ -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()

View File

@ -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()

View File

@ -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');
});
});

View File

@ -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');
});
});

View File

@ -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()

View File

@ -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()

View File

@ -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');
});
});

View File

@ -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');
});
});

View File

@ -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');
});
});

View File

@ -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)');

View File

@ -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');
});
});

View File

@ -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);
});

View File

@ -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>
);
}

View File

@ -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}`,
}}
>
&nbsp;
</li>
))}
</ul>
</span>
<ColorSchemeLabel
id={currentScheme.id}
label={currentScheme.label}
colors={colors}
/>
);
}