mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Panel inspect: Horizontal scrolling in Data table (#22245)
* First try at horizontal scrolling * move width logic to table * Update packages/grafana-ui/src/components/Table/Table.tsx Co-Authored-By: Dominik Prokop <dominik.prokop@grafana.com> * wrap table with memo * fix typo * re add field * WIP: Table scrolling troubles * Annother approach * Think it's working * Removed unnessary change * Table: Added custom scrollbar for horizontal scrolling * Removed console log and fixed test Co-authored-by: Dominik Prokop <dominik.prokop@grafana.com> Co-authored-by: Torkel Ödegaard <torkel@grafana.com>
This commit is contained in:
parent
066d5cf4da
commit
3f7b058bea
@ -1,4 +1,4 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import React, { FC, memo, useMemo } from 'react';
|
||||
import { DataFrame, Field } from '@grafana/data';
|
||||
import { useSortBy, useTable, useBlockLayout, Cell } from 'react-table';
|
||||
import { FixedSizeList } from 'react-window';
|
||||
@ -10,22 +10,25 @@ import { getTableStyles } from './styles';
|
||||
import { TableCell } from './TableCell';
|
||||
import { Icon } from '../Icon/Icon';
|
||||
import { getTextAlign } from './utils';
|
||||
import { CustomScrollbar } from '../CustomScrollbar/CustomScrollbar';
|
||||
|
||||
export interface Props {
|
||||
data: DataFrame;
|
||||
width: number;
|
||||
height: number;
|
||||
/** Minimal column width specified in pixels */
|
||||
columnMinWidth?: number;
|
||||
onCellClick?: TableFilterActionCallback;
|
||||
}
|
||||
|
||||
export const Table = ({ data, height, onCellClick, width }: Props) => {
|
||||
export const Table: FC<Props> = memo(({ data, height, onCellClick, width, columnMinWidth }) => {
|
||||
const theme = useTheme();
|
||||
const [ref, headerRowMeasurements] = useMeasure();
|
||||
const tableStyles = getTableStyles(theme);
|
||||
|
||||
const { getTableProps, headerGroups, rows, prepareRow } = useTable(
|
||||
{
|
||||
columns: useMemo(() => getColumns(data, width), [data]),
|
||||
columns: useMemo(() => getColumns(data, width, columnMinWidth ?? 150), [data, width, columnMinWidth]),
|
||||
data: useMemo(() => getTableRows(data), [data]),
|
||||
},
|
||||
useSortBy,
|
||||
@ -53,28 +56,39 @@ export const Table = ({ data, height, onCellClick, width }: Props) => {
|
||||
[prepareRow, rows]
|
||||
);
|
||||
|
||||
let totalWidth = 0;
|
||||
|
||||
for (const headerGroup of headerGroups) {
|
||||
for (const header of headerGroup.headers) {
|
||||
totalWidth += header.width as number;
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div {...getTableProps()} className={tableStyles.table}>
|
||||
<div>
|
||||
{headerGroups.map((headerGroup: any) => (
|
||||
<div className={tableStyles.thead} {...headerGroup.getHeaderGroupProps()} ref={ref}>
|
||||
{headerGroup.headers.map((column: any) =>
|
||||
renderHeaderCell(column, tableStyles.headerCell, data.fields[column.index])
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<FixedSizeList
|
||||
height={height - headerRowMeasurements.height}
|
||||
itemCount={rows.length}
|
||||
itemSize={tableStyles.rowHeight}
|
||||
width={width}
|
||||
>
|
||||
{RenderRow}
|
||||
</FixedSizeList>
|
||||
<CustomScrollbar>
|
||||
<div>
|
||||
{headerGroups.map((headerGroup: any) => (
|
||||
<div className={tableStyles.thead} {...headerGroup.getHeaderGroupProps()} ref={ref}>
|
||||
{headerGroup.headers.map((column: any) =>
|
||||
renderHeaderCell(column, tableStyles.headerCell, data.fields[column.index])
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<FixedSizeList
|
||||
height={height - headerRowMeasurements.height}
|
||||
itemCount={rows.length}
|
||||
itemSize={tableStyles.rowHeight}
|
||||
width={totalWidth ?? width}
|
||||
style={{ overflow: 'hidden auto' }}
|
||||
>
|
||||
{RenderRow}
|
||||
</FixedSizeList>
|
||||
</CustomScrollbar>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
});
|
||||
|
||||
function renderHeaderCell(column: any, className: string, field: Field) {
|
||||
const headerProps = column.getHeaderProps(column.getSortByToggleProps());
|
||||
|
@ -31,8 +31,10 @@ export const getTableStyles = stylesFactory(
|
||||
cellHeightInner: bodyFontSize * lineHeight,
|
||||
rowHeight: cellHeight + 2,
|
||||
table: css`
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
border-spacing: 0;
|
||||
display: flex;
|
||||
`,
|
||||
thead: css`
|
||||
label: thead;
|
||||
|
@ -40,12 +40,13 @@ describe('Table utils', () => {
|
||||
});
|
||||
|
||||
it('Should distribute width and use field config width', () => {
|
||||
const columns = getColumns(getData(), 1000);
|
||||
const columns = getColumns(getData(), 1000, 120);
|
||||
|
||||
expect(columns[0].width).toBe(450);
|
||||
expect(columns[1].width).toBe(100);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getTextAlign', () => {
|
||||
it('Should use textAlign from custom', () => {
|
||||
const data = getData();
|
||||
|
@ -42,7 +42,7 @@ export function getTextAlign(field: Field): TextAlignProperty {
|
||||
return 'left';
|
||||
}
|
||||
|
||||
export function getColumns(data: DataFrame, availableWidth: number): Column[] {
|
||||
export function getColumns(data: DataFrame, availableWidth: number, columnMinWidth: number): Column[] {
|
||||
const columns: Column[] = [];
|
||||
let fieldCountWithoutWidth = data.fields.length;
|
||||
|
||||
@ -67,7 +67,7 @@ export function getColumns(data: DataFrame, availableWidth: number): Column[] {
|
||||
const sharedWidth = availableWidth / fieldCountWithoutWidth;
|
||||
for (const column of columns) {
|
||||
if (!column.width) {
|
||||
column.width = sharedWidth;
|
||||
column.width = Math.max(sharedWidth, columnMinWidth);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -219,6 +219,7 @@ export class PanelInspector extends PureComponent<Props, State> {
|
||||
if (width === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={{ width, height }}>
|
||||
<Table width={width} height={height} data={processed[selected]} />
|
||||
|
Loading…
Reference in New Issue
Block a user