diff --git a/public/app/features/explore/Table/TableContainer.test.tsx b/public/app/features/explore/Table/TableContainer.test.tsx
index 4fecc5cf6a2..c8db16caca3 100644
--- a/public/app/features/explore/Table/TableContainer.test.tsx
+++ b/public/app/features/explore/Table/TableContainer.test.tsx
@@ -5,8 +5,8 @@ import { DataFrame, FieldType, getDefaultTimeRange, InternalTimeZones, toDataFra
import { TableContainer } from './TableContainer';
-function getTable(): HTMLElement {
- return screen.getAllByRole('table')[0];
+function getTables(): HTMLElement[] {
+ return screen.getAllByRole('table');
}
function getRowsData(rows: HTMLElement[]): Object[] {
@@ -58,48 +58,63 @@ const defaultProps = {
};
describe('TableContainer', () => {
- it('should render component', () => {
- render();
- expect(getTable()).toBeInTheDocument();
- const rows = within(getTable()).getAllByRole('row');
- expect(rows).toHaveLength(5);
- expect(getRowsData(rows)).toEqual([
- { time: '2021-01-01 00:00:00', text: 'test_string_1' },
- { time: '2021-01-01 03:00:00', text: 'test_string_2' },
- { time: '2021-01-01 01:00:00', text: 'test_string_3' },
- { time: '2021-01-01 02:00:00', text: 'test_string_4' },
- ]);
+ describe('With one main frame', () => {
+ it('should render component', () => {
+ render();
+ const tables = getTables();
+ expect(tables.length).toBe(1);
+ expect(tables[0]).toBeInTheDocument();
+ const rows = within(tables[0]).getAllByRole('row');
+ expect(rows).toHaveLength(5);
+ expect(getRowsData(rows)).toEqual([
+ { time: '2021-01-01 00:00:00', text: 'test_string_1' },
+ { time: '2021-01-01 03:00:00', text: 'test_string_2' },
+ { time: '2021-01-01 01:00:00', text: 'test_string_3' },
+ { time: '2021-01-01 02:00:00', text: 'test_string_4' },
+ ]);
+ });
+
+ it('should render 0 series returned on no items', () => {
+ const emptyFrames: DataFrame[] = [
+ {
+ name: 'TableResultName',
+ fields: [],
+ length: 0,
+ },
+ ];
+ render();
+ expect(screen.getByText('0 series returned')).toBeInTheDocument();
+ });
+
+ it('should update time when timezone changes', () => {
+ const { rerender } = render();
+ const rowsBeforeChange = within(getTables()[0]).getAllByRole('row');
+ expect(getRowsData(rowsBeforeChange)).toEqual([
+ { time: '2021-01-01 00:00:00', text: 'test_string_1' },
+ { time: '2021-01-01 03:00:00', text: 'test_string_2' },
+ { time: '2021-01-01 01:00:00', text: 'test_string_3' },
+ { time: '2021-01-01 02:00:00', text: 'test_string_4' },
+ ]);
+
+ rerender();
+ const rowsAfterChange = within(getTables()[0]).getAllByRole('row');
+ expect(getRowsData(rowsAfterChange)).toEqual([
+ { time: '2020-12-31 19:00:00', text: 'test_string_1' },
+ { time: '2020-12-31 22:00:00', text: 'test_string_2' },
+ { time: '2020-12-31 20:00:00', text: 'test_string_3' },
+ { time: '2020-12-31 21:00:00', text: 'test_string_4' },
+ ]);
+ });
});
-
- it('should render 0 series returned on no items', () => {
- const emptyFrames: DataFrame[] = [
- {
- name: 'TableResultName',
- fields: [],
- length: 0,
- },
- ];
- render();
- expect(screen.getByText('0 series returned')).toBeInTheDocument();
- });
-
- it('should update time when timezone changes', () => {
- const { rerender } = render();
- const rowsBeforeChange = within(getTable()).getAllByRole('row');
- expect(getRowsData(rowsBeforeChange)).toEqual([
- { time: '2021-01-01 00:00:00', text: 'test_string_1' },
- { time: '2021-01-01 03:00:00', text: 'test_string_2' },
- { time: '2021-01-01 01:00:00', text: 'test_string_3' },
- { time: '2021-01-01 02:00:00', text: 'test_string_4' },
- ]);
-
- rerender();
- const rowsAfterChange = within(getTable()).getAllByRole('row');
- expect(getRowsData(rowsAfterChange)).toEqual([
- { time: '2020-12-31 19:00:00', text: 'test_string_1' },
- { time: '2020-12-31 22:00:00', text: 'test_string_2' },
- { time: '2020-12-31 20:00:00', text: 'test_string_3' },
- { time: '2020-12-31 21:00:00', text: 'test_string_4' },
- ]);
+ describe('With multiple main frames', () => {
+ it('should render multiple tables for multiple frames', () => {
+ const dataFrames = [dataFrame, dataFrame];
+ const multiDefaultProps = { ...defaultProps, tableResult: dataFrames };
+ render();
+ const tables = getTables();
+ expect(tables.length).toBe(2);
+ expect(tables[0]).toBeInTheDocument();
+ expect(tables[1]).toBeInTheDocument();
+ });
});
});
diff --git a/public/app/features/explore/Table/TableContainer.tsx b/public/app/features/explore/Table/TableContainer.tsx
index 531189fc40b..9a534b4159c 100644
--- a/public/app/features/explore/Table/TableContainer.tsx
+++ b/public/app/features/explore/Table/TableContainer.tsx
@@ -34,25 +34,21 @@ const connector = connect(mapStateToProps, {});
type Props = TableContainerProps & ConnectedProps;
export class TableContainer extends PureComponent {
- getMainFrame(frames: DataFrame[] | null) {
- return frames?.find((df) => df.meta?.custom?.parentRowIndex === undefined) || frames?.[0];
+ getMainFrames(frames: DataFrame[] | null) {
+ return frames?.filter((df) => df.meta?.custom?.parentRowIndex === undefined) || [frames?.[0]];
}
- getTableHeight() {
- const { tableResult } = this.props;
- const mainFrame = this.getMainFrame(tableResult);
-
- if (!mainFrame || mainFrame.length === 0) {
+ getTableHeight(rowCount: number, isSingleTable = true) {
+ if (rowCount === 0) {
return 200;
}
-
- // tries to estimate table height
- return Math.min(600, Math.max(mainFrame.length * 36, 300) + 40 + 46);
+ // tries to estimate table height, with a min of 300 and a max of 600
+ // if there are multiple tables, there is no min
+ return Math.min(600, Math.max(rowCount * 36, isSingleTable ? 300 : 0) + 40 + 46);
}
render() {
const { loading, onCellFilterAdded, tableResult, width, splitOpenFn, range, ariaLabel, timeZone } = this.props;
- const height = this.getTableHeight();
let dataFrames = tableResult;
@@ -85,33 +81,48 @@ export class TableContainer extends PureComponent {
}
}
- const mainFrame = this.getMainFrame(dataFrames);
- const subFrames = dataFrames?.filter((df) => df.meta?.custom?.parentRowIndex !== undefined);
+ // move dataframes to be grouped by table, with optional sub-tables for a row
+ const tableData: Array<{ main: DataFrame; sub?: DataFrame[] }> = [];
+ const mainFrames = this.getMainFrames(dataFrames).filter(
+ (frame: DataFrame | undefined): frame is DataFrame => !!frame && frame.length !== 0
+ );
+
+ mainFrames?.forEach((frame) => {
+ const subFrames =
+ dataFrames?.filter((df) => frame.refId === df.refId && df.meta?.custom?.parentRowIndex !== undefined) ||
+ undefined;
+ tableData.push({ main: frame, sub: subFrames });
+ });
return (
-
- {(innerWidth, innerHeight) => (
- <>
- {mainFrame?.length ? (
-
- ) : (
-
- )}
- >
+ <>
+ {tableData.length === 0 && (
+
+ {() => }
+
)}
-
+ {tableData.length > 0 &&
+ tableData.map((data, i) => (
+ 1 ? `Table - ${data.main.name || data.main.refId || i}` : 'Table'}
+ width={width}
+ height={this.getTableHeight(data.main.length, tableData.length === 1)}
+ loadingState={loading ? LoadingState.Loading : undefined}
+ >
+ {(innerWidth, innerHeight) => (
+
+ )}
+
+ ))}
+ >
);
}
}