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

maximebeauchemin pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/superset.git


The following commit(s) were added to refs/heads/master by this push:
     new 740fbf72d7 feat: redesign labels (#31575)
740fbf72d7 is described below

commit 740fbf72d72f91daa3340b53fa55b8a414a1d40f
Author: Maxime Beauchemin <[email protected]>
AuthorDate: Fri Jan 10 09:30:12 2025 -0800

    feat: redesign labels (#31575)
---
 .../stories/superset-ui-style/Theme.stories.tsx    | 101 ++++++++++++++++++---
 .../src/components/AlteredSliceTag/index.tsx       |  25 +++--
 superset-frontend/src/components/Icons/Icon.tsx    |   4 +
 .../src/components/Label/Label.stories.tsx         |  88 +++++++++++-------
 .../src/components/Label/Label.test.tsx            |   4 +-
 superset-frontend/src/components/Label/index.tsx   |  75 +++++++++------
 .../components/Label/reusable/DatasetTypeLabel.tsx |  49 ++++++++++
 .../components/Label/reusable/PublishedLabel.tsx}  |  53 +++++------
 superset-frontend/src/components/Timer/index.tsx   |   3 +-
 .../dashboard/components/PublishedStatus/index.tsx |  32 +++----
 .../src/pages/DashboardList/index.tsx              |   6 +-
 superset-frontend/src/pages/DatasetList/index.tsx  |  22 +----
 12 files changed, 307 insertions(+), 155 deletions(-)

diff --git 
a/superset-frontend/packages/superset-ui-demo/storybook/stories/superset-ui-style/Theme.stories.tsx
 
b/superset-frontend/packages/superset-ui-demo/storybook/stories/superset-ui-style/Theme.stories.tsx
index 63ede4a8a7..b46c9dfb81 100644
--- 
a/superset-frontend/packages/superset-ui-demo/storybook/stories/superset-ui-style/Theme.stories.tsx
+++ 
b/superset-frontend/packages/superset-ui-demo/storybook/stories/superset-ui-style/Theme.stories.tsx
@@ -25,23 +25,96 @@ export default {
 
 export const ThemeColors = () => {
   const { colors } = supersetTheme;
-  return Object.keys(colors).map(collection => (
+
+  // Define tones to be displayed in columns
+  const tones = [
+    'dark2',
+    'dark1',
+    'base',
+    'light1',
+    'light2',
+    'light3',
+    'light4',
+    'light5',
+  ];
+  const colorTypes = [
+    'primary',
+    'secondary',
+    'grayscale',
+    'error',
+    'warning',
+    'alert',
+    'success',
+    'info',
+  ];
+  return (
     <div>
-      <h2>{collection}</h2>
-      <table style={{ width: '300px' }}>
-        {Object.keys(colors[collection]).map(k => {
-          const hex = colors[collection][k];
-          return (
-            <tr>
-              <td>{k}</td>
-              <td>
-                <code>{hex}</code>
+      <h1>Theme Colors</h1>
+      <table
+        style={{ borderCollapse: 'collapse', width: '100%', textAlign: 'left' 
}}
+      >
+        <thead>
+          <tr>
+            <th style={{ border: '1px solid #ddd', padding: '8px' }}>
+              Category
+            </th>
+            {tones.map(tone => (
+              <th
+                key={tone}
+                style={{ border: '1px solid #ddd', padding: '8px' }}
+              >
+                {tone}
+              </th>
+            ))}
+          </tr>
+        </thead>
+        <tbody>
+          {colorTypes.map(category => (
+            <tr key={category}>
+              <td style={{ border: '1px solid #ddd', padding: '8px' }}>
+                <strong>{category}</strong>
               </td>
-              <td style={{ width: '150px', backgroundColor: hex }} />
+              {tones.map(tone => {
+                const color = colors[category][tone];
+                return (
+                  <td
+                    key={tone}
+                    style={{
+                      border: '1px solid #ddd',
+                      padding: '8px',
+                      backgroundColor: color || '#fff',
+                    }}
+                  >
+                    {color ? <code>{color}</code> : '-'}
+                  </td>
+                );
+              })}
             </tr>
-          );
-        })}
+          ))}
+        </tbody>
       </table>
+      <h3>
+        text.label: <code>{colors.text.label}</code>
+      </h3>
+      <div style={{ color: `#${colors.text.label}` }}>
+        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod
+        tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
+        veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
+        commodo consequat.
+      </div>
+      <h3>
+        text.help: <code>{colors.text.help}</code>
+      </h3>
+      <div style={{ color: `#${colors.text.help}` }}>
+        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod
+        tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
+        veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
+        commodo consequat.
+      </div>
+      <h3>The supersetTheme object</h3>
+      <code>
+        <pre>{JSON.stringify(supersetTheme, null, 2)}</pre>
+      </code>
     </div>
-  ));
+  );
 };
diff --git a/superset-frontend/src/components/AlteredSliceTag/index.tsx 
b/superset-frontend/src/components/AlteredSliceTag/index.tsx
index bd16d1c287..9aca6b46b8 100644
--- a/superset-frontend/src/components/AlteredSliceTag/index.tsx
+++ b/superset-frontend/src/components/AlteredSliceTag/index.tsx
@@ -19,9 +19,11 @@
 import { useCallback, useEffect, useMemo, useState, FC } from 'react';
 
 import { isEqual, isEmpty } from 'lodash';
-import { QueryFormData, styled, t } from '@superset-ui/core';
+import { QueryFormData, t } from '@superset-ui/core';
 import { sanitizeFormData } from 'src/explore/exploreUtils/formData';
 import getControlsForVizType from 'src/utils/getControlsForVizType';
+import Label from 'src/components/Label';
+import Icons from 'src/components/Icons';
 import { safeStringify } from 'src/utils/safeStringify';
 import { Tooltip } from 'src/components/Tooltip';
 import ModalTrigger from '../ModalTrigger';
@@ -68,18 +70,6 @@ export type RowType = {
   control: string;
 };
 
-const StyledLabel = styled.span`
-  ${({ theme }) => `
-    font-size: ${theme.typography.sizes.s}px;
-    color: ${theme.colors.grayscale.dark1};
-    background-color: ${theme.colors.alert.base};
-
-    &:hover {
-      background-color: ${theme.colors.alert.dark1};
-    }
-  `}
-`;
-
 export const alterForComparison = (
   value?: string | null | [],
 ): string | null => {
@@ -228,7 +218,14 @@ const AlteredSliceTag: FC<AlteredSliceTagProps> = props => 
{
   const triggerNode = useMemo(
     () => (
       <Tooltip id="difference-tooltip" title={t('Click to see difference')}>
-        <StyledLabel className="label">{t('Altered')}</StyledLabel>
+        <Label
+          icon={<Icons.Warning iconSize="m" />}
+          className="label"
+          type="alert"
+          onClick={() => {}}
+        >
+          {t('Altered')}
+        </Label>
       </Tooltip>
     ),
     [],
diff --git a/superset-frontend/src/components/Icons/Icon.tsx 
b/superset-frontend/src/components/Icons/Icon.tsx
index b2e7dbfdc1..39e5627235 100644
--- a/superset-frontend/src/components/Icons/Icon.tsx
+++ b/superset-frontend/src/components/Icons/Icon.tsx
@@ -36,6 +36,10 @@ const AntdIconComponent = ({
 
 export const StyledIcon = styled(AntdIconComponent)<IconType>`
   ${({ iconColor }) => iconColor && `color: ${iconColor};`};
+  span {
+    // Fixing alignement on some of the icons
+    line-height: 0px;
+  }
   font-size: ${({ iconSize, theme }) =>
     iconSize
       ? `${theme.typography.sizes[iconSize] || theme.typography.sizes.m}px`
diff --git a/superset-frontend/src/components/Label/Label.stories.tsx 
b/superset-frontend/src/components/Label/Label.stories.tsx
index 5c46182465..20225811d3 100644
--- a/superset-frontend/src/components/Label/Label.stories.tsx
+++ b/superset-frontend/src/components/Label/Label.stories.tsx
@@ -17,14 +17,17 @@
  * under the License.
  */
 import { action } from '@storybook/addon-actions';
-import Label, { Type } from './index';
+import { Meta, StoryFn } from '@storybook/react';
+import Label, { Type, DatasetTypeLabel, PublishedLabel } from './index';
 
+// Define the default export with Storybook configuration
 export default {
   title: 'Label',
   component: Label,
-  excludeStories: 'options',
-};
+  excludeStories: ['options'],
+} as Meta<typeof Label>;
 
+// Explicitly type the options array as an array of `Type`
 export const options: Type[] = [
   'default',
   'alert',
@@ -36,39 +39,60 @@ export const options: Type[] = [
   'secondary',
 ];
 
-export const LabelGallery = () => (
-  <>
-    <h4>Non-interactive</h4>
-    {Object.values(options).map((opt: Type) => (
-      <Label key={opt} type={opt}>
-        {`style: "${opt}"`}
-      </Label>
-    ))}
-    <br />
-    <h4>Interactive</h4>
-    {Object.values(options).map((opt: Type) => (
-      <Label key={opt} type={opt} onClick={action('clicked')}>
-        {`style: "${opt}"`}
-      </Label>
-    ))}
-  </>
-);
+// Define the props for the `LabelGallery` component
+interface LabelGalleryProps {
+  hasOnClick?: boolean;
+  monospace?: boolean;
+}
+
+// Use the `StoryFn` type for LabelGallery
+export const LabelGallery: StoryFn<LabelGalleryProps> = (
+  props: LabelGalleryProps,
+) => {
+  const onClick = props.hasOnClick ? action('clicked') : undefined;
 
-export const InteractiveLabel = (args: any) => {
-  const { hasOnClick, label, monospace, ...rest } = args;
   return (
-    <Label
-      onClick={hasOnClick ? action('clicked') : undefined}
-      monospace={monospace}
-      {...rest}
-    >
-      {label}
-    </Label>
+    <>
+      <h4>Non-interactive</h4>
+      {options.map((opt: Type) => (
+        <Label key={opt} type={opt}>
+          {`style: "${opt}"`}
+        </Label>
+      ))}
+      <br />
+      <h4>Interactive</h4>
+      {options.map((opt: Type) => (
+        <Label key={opt} type={opt} {...props} onClick={onClick}>
+          {`style: "${opt}"`}
+        </Label>
+      ))}
+      <h4>Reusable Labels</h4>
+      <h5>DatasetType</h5>
+      <div>
+        <DatasetTypeLabel datasetType="physical" />
+        <DatasetTypeLabel datasetType="virtual" />
+      </div>
+      <h5>PublishedLabel</h5>
+      <PublishedLabel isPublished />
+      <PublishedLabel isPublished={false} />
+    </>
   );
 };
 
-InteractiveLabel.args = {
+// Define default arguments for Storybook
+LabelGallery.args = {
   hasOnClick: true,
-  label: 'Example',
-  monospace: true,
+  monospace: false,
+};
+
+// Define argument types for Storybook controls
+LabelGallery.argTypes = {
+  monospace: {
+    name: 'monospace',
+    control: { type: 'boolean' },
+  },
+  hasOnClick: {
+    name: 'hasOnClick',
+    control: { type: 'boolean' },
+  },
 };
diff --git a/superset-frontend/src/components/Label/Label.test.tsx 
b/superset-frontend/src/components/Label/Label.test.tsx
index fdf85b9c93..ac57250bc7 100644
--- a/superset-frontend/src/components/Label/Label.test.tsx
+++ b/superset-frontend/src/components/Label/Label.test.tsx
@@ -37,7 +37,9 @@ test('works with an onClick handler', () => {
 // test stories from the storybook!
 test('renders all the storybook gallery variants', () => {
   const { container } = render(<LabelGallery />);
+  const nonInteractiveLabelCount = 4;
+  const renderedLabelCount = options.length * 2 + nonInteractiveLabelCount;
   expect(container.querySelectorAll('.ant-tag')).toHaveLength(
-    options.length * 2,
+    renderedLabelCount,
   );
 });
diff --git a/superset-frontend/src/components/Label/index.tsx 
b/superset-frontend/src/components/Label/index.tsx
index d904a445be..b745084076 100644
--- a/superset-frontend/src/components/Label/index.tsx
+++ b/superset-frontend/src/components/Label/index.tsx
@@ -25,6 +25,8 @@ import {
 
 import { Tag } from 'src/components';
 import { useTheme } from '@superset-ui/core';
+import DatasetTypeLabel from 'src/components/Label/reusable/DatasetTypeLabel';
+import PublishedLabel from 'src/components/Label/reusable/PublishedLabel';
 
 export type OnClickHandler = MouseEventHandler<HTMLElement>;
 
@@ -47,6 +49,7 @@ export interface LabelProps extends 
HTMLAttributes<HTMLSpanElement> {
   children?: ReactNode;
   role?: string;
   monospace?: boolean;
+  icon?: ReactNode;
 }
 
 export default function Label(props: LabelProps) {
@@ -58,6 +61,7 @@ export default function Label(props: LabelProps) {
     style,
     onClick,
     children,
+    icon,
     ...rest
   } = props;
   const {
@@ -71,37 +75,44 @@ export default function Label(props: LabelProps) {
     info,
   } = colors;
 
-  let backgroundColor = grayscale.light3;
-  let backgroundColorHover = onClick ? primary.light2 : grayscale.light3;
-  let borderColor = onClick ? grayscale.light2 : 'transparent';
-  let borderColorHover = onClick ? primary.light1 : 'transparent';
-  let color = grayscale.dark1;
+  let baseColor;
+  if (type === 'primary') {
+    baseColor = primary;
+  } else if (type === 'secondary') {
+    baseColor = secondary;
+  } else if (type === 'success') {
+    baseColor = success;
+  } else if (type === 'alert') {
+    baseColor = alert;
+  } else if (type === 'warning') {
+    baseColor = warning;
+  } else if (type === 'danger') {
+    baseColor = error;
+  } else if (type === 'info') {
+    baseColor = info;
+  } else {
+    baseColor = grayscale;
+  }
+  const color = baseColor.dark2;
+  let borderColor = baseColor.light1;
+  let backgroundColor = baseColor.light2;
+
+  // TODO - REMOVE IF BLOCK LOGIC WHEN shades are fixed to be aligned in terms 
of brightness
+  // currently shades for >=light2 are not aligned for primary, default and 
secondary
+  if (['default', 'primary', 'secondary'].includes(type)) {
+    // @ts-ignore
+    backgroundColor = baseColor.light4;
+    borderColor = baseColor.light2;
+  }
 
-  if (type !== 'default') {
-    color = grayscale.light4;
+  const backgroundColorHover = onClick ? baseColor.light1 : backgroundColor;
+  const borderColorHover = onClick ? baseColor.base : borderColor;
 
-    let baseColor;
-    if (type === 'alert') {
-      color = grayscale.dark1;
-      baseColor = alert;
-    } else if (type === 'success') {
-      baseColor = success;
-    } else if (type === 'warning') {
-      baseColor = warning;
-    } else if (type === 'danger') {
-      baseColor = error;
-    } else if (type === 'info') {
-      baseColor = info;
-    } else if (type === 'secondary') {
-      baseColor = secondary;
-    } else {
-      baseColor = primary;
-    }
-    backgroundColor = baseColor.base;
-    backgroundColorHover = onClick ? baseColor.dark1 : baseColor.base;
-    borderColor = onClick ? baseColor.dark1 : 'transparent';
-    borderColorHover = onClick ? baseColor.dark2 : 'transparent';
+  if (type === 'default') {
+    // Lighter for default
+    backgroundColor = grayscale.light3;
   }
+
   const css = {
     transition: `background-color ${transitionTiming}s`,
     whiteSpace: 'nowrap',
@@ -109,11 +120,14 @@ export default function Label(props: LabelProps) {
     overflow: 'hidden',
     textOverflow: 'ellipsis',
     backgroundColor,
+    borderRadius: 8,
     borderColor,
-    borderRadius: 21,
     padding: '0.35em 0.8em',
     lineHeight: 1,
     color,
+    display: 'inline-flex',
+    verticalAlign: 'middle',
+    alignItems: 'center',
     maxWidth: '100%',
     '&:hover': {
       backgroundColor: backgroundColorHover,
@@ -124,12 +138,12 @@ export default function Label(props: LabelProps) {
   if (monospace) {
     css['font-family'] = theme.typography.families.monospace;
   }
-
   return (
     <Tag
       onClick={onClick}
       role={onClick ? 'button' : undefined}
       style={style}
+      icon={icon}
       {...rest}
       css={css}
     >
@@ -137,3 +151,4 @@ export default function Label(props: LabelProps) {
     </Tag>
   );
 }
+export { DatasetTypeLabel, PublishedLabel };
diff --git 
a/superset-frontend/src/components/Label/reusable/DatasetTypeLabel.tsx 
b/superset-frontend/src/components/Label/reusable/DatasetTypeLabel.tsx
new file mode 100644
index 0000000000..7379665583
--- /dev/null
+++ b/superset-frontend/src/components/Label/reusable/DatasetTypeLabel.tsx
@@ -0,0 +1,49 @@
+/**
+ * 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 Icons from 'src/components/Icons';
+import Label from 'src/components/Label';
+import { t } from '@superset-ui/core';
+
+// Define the prop types for DatasetTypeLabel
+interface DatasetTypeLabelProps {
+  datasetType: 'physical' | 'virtual'; // Accepts only 'physical' or 'virtual'
+}
+
+const SIZE = 's'; // Define the size as a constant
+
+const DatasetTypeLabel: React.FC<DatasetTypeLabelProps> = ({ datasetType }) => 
{
+  const label: string =
+    datasetType === 'physical' ? t('Physical') : t('Virtual');
+  const icon =
+    datasetType === 'physical' ? (
+      <Icons.Table iconSize={SIZE} />
+    ) : (
+      <Icons.ConsoleSqlOutlined iconSize={SIZE} />
+    );
+  const labelType: 'primary' | 'secondary' =
+    datasetType === 'physical' ? 'primary' : 'secondary';
+
+  return (
+    <Label icon={icon} type={labelType}>
+      {label}
+    </Label>
+  );
+};
+
+export default DatasetTypeLabel;
diff --git 
a/superset-frontend/packages/superset-ui-demo/storybook/stories/superset-ui-style/Theme.stories.tsx
 b/superset-frontend/src/components/Label/reusable/PublishedLabel.tsx
similarity index 51%
copy from 
superset-frontend/packages/superset-ui-demo/storybook/stories/superset-ui-style/Theme.stories.tsx
copy to superset-frontend/src/components/Label/reusable/PublishedLabel.tsx
index 63ede4a8a7..a73be8609e 100644
--- 
a/superset-frontend/packages/superset-ui-demo/storybook/stories/superset-ui-style/Theme.stories.tsx
+++ b/superset-frontend/src/components/Label/reusable/PublishedLabel.tsx
@@ -1,4 +1,4 @@
-/*
+/**
  * 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
@@ -16,32 +16,33 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+import Icons from 'src/components/Icons';
+import Label from 'src/components/Label';
+import { t } from '@superset-ui/core';
 
-import { supersetTheme } from '@superset-ui/core';
+// Define props for the PublishedLabel component
+interface PublishedLabelProps {
+  isPublished: boolean; // Whether the item is published
+  onClick?: () => void; // Optional click handler
+}
 
-export default {
-  title: 'Core Packages/@superset-ui-style',
-};
+const PublishedLabel: React.FC<PublishedLabelProps> = ({
+  isPublished,
+  onClick,
+}) => {
+  const label = isPublished ? t('Published') : t('Draft');
+  const icon = isPublished ? (
+    <Icons.CircleCheck iconSize="s" />
+  ) : (
+    <Icons.Minus iconSize="s" />
+  );
+  const labelType = isPublished ? 'primary' : 'secondary';
 
-export const ThemeColors = () => {
-  const { colors } = supersetTheme;
-  return Object.keys(colors).map(collection => (
-    <div>
-      <h2>{collection}</h2>
-      <table style={{ width: '300px' }}>
-        {Object.keys(colors[collection]).map(k => {
-          const hex = colors[collection][k];
-          return (
-            <tr>
-              <td>{k}</td>
-              <td>
-                <code>{hex}</code>
-              </td>
-              <td style={{ width: '150px', backgroundColor: hex }} />
-            </tr>
-          );
-        })}
-      </table>
-    </div>
-  ));
+  return (
+    <Label type={labelType} icon={icon} onClick={onClick}>
+      {label}
+    </Label>
+  );
 };
+
+export default PublishedLabel;
diff --git a/superset-frontend/src/components/Timer/index.tsx 
b/superset-frontend/src/components/Timer/index.tsx
index 4237c9f1ed..f0ae3cf059 100644
--- a/superset-frontend/src/components/Timer/index.tsx
+++ b/superset-frontend/src/components/Timer/index.tsx
@@ -19,6 +19,7 @@
 import { useEffect, useRef, useState } from 'react';
 import { styled } from '@superset-ui/core';
 import Label, { Type } from 'src/components/Label';
+import Icons from 'src/components/Icons';
 
 import { now, fDuration } from 'src/utils/dates';
 
@@ -68,7 +69,7 @@ export default function Timer({
   }, [endTime, isRunning, startTime]);
 
   return (
-    <TimerLabel type={status} role="timer">
+    <TimerLabel icon={<Icons.Clock iconSize="m" />} type={status} role="timer">
       {clockStr}
     </TimerLabel>
   );
diff --git 
a/superset-frontend/src/dashboard/components/PublishedStatus/index.tsx 
b/superset-frontend/src/dashboard/components/PublishedStatus/index.tsx
index 3fdb0de11a..29fb30484c 100644
--- a/superset-frontend/src/dashboard/components/PublishedStatus/index.tsx
+++ b/superset-frontend/src/dashboard/components/PublishedStatus/index.tsx
@@ -19,7 +19,7 @@
 import { Component } from 'react';
 import { t } from '@superset-ui/core';
 import { Tooltip } from 'src/components/Tooltip';
-import Label from 'src/components/Label';
+import { PublishedLabel } from 'src/components/Label';
 import { HeaderProps, HeaderDropdownProps } from '../Header/types';
 
 export type DashboardPublishedStatusType = {
@@ -67,13 +67,12 @@ export default class PublishedStatus extends 
Component<DashboardPublishedStatusT
             placement="bottom"
             title={draftButtonTooltip}
           >
-            <Label
-              onClick={() => {
-                this.togglePublished();
-              }}
-            >
-              {t('Draft')}
-            </Label>
+            <div>
+              <PublishedLabel
+                isPublished={isPublished}
+                onClick={this.togglePublished}
+              />
+            </div>
           </Tooltip>
         );
       }
@@ -83,7 +82,9 @@ export default class PublishedStatus extends 
Component<DashboardPublishedStatusT
           placement="bottom"
           title={draftDivTooltip}
         >
-          <Label>{t('Draft')}</Label>
+          <div>
+            <PublishedLabel isPublished={isPublished} />
+          </div>
         </Tooltip>
       );
     }
@@ -96,13 +97,12 @@ export default class PublishedStatus extends 
Component<DashboardPublishedStatusT
           placement="bottom"
           title={publishedTooltip}
         >
-          <Label
-            onClick={() => {
-              this.togglePublished();
-            }}
-          >
-            {t('Published')}
-          </Label>
+          <div>
+            <PublishedLabel
+              isPublished={isPublished}
+              onClick={this.togglePublished}
+            />
+          </div>
         </Tooltip>
       );
     }
diff --git a/superset-frontend/src/pages/DashboardList/index.tsx 
b/superset-frontend/src/pages/DashboardList/index.tsx
index 361168f418..93d2904086 100644
--- a/superset-frontend/src/pages/DashboardList/index.tsx
+++ b/superset-frontend/src/pages/DashboardList/index.tsx
@@ -34,6 +34,7 @@ import {
 } from 'src/views/CRUD/utils';
 import { useListViewResource, useFavoriteStatus } from 'src/views/CRUD/hooks';
 import ConfirmStatusChange from 'src/components/ConfirmStatusChange';
+import { PublishedLabel } from 'src/components/Label';
 import { TagsList } from 'src/components/Tags';
 import handleResourceExport from 'src/utils/export';
 import Loading from 'src/components/Loading';
@@ -343,8 +344,9 @@ function DashboardList(props: DashboardListProps) {
           row: {
             original: { status },
           },
-        }: any) =>
-          status === DashboardStatus.PUBLISHED ? t('Published') : t('Draft'),
+        }: any) => (
+          <PublishedLabel isPublished={status === DashboardStatus.PUBLISHED} />
+        ),
         Header: t('Status'),
         accessor: 'published',
         size: 'xl',
diff --git a/superset-frontend/src/pages/DatasetList/index.tsx 
b/superset-frontend/src/pages/DatasetList/index.tsx
index d90f60c592..49af61753d 100644
--- a/superset-frontend/src/pages/DatasetList/index.tsx
+++ b/superset-frontend/src/pages/DatasetList/index.tsx
@@ -41,6 +41,7 @@ import ListView, {
   Filters,
   FilterOperator,
 } from 'src/components/ListView';
+import { DatasetTypeLabel } from 'src/components/Label';
 import Loading from 'src/components/Loading';
 import SubMenu, { SubMenuProps, ButtonProps } from 'src/features/home/SubMenu';
 import Owner from 'src/types/Owner';
@@ -279,24 +280,7 @@ const DatasetList: FunctionComponent<DatasetListProps> = ({
           row: {
             original: { kind },
           },
-        }: any) => {
-          if (kind === 'physical') {
-            return (
-              <Tooltip
-                id="physical-dataset-tooltip"
-                title={t('Physical dataset')}
-              >
-                <Icons.DatasetPhysical />
-              </Tooltip>
-            );
-          }
-
-          return (
-            <Tooltip id="virtual-dataset-tooltip" title={t('Virtual dataset')}>
-              <Icons.DatasetVirtual />
-            </Tooltip>
-          );
-        },
+        }: any) => null,
         accessor: 'kind_icon',
         disableSortBy: true,
         size: 'xs',
@@ -360,7 +344,7 @@ const DatasetList: FunctionComponent<DatasetListProps> = ({
           row: {
             original: { kind },
           },
-        }: any) => (kind === 'physical' ? t('Physical') : t('Virtual')),
+        }: any) => <DatasetTypeLabel datasetType={kind} />,
         Header: t('Type'),
         accessor: 'kind',
         disableSortBy: true,

Reply via email to