grafana/packages/grafana-ui/src/components/Table/Table.test.tsx

677 lines
22 KiB
TypeScript
Raw Normal View History

import { render, screen, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';
import { applyFieldOverrides, createTheme, DataFrame, FieldType, toDataFrame } from '@grafana/data';
import { Table } from './Table';
import { Props } from './types';
function getDefaultDataFrame(): DataFrame {
const dataFrame = toDataFrame({
name: 'A',
fields: [
{
name: 'time',
type: FieldType.time,
values: [1609459200000, 1609470000000, 1609462800000, 1609466400000],
config: {
custom: {
filterable: false,
},
},
},
{
name: 'temperature',
type: FieldType.number,
values: [10, NaN, 11, 12],
config: {
custom: {
filterable: false,
},
links: [
{
targetBlank: true,
title: 'Value link',
url: '${__value.text}',
},
],
},
},
{
name: 'img',
type: FieldType.string,
values: ['data:image/png;base64,1', 'data:image/png;base64,2', 'data:image/png;base64,3'],
config: {
custom: {
filterable: false,
displayMode: 'image',
},
links: [
{
targetBlank: true,
title: 'Image link',
url: '${__value.text}',
},
],
},
},
],
});
Table: Support display of multiple sub tables (#71953) * Add nested option to DataFrame. Refactor Table to use nested dataframes for sub-tables * Use nested frames for TraceQL response * debugging * Fix cell text and table position * Update getItemSize * noHeader size * Update sub table renderer * Update table container height * Cleanup and fix RawPrometheusContainer height * Update resultTransformer and docker script * Updates to TableContainer, resultTransformer after merge * Fixes for table pagination in dashboards * Cell height and show footer enhancement/fix * Sub table links * Update RawPrometheusContainer * Remove console log * Update tests * Update storybook * Remove Tempo demo * Store nested data in single field via its values * Move nested prop into custom * Tempo demo * Add field type & update incorrect logic * Update docker compose image for Tempo * Update packages/grafana-data/src/field/fieldOverrides.ts Co-authored-by: Piotr Jamróz <pm.jamroz@gmail.com> * Simplify logic for getting nestedFrames and rendering sub tables * Update docs for table * Update nested table bg color * Lighten nested table bg color * Renames * Migrate frames using parentRowIndex and add deprecation notice * Update title * Align expander icon size between Table and interactive table * Table: Refactor out the expanded rows bits * fix spacing * Add line along left side for expanded rows * Disable hover row background when expanded --------- Co-authored-by: André Pereira <adrapereira@gmail.com> Co-authored-by: Piotr Jamróz <pm.jamroz@gmail.com> Co-authored-by: Torkel Ödegaard <torkel@grafana.com>
2023-08-10 19:33:46 +08:00
return applyOverrides(dataFrame);
}
function applyOverrides(dataFrame: DataFrame) {
const dataFrames = applyFieldOverrides({
data: [dataFrame],
fieldConfig: {
defaults: {},
overrides: [],
},
replaceVariables: (value, vars, format) => {
return vars && value === '${__value.text}' ? '${__value.text} interpolation' : value;
},
timeZone: 'utc',
theme: createTheme(),
});
return dataFrames[0];
}
function getTestContext(propOverrides: Partial<Props> = {}) {
const onSortByChange = jest.fn();
const onCellFilterAdded = jest.fn();
const onColumnResize = jest.fn();
const props: Props = {
ariaLabel: 'aria-label',
data: getDefaultDataFrame(),
height: 600,
width: 800,
onSortByChange,
onCellFilterAdded,
onColumnResize,
initialRowIndex: undefined,
};
Object.assign(props, propOverrides);
const { rerender } = render(<Table {...props} />);
return { rerender, onSortByChange, onCellFilterAdded, onColumnResize };
}
function getTable(): HTMLElement {
return screen.getAllByRole('table')[0];
}
function getFooter(): HTMLElement {
return screen.getByTestId('table-footer');
}
function getColumnHeader(name: string | RegExp): HTMLElement {
return within(getTable()).getByRole('columnheader', { name });
}
function getLinks(row: HTMLElement): HTMLElement[] {
return within(row).getAllByRole('link');
}
function getRowsData(rows: HTMLElement[]): Object[] {
let content = [];
for (let i = 1; i < rows.length; i++) {
const row = getLinks(rows[i])[0];
content.push({
time: within(rows[i]).getByText(/2021*/).textContent,
temperature: row.textContent,
link: row.getAttribute('href'),
});
}
return content;
}
describe('Table', () => {
describe('when mounted without data', () => {
it('then no data to show should be displayed', () => {
getTestContext({ data: toDataFrame([]) });
expect(getTable()).toBeInTheDocument();
expect(screen.queryByRole('row')).not.toBeInTheDocument();
expect(screen.getByText(/No data/i)).toBeInTheDocument();
});
});
describe('when mounted with data', () => {
it('then correct rows should be rendered', () => {
getTestContext();
expect(getTable()).toBeInTheDocument();
expect(screen.getAllByRole('columnheader')).toHaveLength(3);
expect(getColumnHeader(/time/)).toBeInTheDocument();
expect(getColumnHeader(/temperature/)).toBeInTheDocument();
expect(getColumnHeader(/img/)).toBeInTheDocument();
const rows = within(getTable()).getAllByRole('row');
expect(rows).toHaveLength(5);
expect(getRowsData(rows)).toEqual([
{ time: '2021-01-01 00:00:00', temperature: '10', link: '${__value.text} interpolation' },
{ time: '2021-01-01 03:00:00', temperature: 'NaN', link: '${__value.text} interpolation' },
{ time: '2021-01-01 01:00:00', temperature: '11', link: '${__value.text} interpolation' },
{ time: '2021-01-01 02:00:00', temperature: '12', link: '${__value.text} interpolation' },
]);
});
});
describe('when mounted with footer', () => {
it('then footer should be displayed', () => {
const footerValues = ['a', 'b', 'c'];
getTestContext({ footerValues });
expect(getTable()).toBeInTheDocument();
expect(getFooter()).toBeInTheDocument();
});
});
describe('when sorting with column header', () => {
it('then correct rows should be rendered', async () => {
getTestContext();
await userEvent.click(within(getColumnHeader(/temperature/)).getByText(/temperature/i));
await userEvent.click(within(getColumnHeader(/temperature/)).getByText(/temperature/i));
const rows = within(getTable()).getAllByRole('row');
expect(rows).toHaveLength(5);
expect(getRowsData(rows)).toEqual([
{ time: '2021-01-01 02:00:00', temperature: '12', link: '${__value.text} interpolation' },
{ time: '2021-01-01 01:00:00', temperature: '11', link: '${__value.text} interpolation' },
{ time: '2021-01-01 00:00:00', temperature: '10', link: '${__value.text} interpolation' },
{ time: '2021-01-01 03:00:00', temperature: 'NaN', link: '${__value.text} interpolation' },
]);
});
});
describe('on filtering', () => {
it('the rows should be filtered', async () => {
getTestContext({
data: toDataFrame({
name: 'A',
fields: [
{
name: 'number',
type: FieldType.number,
values: [1, 1, 1, 2, 2, 3, 4, 5],
config: {
custom: {
filterable: true,
},
},
},
],
}),
});
expect(within(getTable()).getAllByRole('row')).toHaveLength(9);
await userEvent.click(within(getColumnHeader(/number/)).getByRole('button', { name: '' }));
await userEvent.click(screen.getByLabelText('1'));
await userEvent.click(screen.getByText('Ok'));
// 3 + header row
expect(within(getTable()).getAllByRole('row')).toHaveLength(4);
});
it('should redo footer calculations', async () => {
getTestContext({
footerOptions: { show: true, reducer: ['sum'] },
data: toDataFrame({
name: 'A',
fields: [
{
name: 'number',
type: FieldType.number,
values: [1, 1, 1, 2, 2],
config: {
custom: {
filterable: true,
},
},
},
],
}),
});
expect(within(getFooter()).getByRole('columnheader').getElementsByTagName('span')[0].textContent).toEqual('7');
await userEvent.click(within(getColumnHeader(/number/)).getByRole('button', { name: '' }));
await userEvent.click(screen.getByLabelText('1'));
await userEvent.click(screen.getByText('Ok'));
expect(within(getFooter()).getByRole('columnheader').getElementsByTagName('span')[0].textContent).toEqual('3');
});
it('should filter rows and recalculate footer values when multiple filter values are selected', async () => {
getTestContext({
footerOptions: { show: true, reducer: ['sum'] },
data: toDataFrame({
name: 'A',
fields: [
{
name: 'number',
type: FieldType.number,
values: [1, 1, 1, 2, 2, 3, 3],
config: {
custom: {
filterable: true,
},
},
},
],
}),
});
expect(within(getTable()).getAllByRole('row')).toHaveLength(8);
expect(within(getFooter()).getByRole('columnheader').getElementsByTagName('span')[0].textContent).toEqual('13');
await userEvent.click(within(getColumnHeader(/number/)).getByRole('button', { name: '' }));
await userEvent.click(screen.getByLabelText('2'));
await userEvent.click(screen.getByLabelText('3'));
await userEvent.click(screen.getByText('Ok'));
//4 + header row
expect(within(getTable()).getAllByRole('row')).toHaveLength(5);
expect(within(getFooter()).getByRole('columnheader').getElementsByTagName('span')[0].textContent).toEqual('10');
});
it('should reset when clear filters button is pressed', async () => {
getTestContext({
footerOptions: { show: true, reducer: ['sum'] },
data: toDataFrame({
name: 'A',
fields: [
{
name: 'number',
type: FieldType.number,
values: [1, 1, 1, 2, 2],
config: {
custom: {
filterable: true,
},
},
},
],
}),
});
await userEvent.click(within(getColumnHeader(/number/)).getByRole('button', { name: '' }));
await userEvent.click(screen.getByLabelText('1'));
await userEvent.click(screen.getByText('Ok'));
//3 + header row
expect(within(getTable()).getAllByRole('row')).toHaveLength(4);
expect(within(getFooter()).getByRole('columnheader').getElementsByTagName('span')[0].textContent).toEqual('3');
await userEvent.click(within(getColumnHeader(/number/)).getByRole('button', { name: '' }));
await userEvent.click(screen.getByText('Clear filter'));
//5 + header row
expect(within(getTable()).getAllByRole('row')).toHaveLength(6);
expect(within(getFooter()).getByRole('columnheader').getElementsByTagName('span')[0].textContent).toEqual('7');
});
});
describe('on data change', () => {
it('should redo footer value calculations', async () => {
const { rerender } = getTestContext({
footerOptions: { show: true, reducer: ['sum'] },
data: toDataFrame({
name: 'A',
fields: [
{
name: 'number',
type: FieldType.number,
values: [1, 1, 1, 2, 2],
config: {
custom: {
filterable: true,
},
},
},
],
}),
});
//5 + header row
expect(within(getTable()).getAllByRole('row')).toHaveLength(6);
expect(within(getFooter()).getByRole('columnheader').getElementsByTagName('span')[0].textContent).toEqual('7');
const onSortByChange = jest.fn();
const onCellFilterAdded = jest.fn();
const onColumnResize = jest.fn();
const props: Props = {
ariaLabel: 'aria-label',
data: getDefaultDataFrame(),
height: 600,
width: 800,
onSortByChange,
onCellFilterAdded,
onColumnResize,
};
const propOverrides = {
footerOptions: { show: true, reducer: ['sum'] },
data: toDataFrame({
name: 'A',
fields: [
{
name: 'number',
type: FieldType.number,
values: [1, 1, 1, 2],
config: {
custom: {
filterable: true,
},
},
},
],
}),
};
Object.assign(props, propOverrides);
rerender(<Table {...props} />);
//4 + header row
expect(within(getTable()).getAllByRole('row')).toHaveLength(5);
expect(within(getFooter()).getByRole('columnheader').getElementsByTagName('span')[0].textContent).toEqual('5');
});
});
describe('on table footer disabled', () => {
it('should not show footer', async () => {
getTestContext({
footerOptions: { show: false, reducer: ['sum'] },
data: toDataFrame({
name: 'A',
fields: [
{
name: 'number',
type: FieldType.number,
values: [1, 1, 1, 2, 2],
config: {
custom: {
filterable: true,
},
},
},
],
}),
});
expect(() => screen.getByTestId('table-footer')).toThrow('Unable to find an element');
});
});
describe('on table footer enabled and count calculation selected', () => {
it('should show count of non-null values', async () => {
getTestContext({
footerOptions: { show: true, reducer: ['count'] },
data: toDataFrame({
name: 'A',
fields: [
{
name: 'number',
type: FieldType.number,
values: [1, 1, 1, 2, null],
config: {
custom: {
filterable: true,
},
},
},
],
}),
});
expect(within(getFooter()).getByRole('columnheader').getElementsByTagName('span')[0].textContent).toEqual('4');
});
it('should show count of rows when `count rows` is selected', async () => {
getTestContext({
footerOptions: { show: true, reducer: ['count'], countRows: true },
data: toDataFrame({
name: 'A',
fields: [
{
name: 'number1',
type: FieldType.number,
values: [1, 1, 1, 2, null],
config: {
custom: {
filterable: true,
},
},
},
],
}),
});
expect(within(getFooter()).getByRole('columnheader').getElementsByTagName('span')[0].textContent).toEqual(
Table: Add row number column option (#62256) * baldm0mma/addRowNumbers/ add showRowNums to panel cue * baldm0mma/addRowNumbers/ add panel option for sowing row numbers * baldm0mma/addRowNumbers/ update typing for showRowNums * baldm0mma/addRowNumbers/ add buildFieldsForOptionalRowNums * baldm0mma/addRowNumbers/ update addOptionalNumbersRowToTable * baldm0mma/addRowNumbers/ adjust display method to return numeric and text values * baldm0mma/ chaneg prop name to match * baldm0mma/addRowNumbers/ update boolean swicth path * baldm0mma/addRowNumbers/ move function * baldm0mma/addRowNumbers/ add getToggleHiddenProps * baldm0mma/addRowNumbers/ remove addNumbersRowToTable second arg * baldm0mma/addRowNumbers/ add updateInitialState * baldm0mma/addRowNumbers/ update getInitialState reducer with initialShowRowNumbers arg * baldm0mma/addRowNumbers/ add useEffect for RowNumberColumn toggling * baldm0mma/addRowNums/ bootleg fix * baldm0mma/addRowNumbers/ export OPTIONAL_ROW_NUMBER_COLUMN_WIDTH * baldm0mma/addRowNumbers/ add annos for readability * baldm0mma/addRowNumbers/ remove superfluous annos * baldm0mma/addRowNumbers/ add a few logs * baldm0mma/addRowNumbers/ update annos * baldm0mma/addRowNumbers/ update which footer row displays reducer type * baldm0mma/addRowNumbers/ abstract away defaultRowNumberColumnFieldData * baldm0mma/addRowNumbers/ update annos in utils.tsx * baldm0mma/addRowNumbers/ update annos for defaultRowNumberColumnFieldData * baldm0mma/addRowNumbers/ mark unused args with underscore * baldm0mma/addRowNumbers/ add annos to addRowNumbersFieldToData * baldm0mma/addRowNumbers/ update utils file type * baldm0mma/addRowNumbers/ remove console.logs * baldm0mma/addRowNumbers/ update file type * baldm0mma/addRowNumbers/ update annos in utils * baldm0mma/addRowNumbers/ remove superfluous footerGroups object * baldm0mma/addRowNumbers/ add annos for tests * baldm0mma/addRowNumbers/ add annos for self * baldm0mma/addRowNumbers/ add tests to table.test.tsx * baldm0mma/addRowNumbers/ update tests in utils.test * baldm0mma/addRowNumbers/ update annos and tests * baldm0mma/addRowNumbers/ remove console.logs * baldm0mma/addRowNumbers/ update utils file ext * baldm0mma/addRowNumbers/ update anno in table.tsx * baldm0mma/addRowNumbers/ update annos in table.tsx * baldm0mma/addRowNumbers/ rem error annos * baldm0mma/addRowNumbers/ revert footerCell * baldm0mma/addRowNumbers/ revert tests * baldm0mma/addRowNumbers/ skip tests * baldm0mma/addRowNumbers/ revert table isCountRowSet * baldm0mma/addRowNumbers/ remove cloneDeep * baldm0mma/addRowNumbers/ update filterFields * baldm0mma/addRowNumbers/ skip tests * Refactor count rows * baldm0mma/addRowNumbers/ rem test skips * baldm0mma/addRowNumbers/ update with annos * baldm0mma/addRowNumbers/ skip timeing out test * baldm0mma/addRowNumbers/ static row numbering and test updates * baldm0mma/addRowNumbers/ remove dupe --------- Co-authored-by: Victor Marin <victor.marin@grafana.com>
2023-02-03 22:00:29 +08:00
'Count'
);
expect(within(getFooter()).getByRole('columnheader').getElementsByTagName('span')[1].textContent).toEqual('5');
});
it('should show correct counts when turning `count rows` on and off', async () => {
const { rerender } = getTestContext({
footerOptions: { show: true, reducer: ['count'], countRows: true },
data: toDataFrame({
name: 'A',
fields: [
{
name: 'number1',
type: FieldType.number,
values: [1, 1, 1, 2, null],
config: {
custom: {
filterable: true,
},
},
},
],
}),
});
expect(within(getFooter()).getByRole('columnheader').getElementsByTagName('span')[0].textContent).toEqual(
Table: Add row number column option (#62256) * baldm0mma/addRowNumbers/ add showRowNums to panel cue * baldm0mma/addRowNumbers/ add panel option for sowing row numbers * baldm0mma/addRowNumbers/ update typing for showRowNums * baldm0mma/addRowNumbers/ add buildFieldsForOptionalRowNums * baldm0mma/addRowNumbers/ update addOptionalNumbersRowToTable * baldm0mma/addRowNumbers/ adjust display method to return numeric and text values * baldm0mma/ chaneg prop name to match * baldm0mma/addRowNumbers/ update boolean swicth path * baldm0mma/addRowNumbers/ move function * baldm0mma/addRowNumbers/ add getToggleHiddenProps * baldm0mma/addRowNumbers/ remove addNumbersRowToTable second arg * baldm0mma/addRowNumbers/ add updateInitialState * baldm0mma/addRowNumbers/ update getInitialState reducer with initialShowRowNumbers arg * baldm0mma/addRowNumbers/ add useEffect for RowNumberColumn toggling * baldm0mma/addRowNums/ bootleg fix * baldm0mma/addRowNumbers/ export OPTIONAL_ROW_NUMBER_COLUMN_WIDTH * baldm0mma/addRowNumbers/ add annos for readability * baldm0mma/addRowNumbers/ remove superfluous annos * baldm0mma/addRowNumbers/ add a few logs * baldm0mma/addRowNumbers/ update annos * baldm0mma/addRowNumbers/ update which footer row displays reducer type * baldm0mma/addRowNumbers/ abstract away defaultRowNumberColumnFieldData * baldm0mma/addRowNumbers/ update annos in utils.tsx * baldm0mma/addRowNumbers/ update annos for defaultRowNumberColumnFieldData * baldm0mma/addRowNumbers/ mark unused args with underscore * baldm0mma/addRowNumbers/ add annos to addRowNumbersFieldToData * baldm0mma/addRowNumbers/ update utils file type * baldm0mma/addRowNumbers/ remove console.logs * baldm0mma/addRowNumbers/ update file type * baldm0mma/addRowNumbers/ update annos in utils * baldm0mma/addRowNumbers/ remove superfluous footerGroups object * baldm0mma/addRowNumbers/ add annos for tests * baldm0mma/addRowNumbers/ add annos for self * baldm0mma/addRowNumbers/ add tests to table.test.tsx * baldm0mma/addRowNumbers/ update tests in utils.test * baldm0mma/addRowNumbers/ update annos and tests * baldm0mma/addRowNumbers/ remove console.logs * baldm0mma/addRowNumbers/ update utils file ext * baldm0mma/addRowNumbers/ update anno in table.tsx * baldm0mma/addRowNumbers/ update annos in table.tsx * baldm0mma/addRowNumbers/ rem error annos * baldm0mma/addRowNumbers/ revert footerCell * baldm0mma/addRowNumbers/ revert tests * baldm0mma/addRowNumbers/ skip tests * baldm0mma/addRowNumbers/ revert table isCountRowSet * baldm0mma/addRowNumbers/ remove cloneDeep * baldm0mma/addRowNumbers/ update filterFields * baldm0mma/addRowNumbers/ skip tests * Refactor count rows * baldm0mma/addRowNumbers/ rem test skips * baldm0mma/addRowNumbers/ update with annos * baldm0mma/addRowNumbers/ skip timeing out test * baldm0mma/addRowNumbers/ static row numbering and test updates * baldm0mma/addRowNumbers/ remove dupe --------- Co-authored-by: Victor Marin <victor.marin@grafana.com>
2023-02-03 22:00:29 +08:00
'Count'
);
expect(within(getFooter()).getByRole('columnheader').getElementsByTagName('span')[1].textContent).toEqual('5');
const onSortByChange = jest.fn();
const onCellFilterAdded = jest.fn();
const onColumnResize = jest.fn();
const props: Props = {
ariaLabel: 'aria-label',
data: getDefaultDataFrame(),
height: 600,
width: 800,
onSortByChange,
onCellFilterAdded,
onColumnResize,
};
const propOverrides = {
footerOptions: { show: true, reducer: ['count'], countRows: false },
data: toDataFrame({
name: 'A',
fields: [
{
name: 'number',
type: FieldType.number,
values: [1, 1, 1, 2, null],
config: {
custom: {
filterable: true,
},
},
},
],
}),
};
Object.assign(props, propOverrides);
rerender(<Table {...props} />);
expect(within(getFooter()).getByRole('columnheader').getElementsByTagName('span')[0].textContent).toEqual('4');
});
});
Table: Support display of multiple sub tables (#71953) * Add nested option to DataFrame. Refactor Table to use nested dataframes for sub-tables * Use nested frames for TraceQL response * debugging * Fix cell text and table position * Update getItemSize * noHeader size * Update sub table renderer * Update table container height * Cleanup and fix RawPrometheusContainer height * Update resultTransformer and docker script * Updates to TableContainer, resultTransformer after merge * Fixes for table pagination in dashboards * Cell height and show footer enhancement/fix * Sub table links * Update RawPrometheusContainer * Remove console log * Update tests * Update storybook * Remove Tempo demo * Store nested data in single field via its values * Move nested prop into custom * Tempo demo * Add field type & update incorrect logic * Update docker compose image for Tempo * Update packages/grafana-data/src/field/fieldOverrides.ts Co-authored-by: Piotr Jamróz <pm.jamroz@gmail.com> * Simplify logic for getting nestedFrames and rendering sub tables * Update docs for table * Update nested table bg color * Lighten nested table bg color * Renames * Migrate frames using parentRowIndex and add deprecation notice * Update title * Align expander icon size between Table and interactive table * Table: Refactor out the expanded rows bits * fix spacing * Add line along left side for expanded rows * Disable hover row background when expanded --------- Co-authored-by: André Pereira <adrapereira@gmail.com> Co-authored-by: Piotr Jamróz <pm.jamroz@gmail.com> Co-authored-by: Torkel Ödegaard <torkel@grafana.com>
2023-08-10 19:33:46 +08:00
describe('when mounted with nested data', () => {
beforeEach(() => {
Table: Support display of multiple sub tables (#71953) * Add nested option to DataFrame. Refactor Table to use nested dataframes for sub-tables * Use nested frames for TraceQL response * debugging * Fix cell text and table position * Update getItemSize * noHeader size * Update sub table renderer * Update table container height * Cleanup and fix RawPrometheusContainer height * Update resultTransformer and docker script * Updates to TableContainer, resultTransformer after merge * Fixes for table pagination in dashboards * Cell height and show footer enhancement/fix * Sub table links * Update RawPrometheusContainer * Remove console log * Update tests * Update storybook * Remove Tempo demo * Store nested data in single field via its values * Move nested prop into custom * Tempo demo * Add field type & update incorrect logic * Update docker compose image for Tempo * Update packages/grafana-data/src/field/fieldOverrides.ts Co-authored-by: Piotr Jamróz <pm.jamroz@gmail.com> * Simplify logic for getting nestedFrames and rendering sub tables * Update docs for table * Update nested table bg color * Lighten nested table bg color * Renames * Migrate frames using parentRowIndex and add deprecation notice * Update title * Align expander icon size between Table and interactive table * Table: Refactor out the expanded rows bits * fix spacing * Add line along left side for expanded rows * Disable hover row background when expanded --------- Co-authored-by: André Pereira <adrapereira@gmail.com> Co-authored-by: Piotr Jamróz <pm.jamroz@gmail.com> Co-authored-by: Torkel Ödegaard <torkel@grafana.com>
2023-08-10 19:33:46 +08:00
const nestedFrame = (idx: number) =>
applyOverrides(
toDataFrame({
Table: Support display of multiple sub tables (#71953) * Add nested option to DataFrame. Refactor Table to use nested dataframes for sub-tables * Use nested frames for TraceQL response * debugging * Fix cell text and table position * Update getItemSize * noHeader size * Update sub table renderer * Update table container height * Cleanup and fix RawPrometheusContainer height * Update resultTransformer and docker script * Updates to TableContainer, resultTransformer after merge * Fixes for table pagination in dashboards * Cell height and show footer enhancement/fix * Sub table links * Update RawPrometheusContainer * Remove console log * Update tests * Update storybook * Remove Tempo demo * Store nested data in single field via its values * Move nested prop into custom * Tempo demo * Add field type & update incorrect logic * Update docker compose image for Tempo * Update packages/grafana-data/src/field/fieldOverrides.ts Co-authored-by: Piotr Jamróz <pm.jamroz@gmail.com> * Simplify logic for getting nestedFrames and rendering sub tables * Update docs for table * Update nested table bg color * Lighten nested table bg color * Renames * Migrate frames using parentRowIndex and add deprecation notice * Update title * Align expander icon size between Table and interactive table * Table: Refactor out the expanded rows bits * fix spacing * Add line along left side for expanded rows * Disable hover row background when expanded --------- Co-authored-by: André Pereira <adrapereira@gmail.com> Co-authored-by: Piotr Jamróz <pm.jamroz@gmail.com> Co-authored-by: Torkel Ödegaard <torkel@grafana.com>
2023-08-10 19:33:46 +08:00
name: `nested_frame${idx}`,
fields: [
{
Table: Support display of multiple sub tables (#71953) * Add nested option to DataFrame. Refactor Table to use nested dataframes for sub-tables * Use nested frames for TraceQL response * debugging * Fix cell text and table position * Update getItemSize * noHeader size * Update sub table renderer * Update table container height * Cleanup and fix RawPrometheusContainer height * Update resultTransformer and docker script * Updates to TableContainer, resultTransformer after merge * Fixes for table pagination in dashboards * Cell height and show footer enhancement/fix * Sub table links * Update RawPrometheusContainer * Remove console log * Update tests * Update storybook * Remove Tempo demo * Store nested data in single field via its values * Move nested prop into custom * Tempo demo * Add field type & update incorrect logic * Update docker compose image for Tempo * Update packages/grafana-data/src/field/fieldOverrides.ts Co-authored-by: Piotr Jamróz <pm.jamroz@gmail.com> * Simplify logic for getting nestedFrames and rendering sub tables * Update docs for table * Update nested table bg color * Lighten nested table bg color * Renames * Migrate frames using parentRowIndex and add deprecation notice * Update title * Align expander icon size between Table and interactive table * Table: Refactor out the expanded rows bits * fix spacing * Add line along left side for expanded rows * Disable hover row background when expanded --------- Co-authored-by: André Pereira <adrapereira@gmail.com> Co-authored-by: Piotr Jamróz <pm.jamroz@gmail.com> Co-authored-by: Torkel Ödegaard <torkel@grafana.com>
2023-08-10 19:33:46 +08:00
name: `humidity_${idx}`,
type: FieldType.string,
values: [`3%_${idx}`, `17%_${idx}`],
},
Table: Support display of multiple sub tables (#71953) * Add nested option to DataFrame. Refactor Table to use nested dataframes for sub-tables * Use nested frames for TraceQL response * debugging * Fix cell text and table position * Update getItemSize * noHeader size * Update sub table renderer * Update table container height * Cleanup and fix RawPrometheusContainer height * Update resultTransformer and docker script * Updates to TableContainer, resultTransformer after merge * Fixes for table pagination in dashboards * Cell height and show footer enhancement/fix * Sub table links * Update RawPrometheusContainer * Remove console log * Update tests * Update storybook * Remove Tempo demo * Store nested data in single field via its values * Move nested prop into custom * Tempo demo * Add field type & update incorrect logic * Update docker compose image for Tempo * Update packages/grafana-data/src/field/fieldOverrides.ts Co-authored-by: Piotr Jamróz <pm.jamroz@gmail.com> * Simplify logic for getting nestedFrames and rendering sub tables * Update docs for table * Update nested table bg color * Lighten nested table bg color * Renames * Migrate frames using parentRowIndex and add deprecation notice * Update title * Align expander icon size between Table and interactive table * Table: Refactor out the expanded rows bits * fix spacing * Add line along left side for expanded rows * Disable hover row background when expanded --------- Co-authored-by: André Pereira <adrapereira@gmail.com> Co-authored-by: Piotr Jamróz <pm.jamroz@gmail.com> Co-authored-by: Torkel Ödegaard <torkel@grafana.com>
2023-08-10 19:33:46 +08:00
{
name: `status_${idx}`,
type: FieldType.string,
values: [`ok_${idx}`, `humid_${idx}`],
},
Table: Support display of multiple sub tables (#71953) * Add nested option to DataFrame. Refactor Table to use nested dataframes for sub-tables * Use nested frames for TraceQL response * debugging * Fix cell text and table position * Update getItemSize * noHeader size * Update sub table renderer * Update table container height * Cleanup and fix RawPrometheusContainer height * Update resultTransformer and docker script * Updates to TableContainer, resultTransformer after merge * Fixes for table pagination in dashboards * Cell height and show footer enhancement/fix * Sub table links * Update RawPrometheusContainer * Remove console log * Update tests * Update storybook * Remove Tempo demo * Store nested data in single field via its values * Move nested prop into custom * Tempo demo * Add field type & update incorrect logic * Update docker compose image for Tempo * Update packages/grafana-data/src/field/fieldOverrides.ts Co-authored-by: Piotr Jamróz <pm.jamroz@gmail.com> * Simplify logic for getting nestedFrames and rendering sub tables * Update docs for table * Update nested table bg color * Lighten nested table bg color * Renames * Migrate frames using parentRowIndex and add deprecation notice * Update title * Align expander icon size between Table and interactive table * Table: Refactor out the expanded rows bits * fix spacing * Add line along left side for expanded rows * Disable hover row background when expanded --------- Co-authored-by: André Pereira <adrapereira@gmail.com> Co-authored-by: Piotr Jamróz <pm.jamroz@gmail.com> Co-authored-by: Torkel Ödegaard <torkel@grafana.com>
2023-08-10 19:33:46 +08:00
],
})
Table: Support display of multiple sub tables (#71953) * Add nested option to DataFrame. Refactor Table to use nested dataframes for sub-tables * Use nested frames for TraceQL response * debugging * Fix cell text and table position * Update getItemSize * noHeader size * Update sub table renderer * Update table container height * Cleanup and fix RawPrometheusContainer height * Update resultTransformer and docker script * Updates to TableContainer, resultTransformer after merge * Fixes for table pagination in dashboards * Cell height and show footer enhancement/fix * Sub table links * Update RawPrometheusContainer * Remove console log * Update tests * Update storybook * Remove Tempo demo * Store nested data in single field via its values * Move nested prop into custom * Tempo demo * Add field type & update incorrect logic * Update docker compose image for Tempo * Update packages/grafana-data/src/field/fieldOverrides.ts Co-authored-by: Piotr Jamróz <pm.jamroz@gmail.com> * Simplify logic for getting nestedFrames and rendering sub tables * Update docs for table * Update nested table bg color * Lighten nested table bg color * Renames * Migrate frames using parentRowIndex and add deprecation notice * Update title * Align expander icon size between Table and interactive table * Table: Refactor out the expanded rows bits * fix spacing * Add line along left side for expanded rows * Disable hover row background when expanded --------- Co-authored-by: André Pereira <adrapereira@gmail.com> Co-authored-by: Piotr Jamróz <pm.jamroz@gmail.com> Co-authored-by: Torkel Ödegaard <torkel@grafana.com>
2023-08-10 19:33:46 +08:00
);
Table: Support display of multiple sub tables (#71953) * Add nested option to DataFrame. Refactor Table to use nested dataframes for sub-tables * Use nested frames for TraceQL response * debugging * Fix cell text and table position * Update getItemSize * noHeader size * Update sub table renderer * Update table container height * Cleanup and fix RawPrometheusContainer height * Update resultTransformer and docker script * Updates to TableContainer, resultTransformer after merge * Fixes for table pagination in dashboards * Cell height and show footer enhancement/fix * Sub table links * Update RawPrometheusContainer * Remove console log * Update tests * Update storybook * Remove Tempo demo * Store nested data in single field via its values * Move nested prop into custom * Tempo demo * Add field type & update incorrect logic * Update docker compose image for Tempo * Update packages/grafana-data/src/field/fieldOverrides.ts Co-authored-by: Piotr Jamróz <pm.jamroz@gmail.com> * Simplify logic for getting nestedFrames and rendering sub tables * Update docs for table * Update nested table bg color * Lighten nested table bg color * Renames * Migrate frames using parentRowIndex and add deprecation notice * Update title * Align expander icon size between Table and interactive table * Table: Refactor out the expanded rows bits * fix spacing * Add line along left side for expanded rows * Disable hover row background when expanded --------- Co-authored-by: André Pereira <adrapereira@gmail.com> Co-authored-by: Piotr Jamróz <pm.jamroz@gmail.com> Co-authored-by: Torkel Ödegaard <torkel@grafana.com>
2023-08-10 19:33:46 +08:00
const defaultFrame = getDefaultDataFrame();
getTestContext({
data: applyOverrides({
...defaultFrame,
fields: [
...defaultFrame.fields,
{
name: 'nested',
type: FieldType.nestedFrames,
values: [[nestedFrame(0), nestedFrame(1)]],
config: {},
},
],
}),
});
});
it('then correct rows should be rendered and new table is rendered when expander is clicked', async () => {
expect(getTable()).toBeInTheDocument();
expect(screen.getAllByRole('columnheader')).toHaveLength(4);
expect(getColumnHeader(/time/)).toBeInTheDocument();
expect(getColumnHeader(/temperature/)).toBeInTheDocument();
expect(getColumnHeader(/img/)).toBeInTheDocument();
const rows = within(getTable()).getAllByRole('row');
expect(rows).toHaveLength(5);
expect(getRowsData(rows)).toEqual([
{ time: '2021-01-01 00:00:00', temperature: '10', link: '${__value.text} interpolation' },
{ time: '2021-01-01 03:00:00', temperature: 'NaN', link: '${__value.text} interpolation' },
{ time: '2021-01-01 01:00:00', temperature: '11', link: '${__value.text} interpolation' },
{ time: '2021-01-01 02:00:00', temperature: '12', link: '${__value.text} interpolation' },
]);
await userEvent.click(within(rows[1]).getByLabelText('Expand row'));
Table: Support display of multiple sub tables (#71953) * Add nested option to DataFrame. Refactor Table to use nested dataframes for sub-tables * Use nested frames for TraceQL response * debugging * Fix cell text and table position * Update getItemSize * noHeader size * Update sub table renderer * Update table container height * Cleanup and fix RawPrometheusContainer height * Update resultTransformer and docker script * Updates to TableContainer, resultTransformer after merge * Fixes for table pagination in dashboards * Cell height and show footer enhancement/fix * Sub table links * Update RawPrometheusContainer * Remove console log * Update tests * Update storybook * Remove Tempo demo * Store nested data in single field via its values * Move nested prop into custom * Tempo demo * Add field type & update incorrect logic * Update docker compose image for Tempo * Update packages/grafana-data/src/field/fieldOverrides.ts Co-authored-by: Piotr Jamróz <pm.jamroz@gmail.com> * Simplify logic for getting nestedFrames and rendering sub tables * Update docs for table * Update nested table bg color * Lighten nested table bg color * Renames * Migrate frames using parentRowIndex and add deprecation notice * Update title * Align expander icon size between Table and interactive table * Table: Refactor out the expanded rows bits * fix spacing * Add line along left side for expanded rows * Disable hover row background when expanded --------- Co-authored-by: André Pereira <adrapereira@gmail.com> Co-authored-by: Piotr Jamróz <pm.jamroz@gmail.com> Co-authored-by: Torkel Ödegaard <torkel@grafana.com>
2023-08-10 19:33:46 +08:00
expect(screen.getAllByRole('columnheader')).toHaveLength(8);
expect(getColumnHeader(/humidity_0/)).toBeInTheDocument();
expect(getColumnHeader(/humidity_1/)).toBeInTheDocument();
expect(getColumnHeader(/status_0/)).toBeInTheDocument();
expect(getColumnHeader(/status_1/)).toBeInTheDocument();
const subTable0 = screen.getAllByRole('table')[1];
const subTableRows0 = within(subTable0).getAllByRole('row');
expect(subTableRows0).toHaveLength(3);
expect(within(subTableRows0[1]).getByText(/3%_0/)).toBeInTheDocument();
expect(within(subTableRows0[1]).getByText(/ok_0/)).toBeInTheDocument();
expect(within(subTableRows0[2]).getByText(/17%_0/)).toBeInTheDocument();
expect(within(subTableRows0[2]).getByText(/humid_0/)).toBeInTheDocument();
const subTable1 = screen.getAllByRole('table')[2];
const subTableRows1 = within(subTable1).getAllByRole('row');
expect(subTableRows1).toHaveLength(3);
expect(within(subTableRows1[1]).getByText(/3%_1/)).toBeInTheDocument();
expect(within(subTableRows1[1]).getByText(/ok_1/)).toBeInTheDocument();
expect(within(subTableRows1[2]).getByText(/17%_1/)).toBeInTheDocument();
expect(within(subTableRows1[2]).getByText(/humid_1/)).toBeInTheDocument();
});
it('then properly handle row expansion and sorting', async () => {
expect(getTable()).toBeInTheDocument();
expect(screen.getAllByRole('columnheader')).toHaveLength(4);
expect(getColumnHeader(/time/)).toBeInTheDocument();
expect(getColumnHeader(/temperature/)).toBeInTheDocument();
expect(getColumnHeader(/img/)).toBeInTheDocument();
let rows = within(getTable()).getAllByRole('row');
expect(rows).toHaveLength(5);
expect(getRowsData(rows)).toEqual([
{ time: '2021-01-01 00:00:00', temperature: '10', link: '${__value.text} interpolation' },
{ time: '2021-01-01 03:00:00', temperature: 'NaN', link: '${__value.text} interpolation' },
{ time: '2021-01-01 01:00:00', temperature: '11', link: '${__value.text} interpolation' },
{ time: '2021-01-01 02:00:00', temperature: '12', link: '${__value.text} interpolation' },
]);
// Sort rows, and check the new order
const table = getTable();
await userEvent.click(within(table).getAllByTitle('Toggle SortBy')[0]);
rows = within(table).getAllByRole('row');
expect(rows).toHaveLength(5);
expect(getRowsData(rows)).toEqual([
{ time: '2021-01-01 00:00:00', temperature: '10', link: '${__value.text} interpolation' },
{ time: '2021-01-01 01:00:00', temperature: '11', link: '${__value.text} interpolation' },
{ time: '2021-01-01 02:00:00', temperature: '12', link: '${__value.text} interpolation' },
{ time: '2021-01-01 03:00:00', temperature: 'NaN', link: '${__value.text} interpolation' },
]);
// No sub table exists before expending a row
let tables = screen.getAllByRole('table');
expect(tables).toHaveLength(1);
// Expand a row, and check its height
rows = within(getTable()).getAllByRole('row');
await userEvent.click(within(rows[1]).getByLabelText('Expand row'));
tables = screen.getAllByRole('table');
expect(tables).toHaveLength(3);
let subTable = screen.getAllByRole('table')[2];
expect(subTable.style.height).toBe('108px');
// Sort again rows
tables = screen.getAllByRole('table');
await userEvent.click(within(tables[0]).getAllByTitle('Toggle SortBy')[0]);
rows = within(table).getAllByRole('row');
expect(rows).toHaveLength(5);
expect(getRowsData(rows)).toEqual([
{ time: '2021-01-01 03:00:00', temperature: 'NaN', link: '${__value.text} interpolation' },
{ time: '2021-01-01 02:00:00', temperature: '12', link: '${__value.text} interpolation' },
{ time: '2021-01-01 01:00:00', temperature: '11', link: '${__value.text} interpolation' },
{ time: '2021-01-01 00:00:00', temperature: '10', link: '${__value.text} interpolation' },
]);
// Expand another row
rows = within(getTable()).getAllByRole('row');
await userEvent.click(within(rows[1]).getByLabelText('Expand row'));
subTable = screen.getAllByRole('table')[2];
expect(subTable.style.height).toBe('108px');
});
});
describe('when mounted with scrolled to specific row', () => {
it('the row should be visible', async () => {
getTestContext({
initialRowIndex: 2,
});
expect(getTable()).toBeInTheDocument();
const rows = within(getTable()).getAllByRole('row');
expect(rows).toHaveLength(5);
let selected = within(getTable()).getByRole('row', { selected: true });
expect(selected).toBeVisible();
});
});
});