diff --git a/superset-frontend/package-lock.json b/superset-frontend/package-lock.json index 90ce4b0a7179c..597a05d566502 100644 --- a/superset-frontend/package-lock.json +++ b/superset-frontend/package-lock.json @@ -69231,6 +69231,7 @@ "peerDependencies": { "@superset-ui/chart-controls": "*", "@superset-ui/core": "*", + "memoize-one": "*", "react": "^16.13.1" } }, diff --git a/superset-frontend/packages/superset-ui-core/src/query/types/QueryResponse.ts b/superset-frontend/packages/superset-ui-core/src/query/types/QueryResponse.ts index 1705814df11e3..93c7475d42e11 100644 --- a/superset-frontend/packages/superset-ui-core/src/query/types/QueryResponse.ts +++ b/superset-frontend/packages/superset-ui-core/src/query/types/QueryResponse.ts @@ -67,6 +67,7 @@ export interface ChartDataResponseResult { is_cached: boolean; query: string; rowcount: number; + sql_rowcount: number; stacktrace: string | null; status: | 'stopped' diff --git a/superset-frontend/plugins/plugin-chart-table/test/testData.ts b/superset-frontend/plugins/plugin-chart-table/test/testData.ts index 24abc3381e49f..6c76e865e801a 100644 --- a/superset-frontend/plugins/plugin-chart-table/test/testData.ts +++ b/superset-frontend/plugins/plugin-chart-table/test/testData.ts @@ -80,6 +80,7 @@ const basicQueryResult: ChartDataResponseResult = { is_cached: false, query: 'SELECT ...', rowcount: 100, + sql_rowcount: 100, stacktrace: null, status: 'success', from_dttm: null, diff --git a/superset-frontend/src/components/Chart/DrillBy/useResultsTableView.tsx b/superset-frontend/src/components/Chart/DrillBy/useResultsTableView.tsx index b424b95ea558e..bab24fdd479a7 100644 --- a/superset-frontend/src/components/Chart/DrillBy/useResultsTableView.tsx +++ b/superset-frontend/src/components/Chart/DrillBy/useResultsTableView.tsx @@ -44,6 +44,7 @@ export const useResultsTableView = ( { - render(); - expect(screen.getByText('1 row')).toBeInTheDocument(); -}); - -test('Render a RowCount with multiple rows', () => { - render(); - expect(screen.getByText('3 rows')).toBeInTheDocument(); -}); - -test('Render a RowCount on loading', () => { - render(); - expect(screen.getByText('Loading...')).toBeInTheDocument(); -}); diff --git a/superset-frontend/src/explore/components/DataTableControl/index.tsx b/superset-frontend/src/explore/components/DataTableControl/index.tsx index 8dc4b1d0140d8..60ca470e4a0db 100644 --- a/superset-frontend/src/explore/components/DataTableControl/index.tsx +++ b/superset-frontend/src/explore/components/DataTableControl/index.tsx @@ -44,7 +44,6 @@ import Button from 'src/components/Button'; import Popover from 'src/components/Popover'; import { prepareCopyToClipboardTabularData } from 'src/utils/common'; import CopyToClipboard from 'src/components/CopyToClipboard'; -import RowCountLabel from 'src/explore/components/RowCountLabel'; import { getTimeColumns, setTimeColumns } from './utils'; export const CellNull = styled('span')` @@ -118,14 +117,6 @@ export const FilterInput = ({ ); }; -export const RowCount = ({ - data, - loading, -}: { - data?: Record[]; - loading: boolean; -}) => ; - enum FormatPickerValue { Formatted = 'formatted', Original = 'original', diff --git a/superset-frontend/src/explore/components/DataTablesPane/components/DataTableControls.tsx b/superset-frontend/src/explore/components/DataTablesPane/components/DataTableControls.tsx index 7a02114a2f52b..b1ff73e29e5da 100644 --- a/superset-frontend/src/explore/components/DataTablesPane/components/DataTableControls.tsx +++ b/superset-frontend/src/explore/components/DataTablesPane/components/DataTableControls.tsx @@ -22,10 +22,10 @@ import { css, GenericDataType, styled } from '@superset-ui/core'; import { CopyToClipboardButton, FilterInput, - RowCount, } 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 { TableControlsProps } from '../types'; export const TableControlsWrapper = styled.div` @@ -47,6 +47,7 @@ export const TableControls = ({ onInputChange, columnNames, columnTypes, + rowcount, isLoading, }: TableControlsProps) => { const originalTimeColumns = getTimeColumns(datasourceId); @@ -74,7 +75,7 @@ export const TableControls = ({ align-items: center; `} > - + diff --git a/superset-frontend/src/explore/components/DataTablesPane/components/SamplesPane.tsx b/superset-frontend/src/explore/components/DataTablesPane/components/SamplesPane.tsx index b542aad99643a..eaae35bd2fa56 100644 --- a/superset-frontend/src/explore/components/DataTablesPane/components/SamplesPane.tsx +++ b/superset-frontend/src/explore/components/DataTablesPane/components/SamplesPane.tsx @@ -48,6 +48,7 @@ export const SamplesPane = ({ const [colnames, setColnames] = useState([]); const [coltypes, setColtypes] = useState([]); const [isLoading, setIsLoading] = useState(false); + const [rowcount, setRowCount] = useState(0); const [responseError, setResponseError] = useState(''); const datasourceId = useMemo( () => `${datasource.id}__${datasource.type}`, @@ -66,6 +67,7 @@ export const SamplesPane = ({ setData(ensureIsArray(response.data)); setColnames(ensureIsArray(response.colnames)); setColtypes(ensureIsArray(response.coltypes)); + setRowCount(response.rowcount); setResponseError(''); cache.add(datasource); if (queryForce && actions) { @@ -108,6 +110,7 @@ export const SamplesPane = ({ data={filteredData} columnNames={colnames} columnTypes={coltypes} + rowcount={rowcount} datasourceId={datasourceId} onInputChange={input => setFilterText(input)} isLoading={isLoading} @@ -128,6 +131,7 @@ export const SamplesPane = ({ data={filteredData} columnNames={colnames} columnTypes={coltypes} + rowcount={rowcount} datasourceId={datasourceId} onInputChange={input => setFilterText(input)} isLoading={isLoading} diff --git a/superset-frontend/src/explore/components/DataTablesPane/components/SingleQueryResultPane.tsx b/superset-frontend/src/explore/components/DataTablesPane/components/SingleQueryResultPane.tsx index c2614dfda6ca6..b543167840442 100644 --- a/superset-frontend/src/explore/components/DataTablesPane/components/SingleQueryResultPane.tsx +++ b/superset-frontend/src/explore/components/DataTablesPane/components/SingleQueryResultPane.tsx @@ -30,6 +30,7 @@ export const SingleQueryResultPane = ({ data, colnames, coltypes, + rowcount, datasourceId, dataSize = 50, isVisible, @@ -55,6 +56,7 @@ export const SingleQueryResultPane = ({ data={filteredData} columnNames={colnames} columnTypes={coltypes} + rowcount={rowcount} datasourceId={datasourceId} onInputChange={input => setFilterText(input)} isLoading={false} diff --git a/superset-frontend/src/explore/components/DataTablesPane/components/useResultsPane.tsx b/superset-frontend/src/explore/components/DataTablesPane/components/useResultsPane.tsx index 9b6b597c7900f..bae6b6fd7b32a 100644 --- a/superset-frontend/src/explore/components/DataTablesPane/components/useResultsPane.tsx +++ b/superset-frontend/src/explore/components/DataTablesPane/components/useResultsPane.tsx @@ -119,6 +119,7 @@ export const useResultsPane = ({ data={[]} columnNames={[]} columnTypes={[]} + rowcount={0} datasourceId={queryFormData.datasource} onInputChange={() => {}} isLoading={false} @@ -135,7 +136,6 @@ export const useResultsPane = ({ , ); } - return resultResp .slice(0, queryCount) .map((result, idx) => ( @@ -143,6 +143,7 @@ export const useResultsPane = ({ data={result.data} colnames={result.colnames} coltypes={result.coltypes} + rowcount={result.rowcount} dataSize={dataSize} datasourceId={queryFormData.datasource} key={idx} diff --git a/superset-frontend/src/explore/components/DataTablesPane/test/DataTablesPane.test.tsx b/superset-frontend/src/explore/components/DataTablesPane/test/DataTablesPane.test.tsx index 74358af959e11..b11fe01580f4c 100644 --- a/superset-frontend/src/explore/components/DataTablesPane/test/DataTablesPane.test.tsx +++ b/superset-frontend/src/explore/components/DataTablesPane/test/DataTablesPane.test.tsx @@ -93,6 +93,8 @@ describe('DataTablesPane', () => { data: [{ __timestamp: 1230768000000, genre: 'Action' }], colnames: ['__timestamp', 'genre'], coltypes: [2, 1], + rowcount: 1, + sql_rowcount: 1, }, ], }, @@ -103,7 +105,9 @@ describe('DataTablesPane', () => { useRedux: true, }); userEvent.click(screen.getByText('Results')); - expect(await screen.findByText('1 row')).toBeVisible(); + expect(screen.container.querySelector('.row-count-label').textContent).toBe( + '1 row', + ); userEvent.click(screen.getByLabelText('Copy')); expect(copyToClipboardSpy).toHaveBeenCalledTimes(1); @@ -125,6 +129,8 @@ describe('DataTablesPane', () => { ], colnames: ['__timestamp', 'genre'], coltypes: [2, 1], + rowcount: 2, + sql_rowcount: 2, }, ], }, @@ -134,7 +140,10 @@ describe('DataTablesPane', () => { useRedux: true, }); userEvent.click(screen.getByText('Results')); - expect(await screen.findByText('2 rows')).toBeVisible(); + expect(screen.container.querySelector('.row-count-label').textContent).toBe( + '2 rows', + ); + expect(screen.getByText('Action')).toBeVisible(); expect(screen.getByText('Horror')).toBeVisible(); diff --git a/superset-frontend/src/explore/components/DataTablesPane/test/ResultsPaneOnDashboard.test.tsx b/superset-frontend/src/explore/components/DataTablesPane/test/ResultsPaneOnDashboard.test.tsx index 839126bb62530..a6f9830d2e174 100644 --- a/superset-frontend/src/explore/components/DataTablesPane/test/ResultsPaneOnDashboard.test.tsx +++ b/superset-frontend/src/explore/components/DataTablesPane/test/ResultsPaneOnDashboard.test.tsx @@ -50,6 +50,8 @@ describe('ResultsPaneOnDashboard', () => { ], colnames: ['__timestamp', 'genre'], coltypes: [2, 1], + rowcount: 2, + sql_rowcount: 2, }, ], }, @@ -78,6 +80,8 @@ describe('ResultsPaneOnDashboard', () => { data: [{ genre: 'Action' }, { genre: 'Horror' }], colnames: ['genre'], coltypes: [1], + rowcount: 2, + sql_rowcount: 2, }, ], }, diff --git a/superset-frontend/src/explore/components/DataTablesPane/test/SamplesPane.test.tsx b/superset-frontend/src/explore/components/DataTablesPane/test/SamplesPane.test.tsx index eed6e84808b73..02c421aeec8de 100644 --- a/superset-frontend/src/explore/components/DataTablesPane/test/SamplesPane.test.tsx +++ b/superset-frontend/src/explore/components/DataTablesPane/test/SamplesPane.test.tsx @@ -50,6 +50,8 @@ describe('SamplesPane', () => { ], colnames: ['__timestamp', 'genre'], coltypes: [2, 1], + rowcount: 2, + sql_rowcount: 2, }, }, ); diff --git a/superset-frontend/src/explore/components/DataTablesPane/types.ts b/superset-frontend/src/explore/components/DataTablesPane/types.ts index 4e6062ba4a256..4939b7d7488c6 100644 --- a/superset-frontend/src/explore/components/DataTablesPane/types.ts +++ b/superset-frontend/src/explore/components/DataTablesPane/types.ts @@ -71,11 +71,13 @@ export interface TableControlsProps { columnNames: string[]; columnTypes: GenericDataType[]; isLoading: boolean; + rowcount: number; } export interface QueryResultInterface { colnames: string[]; coltypes: GenericDataType[]; + rowcount: number; data: Record[][]; } diff --git a/superset-frontend/src/explore/components/RowCountLabel/RowCountLabel.test.tsx b/superset-frontend/src/explore/components/RowCountLabel/RowCountLabel.test.tsx index 2e7a44c15e159..8e3e3b0c1d7b4 100644 --- a/superset-frontend/src/explore/components/RowCountLabel/RowCountLabel.test.tsx +++ b/superset-frontend/src/explore/components/RowCountLabel/RowCountLabel.test.tsx @@ -52,7 +52,7 @@ test('RowCountLabel renders limit with danger and tooltip', async () => { expect(screen.getByText(expectedText)).toBeInTheDocument(); userEvent.hover(screen.getByText(expectedText)); const tooltip = await screen.findByRole('tooltip'); - expect(tooltip).toHaveTextContent('Limit reached'); + expect(tooltip).toHaveTextContent('The row limit'); expect(tooltip).toHaveStyle('background: rgba(0, 0, 0, 0.902);'); }); diff --git a/superset-frontend/src/explore/components/RowCountLabel/index.tsx b/superset-frontend/src/explore/components/RowCountLabel/index.tsx index be41be0ba67de..80fc362959469 100644 --- a/superset-frontend/src/explore/components/RowCountLabel/index.tsx +++ b/superset-frontend/src/explore/components/RowCountLabel/index.tsx @@ -28,9 +28,13 @@ type RowCountLabelProps = { loading?: boolean; }; +const limitReachedMsg = t( + 'The row limit set for the chart was reached. The chart may show partial data.', +); + export default function RowCountLabel(props: RowCountLabelProps) { - const { rowcount = 0, limit, loading } = props; - const limitReached = rowcount === limit; + const { rowcount = 0, limit = null, loading } = props; + const limitReached = limit && rowcount >= limit; const type = limitReached || (rowcount === 0 && !loading) ? 'danger' : 'default'; const formattedRowCount = getNumberFormatter()(rowcount); @@ -46,7 +50,7 @@ export default function RowCountLabel(props: RowCountLabelProps) { ); return limitReached ? ( - {t('Limit reached')}}> + {limitReachedMsg}}> {label} ) : (