grafana/grafana-polystat-panel

View on GitHub
src/data/deframer.ts

Summary

Maintainability
A
1 hr
Test Coverage
import { DataFrame, Field, FieldType, FieldConfig } from '@grafana/data';

// Inserts a "Time" field into each dataframe if it is missing
// the value of the timestamp is "now"
// any field without a numeric type is considered a label
export function InsertTime(data: DataFrame[]): DataFrame[] {
  // TODO: time to insert can be taken from the first row if there are timeseries already
  // for now, just insert now
  const timeToInsert = Date.now();
  const newData: DataFrame[] = [];
  for (const frame of data) {
    const newFrame: DataFrame = {
      ...frame,
      meta: {...frame.meta},
      fields: [], // clear the fields
    };
    const hasTimestamp = frameHasTimestamp(frame);
    // rebuild a new frame with labels on the numerical fields
    for (const aField of frame.fields) {
      if (aField.type === FieldType.number) {
        if (!hasTimestamp) {
          const copiedField = Object.assign({}, aField);
          // need to get the number of rows of data for this frame
          const aFieldValues = copiedField.values.toArray();
          const rowsOfField = aFieldValues.length;
          for (let rowNum = 0; rowNum < rowsOfField; rowNum++) {
            // only create a new field when the rowValue is not null
            if (aFieldValues[rowNum] !== null) {
              if (aField.state) {
                copiedField.state = Object.assign({}, aField.state);
              }
              newFrame.fields.push({
                ...copiedField,
                labels: flattenLabels(frame, rowNum),
                values: [getValueOfField(copiedField, rowNum)] as any,
              });
            }
          }
        } else {
          // copy the object
          const copiedField = Object.assign({}, aField);
          if (aField.state) {
            copiedField.state = Object.assign({}, aField.state);
          }
          newFrame.fields.push(copiedField);
        }
      }
    }
    if (!hasTimestamp) {
      const z = [] as any;
      z.add(timeToInsert);
      const fc: FieldConfig = {};
      const timeField: Field = {
        name: 'Time',
        type: FieldType.time,
        values: z,
        config: fc,
      };
      // insert it
      newFrame.fields.push(timeField);
    } else {
      // time field already exists
      // copy all non-number fields from original frame
      for (const aField of frame.fields) {
        if (aField.type !== FieldType.number) {
          const copiedField = Object.assign({}, aField);
          if (aField.state) {
            copiedField.state = Object.assign({}, aField.state);
          }
          newFrame.fields.push(copiedField);
        }
      }
    }
    newData.push(newFrame);
  }

  return newData;
}

function frameHasTimestamp(frame: DataFrame): boolean {
  for (let j = 0; j < frame.fields.length; j++) {
    const aField = frame.fields[j];
    if (aField.type === FieldType.time) {
      return true;
    }
  }
  return false;
}

function flattenLabels(frame: DataFrame, rowNum: number) {
  let labelIndexes = [];
  const numFields = frame.fields.length;

  // first get the fields of type string
  for (let j = 0; j < numFields; j++) {
    if (frame.fields[j].type === FieldType.string) {
      labelIndexes.push(j);
    }
  }
  let labelWithValues = getLabelValues(frame, labelIndexes, rowNum);
  return labelWithValues;
}

function getValueOfField(field: Field, index: number) {
  const bufferValue = field.values.toArray()[index];
  return bufferValue;
}

function getLabelValues(frame: DataFrame, indexes: any[], rowNum: number) {
  let labelAndValue = {};
  for (let index = 0; index < indexes.length; index++) {
    let indexValue = indexes[index];
    let aField = frame.fields[indexValue];
    if (aField.type !== FieldType.number) {
      let value = getValueOfField(aField, rowNum);
      // TODO: fix this...
      // @ts-ignore
      labelAndValue[aField.name] = value;
    }
  }
  return labelAndValue;
}