mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
PieChart: move hiding series to PanelContext (#33756)
This commit is contained in:
parent
8333c55bee
commit
9e2e7b66a1
@ -117,7 +117,7 @@ export function preparePlotConfigBuilder(
|
|||||||
colorMode,
|
colorMode,
|
||||||
pathBuilder: config.drawBars,
|
pathBuilder: config.drawBars,
|
||||||
pointsBuilder: config.drawPoints,
|
pointsBuilder: config.drawPoints,
|
||||||
show: !customConfig.hideFrom?.graph,
|
show: !customConfig.hideFrom?.viz,
|
||||||
gradientMode: customConfig.gradientMode,
|
gradientMode: customConfig.gradientMode,
|
||||||
thresholds: field.config.thresholds,
|
thresholds: field.config.thresholds,
|
||||||
|
|
||||||
|
@ -1,14 +1,5 @@
|
|||||||
import { DataFrameFieldIndex, FieldMatcher } from '@grafana/data';
|
import { DataFrameFieldIndex, FieldMatcher } from '@grafana/data';
|
||||||
|
import { SeriesVisibilityChangeMode } from '..';
|
||||||
/**
|
|
||||||
* Mode to describe if a legend is isolated/selected or being appended to an existing
|
|
||||||
* series selection.
|
|
||||||
* @alpha
|
|
||||||
*/
|
|
||||||
export enum GraphNGLegendEventMode {
|
|
||||||
ToggleSelection = 'select',
|
|
||||||
AppendToSelection = 'append',
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Event being triggered when the user interact with the Graph legend.
|
* Event being triggered when the user interact with the Graph legend.
|
||||||
@ -16,7 +7,7 @@ export enum GraphNGLegendEventMode {
|
|||||||
*/
|
*/
|
||||||
export interface GraphNGLegendEvent {
|
export interface GraphNGLegendEvent {
|
||||||
fieldIndex: DataFrameFieldIndex;
|
fieldIndex: DataFrameFieldIndex;
|
||||||
mode: GraphNGLegendEventMode;
|
mode: SeriesVisibilityChangeMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @alpha */
|
/** @alpha */
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import React from 'react';
|
import { XYFieldMatchers } from './types';
|
||||||
import { GraphNGLegendEventMode, XYFieldMatchers } from './types';
|
|
||||||
import {
|
import {
|
||||||
ArrayVector,
|
ArrayVector,
|
||||||
DataFrame,
|
DataFrame,
|
||||||
@ -18,13 +17,6 @@ export interface PrepConfigOpts {
|
|||||||
[prop: string]: any;
|
[prop: string]: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function mapMouseEventToMode(event: React.MouseEvent): GraphNGLegendEventMode {
|
|
||||||
if (event.ctrlKey || event.metaKey || event.shiftKey) {
|
|
||||||
return GraphNGLegendEventMode.AppendToSelection;
|
|
||||||
}
|
|
||||||
return GraphNGLegendEventMode.ToggleSelection;
|
|
||||||
}
|
|
||||||
|
|
||||||
function applySpanNullsThresholds(frames: DataFrame[]) {
|
function applySpanNullsThresholds(frames: DataFrame[]) {
|
||||||
for (const frame of frames) {
|
for (const frame of frames) {
|
||||||
let refField = frame.fields.find((field) => field.type === FieldType.time); // this doesnt need to be time, just any numeric/asc join field
|
let refField = frame.fields.find((field) => field.type === FieldType.time); // this doesnt need to be time, just any numeric/asc join field
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { EventBusSrv, EventBus } from '@grafana/data';
|
import { EventBusSrv, EventBus } from '@grafana/data';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { SeriesVisibilityChangeMode } from '.';
|
||||||
|
|
||||||
/** @alpha */
|
/** @alpha */
|
||||||
export interface PanelContext {
|
export interface PanelContext {
|
||||||
@ -11,6 +12,8 @@ export interface PanelContext {
|
|||||||
* @alpha -- experimental
|
* @alpha -- experimental
|
||||||
*/
|
*/
|
||||||
onSeriesColorChange?: (label: string, color: string) => void;
|
onSeriesColorChange?: (label: string, color: string) => void;
|
||||||
|
|
||||||
|
onToggleSeriesVisibility?: (label: string, mode: SeriesVisibilityChangeMode) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const PanelContextRoot = React.createContext<PanelContext>({
|
const PanelContextRoot = React.createContext<PanelContext>({
|
||||||
|
@ -38,3 +38,5 @@ export {
|
|||||||
} from './ErrorIndicator';
|
} from './ErrorIndicator';
|
||||||
|
|
||||||
export { usePanelContext, PanelContextProvider, PanelContext } from './PanelContext';
|
export { usePanelContext, PanelContextProvider, PanelContext } from './PanelContext';
|
||||||
|
|
||||||
|
export * from './types';
|
||||||
|
10
packages/grafana-ui/src/components/PanelChrome/types.ts
Normal file
10
packages/grafana-ui/src/components/PanelChrome/types.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
/**
|
||||||
|
* Mode to describe if a legend is isolated/selected or being appended to an existing
|
||||||
|
* series selection.
|
||||||
|
* @alpha
|
||||||
|
*/
|
||||||
|
|
||||||
|
export enum SeriesVisibilityChangeMode {
|
||||||
|
ToggleSelection = 'select',
|
||||||
|
AppendToSelection = 'append',
|
||||||
|
}
|
@ -35,6 +35,7 @@ import { getTooltipContainerStyles } from '../../themes/mixins';
|
|||||||
import { SeriesTable, SeriesTableRowProps, VizTooltipOptions } from '../VizTooltip';
|
import { SeriesTable, SeriesTableRowProps, VizTooltipOptions } from '../VizTooltip';
|
||||||
import { usePanelContext } from '../PanelChrome';
|
import { usePanelContext } from '../PanelChrome';
|
||||||
import { Subscription } from 'rxjs';
|
import { Subscription } from 'rxjs';
|
||||||
|
import { SeriesVisibilityChangeBehavior } from '../VizLegend/types';
|
||||||
|
|
||||||
const defaultLegendOptions: PieChartLegendOptions = {
|
const defaultLegendOptions: PieChartLegendOptions = {
|
||||||
displayMode: LegendDisplayMode.List,
|
displayMode: LegendDisplayMode.List,
|
||||||
@ -94,31 +95,37 @@ function getLegend(props: PieChartProps, displayValues: FieldDisplay[]) {
|
|||||||
if (legendOptions.displayMode === LegendDisplayMode.Hidden) {
|
if (legendOptions.displayMode === LegendDisplayMode.Hidden) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
const values = displayValues.map((v) => v.display);
|
const total = displayValues
|
||||||
const total = values.reduce((acc, item) => item.numeric + acc, 0);
|
.filter((item) => {
|
||||||
|
return !item.field.custom.hideFrom.viz;
|
||||||
|
})
|
||||||
|
.reduce((acc, item) => item.display.numeric + acc, 0);
|
||||||
|
|
||||||
const legendItems = values.map<VizLegendItem>((value, idx) => {
|
const legendItems = displayValues.map<VizLegendItem>((value, idx) => {
|
||||||
|
const hidden = value.field.custom.hideFrom.viz;
|
||||||
|
const display = value.display;
|
||||||
return {
|
return {
|
||||||
label: value.title ?? '',
|
label: display.title ?? '',
|
||||||
color: value.color ?? FALLBACK_COLOR,
|
color: display.color ?? FALLBACK_COLOR,
|
||||||
yAxis: 1,
|
yAxis: 1,
|
||||||
getItemKey: () => (value.title ?? '') + idx,
|
disabled: hidden,
|
||||||
|
getItemKey: () => (display.title ?? '') + idx,
|
||||||
getDisplayValues: () => {
|
getDisplayValues: () => {
|
||||||
const valuesToShow = legendOptions.values ?? [];
|
const valuesToShow = legendOptions.values ?? [];
|
||||||
let displayValues = [];
|
let displayValues = [];
|
||||||
|
|
||||||
if (valuesToShow.includes(PieChartLegendValues.Value)) {
|
if (valuesToShow.includes(PieChartLegendValues.Value)) {
|
||||||
displayValues.push({ numeric: value.numeric, text: formattedValueToString(value), title: 'Value' });
|
displayValues.push({ numeric: display.numeric, text: formattedValueToString(display), title: 'Value' });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (valuesToShow.includes(PieChartLegendValues.Percent)) {
|
if (valuesToShow.includes(PieChartLegendValues.Percent)) {
|
||||||
const fractionOfTotal = value.numeric / total;
|
const fractionOfTotal = hidden ? 0 : display.numeric / total;
|
||||||
const percentOfTotal = fractionOfTotal * 100;
|
const percentOfTotal = fractionOfTotal * 100;
|
||||||
|
|
||||||
displayValues.push({
|
displayValues.push({
|
||||||
numeric: fractionOfTotal,
|
numeric: fractionOfTotal,
|
||||||
percent: percentOfTotal,
|
percent: percentOfTotal,
|
||||||
text: percentOfTotal.toFixed(0) + '%',
|
text: hidden ? '-' : percentOfTotal.toFixed(0) + '%',
|
||||||
title: valuesToShow.length > 1 ? 'Percent' : undefined,
|
title: valuesToShow.length > 1 ? 'Percent' : undefined,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -128,7 +135,14 @@ function getLegend(props: PieChartProps, displayValues: FieldDisplay[]) {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
return <VizLegend items={legendItems} placement={legendOptions.placement} displayMode={legendOptions.displayMode} />;
|
return (
|
||||||
|
<VizLegend
|
||||||
|
items={legendItems}
|
||||||
|
seriesVisibilityChangeBehavior={SeriesVisibilityChangeBehavior.Hide}
|
||||||
|
placement={legendOptions.placement}
|
||||||
|
displayMode={legendOptions.displayMode}
|
||||||
|
/>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function useSliceHighlightState() {
|
function useSliceHighlightState() {
|
||||||
@ -174,7 +188,11 @@ export const PieChartSvg: FC<PieChartSvgProps> = ({
|
|||||||
scroll: true,
|
scroll: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (fieldDisplayValues.length < 0) {
|
const filteredFieldDisplayValues = fieldDisplayValues.filter((dv) => {
|
||||||
|
return !dv.field.custom.hideFrom.viz;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (filteredFieldDisplayValues.length < 0) {
|
||||||
return <div>No data</div>;
|
return <div>No data</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -186,10 +204,12 @@ export const PieChartSvg: FC<PieChartSvgProps> = ({
|
|||||||
|
|
||||||
const showLabel = displayLabels.length > 0;
|
const showLabel = displayLabels.length > 0;
|
||||||
const showTooltip = tooltipOptions.mode !== 'none' && tooltip.tooltipOpen;
|
const showTooltip = tooltipOptions.mode !== 'none' && tooltip.tooltipOpen;
|
||||||
const total = fieldDisplayValues.reduce((acc, item) => item.display.numeric + acc, 0);
|
const total = filteredFieldDisplayValues.reduce((acc, item) => item.display.numeric + acc, 0);
|
||||||
const layout = getPieLayout(width, height, pieType);
|
const layout = getPieLayout(width, height, pieType);
|
||||||
const colors = [
|
const colors = [
|
||||||
...new Set(fieldDisplayValues.map((fieldDisplayValue) => fieldDisplayValue.display.color ?? FALLBACK_COLOR)),
|
...new Set(
|
||||||
|
filteredFieldDisplayValues.map((fieldDisplayValue) => fieldDisplayValue.display.color ?? FALLBACK_COLOR)
|
||||||
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -213,7 +233,7 @@ export const PieChartSvg: FC<PieChartSvgProps> = ({
|
|||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
<Pie
|
<Pie
|
||||||
data={fieldDisplayValues}
|
data={filteredFieldDisplayValues}
|
||||||
pieValue={getValue}
|
pieValue={getValue}
|
||||||
outerRadius={layout.outerRadius}
|
outerRadius={layout.outerRadius}
|
||||||
innerRadius={layout.innerRadius}
|
innerRadius={layout.innerRadius}
|
||||||
|
@ -161,7 +161,7 @@ export const preparePlotConfigBuilder: PrepConfig = ({ frame, theme, timeZone, g
|
|||||||
pointSize: customConfig.pointSize,
|
pointSize: customConfig.pointSize,
|
||||||
pointColor: customConfig.pointColor ?? seriesColor,
|
pointColor: customConfig.pointColor ?? seriesColor,
|
||||||
spanNulls: customConfig.spanNulls || false,
|
spanNulls: customConfig.spanNulls || false,
|
||||||
show: !customConfig.hideFrom?.graph,
|
show: !customConfig.hideFrom?.viz,
|
||||||
gradientMode: customConfig.gradientMode,
|
gradientMode: customConfig.gradientMode,
|
||||||
thresholds: config.thresholds,
|
thresholds: config.thresholds,
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { GraphNGLegendEventMode, XYFieldMatchers } from '../GraphNG/types';
|
import { XYFieldMatchers } from '../GraphNG/types';
|
||||||
import {
|
import {
|
||||||
DataFrame,
|
DataFrame,
|
||||||
FieldColorModeId,
|
FieldColorModeId,
|
||||||
@ -17,7 +17,7 @@ import { AxisPlacement, GraphGradientMode, ScaleDirection, ScaleOrientation } fr
|
|||||||
import { measureText } from '../../utils/measureText';
|
import { measureText } from '../../utils/measureText';
|
||||||
import { PrepConfigOpts } from '../GraphNG/utils';
|
import { PrepConfigOpts } from '../GraphNG/utils';
|
||||||
|
|
||||||
import { TimelineFieldConfig } from '../..';
|
import { SeriesVisibilityChangeMode, TimelineFieldConfig } from '../..';
|
||||||
import { BarValueVisibility, TimelineMode } from './types';
|
import { BarValueVisibility, TimelineMode } from './types';
|
||||||
|
|
||||||
const defaultConfig: TimelineFieldConfig = {
|
const defaultConfig: TimelineFieldConfig = {
|
||||||
@ -26,11 +26,11 @@ const defaultConfig: TimelineFieldConfig = {
|
|||||||
gradientMode: GraphGradientMode.None,
|
gradientMode: GraphGradientMode.None,
|
||||||
};
|
};
|
||||||
|
|
||||||
export function mapMouseEventToMode(event: React.MouseEvent): GraphNGLegendEventMode {
|
export function mapMouseEventToMode(event: React.MouseEvent): SeriesVisibilityChangeMode {
|
||||||
if (event.ctrlKey || event.metaKey || event.shiftKey) {
|
if (event.ctrlKey || event.metaKey || event.shiftKey) {
|
||||||
return GraphNGLegendEventMode.AppendToSelection;
|
return SeriesVisibilityChangeMode.AppendToSelection;
|
||||||
}
|
}
|
||||||
return GraphNGLegendEventMode.ToggleSelection;
|
return SeriesVisibilityChangeMode.ToggleSelection;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function preparePlotFrame(data: DataFrame[], dimFields: XYFieldMatchers) {
|
export function preparePlotFrame(data: DataFrame[], dimFields: XYFieldMatchers) {
|
||||||
@ -186,7 +186,7 @@ export const preparePlotConfigBuilder: PrepConfig = ({
|
|||||||
//colorMode,
|
//colorMode,
|
||||||
fillOpacity,
|
fillOpacity,
|
||||||
theme,
|
theme,
|
||||||
show: !customConfig.hideFrom?.graph,
|
show: !customConfig.hideFrom?.viz,
|
||||||
thresholds: config.thresholds,
|
thresholds: config.thresholds,
|
||||||
|
|
||||||
// The following properties are not used in the uPlot config, but are utilized as transport for legend config
|
// The following properties are not used in the uPlot config, but are utilized as transport for legend config
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
import React, { useCallback } from 'react';
|
import React, { useCallback } from 'react';
|
||||||
import { LegendProps, VizLegendItem } from './types';
|
import { LegendProps, SeriesVisibilityChangeBehavior, VizLegendItem } from './types';
|
||||||
import { LegendDisplayMode } from './models.gen';
|
import { LegendDisplayMode } from './models.gen';
|
||||||
import { VizLegendTable } from './VizLegendTable';
|
import { VizLegendTable } from './VizLegendTable';
|
||||||
import { VizLegendList } from './VizLegendList';
|
import { VizLegendList } from './VizLegendList';
|
||||||
import { DataHoverClearEvent, DataHoverEvent } from '@grafana/data';
|
import { DataHoverClearEvent, DataHoverEvent } from '@grafana/data';
|
||||||
import { usePanelContext } from '../PanelChrome';
|
import { SeriesVisibilityChangeMode, usePanelContext } from '../PanelChrome';
|
||||||
|
import { mapMouseEventToMode } from './utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @public
|
* @public
|
||||||
@ -13,13 +14,14 @@ export const VizLegend: React.FunctionComponent<LegendProps> = ({
|
|||||||
items,
|
items,
|
||||||
displayMode,
|
displayMode,
|
||||||
sortBy: sortKey,
|
sortBy: sortKey,
|
||||||
|
seriesVisibilityChangeBehavior = SeriesVisibilityChangeBehavior.Isolate,
|
||||||
sortDesc,
|
sortDesc,
|
||||||
onToggleSort,
|
|
||||||
onLabelClick,
|
onLabelClick,
|
||||||
|
onToggleSort,
|
||||||
placement,
|
placement,
|
||||||
className,
|
className,
|
||||||
}) => {
|
}) => {
|
||||||
const { eventBus } = usePanelContext();
|
const { eventBus, onToggleSeriesVisibility } = usePanelContext();
|
||||||
|
|
||||||
const onMouseEnter = useCallback(
|
const onMouseEnter = useCallback(
|
||||||
(item: VizLegendItem, event: React.MouseEvent<HTMLElement, MouseEvent>) => {
|
(item: VizLegendItem, event: React.MouseEvent<HTMLElement, MouseEvent>) => {
|
||||||
@ -51,6 +53,23 @@ export const VizLegend: React.FunctionComponent<LegendProps> = ({
|
|||||||
[eventBus]
|
[eventBus]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const onLegendLabelClick = useCallback(
|
||||||
|
(item: VizLegendItem, event: React.MouseEvent<HTMLElement, MouseEvent>) => {
|
||||||
|
if (onLabelClick) {
|
||||||
|
onLabelClick(item, event);
|
||||||
|
}
|
||||||
|
if (onToggleSeriesVisibility) {
|
||||||
|
onToggleSeriesVisibility(
|
||||||
|
item.label,
|
||||||
|
seriesVisibilityChangeBehavior === SeriesVisibilityChangeBehavior.Hide
|
||||||
|
? SeriesVisibilityChangeMode.AppendToSelection
|
||||||
|
: mapMouseEventToMode(event)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[onToggleSeriesVisibility, onLabelClick, seriesVisibilityChangeBehavior]
|
||||||
|
);
|
||||||
|
|
||||||
switch (displayMode) {
|
switch (displayMode) {
|
||||||
case LegendDisplayMode.Table:
|
case LegendDisplayMode.Table:
|
||||||
return (
|
return (
|
||||||
@ -60,7 +79,7 @@ export const VizLegend: React.FunctionComponent<LegendProps> = ({
|
|||||||
placement={placement}
|
placement={placement}
|
||||||
sortBy={sortKey}
|
sortBy={sortKey}
|
||||||
sortDesc={sortDesc}
|
sortDesc={sortDesc}
|
||||||
onLabelClick={onLabelClick}
|
onLabelClick={onLegendLabelClick}
|
||||||
onToggleSort={onToggleSort}
|
onToggleSort={onToggleSort}
|
||||||
onLabelMouseEnter={onMouseEnter}
|
onLabelMouseEnter={onMouseEnter}
|
||||||
onLabelMouseOut={onMouseOut}
|
onLabelMouseOut={onMouseOut}
|
||||||
@ -74,7 +93,7 @@ export const VizLegend: React.FunctionComponent<LegendProps> = ({
|
|||||||
placement={placement}
|
placement={placement}
|
||||||
onLabelMouseEnter={onMouseEnter}
|
onLabelMouseEnter={onMouseEnter}
|
||||||
onLabelMouseOut={onMouseOut}
|
onLabelMouseOut={onMouseOut}
|
||||||
onLabelClick={onLabelClick}
|
onLabelClick={onLegendLabelClick}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
default:
|
default:
|
||||||
|
@ -15,9 +15,9 @@ export interface Props extends VizLegendBaseProps {}
|
|||||||
export const VizLegendList: React.FunctionComponent<Props> = ({
|
export const VizLegendList: React.FunctionComponent<Props> = ({
|
||||||
items,
|
items,
|
||||||
itemRenderer,
|
itemRenderer,
|
||||||
onLabelClick,
|
|
||||||
onLabelMouseEnter,
|
onLabelMouseEnter,
|
||||||
onLabelMouseOut,
|
onLabelMouseOut,
|
||||||
|
onLabelClick,
|
||||||
placement,
|
placement,
|
||||||
className,
|
className,
|
||||||
}) => {
|
}) => {
|
||||||
|
@ -2,12 +2,18 @@ import { DataFrameFieldIndex, DisplayValue } from '@grafana/data';
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { LegendDisplayMode, LegendPlacement } from './models.gen';
|
import { LegendDisplayMode, LegendPlacement } from './models.gen';
|
||||||
|
|
||||||
|
export enum SeriesVisibilityChangeBehavior {
|
||||||
|
Isolate,
|
||||||
|
Hide,
|
||||||
|
}
|
||||||
|
|
||||||
export interface VizLegendBaseProps {
|
export interface VizLegendBaseProps {
|
||||||
placement: LegendPlacement;
|
placement: LegendPlacement;
|
||||||
className?: string;
|
className?: string;
|
||||||
items: VizLegendItem[];
|
items: VizLegendItem[];
|
||||||
itemRenderer?: (item: VizLegendItem, index: number) => JSX.Element;
|
seriesVisibilityChangeBehavior?: SeriesVisibilityChangeBehavior;
|
||||||
onLabelClick?: (item: VizLegendItem, event: React.MouseEvent<HTMLElement>) => void;
|
onLabelClick?: (item: VizLegendItem, event: React.MouseEvent<HTMLElement>) => void;
|
||||||
|
itemRenderer?: (item: VizLegendItem, index: number) => JSX.Element;
|
||||||
onLabelMouseEnter?: (item: VizLegendItem, event: React.MouseEvent<HTMLElement>) => void;
|
onLabelMouseEnter?: (item: VizLegendItem, event: React.MouseEvent<HTMLElement>) => void;
|
||||||
onLabelMouseOut?: (item: VizLegendItem, event: React.MouseEvent<HTMLElement>) => void;
|
onLabelMouseOut?: (item: VizLegendItem, event: React.MouseEvent<HTMLElement>) => void;
|
||||||
}
|
}
|
||||||
|
8
packages/grafana-ui/src/components/VizLegend/utils.ts
Normal file
8
packages/grafana-ui/src/components/VizLegend/utils.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import { SeriesVisibilityChangeMode } from '..';
|
||||||
|
|
||||||
|
export function mapMouseEventToMode(event: React.MouseEvent): SeriesVisibilityChangeMode {
|
||||||
|
if (event.ctrlKey || event.metaKey || event.shiftKey) {
|
||||||
|
return SeriesVisibilityChangeMode.AppendToSelection;
|
||||||
|
}
|
||||||
|
return SeriesVisibilityChangeMode.ToggleSelection;
|
||||||
|
}
|
@ -247,6 +247,7 @@ export { BarChart } from './BarChart/BarChart';
|
|||||||
export { TimelineChart } from './Timeline/TimelineChart';
|
export { TimelineChart } from './Timeline/TimelineChart';
|
||||||
export { BarChartOptions, BarValueVisibility, BarChartFieldConfig } from './BarChart/types';
|
export { BarChartOptions, BarValueVisibility, BarChartFieldConfig } from './BarChart/types';
|
||||||
export { TimelineOptions, TimelineFieldConfig } from './Timeline/types';
|
export { TimelineOptions, TimelineFieldConfig } from './Timeline/types';
|
||||||
export { GraphNGLegendEvent, GraphNGLegendEventMode } from './GraphNG/types';
|
export { GraphNGLegendEvent } from './GraphNG/types';
|
||||||
|
export * from './PanelChrome/types';
|
||||||
export * from './NodeGraph';
|
export * from './NodeGraph';
|
||||||
export { EmotionPerfTest } from './ThemeDemos/EmotionPerfTest';
|
export { EmotionPerfTest } from './ThemeDemos/EmotionPerfTest';
|
||||||
|
@ -5,9 +5,9 @@ import { VizLegendItem } from '../VizLegend/types';
|
|||||||
import { VizLegendOptions } from '../VizLegend/models.gen';
|
import { VizLegendOptions } from '../VizLegend/models.gen';
|
||||||
import { AxisPlacement } from './config';
|
import { AxisPlacement } from './config';
|
||||||
import { VizLayout, VizLayoutLegendProps } from '../VizLayout/VizLayout';
|
import { VizLayout, VizLayoutLegendProps } from '../VizLayout/VizLayout';
|
||||||
import { mapMouseEventToMode } from '../GraphNG/utils';
|
|
||||||
import { VizLegend } from '../VizLegend/VizLegend';
|
import { VizLegend } from '../VizLegend/VizLegend';
|
||||||
import { GraphNGLegendEvent } from '..';
|
import { GraphNGLegendEvent } from '..';
|
||||||
|
import { mapMouseEventToMode } from '../VizLegend/utils';
|
||||||
|
|
||||||
const defaultFormatter = (v: any) => (v == null ? '-' : v.toFixed(1));
|
const defaultFormatter = (v: any) => (v == null ? '-' : v.toFixed(1));
|
||||||
|
|
||||||
|
@ -165,7 +165,7 @@ export interface AxisConfig {
|
|||||||
export interface HideSeriesConfig {
|
export interface HideSeriesConfig {
|
||||||
tooltip: boolean;
|
tooltip: boolean;
|
||||||
legend: boolean;
|
legend: boolean;
|
||||||
graph: boolean;
|
viz: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -233,10 +233,10 @@ describe('preparePlotData', () => {
|
|||||||
{
|
{
|
||||||
name: 'a',
|
name: 'a',
|
||||||
values: [-10, 20, 10],
|
values: [-10, 20, 10],
|
||||||
config: { custom: { stacking: { mode: StackingMode.Normal, group: 'stackA' }, hideFrom: { graph: true } } },
|
config: { custom: { stacking: { mode: StackingMode.Normal, group: 'stackA' }, hideFrom: { viz: true } } },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// Will ignore a series as stacking base as it's hidden from graph
|
// Will ignore a series as stacking base as it's hidden from viz
|
||||||
name: 'b',
|
name: 'b',
|
||||||
values: [10, 10, 10],
|
values: [10, 10, 10],
|
||||||
config: { custom: { stacking: { mode: StackingMode.Normal, group: 'stackA' } } },
|
config: { custom: { stacking: { mode: StackingMode.Normal, group: 'stackA' } } },
|
||||||
@ -249,10 +249,10 @@ describe('preparePlotData', () => {
|
|||||||
{
|
{
|
||||||
name: 'e',
|
name: 'e',
|
||||||
values: [1, 2, 3],
|
values: [1, 2, 3],
|
||||||
config: { custom: { stacking: { mode: StackingMode.Normal, group: 'stackB' }, hideFrom: { graph: true } } },
|
config: { custom: { stacking: { mode: StackingMode.Normal, group: 'stackB' }, hideFrom: { viz: true } } },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// Will ignore e series as stacking base as it's hidden from graph
|
// Will ignore e series as stacking base as it's hidden from viz
|
||||||
name: 'f',
|
name: 'f',
|
||||||
values: [1, 2, 3],
|
values: [1, 2, 3],
|
||||||
config: { custom: { stacking: { mode: StackingMode.Normal, group: 'stackB' } } },
|
config: { custom: { stacking: { mode: StackingMode.Normal, group: 'stackB' } } },
|
||||||
|
@ -96,7 +96,7 @@ export function collectStackingGroups(f: Field, groups: Map<string, number[]>, s
|
|||||||
if (
|
if (
|
||||||
customConfig.stacking?.mode !== StackingMode.None &&
|
customConfig.stacking?.mode !== StackingMode.None &&
|
||||||
customConfig.stacking?.group &&
|
customConfig.stacking?.group &&
|
||||||
!customConfig.hideFrom?.graph
|
!customConfig.hideFrom?.viz
|
||||||
) {
|
) {
|
||||||
if (!groups.has(customConfig.stacking.group)) {
|
if (!groups.has(customConfig.stacking.group)) {
|
||||||
groups.set(customConfig.stacking.group, [seriesIdx]);
|
groups.set(customConfig.stacking.group, [seriesIdx]);
|
||||||
|
@ -4,7 +4,7 @@ import classNames from 'classnames';
|
|||||||
import { Subscription } from 'rxjs';
|
import { Subscription } from 'rxjs';
|
||||||
// Components
|
// Components
|
||||||
import { PanelHeader } from './PanelHeader/PanelHeader';
|
import { PanelHeader } from './PanelHeader/PanelHeader';
|
||||||
import { ErrorBoundary, PanelContextProvider, PanelContext } from '@grafana/ui';
|
import { ErrorBoundary, PanelContextProvider, PanelContext, SeriesVisibilityChangeMode } from '@grafana/ui';
|
||||||
// Utils & Services
|
// Utils & Services
|
||||||
import { getTimeSrv, TimeSrv } from '../services/TimeSrv';
|
import { getTimeSrv, TimeSrv } from '../services/TimeSrv';
|
||||||
import { applyPanelTimeOverrides } from 'app/features/dashboard/utils/panel';
|
import { applyPanelTimeOverrides } from 'app/features/dashboard/utils/panel';
|
||||||
@ -30,6 +30,7 @@ import { selectors } from '@grafana/e2e-selectors';
|
|||||||
import { loadSnapshotData } from '../utils/loadSnapshotData';
|
import { loadSnapshotData } from '../utils/loadSnapshotData';
|
||||||
import { RefreshEvent, RenderEvent } from 'app/types/events';
|
import { RefreshEvent, RenderEvent } from 'app/types/events';
|
||||||
import { changeSeriesColorConfigFactory } from 'app/plugins/panel/timeseries/overrides/colorSeriesConfigFactory';
|
import { changeSeriesColorConfigFactory } from 'app/plugins/panel/timeseries/overrides/colorSeriesConfigFactory';
|
||||||
|
import { seriesVisibilityConfigFactory } from './SeriesVisibilityConfigFactory';
|
||||||
|
|
||||||
const DEFAULT_PLUGIN_ERROR = 'Error in plugin';
|
const DEFAULT_PLUGIN_ERROR = 'Error in plugin';
|
||||||
|
|
||||||
@ -77,6 +78,7 @@ export class PanelChrome extends Component<Props, State> {
|
|||||||
context: {
|
context: {
|
||||||
eventBus,
|
eventBus,
|
||||||
onSeriesColorChange: this.onSeriesColorChange,
|
onSeriesColorChange: this.onSeriesColorChange,
|
||||||
|
onToggleSeriesVisibility: this.onSeriesVisibilityChange,
|
||||||
},
|
},
|
||||||
data: this.getInitialPanelDataState(),
|
data: this.getInitialPanelDataState(),
|
||||||
};
|
};
|
||||||
@ -86,6 +88,12 @@ export class PanelChrome extends Component<Props, State> {
|
|||||||
this.onFieldConfigChange(changeSeriesColorConfigFactory(label, color, this.props.panel.fieldConfig));
|
this.onFieldConfigChange(changeSeriesColorConfigFactory(label, color, this.props.panel.fieldConfig));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
onSeriesVisibilityChange = (label: string, mode: SeriesVisibilityChangeMode) => {
|
||||||
|
this.onFieldConfigChange(
|
||||||
|
seriesVisibilityConfigFactory(label, mode, this.props.panel.fieldConfig, this.state.data.series)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
getInitialPanelDataState(): PanelData {
|
getInitialPanelDataState(): PanelData {
|
||||||
return {
|
return {
|
||||||
state: LoadingState.NotStarted,
|
state: LoadingState.NotStarted,
|
||||||
|
@ -0,0 +1,171 @@
|
|||||||
|
import {
|
||||||
|
ByNamesMatcherMode,
|
||||||
|
DataFrame,
|
||||||
|
DynamicConfigValue,
|
||||||
|
FieldConfigSource,
|
||||||
|
FieldMatcherID,
|
||||||
|
FieldType,
|
||||||
|
getFieldDisplayName,
|
||||||
|
isSystemOverrideWithRef,
|
||||||
|
SystemConfigOverrideRule,
|
||||||
|
} from '@grafana/data';
|
||||||
|
import { SeriesVisibilityChangeMode } from '@grafana/ui';
|
||||||
|
|
||||||
|
const displayOverrideRef = 'hideSeriesFrom';
|
||||||
|
const isHideSeriesOverride = isSystemOverrideWithRef(displayOverrideRef);
|
||||||
|
|
||||||
|
export function seriesVisibilityConfigFactory(
|
||||||
|
label: string,
|
||||||
|
mode: SeriesVisibilityChangeMode,
|
||||||
|
fieldConfig: FieldConfigSource,
|
||||||
|
data: DataFrame[]
|
||||||
|
) {
|
||||||
|
const { overrides } = fieldConfig;
|
||||||
|
|
||||||
|
const displayName = label;
|
||||||
|
const currentIndex = overrides.findIndex(isHideSeriesOverride);
|
||||||
|
|
||||||
|
if (currentIndex < 0) {
|
||||||
|
if (mode === SeriesVisibilityChangeMode.ToggleSelection) {
|
||||||
|
const override = createOverride([displayName]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
...fieldConfig,
|
||||||
|
overrides: [override, ...fieldConfig.overrides],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const displayNames = getDisplayNames(data, displayName);
|
||||||
|
const override = createOverride(displayNames);
|
||||||
|
|
||||||
|
return {
|
||||||
|
...fieldConfig,
|
||||||
|
overrides: [override, ...fieldConfig.overrides],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const overridesCopy = Array.from(overrides);
|
||||||
|
const [current] = overridesCopy.splice(currentIndex, 1) as SystemConfigOverrideRule[];
|
||||||
|
|
||||||
|
if (mode === SeriesVisibilityChangeMode.ToggleSelection) {
|
||||||
|
const existing = getExistingDisplayNames(current);
|
||||||
|
|
||||||
|
if (existing[0] === displayName && existing.length === 1) {
|
||||||
|
return {
|
||||||
|
...fieldConfig,
|
||||||
|
overrides: overridesCopy,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const override = createOverride([displayName]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
...fieldConfig,
|
||||||
|
overrides: [override, ...overridesCopy],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const override = createExtendedOverride(current, displayName);
|
||||||
|
|
||||||
|
if (allFieldsAreExcluded(override, data)) {
|
||||||
|
return {
|
||||||
|
...fieldConfig,
|
||||||
|
overrides: overridesCopy,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...fieldConfig,
|
||||||
|
overrides: [override, ...overridesCopy],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function createOverride(
|
||||||
|
names: string[],
|
||||||
|
mode = ByNamesMatcherMode.exclude,
|
||||||
|
property?: DynamicConfigValue
|
||||||
|
): SystemConfigOverrideRule {
|
||||||
|
property = property ?? {
|
||||||
|
id: 'custom.hideFrom',
|
||||||
|
value: {
|
||||||
|
viz: true,
|
||||||
|
legend: false,
|
||||||
|
tooltip: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
__systemRef: displayOverrideRef,
|
||||||
|
matcher: {
|
||||||
|
id: FieldMatcherID.byNames,
|
||||||
|
options: {
|
||||||
|
mode: mode,
|
||||||
|
names: names,
|
||||||
|
prefix: mode === ByNamesMatcherMode.exclude ? 'All except:' : undefined,
|
||||||
|
readOnly: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
properties: [
|
||||||
|
{
|
||||||
|
...property,
|
||||||
|
value: {
|
||||||
|
viz: true,
|
||||||
|
legend: false,
|
||||||
|
tooltip: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const createExtendedOverride = (
|
||||||
|
current: SystemConfigOverrideRule,
|
||||||
|
displayName: string,
|
||||||
|
mode = ByNamesMatcherMode.exclude
|
||||||
|
): SystemConfigOverrideRule => {
|
||||||
|
const property = current.properties.find((p) => p.id === 'custom.hideFrom');
|
||||||
|
const existing = getExistingDisplayNames(current);
|
||||||
|
const index = existing.findIndex((name) => name === displayName);
|
||||||
|
|
||||||
|
if (index < 0) {
|
||||||
|
existing.push(displayName);
|
||||||
|
} else {
|
||||||
|
existing.splice(index, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return createOverride(existing, mode, property);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getExistingDisplayNames = (rule: SystemConfigOverrideRule): string[] => {
|
||||||
|
const names = rule.matcher.options?.names;
|
||||||
|
if (!Array.isArray(names)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return names;
|
||||||
|
};
|
||||||
|
|
||||||
|
const allFieldsAreExcluded = (override: SystemConfigOverrideRule, data: DataFrame[]): boolean => {
|
||||||
|
return getExistingDisplayNames(override).length === getDisplayNames(data).length;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getDisplayNames = (data: DataFrame[], excludeName?: string): string[] => {
|
||||||
|
const unique = new Set<string>();
|
||||||
|
|
||||||
|
for (const frame of data) {
|
||||||
|
for (const field of frame.fields) {
|
||||||
|
if (field.type !== FieldType.number) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const name = getFieldDisplayName(field, frame, data);
|
||||||
|
|
||||||
|
if (name === excludeName) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
unique.add(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Array.from(unique);
|
||||||
|
};
|
@ -10,7 +10,6 @@ export const PieChartPanel: React.FC<Props> = ({
|
|||||||
height,
|
height,
|
||||||
options,
|
options,
|
||||||
data,
|
data,
|
||||||
onFieldConfigChange,
|
|
||||||
replaceVariables,
|
replaceVariables,
|
||||||
fieldConfig,
|
fieldConfig,
|
||||||
timeZone,
|
timeZone,
|
||||||
|
@ -3,6 +3,7 @@ import { PieChartPanel } from './PieChartPanel';
|
|||||||
import { PieChartOptions } from './types';
|
import { PieChartOptions } from './types';
|
||||||
import { LegendDisplayMode, PieChartType, PieChartLabels, PieChartLegendValues } from '@grafana/ui';
|
import { LegendDisplayMode, PieChartType, PieChartLabels, PieChartLegendValues } from '@grafana/ui';
|
||||||
import { PieChartPanelChangedHandler } from './migrations';
|
import { PieChartPanelChangedHandler } from './migrations';
|
||||||
|
import { addHideFrom } from '../timeseries/config';
|
||||||
|
|
||||||
export const plugin = new PanelPlugin<PieChartOptions>(PieChartPanel)
|
export const plugin = new PanelPlugin<PieChartOptions>(PieChartPanel)
|
||||||
.setPanelChangeHandler(PieChartPanelChangedHandler)
|
.setPanelChangeHandler(PieChartPanelChangedHandler)
|
||||||
@ -20,6 +21,9 @@ export const plugin = new PanelPlugin<PieChartOptions>(PieChartPanel)
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
useCustomConfig: (builder) => {
|
||||||
|
addHideFrom(builder);
|
||||||
|
},
|
||||||
})
|
})
|
||||||
.setPanelOptions((builder) => {
|
.setPanelOptions((builder) => {
|
||||||
builder
|
builder
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import { Field, PanelProps } from '@grafana/data';
|
import { Field, PanelProps } from '@grafana/data';
|
||||||
import { TimeSeries, GraphNGLegendEvent, TooltipPlugin, ZoomPlugin } from '@grafana/ui';
|
import { TimeSeries, TooltipPlugin, ZoomPlugin } from '@grafana/ui';
|
||||||
import { getFieldLinksForExplore } from 'app/features/explore/utils/links';
|
import { getFieldLinksForExplore } from 'app/features/explore/utils/links';
|
||||||
import React, { useCallback } from 'react';
|
import React from 'react';
|
||||||
import { hideSeriesConfigFactory } from './overrides/hideSeriesConfigFactory';
|
|
||||||
import { AnnotationsPlugin } from './plugins/AnnotationsPlugin';
|
import { AnnotationsPlugin } from './plugins/AnnotationsPlugin';
|
||||||
import { ContextMenuPlugin } from './plugins/ContextMenuPlugin';
|
import { ContextMenuPlugin } from './plugins/ContextMenuPlugin';
|
||||||
import { ExemplarsPlugin } from './plugins/ExemplarsPlugin';
|
import { ExemplarsPlugin } from './plugins/ExemplarsPlugin';
|
||||||
@ -17,18 +16,9 @@ export const TimeSeriesPanel: React.FC<TimeSeriesPanelProps> = ({
|
|||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
options,
|
options,
|
||||||
fieldConfig,
|
|
||||||
onChangeTimeRange,
|
onChangeTimeRange,
|
||||||
onFieldConfigChange,
|
|
||||||
replaceVariables,
|
replaceVariables,
|
||||||
}) => {
|
}) => {
|
||||||
const onLegendClick = useCallback(
|
|
||||||
(event: GraphNGLegendEvent) => {
|
|
||||||
onFieldConfigChange(hideSeriesConfigFactory(event, fieldConfig, data.series));
|
|
||||||
},
|
|
||||||
[fieldConfig, onFieldConfigChange, data.series]
|
|
||||||
);
|
|
||||||
|
|
||||||
const getFieldLinks = (field: Field, rowIndex: number) => {
|
const getFieldLinks = (field: Field, rowIndex: number) => {
|
||||||
return getFieldLinksForExplore({ field, rowIndex, range: timeRange });
|
return getFieldLinksForExplore({ field, rowIndex, range: timeRange });
|
||||||
};
|
};
|
||||||
@ -50,7 +40,6 @@ export const TimeSeriesPanel: React.FC<TimeSeriesPanelProps> = ({
|
|||||||
width={width}
|
width={width}
|
||||||
height={height}
|
height={height}
|
||||||
legend={options.legend}
|
legend={options.legend}
|
||||||
onLegendClick={onLegendClick}
|
|
||||||
>
|
>
|
||||||
{(config, alignedDataFrame) => {
|
{(config, alignedDataFrame) => {
|
||||||
return (
|
return (
|
||||||
|
@ -6,13 +6,13 @@ import {
|
|||||||
FieldType,
|
FieldType,
|
||||||
toDataFrame,
|
toDataFrame,
|
||||||
} from '@grafana/data';
|
} from '@grafana/data';
|
||||||
import { GraphNGLegendEvent, GraphNGLegendEventMode } from '@grafana/ui';
|
import { GraphNGLegendEvent, SeriesVisibilityChangeMode } from '@grafana/ui';
|
||||||
import { hideSeriesConfigFactory } from './hideSeriesConfigFactory';
|
import { hideSeriesConfigFactory } from './hideSeriesConfigFactory';
|
||||||
|
|
||||||
describe('hideSeriesConfigFactory', () => {
|
describe('hideSeriesConfigFactory', () => {
|
||||||
it('should create config override matching one series', () => {
|
it('should create config override matching one series', () => {
|
||||||
const event: GraphNGLegendEvent = {
|
const event: GraphNGLegendEvent = {
|
||||||
mode: GraphNGLegendEventMode.ToggleSelection,
|
mode: SeriesVisibilityChangeMode.ToggleSelection,
|
||||||
fieldIndex: {
|
fieldIndex: {
|
||||||
frameIndex: 0,
|
frameIndex: 0,
|
||||||
fieldIndex: 1,
|
fieldIndex: 1,
|
||||||
@ -43,7 +43,7 @@ describe('hideSeriesConfigFactory', () => {
|
|||||||
|
|
||||||
it('should create config override matching one series if selected with others', () => {
|
it('should create config override matching one series if selected with others', () => {
|
||||||
const event: GraphNGLegendEvent = {
|
const event: GraphNGLegendEvent = {
|
||||||
mode: GraphNGLegendEventMode.ToggleSelection,
|
mode: SeriesVisibilityChangeMode.ToggleSelection,
|
||||||
fieldIndex: {
|
fieldIndex: {
|
||||||
frameIndex: 0,
|
frameIndex: 0,
|
||||||
fieldIndex: 1,
|
fieldIndex: 1,
|
||||||
@ -86,7 +86,7 @@ describe('hideSeriesConfigFactory', () => {
|
|||||||
|
|
||||||
it('should create config override that append series to existing override', () => {
|
it('should create config override that append series to existing override', () => {
|
||||||
const event: GraphNGLegendEvent = {
|
const event: GraphNGLegendEvent = {
|
||||||
mode: GraphNGLegendEventMode.AppendToSelection,
|
mode: SeriesVisibilityChangeMode.AppendToSelection,
|
||||||
fieldIndex: {
|
fieldIndex: {
|
||||||
frameIndex: 1,
|
frameIndex: 1,
|
||||||
fieldIndex: 1,
|
fieldIndex: 1,
|
||||||
@ -129,7 +129,7 @@ describe('hideSeriesConfigFactory', () => {
|
|||||||
|
|
||||||
it('should create config override that hides all series if appending only existing series', () => {
|
it('should create config override that hides all series if appending only existing series', () => {
|
||||||
const event: GraphNGLegendEvent = {
|
const event: GraphNGLegendEvent = {
|
||||||
mode: GraphNGLegendEventMode.AppendToSelection,
|
mode: SeriesVisibilityChangeMode.AppendToSelection,
|
||||||
fieldIndex: {
|
fieldIndex: {
|
||||||
frameIndex: 0,
|
frameIndex: 0,
|
||||||
fieldIndex: 1,
|
fieldIndex: 1,
|
||||||
@ -166,7 +166,7 @@ describe('hideSeriesConfigFactory', () => {
|
|||||||
|
|
||||||
it('should create config override that removes series if appending existing field', () => {
|
it('should create config override that removes series if appending existing field', () => {
|
||||||
const event: GraphNGLegendEvent = {
|
const event: GraphNGLegendEvent = {
|
||||||
mode: GraphNGLegendEventMode.AppendToSelection,
|
mode: SeriesVisibilityChangeMode.AppendToSelection,
|
||||||
fieldIndex: {
|
fieldIndex: {
|
||||||
frameIndex: 0,
|
frameIndex: 0,
|
||||||
fieldIndex: 1,
|
fieldIndex: 1,
|
||||||
@ -203,7 +203,7 @@ describe('hideSeriesConfigFactory', () => {
|
|||||||
|
|
||||||
it('should create config override replacing existing series', () => {
|
it('should create config override replacing existing series', () => {
|
||||||
const event: GraphNGLegendEvent = {
|
const event: GraphNGLegendEvent = {
|
||||||
mode: GraphNGLegendEventMode.ToggleSelection,
|
mode: SeriesVisibilityChangeMode.ToggleSelection,
|
||||||
fieldIndex: {
|
fieldIndex: {
|
||||||
frameIndex: 1,
|
frameIndex: 1,
|
||||||
fieldIndex: 1,
|
fieldIndex: 1,
|
||||||
@ -240,7 +240,7 @@ describe('hideSeriesConfigFactory', () => {
|
|||||||
|
|
||||||
it('should create config override removing existing series', () => {
|
it('should create config override removing existing series', () => {
|
||||||
const event: GraphNGLegendEvent = {
|
const event: GraphNGLegendEvent = {
|
||||||
mode: GraphNGLegendEventMode.ToggleSelection,
|
mode: SeriesVisibilityChangeMode.ToggleSelection,
|
||||||
fieldIndex: {
|
fieldIndex: {
|
||||||
frameIndex: 0,
|
frameIndex: 0,
|
||||||
fieldIndex: 1,
|
fieldIndex: 1,
|
||||||
@ -277,7 +277,7 @@ describe('hideSeriesConfigFactory', () => {
|
|||||||
|
|
||||||
it('should remove override if all fields are appended', () => {
|
it('should remove override if all fields are appended', () => {
|
||||||
const event: GraphNGLegendEvent = {
|
const event: GraphNGLegendEvent = {
|
||||||
mode: GraphNGLegendEventMode.AppendToSelection,
|
mode: SeriesVisibilityChangeMode.AppendToSelection,
|
||||||
fieldIndex: {
|
fieldIndex: {
|
||||||
frameIndex: 1,
|
frameIndex: 1,
|
||||||
fieldIndex: 1,
|
fieldIndex: 1,
|
||||||
@ -314,7 +314,7 @@ describe('hideSeriesConfigFactory', () => {
|
|||||||
|
|
||||||
it('should create config override hiding appended series if no previous override exists', () => {
|
it('should create config override hiding appended series if no previous override exists', () => {
|
||||||
const event: GraphNGLegendEvent = {
|
const event: GraphNGLegendEvent = {
|
||||||
mode: GraphNGLegendEventMode.AppendToSelection,
|
mode: SeriesVisibilityChangeMode.AppendToSelection,
|
||||||
fieldIndex: {
|
fieldIndex: {
|
||||||
frameIndex: 0,
|
frameIndex: 0,
|
||||||
fieldIndex: 1,
|
fieldIndex: 1,
|
||||||
@ -357,7 +357,7 @@ describe('hideSeriesConfigFactory', () => {
|
|||||||
|
|
||||||
it('should return existing override if invalid index is passed', () => {
|
it('should return existing override if invalid index is passed', () => {
|
||||||
const event: GraphNGLegendEvent = {
|
const event: GraphNGLegendEvent = {
|
||||||
mode: GraphNGLegendEventMode.ToggleSelection,
|
mode: SeriesVisibilityChangeMode.ToggleSelection,
|
||||||
fieldIndex: {
|
fieldIndex: {
|
||||||
frameIndex: 4,
|
frameIndex: 4,
|
||||||
fieldIndex: 1,
|
fieldIndex: 1,
|
||||||
|
@ -9,7 +9,7 @@ import {
|
|||||||
isSystemOverrideWithRef,
|
isSystemOverrideWithRef,
|
||||||
SystemConfigOverrideRule,
|
SystemConfigOverrideRule,
|
||||||
} from '@grafana/data';
|
} from '@grafana/data';
|
||||||
import { GraphNGLegendEvent, GraphNGLegendEventMode } from '@grafana/ui';
|
import { GraphNGLegendEvent, SeriesVisibilityChangeMode } from '@grafana/ui';
|
||||||
|
|
||||||
const displayOverrideRef = 'hideSeriesFrom';
|
const displayOverrideRef = 'hideSeriesFrom';
|
||||||
const isHideSeriesOverride = isSystemOverrideWithRef(displayOverrideRef);
|
const isHideSeriesOverride = isSystemOverrideWithRef(displayOverrideRef);
|
||||||
@ -38,7 +38,7 @@ export const hideSeriesConfigFactory = (
|
|||||||
const currentIndex = overrides.findIndex(isHideSeriesOverride);
|
const currentIndex = overrides.findIndex(isHideSeriesOverride);
|
||||||
|
|
||||||
if (currentIndex < 0) {
|
if (currentIndex < 0) {
|
||||||
if (mode === GraphNGLegendEventMode.ToggleSelection) {
|
if (mode === SeriesVisibilityChangeMode.ToggleSelection) {
|
||||||
const override = createOverride([displayName]);
|
const override = createOverride([displayName]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -59,7 +59,7 @@ export const hideSeriesConfigFactory = (
|
|||||||
const overridesCopy = Array.from(overrides);
|
const overridesCopy = Array.from(overrides);
|
||||||
const [current] = overridesCopy.splice(currentIndex, 1) as SystemConfigOverrideRule[];
|
const [current] = overridesCopy.splice(currentIndex, 1) as SystemConfigOverrideRule[];
|
||||||
|
|
||||||
if (mode === GraphNGLegendEventMode.ToggleSelection) {
|
if (mode === SeriesVisibilityChangeMode.ToggleSelection) {
|
||||||
const existing = getExistingDisplayNames(current);
|
const existing = getExistingDisplayNames(current);
|
||||||
|
|
||||||
if (existing[0] === displayName && existing.length === 1) {
|
if (existing[0] === displayName && existing.length === 1) {
|
||||||
|
Loading…
Reference in New Issue
Block a user