import React, { PureComponent } from 'react'; import classNames from 'classnames'; import { TimeSeries } from 'app/core/core'; import { SeriesColorPicker, SeriesIcon } from '@grafana/ui'; import { selectors } from '@grafana/e2e-selectors'; export const LEGEND_STATS = ['min', 'max', 'avg', 'current', 'total'] as const; export type LegendStat = typeof LEGEND_STATS[number]; export interface LegendLabelProps { series: TimeSeries; asTable?: boolean; hidden?: boolean; onLabelClick: (series: any, event: any) => void; onColorChange: (series: any, color: string) => void; onToggleAxis: (series: any) => void; } export interface LegendValuesProps { values?: boolean; min?: boolean; max?: boolean; avg?: boolean; current?: boolean; total?: boolean; } type LegendItemProps = LegendLabelProps & LegendValuesProps; interface LegendItemState { yaxis: number; } export class LegendItem extends PureComponent { static defaultProps = { asTable: false, hidden: false, onLabelClick: () => {}, onColorChange: () => {}, onToggleAxis: () => {}, }; constructor(props: LegendItemProps) { super(props); this.state = { yaxis: this.props.series.yaxis, }; } onLabelClick = (e: any) => this.props.onLabelClick(this.props.series, e); onToggleAxis = () => { const yaxis = this.state.yaxis === 2 ? 1 : 2; const info = { alias: this.props.series.alias, yaxis: yaxis }; this.setState({ yaxis: yaxis }); this.props.onToggleAxis(info); }; onColorChange = (color: string) => { this.props.onColorChange(this.props.series, color); // Because of PureComponent nature it makes only shallow props comparison and changing of series.color doesn't run // component re-render. In this case we can't rely on color, selected by user, because it may be overwritten // by series overrides. So we need to use forceUpdate() to make sure we have proper series color. this.forceUpdate(); }; renderLegendValues() { const { series, asTable } = this.props; const legendValueItems = []; for (const valueName of LEGEND_STATS) { // @ts-ignore if (this.props[valueName]) { const valueFormatted = series.formatValue(series.stats[valueName]); legendValueItems.push( ); } } return legendValueItems; } render() { const { series, values, asTable, hidden } = this.props; const seriesOptionClasses = classNames({ 'graph-legend-series-hidden': hidden, 'graph-legend-series--right-y': series.yaxis === 2, }); const valueItems = values ? this.renderLegendValues() : []; const seriesLabel = ( ); if (asTable) { return (
{seriesLabel}
{valueItems} ); } else { return (
{seriesLabel} {valueItems}
); } } } interface LegendSeriesLabelProps { label: string; color: string; yaxis?: number; onLabelClick: (event: any) => void; } class LegendSeriesLabel extends PureComponent { static defaultProps: Partial = { yaxis: undefined, onLabelClick: () => {}, }; render() { const { label, color, yaxis } = this.props; const { onColorChange, onToggleAxis } = this.props; const onLabelClick = this.props.onLabelClick ? this.props.onLabelClick : () => {}; return [ , {label} , ]; } } interface LegendSeriesIconProps { color: string; yaxis?: number; onColorChange?: (color: string) => void; onToggleAxis?: () => void; } interface LegendSeriesIconState { color: string; } class LegendSeriesIcon extends PureComponent { static defaultProps: Partial = { yaxis: undefined, onColorChange: () => {}, onToggleAxis: () => {}, }; onColorChange = (color: string) => { const { onColorChange } = this.props; if (onColorChange) { onColorChange(color); } }; render() { return ( {({ ref, showColorPicker, hideColorPicker }) => ( )} ); } } interface LegendValueProps { value: string; valueName: string; asTable?: boolean; onValueClick?: (event: any) => void; } function LegendValue({ value, valueName, asTable, onValueClick }: LegendValueProps) { if (asTable) { return ( {value} ); } return (
{value}
); }