You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by di...@apache.org on 2022/08/22 13:18:24 UTC

[superset] 35/36: feat: Add label and tooltip for the color schemes control (#21040)

This is an automated email from the ASF dual-hosted git repository.

diegopucci pushed a commit to branch chore/drill-to-detail-modal-tests
in repository https://gitbox.apache.org/repos/asf/superset.git

commit 8821952051ec02e35bf033ee3b4c3735bacc3b32
Author: Geido <60...@users.noreply.github.com>
AuthorDate: Mon Aug 22 10:44:15 2022 +0300

    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
---
 .../integration/dashboard/edit_properties.test.ts  |   2 +-
 .../cypress/integration/explore/control.test.ts    |  31 +++++
 .../explore/visualizations/area.test.js            |   2 +-
 .../explore/visualizations/box_plot.test.js        |   2 +-
 .../explore/visualizations/bubble.test.js          |   2 +-
 .../explore/visualizations/compare.test.js         |   2 +-
 .../explore/visualizations/dist_bar.test.js        |   2 +-
 .../explore/visualizations/dual_line.test.js       |   2 +-
 .../explore/visualizations/gauge.test.js           |   2 +-
 .../explore/visualizations/graph.test.ts           |   2 +-
 .../explore/visualizations/histogram.test.ts       |   2 +-
 .../explore/visualizations/line.test.ts            |   2 +-
 .../integration/explore/visualizations/pie.test.js |   2 +-
 .../explore/visualizations/sankey.test.js          |   2 +-
 .../explore/visualizations/sunburst.test.js        |   2 +-
 .../explore/visualizations/treemap.test.js         |   2 +-
 .../explore/visualizations/world_map.test.js       |   2 +-
 .../ColorSchemeControl/ColorSchemeLabel.test.tsx   |  59 ++++++++++
 .../ColorSchemeControl/ColorSchemeLabel.tsx        | 126 +++++++++++++++++++++
 .../controls/ColorSchemeControl/index.jsx          |  36 +-----
 20 files changed, 238 insertions(+), 46 deletions(-)

diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/edit_properties.test.ts b/superset-frontend/cypress-base/cypress/integration/dashboard/edit_properties.test.ts
index f748a48ac6..0bb83fa414 100644
--- a/superset-frontend/cypress-base/cypress/integration/dashboard/edit_properties.test.ts
+++ b/superset-frontend/cypress-base/cypress/integration/dashboard/edit_properties.test.ts
@@ -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',
diff --git a/superset-frontend/cypress-base/cypress/integration/explore/control.test.ts b/superset-frontend/cypress-base/cypress/integration/explore/control.test.ts
index a4b85de4de..c64f99140a 100644
--- a/superset-frontend/cypress-base/cypress/integration/explore/control.test.ts
+++ b/superset-frontend/cypress-base/cypress/integration/explore/control.test.ts
@@ -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();
diff --git a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/area.test.js b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/area.test.js
index eea3520398..069b457aa7 100644
--- a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/area.test.js
+++ b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/area.test.js
@@ -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()
diff --git a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/box_plot.test.js b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/box_plot.test.js
index 43f644b92d..46242e0114 100644
--- a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/box_plot.test.js
+++ b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/box_plot.test.js
@@ -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');
   });
 });
diff --git a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/bubble.test.js b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/bubble.test.js
index 28243f6862..e41535b549 100644
--- a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/bubble.test.js
+++ b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/bubble.test.js
@@ -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(
diff --git a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/compare.test.js b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/compare.test.js
index d4334bbe94..71f61c1432 100644
--- a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/compare.test.js
+++ b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/compare.test.js
@@ -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()
diff --git a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/dist_bar.test.js b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/dist_bar.test.js
index ecdab93ccf..9f62003c82 100644
--- a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/dist_bar.test.js
+++ b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/dist_bar.test.js
@@ -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()
diff --git a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/dual_line.test.js b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/dual_line.test.js
index e570836d39..1e7ed4c454 100644
--- a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/dual_line.test.js
+++ b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/dual_line.test.js
@@ -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()
diff --git a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/gauge.test.js b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/gauge.test.js
index 0bb5cb48d5..6895d9ef83 100644
--- a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/gauge.test.js
+++ b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/gauge.test.js
@@ -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');
   });
 });
diff --git a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/graph.test.ts b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/graph.test.ts
index b54ff10e76..16747d7221 100644
--- a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/graph.test.ts
+++ b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/graph.test.ts
@@ -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');
   });
 });
diff --git a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/histogram.test.ts b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/histogram.test.ts
index ef1a2df2d5..fbd5cfadeb 100644
--- a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/histogram.test.ts
+++ b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/histogram.test.ts
@@ -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()
diff --git a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/line.test.ts b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/line.test.ts
index b20f69a214..03ab7a6ed0 100644
--- a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/line.test.ts
+++ b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/line.test.ts
@@ -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()
diff --git a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/pie.test.js b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/pie.test.js
index 0590d64fa9..6c6d33e6e6 100644
--- a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/pie.test.js
+++ b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/pie.test.js
@@ -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');
   });
 });
diff --git a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/sankey.test.js b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/sankey.test.js
index b9f6ced3f2..fccefecf32 100644
--- a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/sankey.test.js
+++ b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/sankey.test.js
@@ -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');
   });
 });
diff --git a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/sunburst.test.js b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/sunburst.test.js
index 5118fdfe23..990d1d5294 100644
--- a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/sunburst.test.js
+++ b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/sunburst.test.js
@@ -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');
   });
 });
diff --git a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/treemap.test.js b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/treemap.test.js
index 435e363cb5..efd92a3e4e 100644
--- a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/treemap.test.js
+++ b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/treemap.test.js
@@ -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)');
diff --git a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/world_map.test.js b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/world_map.test.js
index 8b733ee3ff..8faa4e412b 100644
--- a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/world_map.test.js
+++ b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/world_map.test.js
@@ -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');
   });
 });
diff --git a/superset-frontend/src/explore/components/controls/ColorSchemeControl/ColorSchemeLabel.test.tsx b/superset-frontend/src/explore/components/controls/ColorSchemeControl/ColorSchemeLabel.test.tsx
new file mode 100644
index 0000000000..e3117d2f77
--- /dev/null
+++ b/superset-frontend/src/explore/components/controls/ColorSchemeControl/ColorSchemeLabel.test.tsx
@@ -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);
+});
diff --git a/superset-frontend/src/explore/components/controls/ColorSchemeControl/ColorSchemeLabel.tsx b/superset-frontend/src/explore/components/controls/ColorSchemeControl/ColorSchemeLabel.tsx
new file mode 100644
index 0000000000..cd046eb1fd
--- /dev/null
+++ b/superset-frontend/src/explore/components/controls/ColorSchemeControl/ColorSchemeLabel.tsx
@@ -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>
+  );
+}
diff --git a/superset-frontend/src/explore/components/controls/ColorSchemeControl/index.jsx b/superset-frontend/src/explore/components/controls/ColorSchemeControl/index.jsx
index f0ccc12398..d585520785 100644
--- a/superset-frontend/src/explore/components/controls/ColorSchemeControl/index.jsx
+++ b/superset-frontend/src/explore/components/controls/ColorSchemeControl/index.jsx
@@ -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}
+      />
     );
   }