2019-03-08 08:52:20 +08:00
|
|
|
import React, { Component } from 'react';
|
2019-03-06 10:17:44 +08:00
|
|
|
|
2020-04-17 03:35:58 +08:00
|
|
|
import { Table, Select } from '@grafana/ui';
|
2020-05-19 15:23:25 +08:00
|
|
|
import { FieldMatcherID, PanelProps, DataFrame, SelectableValue, getFrameDisplayName } from '@grafana/data';
|
2019-03-07 02:54:47 +08:00
|
|
|
import { Options } from './types';
|
2020-04-17 03:35:58 +08:00
|
|
|
import { css } from 'emotion';
|
|
|
|
import { config } from 'app/core/config';
|
2020-05-19 15:23:25 +08:00
|
|
|
import { TableSortByFieldState } from '@grafana/ui/src/components/Table/types';
|
2019-03-07 02:54:47 +08:00
|
|
|
|
2019-03-06 08:07:46 +08:00
|
|
|
interface Props extends PanelProps<Options> {}
|
|
|
|
|
2019-03-08 08:52:20 +08:00
|
|
|
export class TablePanel extends Component<Props> {
|
2019-03-07 02:10:04 +08:00
|
|
|
constructor(props: Props) {
|
|
|
|
super(props);
|
2019-03-06 10:17:44 +08:00
|
|
|
}
|
|
|
|
|
2020-05-19 15:23:25 +08:00
|
|
|
onColumnResize = (fieldDisplayName: string, width: number) => {
|
|
|
|
const { fieldConfig } = this.props;
|
2020-04-20 15:27:40 +08:00
|
|
|
const { overrides } = fieldConfig;
|
2020-04-07 21:20:27 +08:00
|
|
|
|
2020-04-20 15:27:40 +08:00
|
|
|
const matcherId = FieldMatcherID.byName;
|
|
|
|
const propId = 'custom.width';
|
|
|
|
|
|
|
|
// look for existing override
|
2020-05-11 20:25:26 +08:00
|
|
|
const override = overrides.find(o => o.matcher.id === matcherId && o.matcher.options === fieldDisplayName);
|
2020-04-20 15:27:40 +08:00
|
|
|
|
|
|
|
if (override) {
|
|
|
|
// look for existing property
|
|
|
|
const property = override.properties.find(prop => prop.id === propId);
|
|
|
|
if (property) {
|
|
|
|
property.value = width;
|
|
|
|
} else {
|
|
|
|
override.properties.push({ id: propId, value: width });
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
overrides.push({
|
2020-05-11 20:25:26 +08:00
|
|
|
matcher: { id: matcherId, options: fieldDisplayName },
|
2020-04-20 15:27:40 +08:00
|
|
|
properties: [{ id: propId, value: width }],
|
|
|
|
});
|
|
|
|
}
|
2020-04-07 21:20:27 +08:00
|
|
|
|
|
|
|
this.props.onFieldConfigChange({
|
2020-04-20 15:27:40 +08:00
|
|
|
...fieldConfig,
|
2020-04-07 21:20:27 +08:00
|
|
|
overrides,
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2020-05-19 15:23:25 +08:00
|
|
|
onSortByChange = (sortBy: TableSortByFieldState[]) => {
|
|
|
|
this.props.onOptionsChange({
|
|
|
|
...this.props.options,
|
|
|
|
sortBy,
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2020-04-17 03:35:58 +08:00
|
|
|
onChangeTableSelection = (val: SelectableValue<number>) => {
|
|
|
|
this.props.onOptionsChange({
|
|
|
|
...this.props.options,
|
|
|
|
frameIndex: val.value || 0,
|
|
|
|
});
|
|
|
|
|
|
|
|
// Force a redraw -- but no need to re-query
|
|
|
|
this.forceUpdate();
|
|
|
|
};
|
|
|
|
|
|
|
|
renderTable(frame: DataFrame, width: number, height: number) {
|
2020-04-20 15:27:40 +08:00
|
|
|
const { options } = this.props;
|
|
|
|
|
|
|
|
return (
|
|
|
|
<Table
|
|
|
|
height={height}
|
|
|
|
width={width}
|
|
|
|
data={frame}
|
|
|
|
noHeader={!options.showHeader}
|
|
|
|
resizable={true}
|
2020-05-19 15:23:25 +08:00
|
|
|
initialSortBy={options.sortBy}
|
|
|
|
onSortByChange={this.onSortByChange}
|
2020-04-20 15:27:40 +08:00
|
|
|
onColumnResize={this.onColumnResize}
|
|
|
|
/>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
getCurrentFrameIndex() {
|
|
|
|
const { data, options } = this.props;
|
|
|
|
const count = data.series?.length;
|
|
|
|
return options.frameIndex > 0 && options.frameIndex < count ? options.frameIndex : 0;
|
2020-04-17 03:35:58 +08:00
|
|
|
}
|
|
|
|
|
2019-03-06 10:17:44 +08:00
|
|
|
render() {
|
2020-04-20 15:27:40 +08:00
|
|
|
const { data, height, width } = this.props;
|
2019-03-07 02:10:04 +08:00
|
|
|
|
2020-04-17 03:35:58 +08:00
|
|
|
const count = data.series?.length;
|
|
|
|
|
|
|
|
if (!count || count < 1) {
|
|
|
|
return <div>No data</div>;
|
2019-03-06 08:07:46 +08:00
|
|
|
}
|
|
|
|
|
2020-04-17 03:35:58 +08:00
|
|
|
if (count > 1) {
|
|
|
|
const inputHeight = config.theme.spacing.formInputHeight;
|
2020-04-20 15:27:40 +08:00
|
|
|
const padding = 8 * 2;
|
|
|
|
const currentIndex = this.getCurrentFrameIndex();
|
2020-04-17 03:35:58 +08:00
|
|
|
const names = data.series.map((frame, index) => {
|
|
|
|
return {
|
2020-05-12 19:52:53 +08:00
|
|
|
label: getFrameDisplayName(frame),
|
2020-04-17 03:35:58 +08:00
|
|
|
value: index,
|
|
|
|
};
|
|
|
|
});
|
|
|
|
|
|
|
|
return (
|
|
|
|
<div className={tableStyles.wrapper}>
|
2020-04-20 15:27:40 +08:00
|
|
|
{this.renderTable(data.series[currentIndex], width, height - inputHeight - padding)}
|
|
|
|
<div className={tableStyles.selectWrapper}>
|
|
|
|
<Select options={names} value={names[currentIndex]} onChange={this.onChangeTableSelection} />
|
|
|
|
</div>
|
2020-04-17 03:35:58 +08:00
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2020-04-20 15:27:40 +08:00
|
|
|
return this.renderTable(data.series[0], width, height - 12);
|
2019-03-06 08:07:46 +08:00
|
|
|
}
|
|
|
|
}
|
2020-04-17 03:35:58 +08:00
|
|
|
|
|
|
|
const tableStyles = {
|
|
|
|
wrapper: css`
|
|
|
|
display: flex;
|
|
|
|
flex-direction: column;
|
|
|
|
justify-content: space-between;
|
|
|
|
height: 100%;
|
|
|
|
`,
|
2020-04-20 15:27:40 +08:00
|
|
|
selectWrapper: css`
|
|
|
|
padding: 8px;
|
|
|
|
`,
|
2020-04-17 03:35:58 +08:00
|
|
|
};
|