github.com/thanos-io/thanos@v0.32.5/pkg/ui/react-app/src/pages/graph/DataTable.tsx (about)

     1  import React, { FC, ReactNode } from 'react';
     2  
     3  import { UncontrolledAlert, Table } from 'reactstrap';
     4  
     5  import SeriesName from './SeriesName';
     6  import { Metric, Histogram, SampleValue, SampleHistogram } from '../../types/types';
     7  
     8  import moment from 'moment';
     9  
    10  export interface QueryResult {
    11    data:
    12      | null
    13      | {
    14          resultType: 'vector';
    15          result: InstantSample[];
    16        }
    17      | {
    18          resultType: 'matrix';
    19          result: RangeSamples[];
    20        }
    21      | {
    22          resultType: 'scalar';
    23          result: SampleValue;
    24        }
    25      | {
    26          resultType: 'string';
    27          result: string;
    28        };
    29  }
    30  
    31  interface InstantSample {
    32    metric: Metric;
    33    value?: SampleValue;
    34    histogram?: SampleHistogram;
    35  }
    36  
    37  interface RangeSamples {
    38    metric: Metric;
    39    values?: SampleValue[];
    40    histograms?: SampleHistogram[];
    41  }
    42  
    43  const limitSeries = <S extends InstantSample | RangeSamples>(series: S[]): S[] => {
    44    const maxSeries = 10000;
    45  
    46    if (series.length > maxSeries) {
    47      return series.slice(0, maxSeries);
    48    }
    49    return series;
    50  };
    51  
    52  const DataTable: FC<QueryResult> = ({ data }) => {
    53    if (data === null) {
    54      return <UncontrolledAlert color="light">No data queried yet</UncontrolledAlert>;
    55    }
    56  
    57    if (data.result === null || data.result.length === 0) {
    58      return <UncontrolledAlert color="secondary">Empty query result</UncontrolledAlert>;
    59    }
    60  
    61    const maxFormattableSize = 1000;
    62    let rows: ReactNode[] = [];
    63    let limited = false;
    64    const doFormat = data.result.length <= maxFormattableSize;
    65    switch (data.resultType) {
    66      case 'vector':
    67        rows = (limitSeries(data.result) as InstantSample[]).map((s: InstantSample, index: number): ReactNode => {
    68          return (
    69            <tr key={index}>
    70              <td>
    71                <SeriesName labels={s.metric} format={doFormat} />
    72              </td>
    73              <td>
    74                {s.value && s.value[1]} <HistogramString h={s.histogram && s.histogram[1]} />
    75              </td>
    76            </tr>
    77          );
    78        });
    79        limited = rows.length !== data.result.length;
    80        break;
    81      case 'matrix':
    82        rows = (limitSeries(data.result) as RangeSamples[]).map((s, index) => {
    83          const valuesAndTimes = s.values
    84            ? s.values
    85                .map((v) => {
    86                  return v[1] + ' @' + v[0];
    87                })
    88                .join('\n')
    89            : [];
    90          const histogramsAndTimes = s.histograms
    91            ? s.histograms.map((h, hisIdx) => {
    92                const printedDatetime = moment.unix(h[0]).toISOString(false);
    93                return (
    94                  <React.Fragment key={-hisIdx}>
    95                    <HistogramString h={h[1]} /> @{<span title={printedDatetime}>{h[0]}</span>}
    96                    <br />
    97                  </React.Fragment>
    98                );
    99              })
   100            : [];
   101          return (
   102            <tr style={{ whiteSpace: 'pre' }} key={index}>
   103              <td>
   104                <SeriesName labels={s.metric} format={doFormat} />
   105              </td>
   106              <td>
   107                {valuesAndTimes} {histogramsAndTimes}
   108              </td>
   109            </tr>
   110          );
   111        });
   112        limited = rows.length !== data.result.length;
   113        break;
   114      case 'scalar':
   115        rows.push(
   116          <tr key="0">
   117            <td>scalar</td>
   118            <td>{data.result[1]}</td>
   119          </tr>
   120        );
   121        break;
   122      case 'string':
   123        rows.push(
   124          <tr key="0">
   125            <td>string</td>
   126            <td>{data.result[1]}</td>
   127          </tr>
   128        );
   129        break;
   130      default:
   131        return <UncontrolledAlert color="danger">Unsupported result value type</UncontrolledAlert>;
   132    }
   133  
   134    return (
   135      <>
   136        {limited && (
   137          <UncontrolledAlert color="danger">
   138            <strong>Warning:</strong> Fetched {data.result.length} metrics, only displaying first {rows.length}.
   139          </UncontrolledAlert>
   140        )}
   141        {!doFormat && (
   142          <UncontrolledAlert color="secondary">
   143            <strong>Notice:</strong> Showing more than {maxFormattableSize} series, turning off label formatting for
   144            performance reasons.
   145          </UncontrolledAlert>
   146        )}
   147        <Table hover size="sm" className="data-table">
   148          <tbody>{rows}</tbody>
   149        </Table>
   150      </>
   151    );
   152  };
   153  
   154  export interface HistogramStringProps {
   155    h?: Histogram;
   156  }
   157  
   158  export const HistogramString: FC<HistogramStringProps> = ({ h }) => {
   159    if (!h) {
   160      return <></>;
   161    }
   162    const buckets: string[] = [];
   163  
   164    if (h.buckets) {
   165      for (const bucket of h.buckets) {
   166        const left = bucket[0] === 3 || bucket[0] === 1 ? '[' : '(';
   167        const right = bucket[0] === 3 || bucket[0] === 0 ? ']' : ')';
   168        buckets.push(left + bucket[1] + ',' + bucket[2] + right + ':' + bucket[3] + ' ');
   169      }
   170    }
   171  
   172    return (
   173      <>
   174        {'{'} count:{h.count} sum:{h.sum} {buckets} {'}'}
   175      </>
   176    );
   177  };
   178  
   179  export default DataTable;