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

rusackas 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 4ff9aac1fa feat(sqllab): giving the query history pane a facelift 
(#31316)
4ff9aac1fa is described below

commit 4ff9aac1fae2d88fd7667317c706256d3cfcb4f4
Author: Maxime Beauchemin <[email protected]>
AuthorDate: Thu Dec 12 15:30:50 2024 -0800

    feat(sqllab): giving the query history pane a facelift (#31316)
---
 superset-frontend/src/SqlLab/actions/sqlLab.js     |  4 +-
 .../src/SqlLab/components/QueryTable/index.tsx     | 96 ++++++++++++++++------
 .../src/components/Icons/Icons.stories.tsx         | 13 ++-
 .../src/components/Label/Label.stories.tsx         |  9 +-
 superset-frontend/src/components/Label/index.tsx   | 54 +++++++-----
 5 files changed, 121 insertions(+), 55 deletions(-)

diff --git a/superset-frontend/src/SqlLab/actions/sqlLab.js 
b/superset-frontend/src/SqlLab/actions/sqlLab.js
index 568dbb9b1f..4fd7708338 100644
--- a/superset-frontend/src/SqlLab/actions/sqlLab.js
+++ b/superset-frontend/src/SqlLab/actions/sqlLab.js
@@ -421,9 +421,7 @@ export function postStopQuery(query) {
     })
       .then(() => dispatch(stopQuery(query)))
       .then(() => dispatch(addSuccessToast(t('Query was stopped.'))))
-      .catch(() =>
-        dispatch(addDangerToast(t('Failed at stopping query. %s', query.id))),
-      );
+      .catch(() => dispatch(addDangerToast(t('Failed to stop query.'))));
   };
 }
 
diff --git a/superset-frontend/src/SqlLab/components/QueryTable/index.tsx 
b/superset-frontend/src/SqlLab/components/QueryTable/index.tsx
index 916c04aece..43cc5da7b0 100644
--- a/superset-frontend/src/SqlLab/components/QueryTable/index.tsx
+++ b/superset-frontend/src/SqlLab/components/QueryTable/index.tsx
@@ -16,11 +16,10 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-import { useMemo } from 'react';
+import { useMemo, ReactNode } from 'react';
 import moment from 'moment';
 import Card from 'src/components/Card';
 import ProgressBar from 'src/components/ProgressBar';
-import Label from 'src/components/Label';
 import { t, useTheme, QueryResponse } from '@superset-ui/core';
 import { useDispatch, useSelector } from 'react-redux';
 
@@ -35,6 +34,7 @@ import TableView from 'src/components/TableView';
 import Button from 'src/components/Button';
 import { fDuration } from 'src/utils/dates';
 import Icons from 'src/components/Icons';
+import Label from 'src/components/Label';
 import { Tooltip } from 'src/components/Tooltip';
 import { SqlLabRootState } from 'src/SqlLab/types';
 import ModalTrigger from 'src/components/ModalTrigger';
@@ -44,11 +44,16 @@ import HighlightedSql from '../HighlightedSql';
 import { StaticPosition, verticalAlign, StyledTooltip } from './styles';
 
 interface QueryTableQuery
-  extends Omit<QueryResponse, 'state' | 'sql' | 'progress' | 'results'> {
+  extends Omit<
+    QueryResponse,
+    'state' | 'sql' | 'progress' | 'results' | 'duration' | 'started'
+  > {
   state?: Record<string, any>;
   sql?: Record<string, any>;
   progress?: Record<string, any>;
   results?: Record<string, any>;
+  duration?: ReactNode;
+  started?: ReactNode;
 }
 
 interface QueryTableProps {
@@ -125,55 +130,95 @@ const QueryTable = ({
     const statusAttributes = {
       success: {
         config: {
-          icon: <Icons.Check iconColor={theme.colors.success.base} />,
+          icon: (
+            <Icons.CheckOutlined
+              iconColor={theme.colors.success.base}
+              iconSize="m"
+            />
+          ),
+          // icon: <Icons.Edit iconSize="xl" />,
           label: t('Success'),
         },
       },
       failed: {
         config: {
-          icon: <Icons.XSmall iconColor={theme.colors.error.base} />,
+          icon: (
+            <Icons.CloseOutlined
+              iconColor={theme.colors.error.base}
+              iconSize="m"
+            />
+          ),
           label: t('Failed'),
         },
       },
       stopped: {
         config: {
-          icon: <Icons.XSmall iconColor={theme.colors.error.base} />,
+          icon: (
+            <Icons.CloseOutlined
+              iconColor={theme.colors.error.base}
+              iconSize="m"
+            />
+          ),
           label: t('Failed'),
         },
       },
       running: {
         config: {
-          icon: <Icons.Running iconColor={theme.colors.primary.base} />,
+          icon: (
+            <Icons.LoadingOutlined
+              iconColor={theme.colors.primary.base}
+              iconSize="m"
+            />
+          ),
           label: t('Running'),
         },
       },
       fetching: {
         config: {
-          icon: <Icons.Queued iconColor={theme.colors.primary.base} />,
+          icon: (
+            <Icons.LoadingOutlined
+              iconColor={theme.colors.primary.base}
+              iconSize="m"
+            />
+          ),
           label: t('Fetching'),
         },
       },
       timed_out: {
         config: {
-          icon: <Icons.Offline iconColor={theme.colors.grayscale.light1} />,
+          icon: (
+            <Icons.Clock iconColor={theme.colors.error.base} iconSize="m" />
+          ),
           label: t('Offline'),
         },
       },
       scheduled: {
         config: {
-          icon: <Icons.Queued iconColor={theme.colors.grayscale.base} />,
+          icon: (
+            <Icons.LoadingOutlined
+              iconColor={theme.colors.warning.base}
+              iconSize="m"
+            />
+          ),
           label: t('Scheduled'),
         },
       },
       pending: {
         config: {
-          icon: <Icons.Queued iconColor={theme.colors.grayscale.base} />,
+          icon: (
+            <Icons.LoadingOutlined
+              iconColor={theme.colors.warning.base}
+              iconSize="m"
+            />
+          ),
           label: t('Scheduled'),
         },
       },
       error: {
         config: {
-          icon: <Icons.Error iconColor={theme.colors.error.base} />,
+          icon: (
+            <Icons.Error iconColor={theme.colors.error.base} iconSize="m" />
+          ),
           label: t('Unknown Status'),
         },
       },
@@ -187,16 +232,10 @@ const QueryTable = ({
         const status = statusAttributes[state] || statusAttributes.error;
 
         if (q.endDttm) {
-          q.duration = fDuration(q.startDttm, q.endDttm);
+          q.duration = (
+            <Label monospace>{fDuration(q.startDttm, q.endDttm)}</Label>
+          );
         }
-        const time = moment(q.startDttm).format().split('T');
-        q.time = (
-          <div>
-            <span>
-              {time[0]} <br /> {time[1]}
-            </span>
-          </div>
-        );
         q.user = (
           <Button
             buttonSize="small"
@@ -215,7 +254,9 @@ const QueryTable = ({
             {q.db}
           </Button>
         );
-        q.started = moment(q.startDttm).format('L HH:mm:ss');
+        q.started = (
+          <Label monospace>{moment(q.startDttm).format('L HH:mm:ss')}</Label>
+        );
         q.querylink = (
           <Button
             buttonSize="small"
@@ -241,9 +282,9 @@ const QueryTable = ({
             <ModalTrigger
               className="ResultsModal"
               triggerNode={
-                <Label type="info" className="pointer">
+                <Button buttonSize="xsmall" buttonStyle="tertiary">
                   {t('View')}
-                </Label>
+                </Button>
               }
               modalTitle={t('Data preview')}
               beforeOpen={() => openAsyncResults(query, displayLimit)}
@@ -275,9 +316,7 @@ const QueryTable = ({
             <ProgressBar percent={parseInt(progress.toFixed(0), 10)} striped />
           );
         q.state = (
-          <Tooltip title={status.config.label} placement="bottom">
-            <span>{status.config.icon}</span>
-          </Tooltip>
+          <Tooltip title={status.config.label}>{status.config.icon}</Tooltip>
         );
         q.actions = (
           <div>
@@ -287,6 +326,7 @@ const QueryTable = ({
                 'Overwrite text in the editor with a query on this table',
               )}
               placement="top"
+              className="pointer"
             >
               <Icons.Edit iconSize="xl" />
             </StyledTooltip>
@@ -294,6 +334,7 @@ const QueryTable = ({
               onClick={() => openQueryInNewTab(query)}
               tooltip={t('Run query in a new tab')}
               placement="top"
+              className="pointer"
             >
               <Icons.PlusCircleOutlined iconSize="xl" css={verticalAlign} />
             </StyledTooltip>
@@ -301,6 +342,7 @@ const QueryTable = ({
               <StyledTooltip
                 tooltip={t('Remove query from log')}
                 onClick={() => dispatch(removeQuery(query))}
+                className="pointer"
               >
                 <Icons.Trash iconSize="xl" />
               </StyledTooltip>
diff --git a/superset-frontend/src/components/Icons/Icons.stories.tsx 
b/superset-frontend/src/components/Icons/Icons.stories.tsx
index db7410ca62..5a21daf5fb 100644
--- a/superset-frontend/src/components/Icons/Icons.stories.tsx
+++ b/superset-frontend/src/components/Icons/Icons.stories.tsx
@@ -44,10 +44,19 @@ const IconBlock = styled.div`
   flex-direction: column;
   align-items: center;
   padding: ${({ theme }) => theme.gridUnit * 2}px;
+
+  span {
+    margin-top: ${({ theme }) =>
+      2 * theme.gridUnit}px; // Add spacing between icon and name
+    font-size: ${({ theme }) =>
+      theme.typography.sizes.m}; // Optional: adjust font size for elegance
+    color: ${({ theme }) =>
+      theme.colors.grayscale.base}; // Optional: subtle color for the name
+  }
 `;
 
 export const InteractiveIcons = ({
-  showNames,
+  showNames = true,
   ...rest
 }: IconType & { showNames: boolean }) => (
   <IconSet>
@@ -56,7 +65,7 @@ export const InteractiveIcons = ({
       return (
         <IconBlock key={k}>
           <IconComponent {...rest} />
-          {showNames && k}
+          {showNames && <span>{k}</span>}
         </IconBlock>
       );
     })}
diff --git a/superset-frontend/src/components/Label/Label.stories.tsx 
b/superset-frontend/src/components/Label/Label.stories.tsx
index d502e160c5..5c46182465 100644
--- a/superset-frontend/src/components/Label/Label.stories.tsx
+++ b/superset-frontend/src/components/Label/Label.stories.tsx
@@ -55,9 +55,13 @@ export const LabelGallery = () => (
 );
 
 export const InteractiveLabel = (args: any) => {
-  const { hasOnClick, label, ...rest } = args;
+  const { hasOnClick, label, monospace, ...rest } = args;
   return (
-    <Label onClick={hasOnClick ? action('clicked') : undefined} {...rest}>
+    <Label
+      onClick={hasOnClick ? action('clicked') : undefined}
+      monospace={monospace}
+      {...rest}
+    >
       {label}
     </Label>
   );
@@ -66,4 +70,5 @@ export const InteractiveLabel = (args: any) => {
 InteractiveLabel.args = {
   hasOnClick: true,
   label: 'Example',
+  monospace: true,
 };
diff --git a/superset-frontend/src/components/Label/index.tsx 
b/superset-frontend/src/components/Label/index.tsx
index 30f3ca6aed..d904a445be 100644
--- a/superset-frontend/src/components/Label/index.tsx
+++ b/superset-frontend/src/components/Label/index.tsx
@@ -46,12 +46,20 @@ export interface LabelProps extends 
HTMLAttributes<HTMLSpanElement> {
   style?: CSSProperties;
   children?: ReactNode;
   role?: string;
+  monospace?: boolean;
 }
 
 export default function Label(props: LabelProps) {
   const theme = useTheme();
   const { colors, transitionTiming } = theme;
-  const { type = 'default', onClick, children, ...rest } = props;
+  const {
+    type = 'default',
+    monospace = false,
+    style,
+    onClick,
+    children,
+    ...rest
+  } = props;
   const {
     alert,
     primary,
@@ -89,37 +97,41 @@ export default function Label(props: LabelProps) {
     } else {
       baseColor = primary;
     }
-
     backgroundColor = baseColor.base;
     backgroundColorHover = onClick ? baseColor.dark1 : baseColor.base;
     borderColor = onClick ? baseColor.dark1 : 'transparent';
     borderColorHover = onClick ? baseColor.dark2 : 'transparent';
   }
+  const css = {
+    transition: `background-color ${transitionTiming}s`,
+    whiteSpace: 'nowrap',
+    cursor: onClick ? 'pointer' : 'default',
+    overflow: 'hidden',
+    textOverflow: 'ellipsis',
+    backgroundColor,
+    borderColor,
+    borderRadius: 21,
+    padding: '0.35em 0.8em',
+    lineHeight: 1,
+    color,
+    maxWidth: '100%',
+    '&:hover': {
+      backgroundColor: backgroundColorHover,
+      borderColor: borderColorHover,
+      opacity: 1,
+    },
+  };
+  if (monospace) {
+    css['font-family'] = theme.typography.families.monospace;
+  }
 
   return (
     <Tag
       onClick={onClick}
       role={onClick ? 'button' : undefined}
+      style={style}
       {...rest}
-      css={{
-        transition: `background-color ${transitionTiming}s`,
-        whiteSpace: 'nowrap',
-        cursor: onClick ? 'pointer' : 'default',
-        overflow: 'hidden',
-        textOverflow: 'ellipsis',
-        backgroundColor,
-        borderColor,
-        borderRadius: 21,
-        padding: '0.35em 0.8em',
-        lineHeight: 1,
-        color,
-        maxWidth: '100%',
-        '&:hover': {
-          backgroundColor: backgroundColorHover,
-          borderColor: borderColorHover,
-          opacity: 1,
-        },
-      }}
+      css={css}
     >
       {children}
     </Tag>

Reply via email to