React UI: More conversions to Function Components (#6259)

* React UI: More conversions to Function Components

Signed-off-by: Julius Volz <julius.volz@gmail.com>

* Address chat feedback over Riot

Signed-off-by: Julius Volz <julius.volz@gmail.com>
This commit is contained in:
Julius Volz 2019-11-02 21:45:22 +01:00 committed by GitHub
parent f7446778f3
commit fffb5ca1e9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 109 additions and 130 deletions

View File

@ -1,4 +1,4 @@
import React, { PureComponent, ReactNode } from 'react';
import React, { FC, ReactNode } from 'react';
import { Alert, Table } from 'reactstrap';
@ -41,96 +41,92 @@ interface Metric {
type SampleValue = [number, string];
class DataTable extends PureComponent<QueryResult> {
limitSeries(series: InstantSample[] | RangeSamples[]): InstantSample[] | RangeSamples[] {
const maxSeries = 10000;
const limitSeries = <S extends InstantSample | RangeSamples>(series: S[]): S[] => {
const maxSeries = 10000;
if (series.length > maxSeries) {
return series.slice(0, maxSeries);
}
return series;
if (series.length > maxSeries) {
return series.slice(0, maxSeries);
}
return series;
};
const DataTable: FC<QueryResult> = ({ data }) => {
if (data === null) {
return <Alert color="light">No data queried yet</Alert>;
}
render() {
const data = this.props.data;
if (data.result === null || data.result.length === 0) {
return <Alert color="secondary">Empty query result</Alert>;
}
if (data === null) {
return <Alert color="light">No data queried yet</Alert>;
}
if (data.result === null || data.result.length === 0) {
return <Alert color="secondary">Empty query result</Alert>;
}
let rows: ReactNode[] = [];
let limited = false;
switch (data.resultType) {
case 'vector':
rows = (this.limitSeries(data.result) as InstantSample[]).map(
(s: InstantSample, index: number): ReactNode => {
return (
<tr key={index}>
<td>
<SeriesName labels={s.metric} format={false} />
</td>
<td>{s.value[1]}</td>
</tr>
);
}
);
limited = rows.length !== data.result.length;
break;
case 'matrix':
rows = (this.limitSeries(data.result) as RangeSamples[]).map((s, index) => {
const valueText = s.values
.map(v => {
return [1] + ' @' + v[0];
})
.join('\n');
let rows: ReactNode[] = [];
let limited = false;
switch (data.resultType) {
case 'vector':
rows = (limitSeries(data.result) as InstantSample[]).map(
(s: InstantSample, index: number): ReactNode => {
return (
<tr style={{ whiteSpace: 'pre' }} key={index}>
<tr key={index}>
<td>
<SeriesName labels={s.metric} format={false} />
</td>
<td>{valueText}</td>
<td>{s.value[1]}</td>
</tr>
);
});
limited = rows.length !== data.result.length;
break;
case 'scalar':
rows.push(
<tr key="0">
<td>scalar</td>
<td>{data.result[1]}</td>
}
);
limited = rows.length !== data.result.length;
break;
case 'matrix':
rows = (limitSeries(data.result) as RangeSamples[]).map((s, index) => {
const valueText = s.values
.map(v => {
return [1] + ' @' + v[0];
})
.join('\n');
return (
<tr style={{ whiteSpace: 'pre' }} key={index}>
<td>
<SeriesName labels={s.metric} format={false} />
</td>
<td>{valueText}</td>
</tr>
);
break;
case 'string':
rows.push(
<tr key="0">
<td>scalar</td>
<td>{data.result[1]}</td>
</tr>
);
break;
default:
return <Alert color="danger">Unsupported result value type</Alert>;
}
return (
<>
{limited && (
<Alert color="danger">
<strong>Warning:</strong> Fetched {data.result.length} metrics, only displaying first {rows.length}.
</Alert>
)}
<Table hover size="sm" className="data-table">
<tbody>{rows}</tbody>
</Table>
</>
);
});
limited = rows.length !== data.result.length;
break;
case 'scalar':
rows.push(
<tr key="0">
<td>scalar</td>
<td>{data.result[1]}</td>
</tr>
);
break;
case 'string':
rows.push(
<tr key="0">
<td>scalar</td>
<td>{data.result[1]}</td>
</tr>
);
break;
default:
return <Alert color="danger">Unsupported result value type</Alert>;
}
}
return (
<>
{limited && (
<Alert color="danger">
<strong>Warning:</strong> Fetched {data.result.length} metrics, only displaying first {rows.length}.
</Alert>
)}
<Table hover size="sm" className="data-table">
<tbody>{rows}</tbody>
</Table>
</>
);
};
export default DataTable;

View File

@ -1,4 +1,4 @@
import React, { PureComponent } from 'react';
import React, { FC } from 'react';
import SeriesName from './SeriesName';
@ -6,31 +6,23 @@ interface LegendProps {
series: any; // TODO: Type this.
}
class Legend extends PureComponent<LegendProps> {
renderLegendItem(s: any) {
return (
<tr key={s.index} className="legend-item">
<td>
<div className="legend-swatch" style={{ backgroundColor: s.color }}></div>
</td>
<td>
<SeriesName labels={s.labels} format={true} />
</td>
</tr>
);
}
render() {
return (
<table className="graph-legend">
<tbody>
{this.props.series.map((s: any) => {
return this.renderLegendItem(s);
})}
</tbody>
</table>
);
}
}
const Legend: FC<LegendProps> = ({ series }) => {
return (
<table className="graph-legend">
<tbody>
{series.map((s: any) => (
<tr key={s.index} className="legend-item">
<td>
<div className="legend-swatch" style={{ backgroundColor: s.color }}></div>
</td>
<td>
<SeriesName labels={s.labels} format={true} />
</td>
</tr>
))}
</tbody>
</table>
);
};
export default Legend;

View File

@ -1,4 +1,4 @@
import React, { PureComponent } from 'react';
import React, { FC } from 'react';
import metricToSeriesName from './MetricFormat';
interface SeriesNameProps {
@ -6,11 +6,9 @@ interface SeriesNameProps {
format: boolean;
}
class SeriesName extends PureComponent<SeriesNameProps> {
renderFormatted(): React.ReactNode {
const labels = this.props.labels!;
const labelNodes: React.ReactNode[] = [];
const SeriesName: FC<SeriesNameProps> = ({ labels, format }) => {
const renderFormatted = (): React.ReactElement => {
const labelNodes: React.ReactElement[] = [];
let first = true;
for (const label in labels) {
if (label === '__name__') {
@ -31,31 +29,24 @@ class SeriesName extends PureComponent<SeriesNameProps> {
return (
<>
<span className="legend-metric-name">{labels.__name__ || ''}</span>
<span className="legend-metric-name">{labels!.__name__ || ''}</span>
<span className="legend-label-brace">{'{'}</span>
{labelNodes}
<span className="legend-label-brace">{'}'}</span>
</>
);
};
if (labels === null) {
return <>scalar</>;
}
renderPlain() {
const labels = this.props.labels!;
return metricToSeriesName(labels);
if (format) {
return renderFormatted();
}
render() {
if (this.props.labels === null) {
return 'scalar';
}
if (this.props.format) {
return this.renderFormatted();
}
// Return a simple text node. This is much faster to scroll through
// for longer lists (hundreds of items).
return this.renderPlain();
}
}
// Return a simple text node. This is much faster to scroll through
// for longer lists (hundreds of items).
return <>{metricToSeriesName(labels!)}</>;
};
export default SeriesName;