Commit b709f6ad by Torkel Ödegaard Committed by GitHub

TablePanel: Adding sort order persistance (#24705)

* TablePanel: Adding sort order persistance

* adds panel test dashboard for table panel
parent 6b29c117
import React, { FC, memo, useCallback, useMemo } from 'react';
import { DataFrame, Field } from '@grafana/data';
import { DataFrame, Field, getFieldDisplayName } from '@grafana/data';
import {
Cell,
Column,
......@@ -14,7 +14,12 @@ import {
import { FixedSizeList } from 'react-window';
import { getColumns, getTextAlign } from './utils';
import { useTheme } from '../../themes';
import { TableColumnResizeActionCallback, TableFilterActionCallback, TableSortByActionCallback } from './types';
import {
TableColumnResizeActionCallback,
TableFilterActionCallback,
TableSortByActionCallback,
TableSortByFieldState,
} from './types';
import { getTableStyles, TableStyles } from './styles';
import { TableCell } from './TableCell';
import { Icon } from '../Icon/Icon';
......@@ -30,9 +35,10 @@ export interface Props {
columnMinWidth?: number;
noHeader?: boolean;
resizable?: boolean;
initialSortBy?: TableSortByFieldState[];
onCellClick?: TableFilterActionCallback;
onColumnResize?: TableColumnResizeActionCallback;
onSortBy?: TableSortByActionCallback;
onSortByChange?: TableSortByActionCallback;
}
interface ReactTableInternalState extends UseResizeColumnsState<{}>, UseSortByState<{}> {}
......@@ -43,25 +49,66 @@ function useTableStateReducer(props: Props) {
switch (action.type) {
case 'columnDoneResizing':
if (props.onColumnResize) {
const { data } = props;
const info = (newState.columnResizing.headerIdWidths as any)[0];
const columnIdString = info[0];
const fieldIndex = parseInt(columnIdString, 10);
const width = Math.round(newState.columnResizing.columnWidths[columnIdString] as number);
props.onColumnResize(fieldIndex, width);
const field = data.fields[fieldIndex];
if (!field) {
return newState;
}
const fieldDisplayName = getFieldDisplayName(field, data);
props.onColumnResize(fieldDisplayName, width);
}
case 'toggleSortBy':
if (props.onSortBy) {
// todo call callback and persist
if (props.onSortByChange) {
const { data } = props;
const sortByFields: TableSortByFieldState[] = [];
for (const sortItem of newState.sortBy) {
const field = data.fields[parseInt(sortItem.id, 10)];
if (!field) {
continue;
}
sortByFields.push({
displayName: getFieldDisplayName(field, data),
desc: sortItem.desc,
});
}
props.onSortByChange(sortByFields);
}
break;
}
return newState;
},
[props.onColumnResize]
[props.onColumnResize, props.onSortByChange, props.data]
);
}
function getInitialState(props: Props, columns: Column[]): Partial<ReactTableInternalState> {
const state: Partial<ReactTableInternalState> = {};
if (props.initialSortBy) {
state.sortBy = [];
for (const sortBy of props.initialSortBy) {
for (const col of columns) {
if (col.Header === sortBy.displayName) {
state.sortBy.push({ id: col.id as string, desc: sortBy.desc });
}
}
}
}
return state;
}
export const Table: FC<Props> = memo((props: Props) => {
const { data, height, onCellClick, width, columnMinWidth = COLUMN_MIN_WIDTH, noHeader, resizable = true } = props;
const theme = useTheme();
......@@ -91,10 +138,7 @@ export const Table: FC<Props> = memo((props: Props) => {
data: memoizedData,
disableResizing: !resizable,
stateReducer: stateReducer,
// this is how you set initial sort by state
// initialState: {
// sortBy: [{ id: '2', desc: true }],
// },
initialState: getInitialState(props, memoizedColumns),
}),
[memoizedColumns, memoizedData, stateReducer, resizable]
);
......
......@@ -26,11 +26,11 @@ export interface TableRow {
}
export type TableFilterActionCallback = (key: string, value: string) => void;
export type TableColumnResizeActionCallback = (fieldIndex: number, width: number) => void;
export type TableColumnResizeActionCallback = (fieldDisplayName: string, width: number) => void;
export type TableSortByActionCallback = (state: TableSortByFieldState[]) => void;
export interface TableSortByFieldState {
fieldIndex: number;
displayName: string;
desc?: boolean;
}
......
......@@ -45,7 +45,7 @@ export { ModalsProvider, ModalRoot, ModalsController } from './Modal/ModalsConte
export { SetInterval } from './SetInterval/SetInterval';
export { Table } from './Table/Table';
export { TableCellDisplayMode } from './Table/types';
export { TableCellDisplayMode, TableSortByFieldState } from './Table/types';
export { TableInputCSV } from './TableInputCSV/TableInputCSV';
export { TabsBar } from './Tabs/TabsBar';
export { Tab } from './Tabs/Tab';
......
import React, { Component } from 'react';
import { Table, Select } from '@grafana/ui';
import {
FieldMatcherID,
PanelProps,
DataFrame,
SelectableValue,
getFrameDisplayName,
getFieldDisplayName,
} from '@grafana/data';
import { FieldMatcherID, PanelProps, DataFrame, SelectableValue, getFrameDisplayName } from '@grafana/data';
import { Options } from './types';
import { css } from 'emotion';
import { config } from 'app/core/config';
import { TableSortByFieldState } from '@grafana/ui/src/components/Table/types';
interface Props extends PanelProps<Options> {}
......@@ -20,21 +14,10 @@ export class TablePanel extends Component<Props> {
super(props);
}
onColumnResize = (fieldIndex: number, width: number) => {
const { fieldConfig, data } = this.props;
onColumnResize = (fieldDisplayName: string, width: number) => {
const { fieldConfig } = this.props;
const { overrides } = fieldConfig;
const frame = data.series[this.getCurrentFrameIndex()];
if (!frame) {
return;
}
const field = frame.fields[fieldIndex];
if (!field) {
return;
}
const fieldDisplayName = getFieldDisplayName(field, frame, data.series);
const matcherId = FieldMatcherID.byName;
const propId = 'custom.width';
......@@ -62,6 +45,13 @@ export class TablePanel extends Component<Props> {
});
};
onSortByChange = (sortBy: TableSortByFieldState[]) => {
this.props.onOptionsChange({
...this.props.options,
sortBy,
});
};
onChangeTableSelection = (val: SelectableValue<number>) => {
this.props.onOptionsChange({
...this.props.options,
......@@ -82,6 +72,8 @@ export class TablePanel extends Component<Props> {
data={frame}
noHeader={!options.showHeader}
resizable={true}
initialSortBy={options.sortBy}
onSortByChange={this.onSortByChange}
onColumnResize={this.onColumnResize}
/>
);
......
import { TableSortByFieldState } from '@grafana/ui';
export interface Options {
frameIndex: number;
showHeader: boolean;
sortBy?: TableSortByFieldState[];
}
export interface TableSortBy {
displayName: string;
desc: boolean;
}
export interface CustomFieldConfig {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment