mirror of https://github.com/apache/superset.git
fix(chart): ensure samples data is displayed (#16900)
* initial fix * use data keys for cols * add e2e test * remove code * trim logic
This commit is contained in:
parent
f10bc6d8fe
commit
e6ff25c980
|
@ -113,6 +113,25 @@ describe('VizType control', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('Test datatable', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.login();
|
||||||
|
interceptChart({ legacy: false }).as('tableChartData');
|
||||||
|
interceptChart({ legacy: true }).as('lineChartData');
|
||||||
|
});
|
||||||
|
it('Data Pane opens and loads results', () => {
|
||||||
|
cy.get('[data-test="data-tab"]').click();
|
||||||
|
cy.get('[data-test="row-count-label"]').contains('27 rows retrieved');
|
||||||
|
cy.contains('View results');
|
||||||
|
cy.get('.ant-empty-description').should('not.exist');
|
||||||
|
});
|
||||||
|
it('Datapane loads view samples', () => {
|
||||||
|
cy.contains('View samples').click();
|
||||||
|
cy.get('[data-test="row-count-label"]').contains('1k rows retrieved');
|
||||||
|
cy.get('.ant-empty-description').should('not.exist');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('Time range filter', () => {
|
describe('Time range filter', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.login();
|
cy.login();
|
||||||
|
|
|
@ -150,5 +150,5 @@ export const useTableColumns = (
|
||||||
} as Column),
|
} as Column),
|
||||||
)
|
)
|
||||||
: [],
|
: [],
|
||||||
[data, moreConfigs],
|
[data, colnames, moreConfigs],
|
||||||
);
|
);
|
||||||
|
|
|
@ -106,6 +106,58 @@ const Error = styled.pre`
|
||||||
margin-top: ${({ theme }) => `${theme.gridUnit * 4}px`};
|
margin-top: ${({ theme }) => `${theme.gridUnit * 4}px`};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
interface DataTableProps {
|
||||||
|
columnNames: string[];
|
||||||
|
filterText: string;
|
||||||
|
data: object[] | undefined;
|
||||||
|
isLoading: boolean;
|
||||||
|
error: string | undefined;
|
||||||
|
errorMessage: React.ReactElement | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const DataTable = ({
|
||||||
|
columnNames,
|
||||||
|
filterText,
|
||||||
|
data,
|
||||||
|
isLoading,
|
||||||
|
error,
|
||||||
|
errorMessage,
|
||||||
|
}: DataTableProps) => {
|
||||||
|
// this is to preserve the order of the columns, even if there are integer values,
|
||||||
|
// while also only grabbing the first column's keys
|
||||||
|
const columns = useTableColumns(columnNames, data);
|
||||||
|
const filteredData = useFilteredTableData(filterText, data);
|
||||||
|
|
||||||
|
if (isLoading) {
|
||||||
|
return <Loading />;
|
||||||
|
}
|
||||||
|
if (error) {
|
||||||
|
return <Error>{error}</Error>;
|
||||||
|
}
|
||||||
|
if (data) {
|
||||||
|
if (data.length === 0) {
|
||||||
|
return <span>No data</span>;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<TableView
|
||||||
|
columns={columns}
|
||||||
|
data={filteredData}
|
||||||
|
pageSize={DATA_TABLE_PAGE_SIZE}
|
||||||
|
noDataText={t('No data')}
|
||||||
|
emptyWrapperType={EmptyWrapperType.Small}
|
||||||
|
className="table-condensed"
|
||||||
|
isPaginationSticky
|
||||||
|
showRowCount={false}
|
||||||
|
small
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (errorMessage) {
|
||||||
|
return <Error>{errorMessage}</Error>;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
export const DataTablesPane = ({
|
export const DataTablesPane = ({
|
||||||
queryFormData,
|
queryFormData,
|
||||||
tableSectionHeight,
|
tableSectionHeight,
|
||||||
|
@ -131,7 +183,13 @@ export const DataTablesPane = ({
|
||||||
[RESULT_TYPES.results]: true,
|
[RESULT_TYPES.results]: true,
|
||||||
[RESULT_TYPES.samples]: true,
|
[RESULT_TYPES.samples]: true,
|
||||||
});
|
});
|
||||||
const [columnNames, setColumnNames] = useState<string[]>([]);
|
const [columnNames, setColumnNames] = useState<{
|
||||||
|
[RESULT_TYPES.results]: string[];
|
||||||
|
[RESULT_TYPES.samples]: string[];
|
||||||
|
}>({
|
||||||
|
[RESULT_TYPES.results]: [],
|
||||||
|
[RESULT_TYPES.samples]: [],
|
||||||
|
});
|
||||||
const [error, setError] = useState(NULLISH_RESULTS_STATE);
|
const [error, setError] = useState(NULLISH_RESULTS_STATE);
|
||||||
const [filterText, setFilterText] = useState('');
|
const [filterText, setFilterText] = useState('');
|
||||||
const [activeTabKey, setActiveTabKey] = useState<string>(
|
const [activeTabKey, setActiveTabKey] = useState<string>(
|
||||||
|
@ -192,7 +250,13 @@ export const DataTablesPane = ({
|
||||||
[resultType]: json.result[0].data,
|
[resultType]: json.result[0].data,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
const checkCols = json?.result[0]?.data?.length
|
||||||
|
? Object.keys(json.result[0].data[0])
|
||||||
|
: null;
|
||||||
|
setColumnNames(prevColumnNames => ({
|
||||||
|
...prevColumnNames,
|
||||||
|
[resultType]: json.result[0].columns || checkCols,
|
||||||
|
}));
|
||||||
setIsLoading(prevIsLoading => ({
|
setIsLoading(prevIsLoading => ({
|
||||||
...prevIsLoading,
|
...prevIsLoading,
|
||||||
[resultType]: false,
|
[resultType]: false,
|
||||||
|
@ -215,7 +279,7 @@ export const DataTablesPane = ({
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[queryFormData],
|
[queryFormData, columnNames],
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -239,7 +303,10 @@ export const DataTablesPane = ({
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (queriesResponse && chartStatus === 'success') {
|
if (queriesResponse && chartStatus === 'success') {
|
||||||
const { colnames } = queriesResponse[0];
|
const { colnames } = queriesResponse[0];
|
||||||
setColumnNames([...colnames]);
|
setColumnNames({
|
||||||
|
...columnNames,
|
||||||
|
[RESULT_TYPES.results]: [...colnames],
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}, [queriesResponse]);
|
}, [queriesResponse]);
|
||||||
|
|
||||||
|
@ -289,67 +356,12 @@ export const DataTablesPane = ({
|
||||||
errorMessage,
|
errorMessage,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const filteredData = {
|
|
||||||
[RESULT_TYPES.results]: useFilteredTableData(
|
|
||||||
filterText,
|
|
||||||
formattedData[RESULT_TYPES.results],
|
|
||||||
),
|
|
||||||
[RESULT_TYPES.samples]: useFilteredTableData(
|
|
||||||
filterText,
|
|
||||||
formattedData[RESULT_TYPES.samples],
|
|
||||||
),
|
|
||||||
};
|
|
||||||
|
|
||||||
// this is to preserve the order of the columns, even if there are integer values,
|
|
||||||
// while also only grabbing the first column's keys
|
|
||||||
const columns = {
|
|
||||||
[RESULT_TYPES.results]: useTableColumns(
|
|
||||||
columnNames,
|
|
||||||
data[RESULT_TYPES.results],
|
|
||||||
),
|
|
||||||
[RESULT_TYPES.samples]: useTableColumns(
|
|
||||||
columnNames,
|
|
||||||
data[RESULT_TYPES.samples],
|
|
||||||
),
|
|
||||||
};
|
|
||||||
|
|
||||||
const renderDataTable = (type: string) => {
|
|
||||||
if (isLoading[type]) {
|
|
||||||
return <Loading />;
|
|
||||||
}
|
|
||||||
if (error[type]) {
|
|
||||||
return <Error>{error[type]}</Error>;
|
|
||||||
}
|
|
||||||
if (data[type]) {
|
|
||||||
if (data[type]?.length === 0) {
|
|
||||||
return <span>No data</span>;
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<TableView
|
|
||||||
columns={columns[type]}
|
|
||||||
data={filteredData[type]}
|
|
||||||
pageSize={DATA_TABLE_PAGE_SIZE}
|
|
||||||
noDataText={t('No data')}
|
|
||||||
emptyWrapperType={EmptyWrapperType.Small}
|
|
||||||
className="table-condensed"
|
|
||||||
isPaginationSticky
|
|
||||||
showRowCount={false}
|
|
||||||
small
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (errorMessage) {
|
|
||||||
return <Error>{errorMessage}</Error>;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
|
|
||||||
const TableControls = (
|
const TableControls = (
|
||||||
<TableControlsWrapper>
|
<TableControlsWrapper>
|
||||||
<RowCount data={data[activeTabKey]} loading={isLoading[activeTabKey]} />
|
<RowCount data={data[activeTabKey]} loading={isLoading[activeTabKey]} />
|
||||||
<CopyToClipboardButton
|
<CopyToClipboardButton
|
||||||
data={formattedData[activeTabKey]}
|
data={formattedData[activeTabKey]}
|
||||||
columns={columnNames}
|
columns={columnNames[activeTabKey]}
|
||||||
/>
|
/>
|
||||||
<FilterInput onChangeHandler={setFilterText} />
|
<FilterInput onChangeHandler={setFilterText} />
|
||||||
</TableControlsWrapper>
|
</TableControlsWrapper>
|
||||||
|
@ -363,7 +375,7 @@ export const DataTablesPane = ({
|
||||||
return (
|
return (
|
||||||
<SouthPane data-test="some-purposeful-instance">
|
<SouthPane data-test="some-purposeful-instance">
|
||||||
<TabsWrapper contentHeight={tableSectionHeight}>
|
<TabsWrapper contentHeight={tableSectionHeight}>
|
||||||
<CollapseWrapper>
|
<CollapseWrapper data-test="data-tab">
|
||||||
<Collapse
|
<Collapse
|
||||||
accordion
|
accordion
|
||||||
bordered={false}
|
bordered={false}
|
||||||
|
@ -384,13 +396,27 @@ export const DataTablesPane = ({
|
||||||
tab={t('View results')}
|
tab={t('View results')}
|
||||||
key={RESULT_TYPES.results}
|
key={RESULT_TYPES.results}
|
||||||
>
|
>
|
||||||
{renderDataTable(RESULT_TYPES.results)}
|
<DataTable
|
||||||
|
isLoading={isLoading[RESULT_TYPES.results]}
|
||||||
|
data={data[RESULT_TYPES.results]}
|
||||||
|
columnNames={columnNames[RESULT_TYPES.results]}
|
||||||
|
filterText={filterText}
|
||||||
|
error={error[RESULT_TYPES.results]}
|
||||||
|
errorMessage={errorMessage}
|
||||||
|
/>
|
||||||
</Tabs.TabPane>
|
</Tabs.TabPane>
|
||||||
<Tabs.TabPane
|
<Tabs.TabPane
|
||||||
tab={t('View samples')}
|
tab={t('View samples')}
|
||||||
key={RESULT_TYPES.samples}
|
key={RESULT_TYPES.samples}
|
||||||
>
|
>
|
||||||
{renderDataTable(RESULT_TYPES.samples)}
|
<DataTable
|
||||||
|
isLoading={isLoading[RESULT_TYPES.samples]}
|
||||||
|
data={data[RESULT_TYPES.samples]}
|
||||||
|
columnNames={columnNames[RESULT_TYPES.samples]}
|
||||||
|
filterText={filterText}
|
||||||
|
error={error[RESULT_TYPES.samples]}
|
||||||
|
errorMessage={errorMessage}
|
||||||
|
/>
|
||||||
</Tabs.TabPane>
|
</Tabs.TabPane>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
</Collapse.Panel>
|
</Collapse.Panel>
|
||||||
|
|
Loading…
Reference in New Issue