You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by ms...@apache.org on 2025/06/16 17:06:36 UTC

(superset) 01/01: feat(Dashboard): Row limit warning in dashboards

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

msyavuz pushed a commit to branch msyavuz/feat/row-limit-dashboard
in repository https://gitbox.apache.org/repos/asf/superset.git

commit d4179f88cd0c768fcc16e4e0eae823c042013af7
Author: Mehmet Salih Yavuz <sa...@proton.me>
AuthorDate: Mon Jun 16 20:06:13 2025 +0300

    feat(Dashboard): Row limit warning in dashboards
---
 .../Chart/DrillDetail/DrillDetailTableControls.tsx |  2 +-
 .../RowCountLabel/RowCountLabel.stories.tsx        |  0
 .../RowCountLabel/RowCountLabel.test.tsx           |  0
 .../components/RowCountLabel/index.tsx             |  9 ++---
 .../src/dashboard/components/SliceHeader/index.tsx | 42 ++++++++++++++++++++--
 .../components/SliceHeaderControls/index.tsx       |  3 ++
 .../src/explore/components/ChartPills.tsx          |  3 +-
 .../components/DataTableControls.tsx               |  2 +-
 8 files changed, 52 insertions(+), 9 deletions(-)

diff --git a/superset-frontend/src/components/Chart/DrillDetail/DrillDetailTableControls.tsx b/superset-frontend/src/components/Chart/DrillDetail/DrillDetailTableControls.tsx
index 1c756dd9c5..e42ce2b4b4 100644
--- a/superset-frontend/src/components/Chart/DrillDetail/DrillDetailTableControls.tsx
+++ b/superset-frontend/src/components/Chart/DrillDetail/DrillDetailTableControls.tsx
@@ -26,7 +26,7 @@ import {
   t,
   useTheme,
 } from '@superset-ui/core';
-import RowCountLabel from 'src/explore/components/RowCountLabel';
+import RowCountLabel from 'src/components/RowCountLabel';
 import { Icons } from 'src/components/Icons';
 
 export type TableControlsProps = {
diff --git a/superset-frontend/src/explore/components/RowCountLabel/RowCountLabel.stories.tsx b/superset-frontend/src/components/RowCountLabel/RowCountLabel.stories.tsx
similarity index 100%
rename from superset-frontend/src/explore/components/RowCountLabel/RowCountLabel.stories.tsx
rename to superset-frontend/src/components/RowCountLabel/RowCountLabel.stories.tsx
diff --git a/superset-frontend/src/explore/components/RowCountLabel/RowCountLabel.test.tsx b/superset-frontend/src/components/RowCountLabel/RowCountLabel.test.tsx
similarity index 100%
rename from superset-frontend/src/explore/components/RowCountLabel/RowCountLabel.test.tsx
rename to superset-frontend/src/components/RowCountLabel/RowCountLabel.test.tsx
diff --git a/superset-frontend/src/explore/components/RowCountLabel/index.tsx b/superset-frontend/src/components/RowCountLabel/index.tsx
similarity index 92%
rename from superset-frontend/src/explore/components/RowCountLabel/index.tsx
rename to superset-frontend/src/components/RowCountLabel/index.tsx
index 85f28a5be3..3cbeb9302f 100644
--- a/superset-frontend/src/explore/components/RowCountLabel/index.tsx
+++ b/superset-frontend/src/components/RowCountLabel/index.tsx
@@ -25,6 +25,7 @@ type RowCountLabelProps = {
   rowcount?: number;
   limit?: number;
   loading?: boolean;
+  label?: JSX.Element;
 };
 
 const limitReachedMsg = t(
@@ -32,12 +33,12 @@ const limitReachedMsg = t(
 );
 
 export default function RowCountLabel(props: RowCountLabelProps) {
-  const { rowcount = 0, limit = null, loading } = props;
+  const { rowcount = 0, limit = null, loading, label } = props;
   const limitReached = limit && rowcount >= limit;
   const type =
     limitReached || (rowcount === 0 && !loading) ? 'danger' : 'default';
   const formattedRowCount = getNumberFormatter()(rowcount);
-  const label = (
+  const labelText = (
     <Label type={type}>
       {loading ? (
         t('Loading...')
@@ -50,10 +51,10 @@ export default function RowCountLabel(props: RowCountLabelProps) {
   );
   return limitReached ? (
     <Tooltip id="tt-rowcount-tooltip" title={<span>{limitReachedMsg}</span>}>
-      {label}
+      {label || labelText}
     </Tooltip>
   ) : (
-    label
+    label || labelText
   );
 }
 
diff --git a/superset-frontend/src/dashboard/components/SliceHeader/index.tsx b/superset-frontend/src/dashboard/components/SliceHeader/index.tsx
index 3de1296610..adaffd8746 100644
--- a/superset-frontend/src/dashboard/components/SliceHeader/index.tsx
+++ b/superset-frontend/src/dashboard/components/SliceHeader/index.tsx
@@ -24,7 +24,13 @@ import {
   useRef,
   useState,
 } from 'react';
-import { css, getExtensionsRegistry, styled, t } from '@superset-ui/core';
+import {
+  css,
+  getExtensionsRegistry,
+  styled,
+  t,
+  useTheme,
+} from '@superset-ui/core';
 import { useUiConfig } from 'src/components/UiConfigContext';
 import { Tooltip } from 'src/components/Tooltip';
 import { useSelector } from 'react-redux';
@@ -33,9 +39,10 @@ import SliceHeaderControls from 'src/dashboard/components/SliceHeaderControls';
 import { SliceHeaderControlsProps } from 'src/dashboard/components/SliceHeaderControls/types';
 import FiltersBadge from 'src/dashboard/components/FiltersBadge';
 import { Icons } from 'src/components/Icons';
-import { RootState } from 'src/dashboard/types';
+import { Chart, RootState } from 'src/dashboard/types';
 import { getSliceHeaderTooltip } from 'src/dashboard/util/getSliceHeaderTooltip';
 import { DashboardPageIdContext } from 'src/dashboard/containers/DashboardPage';
+import RowCountLabel from 'src/components/RowCountLabel';
 
 const extensionsRegistry = getExtensionsRegistry();
 
@@ -176,6 +183,17 @@ const SliceHeader = forwardRef<HTMLDivElement, SliceHeaderProps>(
       ({ dashboardInfo }) => dashboardInfo.crossFiltersEnabled,
     );
 
+    const chart = useSelector<RootState, Chart>(
+      state => state.charts[slice.slice_id],
+    );
+
+    const theme = useTheme();
+
+    const firstQueryResponse = chart.queriesResponse?.[0];
+
+    const rowLimit = Number(formData.row_limit || 0);
+    const sqlRowCount = Number(firstQueryResponse?.sql_rowcount || 0);
+
     const canExplore = !editMode && supersetCanExplore;
 
     useEffect(() => {
@@ -262,9 +280,29 @@ const SliceHeader = forwardRef<HTMLDivElement, SliceHeaderProps>(
                   <CrossFilterIcon iconSize="m" />
                 </Tooltip>
               )}
+
               {!uiConfig.hideChartControls && (
                 <FiltersBadge chartId={slice.slice_id} />
               )}
+
+              {sqlRowCount === rowLimit && (
+                <RowCountLabel
+                  css={theme => css`
+                    margin-right: -${theme.gridUnit * 4}px;
+                  `}
+                  rowcount={sqlRowCount}
+                  limit={rowLimit}
+                  label={
+                    <Icons.WarningOutlined
+                      iconSize="l"
+                      iconColor={theme.colors.warning.base}
+                      css={theme => css`
+                        padding: ${theme.gridUnit}px;
+                      `}
+                    />
+                  }
+                />
+              )}
               {!uiConfig.hideChartControls && (
                 <SliceHeaderControls
                   slice={slice}
diff --git a/superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx b/superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx
index 83b1639278..f93255994b 100644
--- a/superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx
+++ b/superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx
@@ -527,6 +527,9 @@ const SliceHeaderControls = (
           id={`slice_${slice.slice_id}-controls`}
           aria-label="More Options"
           aria-haspopup="true"
+          css={theme => css`
+            padding: ${theme.gridUnit * 1.5}px;
+          `}
         >
           <VerticalDotsTrigger />
         </Button>
diff --git a/superset-frontend/src/explore/components/ChartPills.tsx b/superset-frontend/src/explore/components/ChartPills.tsx
index 0eec7aa143..c591284efe 100644
--- a/superset-frontend/src/explore/components/ChartPills.tsx
+++ b/superset-frontend/src/explore/components/ChartPills.tsx
@@ -18,7 +18,7 @@
  */
 import { forwardRef, RefObject } from 'react';
 import { css, QueryData, SupersetTheme } from '@superset-ui/core';
-import RowCountLabel from 'src/explore/components/RowCountLabel';
+import RowCountLabel from 'src/components/RowCountLabel';
 import CachedLabel from 'src/components/CachedLabel';
 import Timer from 'src/components/Timer';
 import { Type } from 'src/components/Label';
@@ -52,6 +52,7 @@ export const ChartPills = forwardRef(
   ) => {
     const isLoading = chartStatus === 'loading';
     const firstQueryResponse = queriesResponse?.[0];
+
     return (
       <div ref={ref}>
         <div
diff --git a/superset-frontend/src/explore/components/DataTablesPane/components/DataTableControls.tsx b/superset-frontend/src/explore/components/DataTablesPane/components/DataTableControls.tsx
index 30dfb87c74..9a95e01928 100644
--- a/superset-frontend/src/explore/components/DataTablesPane/components/DataTableControls.tsx
+++ b/superset-frontend/src/explore/components/DataTablesPane/components/DataTableControls.tsx
@@ -25,7 +25,7 @@ import {
 } from 'src/explore/components/DataTableControl';
 import { applyFormattingToTabularData } from 'src/utils/common';
 import { getTimeColumns } from 'src/explore/components/DataTableControl/utils';
-import RowCountLabel from 'src/explore/components/RowCountLabel';
+import RowCountLabel from 'src/components/RowCountLabel';
 import { TableControlsProps } from '../types';
 
 export const TableControlsWrapper = styled.div`