prometheus/web/ui/react-app/src/pages/graph/DataTable.tsx
Tobias Guggenmos 3a204be6b7 PromQL: Fix string and parentheses handling in engine (#6612)
* WIP: PromQL: Allow engine to return strings

Signed-off-by: Tobias Guggenmos <tguggenm@redhat.com>

* Add test suggested by @roidelapluie

Signed-off-by: Tobias Guggenmos <tguggenm@redhat.com>

* Fix typo in React UI

Signed-off-by: Tobias Guggenmos <tguggenm@redhat.com>

* Fix parenthesis handling for functions and aggregator params

Signed-off-by: Tobias Guggenmos <tguggenm@redhat.com>

* Add more tests

Signed-off-by: Tobias Guggenmos <tguggenm@redhat.com>

* Fix React UI test

Signed-off-by: Tobias Guggenmos <tguggenm@redhat.com>
2020-01-15 18:31:58 +01:00

130 lines
2.9 KiB
TypeScript

import React, { FC, ReactNode } from 'react';
import { Alert, Table } from 'reactstrap';
import SeriesName from './SeriesName';
import { Metric } from '../../types/types';
export interface QueryResult {
data:
| null
| {
resultType: 'vector';
result: InstantSample[];
}
| {
resultType: 'matrix';
result: RangeSamples[];
}
| {
resultType: 'scalar';
result: SampleValue;
}
| {
resultType: 'string';
result: string;
};
}
interface InstantSample {
metric: Metric;
value: SampleValue;
}
interface RangeSamples {
metric: Metric;
values: SampleValue[];
}
type SampleValue = [number, string];
const limitSeries = <S extends InstantSample | RangeSamples>(series: S[]): S[] => {
const maxSeries = 10000;
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>;
}
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 = (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 = (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>
);
});
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>string</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;