@grafana/data#getDisplayProcessor TypeScript Examples

The following examples show how to use @grafana/data#getDisplayProcessor. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: BarGauge.test.tsx    From grafana-chinese with Apache License 2.0 6 votes vote down vote up
function getProps(propOverrides?: Partial<Props>): Props {
  const field: Partial<Field> = {
    type: FieldType.number,
    config: {
      min: 0,
      max: 100,
      thresholds: {
        mode: ThresholdsMode.Absolute,
        steps: [
          { value: -Infinity, color: 'green' },
          { value: 70, color: 'orange' },
          { value: 90, color: 'red' },
        ],
      },
    },
  };
  const theme = getTheme();
  field.display = getDisplayProcessor({ field, theme });

  const props: Props = {
    displayMode: BarGaugeDisplayMode.Basic,
    field: field.config!,
    display: field.display!,
    height: 300,
    width: 300,
    value: field.display(25),
    theme,
    orientation: VizOrientation.Horizontal,
  };

  Object.assign(props, propOverrides);
  return props;
}
Example #2
Source File: SingleModeGraphTooltip.tsx    From grafana-chinese with Apache License 2.0 6 votes vote down vote up
SingleModeGraphTooltip: React.FC<GraphTooltipContentProps> = ({ dimensions, activeDimensions }) => {
  // not hovering over a point, skip rendering
  if (
    activeDimensions.yAxis === null ||
    activeDimensions.yAxis[1] === undefined ||
    activeDimensions.xAxis === null ||
    activeDimensions.xAxis[1] === undefined
  ) {
    return null;
  }
  const time = getValueFromDimension(dimensions.xAxis, activeDimensions.xAxis[0], activeDimensions.xAxis[1]);
  const timeField = getColumnFromDimension(dimensions.xAxis, activeDimensions.xAxis[0]);
  const processedTime = timeField.display ? formattedValueToString(timeField.display(time)) : time;

  const valueField = getColumnFromDimension(dimensions.yAxis, activeDimensions.yAxis[0]);
  const value = getValueFromDimension(dimensions.yAxis, activeDimensions.yAxis[0], activeDimensions.yAxis[1]);
  const display = valueField.display ?? getDisplayProcessor({ field: valueField });
  const disp = display(value);

  return (
    <SeriesTable
      series={[
        {
          color: disp.color,
          label: valueField.name,
          value: formattedValueToString(disp),
        },
      ]}
      timestamp={processedTime}
    />
  );
}
Example #3
Source File: utils.ts    From grafana-chinese with Apache License 2.0 6 votes vote down vote up
getMultiSeriesGraphHoverInfo = (
  // x and y axis dimensions order is aligned
  yAxisDimensions: Field[],
  xAxisDimensions: Field[],
  /** Well, time basically */
  xAxisPosition: number
): {
  results: MultiSeriesHoverInfo[];
  time?: GraphSeriesValue;
} => {
  let i, field, hoverIndex, hoverDistance, pointTime;

  const results: MultiSeriesHoverInfo[] = [];

  let minDistance, minTime;

  for (i = 0; i < yAxisDimensions.length; i++) {
    field = yAxisDimensions[i];
    const time = xAxisDimensions[i];
    hoverIndex = findHoverIndexFromData(time, xAxisPosition);
    hoverDistance = xAxisPosition - time.values.get(hoverIndex);
    pointTime = time.values.get(hoverIndex);
    // Take the closest point before the cursor, or if it does not exist, the closest after
    if (
      minDistance === undefined ||
      (hoverDistance >= 0 && (hoverDistance < minDistance || minDistance < 0)) ||
      (hoverDistance < 0 && hoverDistance > minDistance)
    ) {
      minDistance = hoverDistance;
      minTime = time.display ? formattedValueToString(time.display(pointTime)) : pointTime;
    }

    const display = field.display ?? getDisplayProcessor({ field });
    const disp = display(field.values.get(hoverIndex));

    results.push({
      value: formattedValueToString(disp),
      datapointIndex: hoverIndex,
      seriesIndex: i,
      color: disp.color,
      label: field.name,
      time: time.display ? formattedValueToString(time.display(pointTime)) : pointTime,
    });
  }

  return {
    results,
    time: minTime,
  };
}
Example #4
Source File: fieldDisplayValuesProxy.ts    From grafana-chinese with Apache License 2.0 6 votes vote down vote up
export function getFieldDisplayValuesProxy(frame: DataFrame, rowIndex: number): Record<string, DisplayValue> {
  return new Proxy({} as Record<string, DisplayValue>, {
    get: (obj: any, key: string) => {
      // 1. Match the name
      let field = frame.fields.find(f => key === f.name);
      if (!field) {
        // 2. Match the array index
        const k = toNumber(key);
        field = frame.fields[k];
      }
      if (!field) {
        // 3. Match the title
        field = frame.fields.find(f => key === f.config.title);
      }
      if (!field) {
        return undefined;
      }
      if (!field.display) {
        // Lazy load the display processor
        field.display = getDisplayProcessor({
          field,
          theme: config.theme,
        });
      }
      const raw = field.values.get(rowIndex);
      const disp = field.display(raw);
      disp.toString = () => formattedValueToString(disp);
      return disp;
    },
  });
}
Example #5
Source File: BarGauge.story.tsx    From grafana-chinese with Apache License 2.0 5 votes vote down vote up
function addBarGaugeStory(name: string, overrides: Partial<Props>) {
  BarGaugeStories.add(name, () => {
    const {
      value,
      title,
      minValue,
      maxValue,
      threshold1Color,
      threshold2Color,
      threshold1Value,
      threshold2Value,
    } = getKnobs();

    const field: Partial<Field> = {
      type: FieldType.number,
      config: {
        min: minValue,
        max: maxValue,
        thresholds: {
          mode: ThresholdsMode.Absolute,
          steps: [
            { value: -Infinity, color: 'green' },
            { value: threshold1Value, color: threshold1Color },
            { value: threshold2Value, color: threshold2Color },
          ],
        },
      },
    };
    field.display = getDisplayProcessor({ field });

    const props: Props = {
      theme: {} as any,
      width: 300,
      height: 300,
      value: {
        text: value.toString(),
        title: title,
        numeric: value,
      },
      orientation: VizOrientation.Vertical,
      displayMode: BarGaugeDisplayMode.Basic,
      field: field.config!,
      display: field.display!,
    };

    Object.assign(props, overrides);
    return renderComponentWithTheme(BarGauge, props);
  });
}
Example #6
Source File: GraphContextMenu.tsx    From grafana-chinese with Apache License 2.0 5 votes vote down vote up
GraphContextMenu: React.FC<GraphContextMenuProps> = ({
  getContextMenuSource,
  formatSourceDate,
  items,
  dimensions,
  contextDimensions,
  ...otherProps
}) => {
  const theme = useContext(ThemeContext);
  const source = getContextMenuSource();

  //  Do not render items that do not have label specified
  const itemsToRender = items
    ? items.map(group => ({
        ...group,
        items: group.items.filter(item => item.label),
      }))
    : [];

  const renderHeader = () => {
    if (!source) {
      return null;
    }

    // If dimensions supplied, we can calculate and display value
    let value;
    if (dimensions?.yAxis && contextDimensions?.yAxis?.[1]) {
      const valueFromDimensions = getValueFromDimension(
        dimensions.yAxis,
        contextDimensions.yAxis[0],
        contextDimensions.yAxis[1]
      );
      const display = source.series.valueField.display ?? getDisplayProcessor({ field: source.series.valueField });
      value = display(valueFromDimensions);
    }

    const timeFormat = source.series.hasMsResolution ? MS_DATE_TIME_FORMAT : DEFAULT_DATE_TIME_FORMAT;
    return (
      <div
        className={css`
          padding: ${theme.spacing.xs} ${theme.spacing.sm};
          font-size: ${theme.typography.size.sm};
          z-index: ${theme.zIndex.tooltip};
        `}
      >
        <strong>{formatSourceDate(source.datapoint[0], timeFormat)}</strong>
        <div>
          <SeriesIcon color={source.series.color} />
          <span
            className={css`
              white-space: nowrap;
              padding-left: ${theme.spacing.xs};
            `}
          >
            {source.series.alias || source.series.label}
          </span>
          {value && (
            <span
              className={css`
                white-space: nowrap;
                padding-left: ${theme.spacing.md};
              `}
            >
              {formattedValueToString(value)}
            </span>
          )}
        </div>
      </div>
    );
  };

  return <ContextMenu {...otherProps} items={itemsToRender} renderHeader={renderHeader} />;
}
Example #7
Source File: ResultProcessor.ts    From grafana-chinese with Apache License 2.0 5 votes vote down vote up
getTableResult(): DataFrame | null {
    if (this.state.mode !== ExploreMode.Metrics) {
      return null;
    }

    // For now ignore time series
    // We can change this later, just need to figure out how to
    // Ignore time series only for prometheus
    const onlyTables = this.dataFrames.filter(frame => !isTimeSeries(frame));

    if (onlyTables.length === 0) {
      return null;
    }

    const tables = onlyTables.map(frame => {
      const { fields } = frame;
      const fieldCount = fields.length;
      const rowCount = frame.length;

      const columns = fields.map(field => ({
        text: field.name,
        type: field.type,
        filterable: field.config.filterable,
      }));

      const rows: any[][] = [];
      for (let i = 0; i < rowCount; i++) {
        const row: any[] = [];
        for (let j = 0; j < fieldCount; j++) {
          row.push(frame.fields[j].values.get(i));
        }
        rows.push(row);
      }

      return new TableModel({
        columns,
        rows,
        meta: frame.meta,
      });
    });

    const mergedTable = mergeTablesIntoModel(new TableModel(), ...tables);
    const data = toDataFrame(mergedTable);

    // set display processor
    for (const field of data.fields) {
      field.display = getDisplayProcessor({
        field,
        theme: config.theme,
      });
    }

    return data;
  }
Example #8
Source File: graph.ts    From grafana-chinese with Apache License 2.0 5 votes vote down vote up
onPlotClick(event: JQueryEventObject, pos: any, item: any) {
    const scrollContextElement = this.elem.closest('.view') ? this.elem.closest('.view').get()[0] : null;
    const contextMenuSourceItem = item;

    if (this.panel.xaxis.mode !== 'time') {
      // Skip if panel in histogram or series mode
      return;
    }

    if ((pos.ctrlKey || pos.metaKey) && (this.dashboard.meta.canEdit || this.dashboard.meta.canMakeEditable)) {
      // Skip if range selected (added in "plotselected" event handler)
      if (pos.x !== pos.x1) {
        return;
      }
      setTimeout(() => {
        this.eventManager.updateTime({ from: pos.x, to: null });
      }, 100);
      return;
    } else {
      this.tooltip.clear(this.plot);
      let linksSupplier: LinkModelSupplier<FieldDisplay>;

      if (item) {
        // pickup y-axis index to know which field's config to apply
        const yAxisConfig = this.panel.yaxes[item.series.yaxis.n === 2 ? 1 : 0];
        const dataFrame = this.ctrl.dataList[item.series.dataFrameIndex];
        const field = dataFrame.fields[item.series.fieldIndex];
        const dataIndex = this.getDataIndexWithNullValuesCorrection(item, dataFrame);

        let links = this.panel.options.dataLinks || [];
        if (field.config.links && field.config.links.length) {
          // Append the configured links to the panel datalinks
          links = [...links, ...field.config.links];
        }
        const fieldConfig = {
          decimals: yAxisConfig.decimals,
          links,
        };
        const fieldDisplay = getDisplayProcessor({
          field: { config: fieldConfig, type: FieldType.number },
          theme: getCurrentTheme(),
        })(field.values.get(dataIndex));
        linksSupplier = links.length
          ? getFieldLinksSupplier({
              display: fieldDisplay,
              name: field.name,
              view: new DataFrameView(dataFrame),
              rowIndex: dataIndex,
              colIndex: item.series.fieldIndex,
              field: fieldConfig,
            })
          : undefined;
      }

      this.scope.$apply(() => {
        // Setting nearest CustomScrollbar element as a scroll context for graph context menu
        this.contextMenu.setScrollContextElement(scrollContextElement);
        this.contextMenu.setSource(contextMenuSourceItem);
        this.contextMenu.setMenuItemsSupplier(this.getContextMenuItemsSupplier(pos, linksSupplier) as any);
        this.contextMenu.toggleMenu(pos);
      });
    }
  }
Example #9
Source File: module.ts    From grafana-chinese with Apache License 2.0 5 votes vote down vote up
onFramesReceived(frames: DataFrame[]) {
    const { panel } = this;

    if (frames && frames.length > 1) {
      this.data = {
        value: 0,
        display: {
          text: 'Only queries that return single series/table is supported',
          numeric: NaN,
        },
      };
      this.render();
      return;
    }

    const distinct = getDistinctNames(frames);
    let fieldInfo = distinct.byName[panel.tableColumn]; //
    this.fieldNames = distinct.names;

    if (!fieldInfo) {
      fieldInfo = distinct.first;
    }

    if (!fieldInfo) {
      const processor = getDisplayProcessor({
        field: {
          config: {
            mappings: convertOldAngularValueMapping(this.panel),
            noValue: 'No Data',
          },
        },
        theme: config.theme,
      });
      // When we don't have any field
      this.data = {
        value: null,
        display: processor(null),
      };
    } else {
      this.data = this.processField(fieldInfo);
    }

    this.render();
  }
Example #10
Source File: module.ts    From grafana-chinese with Apache License 2.0 5 votes vote down vote up
processField(fieldInfo: FieldInfo) {
    const { panel, dashboard } = this;

    const name = fieldInfo.field.config.title || fieldInfo.field.name;
    let calc = panel.valueName;
    let calcField = fieldInfo.field;
    let val: any = undefined;

    if ('name' === calc) {
      val = name;
    } else {
      if ('last_time' === calc) {
        if (fieldInfo.frame.firstTimeField) {
          calcField = fieldInfo.frame.firstTimeField;
          calc = ReducerID.last;
        }
      }

      // Normalize functions (avg -> mean, etc)
      const r = fieldReducers.getIfExists(calc);
      if (r) {
        calc = r.id;
        // With strings, don't accidentally use a math function
        if (calcField.type === FieldType.string) {
          const avoid = [ReducerID.mean, ReducerID.sum];
          if (avoid.includes(calc)) {
            calc = panel.valueName = ReducerID.first;
          }
        }
      } else {
        calc = ReducerID.lastNotNull;
      }

      // Calculate the value
      val = reduceField({
        field: calcField,
        reducers: [calc],
      })[calc];
    }

    const processor = getDisplayProcessor({
      field: {
        ...fieldInfo.field,
        config: {
          ...fieldInfo.field.config,
          unit: panel.format,
          decimals: panel.decimals,
          mappings: convertOldAngularValueMapping(panel),
        },
      },
      theme: config.theme,
      timeZone: dashboard.getTimezone(),
    });

    const sparkline: any[] = [];
    const data = {
      field: fieldInfo.field,
      value: val,
      display: processor(val),
      scopedVars: _.extend({}, panel.scopedVars),
      sparkline,
    };

    data.scopedVars['__name'] = { value: name };
    panel.tableColumn = this.fieldNames.length > 1 ? name : '';

    // Get the fields for a sparkline
    if (panel.sparkline && panel.sparkline.show && fieldInfo.frame.firstTimeField) {
      data.sparkline = getFlotPairs({
        xField: fieldInfo.frame.firstTimeField,
        yField: fieldInfo.field,
        nullValueMode: panel.nullPointMode,
      });
    }

    return data;
  }
Example #11
Source File: logs_model.ts    From grafana-chinese with Apache License 2.0 4 votes vote down vote up
export function makeSeriesForLogs(rows: LogRowModel[], intervalMs: number, timeZone: TimeZone): GraphSeriesXY[] {
  // currently interval is rangeMs / resolution, which is too low for showing series as bars.
  // need at least 10px per bucket, so we multiply interval by 10. Should be solved higher up the chain
  // when executing queries & interval calculated and not here but this is a temporary fix.
  // intervalMs = intervalMs * 10;

  // Graph time series by log level
  const seriesByLevel: any = {};
  const bucketSize = intervalMs * 10;
  const seriesList: any[] = [];

  const sortedRows = rows.sort(sortInAscendingOrder);
  for (const row of sortedRows) {
    let series = seriesByLevel[row.logLevel];

    if (!series) {
      seriesByLevel[row.logLevel] = series = {
        lastTs: null,
        datapoints: [],
        alias: row.logLevel,
        target: row.logLevel,
        color: LogLevelColor[row.logLevel],
      };

      seriesList.push(series);
    }

    // align time to bucket size - used Math.floor for calculation as time of the bucket
    // must be in the past (before Date.now()) to be displayed on the graph
    const time = Math.floor(row.timeEpochMs / bucketSize) * bucketSize;

    // Entry for time
    if (time === series.lastTs) {
      series.datapoints[series.datapoints.length - 1][0]++;
    } else {
      series.datapoints.push([1, time]);
      series.lastTs = time;
    }

    // add zero to other levels to aid stacking so each level series has same number of points
    for (const other of seriesList) {
      if (other !== series && other.lastTs !== time) {
        other.datapoints.push([0, time]);
        other.lastTs = time;
      }
    }
  }

  return seriesList.map((series, i) => {
    series.datapoints.sort((a: number[], b: number[]) => {
      return a[1] - b[1];
    });

    // EEEP: converts GraphSeriesXY to DataFrame and back again!
    const data = toDataFrame(series);
    const points = getFlotPairs({
      xField: data.fields[1],
      yField: data.fields[0],
      nullValueMode: NullValueMode.Null,
    });

    const timeField = data.fields[1];
    timeField.display = getDisplayProcessor({
      field: timeField,
      timeZone,
    });

    const valueField = data.fields[0];
    valueField.config = {
      ...valueField.config,
      color: series.color,
    };

    const graphSeries: GraphSeriesXY = {
      color: series.color,
      label: series.alias,
      data: points,
      isVisible: true,
      yAxis: {
        index: 1,
        min: 0,
        tickDecimals: 0,
      },
      seriesIndex: i,
      timeField,
      valueField,
      // for now setting the time step to be 0,
      // and handle the bar width by setting lineWidth instead of barWidth in flot options
      timeStep: 0,
    };

    return graphSeries;
  });
}
Example #12
Source File: getGraphSeriesModel.ts    From grafana-chinese with Apache License 2.0 4 votes vote down vote up
getGraphSeriesModel = (
  dataFrames: DataFrame[],
  timeZone: TimeZone,
  seriesOptions: SeriesOptions,
  graphOptions: GraphOptions,
  legendOptions: GraphLegendEditorLegendOptions,
  fieldOptions?: FieldDisplayOptions
) => {
  const graphs: GraphSeriesXY[] = [];

  const displayProcessor = getDisplayProcessor({
    field: {
      config: {
        unit: fieldOptions?.defaults?.unit,
        decimals: legendOptions.decimals,
      },
    },
  });

  let fieldColumnIndex = -1;
  for (const series of dataFrames) {
    const { timeField } = getTimeField(series);
    if (!timeField) {
      continue;
    }

    for (const field of series.fields) {
      if (field.type !== FieldType.number) {
        continue;
      }
      // Storing index of series field for future inspection
      fieldColumnIndex++;

      // Use external calculator just to make sure it works :)
      const points = getFlotPairs({
        xField: timeField,
        yField: field,
        nullValueMode: NullValueMode.Null,
      });

      if (points.length > 0) {
        const seriesStats = reduceField({ field, reducers: legendOptions.stats });
        let statsDisplayValues: DisplayValue[];

        if (legendOptions.stats) {
          statsDisplayValues = legendOptions.stats.map<DisplayValue>(stat => {
            const statDisplayValue = displayProcessor(seriesStats[stat]);

            return {
              ...statDisplayValue,
              title: stat,
            };
          });
        }

        let color: FieldColor;
        if (seriesOptions[field.name] && seriesOptions[field.name].color) {
          // Case when panel has settings provided via SeriesOptions, i.e. graph panel
          color = {
            mode: FieldColorMode.Fixed,
            fixedColor: seriesOptions[field.name].color,
          };
        } else if (field.config && field.config.color) {
          // Case when color settings are set on field, i.e. Explore logs histogram (see makeSeriesForLogs)
          color = field.config.color;
        } else {
          color = {
            mode: FieldColorMode.Fixed,
            fixedColor: colors[graphs.length % colors.length],
          };
        }

        field.config = fieldOptions
          ? {
              ...field.config,
              unit: fieldOptions.defaults.unit,
              decimals: fieldOptions.defaults.decimals,
              color,
            }
          : { ...field.config, color };

        field.display = getDisplayProcessor({ field });

        // Time step is used to determine bars width when graph is rendered as bar chart
        const timeStep = getSeriesTimeStep(timeField);
        const useMsDateFormat = hasMsResolution(timeField);

        timeField.display = getDisplayProcessor({
          timeZone,
          field: {
            ...timeField,
            type: timeField.type,
            config: {
              unit: `time:${useMsDateFormat ? MS_DATE_TIME_FORMAT : DEFAULT_DATE_TIME_FORMAT}`,
            },
          },
        });

        graphs.push({
          label: field.name,
          data: points,
          color: field.config.color?.fixedColor,
          info: statsDisplayValues,
          isVisible: true,
          yAxis: {
            index: (seriesOptions[field.name] && seriesOptions[field.name].yAxis) || 1,
          },
          // This index is used later on to retrieve appropriate series/time for X and Y axes
          seriesIndex: fieldColumnIndex,
          timeField: { ...timeField },
          valueField: { ...field },
          timeStep,
        });
      }
    }
  }

  return graphs;
}
Example #13
Source File: FileBrowser.tsx    From grafana-s3-plugin with Apache License 2.0 4 votes vote down vote up
listFiles = (prefix: string, edit?: boolean) => {
    getBackendSrv()
      .datasourceRequest({
        url: '/api/ds/query',
        method: 'POST',
        data: {
          queries: [
            {
              refId: 'A',
              path: prefix,
              query: 'LIST FORMATTED',
              orgId: this.props.orgId,
              datasourceId: this.props.dsId,
            },
          ],
        },
      })
      .then(response => {
        const b64 = response.data.results.A.dataframes[0];
        const table = base64StringToArrowTable(b64);
        const frame = arrowTableToDataFrame(table);

        frame.fields[0].display = (value: string) => {
          let icon = this.icons['error'];

          const parts = /^(.*),type=(.*),key=(.*)$/.exec(value);
          if (parts !== null && parts.length === 4) {
            value = parts![1];
            icon = this.icons[parts![2]] || icon;
          }

          return {
            prefix: icon,
            numeric: Number.NaN,
            text: value,
          };
        };

        // @ts-ignore
        frame.fields[0].getLinks = (options: any) => {
          const i = options.valueRowIndex;

          let value = table.getColumnAt(0)!.get(i);
          let href = undefined;

          const parts = /^(.*),type=(.*),key=(.*)$/.exec(value);
          if (parts !== null && parts.length === 4 && parts![2] === 'folder') {
            value = parts![1];
            href = this.setsearchparams({ explore: true, prefix: parts![3] });
          }

          if (href) {
            return [{ href: href, title: value }];
          } else {
            return [undefined];
          }
        };

        frame.fields[1].display = getDisplayProcessor({ field: frame.fields[1] });
        frame.fields[2].display = getDisplayProcessor({ field: frame.fields[2] });

        frame.fields[3].display = (value: string) => {
          return {
            numeric: Number.NaN,
            text: this.icons['delete'],
          };
        };

        // @ts-ignore
        frame.fields[3].getLinks = (options: any) => {
          const i = options.valueRowIndex;
          const value = table.getColumnAt(0)!.get(i);
          let onClick = undefined;

          const parts = /^(.*),type=(.*),key=(.*)$/.exec(value);
          if (parts !== null && parts.length === 4) {
            onClick = () => {
              console.log('Delete', parts![2], parts![3]);
              return getBackendSrv()
                .datasourceRequest({
                  url: '/api/ds/query',
                  method: 'POST',
                  data: {
                    queries: [
                      {
                        refId: 'A',
                        path: parts![3],
                        query: 'DELETE ' + parts![2],
                        orgId: this.props.orgId,
                        datasourceId: this.props.dsId,
                      },
                    ],
                  },
                })
                .then(response => {
                  this.listFiles(this.state.prefix);
                });
            };
          }

          return [{ onClick: onClick, title: 'Delete' }];

          if (onClick) {
            return [{ onClick: onClick, title: 'Delete' }];
          } else {
            return [undefined];
          }
        };

        if (edit) {
          this.setState({
            hints: frame!.meta!.custom!.folders.map((folder: any) => ({ label: folder, value: folder })),
          });
        } else if (prefix === this.state.prefix) {
          this.setState({
            dirty: false,
            files: frame,
            hints: frame!.meta!.custom!.folders.map((folder: any) => ({ label: folder, value: folder })),
          });
        }
      });
  };
Example #14
Source File: getGraphSeriesModel.ts    From loudml-grafana-app with MIT License 4 votes vote down vote up
getGraphSeriesModel = (
  dataFrames: DataFrame[],
  timeZone: TimeZone,
  seriesOptions: SeriesOptions,
  graphOptions: GraphOptions,
  legendOptions: GraphLegendEditorLegendOptions,
  fieldOptions?: FieldDisplayOptions
) => {
  const graphs: GraphSeriesXY[] = [];

  const displayProcessor = getDisplayProcessor({
    field: {
      config: {
        unit: fieldOptions?.defaults?.unit,
        decimals: legendOptions.decimals,
      },
    },
  });

  let fieldColumnIndex = -1;
  for (const series of dataFrames) {
    const { timeField } = getTimeField(series);
    if (!timeField) {
      continue;
    }

    for (const field of series.fields) {
      if (field.type !== FieldType.number) {
        continue;
      }
      // Storing index of series field for future inspection
      fieldColumnIndex++;

      // Use external calculator just to make sure it works :)
      const points = getFlotPairs({
        xField: timeField,
        yField: field,
        nullValueMode: NullValueMode.Null,
      });

      if (points.length > 0) {
        const seriesStats = reduceField({ field, reducers: legendOptions.stats });
        let statsDisplayValues: DisplayValue[];

        if (legendOptions.stats) {
          statsDisplayValues = legendOptions.stats.map<DisplayValue>(stat => {
            const statDisplayValue = displayProcessor(seriesStats[stat]);

            return {
              ...statDisplayValue,
              title: stat,
            };
          });
        }

        let color: FieldColor;
        if (seriesOptions[field.name] && seriesOptions[field.name].color) {
          // Case when panel has settings provided via SeriesOptions, i.e. graph panel
          color = {
            mode: FieldColorMode.Fixed,
            fixedColor: seriesOptions[field.name].color,
          };
        } else if (field.config && field.config.color) {
          // Case when color settings are set on field, i.e. Explore logs histogram (see makeSeriesForLogs)
          color = field.config.color;
        } else {
          color = {
            mode: FieldColorMode.Fixed,
            fixedColor: colors[graphs.length % colors.length],
          };
        }

        field.config = fieldOptions
          ? {
              ...field.config,
              unit: fieldOptions.defaults.unit,
              decimals: fieldOptions.defaults.decimals,
              color,
            }
          : { ...field.config, color };

        field.display = getDisplayProcessor({ field });

        // Time step is used to determine bars width when graph is rendered as bar chart
        const timeStep = getSeriesTimeStep(timeField);
        const useMsDateFormat = hasMsResolution(timeField);

        timeField.display = getDisplayProcessor({
          timeZone,
          field: {
            ...timeField,
            type: timeField.type,
            config: {
              unit: `time:${useMsDateFormat ? MS_DATE_TIME_FORMAT : DEFAULT_DATE_TIME_FORMAT}`,
            },
          },
        });

        graphs.push({
          label: field.name,
          data: points,
          color: field.config.color?.fixedColor,
          info: statsDisplayValues,
          isVisible: true,
          yAxis: {
            index: (seriesOptions[field.name] && seriesOptions[field.name].yAxis) || 1,
          },
          // This index is used later on to retrieve appropriate series/time for X and Y axes
          seriesIndex: fieldColumnIndex,
          timeField: { ...timeField },
          valueField: { ...field },
          timeStep,
        });
      }
    }
  }

  return graphs;
}